#pragma once #include "modules/Materials.h" #include "df/itemdef.h" #include "df/organic_mat_category.h" #include "proto/stockpiles.pb.h" #include namespace df { struct building_stockpilest; } /** * 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(); /** * 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: df::building_stockpilest* mPile; dfstockpiles::StockpileSettings mBuffer; std::map mOtherMatsFurniture; std::map mOtherMatsFinishedGoods; std::map mOtherMatsBars; std::map mOtherMatsBlocks; std::map 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 static typename df::enum_traits::base_type linear_index(df::enum_traits 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 FuncReadImport; // add the token to the serialized list during export typedef std::function FuncWriteExport; // are item's of item_type allowed? typedef std::function FuncItemAllowed; // is this material allowed? typedef std::function FuncMaterialAllowed; // convenient struct for parsing food stockpile items struct food_pair { // exporting FuncWriteExport set_value; std::vector* stockpile_values; // importing FuncReadImport get_value; size_t serialized_count; bool valid; food_pair(FuncWriteExport s, std::vector* 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* 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* 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& list); /** * @see serialize_list_organic_mat */ void unserialize_list_item_type(FuncItemAllowed is_allowed, FuncReadImport read_value, int32_t list_size, std::vector* pile_list); /** * @see serialize_list_organic_mat */ void serialize_list_material(FuncMaterialAllowed is_allowed, FuncWriteExport add_value, const std::vector& list); /** * @see serialize_list_organic_mat */ void unserialize_list_material(FuncMaterialAllowed is_allowed, FuncReadImport read_value, int32_t list_size, std::vector* 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 other_mats, FuncWriteExport add_value, std::vector list); /** * @see serialize_list_organic_mat */ void unserialize_list_other_mats(const std::map other_mats, FuncReadImport read_value, int32_t list_size, std::vector* pile_list); /** * @see serialize_list_organic_mat */ void serialize_list_itemdef(FuncWriteExport add_value, std::vector list, std::vector 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* 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 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 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 add_value, const std::vector& list); bool refuse_type_is_allowed(df::enums::item_type::item_type type); void write_refuse(); void refuse_read_helper(std::function get_value, size_t list_size, std::vector* 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(); };