Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize sees by removing reachability cache and fixing LRU cache. #70546

Merged
merged 11 commits into from
Jan 6, 2024
4 changes: 0 additions & 4 deletions src/action.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -341,8 +341,6 @@ std::string action_ident( action_id act )
return "debug_visibility";
case ACTION_DISPLAY_TRANSPARENCY:
return "debug_transparency";
case ACTION_DISPLAY_REACHABILITY_ZONES:
return "display_reachability_zones";
case ACTION_DISPLAY_LIGHTING:
return "debug_lighting";
case ACTION_DISPLAY_RADIATION:
Expand Down Expand Up @@ -473,7 +471,6 @@ bool can_action_change_worldstate( const action_id act )
case ACTION_DISPLAY_RADIATION:
case ACTION_DISPLAY_NPC_ATTACK_POTENTIAL:
case ACTION_DISPLAY_TRANSPARENCY:
case ACTION_DISPLAY_REACHABILITY_ZONES:
case ACTION_ZOOM_OUT:
case ACTION_ZOOM_IN:
case ACTION_TOGGLE_PIXEL_MINIMAP:
Expand Down Expand Up @@ -928,7 +925,6 @@ action_id handle_action_menu()
REGISTER_ACTION( ACTION_DISPLAY_VISIBILITY );
REGISTER_ACTION( ACTION_DISPLAY_LIGHTING );
REGISTER_ACTION( ACTION_DISPLAY_TRANSPARENCY );
REGISTER_ACTION( ACTION_DISPLAY_REACHABILITY_ZONES );
REGISTER_ACTION( ACTION_DISPLAY_RADIATION );
REGISTER_ACTION( ACTION_DISPLAY_NPC_ATTACK_POTENTIAL );
REGISTER_ACTION( ACTION_TOGGLE_DEBUG_MODE );
Expand Down
2 changes: 0 additions & 2 deletions src/action.h
Original file line number Diff line number Diff line change
Expand Up @@ -342,8 +342,6 @@ enum action_id : int {
ACTION_DISPLAY_TRANSPARENCY,
/** Toggle retracted/transparent high sprites */
ACTION_TOGGLE_PREVENT_OCCLUSION,
/** Toggle reachability zones map */
ACTION_DISPLAY_REACHABILITY_ZONES,
ACTION_DISPLAY_NPC_ATTACK_POTENTIAL,
/** Toggle timing of the game hours */
ACTION_TOGGLE_HOUR_TIMER,
Expand Down
10 changes: 0 additions & 10 deletions src/cata_tiles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1620,16 +1620,6 @@ void cata_tiles::draw( const point &dest, const tripoint &center, int width, int
( ( tr - LIGHT_TRANSPARENCY_OPEN_AIR ) * 8 );
draw_debug_tile( intensity, string_format( "%.2f", tr ) );
}

if( g->display_overlay_state( ACTION_DISPLAY_REACHABILITY_ZONES ) ) {
tripoint tile_pos( x, y, center.z );
int value = here.reachability_cache_value( tile_pos,
g->debug_rz_display.r_cache_vertical, g->debug_rz_display.quadrant );
// use color to denote reachability from you to the target tile according to the
// cache
bool reachable = here.has_potential_los( you.pos(), tile_pos );
draw_debug_tile( reachable ? 0 : 6, std::to_string( value ) );
}
}

if( !invisible[0] ) {
Expand Down
95 changes: 51 additions & 44 deletions src/creature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -348,37 +348,31 @@ bool Creature::sees( const Creature &critter ) const
return true;
}

if( !fov_3d && posz() != critter.posz() ) {
return false;
}

map &here = get_map();

const int target_range = rl_dist( pos(), critter.pos() );
if( target_range > MAX_VIEW_DISTANCE ) {
return false;
}

if( critter.has_flag( mon_flag_ALWAYS_VISIBLE ) || ( has_flag( mon_flag_ALWAYS_SEES_YOU ) &&
critter.is_avatar() ) ) {
return true;
}

const int wanted_range = rl_dist( pos(), critter.pos() );
if( this->has_flag( mon_flag_ALL_SEEING ) ) {
const monster *m = this->as_monster();
return wanted_range < std::max( m->type->vision_day, m->type->vision_night );
}

// player can use mirrors, so `has_potential_los` cannot be used
if( !is_avatar() && !here.has_potential_los( pos(), critter.pos() ) ) {
return false;
return target_range <= std::max( m->type->vision_day, m->type->vision_night );
}

if( critter.is_hallucination() && !is_avatar() ) {
// hallucinations are imaginations of the player character, npcs or monsters don't hallucinate.
return false;
}
if( !fov_3d && posz() != critter.posz() ) {
return false;
}

