From 02ac48872220dfd7bf2ffb04418de7e13d278a78 Mon Sep 17 00:00:00 2001 From: Andrew Krieger Date: Sat, 13 Apr 2024 15:21:28 -0700 Subject: [PATCH] Don't crash when forest mapgen requests groundcover from a biome with no groundcover. --- src/mapgen_functions.cpp | 9 +++++++-- src/regional_settings.cpp | 24 +++++++++++++++++------- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/mapgen_functions.cpp b/src/mapgen_functions.cpp index 3a26a387891e8..9cd85475f5587 100644 --- a/src/mapgen_functions.cpp +++ b/src/mapgen_functions.cpp @@ -932,7 +932,7 @@ void mapgen_forest( mapgendata &dat ) // In order to feather (blend) this overmap tile with adjacent ones, the general composition thereof must be known. // This can be calculated once from dat.t_nesw, and stored here: std::array adjacent_biomes; - for( int d = 0; d < 7; d++ ) { + for( int d = 0; d <= 7; d++ ) { auto lookup = dat.region.forest_composition.biomes.find( dat.t_nesw[d]->get_type_id() ); if( lookup != dat.region.forest_composition.biomes.end() ) { adjacent_biomes[d] = &( lookup->second ); @@ -1187,7 +1187,12 @@ void mapgen_forest( mapgendata &dat ) return *dat.region.default_groundcover.pick(); default: if( adjacent_biomes[feather_selection] != nullptr ) { - return *adjacent_biomes[feather_selection]->groundcover.pick(); + const ter_id *cover = adjacent_biomes[feather_selection]->groundcover.pick(); + if( cover ) { + return *cover; + } + // Adjacent biome has no groundcover, use the region default. + return *dat.region.default_groundcover.pick(); } else { return *dat.region.default_groundcover.pick(); } diff --git a/src/regional_settings.cpp b/src/regional_settings.cpp index cfc9cb0a13013..df0b1b628aaca 100644 --- a/src/regional_settings.cpp +++ b/src/regional_settings.cpp @@ -172,19 +172,29 @@ static void load_forest_mapgen_settings( const JsonObject &jo, if( forest_biome_ter_keys.empty() ) { forest_biome_jo.throw_error( "Biome is not associated with any terrains." ); } - std::string first_ter = forest_biome_ter_keys.get_string( 0 ); - load_forest_biome( forest_biome_jo, forest_mapgen_settings.unfinalized_biomes[first_ter], - overlay ); - for( size_t biome_ter_idx = 1; biome_ter_idx < forest_biome_ter_keys.size(); biome_ter_idx++ ) { + std::string default_ter_name = member.name(); + auto default_ter_it = forest_mapgen_settings.unfinalized_biomes.find( default_ter_name ); + if( default_ter_it == forest_mapgen_settings.unfinalized_biomes.end() ) { + if( overlay ) { + forest_biome_jo.throw_error( "Terrain " + default_ter_name + + " is not defined, cannot be used for forest biome." ); + } + default_ter_it = forest_mapgen_settings.unfinalized_biomes.emplace( default_ter_name, forest_biome{} ).first; + } + forest_biome &default_ter = default_ter_it->second; + load_forest_biome( forest_biome_jo, default_ter, overlay ); + for( size_t biome_ter_idx = 0; biome_ter_idx < forest_biome_ter_keys.size(); biome_ter_idx++ ) { + std::string biome_ter_name = forest_biome_ter_keys.get_string( biome_ter_idx ); + if( biome_ter_name == default_ter_name ) { + continue; + } forest_mapgen_settings.unfinalized_biomes.insert( std::pair - ( forest_biome_ter_keys.get_string( biome_ter_idx ), - forest_mapgen_settings.unfinalized_biomes[first_ter] ) ); + ( forest_biome_ter_keys.get_string( biome_ter_idx ), default_ter ) ); } } else { load_forest_biome( forest_biome_jo, forest_mapgen_settings.unfinalized_biomes[member.name()], overlay ); } - } } }