Merge pull request #3005 from myk002/myk_stockpiles_refuse

cleanup stockpiles plugin and don't bork on empty type vectors
develop
Myk 2023-03-10 14:40:27 -08:00 committed by GitHub
commit f6718b7d5c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 1328 additions and 1887 deletions

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

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

File diff suppressed because it is too large Load Diff

@ -1,349 +1,283 @@
#pragma once #pragma once
// stockpiles plugin
#include "proto/stockpiles.pb.h"
// dfhack
#include "modules/Materials.h" #include "modules/Materials.h"
#include "modules/Items.h"
// df #include "df/itemdef.h"
#include "df/world.h"
#include "df/world_data.h"
#include "df/organic_mat_category.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;
}
#include "proto/stockpiles.pb.h"
/** #include <functional>
* 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 namespace df
{ {
public: struct building_stockpilest;
NullStream(); }
private:
NullBuffer m_sb;
};
/** /**
* Class for serializing the stockpile_settings structure into a Google protobuf * Class for serializing the stockpile_settings structure into a Google protobuf
*/ */
class StockpileSerializer class StockpileSerializer {
{
public: public:
/** /**
* @param out for debugging * @param out for debugging
* @param stockpile stockpile to read or write settings to * @param stockpile stockpile to read or write settings to
*/ */
StockpileSerializer ( df::building_stockpilest * stockpile );
~StockpileSerializer();
void enable_debug ( std::ostream &out ); StockpileSerializer(df::building_stockpilest* stockpile);
/** ~StockpileSerializer();
* 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) * Since we depend on protobuf-lite, not the full lib, we copy this function from
* @return success/failure * protobuf message.cc
*/ */
bool serialize_to_file ( const std::string & file ); bool serialize_to_ostream(std::ostream* output);
/** /**
* Again, copied from message.cc * Will serialize stockpile settings to a file (overwrites existing files)
*/ * @return success/failure
bool parse_from_istream(std::istream* input); */
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 * Read stockpile settings from file
*/ */
bool unserialize_from_file ( const std::string & file ); bool unserialize_from_file(const std::string& file);
private: private:
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;
/**
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(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) {
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();
bool mDebug; food_pair food_map(df::enums::organic_mat_category::organic_mat_category cat);
std::ostream * mOut;
NullStream mNull; void write_food();
df::building_stockpilest * mPile; void read_food();
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] );
/** void furniture_setup_other_mats();
* @see serialize_list_organic_mat void write_furniture();
*/ bool furniture_mat_is_allowed(const DFHack::MaterialInfo& mi);
void unserialize_list_quality ( FuncReadImport read_value, int32_t list_size, bool ( &pile_list ) [7] ); 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);
* @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 );
/** bool refuse_type_is_allowed(df::enums::item_type::item_type type);
* @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 );
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();
* @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 );
bool stone_is_allowed(const DFHack::MaterialInfo& mi);
/** void write_stone();
* @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 );
void read_stone();
/** bool ammo_mat_is_allowed(const DFHack::MaterialInfo& mi);
* 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 );
/** void write_ammo();
* Given a list of other_materials and a token, return its corresponding index void read_ammo();
* @return -1 if not found bool coins_mat_is_allowed(const DFHack::MaterialInfo& mi);
* @see other_mats_index
*/
int other_mats_token ( const std::map<int, std::string> other_mats, const std::string & token );
void write_general(); void write_coins();
void read_general();
void read_coins();
void write_animals(); void bars_blocks_setup_other_mats();
void read_animals();
bool bars_mat_is_allowed(const DFHack::MaterialInfo& mi);
food_pair food_map ( df::enums::organic_mat_category::organic_mat_category cat ); 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_food(); void write_gems();
void read_food();
void furniture_setup_other_mats(); void read_gems();
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 ); 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 refuse_write_helper ( std::function<void ( const std::string & ) > add_value, const std::vector<char> & list ); void write_finished_goods();
void read_finished_goods();
void write_leather();
bool refuse_type_is_allowed ( df::enums::item_type::item_type type ); void read_leather();
void write_cloth();
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(); void read_cloth();
bool wood_mat_is_allowed ( const df::plant_raw * plant ); bool wood_mat_is_allowed(const df::plant_raw* plant);
void write_wood(); void write_wood();
void read_wood(); void read_wood();
bool weapons_mat_is_allowed ( const DFHack::MaterialInfo &mi ); bool weapons_mat_is_allowed(const DFHack::MaterialInfo& mi);
void write_weapons(); void write_weapons();
void read_weapons(); void read_weapons();
void weapons_armor_setup_other_mats(); void weapons_armor_setup_other_mats();
bool armor_mat_is_allowed ( const DFHack::MaterialInfo &mi ); bool armor_mat_is_allowed(const DFHack::MaterialInfo& mi);
void write_armor(); void write_armor();
void read_armor(); void read_armor();
}; };

