From e37b12264a7470f7cc56e6a6b9481138e04525b5 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 1 Sep 2026 02:22:51 -0500 Subject: [PATCH 1/2] provide `Coord2d` and `Coord3d` templates --- docs/changelog.txt | 1 + library/CMakeLists.txt | 3 +- library/include/Coord.h | 206 ++++++++++++++++++++++++++++++++++++++++ plugins/Plugins.cmake | 2 +- plugins/blueprint.cpp | 4 +- plugins/dig-now.cpp | 10 +- plugins/tiletypes.cpp | 7 +- 7 files changed, 221 insertions(+), 12 deletions(-) create mode 100644 library/include/Coord.h diff --git a/docs/changelog.txt b/docs/changelog.txt index e07a76a521..ced2abdf32 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -62,6 +62,7 @@ Template for new versions: ## Fixes ## Misc Improvements +- Added `Coord2d` and `Coord3d` C++ templates, providing a standard set operations for 2-tuples and 3-tuples of any numeric type ## Documentation diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index d87e20531e..48db051e74 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -50,6 +50,7 @@ set(MAIN_HEADERS include/ColorText.h include/Commands.h include/Console.h + include/Coord.h include/Core.h include/CoreDefs.h include/DataDefs.h @@ -394,7 +395,7 @@ else() endif() add_library(dfhooks_dfhack SHARED Hooks.cpp) -target_link_libraries(dfhooks_dfhack PUBLIC dfhack ${FMTLIB}) +target_link_libraries(dfhooks_dfhack PUBLIC dfhack lua ${FMTLIB}) # effectively disables debug builds... set_target_properties(dfhack PROPERTIES DEBUG_POSTFIX "-debug" ) diff --git a/library/include/Coord.h b/library/include/Coord.h new file mode 100644 index 0000000000..3a472343a6 --- /dev/null +++ b/library/include/Coord.h @@ -0,0 +1,206 @@ +#pragma once + +#include +#include +#include + +#include "DataDefs.h" +#include "DataFuncs.h" +#include "Export.h" + +namespace DFHack +{ + template + constexpr T coord_default_initializer = static_cast(-30000); + + template + constexpr T coord_default_initializer = static_cast(std::numeric_limits::infinity()); + + template > + struct Coord2d + { + T x; T y; + + Coord2d() : x(initializer), y(initializer) {} + Coord2d(T x, T y) : x(x), y(y) {} + + bool isValid() const { return x >= 0; } + + void clear() + { + x = y = initializer; + } + + bool operator==(const Coord2d& other) const + { + return x == other.x && y == other.y; + } + bool operator!=(const Coord2d& other) const + { + return x != other.x || y == other.y; + } + bool operator<(const Coord2d& other) const + { + return x < other.x || (x == other.x && y < other.y); + } + + Coord2d operator+(const Coord2d& other) const + { + return {T(x + other.x), T(y + other.y)}; + } + Coord2d operator-(const Coord2d& other) const + { + return {T(x - other.x), T(y - other.y)}; + } + Coord2d operator/(T number) const + { + return {T(x / number), T(y / number)}; + } + Coord2d operator*(T number) const + { + return {T(x * number), T(y * number)}; + } + Coord2d operator%(T number) const requires std::integral + { + return {T(x % number), T(y % number)}; + } + Coord2d operator&(T number) const requires std::integral + { + return {T(x & number), T(y & number)}; + } + + std::size_t operator()() const + { + size_t r = 17; + const size_t m = 65537; + r = m * (r + x); + r = m * (r + y); + return r; + } + }; + + template , typename U = DFHack::Coord2d> + static const struct_field_info coord2d_fields[] = { + { struct_field_info::PRIMITIVE, "x", offsetof(U, x), &df::identity_traits::identity, 0, 0 }, + { struct_field_info::PRIMITIVE, "y", offsetof(U, y), &df::identity_traits::identity, 0, 0 }, + { struct_field_info::OBJ_METHOD, "isValid", 0, df::wrap_function(&U::isValid), 0, 0 }, + { struct_field_info::OBJ_METHOD, "clear", 0, df::wrap_function(&U::clear), 0, 0 } , + { struct_field_info::END } + }; + + template , typename U = DFHack::Coord2d> + static inline const struct_identity coord2d_identity{sizeof(U), &df::allocator_fn, nullptr, "coord", nullptr, coord2d_fields}; + + template > + struct Coord3d + { + T x; T y; T z; + + Coord3d() : x(initializer), y(initializer), z(initializer) {} + Coord3d(Coord2d c, T z) : x(c.x), y(c.y), z(z) {} + Coord3d(T x, T y, T z) : x(x), y(y), z(z) {} + + operator Coord2d() const + { + return {x,y}; + } + + bool isValid() const { return x >= 0; } + + void clear() + { + x = y = z = initializer; + } + + bool operator==(const Coord3d& other) const + { + return x == other.x && y == other.y && z == other.z; + } + bool operator!=(const Coord3d& other) const + { + return x != other.x || y == other.y || z == other.z; + } + bool operator<(const Coord3d& other) const + { + return x < other.x || (x == other.x && (y < other.y || (y == other.y && z < other.z))); + } + + Coord3d operator+(const Coord3d& other) const + { + return {T(x + other.x), T(y + other.y), T(z + other.z)}; + } + Coord3d operator-(const Coord3d& other) const + { + return {T(x - other.x), T(y - other.y), T(z - other.z)}; + } + Coord3d operator/(T number) const + { + return {T(x / number), T(y / number), T(z / number)}; + } + Coord3d operator*(T number) const + { + return {T(x * number), T(y * number), T(z * number)}; + } + Coord3d operator%(T number) const requires std::integral + { + return {T(x % number), T(y % number), T(z % number)}; + } + Coord3d operator&(T number) const requires std::integral + { + return {T(x & number), T(y & number), T(z & number)}; + } + + std::size_t operator()() const + { + size_t r = 17; + const size_t m = 65537; + r = m * (r + x); + r = m * (r + y); + r = m * (r + z); + return r; + } + + // special weirdness used by the dig plugin + + Coord3d operator-(T number) const + { + return Coord3d(x, y, z - number); + } + Coord3d operator+(T number) const + { + return Coord3d(x, y, z + number); + } + }; + + template , typename U = DFHack::Coord3d> + static const struct_field_info coord3d_fields[] = { + { struct_field_info::PRIMITIVE, "x", offsetof(U, x), &df::identity_traits::identity, 0, 0 }, + { struct_field_info::PRIMITIVE, "y", offsetof(U, y), &df::identity_traits::identity, 0, 0 }, + { struct_field_info::PRIMITIVE, "z", offsetof(U, y), &df::identity_traits::identity, 0, 0 }, + { struct_field_info::OBJ_METHOD, "isValid", 0, df::wrap_function(&U::isValid), 0, 0 }, + { struct_field_info::OBJ_METHOD, "clear", 0, df::wrap_function(&U::clear), 0, 0 } , + { struct_field_info::END } + }; + + template , typename U = DFHack::Coord3d> + static inline const struct_identity coord3d_identity{sizeof(U), &df::allocator_fn, nullptr, "coord", nullptr, coord3d_fields}; +} + +namespace df +{ + template + struct DFHACK_EXPORT identity_traits> + { + static const bool is_primitive = false; + static const compound_identity* get() { return &DFHack::coord2d_identity; } + }; + + template + struct DFHACK_EXPORT identity_traits> + { + static const bool is_primitive = false; + static const compound_identity* get() { return &DFHack::coord3d_identity; + } + }; + +} diff --git a/plugins/Plugins.cmake b/plugins/Plugins.cmake index 192662bccc..7408e44031 100644 --- a/plugins/Plugins.cmake +++ b/plugins/Plugins.cmake @@ -124,7 +124,7 @@ macro(dfhack_plugin) target_include_directories(${PLUGIN_NAME} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/proto") target_link_libraries(${PLUGIN_NAME} protobuf-lite) endif() - target_link_libraries(${PLUGIN_NAME} dfhack dfhack-version ${FMTLIB} ${PLUGIN_LINK_LIBRARIES}) + target_link_libraries(${PLUGIN_NAME} dfhack dfhack-version lua ${FMTLIB} ${PLUGIN_LINK_LIBRARIES}) if(UNIX) set(PLUGIN_COMPILE_FLAGS "${PLUGIN_COMPILE_FLAGS} ${PLUGIN_COMPILE_FLAGS_GCC}") diff --git a/plugins/blueprint.cpp b/plugins/blueprint.cpp index 3f046bc142..d1b7a502b4 100644 --- a/plugins/blueprint.cpp +++ b/plugins/blueprint.cpp @@ -118,10 +118,10 @@ struct blueprint_options { }; static const struct_field_info blueprint_options_fields[] = { { struct_field_info::PRIMITIVE, "help", offsetof(blueprint_options, help), &df::identity_traits::identity, 0, 0 }, - { struct_field_info::SUBSTRUCT, "start", offsetof(blueprint_options, start), &df::coord::_identity, 0, 0 }, + { struct_field_info::SUBSTRUCT, "start", offsetof(blueprint_options, start), df::identity_traits::get(), 0, 0}, { struct_field_info::PRIMITIVE, "format", offsetof(blueprint_options, format), df::identity_traits::get(), 0, 0 }, { struct_field_info::PRIMITIVE, "nometa", offsetof(blueprint_options, nometa), &df::identity_traits::identity, 0, 0 }, - { struct_field_info::SUBSTRUCT, "playback_start", offsetof(blueprint_options, playback_start), &df::coord2d::_identity, 0, 0 }, + { struct_field_info::SUBSTRUCT, "playback_start", offsetof(blueprint_options, playback_start), df::identity_traits::get(),0, 0 }, { struct_field_info::PRIMITIVE, "playback_start_comment", offsetof(blueprint_options, playback_start_comment), df::identity_traits::get(), 0, 0 }, { struct_field_info::PRIMITIVE, "split_strategy", offsetof(blueprint_options, split_strategy), df::identity_traits::get(), 0, 0 }, { struct_field_info::PRIMITIVE, "width", offsetof(blueprint_options, width), &df::identity_traits::identity, 0, 0 }, diff --git a/plugins/dig-now.cpp b/plugins/dig-now.cpp index 259978f9bf..ec8e9aa53c 100644 --- a/plugins/dig-now.cpp +++ b/plugins/dig-now.cpp @@ -200,11 +200,11 @@ struct dig_now_options { static struct_identity _identity; }; static const struct_field_info dig_now_options_fields[] = { - { struct_field_info::PRIMITIVE, "help", offsetof(dig_now_options, help), &df::identity_traits::identity, 0, 0 }, - { struct_field_info::SUBSTRUCT, "start", offsetof(dig_now_options, start), &df::coord::_identity, 0, 0 }, - { struct_field_info::SUBSTRUCT, "end", offsetof(dig_now_options, end), &df::coord::_identity, 0, 0 }, - { struct_field_info::SUBSTRUCT, "boulder_percents", offsetof(dig_now_options, boulder_percents), &boulder_percent_options::_identity, 0, 0 }, - { struct_field_info::SUBSTRUCT, "dump_pos", offsetof(dig_now_options, dump_pos), &df::coord::_identity, 0, 0 }, + { struct_field_info::PRIMITIVE, "help", offsetof(dig_now_options, help), &df::identity_traits::identity, 0, 0 }, + { struct_field_info::SUBSTRUCT, "start", offsetof(dig_now_options, start), df::identity_traits::get(), 0, 0 }, + { struct_field_info::SUBSTRUCT, "end", offsetof(dig_now_options, end), df::identity_traits::get(), 0, 0 }, + { struct_field_info::SUBSTRUCT, "boulder_percents", offsetof(dig_now_options, boulder_percents), &boulder_percent_options::_identity, 0, 0 }, + { struct_field_info::SUBSTRUCT, "dump_pos", offsetof(dig_now_options, dump_pos), df::identity_traits::get(), 0, 0 }, { struct_field_info::END } }; struct_identity dig_now_options::_identity(sizeof(dig_now_options), &df::allocator_fn, NULL, "dig_now_options", NULL, dig_now_options_fields); diff --git a/plugins/tiletypes.cpp b/plugins/tiletypes.cpp index dc93bea4bb..16f01fd421 100644 --- a/plugins/tiletypes.cpp +++ b/plugins/tiletypes.cpp @@ -45,6 +45,7 @@ using std::set; #include "modules/MapCache.h" #include "modules/Maps.h" +#include "df/coord2d.h" #include "df/tile_dig_designation.h" #include "df/world.h" @@ -68,9 +69,9 @@ struct tiletypes_options { static struct_identity _identity; }; static const struct_field_info tiletypes_options_fields[] = { - { struct_field_info::PRIMITIVE, "help", offsetof(tiletypes_options, help), &df::identity_traits::identity, 0, 0 }, - { struct_field_info::PRIMITIVE, "quiet", offsetof(tiletypes_options, quiet), &df::identity_traits::identity, 0, 0 }, - { struct_field_info::SUBSTRUCT, "cursor", offsetof(tiletypes_options, cursor), &df::coord::_identity, 0, 0 }, + { struct_field_info::PRIMITIVE, "help", offsetof(tiletypes_options, help), &df::identity_traits::identity, 0, 0 }, + { struct_field_info::PRIMITIVE, "quiet", offsetof(tiletypes_options, quiet), &df::identity_traits::identity, 0, 0 }, + { struct_field_info::SUBSTRUCT, "cursor", offsetof(tiletypes_options, cursor), df::identity_traits::get(), 0, 0}, { struct_field_info::END } }; struct_identity tiletypes_options::_identity(sizeof(tiletypes_options), &df::allocator_fn, NULL, "tiletypes_options", NULL, tiletypes_options_fields); From a79285bda54c0a7f12fa1786594b224d0f81dd3c Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 1 Sep 2026 09:06:03 -0500 Subject: [PATCH 2/2] revise changelog --- docs/changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index ced2abdf32..c37aa38ae2 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -62,7 +62,7 @@ Template for new versions: ## Fixes ## Misc Improvements -- Added `Coord2d` and `Coord3d` C++ templates, providing a standard set operations for 2-tuples and 3-tuples of any numeric type +- Added ``Coord2d`` and ``Coord3d`` C++ templates, providing a standard set operations for 2-tuples and 3-tuples of any numeric type ## Documentation