stockpiles: refactor code into separate files

The file was approaching 3000 lines and contained multiple classes,
making it a real PITA to navigate through. upcoming features would only
add more LOC, so splitting was necessary.
develop
Casey Link 2014-12-02 12:06:01 +01:00
parent 10fa55570e
commit 2e43ea8b38
11 changed files with 3150 additions and 2836 deletions

@ -152,7 +152,7 @@ if (BUILD_SUPPORTED)
DFHACK_PLUGIN(sort sort.cpp LINK_LIBRARIES lua)
DFHACK_PLUGIN(steam-engine steam-engine.cpp)
DFHACK_PLUGIN(stockflow stockflow.cpp LINK_LIBRARIES lua)
DFHACK_PLUGIN(stockpiles stockpiles.cpp PROTOBUFS stockpiles)
add_subdirectory(stockpiles)
DFHACK_PLUGIN(stocks stocks.cpp)
DFHACK_PLUGIN(strangemood strangemood.cpp)
DFHACK_PLUGIN(tiletypes tiletypes.cpp Brushes.h)

File diff suppressed because it is too large Load Diff

@ -0,0 +1,44 @@
PROJECT(stockpiles)
# add *our* headers here.
SET(PROJECT_HDRS
StockpileUtils.h
OrganicMatLookup.h
StockpileSerializer.h
)
SET(PROJECT_SRCS
OrganicMatLookup.cpp
StockpileSerializer.cpp
stockpiles.cpp
)
SET(PROJECT_PROTOS
${CMAKE_CURRENT_SOURCE_DIR}/proto/stockpiles.proto
)
#Create new lists of what sources and headers protoc will output after we invoke it
STRING(REPLACE ".proto" ".pb.cc;" PROJECT_PROTO_SRCS ${PROJECT_PROTOS})
STRING(REPLACE ".proto" ".pb.h;" PROJECT_PROTO_HDRS ${PROJECT_PROTOS})
SET_SOURCE_FILES_PROPERTIES( ${PROJECT_PROTO_HDRS} PROPERTIES GENERATED TRUE)
SET_SOURCE_FILES_PROPERTIES( ${PROJECT_PROTO_SRCS} PROPERTIES GENERATED TRUE)
LIST(APPEND PROJECT_HDRS ${PROJECT_PROTO_HDRS})
LIST(APPEND PROJECT_SRCS ${PROJECT_PROTO_SRCS})
SET_SOURCE_FILES_PROPERTIES( ${PROJECT_HDRS} PROPERTIES HEADER_FILE_ONLY TRUE)
LIST(APPEND PROJECT_SRCS ${PROJECT_HDRS})
#Generate sources from our proto files and store them in the source tree
ADD_CUSTOM_COMMAND(
OUTPUT ${PROJECT_PROTO_SRCS} ${PROJECT_PROTO_HDRS}
COMMAND protoc-bin -I=${CMAKE_CURRENT_SOURCE_DIR}/proto/ --cpp_out=${CMAKE_CURRENT_SOURCE_DIR}/proto/ ${PROJECT_PROTOS}
DEPENDS protoc-bin ${PROJECT_PROTOS}
)
IF(WIN32)
DFHACK_PLUGIN(stockpiles ${PROJECT_SRCS} ${PROJECT_HDRS} LINK_LIBRARIES protobuf-lite)
ELSE()
DFHACK_PLUGIN(stockpiles ${PROJECT_SRCS} ${PROJECT_HDRS} LINK_LIBRARIES protobuf-lite)
ENDIF()

