Skip to content

Commit

Permalink
Store crafting related item data in a separate object inside a value_ptr
Browse files Browse the repository at this point in the history
This reduces the overhead for non-craft items to a single pointer.
  • Loading branch information
BevapDin authored and kevingranade committed Jan 2, 2020
1 parent 3399e37 commit 89a7b1c
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 42 deletions.
6 changes: 3 additions & 3 deletions src/crafting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -956,7 +956,7 @@ int item::get_next_failure_point() const
debugmsg( "get_next_failure_point() called on non-craft '%s.' Aborting.", tname() );
return INT_MAX;
}
return next_failure_point >= 0 ? next_failure_point : INT_MAX;
return craft_data_->next_failure_point >= 0 ? craft_data_->next_failure_point : INT_MAX;
}

void item::set_next_failure_point( const player &crafter )
Expand All @@ -969,7 +969,7 @@ void item::set_next_failure_point( const player &crafter )
const int percent_left = 10000000 - item_counter;
const int failure_point_delta = crafter.crafting_success_roll( get_making() ) * percent_left;

next_failure_point = item_counter + failure_point_delta;
craft_data_->next_failure_point = item_counter + failure_point_delta;
}

static void destroy_random_component( item &craft, const player &crafter )
Expand Down Expand Up @@ -1036,7 +1036,7 @@ requirement_data item::get_continue_reqs() const
debugmsg( "get_continue_reqs() called on non-craft '%s.' Aborting.", tname() );
return requirement_data();
}
return requirement_data::continue_requirements( comps_used, components );
return requirement_data::continue_requirements( craft_data_->comps_used, components );
}

