Skip to content

Commit

Permalink
Redo linear omt deduplication with extra comments and more consistency.
Browse files Browse the repository at this point in the history
  • Loading branch information
akrieger committed Sep 29, 2023
1 parent 91f2c43 commit 2f4de78
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 28 deletions.
35 changes: 26 additions & 9 deletions src/overmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2887,21 +2887,38 @@ void overmap::ter_set( const tripoint_om_omt &p, const oter_id &id )
return;
}

oter_id &val = layer[p.z() + OVERMAP_DEPTH].terrain[p.xy()];
oter_id &current_oter = layer[p.z() + OVERMAP_DEPTH].terrain[p.xy()];
const oter_type_str_id &current_type_id = current_oter->get_type_id();
const oter_type_str_id &incoming_type_id = id->get_type_id();
const bool current_type_same = current_type_id == incoming_type_id;

// Mapgen refinement can push multiple different roads over each other.
// Roads require a predecessor. A road pushed over a road might cause a
// road to be a predecessor to another road. That causes too many spawns
// to happen. So when pushing a predecessor, if the predecessor to-be-pushed
// is linear and the previous predecessor is linear, overwrite it.
// This way only the 'last' rotation/variation generated is kept.
if( id->has_flag( oter_flags::requires_predecessor ) ) {
// Stops linear fallback_predecessor maps (roads etc) spawning over themselves
std::vector<oter_id> &om_predecessors = predecessors_[p];
if( om_predecessors.empty() || !val->is_linear() ) {
om_predecessors.push_back( val );
} else {
// Collapse and keep the last linear oter of matching type
if( om_predecessors.empty() || ( !current_oter->is_linear() && !current_type_same ) ) {
// If we need a predecessor, we must have a predecessor no matter what.
// Or, if the oter to-be-pushed is not linear, push it only if the incoming oter is different.
om_predecessors.push_back( current_oter );
} else if( !current_type_same ) {
// Current oter is linear, incoming oter is different from current.
// If the last predecessor is the same type as the current type, overwrite.
// Else push the current type.
oter_id &last_predecessor = om_predecessors.back();
if( last_predecessor->get_type_id() == val->get_type_id() ) {
last_predecessor = val;
if( last_predecessor->get_type_id() == current_type_id ) {
last_predecessor = current_oter;
} else {
om_predecessors.push_back( current_oter );
}
}
// We had a predecessor, and it was the same type as the incoming one
// Don't push another copy.
}
val = id;
current_oter = id;
}

const oter_id &overmap::ter( const tripoint_om_omt &p ) const
Expand Down
65 changes: 46 additions & 19 deletions src/savegame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -659,30 +659,57 @@ void overmap::unserialize( const JsonObject &jsobj )
} else if( name == "predecessors" ) {
std::vector<std::pair<tripoint_om_omt, std::vector<oter_id>>> flattened_predecessors;
om_member.read( flattened_predecessors, true );
std::vector<oter_id> deduped_predecessors;
for( std::pair<tripoint_om_omt, std::vector<oter_id>> &p : flattened_predecessors ) {
// TODO remove after 0.H release.
// JSONizing roads caused some bad mapgen data to get saved to disk. Repeated redundant linear
// type omts were all saved. The new logic only pushes a linear predecessor if the predecessors
// list is empty or the incoming omt is not linear. Fixup bad saves to conform.
deduped_predecessors.reserve( p.second.size() );
for( const oter_id &id : p.second ) {
if( deduped_predecessors.empty() || !id->is_linear() ) {
deduped_predecessors.push_back( id );
} else {
oter_id &last_predecessor = deduped_predecessors.back();
if( last_predecessor->get_type_id() == id->get_type_id() ) {
last_predecessor = id;
} else {
deduped_predecessors.push_back( id );
std::vector<oter_id> om_predecessors;

for( auto& [p, serialized_predecessors] : flattened_predecessors ) {
if( !serialized_predecessors.empty() ) {
// TODO remove after 0.H release.
// JSONizing roads caused some bad mapgen data to get saved to disk. Fixup bad saves to conform.
// The logic to do this is to emulate setting overmap::set_ter repeatedly. The difference is the
// 'original' terrain is lost, all we have is a chain of predecessors.
// This doesn't matter for the sake of deduplicating predecessors.
//
// Mapgen refinement can push multiple different roads over each other.
// Roads require a predecessor. A road pushed over a road might cause a
// road to be a predecessor to another road. That causes too many spawns
// to happen. So when pushing a predecessor, if the predecessor to-be-pushed
// is linear and the previous predecessor is linear, overwrite it.
// This way only the 'last' rotation/variation generated is kept.
om_predecessors.reserve( serialized_predecessors.size() );
oter_id current_oter;
auto local_set_ter = [&]( oter_id & id ) {
const oter_type_str_id &current_type_id = current_oter->get_type_id();
const oter_type_str_id &incoming_type_id = id->get_type_id();
const bool current_type_same = current_type_id == incoming_type_id;
if( om_predecessors.empty() || ( !current_oter->is_linear() && !current_type_same ) ) {
// If we need a predecessor, we must have a predecessor no matter what.
// Or, if the oter to-be-pushed is not linear, push it only if the incoming oter is different.
om_predecessors.push_back( current_oter );
} else if( !current_type_same ) {
// Current oter is linear, incoming oter is different from current.
// If the last predecessor is the same type as the current type, overwrite.
// Else push the current type.
oter_id &last_predecessor = om_predecessors.back();
if( last_predecessor->get_type_id() == current_type_id ) {
last_predecessor = current_oter;
} else {
om_predecessors.push_back( current_oter );
}
}
current_oter = id;
};

current_oter = serialized_predecessors.front();
for( size_t i = 1; i < serialized_predecessors.size(); ++i ) {
local_set_ter( serialized_predecessors[i] );
}
local_set_ter( layer[p.z() + OVERMAP_DEPTH].terrain[p.xy()] );
}
predecessors_.insert_or_assign( p.first, std::move( deduped_predecessors ) );
predecessors_.insert_or_assign( p, std::move( om_predecessors ) );

// Reuse allocations because it's a good habit.
deduped_predecessors = std::move( p.second );
deduped_predecessors.clear();
om_predecessors = std::move( serialized_predecessors );
om_predecessors.clear();
}
}
}
Expand Down

0 comments on commit 2f4de78

Please sign in to comment.