@ -0,0 +1,155 @@
#include "OrganicMatLookup.h"
#include "StockpileUtils.h"
#include "modules/Materials.h"
#include "MiscUtils.h"
#include "df/world.h"
#include "df/world_data.h"
#include "df/creature_raw.h"
#include "df/caste_raw.h"
#include "df/material.h"
using namespace DFHack;
using namespace df::enums;
using df::global::world;
using std::endl;
/**
* Helper class for mapping the various organic mats between their material indices
* and their index in the stockpile_settings structures.
*/
void OrganicMatLookup::food_mat_by_idx ( std::ostream &out, organic_mat_category::organic_mat_category mat_category, std::vector<int16_t>::size_type food_idx, FoodMat & food_mat )
{
out << "food_lookup: food_idx(" << food_idx << ") ";
df::world_raws &raws = world->raws;
df::special_mat_table table = raws.mat_table;
int32_t main_idx = table.organic_indexes[mat_category][food_idx];
int16_t type = table.organic_types[mat_category][food_idx];
if ( mat_category == organic_mat_category::Fish ||
mat_category == organic_mat_category::UnpreparedFish ||
mat_category == organic_mat_category::Eggs )
{
food_mat.creature = raws.creatures.all[type];
food_mat.caste = food_mat.creature->caste[main_idx];
out << " special creature type(" << type << ") caste("<< main_idx <<")" <<endl;
}
else
{
food_mat.material.decode ( type, main_idx );
out << " type(" << type << ") index("<< main_idx <<") token(" << food_mat.material.getToken() << ")" << endl;
}
}
std::string OrganicMatLookup::food_token_by_idx ( std::ostream &out, organic_mat_category::organic_mat_category mat_category, std::vector<int16_t>::size_type idx )
{
FoodMat food_mat;
food_mat_by_idx ( out, mat_category, idx, food_mat );
if ( food_mat.material.isValid() )
{
return food_mat.material.getToken();
}
else if ( food_mat.creature )
{
return food_mat.creature->creature_id + ":" + food_mat.caste->caste_id;
}
return std::string();
}
size_t OrganicMatLookup::food_max_size ( organic_mat_category::organic_mat_category mat_category )
{
return world->raws.mat_table.organic_types[mat_category].size();
}
void OrganicMatLookup::food_build_map ( std::ostream &out )
{
if ( index_built )
return;
df::world_raws &raws = world->raws;
df::special_mat_table table = raws.mat_table;
using df::enums::organic_mat_category::organic_mat_category;
df::enum_traits<organic_mat_category> traits;
for ( int32_t mat_category = traits.first_item_value; mat_category <= traits.last_item_value; ++mat_category )
{
for ( size_t i = 0; i < table.organic_indexes[mat_category].size(); ++i )
{
int16_t type = table.organic_types[mat_category].at ( i );
int32_t index = table.organic_indexes[mat_category].at ( i );
food_index[mat_category].insert ( std::make_pair ( std::make_pair ( type,index ), i ) ); // wtf.. only in c++
}
}
index_built = true;
}
int16_t OrganicMatLookup::food_idx_by_token ( std::ostream &out, organic_mat_category::organic_mat_category mat_category, const std::string & token )
{
int16_t food_idx = -1;
df::world_raws &raws = world->raws;
df::special_mat_table table = raws.mat_table;
out << "food_idx_by_token: ";
if ( mat_category == organic_mat_category::Fish ||
mat_category == organic_mat_category::UnpreparedFish ||
mat_category == organic_mat_category::Eggs )
{
std::vector<std::string> tokens;
split_string ( &tokens, token, ":" );
if ( tokens.size() != 2 )
{
out << "creature " << "invalid CREATURE:CASTE token: " << token << endl;
}
else
{
int16_t creature_idx = find_creature ( tokens[0] );
if ( creature_idx < 0 )
{
out << " creature invalid token " << tokens[0];
}
else
{
food_idx = linear_index ( table.organic_types[mat_category], creature_idx );
if ( tokens[1] == "MALE" )
food_idx += 1;
if ( table.organic_types[mat_category][food_idx] == creature_idx )
out << "creature " << token << " caste " << tokens[1] << " creature_idx(" << creature_idx << ") food_idx("<< food_idx << ")" << endl;
else
{
out << "ERROR creature caste not found: " << token << " caste " << tokens[1] << " creature_idx(" << creature_idx << ") food_idx("<< food_idx << ")" << endl;
food_idx = -1;
}
}
}
}
else
{
if ( !index_built )
food_build_map ( out );
MaterialInfo mat_info = food_mat_by_token ( out, token );
int16_t type = mat_info.type;
int32_t index = mat_info.index;
int16_t food_idx2 = -1;
auto it = food_index[mat_category].find ( std::make_pair ( type, index ) );
if ( it != food_index[mat_category].end() )
{
out << "matinfo: " << token << " type(" << mat_info.type << ") idx(" << mat_info.index << ") food_idx(" << it->second << ")" << endl;
food_idx = it->second;
}
else
{
out << "matinfo: " << token << " type(" << mat_info.type << ") idx(" << mat_info.index << ") food_idx not found :(" << endl;
}
}
return food_idx;
}
MaterialInfo OrganicMatLookup::food_mat_by_token ( std::ostream &out, const std::string & token )
{
MaterialInfo mat_info;
mat_info.find ( token );
return mat_info;
}
bool OrganicMatLookup::index_built = false;
std::vector<OrganicMatLookup::FoodMatMap> OrganicMatLookup::food_index = std::vector<OrganicMatLookup::FoodMatMap> ( 37 );

