From 018b46ec65bda7ea3cb9e96801c68aef6840fdd4 Mon Sep 17 00:00:00 2001 From: Louis Moureaux Date: Sun, 7 Jul 2024 15:36:34 +0200 Subject: [PATCH] Cache specialists outputs in governor code This avoids a large number of effect evaluations, speeding things up significantly. --- common/aicore/cm.cpp | 18 +++++++++++++----- common/city.cpp | 12 ++++++++---- common/city.h | 7 +++++-- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/common/aicore/cm.cpp b/common/aicore/cm.cpp index 41cd69a28c..5d15efccc6 100644 --- a/common/aicore/cm.cpp +++ b/common/aicore/cm.cpp @@ -201,6 +201,9 @@ struct cm_state { // the output of tiles the city works for free. std::array city_center_output = {0}; + // specialist outputs + std::vector> specialist_outputs = {}; + // cached government centers to avoid looping through all cities std::vector gov_centers; @@ -698,7 +701,7 @@ static void apply_solution(struct cm_state *state, // Finally we must refresh the city to reset all the precomputed fields. city_refresh_from_main_map(pcity, state->workers_map, state->gov_centers, - &state->waste); + &state->waste, &state->specialist_outputs); fc_assert_ret(citizen_count == city_size_get(pcity)); } @@ -969,7 +972,7 @@ static void tile_type_lattice_add(struct tile_type_vector *lattice, Create lattice nodes for each type of specialist. This adds a new tile_type for each specialist type. */ -static void init_specialist_lattice_nodes(struct tile_type_vector *lattice, +static void init_specialist_lattice_nodes(struct cm_state *state, const struct city *pcity) { struct cm_tile_type type; @@ -981,16 +984,21 @@ static void init_specialist_lattice_nodes(struct tile_type_vector *lattice, * the bonus for the specialist (if the city is allowed to use it) */ specialist_type_iterate(i) { + std::array outputs = {0}; + if (city_can_use_specialist(pcity, i)) { type.spec = i; output_type_iterate(output) { - type.production[output] = get_specialist_output(pcity, i, output); + outputs[output] = get_specialist_output(pcity, i, output); + type.production[output] = outputs[output]; } output_type_iterate_end; - tile_type_lattice_add(lattice, &type, 0); + tile_type_lattice_add(&state->lattice, &type, 0); } + + state->specialist_outputs.push_back(outputs); } specialist_type_iterate_end; } @@ -1220,7 +1228,7 @@ static void init_tile_lattice(struct city *pcity, struct cm_state *state) // Add all the specialists into the lattice. if (state->parameter.allow_specialists) { - init_specialist_lattice_nodes(&state->lattice, pcity); + init_specialist_lattice_nodes(state, pcity); } // Set the lattice_depth fields, and clean up unreachable nodes. diff --git a/common/city.cpp b/common/city.cpp index d3f2db606a..eaba104ba1 100644 --- a/common/city.cpp +++ b/common/city.cpp @@ -2235,7 +2235,9 @@ static inline void get_worked_tile_output(const struct city *pcity, Calculate output (gold, science, and luxury) generated by the specialists of a city. The output[] array is not cleared but is just added to. */ -void add_specialist_output(const struct city *pcity, int *output) +void add_specialist_output( + const struct city *pcity, int *output, + const std::vector> *pcsoutputs) { specialist_type_iterate(sp) { @@ -2243,7 +2245,8 @@ void add_specialist_output(const struct city *pcity, int *output) output_type_iterate(stat_index) { - int amount = get_specialist_output(pcity, sp, stat_index); + int amount = pcsoutputs ? pcsoutputs->at(sp)[stat_index] + : get_specialist_output(pcity, sp, stat_index); output[stat_index] += count * amount; } @@ -3027,7 +3030,8 @@ static inline void city_support(struct city *pcity) void city_refresh_from_main_map( struct city *pcity, bool *workers_map, const std::vector &gov_centers, - const std::array *pcwaste) + const std::array *pcwaste, + const std::vector> *pcsoutputs) { if (workers_map == nullptr) { // do a full refresh @@ -3042,7 +3046,7 @@ void city_refresh_from_main_map( // Calculate output from citizens (uses city_tile_cache_get_output()). get_worked_tile_output(pcity, pcity->citizen_base, workers_map); - add_specialist_output(pcity, pcity->citizen_base); + add_specialist_output(pcity, pcity->citizen_base, pcsoutputs); set_city_production(pcity, gov_centers, pcwaste); citizen_base_mood(pcity); diff --git a/common/city.h b/common/city.h index 6c4a8748bc..5daec595e1 100644 --- a/common/city.h +++ b/common/city.h @@ -530,7 +530,9 @@ const char *get_output_identifier(Output_type_id output); const char *get_output_name(Output_type_id output); struct output_type *get_output_type(Output_type_id output); Output_type_id output_type_by_identifier(const char *id); -void add_specialist_output(const struct city *pcity, int *output); +void add_specialist_output( + const struct city *pcity, int *output, + const std::vector> *pcsoutputs = nullptr); void set_city_production( struct city *pcity, const std::vector &gov_centers, const std::array *pcwaste = nullptr); @@ -706,7 +708,8 @@ void city_remove_improvement(struct city *pcity, void city_refresh_from_main_map( struct city *pcity, bool *workers_map, const std::vector &gov_centers, - const std::array *pcwaste = nullptr); + const std::array *pcwaste = nullptr, + const std::vector> *pcsoutputs = nullptr); int city_waste(const struct city *pcity, Output_type_id otype, int total, int *breakdown, const std::vector &gov_centers, const cached_waste *pcwaste = nullptr);