From 6efe406c32e6bd56d89ec25a5ba4733c343452da Mon Sep 17 00:00:00 2001 From: PatrikLundell Date: Tue, 28 May 2024 17:08:14 +0200 Subject: [PATCH 01/18] Barely enough to get it to work --- src/map.cpp | 59 ++++++++++++++++++++++----- src/mapgen.cpp | 55 ++++++++++++++++++-------- src/submap.cpp | 105 +++++++++++++++++++++++++++++++++++++++++++++++++ src/submap.h | 7 ++++ 4 files changed, 199 insertions(+), 27 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index 0e23500e40c6e..a1f4aec6516d2 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -8246,11 +8246,6 @@ void map::saven( const tripoint &grid ) debugmsg( "Tried to save submap node (%d) but it's not loaded", gridn ); return; } - if( submap_to_save->get_ter( point_zero ) == ter_str_id::NULL_ID() ) { - // This is a serious error and should be signaled as soon as possible - debugmsg( "map::saven grid %s uninitialized!", grid.to_string() ); - return; - } const tripoint_abs_sm abs = abs_sub.xy() + grid; @@ -8314,8 +8309,51 @@ void map::loadn( const tripoint &grid, const bool update_vehicles ) this != &get_map() && get_map().inbounds( project_to( grid_abs_sub ) ); submap *tmpsub = MAPBUFFER.lookup_submap( grid_abs_sub ); - if( tmpsub == nullptr ) { - // It doesn't exist; we must generate it! + + bool incomplete = false; + + if( tmpsub != nullptr ) { + for( int x = 0; x < SEEX; x++ ) { + for( int y = 0; y < SEEY; y++ ) { + if( tmpsub->get_ter( {x, y} ) == t_null ) { + incomplete = true; + break; + } + } + if( incomplete ) { + break; + } + } + + if( incomplete ) { + const tripoint_abs_omt grid_abs_omt = project_to( grid_abs_sub ); + const oter_id terrain_type = overmap_buffer.ter( grid_abs_omt ); + ter_id ter = t_null; + + if( terrain_type == oter_open_air ) { + ter = ter_t_open_air; + } else if( terrain_type == oter_empty_rock || terrain_type == oter_deep_rock ) { + ter = ter_t_rock; + } else if( terrain_type == oter_solid_earth ) { + ter = ter_t_soil; + } + + if( ter != t_null ) { + for( int x = 0; x < SEEX; x++ ) { + for( int y = 0; y < SEEY; y++ ) { + if( tmpsub->get_ter( { x, y } ) == t_null ) { + tmpsub->set_ter( { x, y }, ter ); + } + } + } + + incomplete = false; + } + } + } + + if( tmpsub == nullptr || incomplete ) { + // It doesn't exist and we must generate it, or it contains only incomplete info! dbg( D_INFO | D_WARNING ) << "map::loadn: Missing mapbuffer data. Regenerating."; // Each overmap square is two nonants; to prevent overlap, generate only at @@ -8327,8 +8365,9 @@ void map::loadn( const tripoint &grid, const bool update_vehicles ) // Short-circuit if the map tile is uniform // TODO: Replace with json mapgen functions. - if( !generate_uniform_omt( grid_abs_sub_rounded, terrain_type ) ) { - tinymap tmp_map; + if( incomplete || !generate_uniform_omt( grid_abs_sub_rounded, terrain_type ) ) { + + smallmap tmp_map; tmp_map.main_cleanup_override( false ); tmp_map.generate( grid_abs_omt, calendar::turn ); _main_requires_cleanup |= main_inbounds && tmp_map.is_main_cleanup_queued(); @@ -9867,7 +9906,7 @@ size_t map::get_nonant( const tripoint &gridp ) const } if( zlevels ) { - const int indexz = gridp.z + OVERMAP_HEIGHT; // Can't be lower than 0 + const int indexz = gridp.z + OVERMAP_DEPTH; // Can't be lower than 0 return indexz + ( gridp.x + gridp.y * my_MAPSIZE ) * OVERMAP_LAYERS; } else { return gridp.x + gridp.y * my_MAPSIZE; diff --git a/src/mapgen.cpp b/src/mapgen.cpp index a9d37d70c20fe..faa3f661e9c54 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -32,6 +32,7 @@ #include "drawing_primitives.h" #include "enum_conversions.h" #include "enums.h" +#include "field.h" #include "field_type.h" #include "game.h" #include "game_constants.h" @@ -48,6 +49,7 @@ #include "map.h" #include "map_extras.h" #include "map_iterator.h" +#include "mapbuffer.h" #include "mapdata.h" #include "mapgen_functions.h" #include "mapgendata.h" @@ -82,6 +84,8 @@ #include "weighted_list.h" #include "creature_tracker.h" +static furn_id f_null; + static const furn_str_id furn_f_bed( "f_bed" ); static const furn_str_id furn_f_console( "f_console" ); static const furn_str_id furn_f_counter( "f_counter" ); @@ -217,18 +221,16 @@ void map::generate( const tripoint_abs_omt &p, const time_point &when ) // First we have to create new submaps and initialize them to 0 all over // We create all the submaps, even if we're not a tinymap, so that map // generation which overflows won't cause a crash. At the bottom of this - // function, we save the upper-left 4 submaps, and delete the rest. - // Mapgen is not z-level aware yet. Only actually initialize current z-level - // because other submaps won't be touched. + // function, we save the upper-left 4 submaps, plus the ones that were + // generated and modified, and delete the rest. + for( int gridx = 0; gridx < my_MAPSIZE; gridx++ ) { for( int gridy = 0; gridy < my_MAPSIZE; gridy++ ) { - const size_t grid_pos = get_nonant( { gridx, gridy, p_sm.z()} ); - if( getsubmap( grid_pos ) ) { - debugmsg( "Submap already exists at (%d, %d, %d)", gridx, gridy, p_sm.z() ); - continue; + for( int gridz = -OVERMAP_DEPTH; gridz <= OVERMAP_HEIGHT; gridz++ ) { + const size_t grid_pos = get_nonant( { gridx, gridy, gridz } ); + setsubmap( grid_pos, new submap() ); + // TODO: memory leak if the code below throws before the submaps get stored/deleted! } - setsubmap( grid_pos, new submap() ); - // TODO: memory leak if the code below throws before the submaps get stored/deleted! } } oter_id terrain_type = overmap_buffer.ter( p ); @@ -305,17 +307,36 @@ void map::generate( const tripoint_abs_omt &p, const time_point &when ) // Okay, we know who our neighbors are. Let's draw! // And finally save used submaps and delete the rest. + for( int i = 0; i < my_MAPSIZE; i++ ) { for( int j = 0; j < my_MAPSIZE; j++ ) { - dbg( D_INFO ) << "map::generate: submap (" << i << "," << j << ")"; + for( int k = -OVERMAP_DEPTH; k <= OVERMAP_HEIGHT; k++ ) { + dbg( D_INFO ) << "map::generate: submap (" << i << "," << j << ")"; - const tripoint pos( i, j, p_sm.z() ); - if( i <= 1 && j <= 1 ) { - saven( pos ); - } else { - const size_t grid_pos = get_nonant( pos ); - delete getsubmap( grid_pos ); - setsubmap( grid_pos, nullptr ); + const tripoint pos( i, j, k ); + submap *old_sub = MAPBUFFER.lookup_submap( abs_sub.xy() + tripoint{ i, j, k } ); + submap *new_sub = getsubmap( get_nonant( tripoint{ i, j, k } ) ); + + // We have to merge the data generated now with data generated earlier through + // Z level offsets. + + if( old_sub != nullptr && !old_sub->is_uniform() && !new_sub->is_uniform() ) { + old_sub->merge_submaps( new_sub ); + } + + if( i <= 1 && j <= 1 && k == p_sm.z() ) { + if( old_sub == nullptr || old_sub->is_uniform() ) { + saven( pos ); + } else { + delete new_sub; + } + } else { + if( ( old_sub == nullptr || old_sub->is_uniform() ) && !new_sub->is_uniform() ) { + saven( pos ); + } else { + delete new_sub; + } + } } } } diff --git a/src/submap.cpp b/src/submap.cpp index 00b1e880b1641..5e610eceadfa3 100644 --- a/src/submap.cpp +++ b/src/submap.cpp @@ -13,6 +13,10 @@ #include "units.h" #include "vehicle.h" +static furn_id f_null; + +static const furn_str_id furn_f_console( "f_console" ); + void maptile_soa::swap_soa_tile( const point &p1, const point &p2 ) { std::swap( ter[p1.x][p1.y], ter[p2.x][p2.y] ); @@ -376,3 +380,104 @@ void submap::update_lum_rem( const point &p, const item &i ) m->lum[p.x][p.y] = static_cast( count - 1 ); } } + + +void submap::merge_submaps( submap *copy_from ) +{ + this->field_count = 0; + + for( int x = 0; x < SEEX; x++ ) { + for( int y = 0; y < SEEY; y++ ) { + if( this->m->ter[x][y] == t_null ) { + this->m->ter[x][y] = copy_from->m->ter[x][y]; + if( copy_from->get_map_damage( {x, y} ) > 0 ) { + this->set_map_damage( {x, y}, copy_from->get_map_damage( { x, y } ) ); + } + } + + if( copy_from->m->frn[x][y] != f_null && this->m->frn[x][y] == f_null ) { + this->m->frn[x][y] = copy_from->m->frn[x][y]; + } + + this->m->lum[x][y] += copy_from->m->lum[x][y]; + + for( const item itm : copy_from->m->itm[x][y] ) { + this->m->itm[x][y].emplace( itm ); + } + + for( std::map::iterator it = copy_from->m->fld[x][y].begin(); + it != copy_from->m->fld[x][y].end(); it++ ) { + if( !this->m->fld[x][y].find_field( it->first, false ) ) { + this->m->fld[x][y].add_field( it->first, it->second.get_field_intensity(), + it->second.get_field_age() ); + } + } + + for( std::map::iterator it = this->m->fld[x][y].begin(); + it != this->m->fld[x][y].end(); it++ ) { + this->field_count++; + } + + if( copy_from->m->trp[x][y] != tr_null && this->m->trp[x][y] == tr_null ) { + this->m->trp[x][y] = copy_from->m->trp[x][y]; + } + + if( copy_from->m->rad[x][y] > 0 && this->m->rad[x][y] == 0 ) { + this->m->rad[x][y] = copy_from->m->rad[x][y]; + } + } + } + + for( const submap::cosmetic_t cos : copy_from->cosmetics ) { + bool found = false; + + for( size_t i = 0; i < this->cosmetics.size(); ++i ) { + if( this->cosmetics[i].pos == cos.pos ) { + found = true; + break; + } + } + + if( !found ) { + this->insert_cosmetic( cos.pos, cos.type, cos.str ); + } + } + + // TODO: Copy the active item cache + if( !copy_from->active_items.empty() ) { + debugmsg( "Active items found on copied submap which is not supported." ); + } + + if( copy_from->last_touched > this->last_touched ) { + this->last_touched = copy_from->last_touched; + } + + for( const spawn_point spawn : copy_from->spawns ) { + this->spawns.emplace_back( spawn ); + } + + for( const auto &vehicle : copy_from->vehicles ) { + this->vehicles.emplace_back( vehicle.get() ); + } + // Can't let that submap delete the vehicles when it's destroyed + copy_from->vehicles.clear(); + + if( !copy_from->partial_constructions.empty() ) { + debugmsg( "Partial constructions found on copied submap when none are expected." ); + } + + if( copy_from->camp ) { + debugmsg( "Camp found on copied submap when none is expected." ); + } + + for( const std::pair comp : copy_from->computers ) { + if( this->m->frn[comp.first.x][comp.first.y] == furn_f_console && + !this->get_computer( comp.first ) ) { + this->set_computer( comp.first, comp.second ); + } + } + + if( copy_from->temperature_mod != 0 && this->temperature_mod == 0 ) { + this->temperature_mod = copy_from->temperature_mod; + } +} diff --git a/src/submap.h b/src/submap.h index 5f439089ea546..3b44f664b731d 100644 --- a/src/submap.h +++ b/src/submap.h @@ -289,6 +289,13 @@ class submap return !static_cast( m ); } + // Copy the data from the copy_from submap onto the caller submap, merging their + // contents. When there is a conflict the caller's data is kept. + // The operation is intended for mapgen where data from the "official" generation + // may have to be merged with data generated from chunks targeting different + // Z levels. + void merge_submaps( submap *copy_from ); + std::vector cosmetics; // Textual "visuals" for squares active_item_cache active_items; From 94c17b0b078a05653fc1f6bea63a822821ed352e Mon Sep 17 00:00:00 2001 From: PatrikLundell Date: Tue, 28 May 2024 17:09:12 +0200 Subject: [PATCH 02/18] Campus used as test subject. To be reverted. --- .../mapgen/campus/buildings/admin_f0.json | 23 +++++---- .../open_areas/pedestrian_westside.json | 51 ++++++++++++++++++- 2 files changed, 63 insertions(+), 11 deletions(-) diff --git a/data/json/mapgen/campus/buildings/admin_f0.json b/data/json/mapgen/campus/buildings/admin_f0.json index aa7500d3c314f..12536354b6455 100644 --- a/data/json/mapgen/campus/buildings/admin_f0.json +++ b/data/json/mapgen/campus/buildings/admin_f0.json @@ -66,14 +66,14 @@ ".|,,|||||,,,,|||||______", "?|EE|<,,0,,,,:__________", ".|EE|,,,0,,,,:__________", - "?||||||||,,,,|__________", - "???b____|,,,,|__________", - "???b____|,,,,|__________", - "???b____||%%||__________", - "???b____________________", - "???b____________________", - "???b____________________", - "b??b____bbbbbbbbbbbbbbbb", + "?||||||||,,,,|1.......__", + "???b____|,,,,|........__", + "???b____|,,,,|........__", + "???b____||%%||........__", + "???b__________........__", + "???b__________........__", + "???b__________........__", + "b??b____bbbbbb........bb", "b??b____b.[...........[.", "b??b____b...[...[...[...", "bbbb____b.....[.........", @@ -82,7 +82,12 @@ ], "terrain": { }, "furniture": { }, - "palettes": [ "campus_common" ] + "palettes": [ "campus_common" ], + "nested": { + "1": { + "chunks": [ "campus_shack" ] + } + } } } ] diff --git a/data/json/mapgen/campus/open_areas/pedestrian_westside.json b/data/json/mapgen/campus/open_areas/pedestrian_westside.json index 8ec33c5c47447..e879edfa2911b 100644 --- a/data/json/mapgen/campus/open_areas/pedestrian_westside.json +++ b/data/json/mapgen/campus/open_areas/pedestrian_westside.json @@ -1,4 +1,46 @@ [ + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "campus_shack", + "object": { + "mapgensize": [ 8, 8 ], + "rows": [ + "wwwwwww ", + "w,,,,,w ", + "w,,,,,w ", + "w,,,,,w ", + "w,,,,,w ", + "w,,,,,w ", + "w,,,,,w ", + "w w " + ], + "flags": [ "ALLOW_TERRAIN_UNDER_OTHER_DATA" ], + "palettes": [ "fbml_2_metal_palette" ], + "place_nested": [ + { "chunks": [ "campus_shack_roof" ], "x": 0, "y": 0, "z": 1 } + ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "campus_shack_roof", + "object": { + "mapgensize": [ 8, 8 ], + "rows": [ + "rrrrrrr ", + "rrrrrrr ", + "rrrrrrr ", + "rrrrrrr ", + "rrrrrrr ", + "rrrrrrr ", + "rrrrrrr ", + "r r " + ], + "palettes": [ "fbml_2_metal_palette" ] + } + }, { "type": "mapgen", "method": "json", @@ -7,7 +49,7 @@ "object": { "fill_ter": "t_concrete", "rows": [ - "................................................", + "1...............................................", "................................................", "................................................", "................................................", @@ -34,7 +76,12 @@ ], "terrain": { }, "furniture": { }, - "palettes": [ "campus_common" ] + "palettes": [ "campus_common" ], + "nested": { + "1": { + "chunks": [ "campus_shack" ] + } + } } }, { From 70ed3631a2b8feefa8b5ce1ed7566a4127e835e7 Mon Sep 17 00:00:00 2001 From: PatrikLundell Date: Tue, 28 May 2024 17:51:17 +0200 Subject: [PATCH 03/18] Update data/json/mapgen/campus/buildings/admin_f0.json Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- data/json/mapgen/campus/buildings/admin_f0.json | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/data/json/mapgen/campus/buildings/admin_f0.json b/data/json/mapgen/campus/buildings/admin_f0.json index 12536354b6455..d49f0fa6f5f65 100644 --- a/data/json/mapgen/campus/buildings/admin_f0.json +++ b/data/json/mapgen/campus/buildings/admin_f0.json @@ -83,11 +83,7 @@ "terrain": { }, "furniture": { }, "palettes": [ "campus_common" ], - "nested": { - "1": { - "chunks": [ "campus_shack" ] - } - } + "nested": { "1": { "chunks": [ "campus_shack" ] } } } } ] From d47608eab9ea4fe4309f390ca173316681d1734e Mon Sep 17 00:00:00 2001 From: PatrikLundell Date: Tue, 28 May 2024 17:51:23 +0200 Subject: [PATCH 04/18] Update data/json/mapgen/campus/open_areas/pedestrian_westside.json Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- data/json/mapgen/campus/open_areas/pedestrian_westside.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/data/json/mapgen/campus/open_areas/pedestrian_westside.json b/data/json/mapgen/campus/open_areas/pedestrian_westside.json index e879edfa2911b..7eb3b9d1ed630 100644 --- a/data/json/mapgen/campus/open_areas/pedestrian_westside.json +++ b/data/json/mapgen/campus/open_areas/pedestrian_westside.json @@ -17,9 +17,7 @@ ], "flags": [ "ALLOW_TERRAIN_UNDER_OTHER_DATA" ], "palettes": [ "fbml_2_metal_palette" ], - "place_nested": [ - { "chunks": [ "campus_shack_roof" ], "x": 0, "y": 0, "z": 1 } - ] + "place_nested": [ { "chunks": [ "campus_shack_roof" ], "x": 0, "y": 0, "z": 1 } ] } }, { From 99ce7616a5caca34db5a3d0d2c7d111b4fba0ddd Mon Sep 17 00:00:00 2001 From: PatrikLundell Date: Tue, 28 May 2024 17:51:31 +0200 Subject: [PATCH 05/18] Update data/json/mapgen/campus/open_areas/pedestrian_westside.json Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- data/json/mapgen/campus/open_areas/pedestrian_westside.json | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/data/json/mapgen/campus/open_areas/pedestrian_westside.json b/data/json/mapgen/campus/open_areas/pedestrian_westside.json index 7eb3b9d1ed630..9505b3f25b0bb 100644 --- a/data/json/mapgen/campus/open_areas/pedestrian_westside.json +++ b/data/json/mapgen/campus/open_areas/pedestrian_westside.json @@ -75,11 +75,7 @@ "terrain": { }, "furniture": { }, "palettes": [ "campus_common" ], - "nested": { - "1": { - "chunks": [ "campus_shack" ] - } - } + "nested": { "1": { "chunks": [ "campus_shack" ] } } } }, { From c3cb33feb4a97bf0386b7856fe8956c7c1a1a147 Mon Sep 17 00:00:00 2001 From: PatrikLundell Date: Tue, 28 May 2024 18:17:16 +0200 Subject: [PATCH 06/18] demanded changes --- src/submap.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/submap.cpp b/src/submap.cpp index 5e610eceadfa3..cde55c9bf446c 100644 --- a/src/submap.cpp +++ b/src/submap.cpp @@ -401,7 +401,7 @@ void submap::merge_submaps( submap *copy_from ) this->m->lum[x][y] += copy_from->m->lum[x][y]; - for( const item itm : copy_from->m->itm[x][y] ) { + for( const item &itm : copy_from->m->itm[x][y] ) { this->m->itm[x][y].emplace( itm ); } @@ -428,7 +428,7 @@ void submap::merge_submaps( submap *copy_from ) } } - for( const submap::cosmetic_t cos : copy_from->cosmetics ) { + for( const submap::cosmetic_t &cos : copy_from->cosmetics ) { bool found = false; for( size_t i = 0; i < this->cosmetics.size(); ++i ) { @@ -452,7 +452,7 @@ void submap::merge_submaps( submap *copy_from ) this->last_touched = copy_from->last_touched; } - for( const spawn_point spawn : copy_from->spawns ) { + for( const spawn_point &spawn : copy_from->spawns ) { this->spawns.emplace_back( spawn ); } @@ -470,7 +470,7 @@ void submap::merge_submaps( submap *copy_from ) debugmsg( "Camp found on copied submap when none is expected." ); } - for( const std::pair comp : copy_from->computers ) { + for( const std::pair &comp : copy_from->computers ) { if( this->m->frn[comp.first.x][comp.first.y] == furn_f_console && !this->get_computer( comp.first ) ) { this->set_computer( comp.first, comp.second ); From 7e95cb3c8ea667eb56628e721c4d44c71695342e Mon Sep 17 00:00:00 2001 From: PatrikLundell Date: Wed, 29 May 2024 14:49:31 +0200 Subject: [PATCH 07/18] improved merging and removed failures to save submaps --- src/map.cpp | 4 ++++ src/mapgen.cpp | 16 +++++++++++----- src/submap.cpp | 28 ++++++++++++++++++---------- src/submap.h | 8 +++++--- 4 files changed, 38 insertions(+), 18 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index a1f4aec6516d2..b3acd5083103f 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -8264,6 +8264,10 @@ void map::saven( const tripoint &grid ) // Does not create or require a temporary map and does its own saving bool generate_uniform( const tripoint_abs_sm &p, const oter_id &oter ) { + if( MAPBUFFER.lookup_submap( p ) ) { + return false; + } + std::unique_ptr sm = std::make_unique(); if( oter == oter_open_air ) { sm->set_all_ter( ter_t_open_air, true ); diff --git a/src/mapgen.cpp b/src/mapgen.cpp index faa3f661e9c54..fe3103913eb32 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -311,7 +311,7 @@ void map::generate( const tripoint_abs_omt &p, const time_point &when ) for( int i = 0; i < my_MAPSIZE; i++ ) { for( int j = 0; j < my_MAPSIZE; j++ ) { for( int k = -OVERMAP_DEPTH; k <= OVERMAP_HEIGHT; k++ ) { - dbg( D_INFO ) << "map::generate: submap (" << i << "," << j << ")"; + dbg( D_INFO ) << "map::generate: submap (" << i << "," << j << "," << k << ")"; const tripoint pos( i, j, k ); submap *old_sub = MAPBUFFER.lookup_submap( abs_sub.xy() + tripoint{ i, j, k } ); @@ -320,18 +320,24 @@ void map::generate( const tripoint_abs_omt &p, const time_point &when ) // We have to merge the data generated now with data generated earlier through // Z level offsets. - if( old_sub != nullptr && !old_sub->is_uniform() && !new_sub->is_uniform() ) { - old_sub->merge_submaps( new_sub ); + if( old_sub != nullptr && !new_sub->is_uniform() ) { + if( k == p.z() ) { + old_sub->merge_submaps( new_sub, false ); + } else { + // We've generated an overlay and merge it with other overlays if this + // is at a higher Z level, or with the base map (possibly overlayed) if below. + old_sub->merge_submaps( new_sub, true ); + } } if( i <= 1 && j <= 1 && k == p_sm.z() ) { - if( old_sub == nullptr || old_sub->is_uniform() ) { + if( old_sub == nullptr ) { saven( pos ); } else { delete new_sub; } } else { - if( ( old_sub == nullptr || old_sub->is_uniform() ) && !new_sub->is_uniform() ) { + if( old_sub == nullptr && !new_sub->is_uniform() ) { saven( pos ); } else { delete new_sub; diff --git a/src/submap.cpp b/src/submap.cpp index cde55c9bf446c..7c65fcc77c138 100644 --- a/src/submap.cpp +++ b/src/submap.cpp @@ -381,21 +381,20 @@ void submap::update_lum_rem( const point &p, const item &i ) } } - -void submap::merge_submaps( submap *copy_from ) +void submap::merge_submaps( submap *copy_from, bool copy_from_is_overlay ) { this->field_count = 0; for( int x = 0; x < SEEX; x++ ) { for( int y = 0; y < SEEY; y++ ) { - if( this->m->ter[x][y] == t_null ) { + if( copy_from->m->ter[x][y] != t_null && ( copy_from_is_overlay || + this->m->ter[x][y] == t_null ) ) { this->m->ter[x][y] = copy_from->m->ter[x][y]; - if( copy_from->get_map_damage( {x, y} ) > 0 ) { - this->set_map_damage( {x, y}, copy_from->get_map_damage( { x, y } ) ); - } + this->set_map_damage( { x, y }, copy_from->get_map_damage( { x, y } ) ); } - if( copy_from->m->frn[x][y] != f_null && this->m->frn[x][y] == f_null ) { + if( copy_from->m->frn[x][y] != f_null && ( copy_from_is_overlay || + this->m->frn[x][y] == f_null ) ) { this->m->frn[x][y] = copy_from->m->frn[x][y]; } @@ -410,6 +409,10 @@ void submap::merge_submaps( submap *copy_from ) if( !this->m->fld[x][y].find_field( it->first, false ) ) { this->m->fld[x][y].add_field( it->first, it->second.get_field_intensity(), it->second.get_field_age() ); + } else if( copy_from_is_overlay ) { // Modify the field to match + field_entry *fld = this->m->fld[x][y].find_field( it->first, false ); + fld->set_field_intensity( it->second.get_field_intensity() ); + fld->set_field_age( it->second.get_field_age() ); } } @@ -418,11 +421,12 @@ void submap::merge_submaps( submap *copy_from ) this->field_count++; } - if( copy_from->m->trp[x][y] != tr_null && this->m->trp[x][y] == tr_null ) { + if( copy_from->m->trp[x][y] != tr_null && ( copy_from_is_overlay || + this->m->trp[x][y] == tr_null ) ) { this->m->trp[x][y] = copy_from->m->trp[x][y]; } - if( copy_from->m->rad[x][y] > 0 && this->m->rad[x][y] == 0 ) { + if( copy_from->m->rad[x][y] > 0 && ( copy_from_is_overlay || this->m->rad[x][y] == 0 ) ) { this->m->rad[x][y] = copy_from->m->rad[x][y]; } } @@ -432,7 +436,11 @@ void submap::merge_submaps( submap *copy_from ) bool found = false; for( size_t i = 0; i < this->cosmetics.size(); ++i ) { - if( this->cosmetics[i].pos == cos.pos ) { + if( this->cosmetics[i].pos == cos.pos && + this->cosmetics[i].type == cos.type ) { + if( this->cosmetics[i].str == cos.str || !copy_from_is_overlay ) { + this->cosmetics[i].str = cos.str; + } found = true; break; } diff --git a/src/submap.h b/src/submap.h index 3b44f664b731d..41229da0a36bc 100644 --- a/src/submap.h +++ b/src/submap.h @@ -289,12 +289,14 @@ class submap return !static_cast( m ); } - // Copy the data from the copy_from submap onto the caller submap, merging their - // contents. When there is a conflict the caller's data is kept. + // Merge the contents of the two submaps onto the target submap. If there is a + // conflict the overlay wins out. Note that it's technically possible for both + // submaps to actually be overlays, but the one that's not called out is treated + // as the basic map for merging precedent purposes. // The operation is intended for mapgen where data from the "official" generation // may have to be merged with data generated from chunks targeting different // Z levels. - void merge_submaps( submap *copy_from ); + void merge_submaps( submap *copy_from, bool copy_from_is_overlay ); std::vector cosmetics; // Textual "visuals" for squares From acc2445c01d6897a54fce2ada551cf7a65ae58ca Mon Sep 17 00:00:00 2001 From: PatrikLundell Date: Wed, 29 May 2024 16:23:18 +0200 Subject: [PATCH 08/18] test data: place terrain &furniture at level below --- .../mapgen/campus/buildings/admin_f1.json | 43 ++++++++++++++++++- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/data/json/mapgen/campus/buildings/admin_f1.json b/data/json/mapgen/campus/buildings/admin_f1.json index 567db52e6af0c..f9ddc09406ef3 100644 --- a/data/json/mapgen/campus/buildings/admin_f1.json +++ b/data/json/mapgen/campus/buildings/admin_f1.json @@ -1,4 +1,42 @@ [ + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "campus_test_stair_up", + "object": { + "mapgensize": [ 1, 1 ], + "rows": [ "Ö" ], + "flags": [ "ALLOW_TERRAIN_UNDER_OTHER_DATA" ], + "terrain": { "Ö": "t_stairs_up" } + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "campus_test_chair", + "object": { + "mapgensize": [ 1, 1 ], + "rows": [ "Ä" ], + "flags": [ "ALLOW_TERRAIN_UNDER_OTHER_DATA" ], + "terrain": { }, + "furniture": { "Ä": "f_armchair" } + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "campus_test_stair_down", + "object": { + "mapgensize": [ 1, 1 ], + "rows": [ "Ö" ], + "flags": [ "ALLOW_TERRAIN_UNDER_OTHER_DATA" ], + "terrain": { "Ö": "t_stairs_down" }, + "place_nested": [ + { "chunks": [ "campus_test_stair_up" ], "x": 0, "y": 0, "z": -1 }, + { "chunks": [ "campus_test_chair" ], "x": 1, "y": 1, "z": -1 } + ] + } + }, { "type": "mapgen", "method": "json", @@ -66,7 +104,7 @@ " |,,|||||,,,,||||| ", " |EE|>,,0,,,,: ", " |EE|<,,0,,,,: ", - " ||||||||,,,,| ", + " ||||||||,,Ö,| ", " |,,,,| ", " |,,,,| ", " |||||| ", @@ -82,7 +120,8 @@ ], "terrain": { }, "furniture": { }, - "palettes": [ "campus_common" ] + "palettes": [ "campus_common" ], + "nested": { "Ö": { "chunks": [ "campus_test_stair_down" ] } } } } ] From b46978336b5a7719de5123339dfec237f5c29647 Mon Sep 17 00:00:00 2001 From: PatrikLundell Date: Thu, 30 May 2024 16:26:06 +0200 Subject: [PATCH 09/18] Improved generate + supported editmap usage --- src/editmap.cpp | 56 ++++++------ src/map.cpp | 2 +- src/map.h | 2 +- src/mapgen.cpp | 225 +++++++++++++++++++++++++++--------------------- 4 files changed, 157 insertions(+), 128 deletions(-) diff --git a/src/editmap.cpp b/src/editmap.cpp index 790f1276ccbe7..731d917bff2d9 100644 --- a/src/editmap.cpp +++ b/src/editmap.cpp @@ -1844,10 +1844,10 @@ void editmap::mapgen_preview( const real_coords &tc, uilist &gmenu ) // Copy to store the original value, to restore it upon canceling const oter_id orig_oters = omt_ref; overmap_buffer.ter_set( omt_pos, oter_id( gmenu.ret ) ); - tinymap tmpmap; + smallmap tmpmap; // TODO: add a do-not-save-generated-submaps parameter // TODO: keep track of generated submaps to delete them properly and to avoid memory leaks - tmpmap.generate( omt_pos, calendar::turn ); + tmpmap.generate( omt_pos, calendar::turn, false ); gmenu.border_color = c_light_gray; gmenu.hilight_color = c_black_white; @@ -1891,7 +1891,7 @@ void editmap::mapgen_preview( const real_coords &tc, uilist &gmenu ) overmap_buffer.ter_set( omt_pos, oter_id( gmenu.selected ) ); cleartmpmap( tmpmap ); tmpmap.generate( omt_pos, - calendar::turn ); + calendar::turn, false ); } if( showpreview ) { @@ -1916,7 +1916,7 @@ void editmap::mapgen_preview( const real_coords &tc, uilist &gmenu ) if( gpmenu.ret == 0 ) { cleartmpmap( tmpmap ); tmpmap.generate( omt_pos, - calendar::turn ); + calendar::turn, false ); } else if( gpmenu.ret == 1 ) { tmpmap.rotate( 1 ); } else if( gpmenu.ret == 2 ) { @@ -1932,27 +1932,29 @@ void editmap::mapgen_preview( const real_coords &tc, uilist &gmenu ) for( int x = 0; x < 2; x++ ) { for( int y = 0; y < 2; y++ ) { - // Apply previewed mapgen to map. Since this is a function for testing, we try avoid triggering - // functions that would alter the results - const tripoint dest_pos = target_sub + tripoint( x, y, target.z() ); - const tripoint src_pos = tripoint{ x, y, target.z()}; - - submap *destsm = here.get_submap_at_grid( dest_pos ); - submap *srcsm = tmpmap.get_submap_at_grid( src_pos ); - if( srcsm == nullptr || destsm == nullptr ) { - debugmsg( "Tried to apply previewed mapgen at (%d,%d,%d) but the submap is not loaded", src_pos.x, - src_pos.y, src_pos.z ); - continue; - } + for( int z = -OVERMAP_DEPTH; z <= OVERMAP_HEIGHT; z++ ) { + // Apply previewed mapgen to map. Since this is a function for testing, we try avoid triggering + // functions that would alter the results + const tripoint dest_pos = target_sub + tripoint( x, y, z ); + const tripoint src_pos = tripoint{ x, y, z }; + + submap *destsm = here.get_submap_at_grid( dest_pos ); + submap *srcsm = tmpmap.get_submap_at_grid( src_pos ); + if( srcsm == nullptr || destsm == nullptr ) { + debugmsg( "Tried to apply previewed mapgen at (%d,%d,%d) but the submap is not loaded", src_pos.x, + src_pos.y, src_pos.z ); + continue; + } - std::swap( *destsm, *srcsm ); + std::swap( *destsm, *srcsm ); - for( auto &veh : destsm->vehicles ) { - veh->sm_pos = dest_pos; - } + for( auto &veh : destsm->vehicles ) { + veh->sm_pos = dest_pos; + } - if( !destsm->spawns.empty() ) { // trigger spawnpoints - here.spawn_monsters( true ); + if( !destsm->spawns.empty() ) { // trigger spawnpoints + here.spawn_monsters( true ); + } } } } @@ -2216,8 +2218,10 @@ void editmap::cleartmpmap( tinymap &tmpmap ) const smap = nullptr; } - level_cache &ch = tmpmap.get_cache( target.z() ); - ch.clear_vehicle_cache(); - ch.vehicle_list.clear(); - ch.zone_vehicles.clear(); + for( int z = -OVERMAP_DEPTH; z <= OVERMAP_HEIGHT; z++ ) { + level_cache &ch = tmpmap.get_cache( z ); + ch.clear_vehicle_cache(); + ch.vehicle_list.clear(); + ch.zone_vehicles.clear(); + } } diff --git a/src/map.cpp b/src/map.cpp index b3acd5083103f..2d3371bd03d47 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -8373,7 +8373,7 @@ void map::loadn( const tripoint &grid, const bool update_vehicles ) smallmap tmp_map; tmp_map.main_cleanup_override( false ); - tmp_map.generate( grid_abs_omt, calendar::turn ); + tmp_map.generate( grid_abs_omt, calendar::turn, true ); _main_requires_cleanup |= main_inbounds && tmp_map.is_main_cleanup_queued(); } diff --git a/src/map.h b/src/map.h index 56b6b7c2bb0fe..cbb27c37ec417 100644 --- a/src/map.h +++ b/src/map.h @@ -1862,7 +1862,7 @@ class map // mapgen.cpp functions // The code relies on the submap coordinate falling on omt boundaries, so taking a // tripoint_abs_omt coordinate guarantees this will be fulfilled. - void generate( const tripoint_abs_omt &p, const time_point &when ); + void generate( const tripoint_abs_omt &p, const time_point &when, bool save_results ); void place_spawns( const mongroup_id &group, int chance, const point_bub_ms &p1, const point_bub_ms &p2, int z_level, float density, bool individual = false, bool friendly = false, diff --git a/src/mapgen.cpp b/src/mapgen.cpp index fe3103913eb32..10c107ac7ade1 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -210,137 +210,162 @@ static constexpr int MON_RADIUS = 3; static void science_room( map *m, const point &p1, const point &p2, int z, int rotate ); -void map::generate( const tripoint_abs_omt &p, const time_point &when ) +// Assumptions: +// - The map supplied is empty, i.e. no grid entries are in use +// - The map supports Z levels. +void map::generate( const tripoint_abs_omt &p, const time_point &when, bool save_results ) { dbg( D_INFO ) << "map::generate( g[" << g.get() << "], p[" << p << "], " "when[" << to_string( when ) << "] )"; - const tripoint_abs_sm p_sm = project_to( p ); - set_abs_sub( p_sm ); - - // First we have to create new submaps and initialize them to 0 all over - // We create all the submaps, even if we're not a tinymap, so that map - // generation which overflows won't cause a crash. At the bottom of this - // function, we save the upper-left 4 submaps, plus the ones that were - // generated and modified, and delete the rest. - + // Prepare the canvas... for( int gridx = 0; gridx < my_MAPSIZE; gridx++ ) { for( int gridy = 0; gridy < my_MAPSIZE; gridy++ ) { for( int gridz = -OVERMAP_DEPTH; gridz <= OVERMAP_HEIGHT; gridz++ ) { - const size_t grid_pos = get_nonant( { gridx, gridy, gridz } ); - setsubmap( grid_pos, new submap() ); - // TODO: memory leak if the code below throws before the submaps get stored/deleted! + const tripoint pos( gridx, gridy, gridz ); + const size_t grid_pos = get_nonant( pos ); + if( !save_results || MAPBUFFER.lookup_submap( abs_sub.xy() + pos ) == nullptr ) { + setsubmap( grid_pos, new submap() ); + } else { + setsubmap( grid_pos, MAPBUFFER.lookup_submap( abs_sub.xy() + pos ) ); + } } } } - oter_id terrain_type = overmap_buffer.ter( p ); - // This attempts to scale density of zombies inversely with distance from the nearest city. - // In other words, make city centers dense and perimeters sparse. - float density = 0.0f; - for( int i = -MON_RADIUS; i <= MON_RADIUS; i++ ) { - for( int j = -MON_RADIUS; j <= MON_RADIUS; j++ ) { - density += overmap_buffer.ter( p + point( i, j ) )->get_mondensity(); - } + const tripoint_abs_sm p_sm_base = project_to( p ); + std::vector saved_overlay; + saved_overlay.reserve( 4 ); + for( size_t index = 0; index <= 3; index++ ) { + saved_overlay.emplace_back( nullptr ); } - density = density / 100; - mapgendata dat( p, *this, density, when, nullptr ); - draw_map( dat ); + // We're generating all Z levels in one go to be able to account for dependencies + // between levels. We iterate from the top down based on the assumption it is + // more common to add overlays on other Z levels upwards than downwards, so + // going downwards we can immediately apply overlays onto the already generated + // map, while overlays further down will have to be reapplied when the basic + // map exists. - // At some point, we should add region information so we can grab the appropriate extras - map_extras &this_ex = region_settings_map["default"].region_extras[terrain_type->get_extras()]; - map_extras ex = this_ex.filtered_by( dat ); - if( this_ex.chance > 0 && ex.values.empty() && !this_ex.values.empty() ) { - DebugLog( D_WARNING, D_MAP_GEN ) << "Overmap terrain " << terrain_type->get_type_id().str() << - " (extra type \"" << terrain_type->get_extras() << - "\") zlevel = " << p.z() << - " is out of range of all assigned map extras. Skipping map extra generation."; - } else if( ex.chance > 0 && one_in( ex.chance ) ) { - map_extra_id *extra = ex.values.pick(); - if( extra == nullptr ) { - debugmsg( "failed to pick extra for type %s (ter = %s)", terrain_type->get_extras(), - terrain_type->get_type_id().str() ); - } else { - MapExtras::apply_function( *ex.values.pick(), *this, tripoint_abs_sm( abs_sub ) ); + for( int gridz = OVERMAP_HEIGHT; gridz >= -OVERMAP_DEPTH; gridz-- ) { + const tripoint_abs_sm p_sm = {p_sm_base.xy(), gridz}; + set_abs_sub( p_sm ); + + for( int gridx = 0; gridx <= 1; gridx++ ) { + for( int gridy = 0; gridy <= 1; gridy++ ) { + const tripoint pos( gridx, gridy, gridz ); + const size_t grid_pos = get_nonant( pos ); + if( MAPBUFFER.lookup_submap( abs_sub.xy() + pos ) == nullptr && + !getsubmap( grid_pos )->is_uniform() ) { + saved_overlay[gridx + gridy * 2] = getsubmap( grid_pos ); + setsubmap( grid_pos, new submap() ); + } + } } - } - const overmap_static_spawns &spawns = terrain_type->get_static_spawns(); + oter_id terrain_type = overmap_buffer.ter( tripoint_abs_omt( p.xy(), gridz ) ); - float spawn_density = 1.0f; - if( MonsterGroupManager::is_animal( spawns.group ) ) { - spawn_density = get_option< float >( "SPAWN_ANIMAL_DENSITY" ); - } else { - spawn_density = get_option< float >( "SPAWN_DENSITY" ); - } + // This attempts to scale density of zombies inversely with distance from the nearest city. + // In other words, make city centers dense and perimeters sparse. + float density = 0.0f; + for( int i = -MON_RADIUS; i <= MON_RADIUS; i++ ) { + for( int j = -MON_RADIUS; j <= MON_RADIUS; j++ ) { + density += overmap_buffer.ter( p + point( i, j ) )->get_mondensity(); + } + } + density = density / 100; - // Apply a multiplier to the number of monsters for really high densities. - float odds_after_density = spawns.chance * spawn_density; - const float max_odds = 100 - ( 100 - spawns.chance ) / 2.0f; - float density_multiplier = 1.0f; - if( odds_after_density > max_odds ) { - density_multiplier = 1.0f * odds_after_density / max_odds; - odds_after_density = max_odds; - } - const int spawn_count = roll_remainder( density_multiplier ); + mapgendata dat( { p.xy(), gridz}, *this, density, when, nullptr ); + if( !save_results || MAPBUFFER.lookup_submap( p_sm ) == nullptr ) { + draw_map( dat ); + } - if( spawns.group && x_in_y( odds_after_density, 100 ) ) { - int pop = spawn_count * rng( spawns.population.min, spawns.population.max ); - for( ; pop > 0; pop-- ) { - std::vector spawn_details = - MonsterGroupManager::GetResultFromGroup( spawns.group, &pop ); - for( const MonsterGroupResult &mgr : spawn_details ) { - if( !mgr.name ) { - continue; - } - if( const std::optional pt = - random_point( *this, [this]( const tripoint & n ) { - return passable( n ); - } ) ) { - const tripoint_bub_ms pnt = tripoint_bub_ms( pt.value() ); - add_spawn( mgr, pnt ); + // Merge the overlays generated earlier into the current Z level now we have the base map on it. + for( int gridx = 0; gridx <= 1; gridx++ ) { + for( int gridy = 0; gridy <= 1; gridy++ ) { + const tripoint pos( gridx, gridy, gridz ); + const size_t index = gridx + gridy * 2; + if( saved_overlay.at( index ) != nullptr ) { + const size_t grid_pos = get_nonant( pos ); + getsubmap( grid_pos )->merge_submaps( saved_overlay.at( index ), true ); + delete saved_overlay.at( index ); + saved_overlay[index] = nullptr; } } } - } - // Okay, we know who our neighbors are. Let's draw! - // And finally save used submaps and delete the rest. + // At some point, we should add region information so we can grab the appropriate extras + map_extras &this_ex = region_settings_map["default"].region_extras[terrain_type->get_extras()]; + map_extras ex = this_ex.filtered_by( dat ); + if( this_ex.chance > 0 && ex.values.empty() && !this_ex.values.empty() ) { + DebugLog( D_WARNING, D_MAP_GEN ) << "Overmap terrain " << terrain_type->get_type_id().str() << + " (extra type \"" << terrain_type->get_extras() << + "\") zlevel = " << p.z() << + " is out of range of all assigned map extras. Skipping map extra generation."; + } else if( ex.chance > 0 && one_in( ex.chance ) ) { + map_extra_id *extra = ex.values.pick(); + if( extra == nullptr ) { + debugmsg( "failed to pick extra for type %s (ter = %s)", terrain_type->get_extras(), + terrain_type->get_type_id().str() ); + } else { + MapExtras::apply_function( *ex.values.pick(), *this, tripoint_abs_sm( abs_sub ) ); + } + } - for( int i = 0; i < my_MAPSIZE; i++ ) { - for( int j = 0; j < my_MAPSIZE; j++ ) { - for( int k = -OVERMAP_DEPTH; k <= OVERMAP_HEIGHT; k++ ) { - dbg( D_INFO ) << "map::generate: submap (" << i << "," << j << "," << k << ")"; + const overmap_static_spawns &spawns = terrain_type->get_static_spawns(); - const tripoint pos( i, j, k ); - submap *old_sub = MAPBUFFER.lookup_submap( abs_sub.xy() + tripoint{ i, j, k } ); - submap *new_sub = getsubmap( get_nonant( tripoint{ i, j, k } ) ); + float spawn_density = 1.0f; + if( MonsterGroupManager::is_animal( spawns.group ) ) { + spawn_density = get_option< float >( "SPAWN_ANIMAL_DENSITY" ); + } else { + spawn_density = get_option< float >( "SPAWN_DENSITY" ); + } - // We have to merge the data generated now with data generated earlier through - // Z level offsets. + // Apply a multiplier to the number of monsters for really high densities. + float odds_after_density = spawns.chance * spawn_density; + const float max_odds = 100 - ( 100 - spawns.chance ) / 2.0f; + float density_multiplier = 1.0f; + if( odds_after_density > max_odds ) { + density_multiplier = 1.0f * odds_after_density / max_odds; + odds_after_density = max_odds; + } + const int spawn_count = roll_remainder( density_multiplier ); - if( old_sub != nullptr && !new_sub->is_uniform() ) { - if( k == p.z() ) { - old_sub->merge_submaps( new_sub, false ); - } else { - // We've generated an overlay and merge it with other overlays if this - // is at a higher Z level, or with the base map (possibly overlayed) if below. - old_sub->merge_submaps( new_sub, true ); + if( spawns.group && x_in_y( odds_after_density, 100 ) ) { + int pop = spawn_count * rng( spawns.population.min, spawns.population.max ); + for( ; pop > 0; pop-- ) { + std::vector spawn_details = + MonsterGroupManager::GetResultFromGroup( spawns.group, &pop ); + for( const MonsterGroupResult &mgr : spawn_details ) { + if( !mgr.name ) { + continue; + } + if( const std::optional pt = + random_point( *this, [this]( const tripoint & n ) { + return passable( n ); + } ) ) { + const tripoint_bub_ms pnt = tripoint_bub_ms( pt.value() ); + add_spawn( mgr, pnt ); } } + } + } + } - if( i <= 1 && j <= 1 && k == p_sm.z() ) { - if( old_sub == nullptr ) { - saven( pos ); - } else { - delete new_sub; - } - } else { - if( old_sub == nullptr && !new_sub->is_uniform() ) { - saven( pos ); + if( save_results ) { + for( int gridx = 0; gridx < my_MAPSIZE; gridx++ ) { + for( int gridy = 0; gridy < my_MAPSIZE; gridy++ ) { + for( int gridz = -OVERMAP_DEPTH; gridz <= OVERMAP_HEIGHT; gridz++ ) { + const tripoint pos( gridx, gridy, gridz ); + const size_t grid_pos = get_nonant( pos ); + if( gridx <= 1 && gridy <= 1 ) { + if( MAPBUFFER.lookup_submap( abs_sub.xy() + pos ) == nullptr ) { + saven( {gridx, gridy, gridz} ); + } } else { - delete new_sub; + if( MAPBUFFER.lookup_submap( abs_sub.xy() + pos ) == nullptr ) { + delete getsubmap( grid_pos ); + } } } } From fd8941a7b082e2c10b593f1289eff01a093091fb Mon Sep 17 00:00:00 2001 From: PatrikLundell Date: Thu, 30 May 2024 16:59:00 +0200 Subject: [PATCH 10/18] missed the changed test file --- tests/overmap_test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/overmap_test.cpp b/tests/overmap_test.cpp index 37a5c270c4abc..667a5a871f9bc 100644 --- a/tests/overmap_test.cpp +++ b/tests/overmap_test.cpp @@ -451,8 +451,8 @@ TEST_CASE( "overmap_terrain_coverage", "[overmap][slow]" ) for( int i = 0; i < sample_size; ++i ) { // clear the generated maps so we keep getting new results. MAPBUFFER.clear_outside_reality_bubble(); - tinymap tm; - tm.generate( pos, calendar::turn ); + smallmap tm; + tm.generate( pos, calendar::turn, false ); bool found = tally_items( item_counts, p.second.item_counts, tm ); if( enable_item_demographics && found && !p.second.found ) { goal_samples = std::pow( std::log( std::max( 10, count ) ), 3 ); From fa3812dff9344460945f6263d012bd51cb64de76 Mon Sep 17 00:00:00 2001 From: PatrikLundell Date: Fri, 31 May 2024 13:11:09 +0200 Subject: [PATCH 11/18] Moved uniform mapgen into generate & merged the loadn operations --- src/map.cpp | 230 ++++++++++++++++++++----------------------------- src/map.h | 5 +- src/mapgen.cpp | 11 ++- 3 files changed, 108 insertions(+), 138 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index 2d3371bd03d47..030ffe62f38c6 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -8260,24 +8260,29 @@ void map::saven( const tripoint &grid ) MAPBUFFER.add_submap( abs, submap_to_save ); } +ter_str_id uniform_terrain( const oter_id &oter ) +{ + if( oter == oter_open_air ) { + return ter_t_open_air; + } else if( oter == oter_empty_rock || oter == oter_deep_rock ) { + return ter_t_rock; + } else if( oter == oter_solid_earth ) { + return ter_t_soil; + } else { + return t_null.id(); + } +} + // Optimized mapgen function that only works properly for very simple overmap types // Does not create or require a temporary map and does its own saving -bool generate_uniform( const tripoint_abs_sm &p, const oter_id &oter ) +bool generate_uniform( const tripoint_abs_sm &p, const ter_str_id &ter ) { if( MAPBUFFER.lookup_submap( p ) ) { return false; } std::unique_ptr sm = std::make_unique(); - if( oter == oter_open_air ) { - sm->set_all_ter( ter_t_open_air, true ); - } else if( oter == oter_empty_rock || oter == oter_deep_rock ) { - sm->set_all_ter( ter_t_rock, true ); - } else if( oter == oter_solid_earth ) { - sm->set_all_ter( ter_t_soil, true ); - } else { - return false; - } + sm->set_all_ter( ter, true ); sm->last_touched = calendar::turn; return MAPBUFFER.add_submap( p, sm ); } @@ -8287,170 +8292,125 @@ bool generate_uniform_omt( const tripoint_abs_sm &p, const oter_id &terrain_type dbg( D_INFO ) << "generate_uniform p: " << p << " terrain_type: " << terrain_type.id().str(); + const ter_str_id ter = uniform_terrain( terrain_type ); + + if( ter == t_null.id() ) { + return false; + } + bool ret = true; for( int xd = 0; xd <= 1; xd++ ) { for( int yd = 0; yd <= 1; yd++ ) { - ret &= generate_uniform( p + point( xd, yd ), terrain_type ); + ret &= generate_uniform( p + point( xd, yd ), ter ); } } return ret; } -void map::loadn( const tripoint &grid, const bool update_vehicles ) +void map::loadn( const point &grid, bool update_vehicles ) { dbg( D_INFO ) << "map::loadn(game[" << g.get() << "], worldx[" << abs_sub.x() << "], worldy[" << abs_sub.y() << "], grid " << grid << ")"; - const tripoint_abs_sm grid_abs_sub = abs_sub.xy() + grid; - const size_t gridn = get_nonant( grid ); - - dbg( D_INFO ) << "map::loadn grid_abs_sub: " << grid_abs_sub << " gridn: " << gridn; - - const int old_abs_z = abs_sub.z(); // Ugly, but necessary at the moment - abs_sub.z() = grid.z; + const tripoint_abs_sm grid_abs_sub = abs_sub + grid; + const tripoint_abs_omt grid_abs_omt = project_to( grid_abs_sub ); + // Get the base submap "grid" is an offset from. + const tripoint_abs_sm grid_sm_base = project_to( grid_abs_omt ); + bool map_incomplete = false; bool const main_inbounds = this != &get_map() && get_map().inbounds( project_to( grid_abs_sub ) ); - submap *tmpsub = MAPBUFFER.lookup_submap( grid_abs_sub ); - - bool incomplete = false; - - if( tmpsub != nullptr ) { - for( int x = 0; x < SEEX; x++ ) { - for( int y = 0; y < SEEY; y++ ) { - if( tmpsub->get_ter( {x, y} ) == t_null ) { - incomplete = true; + // It might be possible to just check the (0, 0) submap as we should never have + // a case where only one submap is missing from an OMT level. + for( int gridx = 0; gridx <= 1; gridx++ ) { + for( int gridy = 0; gridy <= 1; gridy++ ) { + for( int gridz = -OVERMAP_DEPTH; gridz <= OVERMAP_HEIGHT; gridz++ ) { + const tripoint grid_pos( gridx, gridy, gridz ); + if( MAPBUFFER.lookup_submap( grid_sm_base.xy() + grid_pos ) == nullptr ) { + map_incomplete = true; break; } } - if( incomplete ) { - break; - } } + } - if( incomplete ) { - const tripoint_abs_omt grid_abs_omt = project_to( grid_abs_sub ); - const oter_id terrain_type = overmap_buffer.ter( grid_abs_omt ); - ter_id ter = t_null; - - if( terrain_type == oter_open_air ) { - ter = ter_t_open_air; - } else if( terrain_type == oter_empty_rock || terrain_type == oter_deep_rock ) { - ter = ter_t_rock; - } else if( terrain_type == oter_solid_earth ) { - ter = ter_t_soil; - } - - if( ter != t_null ) { - for( int x = 0; x < SEEX; x++ ) { - for( int y = 0; y < SEEY; y++ ) { - if( tmpsub->get_ter( { x, y } ) == t_null ) { - tmpsub->set_ter( { x, y }, ter ); - } - } - } + if( map_incomplete ) { + smallmap tmp_map; + tmp_map.main_cleanup_override( false ); + tmp_map.generate( grid_abs_omt, calendar::turn, true ); + _main_requires_cleanup |= main_inbounds && tmp_map.is_main_cleanup_queued(); - incomplete = false; + for( int gridz = -OVERMAP_DEPTH; gridz <= OVERMAP_HEIGHT; gridz++ ) { + const tripoint_abs_sm pos = {grid_sm_base.xy(), gridz }; + submap *tmpsub = MAPBUFFER.lookup_submap( pos ); + if( tmpsub == nullptr ) { + dbg( D_ERROR ) << "failed to generate a submap at " << pos; + debugmsg( "failed to generate a submap at %s", pos.to_string() ); + return; } } } - if( tmpsub == nullptr || incomplete ) { - // It doesn't exist and we must generate it, or it contains only incomplete info! - dbg( D_INFO | D_WARNING ) << "map::loadn: Missing mapbuffer data. Regenerating."; - - // Each overmap square is two nonants; to prevent overlap, generate only at - // squares divisible by 2. - const tripoint_abs_omt grid_abs_omt = project_to( grid_abs_sub ); - const tripoint_abs_sm grid_abs_sub_rounded = project_to( grid_abs_omt ); + const int start_z = zlevels ? -OVERMAP_DEPTH : abs_sub.z(); + const int stop_z = zlevels ? OVERMAP_HEIGHT : abs_sub.z(); - const oter_id terrain_type = overmap_buffer.ter( grid_abs_omt ); + submap *tmpsub; - // Short-circuit if the map tile is uniform - // TODO: Replace with json mapgen functions. - if( incomplete || !generate_uniform_omt( grid_abs_sub_rounded, terrain_type ) ) { - - smallmap tmp_map; - tmp_map.main_cleanup_override( false ); - tmp_map.generate( grid_abs_omt, calendar::turn, true ); - _main_requires_cleanup |= main_inbounds && tmp_map.is_main_cleanup_queued(); + for( int z = start_z; z <= stop_z; z++ ) { + const tripoint_abs_sm pos = { grid_abs_sub.xy(), z }; + // New submap changes the content of the map and all caches must be recalculated + set_transparency_cache_dirty( z ); + set_seen_cache_dirty( z ); + set_outside_cache_dirty( z ); + set_floor_cache_dirty( z ); + set_pathfinding_cache_dirty( z ); + tmpsub = MAPBUFFER.lookup_submap( pos ); + setsubmap( get_nonant( { grid.x, grid.y, z } ), tmpsub ); + if( !tmpsub->active_items.empty() ) { + submaps_with_active_items_dirty.emplace( pos ); } - - // This is the same call to MAPBUFFER as above! - tmpsub = MAPBUFFER.lookup_submap( grid_abs_sub ); - if( tmpsub == nullptr ) { - dbg( D_ERROR ) << "failed to generate a submap at " << grid_abs_sub; - debugmsg( "failed to generate a submap at %s", grid_abs_sub.to_string() ); - return; + if( tmpsub->field_count > 0 ) { + get_cache( z ).field_cache.set( grid.x + grid.y * MAPSIZE ); } - } - // New submap changes the content of the map and all caches must be recalculated - set_transparency_cache_dirty( grid.z ); - set_seen_cache_dirty( grid.z ); - set_outside_cache_dirty( grid.z ); - set_floor_cache_dirty( grid.z ); - set_pathfinding_cache_dirty( grid.z ); - setsubmap( gridn, tmpsub ); - if( !tmpsub->active_items.empty() ) { - submaps_with_active_items_dirty.emplace( grid_abs_sub ); - } - if( tmpsub->field_count > 0 ) { - get_cache( grid.z ).field_cache.set( grid.x + grid.y * MAPSIZE ); - } - - // Destroy bugged no-part vehicles - auto &veh_vec = tmpsub->vehicles; - for( auto iter = veh_vec.begin(); iter != veh_vec.end(); ) { - vehicle *veh = iter->get(); - if( veh->part_count() > 0 ) { - // Always fix submap coordinates for easier Z-level-related operations - veh->sm_pos = grid; - iter++; - if( main_inbounds ) { - _main_requires_cleanup = true; - } - } else { - if( veh->tracking_on ) { - overmap_buffer.remove_vehicle( veh ); + // Destroy bugged no-part vehicles + auto &veh_vec = tmpsub->vehicles; + for( auto iter = veh_vec.begin(); iter != veh_vec.end(); ) { + vehicle *veh = iter->get(); + if( veh->part_count() > 0 ) { + // Always fix submap coordinates for easier Z-level-related operations + veh->sm_pos = { grid, z }; + iter++; + if( main_inbounds ) { + _main_requires_cleanup = true; + } + } else { + if( veh->tracking_on ) { + overmap_buffer.remove_vehicle( veh ); + } + dirty_vehicle_list.erase( veh ); + iter = veh_vec.erase( iter ); } - dirty_vehicle_list.erase( veh ); - iter = veh_vec.erase( iter ); } - } - // Update vehicle data - if( update_vehicles ) { - level_cache &map_cache = get_cache( grid.z ); - for( const auto &veh : tmpsub->vehicles ) { - // Only add if not tracking already. - if( map_cache.vehicle_list.find( veh.get() ) == map_cache.vehicle_list.end() ) { - map_cache.vehicle_list.insert( veh.get() ); - if( !veh->loot_zones.empty() ) { - map_cache.zone_vehicles.insert( veh.get() ); + // Update vehicle data + if( update_vehicles ) { + level_cache &map_cache = get_cache( z ); + for( const auto &veh : tmpsub->vehicles ) { + // Only add if not tracking already. + if( map_cache.vehicle_list.find( veh.get() ) == map_cache.vehicle_list.end() ) { + map_cache.vehicle_list.insert( veh.get() ); + if( !veh->loot_zones.empty() ) { + map_cache.zone_vehicles.insert( veh.get() ); + } } } } - } - - abs_sub.z() = old_abs_z; -} -void map::loadn( const point &grid, bool update_vehicles ) -{ - if( zlevels ) { - for( int gridz = -OVERMAP_DEPTH; gridz <= OVERMAP_HEIGHT; gridz++ ) { - loadn( tripoint( grid, gridz ), update_vehicles ); + if( zlevels ) { + add_roofs( tripoint( grid, z ) ); } - - // Note: we want it in a separate loop! It is a post-load cleanup - // Since we're adding roofs, we want it to go up (from lowest to highest) - for( int gridz = -OVERMAP_DEPTH; gridz <= OVERMAP_HEIGHT; gridz++ ) { - add_roofs( tripoint( grid, gridz ) ); - } - } else { - loadn( tripoint( grid, abs_sub.z() ), update_vehicles ); } } diff --git a/src/map.h b/src/map.h index cbb27c37ec417..a2456c03f346b 100644 --- a/src/map.h +++ b/src/map.h @@ -2047,7 +2047,6 @@ class map protected: void saven( const tripoint &grid ); - void loadn( const tripoint &grid, bool update_vehicles ); void loadn( const point &grid, bool update_vehicles ); /** * Fast forward a submap that has just been loading into this map. @@ -2514,7 +2513,9 @@ template void shift_bitset_cache( std::bitset &cache, const point &s ); bool ter_furn_has_flag( const ter_t &ter, const furn_t &furn, ter_furn_flag flag ); -bool generate_uniform( const tripoint_abs_sm &p, const oter_id &oter ); +// Returns the terrain to apply if the terrain is uniform, and t_null otherwise. +ter_str_id uniform_terrain( const oter_id &oter ); +bool generate_uniform( const tripoint_abs_sm &p, const ter_str_id &ter ); bool generate_uniform_omt( const tripoint_abs_sm &p, const oter_id &terrain_type ); /** diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 10c107ac7ade1..af976e8c5af83 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -226,6 +226,14 @@ void map::generate( const tripoint_abs_omt &p, const time_point &when, bool save const size_t grid_pos = get_nonant( pos ); if( !save_results || MAPBUFFER.lookup_submap( abs_sub.xy() + pos ) == nullptr ) { setsubmap( grid_pos, new submap() ); + + // Generate uniform submaps immediately and cheaply. + // This causes them to be available for "proper" overlays even if on a lower Z level. + const ter_str_id ter = uniform_terrain( overmap_buffer.ter( p ) ); + if( ter != t_null.id() ) { + getsubmap( grid_pos )->set_all_ter( ter, true ); + getsubmap( grid_pos )->last_touched = calendar::turn; + } } else { setsubmap( grid_pos, MAPBUFFER.lookup_submap( abs_sub.xy() + pos ) ); } @@ -276,7 +284,8 @@ void map::generate( const tripoint_abs_omt &p, const time_point &when, bool save density = density / 100; mapgendata dat( { p.xy(), gridz}, *this, density, when, nullptr ); - if( !save_results || MAPBUFFER.lookup_submap( p_sm ) == nullptr ) { + if( ( !save_results || MAPBUFFER.lookup_submap( p_sm ) == nullptr ) && + uniform_terrain( overmap_buffer.ter( p ) ) == t_null.id() ) { draw_map( dat ); } From 89d6de1b670ce8378b283937e40acaf6a0805241 Mon Sep 17 00:00:00 2001 From: PatrikLundell Date: Sat, 1 Jun 2024 13:47:49 +0200 Subject: [PATCH 12/18] Documentation updated to reflect 3D mapgen functionality --- doc/MAPGEN.md | 39 ++++++++++++++++++++++++++------------- src/editmap.cpp | 2 -- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/doc/MAPGEN.md b/doc/MAPGEN.md index b056e31f42866..c84bce4cb121f 100644 --- a/doc/MAPGEN.md +++ b/doc/MAPGEN.md @@ -213,9 +213,11 @@ Placing things using x/y coordinates ("place_monsters", "place_loot", "place_ite coordinates beyond 24x24. An important limitation is that ranged random coordinates (such as "x": `[ 10, 18 ]`) must not cross the 24x24 terrain boundaries. Ranges such as `[ 0, 23 ]` and `[ 50, 70 ]` are valid, but `[ 0, 47 ]` and `[ 15, 35 ]` are not because they extend beyond a single 24x24 block. Note that the syntax supports an optional -*relative* "z" coordinate (NOT absolute Z level, although it often would look the same as the reference is often zero), -but it is usable only for faction camp construction for the time being (mapgen separates Z levels by using different -overmap terrain identifiers instead). +*relative* "z" coordinate (NOT absolute Z level, although it often would look the same as the reference is often zero). +Usage of Z level offsets for mapgen (as opposed to later map modifications, such as faction camps) has the limitation +that mapgen flags only take effect for positive offsets (e.g. providing a roof and roof furniture for a building generated +with a probability), but not for negative ones (generating something below the current reference level). This restriction +is due to technical limitations (it's costly and messy to determine a level generation order dynamically). Example: @@ -281,6 +283,14 @@ Examples: * The old mapgen.cpp system involved *The Biggest "if / else if / else if / .." Statement Known to Man*(tm), and is only halfway converted to the "builtin" mapgen class. This means that while custom mapgen functions are allowed, the game will cheerfully forget the default if one is added. +* Mapgen flags don't have any effect on "real" mapgen negative Z level offsets due to technical limitations. They work + normally for generation after mapgen (such as the addition of a camp structure, or other post generation + modifications), as well as for positive Z level offsets for the original generation of maps (e.g. adding upper + stories or roofs to buildings placed using probabilities). Negative offsets will still be applied, but any benefits + from flag directives will be lost. Instead, the overlay produced by the offset orders will be applied by merging + the overlay to the base level map generated once that level has actually been generated. It's expected that things + that need to include a Z level offset will most commonly be defining a base and what's above it, which is why that + direction has the complete support. * TODO: Add to this list. @@ -433,7 +443,10 @@ Some mapgens are intended to be layered on top of existing terrain. This can be nested mapgen, or regular mapgen with a predecessor. When the mapgen changes an existing terrain, the tile may already contain preexisting furniture, traps and items. The following flags provide a mechanism for specifying the behaviour to follow in such situations. It is an error if existing -furniture, traps or items are encountered but no behaviour has been given. +furniture, traps or items are encountered but no behaviour has been given. Note that flags do NOT +affect magens on creation of a new overmap when the Z level offset is negative (i.e. something placed +at a lower Z level than the overmap level being generated) and no error reports are generated. This +is a technical limitation, not a desired feature. A blanket policy can be set using one of these three (mutually exclusive) shorthand flags: - `ALLOW_TERRAIN_UNDER_OTHER_DATA` retains preexisting furniture, traps and items without triggering @@ -527,7 +540,7 @@ Example: | line | Allowed values: `"terrain"`, `"furniture"`, `"trap"`, `"radiation"`, `"trap_remove"`, `"item_remove"`, `"field_remove"`, `"creature_remove"` | id | Terrain, furniture, or trap ID. Examples: `"id": "f_counter"`, `"id": "tr_beartrap"`. Omit for "radiation", "item_remove", "creature_remove", and "field_remove". For `trap_remove` if tr_null is used any traps present will be removed. | x, y | Start X, Y coordinates. Value from `0-23`, or range `[ 0-23, 0-23 ]` for a random value in that range. Example: `"x": 12, "y": [ 5, 15 ]` -| z | (optional) Relative Z coordinate for placement at a different Z level than the nominal one. Value from `-20 to 20`. Also note that range is not supported, and it can only be used for faction camps. +| z | (optional) Relative Z coordinate for placement at a different Z level than the nominal one. Value from `-20 to 20`. Also note that range is not supported. | x2, y2 | End X, Y coordinates. Value from `0-23`, or range `[ 0-23, 0-23 ]` for a random value in that range. Example: `"x": 22, "y": [ 15, 20 ]` | amount | Radiation amount. Value from `0-100`. | chance | (optional) One-in-N chance to apply @@ -554,7 +567,7 @@ Example: | square | Allowed values: `"terrain"`, `"furniture"`, `"trap"`, `"radiation"`, `"trap_remove"`, `"item_remove"`, `"field_remove"`, `"creature_remove"` | id | Terrain, furniture, or trap ID. Examples: `"id": "f_counter"`, `"id": "tr_beartrap"`. Omit for "radiation", "item_remove", creature_remove, and "field_remove". For `trap_remove` if tr_null is used any traps present will be removed. | x, y | Top-left corner of square. -| z | (optional) Relative Z coordinate for placement at a different Z level than the nominal one. Value from `-20 to 20`. Also note that range is not supported, and it can only be used for faction camps. +| z | (optional) Relative Z coordinate for placement at a different Z level than the nominal one. Value from `-20 to 20`. Also note that range is not supported. | x2, y2 | Bottom-right corner of square. ## Spawn a single monster with "place_monster" @@ -568,7 +581,7 @@ Value: `[ array of {objects} ]: [ { "monster": ... } ]` | monster | ID of the monster to spawn. | group | ID of the monster group from which the spawned monster is selected. `monster` and `group` should not be used together. `group` will act over `monster`. | x, y | Spawn coordinates ( specific or area rectangle ). Value: 0-23 or `[ 0-23, 0-23 ]` - random value between `[ a, b ]`. -| z | (optional) Relative Z coordinate for placement at a different Z level than the nominal one. Value from `-20 to 20`. Also note that range is not supported, and it can only be used for faction camps. +| z | (optional) Relative Z coordinate for placement at a different Z level than the nominal one. Value from `-20 to 20`. Also note that range is not supported. | chance | Percentage chance to do spawning. If repeat is used each repeat has separate chance. | repeat | The spawning is repeated this many times. Can be a number or a range. | pack_size | How many monsters are spawned. Can be single number or range like `[1-4]`. Is affected by the chance and spawn density. Ignored when spawning from a group. @@ -649,7 +662,7 @@ Using `place_monsters` to spawn a group of monsters works in a similar fashion t |--|--| | monster | The ID of the monster group that you wish to spawn | | x, y | Spawn coordinates ( specific or area rectangle ). Value: 0-23 or `[ 0-23, 0-23 ]` - random value between `[ a, b ]`. -| z | (optional) Relative Z coordinate for placement at a different Z level than the nominal one. Value from `-20 to 20`. Also note that range is not supported, and it can only be used for faction camps. +| z | (optional) Relative Z coordinate for placement at a different Z level than the nominal one. Value from `-20 to 20`. Also note that range is not supported. | chance | Represents a 1 in N chance that the entire group will spawn. This is done once for each repeat. If this dice roll fails, the entire group specified will not spawn. Leave blank to guarantee spawns. | repeat | The spawning is repeated this many times. Can be a number or a range. Again, this represents the number of times the group will be spawned. | density | This number is multiplied by the spawn density of the world the player is in and then probabilistically rounded to determine how many times to spawn the group. This is done for each time the spawn is repeated. For instance, if the final multiplier from this calculation ends up being `2`, and the repeat value is `6`, then the group will be spawned `2 * 6` or 12 times. @@ -660,7 +673,7 @@ Using `place_npcs` to spawn a group of npcs. |Field|Description | |--|--| | x, y | Spawn coordinates ( specific or area rectangle ). Value: 0-23 or `[ 0-23, 0-23 ]` - random value between `[ a, b ]`. -| z | (optional) Relative Z coordinate for placement at a different Z level than the nominal one. Value from `-20 to 20`. Also note that range is not supported, and it can only be used for faction camps. +| z | (optional) Relative Z coordinate for placement at a different Z level than the nominal one. Value from `-20 to 20`. Also note that range is not supported. | class | The class of the npc that you wish to spawn | | add_trait | A string of array of strings for traits the npc starts with. | unique_id | A string for the unique_id the npc has. @@ -671,7 +684,7 @@ Using `place_variables` to set a group of variables. |Field|Description | |--|--| | x, y | Spawn coordinates ( specific or area rectangle ). Value: 0-23 or `[ 0-23, 0-23 ]` - random value between `[ a, b ]`. -| z | (optional) Relative Z coordinate for placement at a different Z level than the nominal one. Value from `-20 to 20`. Also note that range is not supported, and it can only be used for faction camps. +| z | (optional) Relative Z coordinate for placement at a different Z level than the nominal one. Value from `-20 to 20`. Also note that range is not supported. | name | The name of the global variable to set with the absolute coordinates of x and y. ## Spawn specific items with a "place_item" array @@ -690,7 +703,7 @@ Example: | --- | --- | item | (required) ID of the item to spawn | x, y | (required) Spawn coordinates. Value from `0-23`, or range `[ 0-23, 0-23 ]` for a random value in that range. -| z | (optional) Relative Z coordinate for placement at a different Z level than the nominal one. Value from `-20 to 20`. Also note that range is not supported, and it can only be used for faction camps. +| z | (optional) Relative Z coordinate for placement at a different Z level than the nominal one. Value from `-20 to 20`. Also note that range is not supported. | amount | (required) Number of items to spawn. Single integer, or range `[ a, b ]` for a random value in that range. | chance | (optional) One-in-N chance to spawn item. | repeat | (optional) Value: `[ n1, n2 ]`. Spawn item randomly between `n1` and `n2` times. Only makes sense if the coordinates are random. Example: `[ 1, 3 ]` - repeat 1-3 times. @@ -710,7 +723,7 @@ Example: | --- | --- | id | (required) ID of the faction to apply ownership to. | x, y | (required) Spawn coordinates. Value from `0-23`, or range `[ 0-23, 0-23 ]` for a random value in that range. -| z | (optional) Relative Z coordinate for placement at a different Z level than the nominal one. Value from `-20 to 20`. Also note that range is not supported, and it can only be used for faction camps. +| z | (optional) Relative Z coordinate for placement at a different Z level than the nominal one. Value from `-20 to 20`. Also note that range is not supported. This is an array, so multiple entries can be defined. @@ -1172,7 +1185,7 @@ Place_nested allows for conditional spawning of chunks based on the `"id"`s and/ | --- | --- | chunks/else_chunks | (required, string) the nested_mapgen_id of the chunk that will be conditionally placed. Chunks are placed if the specified neighbor matches, and "else_chunks" otherwise. | x and y | (required, int) the cardinal position in which the chunk will be placed. -| z | (optional) Relative Z coordinate for placement at a different Z level than the nominal one. Value from `-20 to 20`. Also note that range is not supported, and it can only be used for faction camps. +| z | (optional) Relative Z coordinate for placement at a different Z level than the nominal one. Value from `-20 to 20`. Also note that range is not supported. | neighbors | (optional) Any of the neighboring overmaps that should be checked before placing the chunk. Each direction is associated with a list of overmap `"id"` substrings. See [JSON_INFO.md](JSON_INFO.md#Starting-locations) "terrain" section to do more advanced searches, note this field defaults to CONTAINS not TYPE. | joins | (optional) Any mutable overmap special joins that should be checked before placing the chunk. Each direction is associated with a list of join `"id"` strings. | flags | (optional) Any overmap terrain flags that should be checked before placing the chunk. Each direction is associated with a list of `oter_flags` flags. diff --git a/src/editmap.cpp b/src/editmap.cpp index 731d917bff2d9..d25361747f933 100644 --- a/src/editmap.cpp +++ b/src/editmap.cpp @@ -1845,8 +1845,6 @@ void editmap::mapgen_preview( const real_coords &tc, uilist &gmenu ) const oter_id orig_oters = omt_ref; overmap_buffer.ter_set( omt_pos, oter_id( gmenu.ret ) ); smallmap tmpmap; - // TODO: add a do-not-save-generated-submaps parameter - // TODO: keep track of generated submaps to delete them properly and to avoid memory leaks tmpmap.generate( omt_pos, calendar::turn, false ); gmenu.border_color = c_light_gray; From 28273faece7c074ba839ff97a88757005c136077 Mon Sep 17 00:00:00 2001 From: PatrikLundell Date: Sat, 1 Jun 2024 13:52:00 +0200 Subject: [PATCH 13/18] Restored hacked mapgen maps --- .../mapgen/campus/buildings/admin_f0.json | 19 ++++---- .../mapgen/campus/buildings/admin_f1.json | 43 +----------------- .../open_areas/pedestrian_westside.json | 45 +------------------ 3 files changed, 13 insertions(+), 94 deletions(-) diff --git a/data/json/mapgen/campus/buildings/admin_f0.json b/data/json/mapgen/campus/buildings/admin_f0.json index d49f0fa6f5f65..aa7500d3c314f 100644 --- a/data/json/mapgen/campus/buildings/admin_f0.json +++ b/data/json/mapgen/campus/buildings/admin_f0.json @@ -66,14 +66,14 @@ ".|,,|||||,,,,|||||______", "?|EE|<,,0,,,,:__________", ".|EE|,,,0,,,,:__________", - "?||||||||,,,,|1.......__", - "???b____|,,,,|........__", - "???b____|,,,,|........__", - "???b____||%%||........__", - "???b__________........__", - "???b__________........__", - "???b__________........__", - "b??b____bbbbbb........bb", + "?||||||||,,,,|__________", + "???b____|,,,,|__________", + "???b____|,,,,|__________", + "???b____||%%||__________", + "???b____________________", + "???b____________________", + "???b____________________", + "b??b____bbbbbbbbbbbbbbbb", "b??b____b.[...........[.", "b??b____b...[...[...[...", "bbbb____b.....[.........", @@ -82,8 +82,7 @@ ], "terrain": { }, "furniture": { }, - "palettes": [ "campus_common" ], - "nested": { "1": { "chunks": [ "campus_shack" ] } } + "palettes": [ "campus_common" ] } } ] diff --git a/data/json/mapgen/campus/buildings/admin_f1.json b/data/json/mapgen/campus/buildings/admin_f1.json index f9ddc09406ef3..567db52e6af0c 100644 --- a/data/json/mapgen/campus/buildings/admin_f1.json +++ b/data/json/mapgen/campus/buildings/admin_f1.json @@ -1,42 +1,4 @@ [ - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "campus_test_stair_up", - "object": { - "mapgensize": [ 1, 1 ], - "rows": [ "Ö" ], - "flags": [ "ALLOW_TERRAIN_UNDER_OTHER_DATA" ], - "terrain": { "Ö": "t_stairs_up" } - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "campus_test_chair", - "object": { - "mapgensize": [ 1, 1 ], - "rows": [ "Ä" ], - "flags": [ "ALLOW_TERRAIN_UNDER_OTHER_DATA" ], - "terrain": { }, - "furniture": { "Ä": "f_armchair" } - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "campus_test_stair_down", - "object": { - "mapgensize": [ 1, 1 ], - "rows": [ "Ö" ], - "flags": [ "ALLOW_TERRAIN_UNDER_OTHER_DATA" ], - "terrain": { "Ö": "t_stairs_down" }, - "place_nested": [ - { "chunks": [ "campus_test_stair_up" ], "x": 0, "y": 0, "z": -1 }, - { "chunks": [ "campus_test_chair" ], "x": 1, "y": 1, "z": -1 } - ] - } - }, { "type": "mapgen", "method": "json", @@ -104,7 +66,7 @@ " |,,|||||,,,,||||| ", " |EE|>,,0,,,,: ", " |EE|<,,0,,,,: ", - " ||||||||,,Ö,| ", + " ||||||||,,,,| ", " |,,,,| ", " |,,,,| ", " |||||| ", @@ -120,8 +82,7 @@ ], "terrain": { }, "furniture": { }, - "palettes": [ "campus_common" ], - "nested": { "Ö": { "chunks": [ "campus_test_stair_down" ] } } + "palettes": [ "campus_common" ] } } ] diff --git a/data/json/mapgen/campus/open_areas/pedestrian_westside.json b/data/json/mapgen/campus/open_areas/pedestrian_westside.json index 9505b3f25b0bb..8ec33c5c47447 100644 --- a/data/json/mapgen/campus/open_areas/pedestrian_westside.json +++ b/data/json/mapgen/campus/open_areas/pedestrian_westside.json @@ -1,44 +1,4 @@ [ - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "campus_shack", - "object": { - "mapgensize": [ 8, 8 ], - "rows": [ - "wwwwwww ", - "w,,,,,w ", - "w,,,,,w ", - "w,,,,,w ", - "w,,,,,w ", - "w,,,,,w ", - "w,,,,,w ", - "w w " - ], - "flags": [ "ALLOW_TERRAIN_UNDER_OTHER_DATA" ], - "palettes": [ "fbml_2_metal_palette" ], - "place_nested": [ { "chunks": [ "campus_shack_roof" ], "x": 0, "y": 0, "z": 1 } ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "campus_shack_roof", - "object": { - "mapgensize": [ 8, 8 ], - "rows": [ - "rrrrrrr ", - "rrrrrrr ", - "rrrrrrr ", - "rrrrrrr ", - "rrrrrrr ", - "rrrrrrr ", - "rrrrrrr ", - "r r " - ], - "palettes": [ "fbml_2_metal_palette" ] - } - }, { "type": "mapgen", "method": "json", @@ -47,7 +7,7 @@ "object": { "fill_ter": "t_concrete", "rows": [ - "1...............................................", + "................................................", "................................................", "................................................", "................................................", @@ -74,8 +34,7 @@ ], "terrain": { }, "furniture": { }, - "palettes": [ "campus_common" ], - "nested": { "1": { "chunks": [ "campus_shack" ] } } + "palettes": [ "campus_common" ] } }, { From f3aa1e8c5d686d7ebd27323ec37df8cc7d212ef9 Mon Sep 17 00:00:00 2001 From: PatrikLundell Date: Sat, 1 Jun 2024 14:49:28 +0200 Subject: [PATCH 14/18] Changed dermatik nest roof to match ground level --- data/json/mapgen/bugs/nest_dermatik.json | 86 +++++++++++++++++------- 1 file changed, 60 insertions(+), 26 deletions(-) diff --git a/data/json/mapgen/bugs/nest_dermatik.json b/data/json/mapgen/bugs/nest_dermatik.json index eb6dcd02b7172..8e1c1966e1700 100644 --- a/data/json/mapgen/bugs/nest_dermatik.json +++ b/data/json/mapgen/bugs/nest_dermatik.json @@ -1,4 +1,38 @@ [ + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "nest_dermatik_paper_roof", + "object": { "mapgensize": [ 1, 1 ], "rows": [ "#" ], "terrain": { "#": "t_roof_paper" } } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "nest_dermatik_paper_wall", + "object": { + "mapgensize": [ 1, 1 ], + "rows": [ "#" ], + "terrain": { "#": "t_paper" }, + "place_nested": [ { "chunks": [ "nest_dermatik_paper_roof" ], "x": 0, "y": 0, "z": 1 } ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "nest_dermatik_dirt_roof", + "object": { "mapgensize": [ 1, 1 ], "rows": [ "#" ], "terrain": { "#": "t_dirt" } } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "nest_dermatik_dirt_wall", + "object": { + "mapgensize": [ 1, 1 ], + "rows": [ "#" ], + "terrain": { "#": "t_wall_dirt" }, + "place_nested": [ { "chunks": [ "nest_dermatik_dirt_roof" ], "x": 0, "y": 0, "z": 1 } ] + } + }, { "type": "mapgen", "method": "json", @@ -35,7 +69,6 @@ "t": [ "t_region_tree", "t_region_groundcover" ], ",": [ "t_region_tree" ], "-": [ "t_wall_dirt" ], - "#": [ [ "t_paper", 3 ], "t_wall_dirt" ], ".": [ "t_mud_underground", [ "t_floor_paper", 2 ] ], "0": [ "t_pit_shallow" ] }, @@ -48,7 +81,8 @@ { "monster": "mon_dermatik_larva", "x": [ 3, 22 ], "y": [ 8, 22 ], "repeat": [ 2, 4 ] }, { "monster": "mon_dermatik_midwife", "x": [ 10, 12 ], "y": [ 14, 17 ], "repeat": [ 0, 2 ] }, { "monster": "mon_dermatik", "x": [ 0, 23 ], "y": [ 0, 23 ], "repeat": [ 1, 4 ] } - ] + ], + "nested": { "#": { "chunks": [ [ "nest_dermatik_paper_wall", 3 ], [ "nest_dermatik_dirt_wall", 1 ] ] } } } }, { @@ -59,31 +93,31 @@ "fill_ter": "t_open_air", "rows": [ " ", - " ", - " ,, ", - " ,,,,,,,,, ", - " ,,,,,,,,,,,,, ", - " ,,,,,,,,,,,,,,,, ", - " ,,,,,,,,,,,,,,,, ", - " ,,,,,,,,,,,,,,,, ", - " ,,,,,,,,,,,,,,,,, ", - " ,,,,,,,,,,,,,,,,,, ", - " ,,,,,,,,,,,,,,,,,,, ", - " ,,,,,,,,,,,,,,,,,,, ", - " ,,,,,,,,,,,,,,,,,,, ", - " ,,,,,,,,,,,,,,,,,,, ", - " ,,,,,,,,,,,,,,,,,,,, ", - " ,,,,,,,,,,,,,,,,,,,, ", - " ,,,,,,,,,,,,,,,,,,, ", - " ,,,,,,,,,,,,,,,,,,,, ", - " ,,,,,,,,,,,,,,,,,,,,, ", - " ,,,,,,,,,,,,,,,,,,,,, ", - " ,,,,,,,,,,,,,,,,,, ", - " ,,,,,,,,,,,, ", - " ,,, , ", - " " + " - ", + " - ---- ", + " ---...-..--- ", + " --.--..-...--- - ", + " -... .- ...------ ", + " -- . . ..-..--- ", + " --- ....- . ..-- ", + " - .. ..... .--- ", + " - .. .. .... --.- ", + " -- . .... ..-- ", + " --... . ..... ...-- ", + " -- . . ....... ..--- ", + " -- ...... . .-- ", + " -... ........ ...- ", + " - ... ......... .-- ", + " --. ......... .--- ", + " -- ....... . ..-- ", + "--.... .. . . ... ...- ", + " - . ......-- ", + " ------... .......-- ", + " ---- ... -.----- ", + " ---------- - ", + " --- -- " ], - "terrain": { ",": [ "t_roof_paper" ] } + "terrain": { "-": [ "t_dirt" ], ".": [ "t_roof_paper" ] } } } ] From 4baf00c5e905a44d4c6f8aeeec1ef7c9fcaf3079 Mon Sep 17 00:00:00 2001 From: PatrikLundell Date: Sun, 2 Jun 2024 23:07:37 +0200 Subject: [PATCH 15/18] 3D relative apply corrections, fixes to 3D worldgen mapgen --- src/mapgen.cpp | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index af976e8c5af83..9c87f1344155c 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -218,30 +218,31 @@ void map::generate( const tripoint_abs_omt &p, const time_point &when, bool save dbg( D_INFO ) << "map::generate( g[" << g.get() << "], p[" << p << "], " "when[" << to_string( when ) << "] )"; + const tripoint_abs_sm p_sm_base = project_to( p ); + // Prepare the canvas... for( int gridx = 0; gridx < my_MAPSIZE; gridx++ ) { for( int gridy = 0; gridy < my_MAPSIZE; gridy++ ) { for( int gridz = -OVERMAP_DEPTH; gridz <= OVERMAP_HEIGHT; gridz++ ) { const tripoint pos( gridx, gridy, gridz ); const size_t grid_pos = get_nonant( pos ); - if( !save_results || MAPBUFFER.lookup_submap( abs_sub.xy() + pos ) == nullptr ) { + if( !save_results || MAPBUFFER.lookup_submap( p_sm_base.xy() + pos ) == nullptr ) { setsubmap( grid_pos, new submap() ); // Generate uniform submaps immediately and cheaply. // This causes them to be available for "proper" overlays even if on a lower Z level. - const ter_str_id ter = uniform_terrain( overmap_buffer.ter( p ) ); + const ter_str_id ter = uniform_terrain( overmap_buffer.ter( { p.xy(), gridz } ) ); if( ter != t_null.id() ) { getsubmap( grid_pos )->set_all_ter( ter, true ); getsubmap( grid_pos )->last_touched = calendar::turn; } } else { - setsubmap( grid_pos, MAPBUFFER.lookup_submap( abs_sub.xy() + pos ) ); + setsubmap( grid_pos, MAPBUFFER.lookup_submap( p_sm_base.xy() + pos ) ); } } } } - const tripoint_abs_sm p_sm_base = project_to( p ); std::vector saved_overlay; saved_overlay.reserve( 4 ); for( size_t index = 0; index <= 3; index++ ) { @@ -263,8 +264,9 @@ void map::generate( const tripoint_abs_omt &p, const time_point &when, bool save for( int gridy = 0; gridy <= 1; gridy++ ) { const tripoint pos( gridx, gridy, gridz ); const size_t grid_pos = get_nonant( pos ); - if( MAPBUFFER.lookup_submap( abs_sub.xy() + pos ) == nullptr && - !getsubmap( grid_pos )->is_uniform() ) { + if( ( !save_results || MAPBUFFER.lookup_submap( p_sm_base.xy() + pos ) == nullptr ) && + !getsubmap( grid_pos )->is_uniform() && + uniform_terrain( overmap_buffer.ter( { p.xy(), gridz } ) ) == t_null.id() ) { saved_overlay[gridx + gridy * 2] = getsubmap( grid_pos ); setsubmap( grid_pos, new submap() ); } @@ -283,9 +285,15 @@ void map::generate( const tripoint_abs_omt &p, const time_point &when, bool save } density = density / 100; + // Not sure if we actually have to check all submaps. + const bool any_missing = MAPBUFFER.lookup_submap( p_sm ) == nullptr || + MAPBUFFER.lookup_submap( p_sm + point{ 1, 0 } ) == nullptr || + MAPBUFFER.lookup_submap( p_sm + point{ 0, 1 } ) == nullptr || + MAPBUFFER.lookup_submap( p_sm + point{ 1, 1 } ) == nullptr; + mapgendata dat( { p.xy(), gridz}, *this, density, when, nullptr ); - if( ( !save_results || MAPBUFFER.lookup_submap( p_sm ) == nullptr ) && - uniform_terrain( overmap_buffer.ter( p ) ) == t_null.id() ) { + if( ( !save_results || any_missing ) && + uniform_terrain( overmap_buffer.ter( { p.xy(), gridz } ) ) == t_null.id() ) { draw_map( dat ); } @@ -368,11 +376,11 @@ void map::generate( const tripoint_abs_omt &p, const time_point &when, bool save const tripoint pos( gridx, gridy, gridz ); const size_t grid_pos = get_nonant( pos ); if( gridx <= 1 && gridy <= 1 ) { - if( MAPBUFFER.lookup_submap( abs_sub.xy() + pos ) == nullptr ) { + if( MAPBUFFER.lookup_submap( p_sm_base.xy() + pos ) == nullptr ) { saven( {gridx, gridy, gridz} ); } } else { - if( MAPBUFFER.lookup_submap( abs_sub.xy() + pos ) == nullptr ) { + if( MAPBUFFER.lookup_submap( p_sm_base.xy() + pos ) == nullptr ) { delete getsubmap( grid_pos ); } } @@ -380,6 +388,8 @@ void map::generate( const tripoint_abs_omt &p, const time_point &when, bool save } } } + + set_abs_sub( p_sm_base ); } void mapgen_function_builtin::generate( mapgendata &mgd ) @@ -1911,9 +1921,9 @@ class jmapgen_field : public jmapgen_piece return; } if( remove ) { - dat.m.remove_field( tripoint( x.get(), y.get(), z.get() ), chosen_id ); + dat.m.remove_field( tripoint( x.get(), y.get(), dat.zlevel() + z.get() ), chosen_id ); } else { - dat.m.add_field( tripoint( x.get(), y.get(), z.get() ), chosen_id, + dat.m.add_field( tripoint( x.get(), y.get(), dat.zlevel() + z.get() ), chosen_id, random_entry( intensities ), age ); } } @@ -1958,7 +1968,7 @@ class jmapgen_npc : public jmapgen_piece add_msg_debug( debugmode::DF_NPC, "NPC with unique id %s already exists.", unique_id ); return; } - tripoint const dst( x.get(), y.get(), z.get() ); + tripoint const dst( x.get(), y.get(), dat.zlevel() + z.get() ); // TODO: Make place_npc 3D aware. character_id npc_id = dat.m.place_npc( dst.xy(), chosen_id ); if( get_map().inbounds( dat.m.getglobal( dst ) ) ) { @@ -2039,7 +2049,7 @@ class jmapgen_sign : public jmapgen_piece } void apply( const mapgendata &dat, const jmapgen_int &x, const jmapgen_int &y, const jmapgen_int &z, const std::string &/*context*/ ) const override { - const tripoint_bub_ms r( x.get(), y.get(), z.get() ); + const tripoint_bub_ms r( x.get(), y.get(), dat.zlevel() + z.get() ); dat.m.furn_set( r, furn_str_id::NULL_ID() ); dat.m.furn_set( r, sign_furniture ); @@ -5878,7 +5888,7 @@ void map::draw_lab( mapgendata &dat ) } // end aboveground vs belowground // Ants will totally wreck up the place - if( is_ot_match( "ants", terrain_type, ot_match_type::contains ) ) { + if( true ) { //###is_ot_match( "ants", terrain_type, ot_match_type::contains ) ) { for( int i = 0; i < SEEX * 2; i++ ) { for( int j = 0; j < SEEY * 2; j++ ) { // Carve out a diamond area that covers 2 spaces on each edge. From 9f7e61943070fb3615922ae072a1d319e1ccb019 Mon Sep 17 00:00:00 2001 From: PatrikLundell Date: Tue, 4 Jun 2024 10:48:36 +0200 Subject: [PATCH 16/18] demanded changes + correction --- src/map.cpp | 2 +- src/mapgen.cpp | 8 +++----- src/submap.cpp | 9 ++++----- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index f01f4039c0e1d..695db07852f8c 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -8370,7 +8370,7 @@ void map::loadn( const point &grid, bool update_vehicles ) set_floor_cache_dirty( z ); set_pathfinding_cache_dirty( z ); tmpsub = MAPBUFFER.lookup_submap( pos ); - setsubmap( get_nonant( { grid.x, grid.y, z } ), tmpsub ); + setsubmap( get_nonant( { grid, z } ), tmpsub ); if( !tmpsub->active_items.empty() ) { submaps_with_active_items_dirty.emplace( pos ); } diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 52dbf76e2d191..ea2cdda621174 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -84,8 +84,6 @@ #include "weighted_list.h" #include "creature_tracker.h" -static furn_id f_null; - static const furn_str_id furn_f_bed( "f_bed" ); static const furn_str_id furn_f_console( "f_console" ); static const furn_str_id furn_f_counter( "f_counter" ); @@ -297,9 +295,9 @@ void map::generate( const tripoint_abs_omt &p, const time_point &when, bool save // Not sure if we actually have to check all submaps. const bool any_missing = MAPBUFFER.lookup_submap( p_sm ) == nullptr || - MAPBUFFER.lookup_submap( p_sm + point{ 1, 0 } ) == nullptr || - MAPBUFFER.lookup_submap( p_sm + point{ 0, 1 } ) == nullptr || - MAPBUFFER.lookup_submap( p_sm + point{ 1, 1 } ) == nullptr; + MAPBUFFER.lookup_submap( p_sm + point_east ) == nullptr || + MAPBUFFER.lookup_submap( p_sm + point_south_east ) == nullptr || + MAPBUFFER.lookup_submap( p_sm + point_south ) == nullptr; mapgendata dat( { p.xy(), gridz}, *this, density, when, nullptr ); if( ( !save_results || any_missing ) && diff --git a/src/submap.cpp b/src/submap.cpp index cbeade5077dfe..2f1e5d0f9e29c 100644 --- a/src/submap.cpp +++ b/src/submap.cpp @@ -437,11 +437,10 @@ void submap::merge_submaps( submap *copy_from, bool copy_from_is_overlay ) for( const submap::cosmetic_t &cos : copy_from->cosmetics ) { bool found = false; - for( size_t i = 0; i < this->cosmetics.size(); ++i ) { - if( this->cosmetics[i].pos == cos.pos && - this->cosmetics[i].type == cos.type ) { - if( this->cosmetics[i].str == cos.str || !copy_from_is_overlay ) { - this->cosmetics[i].str = cos.str; + for( submap::cosmetic_t &cosmetic : this->cosmetics ) { + if( cosmetic.pos == cos.pos && cosmetic.type == cos.type ) { + if( copy_from_is_overlay ) { + cosmetic.str = cos.str; } found = true; break; From e6c5d7716adb9900b356174d80c513fe4a37d028 Mon Sep 17 00:00:00 2001 From: PatrikLundell Date: Thu, 6 Jun 2024 11:20:12 +0200 Subject: [PATCH 17/18] Added cleanup for unsaved submaps --- src/editmap.cpp | 7 ++----- src/editmap.h | 3 ++- src/map.h | 4 ++++ src/mapgen.cpp | 22 ++++++++++++++++++++++ tests/overmap_test.cpp | 1 + 5 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/editmap.cpp b/src/editmap.cpp index d25361747f933..2c064be64a0b6 100644 --- a/src/editmap.cpp +++ b/src/editmap.cpp @@ -2209,12 +2209,9 @@ void editmap::edit_mapgen() /* * Special voodoo sauce required to cleanse vehicles and caches to prevent debugmsg loops when re-applying mapgen. */ -void editmap::cleartmpmap( tinymap &tmpmap ) const +void editmap::cleartmpmap( smallmap &tmpmap ) const { - for( submap *&smap : tmpmap.grid ) { - delete smap; - smap = nullptr; - } + tmpmap.delete_unmerged_submaps(); for( int z = -OVERMAP_DEPTH; z <= OVERMAP_HEIGHT; z++ ) { level_cache &ch = tmpmap.get_cache( z ); diff --git a/src/editmap.h b/src/editmap.h index 281e005580ca3..a6afb6a2bb72b 100644 --- a/src/editmap.h +++ b/src/editmap.h @@ -18,6 +18,7 @@ class Creature; class field; class map; +class smallmap; class tinymap; class ui_adaptor; class uilist; @@ -60,7 +61,7 @@ class editmap void edit_itm(); void edit_critter( Creature &critter ); void edit_mapgen(); - void cleartmpmap( tinymap &tmpmap ) const; + void cleartmpmap( smallmap &tmpmap ) const; void mapgen_preview( const real_coords &tc, uilist &gmenu ); vehicle *mapgen_veh_query( const tripoint_abs_omt &omt_tgt ); bool mapgen_veh_destroy( const tripoint_abs_omt &omt_tgt, vehicle *car_target ); diff --git a/src/map.h b/src/map.h index 3325dedd17718..5531d3f2133f4 100644 --- a/src/map.h +++ b/src/map.h @@ -1864,6 +1864,9 @@ class map // The code relies on the submap coordinate falling on omt boundaries, so taking a // tripoint_abs_omt coordinate guarantees this will be fulfilled. void generate( const tripoint_abs_omt &p, const time_point &when, bool save_results ); + // Used when contents has been generated by 'generate' with save_results = false to dispose of + // submaps that aren't present in the map buffer. This is done to avoid memory leaks. + void delete_unmerged_submaps(); void place_spawns( const mongroup_id &group, int chance, const point_bub_ms &p1, const point_bub_ms &p2, int z_level, float density, bool individual = false, bool friendly = false, @@ -2559,6 +2562,7 @@ class tinymap : private map using map::is_main_cleanup_queued; using map::main_cleanup_override; using map::generate; + using map::delete_unmerged_submaps; void place_spawns( const mongroup_id &group, int chance, const point_omt_ms &p1, const point_omt_ms &p2, const int z_level, float density, bool individual = false, bool friendly = false, diff --git a/src/mapgen.cpp b/src/mapgen.cpp index ea2cdda621174..a0ac26261d9c9 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -400,6 +400,28 @@ void map::generate( const tripoint_abs_omt &p, const time_point &when, bool save set_abs_sub( p_sm_base ); } +void map::delete_unmerged_submaps() +{ + tripoint_abs_sm sm_base = get_abs_sub(); + + for( size_t index = 0; index < grid.size(); index++ ) { + tripoint offset; + const int ix = static_cast( index ); + + // This is the inverse of get_nonant. + if( zlevels ) { + offset = { ( ix / OVERMAP_LAYERS ) % my_MAPSIZE, ix / OVERMAP_LAYERS / my_MAPSIZE, ix % OVERMAP_LAYERS - OVERMAP_DEPTH }; + } else { + offset = { ix % my_MAPSIZE, ix / my_MAPSIZE, sm_base.z()}; + } + + if( grid[index] != nullptr && MAPBUFFER.lookup_submap( sm_base.xy() + offset ) != grid[index] ) { + delete grid[index]; + grid[index] = nullptr; + } + } +} + void mapgen_function_builtin::generate( mapgendata &mgd ) { ( *fptr )( mgd ); diff --git a/tests/overmap_test.cpp b/tests/overmap_test.cpp index 667a5a871f9bc..acee4524fab83 100644 --- a/tests/overmap_test.cpp +++ b/tests/overmap_test.cpp @@ -459,6 +459,7 @@ TEST_CASE( "overmap_terrain_coverage", "[overmap][slow]" ) sample_size = goal_samples - p.second.samples; p.second.found = true; } + tm.delete_unmerged_submaps(); } } ); p.second.samples = goal_samples; From 86a14f652ca70280f64e80da0f31bbe4ede6c7ed Mon Sep 17 00:00:00 2001 From: PatrikLundell Date: Sat, 15 Jun 2024 18:09:26 +0200 Subject: [PATCH 18/18] Remove test commenting out of code --- src/mapgen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index a0ac26261d9c9..2e8451feb06d3 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -5918,7 +5918,7 @@ void map::draw_lab( mapgendata &dat ) } // end aboveground vs belowground // Ants will totally wreck up the place - if( true ) { //###is_ot_match( "ants", terrain_type, ot_match_type::contains ) ) { + if( is_ot_match( "ants", terrain_type, ot_match_type::contains ) ) { for( int i = 0; i < SEEX * 2; i++ ) { for( int j = 0; j < SEEY * 2; j++ ) { // Carve out a diamond area that covers 2 spaces on each edge.