@ -0,0 +1,47 @@
#pragma once
#include "modules/Materials.h"
#include "df/organic_mat_category.h"
namespace df {
struct creature_raw;
struct caste_raw;
}
/**
* Helper class for mapping the various organic mats between their material indices
* and their index in the stockpile_settings structures.
*/
class OrganicMatLookup
{
// pair of material type and index
typedef std::pair<int16_t, int32_t> FoodMatPair;
// map for using type,index pairs to find the food index
typedef std::map<FoodMatPair, size_t> FoodMatMap;
public:
struct FoodMat
{
DFHack::MaterialInfo material;
df::creature_raw *creature;
df::caste_raw * caste;
FoodMat() : material ( -1 ), creature ( 0 ), caste ( 0 ) {}
};
static void food_mat_by_idx ( std::ostream &out, df::enums::organic_mat_category::organic_mat_category mat_category, std::vector<int16_t>::size_type food_idx, FoodMat & food_mat );
static std::string food_token_by_idx ( std::ostream &out, df::enums::organic_mat_category::organic_mat_category mat_category, std::vector<int16_t>::size_type idx );
static size_t food_max_size ( df::enums::organic_mat_category::organic_mat_category mat_category );
static void food_build_map ( std::ostream &out );
static int16_t food_idx_by_token ( std::ostream &out, df::enums::organic_mat_category::organic_mat_category mat_category, const std::string & token );
static DFHack::MaterialInfo food_mat_by_token ( std::ostream &out, const std::string & token );
static bool index_built;
static std::vector<FoodMatMap> food_index;
private:
OrganicMatLookup();
};

File diff suppressed because it is too large Load Diff

