From e816880375f28e82c978fff2c270464b62ff59e9 Mon Sep 17 00:00:00 2001 From: Nicholas McDaniel Date: Fri, 15 Nov 2024 23:22:57 -0500 Subject: [PATCH 01/10] Update infiniteSky to produce usable tiles --- plugins/CMakeLists.txt | 2 +- plugins/infiniteSky.cpp | 97 ++++++++++++++++++++++++++++++----------- 2 files changed, 73 insertions(+), 26 deletions(-) diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index ccd78e513c..c49e08a8ac 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -125,7 +125,7 @@ if(BUILD_SUPPORTED) #dfhack_plugin(generated-creature-renamer generated-creature-renamer.cpp) dfhack_plugin(getplants getplants.cpp) dfhack_plugin(hotkeys hotkeys.cpp LINK_LIBRARIES lua) - #dfhack_plugin(infiniteSky infiniteSky.cpp) + dfhack_plugin(infiniteSky infiniteSky.cpp) #dfhack_plugin(isoworldremote isoworldremote.cpp PROTOBUFS isoworldremote) #dfhack_plugin(jobutils jobutils.cpp) dfhack_plugin(lair lair.cpp) diff --git a/plugins/infiniteSky.cpp b/plugins/infiniteSky.cpp index 55fd4be229..e957a9f4ec 100644 --- a/plugins/infiniteSky.cpp +++ b/plugins/infiniteSky.cpp @@ -95,25 +95,68 @@ void doInfiniteSky(color_ostream& out, int32_t howMany) { CoreSuspender suspend; int32_t x_count_block = world->map.x_count_block; int32_t y_count_block = world->map.y_count_block; - for ( int32_t count = 0; count < howMany; count++ ) { - //change the size of the pointer stuff - int32_t z_count_block = world->map.z_count_block; - df::map_block**** block_index = world->map.block_index; - for ( int32_t a = 0; a < x_count_block; a++ ) { - for ( int32_t b = 0; b < y_count_block; b++ ) { - df::map_block** blockColumn = new df::map_block*[z_count_block+1]; - memcpy(blockColumn, block_index[a][b], z_count_block*sizeof(df::map_block*)); - blockColumn[z_count_block] = NULL; - delete[] block_index[a][b]; - block_index[a][b] = blockColumn; - - //deal with map_block_column stuff even though it'd probably be fine - df::map_block_column* column = world->map.column_index[a][b]; - if ( !column ) { - out.print("%s, line %d: column is null (%d, %d).\n", __FILE__, __LINE__, a, b); + int32_t z_count_block = world->map.z_count_block; + df::map_block ****block_index = world->map.block_index; + + for (int32_t a = 0; a < x_count_block; a++) { + for (int32_t b = 0; b < y_count_block; b++) { + // Allocate a new block column and copy over data from the old + df::map_block **blockColumn = + new df::map_block *[z_count_block + howMany]; + memcpy(blockColumn, block_index[a][b], + z_count_block * sizeof(df::map_block *)); + delete[] block_index[a][b]; + block_index[a][b] = blockColumn; + + df::map_block *last_air_block = blockColumn[z_count_block - 1]; + for (int32_t count = 0; count < howMany; count++) { + df::map_block *air_block = new df::map_block(); + std::fill(&air_block->tiletype[0][0], + &air_block->tiletype[0][0] + (16 * 16), + df::tiletype::OpenSpace); + + // Set block positions properly (based on prior air layer) + air_block->map_pos = blockColumn[z_count_block - 1]->map_pos; + air_block->map_pos.z += 1; + air_block->region_pos = + blockColumn[z_count_block - 1]->region_pos; + + // Copy other potentially important metadata from prior air + // layer + std::memcpy(air_block->lighting, last_air_block->lighting, + sizeof(air_block->lighting)); + std::memcpy(air_block->temperature_1, + last_air_block->temperature_1, + sizeof(air_block->temperature_1)); + std::memcpy(air_block->temperature_2, + last_air_block->temperature_2, + sizeof(air_block->temperature_2)); + std::memcpy(air_block->region_offset, + last_air_block->region_offset, + sizeof(air_block->region_offset)); + + // Create tile designations to inform lighting and + // outside markers + df::tile_designation designation{}; + designation.bits.light = true; + designation.bits.outside = true; + std::fill(&air_block->designation[0][0], + &air_block->designation[0][0] + (16 * 16), + designation); + + blockColumn[z_count_block + count] = air_block; + world->map.map_blocks.push_back(air_block); + + // deal with map_block_column stuff even though it'd probably be + // fine + df::map_block_column *column = world->map.column_index[a][b]; + if (!column) { + out.print("%s, line %d: column is null (%d, %d).\n", + __FILE__, __LINE__, a, b); continue; } - df::map_block_column::T_unmined_glyphs* glyphs = new df::map_block_column::T_unmined_glyphs; + df::map_block_column::T_unmined_glyphs *glyphs = + new df::map_block_column::T_unmined_glyphs; glyphs->x[0] = 0; glyphs->x[1] = 1; glyphs->x[2] = 2; @@ -129,16 +172,20 @@ void doInfiniteSky(color_ostream& out, int32_t howMany) { column->unmined_glyphs.push_back(glyphs); } } - df::z_level_flags* flags = new df::z_level_flags[z_count_block+1]; - memcpy(flags, world->map_extras.z_level_flags, z_count_block*sizeof(df::z_level_flags)); - flags[z_count_block].whole = 0; - flags[z_count_block].bits.update = 1; - world->map.z_count_block++; - world->map.z_count++; - delete[] world->map_extras.z_level_flags; - world->map_extras.z_level_flags = flags; } + // Update global z level flags + df::z_level_flags *flags = new df::z_level_flags[z_count_block + howMany]; + memcpy(flags, world->map_extras.z_level_flags, + z_count_block * sizeof(df::z_level_flags)); + for (int32_t count = 0; count < howMany; count++) { + flags[z_count_block + count].whole = 0; + flags[z_count_block + count].bits.update = 1; + } + world->map.z_count_block += howMany; + world->map.z_count += howMany; + delete[] world->map_extras.z_level_flags; + world->map_extras.z_level_flags = flags; } DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) From 8ceffa2a3bed5f5fcbf93eb99f392bae89e14251 Mon Sep 17 00:00:00 2001 From: Nicholas McDaniel Date: Sun, 17 Nov 2024 17:04:37 -0500 Subject: [PATCH 02/10] Correct map_block map_pos.z calculation --- plugins/infiniteSky.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/infiniteSky.cpp b/plugins/infiniteSky.cpp index e957a9f4ec..450f9d717c 100644 --- a/plugins/infiniteSky.cpp +++ b/plugins/infiniteSky.cpp @@ -117,7 +117,7 @@ void doInfiniteSky(color_ostream& out, int32_t howMany) { // Set block positions properly (based on prior air layer) air_block->map_pos = blockColumn[z_count_block - 1]->map_pos; - air_block->map_pos.z += 1; + air_block->map_pos.z += count + 1; air_block->region_pos = blockColumn[z_count_block - 1]->region_pos; From 7737a543ea955fc10fecf0232b4b9facabb1a985 Mon Sep 17 00:00:00 2001 From: Nicholas McDaniel Date: Sun, 17 Nov 2024 21:41:47 -0500 Subject: [PATCH 03/10] Prefer usage of last_air_block --- plugins/infiniteSky.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/plugins/infiniteSky.cpp b/plugins/infiniteSky.cpp index 450f9d717c..8a95cfc4f5 100644 --- a/plugins/infiniteSky.cpp +++ b/plugins/infiniteSky.cpp @@ -116,10 +116,9 @@ void doInfiniteSky(color_ostream& out, int32_t howMany) { df::tiletype::OpenSpace); // Set block positions properly (based on prior air layer) - air_block->map_pos = blockColumn[z_count_block - 1]->map_pos; + air_block->map_pos = last_air_block->map_pos; air_block->map_pos.z += count + 1; - air_block->region_pos = - blockColumn[z_count_block - 1]->region_pos; + air_block->region_pos = last_air_block->region_pos; // Copy other potentially important metadata from prior air // layer From 837b93c04c7b91249248b56f61f3342782d8e1e1 Mon Sep 17 00:00:00 2001 From: Nicholas McDaniel Date: Fri, 22 Nov 2024 09:43:25 -0500 Subject: [PATCH 04/10] Persist enabled status and modernize logging --- plugins/infiniteSky.cpp | 105 ++++++++++++++++++++++++++++------------ 1 file changed, 73 insertions(+), 32 deletions(-) diff --git a/plugins/infiniteSky.cpp b/plugins/infiniteSky.cpp index 8a95cfc4f5..90be6b4307 100644 --- a/plugins/infiniteSky.cpp +++ b/plugins/infiniteSky.cpp @@ -2,6 +2,7 @@ #include "Core.h" #include "Console.h" #include "DataDefs.h" +#include "Debug.h" #include "Export.h" #include "PluginManager.h" @@ -24,43 +25,87 @@ using namespace DFHack; using namespace df::enums; DFHACK_PLUGIN("infiniteSky"); +DFHACK_PLUGIN_IS_ENABLED(is_enabled); + REQUIRE_GLOBAL(world); +namespace DFHack { + // for configuration-related logging + DBG_DECLARE(infiniteSky, control, DebugCategory::LINFO); + // for logging during creation of z-levels + DBG_DECLARE(infiniteSky, cycle, DebugCategory::LINFO); +} + +static const string CONFIG_KEY = string(plugin_name) + "/config"; +static PersistentDataItem config; +enum ConfigValues { + CONFIG_IS_ENABLED = 0, +}; + command_result infiniteSky (color_ostream &out, std::vector & parameters); -DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) -{ +DFhackCExport command_result plugin_init(color_ostream &out, + std::vector &commands) { commands.push_back(PluginCommand( - "infiniteSky", - "Create new sky levels on request, or as needed.", + "infiniteSky", "Automatically allocate new z-levels of sky.", infiniteSky)); return CR_OK; } -DFhackCExport command_result plugin_shutdown ( color_ostream &out ) -{ +DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) { + if (!Core::getInstance().isMapLoaded() || !World::isFortressMode()) { + out.printerr("Cannot enable %s without a loaded fort.\n", plugin_name); + return CR_FAILURE; + } + if (enable != is_enabled) { + is_enabled = enable; + DEBUG(control, out) + .print("%s from the API; persisting\n", + is_enabled ? "enabled" : "disabled"); + config.set_bool(CONFIG_IS_ENABLED, is_enabled); + } else { + DEBUG(control, out) + .print("%s from the API, but already %s; no action\n", + is_enabled ? "enabled" : "disabled", + is_enabled ? "enabled" : "disabled"); + } + return CR_OK; } -/* -DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event) -{ - switch (event) { - case SC_GAME_LOADED: - // initialize from the world just loaded - break; - case SC_GAME_UNLOADED: - // cleanup - break; - default: - break; +DFhackCExport command_result plugin_load_site_data(color_ostream &out) { + config = World::GetPersistentSiteData(CONFIG_KEY); + + if (!config.isValid()) { + DEBUG(control, out) + .print("no config found in this save; initializing\n"); + config = World::AddPersistentSiteData(CONFIG_KEY); + config.set_bool(CONFIG_IS_ENABLED, is_enabled); + } + + // 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 = config.get_bool(CONFIG_IS_ENABLED); + DEBUG(control, out) + .print("loading persisted enabled state: %s\n", + is_enabled ? "true" : "false"); + return CR_OK; +} + +DFhackCExport command_result plugin_onstatechange(color_ostream &out, + state_change_event event) { + if (event == DFHack::SC_WORLD_UNLOADED) { + if (is_enabled) { + DEBUG(control, out) + .print("world unloaded; disabling %s\n", plugin_name); + is_enabled = false; + } } return CR_OK; } -*/ static size_t constructionSize = 0; -DFHACK_PLUGIN_IS_ENABLED(enabled); void doInfiniteSky(color_ostream& out, int32_t howMany); DFhackCExport command_result plugin_onupdate ( color_ostream &out ) @@ -150,8 +195,9 @@ void doInfiniteSky(color_ostream& out, int32_t howMany) { // fine df::map_block_column *column = world->map.column_index[a][b]; if (!column) { - out.print("%s, line %d: column is null (%d, %d).\n", - __FILE__, __LINE__, a, b); + DEBUG(cycle, out) + .print("%s, line %d: column is null (%d, %d).\n", + __FILE__, __LINE__, a, b); continue; } df::map_block_column::T_unmined_glyphs *glyphs = @@ -187,27 +233,22 @@ void doInfiniteSky(color_ostream& out, int32_t howMany) { world->map_extras.z_level_flags = flags; } -DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) -{ - enabled = enable; - return CR_OK; -} - command_result infiniteSky (color_ostream &out, std::vector & parameters) { if ( parameters.size() > 1 ) return CR_WRONG_USAGE; - if ( parameters.size() == 0 ) { - out.print("Construction monitoring is %s.\n", enabled ? "enabled" : "disabled"); + if (parameters.size() == 0) { + out.print("Construction monitoring is %s.\n", + is_enabled ? "enabled" : "disabled"); return CR_OK; } if (parameters[0] == "enable") { - enabled = true; + plugin_enable(out, true); out.print("Construction monitoring enabled.\n"); return CR_OK; } if (parameters[0] == "disable") { - enabled = false; + plugin_enable(out, false); out.print("Construction monitoring disabled.\n"); constructionSize = 0; return CR_OK; From a0bd8ee834707ff1ca7768fdbd3189e29ac43fc7 Mon Sep 17 00:00:00 2001 From: Nicholas McDaniel Date: Fri, 22 Nov 2024 10:20:24 -0500 Subject: [PATCH 05/10] Implement automatic z-level additions using EventType::CONSTRUCTION --- plugins/infiniteSky.cpp | 68 ++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 42 deletions(-) diff --git a/plugins/infiniteSky.cpp b/plugins/infiniteSky.cpp index 90be6b4307..003534de39 100644 --- a/plugins/infiniteSky.cpp +++ b/plugins/infiniteSky.cpp @@ -1,15 +1,14 @@ #include "Core.h" -#include "Console.h" #include "DataDefs.h" #include "Debug.h" #include "Export.h" #include "PluginManager.h" #include "modules/World.h" +#include "modules/EventManager.h" #include "df/construction.h" -#include "df/game_mode.h" #include "df/map_block.h" #include "df/map_block_column.h" #include "df/world.h" @@ -44,6 +43,9 @@ enum ConfigValues { command_result infiniteSky (color_ostream &out, std::vector & parameters); +static void constructionEventHandler(color_ostream& out, void* ptr); +EventManager::EventHandler handler(plugin_self, constructionEventHandler,0); + DFhackCExport command_result plugin_init(color_ostream &out, std::vector &commands) { commands.push_back(PluginCommand( @@ -52,6 +54,10 @@ DFhackCExport command_result plugin_init(color_ostream &out, return CR_OK; } +void cleanup() { + EventManager::unregister(EventManager::EventType::CONSTRUCTION, handler); +} + DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) { if (!Core::getInstance().isMapLoaded() || !World::isFortressMode()) { out.printerr("Cannot enable %s without a loaded fort.\n", plugin_name); @@ -63,6 +69,13 @@ DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) { .print("%s from the API; persisting\n", is_enabled ? "enabled" : "disabled"); config.set_bool(CONFIG_IS_ENABLED, is_enabled); + + if (enable) { + EventManager::registerListener( + EventManager::EventType::CONSTRUCTION, handler); + } else { + cleanup(); + } } else { DEBUG(control, out) .print("%s from the API, but already %s; no action\n", @@ -73,6 +86,11 @@ DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) { return CR_OK; } +DFhackCExport command_result plugin_shutdown(color_ostream &out) { + cleanup(); + return CR_OK; +} + DFhackCExport command_result plugin_load_site_data(color_ostream &out) { config = World::GetPersistentSiteData(CONFIG_KEY); @@ -83,10 +101,9 @@ DFhackCExport command_result plugin_load_site_data(color_ostream &out) { config.set_bool(CONFIG_IS_ENABLED, is_enabled); } - // 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 = config.get_bool(CONFIG_IS_ENABLED); + + // Call plugin_enable to set value to ensure the event handler is properly registered + plugin_enable(out, config.get_bool(CONFIG_IS_ENABLED)); DEBUG(control, out) .print("loading persisted enabled state: %s\n", is_enabled ? "true" : "false"); @@ -105,35 +122,13 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, return CR_OK; } -static size_t constructionSize = 0; void doInfiniteSky(color_ostream& out, int32_t howMany); -DFhackCExport command_result plugin_onupdate ( color_ostream &out ) -{ - if ( !Core::getInstance().isMapLoaded() ) - return CR_OK; - { - t_gamemodes mode; - if ( !World::ReadGameMode(mode) ) - return CR_FAILURE; - if ( mode.g_mode != df::enums::game_mode::DWARF ) - return CR_OK; - } +static void constructionEventHandler(color_ostream &out, void *ptr) { + df::construction *constr = (df::construction *)ptr; - if ( world->event.constructions.size() == constructionSize ) - return CR_OK; - int32_t zNow = world->map.z_count_block; - for ( size_t a = constructionSize; a < world->event.constructions.size(); a++ ) { - df::construction* construct = world->event.constructions[a]; - if ( construct->pos.z+2 < zNow ) - continue; + if (constr->pos.z >= world->map.z_count_block - 2) doInfiniteSky(out, 1); - zNow = world->map.z_count_block; - ///break; - } - constructionSize = world->event.constructions.size(); - - return CR_OK; } void doInfiniteSky(color_ostream& out, int32_t howMany) { @@ -242,17 +237,6 @@ command_result infiniteSky (color_ostream &out, std::vector & para is_enabled ? "enabled" : "disabled"); return CR_OK; } - if (parameters[0] == "enable") { - plugin_enable(out, true); - out.print("Construction monitoring enabled.\n"); - return CR_OK; - } - if (parameters[0] == "disable") { - plugin_enable(out, false); - out.print("Construction monitoring disabled.\n"); - constructionSize = 0; - return CR_OK; - } int32_t howMany = 0; howMany = atoi(parameters[0].c_str()); out.print("InfiniteSky: creating %d new z-level%s of sky.\n", howMany, howMany == 1 ? "" : "s" ); From 95e65aac79b4d33f5cb334e418e6a8ef1bba6503 Mon Sep 17 00:00:00 2001 From: Nicholas McDaniel Date: Fri, 22 Nov 2024 10:26:42 -0500 Subject: [PATCH 06/10] Migrate infiniteSky arg parsing to lua --- plugins/CMakeLists.txt | 2 +- plugins/infiniteSky.cpp | 43 +++++++++++++++++++++++++++++-------- plugins/lua/infiniteSky.lua | 27 +++++++++++++++++++++++ 3 files changed, 62 insertions(+), 10 deletions(-) create mode 100644 plugins/lua/infiniteSky.lua diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index c49e08a8ac..2feb0f0cbc 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -125,7 +125,7 @@ if(BUILD_SUPPORTED) #dfhack_plugin(generated-creature-renamer generated-creature-renamer.cpp) dfhack_plugin(getplants getplants.cpp) dfhack_plugin(hotkeys hotkeys.cpp LINK_LIBRARIES lua) - dfhack_plugin(infiniteSky infiniteSky.cpp) + dfhack_plugin(infiniteSky infiniteSky.cpp LINK_LIBRARIES lua) #dfhack_plugin(isoworldremote isoworldremote.cpp PROTOBUFS isoworldremote) #dfhack_plugin(jobutils jobutils.cpp) dfhack_plugin(lair lair.cpp) diff --git a/plugins/infiniteSky.cpp b/plugins/infiniteSky.cpp index 003534de39..7735fd8648 100644 --- a/plugins/infiniteSky.cpp +++ b/plugins/infiniteSky.cpp @@ -3,6 +3,7 @@ #include "DataDefs.h" #include "Debug.h" #include "Export.h" +#include "LuaTools.h" #include "PluginManager.h" #include "modules/World.h" @@ -228,18 +229,42 @@ void doInfiniteSky(color_ostream& out, int32_t howMany) { world->map_extras.z_level_flags = flags; } -command_result infiniteSky (color_ostream &out, std::vector & parameters) -{ - if ( parameters.size() > 1 ) +struct infinitesky_options { + // whether to display help + bool help = false; + + // how many z levels to generate immediately (0 for none) + int32_t n = 0; + + static struct_identity _identity; +}; +static const struct_field_info infinitesky_options_fields[] = { + {struct_field_info::PRIMITIVE, "help", offsetof(infinitesky_options, help), &df::identity_traits::identity, 0, 0}, + {struct_field_info::PRIMITIVE, "n", offsetof(infinitesky_options, n), &df::identity_traits::identity, 0, 0} +}; +struct_identity infinitesky_options::_identity{sizeof(infinitesky_options), &df::allocator_fn, NULL, "infinitesky_options", NULL, infinitesky_options_fields}; + +command_result infiniteSky(color_ostream &out, + std::vector ¶meters) { + if (!Core::getInstance().isMapLoaded() || !World::isFortressMode()) { + out.printerr("Cannot run %s without a loaded fort.\n", plugin_name); + return CR_FAILURE; + } + + infinitesky_options opts; + if (!Lua::CallLuaModuleFunction(out, "plugins.infiniteSky", + "parse_commandline", + std::make_tuple(&opts, parameters)) || + opts.help) return CR_WRONG_USAGE; - if (parameters.size() == 0) { + + if (opts.n != 0) { + out.print("InfiniteSky: creating %d new z-level%s of sky.\n", opts.n, + opts.n == 1 ? "" : "s"); + doInfiniteSky(out, opts.n); + } else { out.print("Construction monitoring is %s.\n", is_enabled ? "enabled" : "disabled"); - return CR_OK; } - int32_t howMany = 0; - howMany = atoi(parameters[0].c_str()); - out.print("InfiniteSky: creating %d new z-level%s of sky.\n", howMany, howMany == 1 ? "" : "s" ); - doInfiniteSky(out, howMany); return CR_OK; } diff --git a/plugins/lua/infiniteSky.lua b/plugins/lua/infiniteSky.lua new file mode 100644 index 0000000000..6e35183973 --- /dev/null +++ b/plugins/lua/infiniteSky.lua @@ -0,0 +1,27 @@ +local _ENV = mkmodule('plugins.infiniteSky') + +local argparse = require('argparse') + +local function process_args(opts, args) + if args[1] == 'help' then + opts.help = true + return + end + + if args[1] ~= nil then + opts.n = argparse.positiveInt(args[1]) + return + end + + return argparse.processArgsGetopt(args, { + {'h', 'help', handler=function() opts.help = true end}, + }) +end + +function parse_commandline(opts, args) + local positionals = process_args(opts, args) + + if opts.help then return end +end + +return _ENV From 466f146aa681d836b68e4338939ff7b2a3c182a9 Mon Sep 17 00:00:00 2001 From: Nicholas McDaniel Date: Fri, 22 Nov 2024 10:31:34 -0500 Subject: [PATCH 07/10] Update documentation and changelog for infiniteSky --- docs/changelog.txt | 1 + docs/plugins/infiniteSky.rst | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index d96475f0ee..99d09bd491 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -52,6 +52,7 @@ Template for new versions: # Future ## New Tools +- `infiniteSky`: (reinstated) tool for automatically creating new z-levels of sky ## New Features - `tweak`: ``realistic-melting``: change melting return for inorganic armor parts, shields, weapons, trap components and tools to stop smelters from creating metal, bring melt return for adamantine in line with other metals to ~95% of forging cost. wear reduces melt return by 10% per level diff --git a/docs/plugins/infiniteSky.rst b/docs/plugins/infiniteSky.rst index 0c14804afd..a20b05b892 100644 --- a/docs/plugins/infiniteSky.rst +++ b/docs/plugins/infiniteSky.rst @@ -2,8 +2,8 @@ infiniteSky =========== .. dfhack-tool:: - :summary: Automatically allocate new z-levels of sky - :tags: unavailable + :summary: Automatically allocate new z-levels of sky. + :tags: fort auto design map If enabled, this plugin will automatically allocate new z-levels of sky at the top of the map as you build up. Or it can allocate one or many additional levels From 795f2e7d8c0fd3563ec0a26e1846f29a86e9ab0a Mon Sep 17 00:00:00 2001 From: Nicholas McDaniel Date: Sat, 23 Nov 2024 08:47:50 -0500 Subject: [PATCH 08/10] Rename infiniteSky to infinite-sky for naming consistency --- data/base_command_counts.json | 2 +- docs/changelog.txt | 2 +- docs/plugins/{infiniteSky.rst => infinite-sky.rst} | 10 ++++++---- plugins/CMakeLists.txt | 2 +- plugins/{infiniteSky.cpp => infinite-sky.cpp} | 8 ++++---- plugins/lua/{infiniteSky.lua => infinite-sky.lua} | 2 +- 6 files changed, 14 insertions(+), 12 deletions(-) rename docs/plugins/{infiniteSky.rst => infinite-sky.rst} (89%) rename plugins/{infiniteSky.cpp => infinite-sky.cpp} (97%) rename plugins/lua/{infiniteSky.lua => infinite-sky.lua} (91%) diff --git a/data/base_command_counts.json b/data/base_command_counts.json index 6acfda21b1..a05d50c1ed 100644 --- a/data/base_command_counts.json +++ b/data/base_command_counts.json @@ -98,7 +98,7 @@ "gui/mechanisms": 1, "gui/pathable": 1, "hotkeys": 1, - "infiniteSky": 1, + "infinite-sky": 1, "force": 1, "hermit": 1, "strangemood": 1, diff --git a/docs/changelog.txt b/docs/changelog.txt index 99d09bd491..4d3a320689 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -52,7 +52,7 @@ Template for new versions: # Future ## New Tools -- `infiniteSky`: (reinstated) tool for automatically creating new z-levels of sky +- `infinite-sky`: (reinstated, renamed from ``infiniteSky``) tool for automatically creating new z-levels of sky ## New Features - `tweak`: ``realistic-melting``: change melting return for inorganic armor parts, shields, weapons, trap components and tools to stop smelters from creating metal, bring melt return for adamantine in line with other metals to ~95% of forging cost. wear reduces melt return by 10% per level diff --git a/docs/plugins/infiniteSky.rst b/docs/plugins/infinite-sky.rst similarity index 89% rename from docs/plugins/infiniteSky.rst rename to docs/plugins/infinite-sky.rst index a20b05b892..6ec0fc9a21 100644 --- a/docs/plugins/infiniteSky.rst +++ b/docs/plugins/infinite-sky.rst @@ -1,5 +1,7 @@ -infiniteSky -=========== +.. _infinitesky: + +infinite-sky +============ .. dfhack-tool:: :summary: Automatically allocate new z-levels of sky. @@ -12,11 +14,11 @@ at your command. Usage ----- -``enable infiniteSky`` +``enable infinite-sky`` Enables monitoring of constructions. If you build anything in the second highest z-level, it will allocate one more sky level. You can build stairs up as high as you like! -``infiniteSky []`` +``infinite-sky []`` Raise the sky by n z-levels. If run without parameters, raises the sky by one z-level. diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 2feb0f0cbc..30e32b2f21 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -125,7 +125,7 @@ if(BUILD_SUPPORTED) #dfhack_plugin(generated-creature-renamer generated-creature-renamer.cpp) dfhack_plugin(getplants getplants.cpp) dfhack_plugin(hotkeys hotkeys.cpp LINK_LIBRARIES lua) - dfhack_plugin(infiniteSky infiniteSky.cpp LINK_LIBRARIES lua) + dfhack_plugin(infinite-sky infinite-sky.cpp LINK_LIBRARIES lua) #dfhack_plugin(isoworldremote isoworldremote.cpp PROTOBUFS isoworldremote) #dfhack_plugin(jobutils jobutils.cpp) dfhack_plugin(lair lair.cpp) diff --git a/plugins/infiniteSky.cpp b/plugins/infinite-sky.cpp similarity index 97% rename from plugins/infiniteSky.cpp rename to plugins/infinite-sky.cpp index 7735fd8648..80a8900308 100644 --- a/plugins/infiniteSky.cpp +++ b/plugins/infinite-sky.cpp @@ -24,7 +24,7 @@ using namespace std; using namespace DFHack; using namespace df::enums; -DFHACK_PLUGIN("infiniteSky"); +DFHACK_PLUGIN("infinite-sky"); DFHACK_PLUGIN_IS_ENABLED(is_enabled); REQUIRE_GLOBAL(world); @@ -50,7 +50,7 @@ EventManager::EventHandler handler(plugin_self, constructionEventHandler,0); DFhackCExport command_result plugin_init(color_ostream &out, std::vector &commands) { commands.push_back(PluginCommand( - "infiniteSky", "Automatically allocate new z-levels of sky.", + "infinite-sky", "Automatically allocate new z-levels of sky.", infiniteSky)); return CR_OK; } @@ -252,14 +252,14 @@ command_result infiniteSky(color_ostream &out, } infinitesky_options opts; - if (!Lua::CallLuaModuleFunction(out, "plugins.infiniteSky", + if (!Lua::CallLuaModuleFunction(out, "plugins.infinite-sky", "parse_commandline", std::make_tuple(&opts, parameters)) || opts.help) return CR_WRONG_USAGE; if (opts.n != 0) { - out.print("InfiniteSky: creating %d new z-level%s of sky.\n", opts.n, + out.print("Infinite-sky: creating %d new z-level%s of sky.\n", opts.n, opts.n == 1 ? "" : "s"); doInfiniteSky(out, opts.n); } else { diff --git a/plugins/lua/infiniteSky.lua b/plugins/lua/infinite-sky.lua similarity index 91% rename from plugins/lua/infiniteSky.lua rename to plugins/lua/infinite-sky.lua index 6e35183973..0e8c7cff1d 100644 --- a/plugins/lua/infiniteSky.lua +++ b/plugins/lua/infinite-sky.lua @@ -1,4 +1,4 @@ -local _ENV = mkmodule('plugins.infiniteSky') +local _ENV = mkmodule('plugins.infinite-sky') local argparse = require('argparse') From 160f3fa2dfd3eb9c425ad6ab6e255f35945be0ac Mon Sep 17 00:00:00 2001 From: Nicholas McDaniel Date: Sat, 23 Nov 2024 08:52:30 -0500 Subject: [PATCH 09/10] Fix documentation to use adjusted usage --- docs/plugins/infinite-sky.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/plugins/infinite-sky.rst b/docs/plugins/infinite-sky.rst index 6ec0fc9a21..625bf71786 100644 --- a/docs/plugins/infinite-sky.rst +++ b/docs/plugins/infinite-sky.rst @@ -18,9 +18,10 @@ Usage Enables monitoring of constructions. If you build anything in the second highest z-level, it will allocate one more sky level. You can build stairs up as high as you like! -``infinite-sky []`` - Raise the sky by n z-levels. If run without parameters, raises the sky by - one z-level. +``infinite-sky`` + Print current status. +``infinite-sky `` + Raise the sky by n z-levels. .. warning:: From 69ba0b6cc8a7afd9418231cf935050821733eb1e Mon Sep 17 00:00:00 2001 From: Nicholas McDaniel Date: Thu, 28 Nov 2024 12:13:21 -0500 Subject: [PATCH 10/10] Implement suggested changes --- plugins/infinite-sky.cpp | 167 +++++++++++++++++------------------ plugins/lua/infinite-sky.lua | 23 ++--- 2 files changed, 87 insertions(+), 103 deletions(-) diff --git a/plugins/infinite-sky.cpp b/plugins/infinite-sky.cpp index 80a8900308..0dcd69c006 100644 --- a/plugins/infinite-sky.cpp +++ b/plugins/infinite-sky.cpp @@ -1,13 +1,12 @@ #include "Core.h" -#include "DataDefs.h" #include "Debug.h" -#include "Export.h" #include "LuaTools.h" #include "PluginManager.h" -#include "modules/World.h" #include "modules/EventManager.h" +#include "modules/Maps.h" +#include "modules/World.h" #include "df/construction.h" #include "df/map_block.h" @@ -19,7 +18,8 @@ #include #include -using namespace std; +using std::string; +using std::vector; using namespace DFHack; using namespace df::enums; @@ -45,7 +45,7 @@ enum ConfigValues { command_result infiniteSky (color_ostream &out, std::vector & parameters); static void constructionEventHandler(color_ostream& out, void* ptr); -EventManager::EventHandler handler(plugin_self, constructionEventHandler,0); +EventManager::EventHandler handler(plugin_self, constructionEventHandler,11); DFhackCExport command_result plugin_init(color_ostream &out, std::vector &commands) { @@ -87,11 +87,6 @@ DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) { return CR_OK; } -DFhackCExport command_result plugin_shutdown(color_ostream &out) { - cleanup(); - return CR_OK; -} - DFhackCExport command_result plugin_load_site_data(color_ostream &out) { config = World::GetPersistentSiteData(CONFIG_KEY); @@ -102,7 +97,6 @@ DFhackCExport command_result plugin_load_site_data(color_ostream &out) { config.set_bool(CONFIG_IS_ENABLED, is_enabled); } - // Call plugin_enable to set value to ensure the event handler is properly registered plugin_enable(out, config.get_bool(CONFIG_IS_ENABLED)); DEBUG(control, out) @@ -118,6 +112,7 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, DEBUG(control, out) .print("world unloaded; disabling %s\n", plugin_name); is_enabled = false; + cleanup(); } } return CR_OK; @@ -134,86 +129,84 @@ static void constructionEventHandler(color_ostream &out, void *ptr) { void doInfiniteSky(color_ostream& out, int32_t howMany) { CoreSuspender suspend; - int32_t x_count_block = world->map.x_count_block; - int32_t y_count_block = world->map.y_count_block; int32_t z_count_block = world->map.z_count_block; df::map_block ****block_index = world->map.block_index; - for (int32_t a = 0; a < x_count_block; a++) { - for (int32_t b = 0; b < y_count_block; b++) { - // Allocate a new block column and copy over data from the old - df::map_block **blockColumn = - new df::map_block *[z_count_block + howMany]; - memcpy(blockColumn, block_index[a][b], - z_count_block * sizeof(df::map_block *)); - delete[] block_index[a][b]; - block_index[a][b] = blockColumn; - - df::map_block *last_air_block = blockColumn[z_count_block - 1]; - for (int32_t count = 0; count < howMany; count++) { - df::map_block *air_block = new df::map_block(); - std::fill(&air_block->tiletype[0][0], - &air_block->tiletype[0][0] + (16 * 16), - df::tiletype::OpenSpace); - - // Set block positions properly (based on prior air layer) - air_block->map_pos = last_air_block->map_pos; - air_block->map_pos.z += count + 1; - air_block->region_pos = last_air_block->region_pos; - - // Copy other potentially important metadata from prior air - // layer - std::memcpy(air_block->lighting, last_air_block->lighting, - sizeof(air_block->lighting)); - std::memcpy(air_block->temperature_1, - last_air_block->temperature_1, - sizeof(air_block->temperature_1)); - std::memcpy(air_block->temperature_2, - last_air_block->temperature_2, - sizeof(air_block->temperature_2)); - std::memcpy(air_block->region_offset, - last_air_block->region_offset, - sizeof(air_block->region_offset)); - - // Create tile designations to inform lighting and - // outside markers - df::tile_designation designation{}; - designation.bits.light = true; - designation.bits.outside = true; - std::fill(&air_block->designation[0][0], - &air_block->designation[0][0] + (16 * 16), - designation); - - blockColumn[z_count_block + count] = air_block; - world->map.map_blocks.push_back(air_block); - - // deal with map_block_column stuff even though it'd probably be - // fine - df::map_block_column *column = world->map.column_index[a][b]; - if (!column) { - DEBUG(cycle, out) - .print("%s, line %d: column is null (%d, %d).\n", - __FILE__, __LINE__, a, b); - continue; - } - df::map_block_column::T_unmined_glyphs *glyphs = - new df::map_block_column::T_unmined_glyphs; - glyphs->x[0] = 0; - glyphs->x[1] = 1; - glyphs->x[2] = 2; - glyphs->x[3] = 3; - glyphs->y[0] = 0; - glyphs->y[1] = 0; - glyphs->y[2] = 0; - glyphs->y[3] = 0; - glyphs->tile[0] = 'e'; - glyphs->tile[1] = 'x'; - glyphs->tile[2] = 'p'; - glyphs->tile[3] = '^'; - column->unmined_glyphs.push_back(glyphs); + cuboid last_air_layer( + 0, 0, world->map.z_count_block - 1, + world->map.x_count_block - 1, world->map.y_count_block - 1, world->map.z_count_block - 1); + + last_air_layer.forCoord([&](df::coord bpos) { + // Allocate a new block column and copy over data from the old + df::map_block **blockColumn = + new df::map_block *[z_count_block + howMany]; + memcpy(blockColumn, block_index[bpos.x][bpos.y], + z_count_block * sizeof(df::map_block *)); + delete[] block_index[bpos.x][bpos.y]; + block_index[bpos.x][bpos.y] = blockColumn; + + df::map_block *last_air_block = blockColumn[bpos.z]; + for (int32_t count = 0; count < howMany; count++) { + df::map_block *air_block = new df::map_block(); + std::fill(&air_block->tiletype[0][0], + &air_block->tiletype[0][0] + (16 * 16), + df::tiletype::OpenSpace); + + // Set block positions properly (based on prior air layer) + air_block->map_pos = last_air_block->map_pos; + air_block->map_pos.z += count + 1; + air_block->region_pos = last_air_block->region_pos; + + // Copy other potentially important metadata from prior air + // layer + std::memcpy(air_block->lighting, last_air_block->lighting, + sizeof(air_block->lighting)); + std::memcpy(air_block->temperature_1, last_air_block->temperature_1, + sizeof(air_block->temperature_1)); + std::memcpy(air_block->temperature_2, last_air_block->temperature_2, + sizeof(air_block->temperature_2)); + std::memcpy(air_block->region_offset, last_air_block->region_offset, + sizeof(air_block->region_offset)); + + // Create tile designations to inform lighting and + // outside markers + df::tile_designation designation{}; + designation.bits.light = true; + designation.bits.outside = true; + std::fill(&air_block->designation[0][0], + &air_block->designation[0][0] + (16 * 16), designation); + + blockColumn[z_count_block + count] = air_block; + world->map.map_blocks.push_back(air_block); + + // deal with map_block_column stuff even though it'd probably be + // fine + df::map_block_column *column = + world->map.column_index[bpos.x][bpos.y]; + if (!column) { + DEBUG(cycle, out) + .print("%s, line %d: column is null (%d, %d).\n", __FILE__, + __LINE__, bpos.x, bpos.y); + continue; } + df::map_block_column::T_unmined_glyphs *glyphs = + new df::map_block_column::T_unmined_glyphs; + glyphs->x[0] = 0; + glyphs->x[1] = 1; + glyphs->x[2] = 2; + glyphs->x[3] = 3; + glyphs->y[0] = 0; + glyphs->y[1] = 0; + glyphs->y[2] = 0; + glyphs->y[3] = 0; + glyphs->tile[0] = 'e'; + glyphs->tile[1] = 'x'; + glyphs->tile[2] = 'p'; + glyphs->tile[3] = '^'; + column->unmined_glyphs.push_back(glyphs); } - } + return true; + }); // Update global z level flags df::z_level_flags *flags = new df::z_level_flags[z_count_block + howMany]; @@ -258,7 +251,7 @@ command_result infiniteSky(color_ostream &out, opts.help) return CR_WRONG_USAGE; - if (opts.n != 0) { + if (opts.n > 0) { out.print("Infinite-sky: creating %d new z-level%s of sky.\n", opts.n, opts.n == 1 ? "" : "s"); doInfiniteSky(out, opts.n); diff --git a/plugins/lua/infinite-sky.lua b/plugins/lua/infinite-sky.lua index 0e8c7cff1d..ae7ee9531c 100644 --- a/plugins/lua/infinite-sky.lua +++ b/plugins/lua/infinite-sky.lua @@ -2,26 +2,17 @@ local _ENV = mkmodule('plugins.infinite-sky') local argparse = require('argparse') -local function process_args(opts, args) - if args[1] == 'help' then +function parse_commandline(opts, args) + local positionals = argparse.processArgsGetopt(args, { + {'h', 'help', handler=function() opts.help = true end}, + }) + if opts.help or positionals[1] == 'help' then opts.help = true return end - - if args[1] ~= nil then - opts.n = argparse.positiveInt(args[1]) - return + if positionals[1] then + opts.n = argparse.positiveInt(positionals[1]) end - - return argparse.processArgsGetopt(args, { - {'h', 'help', handler=function() opts.help = true end}, - }) -end - -function parse_commandline(opts, args) - local positionals = process_args(opts, args) - - if opts.help then return end end return _ENV