#pragma once #include #include #include "df/building.h" #include "df/dfhack_material_category.h" #include "df/item_quality.h" #include "df/job_item.h" #include "modules/Materials.h" #include "modules/Persistence.h" class ItemFilter { public: ItemFilter(); void clear(); bool deserialize(std::string ser); std::string serialize() const; void addMaterialMask(uint32_t mask); void clearMaterialMask(); void setMaterials(std::vector materials); void incMinQuality(); void decMinQuality(); void incMaxQuality(); void decMaxQuality(); void toggleDecoratedOnly(); uint32_t getMaterialMask() const; std::vector getMaterials() const; std::string getMinQuality() const; std::string getMaxQuality() const; bool getDecoratedOnly() const; bool matches(df::dfhack_material_category mask) const; bool matches(DFHack::MaterialInfo &material) const; bool matches(df::item *item) const; private: // remove friend declaration when we no longer need v1 deserialization friend void migrateV1ToV2(); df::dfhack_material_category mat_mask; std::vector materials; df::item_quality min_quality; df::item_quality max_quality; bool decorated_only; bool deserializeMaterialMask(std::string ser); bool deserializeMaterials(std::string ser); void setMinQuality(int quality); void setMaxQuality(int quality); bool matchesMask(DFHack::MaterialInfo &mat) const; }; class PlannedBuilding { public: PlannedBuilding(df::building *building, const std::vector &filters); PlannedBuilding(DFHack::PersistentDataItem &config); bool isValid() const; void remove(); df::building * getBuilding(); const std::vector & getFilters() const; private: DFHack::PersistentDataItem config; df::building *building; const df::building::key_field_type building_id; const std::vector filters; }; // building type, subtype, custom typedef std::tuple BuildingTypeKey; BuildingTypeKey toBuildingTypeKey( df::building_type btype, int16_t subtype, int32_t custom); BuildingTypeKey toBuildingTypeKey(df::building *bld); BuildingTypeKey toBuildingTypeKey(df::ui_build_selector *uibs); struct BuildingTypeKeyHash { std::size_t operator() (const BuildingTypeKey & key) const; }; class Planner { public: class ItemFiltersWrapper { public: ItemFiltersWrapper(std::vector & item_filters) : item_filters(item_filters) { } std::vector::reverse_iterator rbegin() const { return item_filters.rbegin(); } std::vector::reverse_iterator rend() const { return item_filters.rend(); } const std::vector & get() const { return item_filters; } private: std::vector &item_filters; }; const std::map & getGlobalSettings() const; bool setGlobalSetting(std::string name, bool value); void reset(); void addPlannedBuilding(df::building *bld); PlannedBuilding *getPlannedBuilding(df::building *bld); bool isPlannableBuilding(BuildingTypeKey key); // returns an empty vector if the type is not supported ItemFiltersWrapper getItemFilters(BuildingTypeKey key); void doCycle(); private: DFHack::PersistentDataItem config; std::map global_settings; std::unordered_map, BuildingTypeKeyHash> default_item_filters; // building id -> PlannedBuilding std::unordered_map planned_buildings; // vector id -> filter bucket -> queue of (building id, job_item index) std::map>>> tasks; bool registerTasks(PlannedBuilding &plannedBuilding); void unregisterBuilding(int32_t id); void popInvalidTasks(std::queue> &task_queue); void doVector(df::job_item_vector_id vector_id, std::map>> & buckets); }; extern Planner planner;