@ -0,0 +1,349 @@
#pragma once
// stockpiles plugin
#include "proto/stockpiles.pb.h"
// dfhack
#include "modules/Materials.h"
#include "modules/Items.h"
// df
#include "df/world.h"
#include "df/world_data.h"
#include "df/organic_mat_category.h"
#include "df/furniture_type.h"
#include "df/item_quality.h"
#include "df/item_type.h"
// stl
#include <functional>
#include <vector>
#include <ostream>
#include <istream>
namespace df {
struct building_stockpilest;
}
/**
* Null buffer that acts like /dev/null for when debug is disabled
*/
class NullBuffer : public std::streambuf
{
public:
int overflow ( int c );
};
class NullStream : public std::ostream
{
public:
NullStream();
private:
NullBuffer m_sb;
};
/**
* Class for serializing the stockpile_settings structure into a Google protobuf
*/
class StockpileSerializer
{
public:
/**
* @param out for debugging
* @param stockpile stockpile to read or write settings to
*/
StockpileSerializer ( df::building_stockpilest * stockpile );
~StockpileSerializer();
void enable_debug ( std::ostream &out );
/**
* Since we depend on protobuf-lite, not the full lib, we copy this function from
* protobuf message.cc
*/
bool serialize_to_ostream(std::ostream* output);
/**
* Will serialize stockpile settings to a file (overwrites existing files)
* @return success/failure
*/
bool serialize_to_file ( const std::string & file );
/**
* Again, copied from message.cc
*/
bool parse_from_istream(std::istream* input);
/**
* Read stockpile settings from file
*/
bool unserialize_from_file ( const std::string & file );
private:
bool mDebug;
std::ostream * mOut;
NullStream mNull;
df::building_stockpilest * mPile;
dfstockpiles::StockpileSettings mBuffer;
std::map<int, std::string> mOtherMatsFurniture;
std::map<int, std::string> mOtherMatsFinishedGoods;
std::map<int, std::string> mOtherMatsBars;
std::map<int, std::string> mOtherMatsBlocks;
std::map<int, std::string> mOtherMatsWeaponsArmor;
std::ostream & debug();
/**
read memory structures and serialize to protobuf
*/
void write();
// parse serialized data into ui indices
void read ();
/**
* Find an enum's value based off the string label.
* @param traits the enum's trait struct
* @param token the string value in key_table
* @return the enum's value, -1 if not found
*/
template<typename E>
static typename df::enum_traits<E>::base_type linear_index ( std::ostream & out, df::enum_traits<E> traits, const std::string &token )
{
auto j = traits.first_item_value;
auto limit = traits.last_item_value;
// sometimes enums start at -1, which is bad news for array indexing
if ( j < 0 )
{
j += abs ( traits.first_item_value );
limit += abs ( traits.first_item_value );
}
for ( ; j <= limit; ++j )
{
// out << " linear_index("<< token <<") = table["<<j<<"/"<<limit<<"]: " <<traits.key_table[j] << endl;
if ( token.compare ( traits.key_table[j] ) == 0 )
return j;
}
return -1;
}
// read the token from the serailized list during import
typedef std::function<std::string ( const size_t& ) > FuncReadImport;
// add the token to the serialized list during export
typedef std::function<void ( const std::string & ) > FuncWriteExport;
// are item's of item_type allowed?
typedef std::function<bool ( df::enums::item_type::item_type ) > FuncItemAllowed;
// is this material allowed?
typedef std::function<bool ( const DFHack::MaterialInfo & ) > FuncMaterialAllowed;
// convenient struct for parsing food stockpile items
struct food_pair
{
// exporting
FuncWriteExport set_value;
std::vector<char> * stockpile_values;
// importing
FuncReadImport get_value;
size_t serialized_count;
bool valid;
food_pair ( FuncWriteExport s, std::vector<char>* sp_v, FuncReadImport g, size_t count )
: set_value ( s )
, stockpile_values ( sp_v )
, get_value ( g )
, serialized_count ( count )
, valid ( true )
{}
food_pair(): valid( false ) {}
};
/**
* There are many repeated (un)serialization cases throughout the stockpile_settings structure,
* so the most common cases have been generalized into generic functions using lambdas.
*
* The basic process to serialize a stockpile_settings structure is:
* 1. loop through the list
* 2. for every element that is TRUE:
* 3. map the specific stockpile_settings index into a general material, creature, etc index
* 4. verify that type is allowed in the list (e.g., no stone in gems stockpiles)
* 5. add it to the protobuf using FuncWriteExport
*
* The unserialization process is the same in reverse.
*/
void serialize_list_organic_mat ( FuncWriteExport add_value, const std::vector<char> * list, df::enums::organic_mat_category::organic_mat_category cat );
/**
* @see serialize_list_organic_mat
*/
void unserialize_list_organic_mat ( FuncReadImport get_value, size_t list_size, std::vector<char> *pile_list, df::enums::organic_mat_category::organic_mat_category cat );
/**
* @see serialize_list_organic_mat
*/
void serialize_list_item_type ( FuncItemAllowed is_allowed, FuncWriteExport add_value, const std::vector<char> &list );
/**
* @see serialize_list_organic_mat
*/
void unserialize_list_item_type ( FuncItemAllowed is_allowed, FuncReadImport read_value, int32_t list_size, std::vector<char> *pile_list );
/**
* @see serialize_list_organic_mat
*/
void serialize_list_material ( FuncMaterialAllowed is_allowed, FuncWriteExport add_value, const std::vector<char> &list );
/**
* @see serialize_list_organic_mat
*/
void unserialize_list_material ( FuncMaterialAllowed is_allowed, FuncReadImport read_value, int32_t list_size, std::vector<char> *pile_list );
/**
* @see serialize_list_organic_mat
*/
void serialize_list_quality ( FuncWriteExport add_value, const bool ( &quality_list ) [7] );
/**
* Set all values in a bool[7] to false
*/
void quality_clear ( bool ( &pile_list ) [7] );
/**
* @see serialize_list_organic_mat
*/
void unserialize_list_quality ( FuncReadImport read_value, int32_t list_size, bool ( &pile_list ) [7] );
/**
* @see serialize_list_organic_mat
*/
void serialize_list_other_mats ( const std::map<int, std::string> other_mats, FuncWriteExport add_value, std::vector<char> list );
/**
* @see serialize_list_organic_mat
*/
void unserialize_list_other_mats ( const std::map<int, std::string> other_mats, FuncReadImport read_value, int32_t list_size, std::vector<char> *pile_list );
/**
* @see serialize_list_organic_mat
*/
void serialize_list_itemdef ( FuncWriteExport add_value, std::vector<char> list, std::vector<df::itemdef *> items, df::enums::item_type::item_type type );
/**
* @see serialize_list_organic_mat
*/
void unserialize_list_itemdef ( FuncReadImport read_value, int32_t list_size, std::vector<char> *pile_list, df::enums::item_type::item_type type );
/**
* Given a list of other_materials and an index, return its corresponding token
* @return empty string if not found
* @see other_mats_token
*/
std::string other_mats_index ( const std::map<int, std::string> other_mats, int idx );
/**
* Given a list of other_materials and a token, return its corresponding index
* @return -1 if not found
* @see other_mats_index
*/
int other_mats_token ( const std::map<int, std::string> other_mats, const std::string & token );
void write_general();
void read_general();
void write_animals();
void read_animals();
food_pair food_map ( df::enums::organic_mat_category::organic_mat_category cat );
void write_food();
void read_food();
void furniture_setup_other_mats();
void write_furniture();
bool furniture_mat_is_allowed ( const DFHack::MaterialInfo &mi );
void read_furniture();
bool refuse_creature_is_allowed ( const df::creature_raw *raw );
void refuse_write_helper ( std::function<void ( const std::string & ) > add_value, const std::vector<char> & list );
bool refuse_type_is_allowed ( df::enums::item_type::item_type type );
void write_refuse();
void refuse_read_helper ( std::function<std::string ( const size_t& ) > get_value, size_t list_size, std::vector<char>* pile_list );
void read_refuse();
bool stone_is_allowed ( const DFHack::MaterialInfo &mi );
void write_stone();
void read_stone();
bool ammo_mat_is_allowed ( const DFHack::MaterialInfo &mi );
void write_ammo();
void read_ammo();
bool coins_mat_is_allowed ( const DFHack::MaterialInfo &mi );
void write_coins();
void read_coins();
void bars_blocks_setup_other_mats();
bool bars_mat_is_allowed ( const DFHack::MaterialInfo &mi );
bool blocks_mat_is_allowed ( const DFHack::MaterialInfo &mi );
void write_bars_blocks();
void read_bars_blocks();
bool gem_mat_is_allowed ( const DFHack::MaterialInfo &mi );
bool gem_cut_mat_is_allowed ( const DFHack::MaterialInfo &mi );
bool gem_other_mat_is_allowed(DFHack::MaterialInfo &mi );
void write_gems();
void read_gems();
bool finished_goods_type_is_allowed ( df::enums::item_type::item_type type );
void finished_goods_setup_other_mats();
bool finished_goods_mat_is_allowed ( const DFHack::MaterialInfo &mi );
void write_finished_goods();
void read_finished_goods();
void write_leather();
void read_leather();
void write_cloth();
void read_cloth();
bool wood_mat_is_allowed ( const df::plant_raw * plant );
void write_wood();
void read_wood();
bool weapons_mat_is_allowed ( const DFHack::MaterialInfo &mi );
void write_weapons();
void read_weapons();
void weapons_armor_setup_other_mats();
bool armor_mat_is_allowed ( const DFHack::MaterialInfo &mi );
void write_armor();
void read_armor();
};

