Skip to content

Commit

Permalink
Add stats tracker (#33782)
Browse files Browse the repository at this point in the history
* Added auto_hash and range_hash

range_hash is a hash for using e.g. containers as keys in unordered_maps.

auto_hash is a hash function that chooses automatically between std::hash
and cata::tuple_hash depending on the hashed type.

* Add event::data_type

This is a typedef for the map type used to store the event data.  Adding
it because the underlying type seems likely to change in the future.

* Add a simple stats_tracker that counts events

* Add stats_tracker to game

* Serialize stats_tracker

* Add hp_part case for cata_variant

* Add (and use) a character_takes_damage event

* Add stats_tracker::total

This sums the value of a particular field in events satisfying a
criterion.

* Replace lifetime_stats with stats_tracker

Previously each player object contained some lifetime_stats about tiles
moved, etc.  Replace all that with the newly added stats_tracker
functionality.

One side-effect is that muscle-powered bionics now recharge at random
intervals, rather than regularly, but should have the same average
charge rates.

* Some comments to help explain stats_tracker

* Add std::hash specialization for event_type

This is supposed to be in the standard library in C++14 but gcc 5.3
lacks it.
  • Loading branch information
jbytheway authored and ZhilkinSerg committed Sep 4, 2019
1 parent 79cdb87 commit 9df45a3
Show file tree
Hide file tree
Showing 18 changed files with 422 additions and 78 deletions.
19 changes: 19 additions & 0 deletions src/bodypart.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,25 @@ std::string enum_to_string<side>( side data )
abort();
}

template<>
std::string enum_to_string<hp_part>( hp_part data )
{
switch( data ) {
// *INDENT-OFF*
case hp_part::hp_head: return "head";
case hp_part::hp_torso: return "torso";
case hp_part::hp_arm_l: return "arm_l";
case hp_part::hp_arm_r: return "arm_r";
case hp_part::hp_leg_l: return "leg_l";
case hp_part::hp_leg_r: return "leg_r";
// *INDENT-ON*
case hp_part::num_hp_parts:
break;
}
debugmsg( "Invalid hp_part" );
abort();
}

} // namespace io

namespace
Expand Down
1 change: 1 addition & 0 deletions src/cata_variant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ std::string enum_to_string<cata_variant_type>( cata_variant_type type )
case cata_variant_type::bool_: return "bool";
case cata_variant_type::character_id: return "character_id";
case cata_variant_type::efftype_id: return "efftype_id";
case cata_variant_type::hp_part: return "hp_part";
case cata_variant_type::int_: return "int";
case cata_variant_type::itype_id: return "itype_id";
case cata_variant_type::matype_id: return "matype_id";
Expand Down
7 changes: 6 additions & 1 deletion src/cata_variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
enum add_type : int;
enum body_part : int;
enum class mutagen_technique : int;
enum hp_part : int;

using itype_id = std::string;