void item::inherit_flags( const item &parent )
Expand Down
43 changes: 25 additions & 18 deletions src/item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -284,9 +284,10 @@ static const item *get_most_rotten_component( const item &craft )
item::item( const recipe *rec, int qty, std::list<item> items, std::vector<item_comp> selections )
: item( "craft", calendar::turn, qty )
{
making = rec;
craft_data_ = cata::make_value<craft_data>();
craft_data_->making = rec;
components = items;
comps_used = selections;
craft_data_->comps_used = selections;

if( is_food() ) {
active = true;
Expand Down Expand Up @@ -753,10 +754,10 @@ bool item::stacks_with( const item &rhs, bool check_components ) const
if( corpse != nullptr && rhs.corpse != nullptr && corpse->id != rhs.corpse->id ) {
return false;
}
if( is_craft() && rhs.is_craft() ) {
if( get_making().ident() != rhs.get_making().ident() ) {
return false;
}
if( craft_data_ || rhs.craft_data_ ) {
// In-progress crafts are always distinct items. Easier to handle for the player,
// and there shouldn't be that many items of this type around anyway.
return false;
}
if( check_components || is_comestible() || is_craft() ) {
//Only check if at least one item isn't using the default recipe or is comestible
Expand Down Expand Up @@ -2560,7 +2561,7 @@ void item::final_info( std::vector<iteminfo> &info, const iteminfo_query *parts,
"It is %d percent complete." );
const int percent_progress = item_counter / 100000;
info.push_back( iteminfo( "DESCRIPTION", string_format( desc,
making->result_name(),
craft_data_->making->result_name(),
percent_progress ) ) );
} else {
info.push_back( iteminfo( "DESCRIPTION", type->description.translated() ) );
Expand Down Expand Up @@ -3799,7 +3800,7 @@ std::string item::tname( unsigned int quantity, bool with_prefix, unsigned int t
} else if( is_armor() && has_clothing_mod() ) {
maintext = label( quantity ) + "+1";
} else if( is_craft() ) {
maintext = string_format( _( "in progress %s" ), making->result_name() );
maintext = string_format( _( "in progress %s" ), craft_data_->making->result_name() );
if( charges > 1 ) {
maintext += string_format( " (%d)", charges );
}
Expand Down Expand Up @@ -5713,7 +5714,7 @@ bool item::is_brewable() const
bool item::is_food_container() const
{
return ( !contents.empty() && contents.front().is_food() ) || ( is_craft() &&
making->create_result().is_food_container() );
craft_data_->making->create_result().is_food_container() );
}

bool item::has_temperature() const
Expand Down Expand Up @@ -6034,7 +6035,7 @@ bool item::is_salvageable() const

bool item::is_craft() const
{
return making != nullptr;
return craft_data_ != nullptr;
}

bool item::is_funnel_container( units::volume &bigger_than ) const
Expand Down Expand Up @@ -9451,37 +9452,43 @@ void item::set_favorite( const bool favorite )

const recipe &item::get_making() const
{
if( !making ) {
if( !craft_data_ ) {
debugmsg( "'%s' is not a craft or has a null recipe", tname() );
return recipe().ident().obj();
static const recipe dummy{};
return dummy;
}
return *making;
assert( craft_data_->making );
return *craft_data_->making;
}

void item::set_tools_to_continue( bool value )
{
tools_to_continue = value;
assert( craft_data_ );
craft_data_->tools_to_continue = value;
}

bool item::has_tools_to_continue() const
{
return tools_to_continue;
assert( craft_data_ );
return craft_data_->tools_to_continue;
}

void item::set_cached_tool_selections( const std::vector<comp_selection<tool_comp>> &selections )
{
cached_tool_selections = selections;
assert( craft_data_ );
craft_data_->cached_tool_selections = selections;
}

const std::vector<comp_selection<tool_comp>> &item::get_cached_tool_selections() const
{
return cached_tool_selections;
assert( craft_data_ );
return craft_data_->cached_tool_selections;
}

const cata::value_ptr<islot_comestible> &item::get_comestible() const
{
if( is_craft() ) {
return find_type( making->result() )->comestible;
return find_type( craft_data_->making->result() )->comestible;
} else {
return type->comestible;
}
Expand Down
31 changes: 22 additions & 9 deletions src/item.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <utility>

#include "calendar.h"
#include "value_ptr.h"
#include "cata_utility.h"
#include "craft_command.h"
#include "debug.h"
Expand Down Expand Up @@ -42,12 +43,11 @@ namespace cata
{
template<typename T>
class optional;
template<typename T>
class value_ptr;
} // namespace cata
class nc_color;
class JsonIn;
class JsonOut;
class JsonObject;
class iteminfo_query;
template<typename T>
class ret_val;
Expand Down Expand Up @@ -2113,13 +2113,26 @@ class item : public visitable<item>
std::string corpse_name; // Name of the late lamented
std::set<matec_id> techniques; // item specific techniques

// Only for in-progress crafts
const recipe *making = nullptr;
int next_failure_point = -1;
std::vector<item_comp> comps_used;
// If the crafter has insufficient tools to continue to the next 5% progress step
bool tools_to_continue = false;
std::vector<comp_selection<tool_comp>> cached_tool_selections;
/**
* Data for items that represent in-progress crafts.
*/
class craft_data
{
public:
const recipe *making = nullptr;
int next_failure_point = -1;
std::vector<item_comp> comps_used;
// If the crafter has insufficient tools to continue to the next 5% progress step
bool tools_to_continue = false;
std::vector<comp_selection<tool_comp>> cached_tool_selections;

void serialize( JsonOut &jsout ) const;
void deserialize( JsonIn &jsin );
void deserialize( const JsonObject &obj );
};

cata::value_ptr<craft_data> craft_data_;

// any relic data specific to this item
cata::optional<relic> relic_data;
public:
Expand Down
56 changes: 44 additions & 12 deletions src/savegame_json.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2034,6 +2034,47 @@ void units::energy::deserialize( JsonIn &jsin )

static void migrate_toolmod( item &it );

void item::craft_data::serialize( JsonOut &jsout ) const
{
jsout.start_object();
jsout.member( "making", making->ident().str() );
jsout.member( "comps_used", comps_used );
jsout.member( "next_failure_point", next_failure_point );
jsout.member( "tools_to_continue", tools_to_continue );
jsout.member( "cached_tool_selections", cached_tool_selections );
jsout.end_object();
}

void item::craft_data::deserialize( JsonIn &jsin )
{
deserialize( jsin.get_object() );
}

void item::craft_data::deserialize( const JsonObject &obj )
{
making = &recipe_id( obj.get_string( "making" ) ).obj();
obj.read( "comps_used", comps_used );
next_failure_point = obj.get_int( "next_failure_point", -1 );
tools_to_continue = obj.get_bool( "tools_to_continue", false );
obj.read( "cached_tool_selections", cached_tool_selections );
}

// Template parameter because item::craft_data is private and I don't want to make it public.
template<typename T>
static void load_legacy_craft_data( io::JsonObjectInputArchive &archive, T &value )
{
if( archive.has_member( "making" ) ) {
value = cata::make_value<typename T::element_type>();
value->deserialize( archive );
}
}

// Dummy function as we never load anything from an output archive.
template<typename T>
static void load_legacy_craft_data( io::JsonObjectOutputArchive &, T & )
{
}

template<typename Archive>
void item::io( Archive &archive )
{
Expand All @@ -2055,10 +2096,6 @@ void item::io( Archive &archive )
corpse = &mtype_id( id ).obj();
}
};
const auto load_making = [this]( const std::string & id ) {
making = &recipe_id( id ).obj();
};

archive.template io<const itype>( "typeid", type, load_type, []( const itype & i ) {
return i.get_id();
}, io::required_tag() );
Expand Down Expand Up @@ -2109,17 +2146,10 @@ void item::io( Archive &archive )
[]( const mtype & i ) {
return i.id.str();
} );
archive.template io<const recipe>( "making", making, load_making,
[]( const recipe & i ) {
return i.ident().str();
} );
archive.io( "craft_data", craft_data_, decltype( craft_data_ )() );
archive.io( "light", light.luminance, nolight.luminance );
archive.io( "light_width", light.width, nolight.width );
archive.io( "light_dir", light.direction, nolight.direction );
archive.io( "comps_used", comps_used, io::empty_default_tag() );
archive.io( "next_failure_point", next_failure_point, -1 );
archive.io( "tools_to_continue", tools_to_continue, false );
archive.io( "cached_tool_selections", cached_tool_selections, io::empty_default_tag() );

archive.io( "relic_data", relic_data );

Expand All @@ -2130,6 +2160,8 @@ void item::io( Archive &archive )
}
/* Loading has finished, following code is to ensure consistency and fixes bugs in saves. */

load_legacy_craft_data( archive, craft_data_ );

double float_damage = 0;
if( archive.read( "damage", float_damage ) ) {
damage_ = std::min( std::max( min_damage(),
Expand Down
21 changes: 21 additions & 0 deletions src/value_ptr.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

#include <memory>

class JsonIn;
class JsonOut;

namespace cata
{

Expand All @@ -24,6 +27,24 @@ class value_ptr : public std::unique_ptr<T>
std::unique_ptr<T>::operator=( std::move( other ) );
return *this;
}

template<typename Stream = JsonOut>
void serialize( Stream &jsout ) const {
if( this->get() ) {
this->get()->serialize( jsout );
} else {
jsout.write_null();
}
}
template<typename Stream = JsonIn>
void deserialize( Stream &jsin ) {
if( jsin.test_null() ) {
this->reset();
} else {
this->reset( new T() );
this->get()->deserialize( jsin );
}
}
};

template <class T, class... Args>
Expand Down

0 comments on commit 89a7b1c

Please sign in to comment.