@ -0,0 +1,53 @@
#pragma once
#include "MiscUtils.h"
#include "df/world.h"
#include "df/world_data.h"
#include "df/creature_raw.h"
#include "df/plant_raw.h"
// Utility Functions {{{
// A set of convenience functions for doing common lookups
/**
* Retrieve creature raw from index
*/
static df::creature_raw* find_creature ( int32_t idx )
{
return df::global::world->raws.creatures.all[idx];
}
/**
* Retrieve creature index from id string
* @return -1 if not found
*/
static int16_t find_creature ( const std::string &creature_id )
{
return linear_index ( df::global::world->raws.creatures.all, &df::creature_raw::creature_id, creature_id );
}
/**
* Retrieve plant raw from index
*/
static df::plant_raw* find_plant ( size_t idx )
{
return df::global::world->raws.plants.all[idx];
}
/**
* Retrieve plant index from id string
* @return -1 if not found
*/
static size_t find_plant ( const std::string &plant_id )
{
return linear_index ( df::global::world->raws.plants.all, &df::plant_raw::id, plant_id );
}
// }}} utility Functions

@ -0,0 +1,3 @@
*.pb.cc
*.pb.cc.rule
*.pb.h

@ -0,0 +1,303 @@
#include "Core.h"
#include "Console.h"
#include "Export.h"
#include "PluginManager.h"
#include "StockpileSerializer.h"
#include "df/world.h"
#include "df/world_data.h"
#include "df/ui.h"
#include "df/building_stockpilest.h"
#include "df/stockpile_settings.h"
#include "df/global_objects.h"
#include "df/viewscreen_dwarfmodest.h"
// os
#include <sys/stat.h>
// stl
#include <functional>
#include <vector>
using std::vector;
using std::string;
using std::endl;
using namespace DFHack;
using namespace df::enums;
using namespace google::protobuf;
using namespace dfstockpiles;
using df::global::world;
using df::global::ui;
using df::global::selection_rect;
using df::building_stockpilest;
using std::placeholders::_1;
static command_result copystock ( color_ostream &out, vector <string> & parameters );
static bool copystock_guard ( df::viewscreen *top );
static command_result savestock ( color_ostream &out, vector <string> & parameters );
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" );
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands )
{
if ( world && ui )
{
commands.push_back (
PluginCommand (
"copystock", "Copy stockpile under cursor.",
copystock, copystock_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"
)
);
commands.push_back (
PluginCommand (
"savestock", "Save the active stockpile's settings to a file.",
savestock, savestock_guard,
"Must be in 'q' mode and have a stockpile selected.\n"
"example: 'savestock food.dfstock' will save the settings to 'food.dfstock'\n"
"in your stockpile folder.\n"
"Omitting the filename will result in text output directly to the console\n\n"
" -d, --debug: enable debug output\n"
" <filename> : filename to save stockpile settings to (will be overwritten!)\n"
)
);
commands.push_back (
PluginCommand (
"loadstock", "Load settings from a file and apply them to the active stockpile.",
loadstock, loadstock_guard,
"Must be in 'q' mode and have a stockpile selected.\n"
"example: 'loadstock food.dfstock' will load the settings from 'food.dfstock'\n"
"in your stockpile folder and apply them to the selected stockpile.\n"
" -d, --debug: enable debug output\n"
" <filename> : filename to load stockpile settings from\n"
)
);
}
std::cerr << "world: " << sizeof ( df::world ) << " ui: " << sizeof ( df::ui )
<< " b_stock: " << sizeof ( building_stockpilest ) << endl;
return CR_OK;
}
DFhackCExport command_result plugin_shutdown ( color_ostream &out )
{
return CR_OK;
}
static bool copystock_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;
}
}
static command_result copystock ( color_ostream &out, vector <string> & parameters )
{
// HOTKEY COMMAND: CORE ALREADY SUSPENDED
// For convenience: when used in the stockpiles mode, switch to 'q'
if ( ui->main.mode == ui_sidebar_mode::Stockpiles )
{
world->selected_building = NULL; // just in case it contains some kind of garbage
ui->main.mode = ui_sidebar_mode::QueryBuilding;
selection_rect->start_x = -30000;
out << "Switched back to query building." << endl;
return CR_OK;
}
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;
}
ui->stockpile.custom_settings = sp->settings;
ui->main.mode = ui_sidebar_mode::Stockpiles;
world->selected_stockpile_type = stockpile_category::Custom;
out << "Stockpile options copied." << endl;
return CR_OK;
}
static bool savestock_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;
}
}
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;
}
}
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 )
{
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() > 2 )
{
out.printerr ( "Invalid parameters\n" );
return CR_WRONG_USAGE;
}
bool debug = false;
std::string file;
for ( size_t i = 0; i < parameters.size(); ++i )
{
const std::string o = parameters.at ( i );
if ( o == "--debug" || o == "-d" )
debug = true;
else if ( !o.empty() && o[0] != '-' )
{
file = o;
}
}
if ( file.empty() )
{
out.printerr ( "You must supply a valid filename.\n" );
return CR_WRONG_USAGE;
}
StockpileSerializer cereal ( sp );
if ( debug )
cereal.enable_debug ( out );
if ( !is_dfstockfile ( file ) ) file += ".dfstock";
if ( !cereal.serialize_to_file ( file ) )
{
out.printerr ( "serialize failed\n" );
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 || parameters.size() > 2 )
{
out.printerr ( "Invalid parameters\n" );
return CR_WRONG_USAGE;
}
bool debug = false;
std::string file;
for ( size_t i = 0; i < parameters.size(); ++i )
{
const std::string o = parameters.at ( i );
if ( o == "--debug" || o == "-d" )
debug = true;
else if ( !o.empty() && o[0] != '-' )
{
file = o;
}
}
if ( !is_dfstockfile ( file ) ) file += ".dfstock";
if ( file.empty() || !file_exists ( file ) )
{
out.printerr ( "loadstock: a .dfstock file is required to import\n" );
return CR_WRONG_USAGE;
}
StockpileSerializer cereal ( sp );
if ( debug )
cereal.enable_debug ( out );
if ( !cereal.unserialize_from_file ( file ) )
{
out.printerr ( "unserialization failed\n" );
return CR_FAILURE;
}
return CR_OK;
}