// Used with the Mind over Matter power Obscurity, to telepathically erase yourself from a target's perceptions
if( has_effect( effect_telepathic_ignorance ) &&
critter.has_effect( effect_telepathic_ignorance_self ) ) {
return false;
}

// Creature has stumbled into an invisible player and is now aware of them
if( has_effect( effect_stumbled_into_invisible ) &&
Expand All @@ -395,39 +389,52 @@ bool Creature::sees( const Creature &critter ) const

// Can always see adjacent monsters on the same level.
// We also bypass lighting for vertically adjacent monsters, but still check for floors.
if( wanted_range <= 1 && ( posz() == critter.posz() || here.sees( pos(), critter.pos(), 1 ) ) ) {
return visible( ch );
} else if( ( wanted_range > 1 && critter.digging() &&
here.has_flag( ter_furn_flag::TFLAG_DIGGABLE, critter.pos() ) ) ||
( critter.has_flag( mon_flag_CAMOUFLAGE ) && wanted_range > this->get_eff_per() ) ||
( critter.has_flag( mon_flag_WATER_CAMOUFLAGE ) &&
wanted_range > this->get_eff_per() &&
( critter.is_likely_underwater() ||
here.has_flag( ter_furn_flag::TFLAG_DEEP_WATER, critter.pos() ) ||
( here.has_flag( ter_furn_flag::TFLAG_SHALLOW_WATER, critter.pos() ) &&
critter.get_size() < creature_size::medium ) ) ) ||
( critter.has_flag( mon_flag_NIGHT_INVISIBILITY ) &&
here.light_at( critter.pos() ) <= lit_level::LOW ) ||
critter.has_effect( effect_invisibility ) ||
( !is_likely_underwater() && critter.is_likely_underwater() &&
majority_rule( critter.has_flag( mon_flag_WATER_CAMOUFLAGE ),
here.has_flag( ter_furn_flag::TFLAG_DEEP_WATER, critter.pos() ),
posz() != critter.posz() ) ) ||
( here.has_flag_ter_or_furn( ter_furn_flag::TFLAG_HIDE_PLACE, critter.pos() ) &&
!( std::abs( posx() - critter.posx() ) <= 1 && std::abs( posy() - critter.posy() ) <= 1 &&
std::abs( posz() - critter.posz() ) <= 1 ) ) ||
( here.has_flag_ter_or_furn( ter_furn_flag::TFLAG_SMALL_HIDE, critter.pos() ) &&
critter.has_flag( mon_flag_SMALL_HIDER ) &&
!( std::abs( posx() - critter.posx() ) <= 1 && std::abs( posy() - critter.posy() ) <= 1 &&
std::abs( posz() - critter.posz() ) <= 1 ) ) ) {
if( target_range <= 1 ) {
return ( posz() == critter.posz() || here.sees( pos(), critter.pos(), 1 ) ) && visible( ch );
}

// If we cannot see without any of the penalties below, bail now.
if( !sees( critter.pos(), critter.is_avatar() ) ) {
return false;
}

// Used with the Mind over Matter power Obscurity, to telepathically erase yourself from a target's perceptions
if( has_effect( effect_telepathic_ignorance ) &&
critter.has_effect( effect_telepathic_ignorance_self ) ) {
return false;
}

if( ( target_range > 2 && critter.digging() &&
here.has_flag( ter_furn_flag::TFLAG_DIGGABLE, critter.pos() ) ) ||
( critter.has_flag( mon_flag_CAMOUFLAGE ) && target_range > this->get_eff_per() ) ||
( critter.has_flag( mon_flag_WATER_CAMOUFLAGE ) &&
target_range > this->get_eff_per() &&
( critter.is_likely_underwater() ||
here.has_flag( ter_furn_flag::TFLAG_DEEP_WATER, critter.pos() ) ||
( here.has_flag( ter_furn_flag::TFLAG_SHALLOW_WATER, critter.pos() ) &&
critter.get_size() < creature_size::medium ) ) ) ||
( critter.has_flag( mon_flag_NIGHT_INVISIBILITY ) &&
here.light_at( critter.pos() ) <= lit_level::LOW ) ||
critter.has_effect( effect_invisibility ) ||
( !is_likely_underwater() && critter.is_likely_underwater() &&
majority_rule( critter.has_flag( mon_flag_WATER_CAMOUFLAGE ),
here.has_flag( ter_furn_flag::TFLAG_DEEP_WATER, critter.pos() ),
posz() != critter.posz() ) ) ||
( here.has_flag_ter_or_furn( ter_furn_flag::TFLAG_HIDE_PLACE, critter.pos() ) &&
!( std::abs( posx() - critter.posx() ) <= 1 && std::abs( posy() - critter.posy() ) <= 1 &&
std::abs( posz() - critter.posz() ) <= 1 ) ) ||
( here.has_flag_ter_or_furn( ter_furn_flag::TFLAG_SMALL_HIDE, critter.pos() ) &&
critter.has_flag( mon_flag_SMALL_HIDER ) &&
!( std::abs( posx() - critter.posx() ) <= 1 && std::abs( posy() - critter.posy() ) <= 1 &&
std::abs( posz() - critter.posz() ) <= 1 ) ) ) {
return false;
}
if( ch != nullptr ) {
if( ch->is_crouching() || ch->is_prone() || pos().z != critter.pos().z ) {
const int coverage = std::max( here.obstacle_coverage( pos(), critter.pos() ),
here.ledge_coverage( *this, critter.pos() ) );
if( coverage < 30 ) {
return sees( critter.pos(), critter.is_avatar() ) && visible( ch );
return visible( ch );
}
float size_modifier = 1.0f;
switch( ch->get_size() ) {
Expand Down Expand Up @@ -459,12 +466,12 @@ bool Creature::sees( const Creature &critter ) const

if( coverage < profile ) {
const int vision_modifier = std::max( 30 * ( 1 - coverage / profile ), 1 );
return sees( critter.pos(), critter.is_avatar(), vision_modifier ) && visible( ch );
return target_range <= vision_modifier && visible( ch );
}
return false;
}
}
return sees( critter.pos(), critter.is_avatar() ) && visible( ch );
return visible( ch );
}

bool Creature::sees( const tripoint &t, bool is_avatar, int range_mod ) const
Expand Down
5 changes: 0 additions & 5 deletions src/debug_menu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,6 @@ std::string enum_to_string<debug_menu::debug_menu_index>( debug_menu::debug_menu
case debug_menu::debug_menu_index::DISPLAY_VISIBILITY: return "DISPLAY_VISIBILITY";
case debug_menu::debug_menu_index::DISPLAY_LIGHTING: return "DISPLAY_LIGHTING";
case debug_menu::debug_menu_index::DISPLAY_TRANSPARENCY: return "DISPLAY_TRANSPARENCY";
case debug_menu::debug_menu_index::DISPLAY_REACHABILITY_ZONES: return "DISPLAY_REACHABILITY_ZONES";
case debug_menu::debug_menu_index::DISPLAY_RADIATION: return "DISPLAY_RADIATION";
case debug_menu::debug_menu_index::HOUR_TIMER: return "HOUR_TIMER";
case debug_menu::debug_menu_index::CHANGE_SPELLS: return "CHANGE_SPELLS";
Expand Down Expand Up @@ -483,7 +482,6 @@ static int info_uilist( bool display_all_entries = true )
{ uilist_entry( debug_menu_index::DISPLAY_VISIBILITY, true, 'v', _( "Toggle display visibility" ) ) },
{ uilist_entry( debug_menu_index::DISPLAY_LIGHTING, true, 'l', _( "Toggle display lighting" ) ) },
{ uilist_entry( debug_menu_index::DISPLAY_TRANSPARENCY, true, 'p', _( "Toggle display transparency" ) ) },
{ uilist_entry( debug_menu_index::DISPLAY_REACHABILITY_ZONES, true, 'z', _( "Toggle display reachability zones" ) ) },
{ uilist_entry( debug_menu_index::DISPLAY_RADIATION, true, 'R', _( "Toggle display radiation" ) ) },
{ uilist_entry( debug_menu_index::SHOW_MUT_CAT, true, 'm', _( "Show mutation category levels" ) ) },
{ uilist_entry( debug_menu_index::BENCHMARK, true, 'b', _( "Draw benchmark (X seconds)" ) ) },
Expand Down Expand Up @@ -3302,9 +3300,6 @@ void debug()
case debug_menu_index::DISPLAY_TRANSPARENCY:
g->display_toggle_overlay( ACTION_DISPLAY_TRANSPARENCY );
break;
case debug_menu_index::DISPLAY_REACHABILITY_ZONES:
g->display_reachability_zones();
break;
case debug_menu_index::HOUR_TIMER:
g->toggle_debug_hour_timer();
break;
Expand Down
1 change: 0 additions & 1 deletion src/debug_menu.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ enum class debug_menu_index : int {
DISPLAY_VISIBILITY,
DISPLAY_LIGHTING,
DISPLAY_TRANSPARENCY,
DISPLAY_REACHABILITY_ZONES,
DISPLAY_RADIATION,
HOUR_TIMER,
CHANGE_SPELLS,
Expand Down
49 changes: 0 additions & 49 deletions src/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7776,10 +7776,6 @@ look_around_result game::look_around(
if( !MAP_SHARING::isCompetitive() || MAP_SHARING::isDebugger() ) {
display_transparency();
}
} else if( action == "display_reachability_zones" ) {
if( !MAP_SHARING::isCompetitive() || MAP_SHARING::isDebugger() ) {
display_reachability_zones();
}
} else if( action == "debug_radiation" ) {
if( !MAP_SHARING::isCompetitive() || MAP_SHARING::isDebugger() ) {
display_radiation();
Expand Down Expand Up @@ -12808,51 +12804,6 @@ void game::display_transparency()
}
}

// Debug menu: asks which reachability cache to display
void game::display_reachability_zones()
{
if( use_tiles ) {
display_toggle_overlay( ACTION_DISPLAY_REACHABILITY_ZONES );
if( display_overlay_state( ACTION_DISPLAY_REACHABILITY_ZONES ) ) {
const auto &menu_popup = [&]( int prev_value,
const std::vector<std::string> &items ) -> std::optional<int> {
uilist menu;
int count = 0;
for( const auto &menu_str : items )
{
menu.addentry( count++, true, MENU_AUTOASSIGN, "%s", menu_str );
}
menu.selected = prev_value;
menu.w_y_setup = 0;
menu.query();
if( menu.ret < 0 )
{
return std::nullopt;
}
return menu.ret;
};
static_assert(
static_cast<int>( enum_traits<reachability_cache_quadrant >::last ) == 3,
"Debug menu expects at least 4 elements in the `quadrant` enum."
);
std::optional<int> cache =
menu_popup( debug_rz_display.r_cache_vertical, { "Horizontal", "Vertical (upward)" } );
std::optional<int> quadrant;
if( cache ) {
quadrant =
menu_popup( static_cast<int>( debug_rz_display.quadrant ),
/**/{ "NE", "SE", "SW", "NW" } );
}
if( cache && quadrant ) {
debug_rz_display.r_cache_vertical = *cache;
debug_rz_display.quadrant = static_cast<reachability_cache_quadrant>( *quadrant );
} else { // user cancelled selection, toggle overlay off
display_toggle_overlay( ACTION_DISPLAY_REACHABILITY_ZONES );
}
}
}
}

void game::init_autosave()
{
moves_since_last_save = 0;
Expand Down
8 changes: 0 additions & 8 deletions src/game.h
Original file line number Diff line number Diff line change
Expand Up @@ -1091,14 +1091,6 @@ class game
std::vector<effect_on_condition_id> inactive_global_effect_on_condition_vector;
queued_eocs queued_global_effect_on_conditions;

// setting that specifies which reachability zone cache to display
struct debug_reachability_zones_display {
public:
bool r_cache_vertical;
reachability_cache_quadrant quadrant;
} debug_rz_display = {}; // NOLINT(cata-serialize)
void display_reachability_zones(); // Displays reachability zones

spell_events &spell_events_subscriber();

pimpl<creature_tracker> critter_tracker;
Expand Down
7 changes: 0 additions & 7 deletions src/handle_action.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2893,13 +2893,6 @@ bool game::do_regular_action( action_id &act, avatar &player_character,
display_transparency();
break;

case ACTION_DISPLAY_REACHABILITY_ZONES:
if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) {
break; //don't do anything when sharing and not debugger
}
display_reachability_zones();
break;

case ACTION_TOGGLE_DEBUG_MODE:
if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) {
break; //don't do anything when sharing and not debugger
Expand Down
11 changes: 0 additions & 11 deletions src/level_cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
#include "game_constants.h"
#include "lightmap.h"
#include "point.h"
#include "reachability_cache.h"
#include "shadowcasting.h"
#include "value_ptr.h"

Expand Down Expand Up @@ -72,16 +71,6 @@ struct level_cache {
// effective "visibility_cache" is calculated as "max(seen_cache, camera_cache)"
cata::mdarray<float, point_bub_ms> camera_cache;

// reachability caches
// Note: indirection here is introduced, because caches are quite large:
// at least (MAPSIZE_X * MAPSIZE_Y) * 4 bytes (≈69,696 bytes) each
// so having them directly as part of the level_cache interferes with
// CPU cache coherency of level_cache
cata::value_ptr<reachability_cache_horizontal>r_hor_cache =
cata::make_value<reachability_cache_horizontal>();
cata::value_ptr<reachability_cache_vertical> r_up_cache =
cata::make_value<reachability_cache_vertical>();

// stores resulting apparent brightness to player, calculated by map::apparent_light_at
cata::mdarray<lit_level, point_bub_ms> visibility_cache;
std::bitset<MAPSIZE_X *MAPSIZE_Y> map_memory_cache_dec;
Expand Down
Loading
Loading