From 3fc4d056c30905ea2e793003e1de5f5c4fa5eb7b Mon Sep 17 00:00:00 2001 From: eamondo2 Date: Fri, 20 Jan 2023 17:58:38 -0500 Subject: [PATCH 01/19] initial automelt --- plugins/CMakeLists.txt | 2 +- plugins/automelt.cpp | 804 +++++++++++++++++++++++++++++---------- plugins/lua/automelt.lua | 75 ++++ 3 files changed, 683 insertions(+), 198 deletions(-) create mode 100644 plugins/lua/automelt.lua diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 3d36b95fc..e92bfaac7 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -83,7 +83,7 @@ dfhack_plugin(autofarm autofarm.cpp) #dfhack_plugin(autogems autogems.cpp LINK_LIBRARIES jsoncpp_static) #add_subdirectory(autolabor) #dfhack_plugin(automaterial automaterial.cpp LINK_LIBRARIES lua) -#dfhack_plugin(automelt automelt.cpp) +dfhack_plugin(automelt automelt.cpp LINK_LIBRARIES lua) #dfhack_plugin(autonestbox autonestbox.cpp LINK_LIBRARIES lua) #dfhack_plugin(autotrade autotrade.cpp) dfhack_plugin(blueprint blueprint.cpp LINK_LIBRARIES lua) diff --git a/plugins/automelt.cpp b/plugins/automelt.cpp index 9ca20e9ea..1808a6a59 100644 --- a/plugins/automelt.cpp +++ b/plugins/automelt.cpp @@ -1,294 +1,704 @@ -#include "uicommon.h" -#include "modules/Gui.h" +#include "Debug.h" +#include "LuaTools.h" +#include "PluginManager.h" +#include "TileTypes.h" + +#include "modules/Buildings.h" +#include "modules/Maps.h" +#include "modules/Items.h" +#include "modules/World.h" +#include "modules/Designations.h" +#include "modules/Persistence.h" +#include "modules/Units.h" + +// #include "uicommon.h" #include "df/world.h" +#include "df/building.h" #include "df/world_raws.h" #include "df/building_def.h" #include "df/viewscreen_dwarfmodest.h" #include "df/building_stockpilest.h" -#include "modules/Buildings.h" -#include "modules/Items.h" #include "df/plotinfost.h" -#include "modules/Maps.h" -#include "modules/World.h" #include "df/item_quality.h" +#include +#include + using df::building_stockpilest; +using std::map; +using std::multimap; +using std::pair; +using std::string; +using std::unordered_map; +using std::vector; + +using namespace DFHack; +using namespace df::enums; DFHACK_PLUGIN("automelt"); -#define PLUGIN_VERSION 0.3 REQUIRE_GLOBAL(gps); REQUIRE_GLOBAL(world); REQUIRE_GLOBAL(cursor); REQUIRE_GLOBAL(plotinfo); -static const string PERSISTENCE_KEY = "automelt/stockpiles"; +namespace DFHack +{ + DBG_DECLARE(automelt, status, DebugCategory::LINFO); + DBG_DECLARE(automelt, cycle, DebugCategory::LINFO); + DBG_DECLARE(automelt, perf, DebugCategory::LTRACE); +} + +static const string CONFIG_KEY = string(plugin_name) + "/config"; +static const string STOCKPILE_CONFIG_KEY_PREFIX = string(plugin_name) + "/stockpile/"; +static PersistentDataItem config; + +static vector watched_stockpiles; +static unordered_map watched_stockpiles_indices; + -static int mark_item(df::item *item, df::item_flags bad_flags, int32_t stockpile_id) +enum ConfigValues { - if (item->flags.whole & bad_flags.whole) - return 0; + CONFIG_IS_ENABLED = 0, - if (item->isAssignedToThisStockpile(stockpile_id)) { - size_t marked_count = 0; - std::vector contents; - Items::getContainedItems(item, &contents); - for (auto child = contents.begin(); child != contents.end(); child++) - { - marked_count += mark_item(*child, bad_flags, stockpile_id); - } +}; - return marked_count; - } +enum StockpileConfigValues +{ + STOCKPILE_CONFIG_ID = 0, + STOCKPILE_CONFIG_MONITORED = 1, + STOCKPILE_CONFIG_MELT = 2, - if (!can_melt(item)) - return 0; +}; - if (is_set_to_melt(item)) - return 0; +static int get_config_val(PersistentDataItem &c, int index) +{ + if (!c.isValid()) + return -1; + return c.ival(index); +} +static bool get_config_bool(PersistentDataItem &c, int index) +{ + return get_config_val(c, index) == 1; +} +static void set_config_val(PersistentDataItem &c, int index, int value) +{ + if (c.isValid()) + c.ival(index) = value; +} +static void set_config_bool(PersistentDataItem &c, int index, bool value) +{ + set_config_val(c, index, value ? 1 : 0); +} - insert_into_vector(world->items.other[items_other_id::ANY_MELT_DESIGNATED], &df::item::id, item); - item->flags.bits.melt = true; - return 1; +static PersistentDataItem &ensure_stockpile_config(color_ostream &out, int id) +{ + if (watched_stockpiles_indices.count(id)) + return watched_stockpiles[watched_stockpiles_indices[id]]; + string keyname = STOCKPILE_CONFIG_KEY_PREFIX + int_to_string(id); + DEBUG(status, out).print("creating new persistent key for stockpile %d\n", id); + watched_stockpiles.emplace_back(World::GetPersistentData(keyname, NULL)); + size_t idx = watched_stockpiles.size() - 1; + watched_stockpiles_indices.emplace(id, idx); + return watched_stockpiles[idx]; } -static void mark_all_in_stockpiles(vector &stockpiles) +static void remove_stockpile_config(color_ostream &out, int id) { - // Precompute a bitmask with the bad flags - df::item_flags bad_flags; - bad_flags.whole = 0; + if (!watched_stockpiles_indices.count(id)) + return; + DEBUG(status, out).print("removing persistent key for stockpile %d\n", id); + size_t idx = watched_stockpiles_indices[id]; + World::DeletePersistentData(watched_stockpiles[idx]); + watched_stockpiles.erase(watched_stockpiles.begin() + idx); + watched_stockpiles_indices.erase(id); +} -#define F(x) bad_flags.bits.x = true; - F(dump); F(forbid); F(garbage_collect); - F(hostile); F(on_fire); F(rotten); F(trader); - F(in_building); F(construction); F(artifact); - F(spider_web); F(owned); F(in_job); -#undef F +static void validate_stockpile_configs(color_ostream &out) +{ + for (auto &c : watched_stockpiles) { + int id = get_config_val(c, STOCKPILE_CONFIG_ID); + if (!df::building::find(id)){ + remove_stockpile_config(out, id); + } + } +} - size_t marked_count = 0; - for (auto it = stockpiles.begin(); it != stockpiles.end(); it++) - { - if (!it->isValid()) - continue; +static const int32_t CYCLE_TICKS = 1200; +static int32_t cycle_timestamp = 0; // world->frame_counter at last cycle - auto spid = it->getId(); - Buildings::StockpileIterator stored; - for (stored.begin(it->getStockpile()); !stored.done(); ++stored) - { - marked_count += mark_item(*stored, bad_flags, spid); - } +static command_result do_command(color_ostream &out, vector ¶meters); +static int32_t do_cycle(color_ostream &out); + +DFHACK_PLUGIN_IS_ENABLED(is_enabled); + +DFhackCExport command_result plugin_init(color_ostream &out, std::vector &commands) +{ + DEBUG(status, out).print("initializing %s\n", plugin_name); + + // provide a configuration interface for the plugin + commands.push_back(PluginCommand( + plugin_name, + "Auto melt items in designated stockpiles.", + do_command)); + + return CR_OK; +} + +DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) +{ + if (!Core::getInstance().isWorldLoaded()) + { + out.printerr("Cannot enable %s without a loaded world.\n", plugin_name); + return CR_FAILURE; } - if (marked_count) - Gui::showAnnouncement("Marked " + int_to_string(marked_count) + " items to melt", COLOR_GREEN, false); + if (enable != is_enabled) + { + is_enabled = enable; + DEBUG(status, out).print("%s from the API; persisting\n", is_enabled ? "enabled" : "disabled"); + set_config_bool(config, CONFIG_IS_ENABLED, is_enabled); + } + else + { + DEBUG(status, out).print("%s from the API, but already %s; no action\n", is_enabled ? "enabled" : "disabled", is_enabled ? "enabled" : "disabled"); + } + return CR_OK; } -/* - * Stockpile Monitoring - */ +DFhackCExport command_result plugin_shutdown(color_ostream &out) +{ + DEBUG(status, out).print("shutting down %s\n", plugin_name); + + return CR_OK; +} -class StockpileMonitor +DFhackCExport command_result plugin_load_data(color_ostream &out) { -public: - bool isMonitored(df::building_stockpilest *sp) + config = World::GetPersistentData(CONFIG_KEY); + + if (!config.isValid()) { - for (auto it = monitored_stockpiles.begin(); it != monitored_stockpiles.end(); it++) - { - if (it->matches(sp)) - return true; - } + DEBUG(status, out).print("no config found in this save; initializing\n"); + config = World::AddPersistentData(CONFIG_KEY); + set_config_bool(config, CONFIG_IS_ENABLED, is_enabled); + } - return false; + // we have to copy our enabled flag into the global plugin variable, but + // all the other state we can directly read/modify from the persistent + // data structure. + is_enabled = get_config_bool(config, CONFIG_IS_ENABLED); + DEBUG(status, out).print("loading persisted enabled state: %s\n", is_enabled ? "true" : "false"); + World::GetPersistentData(&watched_stockpiles, STOCKPILE_CONFIG_KEY_PREFIX, true); + watched_stockpiles_indices.clear(); + const size_t num_watched_stockpiles = watched_stockpiles.size(); + for (size_t idx = 0; idx < num_watched_stockpiles; ++idx) + { + auto &c = watched_stockpiles[idx]; + watched_stockpiles_indices.emplace(get_config_val(c, STOCKPILE_CONFIG_ID), idx); } + validate_stockpile_configs(out); + + return CR_OK; +} - void add(df::building_stockpilest *sp) +DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event) +{ + if (event == DFHack::SC_WORLD_UNLOADED) { - auto pile = PersistentStockpileInfo(sp, PERSISTENCE_KEY); - if (pile.isValid()) + if (is_enabled) { - monitored_stockpiles.push_back(PersistentStockpileInfo(pile)); - monitored_stockpiles.back().save(); + DEBUG(status, out).print("world unloaded; disabling %s\n", plugin_name); + is_enabled = false; } } + + return CR_OK; +} + +DFhackCExport command_result plugin_onupdate(color_ostream &out) +{ + if (is_enabled && world->frame_counter - cycle_timestamp >= CYCLE_TICKS) + { + int32_t marked = do_cycle(out); + if (0 < marked) + out.print("automelt: marked %d item(s) for melting\n", marked); + } + return CR_OK; +} + + +static bool call_automelt_lua(color_ostream *out, const char *fn_name, + int nargs = 0, int nres = 0, + Lua::LuaLambda && args_lambda = Lua::DEFAULT_LUA_LAMBDA, + Lua::LuaLambda && res_lambda = Lua::DEFAULT_LUA_LAMBDA) { + DEBUG(status).print("calling automelt lua function: '%s'\n", fn_name); + + CoreSuspender guard; + + auto L = Lua::Core::State; + Lua::StackUnwinder top(L); + + if (!out) + out = &Core::getInstance().getConsole(); + + return Lua::CallLuaModuleFunction(*out, L, "plugins.automelt", fn_name, + nargs, nres, + std::forward(args_lambda), + std::forward(res_lambda)); +} + +static command_result do_command(color_ostream &out, vector ¶meters) { + CoreSuspender suspend; + + if (!Core::getInstance().isWorldLoaded()) { + out.printerr("Cannot run %s without a loaded world.\n", plugin_name); + return CR_FAILURE; + } + + bool show_help = false; + if (!call_automelt_lua(&out, "parse_commandline", parameters.size(), 1, + [&](lua_State *L) { + for (const string ¶m : parameters) + Lua::Push(L, param); + }, + [&](lua_State *L) { + show_help = !lua_toboolean(L, -1); + })) { + return CR_FAILURE; + } + + return show_help ? CR_WRONG_USAGE : CR_OK; +} + +static inline bool is_metal_item(df::item *item) +{ + MaterialInfo mat(item); + return (mat.getCraftClass() == craft_material_class::Metal); +} + +static bool isStockpile(df::building * building) { + return building->getType() == df::building_type::Stockpile; +} + +// Copied from Kelly Martin's code +static inline bool can_melt(df::item *item) +{ + + df::item_flags bad_flags; + bad_flags.whole = 0; + +#define F(x) bad_flags.bits.x = true; + F(dump); + F(forbid); + F(garbage_collect); + F(in_job); + F(hostile); + F(on_fire); + F(rotten); + F(trader); + F(in_building); + F(construction); + F(artifact); + F(melt); +#undef F + + if (item->flags.whole & bad_flags.whole) + return false; + + df::item_type t = item->getType(); + + if (t == df::enums::item_type::BOX || t == df::enums::item_type::BAR) + return false; + + if (!is_metal_item(item)) + return false; - void remove(df::building_stockpilest *sp) + for (auto g = item->general_refs.begin(); g != item->general_refs.end(); g++) { - for (auto it = monitored_stockpiles.begin(); it != monitored_stockpiles.end(); it++) + switch ((*g)->getType()) + { + case general_ref_type::CONTAINS_ITEM: + case general_ref_type::UNIT_HOLDER: + case general_ref_type::CONTAINS_UNIT: + return false; + case general_ref_type::CONTAINED_IN_ITEM: { - if (it->matches(sp)) + df::item *c = (*g)->getItem(); + for (auto gg = c->general_refs.begin(); gg != c->general_refs.end(); gg++) { - it->remove(); - monitored_stockpiles.erase(it); - break; + if ((*gg)->getType() == general_ref_type::UNIT_HOLDER) + return false; } } + break; + default: + break; + } } - void doCycle() - { - for (auto it = monitored_stockpiles.begin(); it != monitored_stockpiles.end();) - { - if (!it->isValid()) - it = monitored_stockpiles.erase(it); - else - ++it; - } + if (item->getQuality() >= item_quality::Masterful) + return false; + + return true; +} + +static inline bool is_set_to_melt(df::item *item) +{ + return item->flags.bits.melt; +} - mark_all_in_stockpiles(monitored_stockpiles); +static int mark_item(color_ostream &out, df::item *item, df::item_flags bad_flags, int32_t stockpile_id, int32_t &premarked_item_count, int32_t &item_count, bool should_melt) +{ + TRACE(perf,out).print("%s running mark_item\nshould_melt=%d\n", plugin_name,should_melt); + string name = ""; + item->getItemDescription(&name, 0); + TRACE(perf,out).print("item %s %d\n", name, item->id); + if (item->flags.whole & bad_flags.whole){ + TRACE(perf,out).print("rejected flag check\n"); + item_count++; + return 0; } - void reset() + if (item->isAssignedToThisStockpile(stockpile_id)) { - monitored_stockpiles.clear(); - std::vector items; - DFHack::World::GetPersistentData(&items, PERSISTENCE_KEY); - - for (auto i = items.begin(); i != items.end(); i++) + TRACE(perf,out).print("assignedToStockpile\n"); + size_t marked_count = 0; + std::vector contents; + Items::getContainedItems(item, &contents); + for (auto child = contents.begin(); child != contents.end(); child++) { - auto pile = PersistentStockpileInfo(*i, PERSISTENCE_KEY); - if (pile.load()) - monitored_stockpiles.push_back(PersistentStockpileInfo(pile)); - else - pile.remove(); + TRACE(perf,out).print("inside child loop\n"); + marked_count += mark_item(out, *child, bad_flags, stockpile_id, premarked_item_count, item_count, should_melt); } + return marked_count; } + TRACE(perf,out).print("past recurse loop\n"); -private: - vector monitored_stockpiles; -}; + if (is_set_to_melt(item)) { + TRACE(perf,out).print("already set to melt\n"); + premarked_item_count++; + item_count++; + return 0; + } + + if (!can_melt(item)) { + TRACE(perf,out).print("cannot melt\n"); + item_count++; + return 0; + } -static StockpileMonitor monitor; + TRACE(perf,out).print("increment item count\n"); + item_count++; -#define DELTA_TICKS 610 + //Only melt if told to, else count + if (should_melt) { + TRACE(perf,out).print("should_melt hit\n"); + insert_into_vector(world->items.other[items_other_id::ANY_MELT_DESIGNATED], &df::item::id, item); + item->flags.bits.melt = 1; + return 1; + } else { + return 0; + } -DFhackCExport command_result plugin_onupdate ( color_ostream &out ) +} + + +static int32_t mark_all_in_stockpile(color_ostream &out, PersistentDataItem & stockpile, int32_t &premarked_item_count, int32_t &item_count, bool should_melt) { - if(!Maps::IsValid()) - return CR_OK; + TRACE(perf,out).print("%s running mark_all_in_stockpile\nshould_melt=%d", plugin_name, should_melt); + // Precompute a bitmask with the bad flags + df::item_flags bad_flags; + bad_flags.whole = 0; + +#define F(x) bad_flags.bits.x = true; + F(dump); + F(forbid); + F(garbage_collect); + F(hostile); + F(on_fire); + F(rotten); + F(trader); + F(in_building); + F(construction); + F(artifact); + F(spider_web); + F(owned); + F(in_job); +#undef F - if (DFHack::World::ReadPauseState()) - return CR_OK; + size_t marked_count = 0; + + if(!stockpile.isValid()) { + return 0; + } - if (world->frame_counter % DELTA_TICKS != 0) - return CR_OK; + int spid = get_config_val(stockpile, STOCKPILE_CONFIG_ID); + auto found = df::building::find(spid); + if (!isStockpile(found)){ + + return 0; + } - monitor.doCycle(); + df::building_stockpilest * pile_cast = virtual_cast(found); - return CR_OK; + if (!pile_cast) + return 0; + + Buildings::StockpileIterator stored; + for (stored.begin(pile_cast); !stored.done(); ++stored) { + + marked_count += mark_item(out, *stored, bad_flags, spid, premarked_item_count, item_count, should_melt); + } + TRACE(perf,out).print("marked_count %d\npremarked_count %d\n", marked_count, premarked_item_count); + return marked_count; } -/* - * Interface - */ +static int32_t scan_stockpiles(color_ostream &out, bool disable_melt, map &item_counts, map &marked_item_counts, map &premarked_item_counts) { + TRACE(perf, out).print("%s running scan_stockpiles\n", plugin_name); + int32_t newly_marked = 0; + + // if (item_counts) + item_counts.clear(); + // if (marked_item_counts) + marked_item_counts.clear(); + // if (premarked_item_counts) + premarked_item_counts.clear(); -struct melt_hook : public df::viewscreen_dwarfmodest -{ - typedef df::viewscreen_dwarfmodest interpose_base; - bool handleInput(set *input) - { - if (Gui::inRenameBuilding()) - return false; + //Parse all the watched piles + for (auto &c : watched_stockpiles) { + int id = get_config_val(c, STOCKPILE_CONFIG_ID); + //Check for monitor status + bool monitored = get_config_bool(c, STOCKPILE_CONFIG_MONITORED); + //Check melt status + bool melt_enabled = get_config_bool(c, STOCKPILE_CONFIG_MELT); - building_stockpilest *sp = get_selected_stockpile(); - if (!sp) - return false; + melt_enabled = melt_enabled && (!disable_melt); - if (input->count(interface_key::CUSTOM_SHIFT_M)) - { - if (monitor.isMonitored(sp)) - monitor.remove(sp); - else - monitor.add(sp); - } + if (!monitored) continue; + + TRACE(perf,out).print("%s past monitor check\nmelt_enabled=%d", plugin_name, melt_enabled); + + int32_t item_count = 0; + + int32_t premarked_count = 0; + + int32_t marked = mark_all_in_stockpile(out, c, premarked_count, item_count, melt_enabled); + + item_counts.emplace(id, item_count); + + marked_item_counts.emplace(id, marked); + + premarked_item_counts.emplace(id, premarked_count); + + newly_marked += marked; - return false; } - DEFINE_VMETHOD_INTERPOSE(void, feed, (set *input)) - { - if (!handleInput(input)) - INTERPOSE_NEXT(feed)(input); + return newly_marked; +} + + +static int32_t do_cycle(color_ostream &out) { + DEBUG(cycle,out).print("running %s cycle\n", plugin_name); + cycle_timestamp = world->frame_counter; + + validate_stockpile_configs(out); + + int32_t marked_items_total; + map item_counts, marked_items_counts, premarked_item_counts; + + marked_items_total = scan_stockpiles(out, false, item_counts, marked_items_counts, premarked_item_counts); + + return marked_items_total; +} + +static void push_stockpile_config(lua_State *L, int id, bool monitored, + bool melt) { + map stockpile_config; + stockpile_config.emplace("id", id); + stockpile_config.emplace("monitored", monitored); + stockpile_config.emplace("melt", melt); + + Lua::Push(L, stockpile_config); +} + +static void push_stockpile_config(lua_State *L, PersistentDataItem &c) { + push_stockpile_config(L, get_config_val(c, STOCKPILE_CONFIG_ID), + get_config_bool(c, STOCKPILE_CONFIG_MONITORED), + get_config_bool(c, STOCKPILE_CONFIG_MELT)); +} + +static void automelt_designate(color_ostream &out) { + DEBUG(status, out).print("entering automelt designate\n"); + out.print("designated %d item(s) for melting\n", do_cycle(out)); +} + +static void automelt_printStatus(color_ostream &out) { + DEBUG(status,out).print("entering automelt_printStatus\n"); + validate_stockpile_configs(out); + out.print("automelt is %s\n\n", is_enabled ? "enabled" : "disabled"); + + map item_counts, marked_item_counts, premarked_item_counts; + int32_t marked_items = scan_stockpiles(out, true, item_counts, marked_item_counts, premarked_item_counts); + + int32_t total_items_all_piles = 0; + int32_t premarked_items_all_piles = 0; + + + for (auto &i : watched_stockpiles) { + int id = get_config_val(i, STOCKPILE_CONFIG_ID); + total_items_all_piles+= item_counts[id]; + premarked_items_all_piles += premarked_item_counts[id]; } - DEFINE_VMETHOD_INTERPOSE(void, render, ()) - { - INTERPOSE_NEXT(render)(); - - building_stockpilest *sp = get_selected_stockpile(); - if (!sp) - return; - - auto dims = Gui::getDwarfmodeViewDims(); - int left_margin = dims.menu_x1 + 1; - int x = left_margin; - int y = dims.y2 - 6; - - int links = 0; - links += sp->links.give_to_pile.size(); - links += sp->links.take_from_pile.size(); - links += sp->links.give_to_workshop.size(); - links += sp->links.take_from_workshop.size(); - bool state = monitor.isMonitored(sp); - - if (links + 12 >= y) { - y = dims.y2; - OutputString(COLOR_WHITE, x, y, "Auto: "); - x += 5; - OutputString(COLOR_LIGHTRED, x, y, "M"); - OutputString(state? COLOR_LIGHTGREEN: COLOR_GREY, x, y, "elt "); - } else { - OutputToggleString(x, y, "Auto melt", "M", state, true, left_margin, COLOR_WHITE, COLOR_LIGHTRED); + out.print("summary:\n"); + out.print(" total items in monitored piles: %d\n", total_items_all_piles); + out.print(" marked items in monitored piles: %d\n", premarked_items_all_piles); + + int name_width = 11; + for (auto &stockpile : world->buildings.other.STOCKPILE) { + if (!isStockpile(stockpile)) continue; + name_width = std::max(name_width, (int)stockpile->name.size()); + } + name_width = -name_width; + + const char *fmt = "%*s %4s %4s %4s\n"; + out.print(fmt, name_width, "name", " id ", "monitored", "melt"); + out.print(fmt, name_width, "----", "----", "---------", "----"); + + for (auto &stockpile : world->buildings.other.STOCKPILE) { + if (!isStockpile(stockpile)) continue; + bool melt = false; + bool monitored = false; + if (watched_stockpiles_indices.count(stockpile->id)) { + auto &c = watched_stockpiles[watched_stockpiles_indices[stockpile->id]]; + melt = get_config_bool(c, STOCKPILE_CONFIG_MELT); + monitored = get_config_bool(c, STOCKPILE_CONFIG_MONITORED); } + + out.print(fmt, name_width, stockpile->name.c_str(), int_to_string(stockpile->id).c_str(), + monitored ? "[x]" : "[ ]", melt ? "[x]": "[ ]"); } -}; -IMPLEMENT_VMETHOD_INTERPOSE(melt_hook, feed); -IMPLEMENT_VMETHOD_INTERPOSE(melt_hook, render); +} +static void automelt_setStockpileConfig(color_ostream &out, int id, bool monitored, bool melt) { + DEBUG(status,out).print("entering automelt_setStockpileConfig\n"); + validate_stockpile_configs(out); + bool isInvalidStockpile = !df::building::find(id); + bool hasNoData = !melt && !monitored; + if (isInvalidStockpile || hasNoData) { + remove_stockpile_config(out, id); + return; + } + + PersistentDataItem &c = ensure_stockpile_config(out, id); + set_config_val(c, STOCKPILE_CONFIG_ID, id); + set_config_bool(c, STOCKPILE_CONFIG_MONITORED, monitored); + set_config_bool(c, STOCKPILE_CONFIG_MELT, melt); +} -DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event) -{ - switch (event) - { - case DFHack::SC_MAP_LOADED: - monitor.reset(); - break; - case DFHack::SC_MAP_UNLOADED: - break; - default: - break; +static int automelt_getStockpileConfig(lua_State *L) { + color_ostream *out = Lua::GetOutput(L); + if (!out) + out = &Core::getInstance().getConsole(); + DEBUG(status, *out).print("entering automelt_getStockpileConfig\n"); + validate_stockpile_configs(*out); + + int id; + if (lua_isnumber(L, -1)) { + id = lua_tointeger(L, -1); + if (!df::building::find(id)) + return 0; + + } else { + const char * name = lua_tostring(L, -1); + if (!name) + return 0; + string nameStr = name; + bool found = false; + for (auto &stockpile : world->buildings.other.STOCKPILE) { + if (!isStockpile(stockpile)) continue; + if (nameStr == stockpile->name) { + id = stockpile->id; + found = true; + break; + } + + } + if (!found) + return 0; } - return CR_OK; + + if (watched_stockpiles_indices.count(id)) { + push_stockpile_config(L, watched_stockpiles[watched_stockpiles_indices[id]]); + } else { + push_stockpile_config(L, id, false, false); + } + return 1; } -DFHACK_PLUGIN_IS_ENABLED(is_enabled); +//TODO +static int automelt_getItemCountsAndStockpileConfigs(lua_State *L) { + color_ostream *out = Lua::GetOutput(L); + if (!out) + out = &Core::getInstance().getConsole(); + DEBUG(status,*out).print("entering automelt_getItemCountsAndStockpileConfigs\n"); + validate_stockpile_configs(*out); -DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) -{ - if (enable != is_enabled) - { - if (!INTERPOSE_HOOK(melt_hook, feed).apply(enable) || - !INTERPOSE_HOOK(melt_hook, render).apply(enable)) - return CR_FAILURE; + map item_counts, marked_item_counts, premarked_item_counts; + int32_t marked_items = scan_stockpiles(*out, true, item_counts, marked_item_counts, premarked_item_counts); - is_enabled = enable; + int32_t total_items_all_piles = 0; + int32_t premarked_items_all_piles = 0; + + + for (auto &i : watched_stockpiles) { + int id = get_config_val(i, STOCKPILE_CONFIG_ID); + total_items_all_piles+= item_counts[id]; + premarked_items_all_piles += premarked_item_counts[id]; } - return CR_OK; -} + map summary; + summary.emplace("total_items", total_items_all_piles); + summary.emplace("marked_items", marked_items); + summary.emplace("premarked_items", premarked_items_all_piles); + + Lua::Push(L, summary); + Lua::Push(L, item_counts); + Lua::Push(L, marked_item_counts); + Lua::Push(L, premarked_item_counts); + int32_t bldg_count = 0; + + for (auto pile : world->buildings.other.STOCKPILE) { + if (!isStockpile(pile)) + continue; + bldg_count++; + + int id = pile->id; + if (watched_stockpiles_indices.count(id)) { + push_stockpile_config(L, watched_stockpiles[watched_stockpiles_indices[id]]); + } else { + push_stockpile_config(L, id, false, false); + } + } + return 4+bldg_count; -DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) -{ - return CR_OK; -} -DFhackCExport command_result plugin_shutdown ( color_ostream &out ) -{ - // ensure we disengage our hooks - plugin_enable(out, false); - return CR_OK; } + +DFHACK_PLUGIN_LUA_FUNCTIONS{ + DFHACK_LUA_FUNCTION(automelt_printStatus), + DFHACK_LUA_FUNCTION(automelt_designate), + DFHACK_LUA_FUNCTION(automelt_setStockpileConfig), + DFHACK_LUA_END}; + +DFHACK_PLUGIN_LUA_COMMANDS{ + DFHACK_LUA_COMMAND(automelt_getStockpileConfig), + DFHACK_LUA_COMMAND(automelt_getItemCountsAndStockpileConfigs), + DFHACK_LUA_END}; \ No newline at end of file diff --git a/plugins/lua/automelt.lua b/plugins/lua/automelt.lua new file mode 100644 index 000000000..bba93b3c4 --- /dev/null +++ b/plugins/lua/automelt.lua @@ -0,0 +1,75 @@ +local _ENV = mkmodule('plugins.automelt') + +local argparse = require('argparse') + +local function process_args(opts, args) + if args[1] == 'help' then + opts.help = true + return + end + + return argparse.processArgsGetopt(args, { + {'h', 'help', handler=function() opts.help = true end}, + }) +end + + +local function do_set_stockpile_config(var_name, val, stockpiles) + for _,bspec in ipairs(argparse.stringList(stockpiles)) do + local config = automelt_getStockpileConfig(bspec) + config[var_name] = val + automelt_setStockpileConfig(config.id, config.monitor, config.melt) + end +end + + +function parse_commandline(...) + local args, opts = {...}, {} + local positionals = process_args(opts, args) + + if opts.help then + return false + end + + local command = positionals[1] + if not command or command == 'status' then + automelt_printStatus() + elseif command == 'designate' then + automelt_designate() + elseif command == 'melt' then + do_set_stockpile_config('melt', true, args[2]) + elseif command == 'nomelt' then + do_set_stockpile_config('melt', false, args[2]) + elseif command == 'monitor' then + do_set_stockpile_config('monitor', true, args[2]) + elseif command == 'nomonitor'then + do_set_stockpile_config('monitor', false, args[2]) + else + return false + end + + return true +end + +-- used by gui/autochop +function setStockpileConfig(config) + automelt_setStockpileConfig(config.id, config.monitored, config.melt) +end + +function getItemCountsAndStockpileConfigs() + local data = {automelt_getItemCountsAndStockpileConfigs()} + local ret = {} + ret.summary = table.remove(data, 1) + ret.item_counts = table.remove(data, 1) + ret.marked_item_counts = table.remove(data, 1) + ret.premarked_item_counts = table.remove(data, 1) + ret.stockpile_configs = data + for _,c in ipairs(ret.stockpile_configs) do + c.name = df.building.find(c.id).name + c.monitored = c.monitored ~= 0 + c.melt = c.melt ~= 0 + end + return ret +end + +return _ENV From e4e4cae5e67e2b841132474a3363a78514ef177b Mon Sep 17 00:00:00 2001 From: eamondo2 Date: Sat, 21 Jan 2023 02:08:58 -0500 Subject: [PATCH 02/19] fix check failures --- plugins/automelt.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/plugins/automelt.cpp b/plugins/automelt.cpp index 1808a6a59..13b8ef9c5 100644 --- a/plugins/automelt.cpp +++ b/plugins/automelt.cpp @@ -213,7 +213,7 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan is_enabled = false; } } - + return CR_OK; } @@ -354,7 +354,7 @@ static int mark_item(color_ostream &out, df::item *item, df::item_flags bad_flag TRACE(perf,out).print("%s running mark_item\nshould_melt=%d\n", plugin_name,should_melt); string name = ""; item->getItemDescription(&name, 0); - TRACE(perf,out).print("item %s %d\n", name, item->id); + TRACE(perf,out).print("item %s %d\n", name.c_str(), item->id); if (item->flags.whole & bad_flags.whole){ TRACE(perf,out).print("rejected flag check\n"); item_count++; @@ -429,7 +429,7 @@ static int32_t mark_all_in_stockpile(color_ostream &out, PersistentDataItem & st F(in_job); #undef F - size_t marked_count = 0; + int32_t marked_count = 0; if(!stockpile.isValid()) { return 0; @@ -438,7 +438,7 @@ static int32_t mark_all_in_stockpile(color_ostream &out, PersistentDataItem & st int spid = get_config_val(stockpile, STOCKPILE_CONFIG_ID); auto found = df::building::find(spid); if (!isStockpile(found)){ - + return 0; } @@ -460,7 +460,7 @@ static int32_t mark_all_in_stockpile(color_ostream &out, PersistentDataItem & st static int32_t scan_stockpiles(color_ostream &out, bool disable_melt, map &item_counts, map &marked_item_counts, map &premarked_item_counts) { TRACE(perf, out).print("%s running scan_stockpiles\n", plugin_name); int32_t newly_marked = 0; - + // if (item_counts) item_counts.clear(); // if (marked_item_counts) @@ -485,7 +485,7 @@ static int32_t scan_stockpiles(color_ostream &out, bool disable_melt, map item_counts, marked_item_counts, premarked_item_counts; - int32_t marked_items = scan_stockpiles(out, true, item_counts, marked_item_counts, premarked_item_counts); + scan_stockpiles(out, true, item_counts, marked_item_counts, premarked_item_counts); int32_t total_items_all_piles = 0; int32_t premarked_items_all_piles = 0; @@ -581,7 +581,7 @@ static void automelt_printStatus(color_ostream &out) { monitored = get_config_bool(c, STOCKPILE_CONFIG_MONITORED); } - out.print(fmt, name_width, stockpile->name.c_str(), int_to_string(stockpile->id).c_str(), + out.print(fmt, name_width, stockpile->name.c_str(), int_to_string(stockpile->id).c_str(), monitored ? "[x]" : "[ ]", melt ? "[x]": "[ ]"); } @@ -595,7 +595,7 @@ static void automelt_setStockpileConfig(color_ostream &out, int id, bool monitor if (isInvalidStockpile || hasNoData) { remove_stockpile_config(out, id); return; - } + } PersistentDataItem &c = ensure_stockpile_config(out, id); set_config_val(c, STOCKPILE_CONFIG_ID, id); @@ -615,7 +615,7 @@ static int automelt_getStockpileConfig(lua_State *L) { id = lua_tointeger(L, -1); if (!df::building::find(id)) return 0; - + } else { const char * name = lua_tostring(L, -1); if (!name) @@ -668,18 +668,18 @@ static int automelt_getItemCountsAndStockpileConfigs(lua_State *L) { summary.emplace("total_items", total_items_all_piles); summary.emplace("marked_items", marked_items); summary.emplace("premarked_items", premarked_items_all_piles); - + Lua::Push(L, summary); Lua::Push(L, item_counts); Lua::Push(L, marked_item_counts); Lua::Push(L, premarked_item_counts); int32_t bldg_count = 0; - + for (auto pile : world->buildings.other.STOCKPILE) { if (!isStockpile(pile)) continue; bldg_count++; - + int id = pile->id; if (watched_stockpiles_indices.count(id)) { push_stockpile_config(L, watched_stockpiles[watched_stockpiles_indices[id]]); From 0a66f411522e96802c56a637e761ef2a9cef6a1d Mon Sep 17 00:00:00 2001 From: eamondo2 Date: Sat, 21 Jan 2023 02:15:35 -0500 Subject: [PATCH 03/19] fix newline pre-commit.ci complaint --- plugins/automelt.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/automelt.cpp b/plugins/automelt.cpp index 13b8ef9c5..aa73e8895 100644 --- a/plugins/automelt.cpp +++ b/plugins/automelt.cpp @@ -701,4 +701,5 @@ DFHACK_PLUGIN_LUA_FUNCTIONS{ DFHACK_PLUGIN_LUA_COMMANDS{ DFHACK_LUA_COMMAND(automelt_getStockpileConfig), DFHACK_LUA_COMMAND(automelt_getItemCountsAndStockpileConfigs), - DFHACK_LUA_END}; \ No newline at end of file + DFHACK_LUA_END}; + \ No newline at end of file From 50c3bea84bb72f81923f807486eaff66d5113442 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 21 Jan 2023 07:20:18 +0000 Subject: [PATCH 04/19] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- plugins/automelt.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/automelt.cpp b/plugins/automelt.cpp index aa73e8895..69f72d408 100644 --- a/plugins/automelt.cpp +++ b/plugins/automelt.cpp @@ -702,4 +702,4 @@ DFHACK_PLUGIN_LUA_COMMANDS{ DFHACK_LUA_COMMAND(automelt_getStockpileConfig), DFHACK_LUA_COMMAND(automelt_getItemCountsAndStockpileConfigs), DFHACK_LUA_END}; - \ No newline at end of file + From 0fbf17f1c8a3ef63e9b6681191d7bbb2d251ae9b Mon Sep 17 00:00:00 2001 From: eamondo2 Date: Sat, 21 Jan 2023 18:22:15 -0500 Subject: [PATCH 05/19] refactor/fix as per GH suggest --- data/init/dfhack.tools.init | 3 + plugins/automelt.cpp | 171 +++++++++++++++++++++--------------- plugins/lua/automelt.lua | 7 +- 3 files changed, 104 insertions(+), 77 deletions(-) diff --git a/data/init/dfhack.tools.init b/data/init/dfhack.tools.init index fdad95be6..e2abf3dbe 100644 --- a/data/init/dfhack.tools.init +++ b/data/init/dfhack.tools.init @@ -84,6 +84,9 @@ enable overlay # Allow buildings to be placed now and built later when materials are available enable buildingplan +#Allow designated stockpiles to automatically mark items for melting +enable automelt + # Dwarf Manipulator (simple in-game Dwarf Therapist replacement) #enable manipulator diff --git a/plugins/automelt.cpp b/plugins/automelt.cpp index aa73e8895..cb6525628 100644 --- a/plugins/automelt.cpp +++ b/plugins/automelt.cpp @@ -11,6 +11,8 @@ #include "modules/Designations.h" #include "modules/Persistence.h" #include "modules/Units.h" +#include "modules/Screen.h" +#include "modules/Gui.h" // #include "uicommon.h" @@ -38,6 +40,7 @@ using namespace DFHack; using namespace df::enums; DFHACK_PLUGIN("automelt"); +DFHACK_PLUGIN_IS_ENABLED(is_enabled); REQUIRE_GLOBAL(gps); REQUIRE_GLOBAL(world); REQUIRE_GLOBAL(cursor); @@ -47,7 +50,7 @@ namespace DFHack { DBG_DECLARE(automelt, status, DebugCategory::LINFO); DBG_DECLARE(automelt, cycle, DebugCategory::LINFO); - DBG_DECLARE(automelt, perf, DebugCategory::LTRACE); + DBG_DECLARE(automelt, perf, DebugCategory::LINFO); } static const string CONFIG_KEY = string(plugin_name) + "/config"; @@ -57,18 +60,10 @@ static PersistentDataItem config; static vector watched_stockpiles; static unordered_map watched_stockpiles_indices; - -enum ConfigValues -{ - CONFIG_IS_ENABLED = 0, - -}; - enum StockpileConfigValues { STOCKPILE_CONFIG_ID = 0, STOCKPILE_CONFIG_MONITORED = 1, - STOCKPILE_CONFIG_MELT = 2, }; @@ -131,8 +126,6 @@ static int32_t cycle_timestamp = 0; // world->frame_counter at last cycle static command_result do_command(color_ostream &out, vector ¶meters); static int32_t do_cycle(color_ostream &out); -DFHACK_PLUGIN_IS_ENABLED(is_enabled); - DFhackCExport command_result plugin_init(color_ostream &out, std::vector &commands) { DEBUG(status, out).print("initializing %s\n", plugin_name); @@ -148,17 +141,10 @@ DFhackCExport command_result plugin_init(color_ostream &out, std::vectorframe_counter - cycle_timestamp >= CYCLE_TICKS) { int32_t marked = do_cycle(out); @@ -349,53 +332,57 @@ static inline bool is_set_to_melt(df::item *item) return item->flags.bits.melt; } +static inline bool is_in_job(df::item *item) { + return item->flags.bits.in_job; +} + static int mark_item(color_ostream &out, df::item *item, df::item_flags bad_flags, int32_t stockpile_id, int32_t &premarked_item_count, int32_t &item_count, bool should_melt) { - TRACE(perf,out).print("%s running mark_item\nshould_melt=%d\n", plugin_name,should_melt); + DEBUG(perf,out).print("%s running mark_item\nshould_melt=%d\n", plugin_name,should_melt); string name = ""; item->getItemDescription(&name, 0); - TRACE(perf,out).print("item %s %d\n", name.c_str(), item->id); + DEBUG(perf,out).print("item %s %d\n", name.c_str(), item->id); if (item->flags.whole & bad_flags.whole){ - TRACE(perf,out).print("rejected flag check\n"); + DEBUG(perf,out).print("rejected flag check\n"); item_count++; return 0; } if (item->isAssignedToThisStockpile(stockpile_id)) { - TRACE(perf,out).print("assignedToStockpile\n"); + DEBUG(perf,out).print("assignedToStockpile\n"); size_t marked_count = 0; std::vector contents; Items::getContainedItems(item, &contents); for (auto child = contents.begin(); child != contents.end(); child++) { - TRACE(perf,out).print("inside child loop\n"); + DEBUG(perf,out).print("inside child loop\n"); marked_count += mark_item(out, *child, bad_flags, stockpile_id, premarked_item_count, item_count, should_melt); } return marked_count; } - TRACE(perf,out).print("past recurse loop\n"); + DEBUG(perf,out).print("past recurse loop\n"); if (is_set_to_melt(item)) { - TRACE(perf,out).print("already set to melt\n"); + DEBUG(perf,out).print("already set to melt\n"); premarked_item_count++; item_count++; return 0; } if (!can_melt(item)) { - TRACE(perf,out).print("cannot melt\n"); + DEBUG(perf,out).print("cannot melt\n"); item_count++; return 0; } - TRACE(perf,out).print("increment item count\n"); + DEBUG(perf,out).print("increment item count\n"); item_count++; //Only melt if told to, else count if (should_melt) { - TRACE(perf,out).print("should_melt hit\n"); + DEBUG(perf,out).print("should_melt hit\n"); insert_into_vector(world->items.other[items_other_id::ANY_MELT_DESIGNATED], &df::item::id, item); item->flags.bits.melt = 1; return 1; @@ -408,7 +395,7 @@ static int mark_item(color_ostream &out, df::item *item, df::item_flags bad_flag static int32_t mark_all_in_stockpile(color_ostream &out, PersistentDataItem & stockpile, int32_t &premarked_item_count, int32_t &item_count, bool should_melt) { - TRACE(perf,out).print("%s running mark_all_in_stockpile\nshould_melt=%d", plugin_name, should_melt); + DEBUG(perf,out).print("%s running mark_all_in_stockpile\nshould_melt=%d\n", plugin_name, should_melt); // Precompute a bitmask with the bad flags df::item_flags bad_flags; bad_flags.whole = 0; @@ -426,7 +413,6 @@ static int32_t mark_all_in_stockpile(color_ostream &out, PersistentDataItem & st F(artifact); F(spider_web); F(owned); - F(in_job); #undef F int32_t marked_count = 0; @@ -448,17 +434,20 @@ static int32_t mark_all_in_stockpile(color_ostream &out, PersistentDataItem & st return 0; Buildings::StockpileIterator stored; + DEBUG(perf,out).print("starting item iter. loop\n"); for (stored.begin(pile_cast); !stored.done(); ++stored) { - + DEBUG(perf,out).print("calling mark_item\n"); marked_count += mark_item(out, *stored, bad_flags, spid, premarked_item_count, item_count, should_melt); + DEBUG(perf,out).print("end mark_item call\n"); } - TRACE(perf,out).print("marked_count %d\npremarked_count %d\n", marked_count, premarked_item_count); + DEBUG(perf,out).print("end item iter. loop\n"); + DEBUG(perf,out).print("exit mark_all_in_stockpile\nmarked_count %d\npremarked_count %d\n", marked_count, premarked_item_count); return marked_count; } -static int32_t scan_stockpiles(color_ostream &out, bool disable_melt, map &item_counts, map &marked_item_counts, map &premarked_item_counts) { - TRACE(perf, out).print("%s running scan_stockpiles\n", plugin_name); +static int32_t scan_stockpiles(color_ostream &out, bool should_melt, map &item_counts, map &marked_item_counts, map &premarked_item_counts) { + DEBUG(perf,out).print("running scan_stockpiles\n"); int32_t newly_marked = 0; // if (item_counts) @@ -472,22 +461,18 @@ static int32_t scan_stockpiles(color_ostream &out, bool disable_melt, map item_counts, marked_items_counts, premarked_item_counts; - marked_items_total = scan_stockpiles(out, false, item_counts, marked_items_counts, premarked_item_counts); - + marked_items_total = scan_stockpiles(out, true, item_counts, marked_items_counts, premarked_item_counts); + DEBUG(perf,out).print("exit %s do_cycle\n", plugin_name); return marked_items_total; } -static void push_stockpile_config(lua_State *L, int id, bool monitored, - bool melt) { +static int getSelectedStockpile(color_ostream &out) { + int32_t stock_id = 0; + df::building *selected_bldg = NULL; + selected_bldg = Gui::getSelectedBuilding(out, true); + if (selected_bldg->getType() != df::building_type::Stockpile) { + DEBUG(status,out).print("Selected building is not stockpile\n"); + return -1; + } + + return selected_bldg->id; +} + +static PersistentDataItem *getSelectedStockpileConfig(color_ostream &out) { + int32_t bldg_id = getSelectedStockpile(out); + if (bldg_id == -1) { + DEBUG(status,out).print("Selected bldg invalid\n"); + return NULL; + } + + validate_stockpile_configs(out); + PersistentDataItem *c = NULL; + if (watched_stockpiles_indices.count(bldg_id)) { + c = &(watched_stockpiles[watched_stockpiles_indices[bldg_id]]); + return c; + } else { + DEBUG(status,out).print("No existing config\n"); + return NULL; + } + +} + + + +static void push_stockpile_config(lua_State *L, int id, bool monitored) { map stockpile_config; stockpile_config.emplace("id", id); stockpile_config.emplace("monitored", monitored); - stockpile_config.emplace("melt", melt); Lua::Push(L, stockpile_config); } static void push_stockpile_config(lua_State *L, PersistentDataItem &c) { push_stockpile_config(L, get_config_val(c, STOCKPILE_CONFIG_ID), - get_config_bool(c, STOCKPILE_CONFIG_MONITORED), - get_config_bool(c, STOCKPILE_CONFIG_MELT)); + get_config_bool(c, STOCKPILE_CONFIG_MONITORED)); } static void automelt_designate(color_ostream &out) { @@ -544,7 +559,7 @@ static void automelt_printStatus(color_ostream &out) { out.print("automelt is %s\n\n", is_enabled ? "enabled" : "disabled"); map item_counts, marked_item_counts, premarked_item_counts; - scan_stockpiles(out, true, item_counts, marked_item_counts, premarked_item_counts); + scan_stockpiles(out, false, item_counts, marked_item_counts, premarked_item_counts); int32_t total_items_all_piles = 0; int32_t premarked_items_all_piles = 0; @@ -567,31 +582,29 @@ static void automelt_printStatus(color_ostream &out) { } name_width = -name_width; - const char *fmt = "%*s %4s %4s %4s\n"; - out.print(fmt, name_width, "name", " id ", "monitored", "melt"); - out.print(fmt, name_width, "----", "----", "---------", "----"); + const char *fmt = "%*s %4s %4s\n"; + out.print(fmt, name_width, "name", " id ", "monitored"); + out.print(fmt, name_width, "----", "----", "---------"); for (auto &stockpile : world->buildings.other.STOCKPILE) { if (!isStockpile(stockpile)) continue; - bool melt = false; bool monitored = false; if (watched_stockpiles_indices.count(stockpile->id)) { auto &c = watched_stockpiles[watched_stockpiles_indices[stockpile->id]]; - melt = get_config_bool(c, STOCKPILE_CONFIG_MELT); monitored = get_config_bool(c, STOCKPILE_CONFIG_MONITORED); } - out.print(fmt, name_width, stockpile->name.c_str(), int_to_string(stockpile->id).c_str(), - monitored ? "[x]" : "[ ]", melt ? "[x]": "[ ]"); + out.print(fmt, name_width, stockpile->name.c_str(), int_to_string(stockpile->id).c_str(), monitored ? "[x]": "[ ]"); } + DEBUG(status,out).print("exiting automelt_printStatus\n"); } -static void automelt_setStockpileConfig(color_ostream &out, int id, bool monitored, bool melt) { +static void automelt_setStockpileConfig(color_ostream &out, int id, bool monitored) { DEBUG(status,out).print("entering automelt_setStockpileConfig\n"); validate_stockpile_configs(out); bool isInvalidStockpile = !df::building::find(id); - bool hasNoData = !melt && !monitored; + bool hasNoData = !monitored; if (isInvalidStockpile || hasNoData) { remove_stockpile_config(out, id); return; @@ -600,7 +613,6 @@ static void automelt_setStockpileConfig(color_ostream &out, int id, bool monitor PersistentDataItem &c = ensure_stockpile_config(out, id); set_config_val(c, STOCKPILE_CONFIG_ID, id); set_config_bool(c, STOCKPILE_CONFIG_MONITORED, monitored); - set_config_bool(c, STOCKPILE_CONFIG_MELT, melt); } static int automelt_getStockpileConfig(lua_State *L) { @@ -638,11 +650,29 @@ static int automelt_getStockpileConfig(lua_State *L) { if (watched_stockpiles_indices.count(id)) { push_stockpile_config(L, watched_stockpiles[watched_stockpiles_indices[id]]); } else { - push_stockpile_config(L, id, false, false); + push_stockpile_config(L, id, false); } return 1; } +static int automelt_getSelectedStockpileConfig(lua_State *L){ + color_ostream *out = Lua::GetOutput(L); + if (!out) + out = &Core::getInstance().getConsole(); + DEBUG(status, *out).print("entering automelt_getSelectedStockpileConfig\n"); + validate_stockpile_configs(*out); + + int32_t stock_id = getSelectedStockpile(*out); + PersistentDataItem *c = getSelectedStockpileConfig(*out); + + //If we have a valid config entry, use that. Else assume all false. + if (c) { + push_stockpile_config(L, *c); + } else { + push_stockpile_config(L, stock_id, false); + } +} + //TODO static int automelt_getItemCountsAndStockpileConfigs(lua_State *L) { color_ostream *out = Lua::GetOutput(L); @@ -652,7 +682,7 @@ static int automelt_getItemCountsAndStockpileConfigs(lua_State *L) { validate_stockpile_configs(*out); map item_counts, marked_item_counts, premarked_item_counts; - int32_t marked_items = scan_stockpiles(*out, true, item_counts, marked_item_counts, premarked_item_counts); + int32_t marked_items = scan_stockpiles(*out, false, item_counts, marked_item_counts, premarked_item_counts); int32_t total_items_all_piles = 0; int32_t premarked_items_all_piles = 0; @@ -684,12 +714,12 @@ static int automelt_getItemCountsAndStockpileConfigs(lua_State *L) { if (watched_stockpiles_indices.count(id)) { push_stockpile_config(L, watched_stockpiles[watched_stockpiles_indices[id]]); } else { - push_stockpile_config(L, id, false, false); + push_stockpile_config(L, id, false); } } - return 4+bldg_count; - + DEBUG(perf, *out).print("exit automelt_getItemCountsAndStockpileConfigs\n"); + return 4+bldg_count; } DFHACK_PLUGIN_LUA_FUNCTIONS{ @@ -702,4 +732,3 @@ DFHACK_PLUGIN_LUA_COMMANDS{ DFHACK_LUA_COMMAND(automelt_getStockpileConfig), DFHACK_LUA_COMMAND(automelt_getItemCountsAndStockpileConfigs), DFHACK_LUA_END}; - \ No newline at end of file diff --git a/plugins/lua/automelt.lua b/plugins/lua/automelt.lua index bba93b3c4..2cccc7342 100644 --- a/plugins/lua/automelt.lua +++ b/plugins/lua/automelt.lua @@ -36,10 +36,6 @@ function parse_commandline(...) automelt_printStatus() elseif command == 'designate' then automelt_designate() - elseif command == 'melt' then - do_set_stockpile_config('melt', true, args[2]) - elseif command == 'nomelt' then - do_set_stockpile_config('melt', false, args[2]) elseif command == 'monitor' then do_set_stockpile_config('monitor', true, args[2]) elseif command == 'nomonitor'then @@ -53,7 +49,7 @@ end -- used by gui/autochop function setStockpileConfig(config) - automelt_setStockpileConfig(config.id, config.monitored, config.melt) + automelt_setStockpileConfig(config.id, config.monitored) end function getItemCountsAndStockpileConfigs() @@ -67,7 +63,6 @@ function getItemCountsAndStockpileConfigs() for _,c in ipairs(ret.stockpile_configs) do c.name = df.building.find(c.id).name c.monitored = c.monitored ~= 0 - c.melt = c.melt ~= 0 end return ret end From 6585055ed244be7adcec919d7e401567bc2dcbc8 Mon Sep 17 00:00:00 2001 From: eamondo2 Date: Sun, 22 Jan 2023 04:13:23 -0500 Subject: [PATCH 06/19] fixes, global item counts --- plugins/automelt.cpp | 163 +++++++++++++++++++++++++++++-------------- 1 file changed, 109 insertions(+), 54 deletions(-) diff --git a/plugins/automelt.cpp b/plugins/automelt.cpp index 71421bacd..031c574f4 100644 --- a/plugins/automelt.cpp +++ b/plugins/automelt.cpp @@ -73,15 +73,18 @@ static int get_config_val(PersistentDataItem &c, int index) return -1; return c.ival(index); } + static bool get_config_bool(PersistentDataItem &c, int index) { return get_config_val(c, index) == 1; } + static void set_config_val(PersistentDataItem &c, int index, int value) { if (c.isValid()) c.ival(index) = value; } + static void set_config_bool(PersistentDataItem &c, int index, bool value) { set_config_val(c, index, value ? 1 : 0); @@ -336,7 +339,8 @@ static inline bool is_in_job(df::item *item) { return item->flags.bits.in_job; } -static int mark_item(color_ostream &out, df::item *item, df::item_flags bad_flags, int32_t stockpile_id, int32_t &premarked_item_count, int32_t &item_count, bool should_melt) +static int mark_item(color_ostream &out, df::item *item, df::item_flags bad_flags, int32_t stockpile_id, + int32_t &premarked_item_count, int32_t &item_count, map &tracked_item_map, bool should_melt) { DEBUG(perf,out).print("%s running mark_item\nshould_melt=%d\n", plugin_name,should_melt); string name = ""; @@ -357,7 +361,7 @@ static int mark_item(color_ostream &out, df::item *item, df::item_flags bad_flag for (auto child = contents.begin(); child != contents.end(); child++) { DEBUG(perf,out).print("inside child loop\n"); - marked_count += mark_item(out, *child, bad_flags, stockpile_id, premarked_item_count, item_count, should_melt); + marked_count += mark_item(out, *child, bad_flags, stockpile_id, premarked_item_count, item_count, tracked_item_map, should_melt); } return marked_count; } @@ -366,7 +370,9 @@ static int mark_item(color_ostream &out, df::item *item, df::item_flags bad_flag if (is_set_to_melt(item)) { DEBUG(perf,out).print("already set to melt\n"); + tracked_item_map.emplace(item->id, true); premarked_item_count++; + DEBUG(perf,out).print("premarked_item_count=%d\n", premarked_item_count); item_count++; return 0; } @@ -385,6 +391,7 @@ static int mark_item(color_ostream &out, df::item *item, df::item_flags bad_flag DEBUG(perf,out).print("should_melt hit\n"); insert_into_vector(world->items.other[items_other_id::ANY_MELT_DESIGNATED], &df::item::id, item); item->flags.bits.melt = 1; + tracked_item_map.emplace(item->id, true); return 1; } else { return 0; @@ -393,7 +400,7 @@ static int mark_item(color_ostream &out, df::item *item, df::item_flags bad_flag } -static int32_t mark_all_in_stockpile(color_ostream &out, PersistentDataItem & stockpile, int32_t &premarked_item_count, int32_t &item_count, bool should_melt) +static int32_t mark_all_in_stockpile(color_ostream &out, PersistentDataItem & stockpile, int32_t &premarked_item_count, int32_t &item_count, map &tracked_item_map, bool should_melt) { DEBUG(perf,out).print("%s running mark_all_in_stockpile\nshould_melt=%d\n", plugin_name, should_melt); // Precompute a bitmask with the bad flags @@ -437,8 +444,8 @@ static int32_t mark_all_in_stockpile(color_ostream &out, PersistentDataItem & st DEBUG(perf,out).print("starting item iter. loop\n"); for (stored.begin(pile_cast); !stored.done(); ++stored) { DEBUG(perf,out).print("calling mark_item\n"); - marked_count += mark_item(out, *stored, bad_flags, spid, premarked_item_count, item_count, should_melt); - DEBUG(perf,out).print("end mark_item call\n"); + marked_count += mark_item(out, *stored, bad_flags, spid, premarked_item_count, item_count, tracked_item_map, should_melt); + DEBUG(perf,out).print("end mark_item call\npremarked_item_count=%d\n", premarked_item_count); } DEBUG(perf,out).print("end item iter. loop\n"); DEBUG(perf,out).print("exit mark_all_in_stockpile\nmarked_count %d\npremarked_count %d\n", marked_count, premarked_item_count); @@ -446,17 +453,14 @@ static int32_t mark_all_in_stockpile(color_ostream &out, PersistentDataItem & st } -static int32_t scan_stockpiles(color_ostream &out, bool should_melt, map &item_counts, map &marked_item_counts, map &premarked_item_counts) { +static int32_t scan_stockpiles(color_ostream &out, bool should_melt, map &item_count_piles, map &premarked_item_count_piles, + map &marked_item_count_piles, map &tracked_item_map) { DEBUG(perf,out).print("running scan_stockpiles\n"); int32_t newly_marked = 0; - // if (item_counts) - item_counts.clear(); - // if (marked_item_counts) - marked_item_counts.clear(); - // if (premarked_item_counts) - premarked_item_counts.clear(); - + item_count_piles.clear(); + premarked_item_count_piles.clear(); + marked_item_count_piles.clear(); //Parse all the watched piles for (auto &c : watched_stockpiles) { @@ -472,13 +476,15 @@ static int32_t scan_stockpiles(color_ostream &out, bool should_melt, map &tracked_item_map) { + + DEBUG(perf,out).print("running scan_all_melt_designated\n"); + int32_t marked_item_count = 0; + //loop over all items marked as melt-designated + for (auto item : world->items.other[items_other_id::ANY_MELT_DESIGNATED]) { + //item has already been marked/counted as inside a stockpile. Don't double-count. + if (tracked_item_map.count(item->id)) { + continue; + } + marked_item_count++; + } + DEBUG(perf,out).print("exiting scan_all_melt_designated\n"); + return marked_item_count; +} + +static int32_t scan_count_all(color_ostream &out, bool should_melt, int32_t &marked_item_count_total, int32_t &marked_total_count_all_piles, int32_t &marked_item_count_global, + int32_t &total_items_all_piles, map &item_count_piles, map &premarked_item_count_piles, map &marked_item_count_piles) { + + //Wraps both scan_stockpiles and scan_all_melt_designated + //Returns count of items in piles freshly marked + + int32_t newly_marked_items_piles = 0; + + map tracked_item_map_piles; + + tracked_item_map_piles.clear(); + + newly_marked_items_piles = scan_stockpiles(out, should_melt, item_count_piles, premarked_item_count_piles, marked_item_count_piles, tracked_item_map_piles); + marked_item_count_global = scan_all_melt_designated(out, tracked_item_map_piles); + + for (auto &i : watched_stockpiles) { + int id = get_config_val(i, STOCKPILE_CONFIG_ID); + total_items_all_piles+= item_count_piles[id]; + marked_total_count_all_piles += premarked_item_count_piles[id]; + } + + marked_item_count_total = marked_item_count_global + marked_total_count_all_piles; + + + return newly_marked_items_piles; + +} static int32_t do_cycle(color_ostream &out) { DEBUG(cycle,out).print("running %s cycle\n", plugin_name); @@ -494,12 +543,18 @@ static int32_t do_cycle(color_ostream &out) { validate_stockpile_configs(out); - int32_t marked_items_total; - map item_counts, marked_items_counts, premarked_item_counts; + int32_t marked_item_count_total = 0; + int32_t marked_item_count_global = 0; + int32_t newly_marked_items_piles = 0; + int32_t total_items_all_piles = 0; + int32_t marked_total_count_all_piles = 0; + map item_count_piles, premarked_item_count_piles, marked_item_count_piles; + + newly_marked_items_piles = scan_count_all(out, true, marked_item_count_total, marked_total_count_all_piles, marked_item_count_global, + total_items_all_piles, item_count_piles, premarked_item_count_piles, marked_item_count_piles); - marked_items_total = scan_stockpiles(out, true, item_counts, marked_items_counts, premarked_item_counts); DEBUG(perf,out).print("exit %s do_cycle\n", plugin_name); - return marked_items_total; + return newly_marked_items_piles; } static int getSelectedStockpile(color_ostream &out) { @@ -533,8 +588,6 @@ static PersistentDataItem *getSelectedStockpileConfig(color_ostream &out) { } - - static void push_stockpile_config(lua_State *L, int id, bool monitored) { map stockpile_config; stockpile_config.emplace("id", id); @@ -558,22 +611,20 @@ static void automelt_printStatus(color_ostream &out) { validate_stockpile_configs(out); out.print("automelt is %s\n\n", is_enabled ? "enabled" : "disabled"); - map item_counts, marked_item_counts, premarked_item_counts; - scan_stockpiles(out, false, item_counts, marked_item_counts, premarked_item_counts); - + int32_t marked_item_count_total = 0; + int32_t marked_item_count_global = 0; int32_t total_items_all_piles = 0; - int32_t premarked_items_all_piles = 0; + int32_t marked_total_count_all_piles = 0; + map item_count_piles, premarked_item_count_piles, marked_item_count_piles; - - for (auto &i : watched_stockpiles) { - int id = get_config_val(i, STOCKPILE_CONFIG_ID); - total_items_all_piles+= item_counts[id]; - premarked_items_all_piles += premarked_item_counts[id]; - } + scan_count_all(out, false, marked_item_count_total, marked_total_count_all_piles, marked_item_count_global, + total_items_all_piles, item_count_piles, premarked_item_count_piles, marked_item_count_piles); out.print("summary:\n"); - out.print(" total items in monitored piles: %d\n", total_items_all_piles); - out.print(" marked items in monitored piles: %d\n", premarked_items_all_piles); + out.print(" total items in monitored piles: %d\n", total_items_all_piles); + out.print(" marked items in monitored piles: %d\n", marked_total_count_all_piles); + out.print("marked items global (excludes those in monitored piles): %d\n", marked_item_count_global); + out.print(" marked items global (monitored piles + others): %d\n", marked_item_count_total); int name_width = 11; for (auto &stockpile : world->buildings.other.STOCKPILE) { @@ -582,19 +633,26 @@ static void automelt_printStatus(color_ostream &out) { } name_width = -name_width; - const char *fmt = "%*s %4s %4s\n"; - out.print(fmt, name_width, "name", " id ", "monitored"); - out.print(fmt, name_width, "----", "----", "---------"); + const char *fmt = "%*s %4s %4s %5s %5s\n"; + out.print(fmt, name_width, "name", " id ", "monitored", "items", "marked"); + out.print(fmt, name_width, "----", "----", "---------", "-----", "------"); for (auto &stockpile : world->buildings.other.STOCKPILE) { if (!isStockpile(stockpile)) continue; bool monitored = false; + int32_t item_count = 0; + int32_t marked_item_count = 0; if (watched_stockpiles_indices.count(stockpile->id)) { auto &c = watched_stockpiles[watched_stockpiles_indices[stockpile->id]]; monitored = get_config_bool(c, STOCKPILE_CONFIG_MONITORED); + int id = get_config_val(c, STOCKPILE_CONFIG_ID); + item_count = item_count_piles[id]; + marked_item_count = premarked_item_count_piles[id]; + } - out.print(fmt, name_width, stockpile->name.c_str(), int_to_string(stockpile->id).c_str(), monitored ? "[x]": "[ ]"); + out.print(fmt, name_width, stockpile->name.c_str(), int_to_string(stockpile->id).c_str(), monitored ? "[x]": "[ ]", + int_to_string(item_count).c_str(), int_to_string(marked_item_count).c_str()); } DEBUG(status,out).print("exiting automelt_printStatus\n"); @@ -681,28 +739,25 @@ static int automelt_getItemCountsAndStockpileConfigs(lua_State *L) { DEBUG(status,*out).print("entering automelt_getItemCountsAndStockpileConfigs\n"); validate_stockpile_configs(*out); - map item_counts, marked_item_counts, premarked_item_counts; - int32_t marked_items = scan_stockpiles(*out, false, item_counts, marked_item_counts, premarked_item_counts); - + int32_t marked_item_count_total = 0; + int32_t marked_item_count_global = 0; int32_t total_items_all_piles = 0; - int32_t premarked_items_all_piles = 0; + int32_t marked_total_count_all_piles = 0; + map item_count_piles, premarked_item_count_piles, marked_item_count_piles; - - for (auto &i : watched_stockpiles) { - int id = get_config_val(i, STOCKPILE_CONFIG_ID); - total_items_all_piles+= item_counts[id]; - premarked_items_all_piles += premarked_item_counts[id]; - } + scan_count_all(*out, false, marked_item_count_total, marked_total_count_all_piles, marked_item_count_global, + total_items_all_piles, item_count_piles, premarked_item_count_piles, marked_item_count_piles); map summary; summary.emplace("total_items", total_items_all_piles); - summary.emplace("marked_items", marked_items); - summary.emplace("premarked_items", premarked_items_all_piles); + summary.emplace("premarked_items", marked_total_count_all_piles); + summary.emplace("marked_item_count_global", marked_item_count_global); + summary.emplace("marked_item_count_total", marked_item_count_total); Lua::Push(L, summary); - Lua::Push(L, item_counts); - Lua::Push(L, marked_item_counts); - Lua::Push(L, premarked_item_counts); + Lua::Push(L, item_count_piles); + Lua::Push(L, marked_item_count_piles); + Lua::Push(L, premarked_item_count_piles); int32_t bldg_count = 0; for (auto pile : world->buildings.other.STOCKPILE) { From 969f8162a83e1fb598ff04a8fd50feff2b359588 Mon Sep 17 00:00:00 2001 From: eamondo2 Date: Sun, 22 Jan 2023 04:39:41 -0500 Subject: [PATCH 07/19] Further updates from comments/review. --- plugins/automelt.cpp | 93 +++++++++++++++++++--------------------- plugins/lua/automelt.lua | 2 +- 2 files changed, 46 insertions(+), 49 deletions(-) diff --git a/plugins/automelt.cpp b/plugins/automelt.cpp index 031c574f4..60b76730a 100644 --- a/plugins/automelt.cpp +++ b/plugins/automelt.cpp @@ -268,27 +268,40 @@ static bool isStockpile(df::building * building) { return building->getType() == df::building_type::Stockpile; } +struct BadFlagsCanMelt { + uint32_t whole; + + BadFlagsCanMelt() { + df::item_flags flags; + #define F(x) flags.bits.x = true; + F(dump); F(forbid); F(garbage_collect); + F(hostile); F(on_fire); F(rotten); F(trader); + F(in_building); F(construction); F(in_job); + #undef F + whole = flags.whole; + } +}; + +struct BadFlagsMarkItem { + uint32_t whole; + + BadFlagsMarkItem() { + df::item_flags flags; + #define F(x) flags.bits.x = true; + F(dump); F(forbid); F(garbage_collect); + F(hostile); F(on_fire); F(rotten); F(trader); + F(in_building); F(construction); F(artifact); + F(spider_web); F(owned); + #undef F + whole = flags.whole; + } +}; + // Copied from Kelly Martin's code static inline bool can_melt(df::item *item) { - df::item_flags bad_flags; - bad_flags.whole = 0; - -#define F(x) bad_flags.bits.x = true; - F(dump); - F(forbid); - F(garbage_collect); - F(in_job); - F(hostile); - F(on_fire); - F(rotten); - F(trader); - F(in_building); - F(construction); - F(artifact); - F(melt); -#undef F + static const BadFlagsCanMelt bad_flags; if (item->flags.whole & bad_flags.whole) return false; @@ -301,9 +314,9 @@ static inline bool can_melt(df::item *item) if (!is_metal_item(item)) return false; - for (auto g = item->general_refs.begin(); g != item->general_refs.end(); g++) + for (auto &g : item->general_refs) { - switch ((*g)->getType()) + switch (g->getType()) { case general_ref_type::CONTAINS_ITEM: case general_ref_type::UNIT_HOLDER: @@ -311,10 +324,10 @@ static inline bool can_melt(df::item *item) return false; case general_ref_type::CONTAINED_IN_ITEM: { - df::item *c = (*g)->getItem(); - for (auto gg = c->general_refs.begin(); gg != c->general_refs.end(); gg++) + df::item *c = g->getItem(); + for (auto &gg : c->general_refs) { - if ((*gg)->getType() == general_ref_type::UNIT_HOLDER) + if (gg->getType() == general_ref_type::UNIT_HOLDER) return false; } } @@ -335,17 +348,17 @@ static inline bool is_set_to_melt(df::item *item) return item->flags.bits.melt; } -static inline bool is_in_job(df::item *item) { - return item->flags.bits.in_job; -} - -static int mark_item(color_ostream &out, df::item *item, df::item_flags bad_flags, int32_t stockpile_id, +static int mark_item(color_ostream &out, df::item *item, BadFlagsMarkItem bad_flags, int32_t stockpile_id, int32_t &premarked_item_count, int32_t &item_count, map &tracked_item_map, bool should_melt) { DEBUG(perf,out).print("%s running mark_item\nshould_melt=%d\n", plugin_name,should_melt); - string name = ""; - item->getItemDescription(&name, 0); - DEBUG(perf,out).print("item %s %d\n", name.c_str(), item->id); + + if (DBG_NAME(perf).isEnabled(DebugCategory::LDEBUG)) { + string name = ""; + item->getItemDescription(&name, 0); + DEBUG(perf,out).print("item %s %d\n", name.c_str(), item->id); + } + if (item->flags.whole & bad_flags.whole){ DEBUG(perf,out).print("rejected flag check\n"); item_count++; @@ -403,24 +416,8 @@ static int mark_item(color_ostream &out, df::item *item, df::item_flags bad_flag static int32_t mark_all_in_stockpile(color_ostream &out, PersistentDataItem & stockpile, int32_t &premarked_item_count, int32_t &item_count, map &tracked_item_map, bool should_melt) { DEBUG(perf,out).print("%s running mark_all_in_stockpile\nshould_melt=%d\n", plugin_name, should_melt); - // Precompute a bitmask with the bad flags - df::item_flags bad_flags; - bad_flags.whole = 0; - -#define F(x) bad_flags.bits.x = true; - F(dump); - F(forbid); - F(garbage_collect); - F(hostile); - F(on_fire); - F(rotten); - F(trader); - F(in_building); - F(construction); - F(artifact); - F(spider_web); - F(owned); -#undef F + + static const BadFlagsMarkItem bad_flags; int32_t marked_count = 0; diff --git a/plugins/lua/automelt.lua b/plugins/lua/automelt.lua index 2cccc7342..9be662ee9 100644 --- a/plugins/lua/automelt.lua +++ b/plugins/lua/automelt.lua @@ -47,7 +47,7 @@ function parse_commandline(...) return true end --- used by gui/autochop +-- used by gui/auomelt function setStockpileConfig(config) automelt_setStockpileConfig(config.id, config.monitored) end From 84f7fc85da0a03299794f56a7d7c33c4ceac7413 Mon Sep 17 00:00:00 2001 From: eamondo2 Date: Sun, 22 Jan 2023 04:44:33 -0500 Subject: [PATCH 08/19] trim trailing whitespace --- plugins/automelt.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/plugins/automelt.cpp b/plugins/automelt.cpp index 60b76730a..e112491a7 100644 --- a/plugins/automelt.cpp +++ b/plugins/automelt.cpp @@ -348,11 +348,11 @@ static inline bool is_set_to_melt(df::item *item) return item->flags.bits.melt; } -static int mark_item(color_ostream &out, df::item *item, BadFlagsMarkItem bad_flags, int32_t stockpile_id, +static int mark_item(color_ostream &out, df::item *item, BadFlagsMarkItem bad_flags, int32_t stockpile_id, int32_t &premarked_item_count, int32_t &item_count, map &tracked_item_map, bool should_melt) { DEBUG(perf,out).print("%s running mark_item\nshould_melt=%d\n", plugin_name,should_melt); - + if (DBG_NAME(perf).isEnabled(DebugCategory::LDEBUG)) { string name = ""; item->getItemDescription(&name, 0); @@ -416,7 +416,7 @@ static int mark_item(color_ostream &out, df::item *item, BadFlagsMarkItem bad_fl static int32_t mark_all_in_stockpile(color_ostream &out, PersistentDataItem & stockpile, int32_t &premarked_item_count, int32_t &item_count, map &tracked_item_map, bool should_melt) { DEBUG(perf,out).print("%s running mark_all_in_stockpile\nshould_melt=%d\n", plugin_name, should_melt); - + static const BadFlagsMarkItem bad_flags; int32_t marked_count = 0; @@ -450,7 +450,7 @@ static int32_t mark_all_in_stockpile(color_ostream &out, PersistentDataItem & st } -static int32_t scan_stockpiles(color_ostream &out, bool should_melt, map &item_count_piles, map &premarked_item_count_piles, +static int32_t scan_stockpiles(color_ostream &out, bool should_melt, map &item_count_piles, map &premarked_item_count_piles, map &marked_item_count_piles, map &tracked_item_map) { DEBUG(perf,out).print("running scan_stockpiles\n"); int32_t newly_marked = 0; @@ -508,7 +508,7 @@ static int32_t scan_all_melt_designated(color_ostream &out, map & static int32_t scan_count_all(color_ostream &out, bool should_melt, int32_t &marked_item_count_total, int32_t &marked_total_count_all_piles, int32_t &marked_item_count_global, int32_t &total_items_all_piles, map &item_count_piles, map &premarked_item_count_piles, map &marked_item_count_piles) { - + //Wraps both scan_stockpiles and scan_all_melt_designated //Returns count of items in piles freshly marked @@ -528,7 +528,7 @@ static int32_t scan_count_all(color_ostream &out, bool should_melt, int32_t &mar } marked_item_count_total = marked_item_count_global + marked_total_count_all_piles; - + return newly_marked_items_piles; @@ -648,7 +648,7 @@ static void automelt_printStatus(color_ostream &out) { } - out.print(fmt, name_width, stockpile->name.c_str(), int_to_string(stockpile->id).c_str(), monitored ? "[x]": "[ ]", + out.print(fmt, name_width, stockpile->name.c_str(), int_to_string(stockpile->id).c_str(), monitored ? "[x]": "[ ]", int_to_string(item_count).c_str(), int_to_string(marked_item_count).c_str()); } DEBUG(status,out).print("exiting automelt_printStatus\n"); From 2e6ba64f5648aa5aceb4e752a22528480c7bff4c Mon Sep 17 00:00:00 2001 From: eamondo2 Date: Sun, 22 Jan 2023 04:46:35 -0500 Subject: [PATCH 09/19] Hopefully fix end-of-file-fixer complaint --- plugins/automelt.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/automelt.cpp b/plugins/automelt.cpp index e112491a7..0b3c1bdf7 100644 --- a/plugins/automelt.cpp +++ b/plugins/automelt.cpp @@ -784,4 +784,3 @@ DFHACK_PLUGIN_LUA_COMMANDS{ DFHACK_LUA_COMMAND(automelt_getStockpileConfig), DFHACK_LUA_COMMAND(automelt_getItemCountsAndStockpileConfigs), DFHACK_LUA_END}; - From 9bcd9c27bf5e465a1e7042ed0970683cae95bdd8 Mon Sep 17 00:00:00 2001 From: eamondo2 Date: Sun, 22 Jan 2023 04:55:14 -0500 Subject: [PATCH 10/19] Fix build failure --- plugins/automelt.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/automelt.cpp b/plugins/automelt.cpp index 0b3c1bdf7..b12bc3b7c 100644 --- a/plugins/automelt.cpp +++ b/plugins/automelt.cpp @@ -555,7 +555,6 @@ static int32_t do_cycle(color_ostream &out) { } static int getSelectedStockpile(color_ostream &out) { - int32_t stock_id = 0; df::building *selected_bldg = NULL; selected_bldg = Gui::getSelectedBuilding(out, true); if (selected_bldg->getType() != df::building_type::Stockpile) { @@ -726,6 +725,8 @@ static int automelt_getSelectedStockpileConfig(lua_State *L){ } else { push_stockpile_config(L, stock_id, false); } + + return 1; } //TODO @@ -783,4 +784,5 @@ DFHACK_PLUGIN_LUA_FUNCTIONS{ DFHACK_PLUGIN_LUA_COMMANDS{ DFHACK_LUA_COMMAND(automelt_getStockpileConfig), DFHACK_LUA_COMMAND(automelt_getItemCountsAndStockpileConfigs), + DFHACK_LUA_COMMAND(automelt_getSelectedStockpileConfig), DFHACK_LUA_END}; From 4d876f85b73b3f28bbc2f949f7d0f95e12302028 Mon Sep 17 00:00:00 2001 From: eamondo2 Date: Sun, 22 Jan 2023 05:14:08 -0500 Subject: [PATCH 11/19] Prelim. doc updates. --- docs/plugins/automelt.rst | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/docs/plugins/automelt.rst b/docs/plugins/automelt.rst index 9abe2cc9c..4a3bc6e60 100644 --- a/docs/plugins/automelt.rst +++ b/docs/plugins/automelt.rst @@ -6,9 +6,9 @@ automelt :tags: untested fort productivity items stockpiles :no-command: -When `enabled `, this plugin adds an option to the :kbd:`q` menu for -stockpiles. When the ``automelt`` option is selected for the stockpile, any -items placed in the stockpile will automatically be designated to be melted. +Automelt checks monitor-enabled stockpiles once every in-game day, and will mark valid items for melting. + +Please see `gui/automelt` for the interactive configuration dialog. Usage ----- @@ -16,3 +16,31 @@ Usage :: enable automelt + automelt [status] + automelt (designate) + automelt (monitor|nomonitor) + +Examples +-------- + +Automatically designate all meltable items in the stockpile `melt` for melting. :: + + enable automelt + automelt monitor melt + +Enable monitoring for the stockpile `melt`, and mmediately designate all meltable items in monitored stockpiles for melting. :: + + automelt monitor melt + automelt designate + +Commands +-------- + +``status`` + Shows current configuration and relevant statistics + +``designate`` + Designates items in monitored stockpiles for melting right now. This works even if ``automelt`` is not currently enabled. + +``(no)monitor `` + Enable/disable monitoring of a given stockpile. Requires the stockpile to have a name set. \ No newline at end of file From 96fc53f29d3bf02d075fa5eac8b3411accf1c7e6 Mon Sep 17 00:00:00 2001 From: eamondo2 Date: Sun, 22 Jan 2023 05:22:43 -0500 Subject: [PATCH 12/19] Always with the trailing whitespace --- docs/plugins/automelt.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/plugins/automelt.rst b/docs/plugins/automelt.rst index 4a3bc6e60..83f433599 100644 --- a/docs/plugins/automelt.rst +++ b/docs/plugins/automelt.rst @@ -23,13 +23,13 @@ Usage Examples -------- -Automatically designate all meltable items in the stockpile `melt` for melting. :: +Automatically designate all meltable items in the stockpile ("melt") for melting. :: enable automelt automelt monitor melt -Enable monitoring for the stockpile `melt`, and mmediately designate all meltable items in monitored stockpiles for melting. :: - +Enable monitoring for the stockpile ("melt"), and mmediately designate all meltable items in monitored stockpiles for melting. :: + automelt monitor melt automelt designate @@ -43,4 +43,4 @@ Commands Designates items in monitored stockpiles for melting right now. This works even if ``automelt`` is not currently enabled. ``(no)monitor `` - Enable/disable monitoring of a given stockpile. Requires the stockpile to have a name set. \ No newline at end of file + Enable/disable monitoring of a given stockpile. Requires the stockpile to have a name set. From 78c6b3683e5bd515994ef36fc6d8e3d0176b8066 Mon Sep 17 00:00:00 2001 From: eamondo2 Date: Mon, 23 Jan 2023 01:56:33 -0500 Subject: [PATCH 13/19] Changes as per GH suggestions. Doc updates. --- docs/plugins/automelt.rst | 23 ++++++++++----- plugins/automelt.cpp | 59 +++++++++++++++++++++++++++++++-------- plugins/lua/automelt.lua | 9 ++++-- 3 files changed, 71 insertions(+), 20 deletions(-) diff --git a/docs/plugins/automelt.rst b/docs/plugins/automelt.rst index 83f433599..45f51561a 100644 --- a/docs/plugins/automelt.rst +++ b/docs/plugins/automelt.rst @@ -17,21 +17,28 @@ Usage enable automelt automelt [status] - automelt (designate) - automelt (monitor|nomonitor) + automelt designate + automelt (monitor|nomonitor) [,...] Examples -------- -Automatically designate all meltable items in the stockpile ("melt") for melting. :: +Automatically monitor stockpile ("melt"), marking new valid items for melting. This also immediately marks all present items for melting:: enable automelt automelt monitor melt -Enable monitoring for the stockpile ("melt"), and mmediately designate all meltable items in monitored stockpiles for melting. :: +Enable monitoring for ("Stockpile #52"), which has not been given a custom name:: - automelt monitor melt - automelt designate + automelt monitor "Stockpile #52" + +Enable monitoring for ("Stockpile #52"), which has not been given a custom name:: + + automelt monitor 52 + +Enable monitoring for multiple stockpiles ("Stockpile #52", "Stockpile #35", and "melt"):: + + automelt monitor 52,"Stockpile #35",melt Commands -------- @@ -43,4 +50,6 @@ Commands Designates items in monitored stockpiles for melting right now. This works even if ``automelt`` is not currently enabled. ``(no)monitor `` - Enable/disable monitoring of a given stockpile. Requires the stockpile to have a name set. + Enable/disable monitoring of a given stockpile. Works with either the stockpile's name (if set) or ID. + If the stockpile has no custom name set, you may designate it by either the full name as reported by + the status command, or by just the number. \ No newline at end of file diff --git a/plugins/automelt.cpp b/plugins/automelt.cpp index b12bc3b7c..c0d80532a 100644 --- a/plugins/automelt.cpp +++ b/plugins/automelt.cpp @@ -276,7 +276,8 @@ struct BadFlagsCanMelt { #define F(x) flags.bits.x = true; F(dump); F(forbid); F(garbage_collect); F(hostile); F(on_fire); F(rotten); F(trader); - F(in_building); F(construction); F(in_job); + F(in_building); F(construction); F(artifact); + F(spider_web); F(owned); F(in_job); #undef F whole = flags.whole; } @@ -361,7 +362,6 @@ static int mark_item(color_ostream &out, df::item *item, BadFlagsMarkItem bad_fl if (item->flags.whole & bad_flags.whole){ DEBUG(perf,out).print("rejected flag check\n"); - item_count++; return 0; } @@ -392,7 +392,6 @@ static int mark_item(color_ostream &out, df::item *item, BadFlagsMarkItem bad_fl if (!can_melt(item)) { DEBUG(perf,out).print("cannot melt\n"); - item_count++; return 0; } @@ -588,7 +587,6 @@ static void push_stockpile_config(lua_State *L, int id, bool monitored) { map stockpile_config; stockpile_config.emplace("id", id); stockpile_config.emplace("monitored", monitored); - Lua::Push(L, stockpile_config); } @@ -625,13 +623,18 @@ static void automelt_printStatus(color_ostream &out) { int name_width = 11; for (auto &stockpile : world->buildings.other.STOCKPILE) { if (!isStockpile(stockpile)) continue; - name_width = std::max(name_width, (int)stockpile->name.size()); + if (stockpile->name.empty()) { + string stock_name = "Stockpile #" + int_to_string(stockpile->stockpile_number); + name_width = std::max(name_width, (int)(stock_name.size())); + } else { + name_width = std::max(name_width, (int)stockpile->name.size()); + } } name_width = -name_width; - const char *fmt = "%*s %4s %4s %5s %5s\n"; - out.print(fmt, name_width, "name", " id ", "monitored", "items", "marked"); - out.print(fmt, name_width, "----", "----", "---------", "-----", "------"); + const char *fmt = "%*s %9s %5s %6s\n"; + out.print(fmt, name_width, "name", "monitored", "items", "marked"); + out.print(fmt, name_width, "----", "---------", "-----", "------"); for (auto &stockpile : world->buildings.other.STOCKPILE) { if (!isStockpile(stockpile)) continue; @@ -644,11 +647,19 @@ static void automelt_printStatus(color_ostream &out) { int id = get_config_val(c, STOCKPILE_CONFIG_ID); item_count = item_count_piles[id]; marked_item_count = premarked_item_count_piles[id]; + } + int32_t stockpile_number = stockpile->stockpile_number; + if (stockpile->name.empty()) { + string stock_name = "Stockpile #" + int_to_string(stockpile->stockpile_number); + out.print(fmt, name_width, stock_name, monitored ? "[x]": "[ ]", + int_to_string(item_count).c_str(), int_to_string(marked_item_count).c_str()); + } else { + out.print(fmt, name_width, stockpile->name.c_str(), monitored ? "[x]": "[ ]", + int_to_string(item_count).c_str(), int_to_string(marked_item_count).c_str()); } - out.print(fmt, name_width, stockpile->name.c_str(), int_to_string(stockpile->id).c_str(), monitored ? "[x]": "[ ]", - int_to_string(item_count).c_str(), int_to_string(marked_item_count).c_str()); + } DEBUG(status,out).print("exiting automelt_printStatus\n"); @@ -667,6 +678,11 @@ static void automelt_setStockpileConfig(color_ostream &out, int id, bool monitor PersistentDataItem &c = ensure_stockpile_config(out, id); set_config_val(c, STOCKPILE_CONFIG_ID, id); set_config_bool(c, STOCKPILE_CONFIG_MONITORED, monitored); + + //If we're marking something as monitored, go ahead and designate contents. + if (monitored) { + automelt_designate(out); + } } static int automelt_getStockpileConfig(lua_State *L) { @@ -678,10 +694,23 @@ static int automelt_getStockpileConfig(lua_State *L) { int id; if (lua_isnumber(L, -1)) { + bool found = false; id = lua_tointeger(L, -1); - if (!df::building::find(id)) + + for (auto &stockpile : world->buildings.other.STOCKPILE) { + if (!isStockpile(stockpile)) continue; + if (id == stockpile->stockpile_number){ + id = stockpile->id; + found = true; + break; + + } + } + + if (!found) return 0; + } else { const char * name = lua_tostring(L, -1); if (!name) @@ -694,8 +723,16 @@ static int automelt_getStockpileConfig(lua_State *L) { id = stockpile->id; found = true; break; + } else { + string stock_name = "Stockpile #" + int_to_string(stockpile->stockpile_number); + if (stock_name == nameStr) { + id = stockpile->id; + found = true; + break; + } } + } if (!found) return 0; diff --git a/plugins/lua/automelt.lua b/plugins/lua/automelt.lua index 9be662ee9..dc6c94f9b 100644 --- a/plugins/lua/automelt.lua +++ b/plugins/lua/automelt.lua @@ -38,7 +38,7 @@ function parse_commandline(...) automelt_designate() elseif command == 'monitor' then do_set_stockpile_config('monitor', true, args[2]) - elseif command == 'nomonitor'then + elseif command == 'nomonitor' or command == 'unmonitor' then do_set_stockpile_config('monitor', false, args[2]) else return false @@ -47,12 +47,13 @@ function parse_commandline(...) return true end --- used by gui/auomelt +-- used by gui/automelt function setStockpileConfig(config) automelt_setStockpileConfig(config.id, config.monitored) end function getItemCountsAndStockpileConfigs() + local fmt = 'Stockpile #%-5s' local data = {automelt_getItemCountsAndStockpileConfigs()} local ret = {} ret.summary = table.remove(data, 1) @@ -62,6 +63,10 @@ function getItemCountsAndStockpileConfigs() ret.stockpile_configs = data for _,c in ipairs(ret.stockpile_configs) do c.name = df.building.find(c.id).name + if not c.name or c.name == '' then + c.name = (fmt):format(tostring(df.building.find(c.id).stockpile_number)) + c.name = c.name.gsub(c.name, '^%s*(.-)%s*$', '%1') + end c.monitored = c.monitored ~= 0 end return ret From 44d8ce2bdcb4f06f2e520c57f9918837fcdfd4bd Mon Sep 17 00:00:00 2001 From: eamondo2 Date: Mon, 23 Jan 2023 01:58:57 -0500 Subject: [PATCH 14/19] whitespace fix --- docs/plugins/automelt.rst | 2 +- plugins/automelt.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/plugins/automelt.rst b/docs/plugins/automelt.rst index 45f51561a..6b14d9dc4 100644 --- a/docs/plugins/automelt.rst +++ b/docs/plugins/automelt.rst @@ -52,4 +52,4 @@ Commands ``(no)monitor `` Enable/disable monitoring of a given stockpile. Works with either the stockpile's name (if set) or ID. If the stockpile has no custom name set, you may designate it by either the full name as reported by - the status command, or by just the number. \ No newline at end of file + the status command, or by just the number. diff --git a/plugins/automelt.cpp b/plugins/automelt.cpp index c0d80532a..c78f36f51 100644 --- a/plugins/automelt.cpp +++ b/plugins/automelt.cpp @@ -696,7 +696,7 @@ static int automelt_getStockpileConfig(lua_State *L) { if (lua_isnumber(L, -1)) { bool found = false; id = lua_tointeger(L, -1); - + for (auto &stockpile : world->buildings.other.STOCKPILE) { if (!isStockpile(stockpile)) continue; if (id == stockpile->stockpile_number){ @@ -706,7 +706,7 @@ static int automelt_getStockpileConfig(lua_State *L) { } } - + if (!found) return 0; From 6592cadc0947ce1b223b1ac4f944268c4b8f1cdf Mon Sep 17 00:00:00 2001 From: eamondo2 Date: Mon, 23 Jan 2023 13:35:26 -0500 Subject: [PATCH 15/19] Bugfixes, resolved CTD issue. --- plugins/automelt.cpp | 78 +++++++++++++++++++++------------------- plugins/lua/automelt.lua | 15 +++++--- 2 files changed, 51 insertions(+), 42 deletions(-) diff --git a/plugins/automelt.cpp b/plugins/automelt.cpp index c78f36f51..e9bd30f76 100644 --- a/plugins/automelt.cpp +++ b/plugins/automelt.cpp @@ -57,8 +57,10 @@ static const string CONFIG_KEY = string(plugin_name) + "/config"; static const string STOCKPILE_CONFIG_KEY_PREFIX = string(plugin_name) + "/stockpile/"; static PersistentDataItem config; -static vector watched_stockpiles; -static unordered_map watched_stockpiles_indices; +// static vector watched_stockpiles; +// static unordered_map watched_stockpiles_indices; + +static unordered_map watched_stockpiles; enum StockpileConfigValues { @@ -92,31 +94,31 @@ static void set_config_bool(PersistentDataItem &c, int index, bool value) static PersistentDataItem &ensure_stockpile_config(color_ostream &out, int id) { - if (watched_stockpiles_indices.count(id)) - return watched_stockpiles[watched_stockpiles_indices[id]]; + DEBUG(cycle,out).print("ensuring stockpile config id=%d\n", id); + if (watched_stockpiles.count(id)){ + DEBUG(cycle,out).print("stockpile exists in watched_indices\n"); + return watched_stockpiles[id]; + } + string keyname = STOCKPILE_CONFIG_KEY_PREFIX + int_to_string(id); - DEBUG(status, out).print("creating new persistent key for stockpile %d\n", id); - watched_stockpiles.emplace_back(World::GetPersistentData(keyname, NULL)); - size_t idx = watched_stockpiles.size() - 1; - watched_stockpiles_indices.emplace(id, idx); - return watched_stockpiles[idx]; + DEBUG(status,out).print("creating new persistent key for stockpile %d\n", id); + watched_stockpiles.emplace(id, World::GetPersistentData(keyname, NULL)); + return watched_stockpiles[id]; } static void remove_stockpile_config(color_ostream &out, int id) { - if (!watched_stockpiles_indices.count(id)) + if (!watched_stockpiles.count(id)) return; DEBUG(status, out).print("removing persistent key for stockpile %d\n", id); - size_t idx = watched_stockpiles_indices[id]; - World::DeletePersistentData(watched_stockpiles[idx]); - watched_stockpiles.erase(watched_stockpiles.begin() + idx); - watched_stockpiles_indices.erase(id); + World::DeletePersistentData(watched_stockpiles[id]); + watched_stockpiles.erase(id); } static void validate_stockpile_configs(color_ostream &out) { for (auto &c : watched_stockpiles) { - int id = get_config_val(c, STOCKPILE_CONFIG_ID); + int id = get_config_val(c.second, STOCKPILE_CONFIG_ID); if (!df::building::find(id)){ remove_stockpile_config(out, id); } @@ -174,13 +176,14 @@ DFhackCExport command_result plugin_load_data(color_ostream &out) } DEBUG(status, out).print("loading persisted enabled state: %s\n", is_enabled ? "true" : "false"); - World::GetPersistentData(&watched_stockpiles, STOCKPILE_CONFIG_KEY_PREFIX, true); - watched_stockpiles_indices.clear(); - const size_t num_watched_stockpiles = watched_stockpiles.size(); + vector loaded_persist_data; + World::GetPersistentData(&loaded_persist_data, STOCKPILE_CONFIG_KEY_PREFIX, true); + watched_stockpiles.clear(); + const size_t num_watched_stockpiles = loaded_persist_data.size(); for (size_t idx = 0; idx < num_watched_stockpiles; ++idx) { - auto &c = watched_stockpiles[idx]; - watched_stockpiles_indices.emplace(get_config_val(c, STOCKPILE_CONFIG_ID), idx); + auto &c = loaded_persist_data[idx]; + watched_stockpiles.emplace(get_config_val(c, STOCKPILE_CONFIG_ID), c); } validate_stockpile_configs(out); @@ -460,9 +463,9 @@ static int32_t scan_stockpiles(color_ostream &out, bool should_melt, mapid)) { - auto &c = watched_stockpiles[watched_stockpiles_indices[stockpile->id]]; + if (watched_stockpiles.count(stockpile->id)) { + auto &c = watched_stockpiles[stockpile->id]; monitored = get_config_bool(c, STOCKPILE_CONFIG_MONITORED); int id = get_config_val(c, STOCKPILE_CONFIG_ID); item_count = item_count_piles[id]; @@ -666,11 +669,12 @@ static void automelt_printStatus(color_ostream &out) { } static void automelt_setStockpileConfig(color_ostream &out, int id, bool monitored) { - DEBUG(status,out).print("entering automelt_setStockpileConfig\n"); + DEBUG(status,out).print("entering automelt_setStockpileConfig for id=%d and monitored=%d\n", id, monitored); validate_stockpile_configs(out); - bool isInvalidStockpile = !df::building::find(id); + bool isInvalidStockpile = !df::building::find(id) || !isStockpile(df::building::find(id)); bool hasNoData = !monitored; if (isInvalidStockpile || hasNoData) { + DEBUG(cycle,out).print("calling remove_stockpile_config with id=%d monitored=%d\n", id, monitored); remove_stockpile_config(out, id); return; } @@ -703,14 +707,12 @@ static int automelt_getStockpileConfig(lua_State *L) { id = stockpile->id; found = true; break; - } } if (!found) return 0; - } else { const char * name = lua_tostring(L, -1); if (!name) @@ -732,14 +734,13 @@ static int automelt_getStockpileConfig(lua_State *L) { } } - } if (!found) return 0; } - if (watched_stockpiles_indices.count(id)) { - push_stockpile_config(L, watched_stockpiles[watched_stockpiles_indices[id]]); + if (watched_stockpiles.count(id)) { + push_stockpile_config(L, watched_stockpiles[id]); } else { push_stockpile_config(L, id, false); } @@ -801,8 +802,11 @@ static int automelt_getItemCountsAndStockpileConfigs(lua_State *L) { bldg_count++; int id = pile->id; - if (watched_stockpiles_indices.count(id)) { - push_stockpile_config(L, watched_stockpiles[watched_stockpiles_indices[id]]); + DEBUG(cycle,*out).print("id=%d\ncount_res=%d\n", id, watched_stockpiles.count(id)); + + if (watched_stockpiles.count(id)) { + DEBUG(cycle,*out).print("indexed_id=%d\n", get_config_val(watched_stockpiles[id], STOCKPILE_CONFIG_ID)); + push_stockpile_config(L, watched_stockpiles[id]); } else { push_stockpile_config(L, id, false); } diff --git a/plugins/lua/automelt.lua b/plugins/lua/automelt.lua index dc6c94f9b..d70cf2e8e 100644 --- a/plugins/lua/automelt.lua +++ b/plugins/lua/automelt.lua @@ -62,12 +62,17 @@ function getItemCountsAndStockpileConfigs() ret.premarked_item_counts = table.remove(data, 1) ret.stockpile_configs = data for _,c in ipairs(ret.stockpile_configs) do - c.name = df.building.find(c.id).name - if not c.name or c.name == '' then - c.name = (fmt):format(tostring(df.building.find(c.id).stockpile_number)) - c.name = c.name.gsub(c.name, '^%s*(.-)%s*$', '%1') + if not c.id or c.id == -1 then + c.name = "ERROR" + c.monitored = false + else + c.name = df.building.find(c.id).name + if not c.name or c.name == '' then + c.name = (fmt):format(tostring(df.building.find(c.id).stockpile_number)) + end + c.monitored = c.monitored ~= 0 end - c.monitored = c.monitored ~= 0 + end return ret end From 75364269298635ba2394223aff9bf1f0bb30e805 Mon Sep 17 00:00:00 2001 From: eamondo2 Date: Mon, 23 Jan 2023 13:36:12 -0500 Subject: [PATCH 16/19] trailing whitespace trim --- plugins/automelt.cpp | 2 +- plugins/lua/automelt.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/automelt.cpp b/plugins/automelt.cpp index e9bd30f76..231a060fa 100644 --- a/plugins/automelt.cpp +++ b/plugins/automelt.cpp @@ -803,7 +803,7 @@ static int automelt_getItemCountsAndStockpileConfigs(lua_State *L) { int id = pile->id; DEBUG(cycle,*out).print("id=%d\ncount_res=%d\n", id, watched_stockpiles.count(id)); - + if (watched_stockpiles.count(id)) { DEBUG(cycle,*out).print("indexed_id=%d\n", get_config_val(watched_stockpiles[id], STOCKPILE_CONFIG_ID)); push_stockpile_config(L, watched_stockpiles[id]); diff --git a/plugins/lua/automelt.lua b/plugins/lua/automelt.lua index d70cf2e8e..4f1d82ad9 100644 --- a/plugins/lua/automelt.lua +++ b/plugins/lua/automelt.lua @@ -72,7 +72,7 @@ function getItemCountsAndStockpileConfigs() end c.monitored = c.monitored ~= 0 end - + end return ret end From 386546126ede76f3b6b1ad3fdfabec37a0fd9a98 Mon Sep 17 00:00:00 2001 From: eamondo2 Date: Mon, 23 Jan 2023 16:14:49 -0500 Subject: [PATCH 17/19] fix GH suggest, cache found building --- plugins/automelt.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/automelt.cpp b/plugins/automelt.cpp index 231a060fa..ba35683c1 100644 --- a/plugins/automelt.cpp +++ b/plugins/automelt.cpp @@ -671,7 +671,8 @@ static void automelt_printStatus(color_ostream &out) { static void automelt_setStockpileConfig(color_ostream &out, int id, bool monitored) { DEBUG(status,out).print("entering automelt_setStockpileConfig for id=%d and monitored=%d\n", id, monitored); validate_stockpile_configs(out); - bool isInvalidStockpile = !df::building::find(id) || !isStockpile(df::building::find(id)); + auto bldg = df::building::find(id); + bool isInvalidStockpile = bldg || !isStockpile(bldg); bool hasNoData = !monitored; if (isInvalidStockpile || hasNoData) { DEBUG(cycle,out).print("calling remove_stockpile_config with id=%d monitored=%d\n", id, monitored); From c5ce1b17660254ce1ad9b045ac717b113a001936 Mon Sep 17 00:00:00 2001 From: eamondo2 Date: Mon, 23 Jan 2023 16:20:37 -0500 Subject: [PATCH 18/19] Fix build complaints --- plugins/automelt.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/plugins/automelt.cpp b/plugins/automelt.cpp index ba35683c1..e56c79d9f 100644 --- a/plugins/automelt.cpp +++ b/plugins/automelt.cpp @@ -652,10 +652,9 @@ static void automelt_printStatus(color_ostream &out) { marked_item_count = premarked_item_count_piles[id]; } - int32_t stockpile_number = stockpile->stockpile_number; if (stockpile->name.empty()) { string stock_name = "Stockpile #" + int_to_string(stockpile->stockpile_number); - out.print(fmt, name_width, stock_name, monitored ? "[x]": "[ ]", + out.print(fmt, name_width, stock_name.c_str(), monitored ? "[x]": "[ ]", int_to_string(item_count).c_str(), int_to_string(marked_item_count).c_str()); } else { out.print(fmt, name_width, stockpile->name.c_str(), monitored ? "[x]": "[ ]", @@ -803,8 +802,6 @@ static int automelt_getItemCountsAndStockpileConfigs(lua_State *L) { bldg_count++; int id = pile->id; - DEBUG(cycle,*out).print("id=%d\ncount_res=%d\n", id, watched_stockpiles.count(id)); - if (watched_stockpiles.count(id)) { DEBUG(cycle,*out).print("indexed_id=%d\n", get_config_val(watched_stockpiles[id], STOCKPILE_CONFIG_ID)); push_stockpile_config(L, watched_stockpiles[id]); From 87507079485c44161d29ce083ef9157057c462c7 Mon Sep 17 00:00:00 2001 From: Eamon Bode Date: Mon, 23 Jan 2023 16:32:47 -0500 Subject: [PATCH 19/19] Update plugins/automelt.cpp Co-authored-by: Myk --- plugins/automelt.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/automelt.cpp b/plugins/automelt.cpp index e56c79d9f..5b68bb10b 100644 --- a/plugins/automelt.cpp +++ b/plugins/automelt.cpp @@ -671,7 +671,7 @@ static void automelt_setStockpileConfig(color_ostream &out, int id, bool monitor DEBUG(status,out).print("entering automelt_setStockpileConfig for id=%d and monitored=%d\n", id, monitored); validate_stockpile_configs(out); auto bldg = df::building::find(id); - bool isInvalidStockpile = bldg || !isStockpile(bldg); + bool isInvalidStockpile = !bldg || !isStockpile(bldg); bool hasNoData = !monitored; if (isInvalidStockpile || hasNoData) { DEBUG(cycle,out).print("calling remove_stockpile_config with id=%d monitored=%d\n", id, monitored);