@ -3,26 +3,16 @@
#include "MiscUtils.h" #include "MiscUtils.h"
#include "df/world.h" #include "df/world.h"
#include "df/world_data.h"
#include "df/creature_raw.h" #include "df/creature_raw.h"
#include "df/plant_raw.h" #include "df/plant_raw.h"
#include <string>
#include <algorithm>
#include <functional>
// os
#include <sys/stat.h>
// Utility Functions {{{ // Utility Functions {{{
// A set of convenience functions for doing common lookups // A set of convenience functions for doing common lookups
/** /**
* Retrieve creature raw from index * Retrieve creature raw from index
*/ */
static inline df::creature_raw* find_creature ( int32_t idx ) static inline df::creature_raw* find_creature(int32_t idx) {
{
return df::global::world->raws.creatures.all[idx]; return df::global::world->raws.creatures.all[idx];
} }
@ -30,16 +20,14 @@ static inline df::creature_raw* find_creature ( int32_t idx )
* Retrieve creature index from id string * Retrieve creature index from id string
* @return -1 if not found * @return -1 if not found
*/ */
static inline int16_t find_creature ( const std::string &creature_id ) static inline 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);
return linear_index ( df::global::world->raws.creatures.all, &df::creature_raw::creature_id, creature_id );
} }
/** /**
* Retrieve plant raw from index * Retrieve plant raw from index
*/ */
static inline df::plant_raw* find_plant ( size_t idx ) static inline df::plant_raw* find_plant(size_t idx) {
{
return df::global::world->raws.plants.all[idx]; return df::global::world->raws.plants.all[idx];
} }
@ -47,32 +35,26 @@ static inline df::plant_raw* find_plant ( size_t idx )
* Retrieve plant index from id string * Retrieve plant index from id string
* @return -1 if not found * @return -1 if not found
*/ */
static inline size_t find_plant ( const std::string &plant_id ) static inline size_t find_plant(const std::string& plant_id) {
{ return linear_index(df::global::world->raws.plants.all, &df::plant_raw::id, plant_id);
return linear_index ( df::global::world->raws.plants.all, &df::plant_raw::id, plant_id );
} }
struct less_than_no_case struct less_than_no_case {
{ bool operator () (char x, char y) const {
bool operator () (char x, char y) const return toupper(static_cast<unsigned char>(x)) < toupper(static_cast<unsigned char>(y));
{ }
return toupper( static_cast< unsigned char >(x)) < toupper( static_cast< unsigned char >(y));
}
}; };
static inline bool CompareNoCase(const std::string &a, const std::string &b) static inline bool CompareNoCase(const std::string& a, const std::string& b) {
{ return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end(), less_than_no_case());
return std::lexicographical_compare( a.begin(),a.end(), b.begin(),b.end(), less_than_no_case() );
} }
/** /**
* Checks if the parameter has the dfstock extension. * Checks if the parameter has the dfstock extension.
* Doesn't check if the file exists or not. * Doesn't check if the file exists or not.
*/ */
static inline bool is_dfstockfile ( const std::string& filename ) static inline bool is_dfstockfile(const std::string& filename) {
{ return filename.rfind(".dfstock") != std::string::npos;
return filename.rfind ( ".dfstock" ) != std::string::npos;
} }
// }}} utility Functions // }}} utility Functions