Expand All @@ -30,6 +31,7 @@ enum class cata_variant_type : int {
bool_,
character_id,
efftype_id,
hp_part,
int_,
itype_id,
matype_id,
Expand Down Expand Up @@ -143,7 +145,7 @@ struct convert_enum {
};

// These are the specializations of convert for each value type.
static_assert( static_cast<int>( cata_variant_type::num_types ) == 18,
static_assert( static_cast<int>( cata_variant_type::num_types ) == 19,
"This assert is a reminder to add conversion support for any new types to the "
"below specializations" );

Expand Down Expand Up @@ -186,6 +188,9 @@ struct convert<cata_variant_type::character_id> {
template<>
struct convert<cata_variant_type::efftype_id> : convert_string_id<efftype_id> {};

template<>
struct convert<cata_variant_type::hp_part> : convert_enum<hp_part> {};

template<>
struct convert<cata_variant_type::int_> {
using type = int;
Expand Down
9 changes: 8 additions & 1 deletion src/event.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,19 @@ std::string enum_to_string<event_type>( event_type data )
case event_type::activates_mininuke: return "activates_mininuke";
case event_type::administers_mutagen: return "administers_mutagen";
case event_type::angers_amigara_horrors: return "angers_amigara_horrors";
case event_type::avatar_moves: return "avatar_moves";
case event_type::awakes_dark_wyrms: return "awakes_dark_wyrms";
case event_type::becomes_wanted: return "becomes_wanted";
case event_type::broken_bone_mends: return "broken_bone_mends";
case event_type::buries_corpse: return "buries_corpse";
case event_type::causes_resonance_cascade: return "causes_resonance_cascade";
case event_type::character_gains_effect: return "character_gains_effect";
case event_type::character_gets_headshot: return "character_gets_headshot";
case event_type::character_heals_damage: return "character_heals_damage";
case event_type::character_kills_character: return "character_kills_character";
case event_type::character_kills_monster: return "character_kills_monster";
case event_type::character_loses_effect: return "character_loses_effect";
case event_type::character_takes_damage: return "character_takes_damage";
case event_type::character_triggers_trap: return "character_triggers_trap";
case event_type::consumes_marloss_item: return "consumes_marloss_item";
case event_type::crosses_marloss_threshold: return "crosses_marloss_threshold";
Expand Down Expand Up @@ -87,7 +91,7 @@ constexpr std::array<std::pair<const char *, cata_variant_type>,
constexpr std::array<std::pair<const char *, cata_variant_type>,
event_spec_character::fields.size()> event_spec_character::fields;

static_assert( static_cast<int>( event_type::num_event_types ) == 57,
static_assert( static_cast<int>( event_type::num_event_types ) == 61,
"This static_assert is a reminder to add a definition below when you add a new "
"event_type. If your event_spec specialization inherits from another struct for "
"its fields definition then you probably don't need a definition here." );
Expand All @@ -99,12 +103,15 @@ static_assert( static_cast<int>( event_type::num_event_types ) == 57,

DEFINE_EVENT_FIELDS( activates_artifact )
DEFINE_EVENT_FIELDS( administers_mutagen )
DEFINE_EVENT_FIELDS( avatar_moves )
DEFINE_EVENT_FIELDS( broken_bone_mends )
DEFINE_EVENT_FIELDS( buries_corpse )
DEFINE_EVENT_FIELDS( character_gains_effect )
DEFINE_EVENT_FIELDS( character_heals_damage )
DEFINE_EVENT_FIELDS( character_kills_character )
DEFINE_EVENT_FIELDS( character_kills_monster )
DEFINE_EVENT_FIELDS( character_loses_effect )
DEFINE_EVENT_FIELDS( character_takes_damage )
DEFINE_EVENT_FIELDS( character_triggers_trap )
DEFINE_EVENT_FIELDS( consumes_marloss_item )
DEFINE_EVENT_FIELDS( crosses_mutation_threshold )
Expand Down
57 changes: 54 additions & 3 deletions src/event.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,19 @@ enum class event_type {
activates_mininuke,
administers_mutagen,
angers_amigara_horrors,
avatar_moves,
awakes_dark_wyrms,
becomes_wanted,
broken_bone_mends,
buries_corpse,
causes_resonance_cascade,
character_gains_effect,
character_gets_headshot,
character_heals_damage,
character_kills_character,
character_kills_monster,
character_loses_effect,
character_takes_damage,
character_triggers_trap,
consumes_marloss_item,
crosses_marloss_threshold,
Expand Down Expand Up @@ -91,6 +95,18 @@ std::string enum_to_string<event_type>( event_type data );

} // namespace io

namespace std
{

template<>
struct hash<event_type> {
size_t operator()( const event_type v ) const noexcept {
return static_cast<size_t>( v );
}
};

} // namespace std

namespace cata
{

Expand All @@ -117,7 +133,7 @@ struct event_spec_character {
};
};

static_assert( static_cast<int>( event_type::num_event_types ) == 57,
static_assert( static_cast<int>( event_type::num_event_types ) == 61,
"This static_assert is to remind you to add a specialization for your new "
"event_type below" );

Expand Down Expand Up @@ -145,6 +161,14 @@ struct event_spec<event_type::administers_mutagen> {
template<>
struct event_spec<event_type::angers_amigara_horrors> : event_spec_empty {};

template<>
struct event_spec<event_type::avatar_moves> {
static constexpr std::array<std::pair<const char *, cata_variant_type>, 1> fields = {{
{ "mount", cata_variant_type::mtype_id },
}
};
};

template<>
struct event_spec<event_type::awakes_dark_wyrms> : event_spec_empty {};

Expand Down Expand Up @@ -182,6 +206,18 @@ struct event_spec<event_type::character_gains_effect> {
};
};

template<>
struct event_spec<event_type::character_gets_headshot> : event_spec_character {};

template<>
struct event_spec<event_type::character_heals_damage> {
static constexpr std::array<std::pair<const char *, cata_variant_type>, 2> fields = {{
{ "character", cata_variant_type::character_id },
{ "damage", cata_variant_type::int_ },
}
};
};

template<>
struct event_spec<event_type::character_kills_monster> {
static constexpr std::array<std::pair<const char *, cata_variant_type>, 2> fields = {{
Expand Down Expand Up @@ -210,6 +246,15 @@ struct event_spec<event_type::character_loses_effect> {
};
};

template<>
struct event_spec<event_type::character_takes_damage> {
static constexpr std::array<std::pair<const char *, cata_variant_type>, 2> fields = {{
{ "character", cata_variant_type::character_id },
{ "damage", cata_variant_type::int_ },
}
};
};

template<>
struct event_spec<event_type::character_triggers_trap> {
static constexpr std::array<std::pair<const char *, cata_variant_type>, 2> fields = {{
Expand Down Expand Up @@ -476,7 +521,9 @@ struct make_event_helper;
class event
{
public:
event( event_type type, time_point time, std::map<std::string, cata_variant> &&data )
using data_type = std::map<std::string, cata_variant>;

event( event_type type, time_point time, data_type &&data )
: type_( type )
, time_( time )
, data_( std::move( data ) )
Expand Down Expand Up @@ -526,10 +573,14 @@ class event
auto get( const std::string &key ) const {
return get_variant( key ).get<T>();
}

const data_type &data() const {
return data_;
}
private:
event_type type_;
time_point time_;
std::map<std::string, cata_variant> data_;
data_type data_;
};

namespace event_detail
Expand Down
22 changes: 17 additions & 5 deletions src/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@
#include "dependency_tree.h"
#include "editmap.h"
#include "enums.h"
#include "timed_event.h"
#include "faction.h"
#include "filesystem.h"
#include "game_constants.h"
Expand Down Expand Up @@ -104,9 +103,11 @@
#include "sdltiles.h"
#include "sounds.h"
#include "start_location.h"
#include "stats_tracker.h"
#include "string_formatter.h"
#include "string_input_popup.h"
#include "submap.h"
#include "timed_event.h"
#include "translations.h"
#include "trap.h"
#include "uistate.h"
Expand Down Expand Up @@ -279,6 +280,7 @@ game::game() :
{
player_was_sleeping = false;
reset_light_level();
events().subscribe( &*stats_tracker_ptr );
events().subscribe( &*kill_tracker_ptr );
events().subscribe( &*memorial_logger_ptr );
world_generator = std::make_unique<worldfactory>();
Expand Down Expand Up @@ -662,6 +664,7 @@ void game::setup()

SCT.vSCT.clear(); //Delete pending messages

stats().clear();
// reset kill counts
kill_tracker_ptr->clear();
// reset follower list
Expand Down Expand Up @@ -2856,6 +2859,11 @@ event_bus &game::events()
return *event_bus_ptr;
}

stats_tracker &game::stats()
{
return *stats_tracker_ptr;
}

memorial_logger &game::memorial()
{
return *memorial_logger_ptr;
Expand Down Expand Up @@ -9070,8 +9078,12 @@ bool game::walk_move( const tripoint &dest_loc )
add_msg( m_good, _( "You are hiding in the %s." ), m.name( dest_loc ) );
}

if( dest_loc != u.pos() && !u.is_mounted() ) {
u.lifetime_stats.squares_walked++;
if( dest_loc != u.pos() ) {
mtype_id mount_type;
if( u.is_mounted() ) {
mount_type = u.mounted_creature->type->id;
}
g->events().send<event_type::avatar_moves>( mount_type );
}

tripoint oldpos = u.pos();
Expand Down Expand Up @@ -9722,7 +9734,7 @@ void game::on_move_effects()
// TODO: Move this to a character method
if( !u.is_mounted() ) {
const item muscle( "muscle" );
if( u.lifetime_stats.squares_walked % 8 == 0 ) {// active power gen
if( one_in( 8 ) ) {// active power gen
if( u.has_active_bionic( bionic_id( "bio_torsionratchet" ) ) ) {
u.charge_power( 1 );
}
Expand All @@ -9732,7 +9744,7 @@ void game::on_move_effects()
}
}
}
if( u.lifetime_stats.squares_walked % 160 == 0 ) { // passive power gen
if( one_in( 160 ) ) {// passive power gen
if( u.has_bionic( bionic_id( "bio_torsionratchet" ) ) ) {
u.charge_power( 1 );
}
Expand Down
5 changes: 4 additions & 1 deletion src/game.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,9 @@ class map;
class memorial_logger;
class faction_manager;
class new_faction_manager;
class player;
class npc;
class player;
class stats_tracker;
class vehicle;
class Creature_tracker;
class scenario;
Expand Down Expand Up @@ -875,6 +876,7 @@ class game
pimpl<scent_map> scent_ptr;
pimpl<timed_event_manager> timed_event_manager_ptr;
pimpl<event_bus> event_bus_ptr;
pimpl<stats_tracker> stats_tracker_ptr;
pimpl<kill_tracker> kill_tracker_ptr;
pimpl<memorial_logger> memorial_logger_ptr;

Expand All @@ -886,6 +888,7 @@ class game
timed_event_manager &timed_events;

event_bus &events();
stats_tracker &stats();
memorial_logger &memorial();

pimpl<Creature_tracker> critter_tracker;
Expand Down
26 changes: 26 additions & 0 deletions src/hash_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,32 @@ struct tuple_hash {
}
};

// auto_hash will use std::hash for most types but tuple_hash for pair or
// tuple.
template<typename T>
struct auto_hash : std::hash<T> {};

template<typename T, typename U>
struct auto_hash<std::pair<T, U>> : tuple_hash {};

template<typename... T>
struct auto_hash<std::tuple<T...>> : tuple_hash {};

struct range_hash {
template<typename Range>
std::size_t operator()( const Range &range ) const noexcept {
using value_type = typename Range::value_type;
using hash_type = auto_hash<value_type>;
hash_type hash;

std::size_t seed = range.size();
for( const auto &value : range ) {
hash_combine( seed, value, hash );
}
return seed;
}
};

} // namespace cata

#endif // CATA_TUPLE_HASH_H
Loading

0 comments on commit 9df45a3

Please sign in to comment.