stockpiles: serialization complete

* working file import/export
develop
Casey Link 2014-11-20 10:33:09 +01:00
parent 224a19295d
commit f7ed821ef9
1 changed files with 246 additions and 52 deletions

@ -43,6 +43,8 @@
#include <google/protobuf/text_format.h> #include <google/protobuf/text_format.h>
#include <sys/stat.h>
#include <functional> #include <functional>
using std::vector; using std::vector;
@ -66,6 +68,9 @@ static bool copystock_guard ( df::viewscreen *top );
static command_result savestock ( color_ostream &out, vector <string> & parameters ); static command_result savestock ( color_ostream &out, vector <string> & parameters );
static bool savestock_guard ( df::viewscreen *top ); static bool savestock_guard ( df::viewscreen *top );
static command_result loadstock( color_ostream &out, vector <string> & parameters );
static bool loadstock_guard ( df::viewscreen *top );
DFHACK_PLUGIN ( "stockpiles" ); DFHACK_PLUGIN ( "stockpiles" );
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands ) DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands )
@ -91,6 +96,16 @@ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <Plug
" - In 'p': invoke in order to switch back to 'q'.\n" " - In 'p': invoke in order to switch back to 'q'.\n"
) )
); );
commands.push_back (
PluginCommand (
"loadstock", "Import stockpile settings and aplply them to the stockpile under cursor.",
loadstock, loadstock_guard,
" - In 'q' or 't' mode: select a stockpile and invoke in order\n"
" to switch to the 'p' stockpile creation mode, and initialize\n"
" the custom settings from the selected stockpile.\n"
" - In 'p': invoke in order to switch back to 'q'.\n"
)
);
} }
std::cerr << "world: " << sizeof ( df::world ) << " ui: " << sizeof ( df::ui ) std::cerr << "world: " << sizeof ( df::world ) << " ui: " << sizeof ( df::ui )
<< " b_stock: " << sizeof ( building_stockpilest ) << endl; << " b_stock: " << sizeof ( building_stockpilest ) << endl;
@ -167,6 +182,23 @@ static bool savestock_guard ( df::viewscreen *top )
} }
} }
static bool loadstock_guard ( df::viewscreen *top )
{
using namespace ui_sidebar_mode;
if ( !Gui::dwarfmode_hotkey ( top ) )
return false;
switch ( ui->main.mode ) {
case Stockpiles:
return true;
case BuildingItems:
case QueryBuilding:
return !!virtual_cast<building_stockpilest> ( world->selected_building );
default:
return false;
}
}
/** /**
@ -319,14 +351,58 @@ public:
StockpileSerializer ( color_ostream &out, building_stockpilest const * stockpile ) StockpileSerializer ( color_ostream &out, building_stockpilest const * stockpile )
: mOut ( &out ) : mOut ( &out )
, mPile ( stockpile ) { , mPile ( stockpile ) {
// build other mats indices
// build other_mats indices
furniture_setup_other_mats(); furniture_setup_other_mats();
bars_blocks_setup_other_mats(); bars_blocks_setup_other_mats();
finished_goods_setup_other_mats(); finished_goods_setup_other_mats();
weapons_armor_setup_other_mats(); weapons_armor_setup_other_mats();
} }
StockpileSettings write() { ~StockpileSerializer() {}
/**
* Will serialize stockpile settings to a file (overwrites existing files)
* @return success/failure
*/
bool serialize_to_file ( const std::string & file ) {
mBuffer.Clear();
write();
std::fstream output ( file, std::ios::out | std::ios::binary );
return mBuffer.SerializeToOstream ( &output );
}
/**
* Serializes the stockpile settings to a string.
* @return empty string on error
*/
std::string serialize_to_string() {
mBuffer.Clear();
write();
std::string str;
if ( !TextFormat::PrintToString ( mBuffer, &str ) )
return std::string();
return str;
}
bool unserialize_from_file(const std::string & file ) {
mBuffer.Clear();
std::fstream input(file, std::ios::in | std::ios::binary);
const bool res = mBuffer.ParseFromIstream(&input);
read();
return res;
}
bool unserialize_from_string(const std::string & data) {
mBuffer.Clear();
return TextFormat::ParseFromString(data, &mBuffer);
}
private:
/**
read memory structures and serialize to protobuf
*/
void write() {
// *mOut << "GROUP SET " << bitfield_to_string(mPile->settings.flags) << endl; // *mOut << "GROUP SET " << bitfield_to_string(mPile->settings.flags) << endl;
write_general(); write_general();
if ( mPile->settings.flags.bits.animals ) if ( mPile->settings.flags.bits.animals )
@ -359,16 +435,10 @@ public:
write_weapons(); write_weapons();
if ( mPile->settings.flags.bits.armor ) if ( mPile->settings.flags.bits.armor )
write_armor(); write_armor();
std::string str;
TextFormat::PrintToString ( mBuffer, &str );
*mOut << "serialized: " << str << endl;
return mBuffer;
} }
void read ( const StockpileSettings & settings ) { void read () {
*mOut << endl << "==READ==" << endl; *mOut << endl << "==READ==" << endl;
mBuffer = settings;
read_general(); read_general();
read_animals(); read_animals();
read_food(); read_food();
@ -387,8 +457,6 @@ public:
read_armor(); read_armor();
} }
~StockpileSerializer() {}
private:
color_ostream * mOut; color_ostream * mOut;
building_stockpilest const * mPile; building_stockpilest const * mPile;
StockpileSettings mBuffer; StockpileSettings mBuffer;
@ -427,7 +495,7 @@ private:
// are item's of item_type allowed? // are item's of item_type allowed?
typedef std::function<bool ( item_type::item_type ) > FuncItemAllowed; typedef std::function<bool ( item_type::item_type ) > FuncItemAllowed;
// is this material allowed? // is this material allowed?
typedef std::function<bool ( const MaterialInfo &) > FuncMaterialAllowed; typedef std::function<bool ( const MaterialInfo & ) > FuncMaterialAllowed;
struct food_pair { struct food_pair {
// exporting // exporting
@ -497,13 +565,13 @@ private:
} }
} }
void serialize_list_material ( FuncMaterialAllowed is_allowed, FuncWriteExport add_value, std::vector<char> list ) { void serialize_list_material ( FuncMaterialAllowed is_allowed, FuncWriteExport add_value, std::vector<char> list ) {
MaterialInfo mi; MaterialInfo mi;
for ( size_t i = 0; i < list.size(); ++i ) { for ( size_t i = 0; i < list.size(); ++i ) {
if ( list.at ( i ) ) { if ( list.at ( i ) ) {
mi.decode ( 0, i ); mi.decode ( 0, i );
if ( !is_allowed( mi ) ) continue; if ( !is_allowed ( mi ) ) continue;
*mOut << " material" << i << " is " << mi.getToken() << endl; *mOut << " material" << i << " is " << mi.getToken() << endl;
add_value(mi.getToken()); add_value ( mi.getToken() );
} }
} }
} }
@ -520,22 +588,22 @@ private:
} }
void serialize_list_quality ( FuncWriteExport add_value, const bool (&quality_list)[7] ) { void serialize_list_quality ( FuncWriteExport add_value, const bool ( &quality_list ) [7] ) {
using df::enums::item_quality::item_quality; using df::enums::item_quality::item_quality;
df::enum_traits<item_quality> quality_traits; df::enum_traits<item_quality> quality_traits;
for ( size_t i = 0; i < 7; ++i ) { for ( size_t i = 0; i < 7; ++i ) {
if ( quality_list[i] ) { if ( quality_list[i] ) {
const std::string f_type ( quality_traits.key_table[i] ); const std::string f_type ( quality_traits.key_table[i] );
add_value( f_type ); add_value ( f_type );
*mOut << " quality: " << i << " is " << f_type <<endl; *mOut << " quality: " << i << " is " << f_type <<endl;
} }
} }
} }
void unserialize_list_quality( FuncReadImport read_value, int32_t list_size ) { void unserialize_list_quality ( FuncReadImport read_value, int32_t list_size ) {
using df::enums::item_quality::item_quality; using df::enums::item_quality::item_quality;
df::enum_traits<item_quality> quality_traits; df::enum_traits<item_quality> quality_traits;
for ( int i = 0; i < list_size; ++i ) { for ( int i = 0; i < list_size; ++i ) {
const std::string quality = read_value( i ); const std::string quality = read_value ( i );
df::enum_traits<item_quality>::base_type idx = linear_index ( *mOut, quality_traits, quality ); df::enum_traits<item_quality>::base_type idx = linear_index ( *mOut, quality_traits, quality );
if ( idx < 0 ) { if ( idx < 0 ) {
*mOut << " invalid quality token " << quality << endl; *mOut << " invalid quality token " << quality << endl;
@ -545,29 +613,29 @@ private:
} }
} }
void serialize_list_other_mats(const std::map<int, std::string> other_mats, FuncWriteExport add_value, std::vector<char> list) { void serialize_list_other_mats ( const std::map<int, std::string> other_mats, FuncWriteExport add_value, std::vector<char> list ) {
for ( size_t i = 0; i < list.size(); ++i ) { for ( size_t i = 0; i < list.size(); ++i ) {
if ( list.at ( i ) ) { if ( list.at ( i ) ) {
const std::string token = other_mats_index(other_mats, i); const std::string token = other_mats_index ( other_mats, i );
if ( token.empty() ) { if ( token.empty() ) {
*mOut << " invalid other material with index " << i << endl; *mOut << " invalid other material with index " << i << endl;
continue; continue;
} }
add_value(token); add_value ( token );
*mOut << " other mats " << i << " is " << token << endl; *mOut << " other mats " << i << " is " << token << endl;
} }
} }
} }
void unserialize_list_other_mats(const std::map<int, std::string> other_mats, FuncReadImport read_value, int32_t list_size ) { void unserialize_list_other_mats ( const std::map<int, std::string> other_mats, FuncReadImport read_value, int32_t list_size ) {
for ( int i = 0; i < list_size; ++i ) { for ( int i = 0; i < list_size; ++i ) {
const std::string token = read_value( i ); const std::string token = read_value ( i );
size_t idx = other_mats_token( other_mats, token ); size_t idx = other_mats_token ( other_mats, token );
if ( idx < 0 ) { if ( idx < 0 ) {
*mOut << "invalid other mat with token " << token; *mOut << "invalid other mat with token " << token;
continue; continue;
} }
*mOut << " other_mats " << idx << " is " << token << endl; *mOut << " other_mats " << idx << " is " << token << endl;
} }
} }
void serialize_list_itemdef ( FuncWriteExport add_value, std::vector<char> list, std::vector<df::itemdef *> items, item_type::item_type type ) { void serialize_list_itemdef ( FuncWriteExport add_value, std::vector<char> list, std::vector<df::itemdef *> items, item_type::item_type type ) {
@ -587,20 +655,20 @@ private:
void unserialize_list_itemdef ( FuncReadImport read_value, int32_t list_size ) { void unserialize_list_itemdef ( FuncReadImport read_value, int32_t list_size ) {
for ( int i = 0; i < list_size; ++i ) { for ( int i = 0; i < list_size; ++i ) {
std::string token = read_value( i ); std::string token = read_value ( i );
ItemTypeInfo ii; ItemTypeInfo ii;
if ( !ii.find ( token ) ) continue; if ( !ii.find ( token ) ) continue;
*mOut << " itemdef " << ii.subtype << " is " << token << endl; *mOut << " itemdef " << ii.subtype << " is " << token << endl;
} }
} }
std::string other_mats_index( const std::map<int, std::string> other_mats, int idx ) { std::string other_mats_index ( const std::map<int, std::string> other_mats, int idx ) {
auto it = other_mats.find ( idx ); auto it = other_mats.find ( idx );
if ( it == other_mats.end() ) if ( it == other_mats.end() )
return std::string(); return std::string();
return it->second; return it->second;
} }
int other_mats_token( const std::map<int, std::string> other_mats, const std::string & token) { int other_mats_token ( const std::map<int, std::string> other_mats, const std::string & token ) {
for ( auto it = other_mats.begin(); it != other_mats.end(); ++it ) { for ( auto it = other_mats.begin(); it != other_mats.end(); ++it ) {
if ( it->second == token ) if ( it->second == token )
return it->first; return it->first;
@ -613,12 +681,20 @@ private:
mBuffer.set_max_wheelbarrows ( mPile->max_wheelbarrows ); mBuffer.set_max_wheelbarrows ( mPile->max_wheelbarrows );
mBuffer.set_use_links_only ( mPile->use_links_only ); mBuffer.set_use_links_only ( mPile->use_links_only );
mBuffer.set_unknown1 ( mPile->settings.unk1 ); mBuffer.set_unknown1 ( mPile->settings.unk1 );
*mOut << "unknown is " << mPile->settings.unk1 << endl; mBuffer.set_allow_inorganic ( mPile->settings.allow_inorganic );
mBuffer.set_allow_organic ( mPile->settings.allow_organic );
} }
void read_general() { void read_general() {
int bins = mBuffer.max_bins(); const int bins = mBuffer.max_bins();
*mOut << "Max bins: " << bins <<endl; const int wheelbarrows = mBuffer.max_wheelbarrows();
const bool use_links_only = mBuffer.use_links_only();
const bool unknown1 = mBuffer.unknown1();
const bool allow_inorganic = mBuffer.allow_inorganic();
const bool allow_organic = mBuffer.allow_organic();
} }
void write_animals() { void write_animals() {
dfstockpiles::StockpileSettings::AnimalsSet animals; dfstockpiles::StockpileSettings::AnimalsSet animals;
animals.set_empty_cages ( mPile->settings.animals.empty_cages ); animals.set_empty_cages ( mPile->settings.animals.empty_cages );
@ -896,9 +972,9 @@ private:
} }
} }
// other mats // other mats
serialize_list_other_mats(mOtherMatsFurniture, [=] ( const std::string &token ) { serialize_list_other_mats ( mOtherMatsFurniture, [=] ( const std::string &token ) {
furniture->add_other_mats( token ); furniture->add_other_mats ( token );
}, mPile->settings.furniture.other_mats ); }, mPile->settings.furniture.other_mats );
// for ( size_t i = 0; i < mPile->settings.furniture.other_mats.size(); ++i ) { // for ( size_t i = 0; i < mPile->settings.furniture.other_mats.size(); ++i ) {
// if ( mPile->settings.furniture.other_mats.at ( i ) ) { // if ( mPile->settings.furniture.other_mats.at ( i ) ) {
@ -911,12 +987,12 @@ private:
// *mOut << " other mats " << i << " is " << token << endl; // *mOut << " other mats " << i << " is " << token << endl;
// } // }
// } // }
serialize_list_quality([=] ( const std::string &token ) { serialize_list_quality ( [=] ( const std::string &token ) {
furniture->add_quality_core ( token ); furniture->add_quality_core ( token );
}, mPile->settings.furniture.quality_core); }, mPile->settings.furniture.quality_core );
serialize_list_quality([=] ( const std::string &token ) { serialize_list_quality ( [=] ( const std::string &token ) {
furniture->add_quality_total( token ); furniture->add_quality_total ( token );
}, mPile->settings.furniture.quality_total); }, mPile->settings.furniture.quality_total );
} }
/* skip gems and non hard things /* skip gems and non hard things
@ -949,8 +1025,8 @@ private:
*mOut << " mats " << mi.index << " is " << token << endl; *mOut << " mats " << mi.index << " is " << token << endl;
} }
// other materials // other materials
unserialize_list_other_mats( mOtherMatsFurniture, [=] ( const size_t & idx ) -> const std::string& { unserialize_list_other_mats ( mOtherMatsFurniture, [=] ( const size_t & idx ) -> const std::string& {
return furniture.other_mats( idx ); return furniture.other_mats ( idx );
}, furniture.other_mats_size() ); }, furniture.other_mats_size() );
// core quality // core quality
@ -1209,8 +1285,8 @@ private:
}, mPile->settings.ammo.quality_core ); }, mPile->settings.ammo.quality_core );
// quality total // quality total
serialize_list_quality ( [=] ( const std::string &token ) { serialize_list_quality ( [=] ( const std::string &token ) {
ammo->add_quality_total( token ); ammo->add_quality_total ( token );
}, mPile->settings.ammo.quality_total); }, mPile->settings.ammo.quality_total );
} }
void read_ammo() { void read_ammo() {
@ -1787,7 +1863,7 @@ private:
} }
bool armor_mat_is_allowed ( const MaterialInfo &mi ) { bool armor_mat_is_allowed ( const MaterialInfo &mi ) {
return weapons_mat_is_allowed ( mi ); return mi.isValid() && mi.material && mi.material->flags.is_set ( material_flags::IS_METAL );
} }
void write_armor() { void write_armor() {
@ -1796,6 +1872,48 @@ private:
armor->set_unusable ( mPile->settings.armor.unusable ); armor->set_unusable ( mPile->settings.armor.unusable );
armor->set_usable ( mPile->settings.armor.usable ); armor->set_usable ( mPile->settings.armor.usable );
// armor type
serialize_list_itemdef ( [=] ( const std::string &token ) {
armor->add_body ( token );
}, mPile->settings.armor.body,
std::vector<df::itemdef*> ( world->raws.itemdefs.armor.begin(),world->raws.itemdefs.armor.end() ),
item_type::ARMOR );
// helm type
serialize_list_itemdef ( [=] ( const std::string &token ) {
armor->add_head ( token );
}, mPile->settings.armor.head,
std::vector<df::itemdef*> ( world->raws.itemdefs.helms.begin(),world->raws.itemdefs.helms.end() ),
item_type::HELM );
// shoes type
serialize_list_itemdef ( [=] ( const std::string &token ) {
armor->add_feet ( token );
}, mPile->settings.armor.feet,
std::vector<df::itemdef*> ( world->raws.itemdefs.shoes.begin(),world->raws.itemdefs.shoes.end() ),
item_type::SHOES );
// gloves type
serialize_list_itemdef ( [=] ( const std::string &token ) {
armor->add_hands ( token );
}, mPile->settings.armor.hands,
std::vector<df::itemdef*> ( world->raws.itemdefs.gloves.begin(),world->raws.itemdefs.gloves.end() ),
item_type::GLOVES );
// pant type
serialize_list_itemdef ( [=] ( const std::string &token ) {
armor->add_legs ( token );
}, mPile->settings.armor.legs,
std::vector<df::itemdef*> ( world->raws.itemdefs.pants.begin(),world->raws.itemdefs.pants.end() ),
item_type::PANTS );
// shield type
serialize_list_itemdef ( [=] ( const std::string &token ) {
armor->add_shield ( token );
}, mPile->settings.armor.shield,
std::vector<df::itemdef*> ( world->raws.itemdefs.shields.begin(),world->raws.itemdefs.shields.end() ),
item_type::SHIELD );
// materials // materials
FuncMaterialAllowed mat_filter = std::bind ( &StockpileSerializer::armor_mat_is_allowed, this, _1 ); FuncMaterialAllowed mat_filter = std::bind ( &StockpileSerializer::armor_mat_is_allowed, this, _1 );
serialize_list_material ( mat_filter, [=] ( const std::string &token ) { serialize_list_material ( mat_filter, [=] ( const std::string &token ) {
@ -1828,6 +1946,36 @@ private:
*mOut << "unusable " << unusable << endl; *mOut << "unusable " << unusable << endl;
*mOut << "usable " << usable << endl; *mOut << "usable " << usable << endl;
// body type
unserialize_list_itemdef ( [=] ( const size_t & idx ) -> const std::string& {
return armor.body ( idx );
}, armor.body_size() );
// head type
unserialize_list_itemdef ( [=] ( const size_t & idx ) -> const std::string& {
return armor.head ( idx );
}, armor.head_size() );
// feet type
unserialize_list_itemdef ( [=] ( const size_t & idx ) -> const std::string& {
return armor.feet ( idx );
}, armor.feet_size() );
// hands type
unserialize_list_itemdef ( [=] ( const size_t & idx ) -> const std::string& {
return armor.hands ( idx );
}, armor.hands_size() );
// legs type
unserialize_list_itemdef ( [=] ( const size_t & idx ) -> const std::string& {
return armor.legs ( idx );
}, armor.legs_size() );
// shield type
unserialize_list_itemdef ( [=] ( const size_t & idx ) -> const std::string& {
return armor.shield ( idx );
}, armor.shield_size() );
// materials // materials
FuncMaterialAllowed mat_filter = std::bind ( &StockpileSerializer::armor_mat_is_allowed, this, _1 ); FuncMaterialAllowed mat_filter = std::bind ( &StockpileSerializer::armor_mat_is_allowed, this, _1 );
unserialize_list_material ( mat_filter, [=] ( const size_t & idx ) -> const std::string& { unserialize_list_material ( mat_filter, [=] ( const size_t & idx ) -> const std::string& {
@ -1851,20 +1999,66 @@ private:
} }
}; };
static bool file_exists(const std::string& filename )
{
struct stat buf;
if ( stat ( filename.c_str(), &buf ) != -1 ) {
return true;
}
return false;
}
static bool is_dfstockfile(const std::string& filename) {
return filename.rfind(".dfstock") != std::string::npos;
}
// exporting
static command_result savestock ( color_ostream &out, vector <string> & parameters ) static command_result savestock ( color_ostream &out, vector <string> & parameters )
{ {
// HOTKEY COMMAND: CORE ALREADY SUSPENDED
building_stockpilest *sp = virtual_cast<building_stockpilest> ( world->selected_building ); building_stockpilest *sp = virtual_cast<building_stockpilest> ( world->selected_building );
if ( !sp ) { if ( !sp ) {
out.printerr ( "Selected building isn't a stockpile.\n" ); out.printerr ( "Selected building isn't a stockpile.\n" );
return CR_WRONG_USAGE; return CR_WRONG_USAGE;
} }
// for testing
StockpileSerializer cereal ( out, sp ); StockpileSerializer cereal ( out, sp );
StockpileSettings s = cereal.write(); if ( parameters.size() < 1 ) {
StockpileSerializer cereal2 ( out, sp ); std::string data = cereal.serialize_to_string();
cereal2.read ( s ); out << data << endl;
} else {
std::string file = parameters.at ( 0 );
if ( !is_dfstockfile ( file ) ) file += ".dfstock";
if ( !cereal.serialize_to_file ( file ) ) {
out << "serialize failed" << endl;
return CR_FAILURE;
}
}
return CR_OK;
}
// importing
static command_result loadstock ( color_ostream &out, vector <string> & parameters )
{
building_stockpilest *sp = virtual_cast<building_stockpilest> ( world->selected_building );
if ( !sp ) {
out.printerr ( "Selected building isn't a stockpile.\n" );
return CR_WRONG_USAGE;
}
if ( parameters.size() != 1 ||
!file_exists ( parameters.at ( 0 ) ) ||
!is_dfstockfile ( parameters.at ( 0 ) ) ) {
out << parameters.size() << "\t" << file_exists(parameters.at(0)) << "\t" << is_dfstockfile(parameters.at(0)) << endl;
out.printerr ( "loadstock: first parameter must be a .dfstock file\n" );
return CR_WRONG_USAGE;
}
StockpileSerializer cereal ( out, sp );
if ( !cereal.unserialize_from_file ( parameters.at ( 0 ) ) ) {
out << "unserialize failed" << endl;
return CR_FAILURE;
}
return CR_OK; return CR_OK;
} }