@ -1,3 +1,4 @@
#include "Debug.h"
#include "PluginManager.h" #include "PluginManager.h"
#include "StockpileUtils.h" #include "StockpileUtils.h"
#include "StockpileSerializer.h" #include "StockpileSerializer.h"
@ -12,11 +13,16 @@ using namespace DFHack;
DFHACK_PLUGIN("stockpiles"); DFHACK_PLUGIN("stockpiles");
static command_result savestock ( color_ostream &out, vector <string> & parameters ); REQUIRE_GLOBAL(world);
static command_result loadstock ( color_ostream &out, vector <string> & parameters );
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands ) namespace DFHack {
{ DBG_DECLARE(stockpiles, log, DebugCategory::LINFO);
}
static command_result savestock(color_ostream& out, vector <string>& parameters);
static command_result loadstock(color_ostream& out, vector <string>& parameters);
DFhackCExport command_result plugin_init(color_ostream& out, std::vector <PluginCommand>& commands) {
commands.push_back(PluginCommand( commands.push_back(PluginCommand(
"savestock", "savestock",
"Save the active stockpile's settings to a file.", "Save the active stockpile's settings to a file.",
@ -31,61 +37,46 @@ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <Plug
return CR_OK; return CR_OK;
} }
DFhackCExport command_result plugin_shutdown ( color_ostream &out ) DFhackCExport command_result plugin_shutdown(color_ostream& out) {
{
return CR_OK; return CR_OK;
} }
// exporting // exporting
static command_result savestock ( color_ostream &out, vector <string> & parameters ) static command_result savestock(color_ostream& out, vector <string>& parameters) {
{ df::building_stockpilest* sp = Gui::getSelectedStockpile(out, true);
df::building_stockpilest *sp = Gui::getSelectedStockpile(out, true); 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;
} }
if ( parameters.size() > 2 ) if (parameters.size() > 2) {
{ out.printerr("Invalid parameters\n");
out.printerr ( "Invalid parameters\n" );
return CR_WRONG_USAGE; return CR_WRONG_USAGE;
} }
bool debug = false;
std::string file; std::string file;
for ( size_t i = 0; i < parameters.size(); ++i ) for (size_t i = 0; i < parameters.size(); ++i) {
{ const std::string o = parameters.at(i);
const std::string o = parameters.at ( i ); if (!o.empty() && o[0] != '-') {
if ( o == "--debug" || o == "-d" )
debug = true;
else if ( !o.empty() && o[0] != '-' )
{
file = o; file = o;
} }
} }
if ( file.empty() ) if (file.empty()) {
{ out.printerr("You must supply a valid filename.\n");
out.printerr ( "You must supply a valid filename.\n" );
return CR_WRONG_USAGE; return CR_WRONG_USAGE;
} }
StockpileSerializer cereal ( sp ); StockpileSerializer cereal(sp);
if ( debug )
cereal.enable_debug ( out );
if ( !is_dfstockfile ( file ) ) file += ".dfstock"; if (!is_dfstockfile(file)) file += ".dfstock";
try try {
{ if (!cereal.serialize_to_file(file)) {
if ( !cereal.serialize_to_file ( file ) ) out.printerr("could not save to %s\n", file.c_str());
{
out.printerr ( "could not save to %s\n", file.c_str() );
return CR_FAILURE; return CR_FAILURE;
} }
} }
catch ( std::exception &e ) catch (std::exception& e) {
{ out.printerr("serialization failed: protobuf exception: %s\n", e.what());
out.printerr ( "serialization failed: protobuf exception: %s\n", e.what() );
return CR_FAILURE; return CR_FAILURE;
} }
@ -94,59 +85,45 @@ static command_result savestock ( color_ostream &out, vector <string> & paramete
// importing // importing
static command_result loadstock ( color_ostream &out, vector <string> & parameters ) static command_result loadstock(color_ostream& out, vector <string>& parameters) {
{ df::building_stockpilest* sp = Gui::getSelectedStockpile(out, true);
df::building_stockpilest *sp = Gui::getSelectedStockpile(out, true); 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;
} }
if ( parameters.size() < 1 || parameters.size() > 2 ) if (parameters.size() < 1 || parameters.size() > 2) {
{ out.printerr("Invalid parameters\n");
out.printerr ( "Invalid parameters\n" );
return CR_WRONG_USAGE; return CR_WRONG_USAGE;
} }
bool debug = false;
std::string file; std::string file;
for ( size_t i = 0; i < parameters.size(); ++i ) for (size_t i = 0; i < parameters.size(); ++i) {
{ const std::string o = parameters.at(i);
const std::string o = parameters.at ( i ); if (!o.empty() && o[0] != '-') {
if ( o == "--debug" || o == "-d" )
debug = true;
else if ( !o.empty() && o[0] != '-' )
{
file = o; file = o;
} }
} }
if ( file.empty() ) { if (file.empty()) {
out.printerr ( "ERROR: missing .dfstock file parameter\n"); out.printerr("ERROR: missing .dfstock file parameter\n");
return DFHack::CR_WRONG_USAGE; return DFHack::CR_WRONG_USAGE;
} }
if ( !is_dfstockfile ( file ) ) if (!is_dfstockfile(file))
file += ".dfstock"; file += ".dfstock";
if ( !Filesystem::exists ( file ) ) if (!Filesystem::exists(file)) {
{ out.printerr("ERROR: the .dfstock file doesn't exist: %s\n", file.c_str());
out.printerr ( "ERROR: the .dfstock file doesn't exist: %s\n", file.c_str());
return CR_WRONG_USAGE; return CR_WRONG_USAGE;
} }
StockpileSerializer cereal ( sp ); StockpileSerializer cereal(sp);
if ( debug ) try {
cereal.enable_debug ( out ); if (!cereal.unserialize_from_file(file)) {
try out.printerr("unserialization failed: %s\n", file.c_str());
{
if ( !cereal.unserialize_from_file ( file ) )
{
out.printerr ( "unserialization failed: %s\n", file.c_str() );
return CR_FAILURE; return CR_FAILURE;
} }
} }
catch ( std::exception &e ) catch (std::exception& e) {
{ out.printerr("unserialization failed: protobuf exception: %s\n", e.what());
out.printerr ( "unserialization failed: protobuf exception: %s\n", e.what() );
return CR_FAILURE; return CR_FAILURE;
} }
return CR_OK; return CR_OK;