Skip to content

Commit

Permalink
Cache sort order of localised population menu columns
Browse files Browse the repository at this point in the history
  • Loading branch information
Hop311 committed Jul 26, 2024
1 parent 7dfb935 commit 7ca15c8
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ Error GameSingleton::setup_game(int32_t bookmark_index) {

MenuSingleton* menu_singleton = MenuSingleton::get_singleton();
ERR_FAIL_NULL_V(menu_singleton, FAILED);
ret &= menu_singleton->_population_menu_update_provinces();
ret &= menu_singleton->_population_menu_update_provinces() == OK;

return ERR(ret);
}
Expand Down
6 changes: 5 additions & 1 deletion extension/src/openvic-extension/singletons/MenuSingleton.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ void MenuSingleton::_bind_methods() {
OV_BIND_METHOD(MenuSingleton::population_menu_select_province, { "province_index" });
OV_BIND_METHOD(MenuSingleton::population_menu_toggle_expanded, { "toggle_index", "emit_selected_changed" }, DEFVAL(true));

OV_BIND_METHOD(MenuSingleton::population_menu_update_locale_sort_cache);
OV_BIND_METHOD(MenuSingleton::population_menu_select_sort_key, { "sort_key" });
OV_BIND_METHOD(MenuSingleton::get_population_menu_pop_rows, { "start", "count" });
OV_BIND_METHOD(MenuSingleton::get_population_menu_pop_row_count);
Expand Down Expand Up @@ -147,7 +148,10 @@ MenuSingleton* MenuSingleton::get_singleton() {
return singleton;
}

MenuSingleton::MenuSingleton() {
MenuSingleton::MenuSingleton() : population_menu {
.pop_type_sort_cache { nullptr }, .culture_sort_cache { nullptr }, .religion_sort_cache { nullptr },
.province_sort_cache { nullptr }, .rebel_type_sort_cache { nullptr }
} {
ERR_FAIL_COND(singleton != nullptr);
singleton = this;
}
Expand Down
21 changes: 14 additions & 7 deletions extension/src/openvic-extension/singletons/MenuSingleton.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <godot_cpp/classes/image.hpp>

#include <openvic-simulation/pop/Pop.hpp>
#include <openvic-simulation/types/IndexedMap.hpp>
#include <openvic-simulation/types/OrderedContainers.hpp>

namespace OpenVic {
Expand Down Expand Up @@ -61,6 +62,11 @@ namespace OpenVic {
SORT_LUXURY_NEEDS, SORT_REBEL_FACTION, SORT_SIZE_CHANGE, SORT_LITERACY, MAX_SORT_KEY
} sort_key = NONE;
bool sort_descending = true;
IndexedMap<PopType, size_t> pop_type_sort_cache;
IndexedMap<Culture, size_t> culture_sort_cache;
IndexedMap<Religion, size_t> religion_sort_cache;
IndexedMap<ProvinceInstance, size_t> province_sort_cache;
IndexedMap<RebelType, size_t> rebel_type_sort_cache;

std::vector<Pop const*> pops, filtered_pops;
};
Expand Down Expand Up @@ -110,28 +116,29 @@ namespace OpenVic {
godot::String get_longform_date() const;

/* POPULATION MENU */
bool _population_menu_update_provinces();
godot::Error _population_menu_update_provinces();
int32_t get_population_menu_province_list_row_count() const;
godot::TypedArray<godot::Dictionary> get_population_menu_province_list_rows(int32_t start, int32_t count) const;
godot::Error population_menu_select_province_list_entry(int32_t select_index, bool set_scroll_index = false);
godot::Error population_menu_select_province(int32_t province_index);
godot::Error population_menu_toggle_expanded(int32_t toggle_index, bool emit_selected_changed = true);

void _population_menu_update_pops();
void _population_menu_update_filtered_pops();
godot::Error _population_menu_update_pops();
godot::Error _population_menu_update_filtered_pops();
using sort_func_t = std::function<bool(Pop const*, Pop const*)>;
sort_func_t _get_population_menu_sort_func(population_menu_t::PopSortKey sort_key) const;
void _population_menu_sort_pops();
godot::Error _population_menu_sort_pops();
godot::Error population_menu_update_locale_sort_cache();
godot::Error population_menu_select_sort_key(population_menu_t::PopSortKey sort_key);
godot::TypedArray<godot::Dictionary> get_population_menu_pop_rows(int32_t start, int32_t count) const;
int32_t get_population_menu_pop_row_count() const;

bool _population_menu_generate_pop_filters();
godot::Error _population_menu_generate_pop_filters();
godot::PackedInt32Array get_population_menu_pop_filter_setup_info();
godot::TypedArray<godot::Dictionary> get_population_menu_pop_filter_info() const;
godot::Error population_menu_toggle_pop_filter(int32_t filter_index);
void population_menu_select_all_pop_filters();
void population_menu_deselect_all_pop_filters();
godot::Error population_menu_select_all_pop_filters();
godot::Error population_menu_deselect_all_pop_filters();

godot::PackedStringArray get_population_menu_distribution_setup_info() const;
/* Array of GFXPieChartTexture::godot_pie_chart_data_t. */
Expand Down
156 changes: 112 additions & 44 deletions extension/src/openvic-extension/singletons/PopulationMenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <openvic-simulation/InstanceManager.hpp>

#include "openvic-extension/classes/GFXPieChartTexture.hpp"
#include "openvic-extension/classes/GUINode.hpp"
#include "openvic-extension/singletons/GameSingleton.hpp"
#include "openvic-extension/utility/Utilities.hpp"

Expand All @@ -16,18 +17,18 @@ using OpenVic::Utilities::std_view_to_godot_string;

/* POPULATION MENU */

bool MenuSingleton::_population_menu_update_provinces() {
Error MenuSingleton::_population_menu_update_provinces() {
GameSingleton const* game_singleton = GameSingleton::get_singleton();
ERR_FAIL_NULL_V(game_singleton, false);
ERR_FAIL_NULL_V(game_singleton, FAILED);
InstanceManager const* instance_manager = game_singleton->get_instance_manager();
ERR_FAIL_NULL_V(instance_manager, false);
ERR_FAIL_NULL_V(instance_manager, FAILED);

population_menu.province_list_entries.clear();
population_menu.visible_province_list_entries = 0;
ERR_FAIL_COND_V(!_population_menu_generate_pop_filters(), false);
ERR_FAIL_COND_V(_population_menu_generate_pop_filters() != OK, FAILED);

MapInstance const& map_instance = instance_manager->get_map_instance();
ERR_FAIL_COND_V(!map_instance.province_instances_are_locked(), false);
ERR_FAIL_COND_V(!map_instance.province_instances_are_locked(), FAILED);

for (CountryDefinition const* country : {
// Example country
Expand Down Expand Up @@ -57,9 +58,7 @@ bool MenuSingleton::_population_menu_update_provinces() {

// TODO - may need to emit population_menu_province_list_selected_changed if _update_info cannot be guaranteed

_population_menu_update_pops();

return true;
return _population_menu_update_pops();
}

int32_t MenuSingleton::get_population_menu_province_list_row_count() const {
Expand Down Expand Up @@ -262,9 +261,7 @@ Error MenuSingleton::population_menu_select_province_list_entry(int32_t select_i
set_scroll_index ? entry_visitor.selected_visible_index : -1
);

_population_menu_update_pops();

return OK;
return _population_menu_update_pops();
}

Error MenuSingleton::population_menu_select_province(int32_t province_index) {
Expand Down Expand Up @@ -365,7 +362,7 @@ Error MenuSingleton::population_menu_toggle_expanded(int32_t toggle_index, bool
return OK;
}

void MenuSingleton::_population_menu_update_pops() {
Error MenuSingleton::_population_menu_update_pops() {
for (auto [pop_type, filter] : mutable_iterator(population_menu.pop_filters)) {
filter.count = 0;
filter.promotion_demotion_change = 0;
Expand All @@ -387,10 +384,10 @@ void MenuSingleton::_population_menu_update_pops() {
}
}

_population_menu_update_filtered_pops();
return _population_menu_update_filtered_pops();
}

void MenuSingleton::_population_menu_update_filtered_pops() {
Error MenuSingleton::_population_menu_update_filtered_pops() {
population_menu.filtered_pops.clear();

for (fixed_point_map_t<HasIdentifierAndColour const*>& distribution : population_menu.distributions) {
Expand Down Expand Up @@ -419,19 +416,17 @@ void MenuSingleton::_population_menu_update_filtered_pops() {
normalise_fixed_point_map(distribution);
}

_population_menu_sort_pops();
return _population_menu_sort_pops();
}

template<std::derived_from<HasIdentifier> T>
static bool compare_translated_identifiers(Object const& object, T const& lhs, T const& rhs) {
return object.tr(std_view_to_godot_string(lhs.get_identifier()))
< object.tr(std_view_to_godot_string(rhs.get_identifier()));
template<typename T>
static constexpr bool indexed_map_lookup_less_than(IndexedMap<T, size_t> const& map, T const& lhs, T const& rhs) {
return map[lhs] < map[rhs];
}

template<std::derived_from<HasIdentifier> T>
static bool compare_translated_identifiers(Object const& object, T const* lhs, T const* rhs) {
return (lhs != nullptr ? object.tr(std_view_to_godot_string(lhs->get_identifier())) : godot::String {})
< (rhs != nullptr ? object.tr(std_view_to_godot_string(rhs->get_identifier())) : godot::String {});
template<typename T>
static constexpr bool indexed_map_lookup_less_than(IndexedMap<T, size_t> const& map, T const* lhs, T const* rhs) {
return lhs != nullptr && rhs != nullptr && map[*lhs] < map[*rhs];
}

MenuSingleton::sort_func_t MenuSingleton::_get_population_menu_sort_func(population_menu_t::PopSortKey sort_key) const {
Expand All @@ -443,19 +438,19 @@ MenuSingleton::sort_func_t MenuSingleton::_get_population_menu_sort_func(populat
};
case SORT_TYPE:
return [this](Pop const* a, Pop const* b) -> bool {
return compare_translated_identifiers(*this, a->get_type(), b->get_type());
return indexed_map_lookup_less_than(population_menu.pop_type_sort_cache, a->get_type(), b->get_type());
};
case SORT_CULTURE:
return [this](Pop const* a, Pop const* b) -> bool {
return compare_translated_identifiers(*this, a->get_culture(), b->get_culture());
return indexed_map_lookup_less_than(population_menu.culture_sort_cache, a->get_culture(), b->get_culture());
};
case SORT_RELIGION:
return [this](Pop const* a, Pop const* b) -> bool {
return compare_translated_identifiers(*this, a->get_religion(), b->get_religion());
return indexed_map_lookup_less_than(population_menu.religion_sort_cache, a->get_religion(), b->get_religion());
};
case SORT_LOCATION:
return [this](Pop const* a, Pop const* b) -> bool {
return compare_translated_identifiers(*this, a->get_location(), b->get_location());
return indexed_map_lookup_less_than(population_menu.province_sort_cache, a->get_location(), b->get_location());
};
case SORT_MILITANCY:
return [](Pop const* a, Pop const* b) -> bool {
Expand Down Expand Up @@ -497,7 +492,9 @@ MenuSingleton::sort_func_t MenuSingleton::_get_population_menu_sort_func(populat
return [this](Pop const* a, Pop const* b) -> bool {
// TODO - include country adjective for [pan-]nationalist rebels
// TODO - handle social/political reform movements
return compare_translated_identifiers(*this, a->get_rebel_type(), b->get_rebel_type());
return indexed_map_lookup_less_than(
population_menu.rebel_type_sort_cache, a->get_rebel_type(), b->get_rebel_type()
);
};
case SORT_SIZE_CHANGE:
return [](Pop const* a, Pop const* b) -> bool {
Expand All @@ -513,8 +510,16 @@ MenuSingleton::sort_func_t MenuSingleton::_get_population_menu_sort_func(populat
}
}

void MenuSingleton::_population_menu_sort_pops() {
Error MenuSingleton::_population_menu_sort_pops() {
if (population_menu.sort_key != population_menu_t::NONE) {
if (
!population_menu.pop_type_sort_cache.has_keys() || !population_menu.culture_sort_cache.has_keys() ||
!population_menu.religion_sort_cache.has_keys() || !population_menu.province_sort_cache.has_keys() ||
!population_menu.rebel_type_sort_cache.has_keys()
) {
ERR_FAIL_COND_V(population_menu_update_locale_sort_cache() != OK, FAILED);
}

const sort_func_t base_sort_func = _get_population_menu_sort_func(population_menu.sort_key);

const sort_func_t sort_func = population_menu.sort_descending
Expand All @@ -525,6 +530,68 @@ void MenuSingleton::_population_menu_sort_pops() {
}

emit_signal(_signal_population_menu_pops_changed());

return OK;
}

Error MenuSingleton::population_menu_update_locale_sort_cache() {
GameSingleton const* game_singleton = GameSingleton::get_singleton();
ERR_FAIL_NULL_V(game_singleton, FAILED);
InstanceManager const* instance_manager = game_singleton->get_instance_manager();
ERR_FAIL_NULL_V(instance_manager, FAILED);

std::vector<String> localised_items;
std::vector<size_t> sorted_items;

const auto generate_sort_cache = [this, &localised_items, &sorted_items]<HasGetIdentifier T>(
IndexedMap<T, size_t>& cache, std::vector<T> const& items
) {
localised_items.resize(items.size());
sorted_items.resize(items.size());

for (size_t idx = 0; idx < items.size(); ++idx) {
String identifier = std_view_to_godot_string(items[idx].get_identifier());
if constexpr (std::is_same_v<T, ProvinceInstance>) {
identifier = GUINode::format_province_name(identifier);
}
localised_items[idx] = tr(identifier).to_lower();
sorted_items[idx] = idx;
}

std::sort(
sorted_items.begin(), sorted_items.end(), [&localised_items](size_t a, size_t b) -> bool {
return localised_items[a] < localised_items[b];
}
);

cache.set_keys(&items);
for (size_t idx = 0; idx < sorted_items.size(); ++idx) {
cache[sorted_items[idx]] = idx;
}
};

generate_sort_cache(
population_menu.pop_type_sort_cache,
game_singleton->get_definition_manager().get_pop_manager().get_pop_types()
);
generate_sort_cache(
population_menu.culture_sort_cache,
game_singleton->get_definition_manager().get_pop_manager().get_culture_manager().get_cultures()
);
generate_sort_cache(
population_menu.religion_sort_cache,
game_singleton->get_definition_manager().get_pop_manager().get_religion_manager().get_religions()
);
generate_sort_cache(
population_menu.province_sort_cache,
instance_manager->get_map_instance().get_province_instances()
);
generate_sort_cache(
population_menu.rebel_type_sort_cache,
game_singleton->get_definition_manager().get_politics_manager().get_rebel_manager().get_rebel_types()
);

return OK;
}

Error MenuSingleton::population_menu_select_sort_key(population_menu_t::PopSortKey sort_key) {
Expand All @@ -543,9 +610,7 @@ Error MenuSingleton::population_menu_select_sort_key(population_menu_t::PopSortK
population_menu.sort_key = sort_key;
}

_population_menu_sort_pops();

return OK;
return _population_menu_sort_pops();
}

TypedArray<Dictionary> MenuSingleton::get_population_menu_pop_rows(int32_t start, int32_t count) const {
Expand Down Expand Up @@ -650,23 +715,23 @@ int32_t MenuSingleton::get_population_menu_pop_row_count() const {
return population_menu.filtered_pops.size();
}

bool MenuSingleton::_population_menu_generate_pop_filters() {
Error MenuSingleton::_population_menu_generate_pop_filters() {
if (population_menu.pop_filters.empty()) {
GameSingleton const* game_singleton = GameSingleton::get_singleton();
ERR_FAIL_NULL_V(game_singleton, false);
ERR_FAIL_NULL_V(game_singleton, FAILED);

for (PopType const& pop_type : game_singleton->get_definition_manager().get_pop_manager().get_pop_types()) {
population_menu.pop_filters.emplace(&pop_type, population_menu_t::pop_filter_t { 0, 0, true });
}

ERR_FAIL_COND_V_MSG(population_menu.pop_filters.empty(), false, "Failed to generate population menu pop filters!");
ERR_FAIL_COND_V_MSG(population_menu.pop_filters.empty(), FAILED, "Failed to generate population menu pop filters!");
}

return true;
return OK;
}

PackedInt32Array MenuSingleton::get_population_menu_pop_filter_setup_info() {
ERR_FAIL_COND_V(!_population_menu_generate_pop_filters(), {});
ERR_FAIL_COND_V(_population_menu_generate_pop_filters() != OK, {});

PackedInt32Array array;
ERR_FAIL_COND_V(array.resize(population_menu.pop_filters.size()) != OK, {});
Expand Down Expand Up @@ -709,12 +774,10 @@ Error MenuSingleton::population_menu_toggle_pop_filter(int32_t index) {
population_menu_t::pop_filter_t& filter = mutable_iterator(population_menu.pop_filters).begin()[index].second;
filter.selected = !filter.selected;

_population_menu_update_filtered_pops();

return OK;
return _population_menu_update_filtered_pops();
}

void MenuSingleton::population_menu_select_all_pop_filters() {
Error MenuSingleton::population_menu_select_all_pop_filters() {
bool changed = false;

for (auto [pop_type, filter] : mutable_iterator(population_menu.pop_filters)) {
Expand All @@ -725,21 +788,26 @@ void MenuSingleton::population_menu_select_all_pop_filters() {
}

if (changed) {
_population_menu_update_filtered_pops();
return _population_menu_update_filtered_pops();
}

return OK;
}

void MenuSingleton::population_menu_deselect_all_pop_filters() {
Error MenuSingleton::population_menu_deselect_all_pop_filters() {
bool changed = false;
for (auto [pop_type, filter] : mutable_iterator(population_menu.pop_filters)) {
if (filter.selected) {
filter.selected = false;
changed = true;
}
}

if (changed) {
_population_menu_update_filtered_pops();
return _population_menu_update_filtered_pops();
}

return OK;
}

PackedStringArray MenuSingleton::get_population_menu_distribution_setup_info() const {
Expand Down
Loading

0 comments on commit 7ca15c8

Please sign in to comment.