From 1f970f43521810a344c977c08e68e9dd2cc380aa Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 3 Jan 2025 05:21:26 -0800 Subject: [PATCH] convert rename.cpp into an example for how to do rpc --- docs/about/Removed.rst | 6 + docs/plugins/rename.rst | 33 -- plugins/CMakeLists.txt | 38 +- plugins/examples/rpc_example.cpp | 68 +++ plugins/lua/rename.lua | 13 - plugins/proto/{rename.proto => example.proto} | 11 +- plugins/rename.cpp | 408 ------------------ 7 files changed, 82 insertions(+), 495 deletions(-) delete mode 100644 docs/plugins/rename.rst create mode 100644 plugins/examples/rpc_example.cpp delete mode 100644 plugins/lua/rename.lua rename plugins/proto/{rename.proto => example.proto} (66%) delete mode 100644 plugins/rename.cpp diff --git a/docs/about/Removed.rst b/docs/about/Removed.rst index cfbb42ece2..5f73b86be3 100644 --- a/docs/about/Removed.rst +++ b/docs/about/Removed.rst @@ -314,6 +314,12 @@ plants ====== Renamed to `plant`. +.. _rename: + +rename +====== +Superseded by vanilla rename capabilities and `gui/rename`. + .. _resume: resume diff --git a/docs/plugins/rename.rst b/docs/plugins/rename.rst deleted file mode 100644 index a002fc4e4b..0000000000 --- a/docs/plugins/rename.rst +++ /dev/null @@ -1,33 +0,0 @@ -rename -====== - -.. dfhack-tool:: - :summary: Easily rename things. - :tags: unavailable - -Use `gui/rename` for an in-game interface. - -Usage ------ - -``rename squad ""`` - Rename the indicated squad. The ordinal is the number that corresponds to - the list of squads in the squads menu (:kbd:`s`). The first squad is ordinal - ``1``. -``rename hotkey ""`` - Rename the indicated hotkey. The ordinal the the number that corresponds to - the list of hotkeys in the hotkeys menu (:kbd:`H`). The first hotkey is - ordinal ``1``. -``rename unit ""`` - Give the selected unit the given nickname. -``rename unit-profession ""`` - Give the selected unit the given profession name. -``rename building ""`` - Set a custom name to the selected building. The building must be a - stockpile, workshop, furnace, trap, siege engine, or activity zone. - -Example -------- - -``rename squad 1 "The Whiz Bonkers"`` - Rename the first squad to The Whiz Bonkers. diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index bb1b140aea..ff71159e5e 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -22,45 +22,16 @@ if(INSTALL_DATA_FILES) FILES_MATCHING PATTERN "*.diff") endif() -# Protobuf -file(GLOB PROJECT_PROTOS ${CMAKE_CURRENT_SOURCE_DIR}/proto/*.proto) - -string(REPLACE ".proto" ".pb.cc" PROJECT_PROTO_SRCS "${PROJECT_PROTOS}") -string(REPLACE ".proto" ".pb.h" PROJECT_PROTO_HDRS "${PROJECT_PROTOS}") -string(REPLACE "/proto/" "/proto/tmp/" PROJECT_PROTO_TMP_FILES "${PROJECT_PROTO_SRCS};${PROJECT_PROTO_HDRS}") -set_source_files_properties(${PROJECT_PROTO_SRCS} ${PROJECT_PROTO_HDRS} - PROPERTIES GENERATED TRUE) - -# Force a re-gen if any *.pb.* files are missing -# (only runs when cmake is run, but better than nothing) -foreach(file IN LISTS PROJECT_PROTO_SRCS PROJECT_PROTO_HDRS) - if(NOT EXISTS ${file}) - # message("Resetting generate_proto because '${file}' is missing") - file(REMOVE ${PROJECT_PROTO_TMP_FILES}) - break() - endif() -endforeach() - -add_custom_command( - OUTPUT ${PROJECT_PROTO_TMP_FILES} - COMMAND protoc-bin -I=${dfhack_SOURCE_DIR}/library/proto/ - -I=${CMAKE_CURRENT_SOURCE_DIR}/proto/ - --cpp_out=${CMAKE_CURRENT_SOURCE_DIR}/proto/tmp/ - ${PROJECT_PROTOS} - COMMAND ${PERL_EXECUTABLE} ${dfhack_SOURCE_DIR}/depends/copy-if-different.pl - ${PROJECT_PROTO_TMP_FILES} - ${CMAKE_CURRENT_SOURCE_DIR}/proto/ - COMMENT "Generating plugin protobufs" - DEPENDS protoc-bin ${PROJECT_PROTOS} -) -add_custom_target(generate_proto DEPENDS ${PROJECT_PROTO_TMP_FILES}) - set_source_files_properties( Brushes.h PROPERTIES HEADER_FILE_ONLY TRUE ) # Plugins # If you are adding a plugin that you do not intend to commit to the DFHack repo, # see instructions for adding "external" plugins at the end of this file. +# Example plugin that uses protobufs +# proto file must be in the proto/ folder +# dfhack_plugin(rename rename.cpp LINK_LIBRARIES lua PROTOBUFS rename) + option(BUILD_SUPPORTED "Build the supported plugins (reveal, probe, etc.)." ON) if(BUILD_SUPPORTED) dfhack_plugin(3dveins 3dveins.cpp) @@ -133,7 +104,6 @@ if(BUILD_SUPPORTED) #dfhack_plugin(power-meter power-meter.cpp LINK_LIBRARIES lua) dfhack_plugin(regrass regrass.cpp LINK_LIBRARIES lua) add_subdirectory(remotefortressreader) - #dfhack_plugin(rename rename.cpp LINK_LIBRARIES lua PROTOBUFS rename) #add_subdirectory(rendermax) dfhack_plugin(reveal reveal.cpp LINK_LIBRARIES lua) dfhack_plugin(seedwatch seedwatch.cpp LINK_LIBRARIES lua) diff --git a/plugins/examples/rpc_example.cpp b/plugins/examples/rpc_example.cpp new file mode 100644 index 0000000000..0f9793b5e7 --- /dev/null +++ b/plugins/examples/rpc_example.cpp @@ -0,0 +1,68 @@ +#include "PluginManager.h" + +#include "RemoteServer.h" +#include "example.pb.h" // see plugins/proto/example.proto + +using std::vector; +using std::string; + +using namespace DFHack; +using namespace dfproto; + +DFHACK_PLUGIN("example_rpc"); + +DFhackCExport command_result plugin_init (color_ostream &out, std::vector &commands) { + return CR_OK; +} + +DFhackCExport command_result plugin_shutdown (color_ostream &out) { + return CR_OK; +} + +static command_result RenameSquad(color_ostream &stream, const RenameSquadIn *in) { + df::squad *squad = df::squad::find(in->squad_id()); + if (!squad) + return CR_NOT_FOUND; + + if (in->has_nickname()) + Translation::setNickname(&squad->name, UTF2DF(in->nickname())); + if (in->has_alias()) + squad->alias = UTF2DF(in->alias()); + + return CR_OK; +} + +static command_result RenameUnit(color_ostream &stream, const RenameUnitIn *in) { + df::unit *unit = df::unit::find(in->unit_id()); + if (!unit) + return CR_NOT_FOUND; + + if (in->has_nickname()) + Units::setNickname(unit, UTF2DF(in->nickname())); + if (in->has_profession()) + unit->custom_profession = UTF2DF(in->profession()); + + return CR_OK; +} + +static command_result RenameBuilding(color_ostream &stream, const RenameBuildingIn *in) { + auto building = df::building::find(in->building_id()); + if (!building) + return CR_NOT_FOUND; + + if (in->has_name()) + { + if (!renameBuilding(building, in->name())) + return CR_FAILURE; + } + + return CR_OK; +} + +DFhackCExport RPCService *plugin_rpcconnect(color_ostream &out) { + RPCService *svc = new RPCService(); + svc->addFunction("RenameSquad", RenameSquad); + svc->addFunction("RenameUnit", RenameUnit); + svc->addFunction("RenameBuilding", RenameBuilding); + return svc; +} diff --git a/plugins/lua/rename.lua b/plugins/lua/rename.lua deleted file mode 100644 index 82ed76b27d..0000000000 --- a/plugins/lua/rename.lua +++ /dev/null @@ -1,13 +0,0 @@ -local _ENV = mkmodule('plugins.rename') - ---[[ - - Native functions: - - * canRenameBuilding(building) - * isRenamingBuilding(building) - * renameBuilding(building, name) - ---]] - -return _ENV diff --git a/plugins/proto/rename.proto b/plugins/proto/example.proto similarity index 66% rename from plugins/proto/rename.proto rename to plugins/proto/example.proto index ef3f574239..d3f8318765 100644 --- a/plugins/proto/rename.proto +++ b/plugins/proto/example.proto @@ -4,27 +4,24 @@ package dfproto; option optimize_for = LITE_RUNTIME; -// DISABLED Plugin: rename +// Plugin: mypluginname -// DISABLED RPC RenameSquad : RenameSquadIn -> EmptyMessage +// RPC RenameSquad : RenameSquadIn -> EmptyMessage message RenameSquadIn { required int32 squad_id = 1; - optional string nickname = 2; optional string alias = 3; } -// DISABLED RPC RenameUnit : RenameUnitIn -> EmptyMessage +// RPC RenameUnit : RenameUnitIn -> EmptyMessage message RenameUnitIn { required int32 unit_id = 1; - optional string nickname = 2; optional string profession = 3; } -// DISABLED RPC RenameBuilding : RenameBuildingIn -> EmptyMessage +// RPC RenameBuilding : RenameBuildingIn -> EmptyMessage message RenameBuildingIn { required int32 building_id = 1; - optional string name = 2; } diff --git a/plugins/rename.cpp b/plugins/rename.cpp deleted file mode 100644 index 39bcff2eb6..0000000000 --- a/plugins/rename.cpp +++ /dev/null @@ -1,408 +0,0 @@ -#include "Console.h" -#include "Export.h" -#include "PluginManager.h" - -#include -#include - -#include "modules/Gui.h" -#include "modules/Translation.h" -#include "modules/Units.h" -#include "modules/World.h" -#include "modules/Screen.h" - -#include -#include "df/plotinfost.h" -#include "df/gamest.h" -#include "df/world.h" -#include "df/squad.h" -#include "df/unit.h" -#include "df/unit_soul.h" -#include "df/historical_entity.h" -#include "df/historical_figure.h" -#include "df/historical_figure_info.h" -#include "df/identity.h" -#include "df/language_name.h" -#include "df/building_stockpilest.h" -#include "df/building_workshopst.h" -#include "df/building_furnacest.h" -#include "df/building_trapst.h" -#include "df/building_siegeenginest.h" -#include "df/building_civzonest.h" -#include "df/viewscreen_dwarfmodest.h" - -#include "RemoteServer.h" -#include "rename.pb.h" - -#include "MiscUtils.h" - -#include - -using std::vector; -using std::string; -using std::endl; -using namespace DFHack; -using namespace df::enums; -using namespace dfproto; - -DFHACK_PLUGIN("rename"); -DFHACK_PLUGIN_IS_ENABLED(is_enabled); - -REQUIRE_GLOBAL(plotinfo); -REQUIRE_GLOBAL(game); -REQUIRE_GLOBAL(world); - -DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event); - -static command_result rename(color_ostream &out, vector & parameters); - -DFhackCExport command_result plugin_init (color_ostream &out, std::vector &commands) -{ - if (world && plotinfo) { - commands.push_back(PluginCommand( - "rename", - "Easily rename things.", - rename)); - - if (Core::getInstance().isWorldLoaded()) - plugin_onstatechange(out, SC_WORLD_LOADED); - } - - return CR_OK; -} - -static void init_buildings(bool enable); - -DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event) -{ - switch (event) { - case SC_WORLD_LOADED: - init_buildings(true); - break; - case SC_WORLD_UNLOADED: - init_buildings(false); - break; - default: - break; - } - - return CR_OK; -} - -DFhackCExport command_result plugin_shutdown ( color_ostream &out ) -{ - return CR_OK; -} - -/* - * Building renaming - it needs some per-type hacking. - */ - -#define KNOWN_BUILDINGS \ - BUILDING('p', building_stockpilest, "Stockpile") \ - BUILDING('w', building_workshopst, NULL) \ - BUILDING('e', building_furnacest, NULL) \ - BUILDING('T', building_trapst, NULL) \ - BUILDING('i', building_siegeenginest, NULL) \ - BUILDING('Z', building_civzonest, "Zone") - -#define BUILDING(code, cname, tag) \ - struct cname##_hook : df::cname { \ - typedef df::cname interpose_base; \ - DEFINE_VMETHOD_INTERPOSE(void, getName, (std::string *buf)) { \ - if (!name.empty()) {\ - buf->clear(); \ - *buf += name; \ - *buf += " ("; \ - if (tag) *buf += (const char*)tag; \ - else { std::string tmp; INTERPOSE_NEXT(getName)(&tmp); *buf += tmp; } \ - *buf += ")"; \ - return; \ - } \ - else \ - INTERPOSE_NEXT(getName)(buf); \ - } \ - }; \ - IMPLEMENT_VMETHOD_INTERPOSE_PRIO(cname##_hook, getName, 100); -KNOWN_BUILDINGS -#undef BUILDING - -struct dwarf_render_zone_hook : df::viewscreen_dwarfmodest { - typedef df::viewscreen_dwarfmodest interpose_base; - - DEFINE_VMETHOD_INTERPOSE(void, render, ()) - { - INTERPOSE_NEXT(render)(); - - if (plotinfo->main.mode == ui_sidebar_mode::Zones && - game && game->zone.selected && - !game->zone.selected->name.empty()) - { - auto dims = Gui::getDwarfmodeViewDims(); - int width = dims.menu_x2 - dims.menu_x1 - 1; - - Screen::Pen pen(' ',COLOR_WHITE); - Screen::fillRect(pen, dims.menu_x1, dims.y1+1, dims.menu_x2, dims.y1+1); - - std::string name; - game->zone.selected->getName(&name); - Screen::paintString(pen, dims.menu_x1+1, dims.y1+1, name.substr(0, width)); - } - } -}; - -IMPLEMENT_VMETHOD_INTERPOSE(dwarf_render_zone_hook, render); - -static char getBuildingCode(df::building *bld) -{ - CHECK_NULL_POINTER(bld); - -#define BUILDING(code, cname, tag) \ - if (strict_virtual_cast(bld)) return code; -KNOWN_BUILDINGS -#undef BUILDING - - return 0; -} - -static bool enable_building_rename(char code, bool enable) -{ - if (enable) - is_enabled = true; - - if (code == 'Z') - INTERPOSE_HOOK(dwarf_render_zone_hook, render).apply(enable); - - switch (code) { -#define BUILDING(code, cname, tag) \ - case code: return INTERPOSE_HOOK(cname##_hook, getName).apply(enable); -KNOWN_BUILDINGS -#undef BUILDING - default: - return false; - } -} - -static void disable_building_rename() -{ - is_enabled = false; - INTERPOSE_HOOK(dwarf_render_zone_hook, render).remove(); - -#define BUILDING(code, cname, tag) \ - INTERPOSE_HOOK(cname##_hook, getName).remove(); -KNOWN_BUILDINGS -#undef BUILDING -} - -static bool is_enabled_building(char code) -{ - switch (code) { -#define BUILDING(code, cname, tag) \ - case code: return INTERPOSE_HOOK(cname##_hook, getName).is_applied(); -KNOWN_BUILDINGS -#undef BUILDING - default: - return false; - } -} - -static void init_buildings(bool enable) -{ - disable_building_rename(); - - if (enable) - { - auto entry = World::GetPersistentData("rename/building_types"); - - if (entry.isValid()) - { - std::string val = entry.val(); - for (size_t i = 0; i < val.size(); i++) - enable_building_rename(val[i], true); - } - } -} - -static bool canRenameBuilding(df::building *bld) -{ - return getBuildingCode(bld) != 0; -} - -static bool isRenamingBuilding(df::building *bld) -{ - return is_enabled_building(getBuildingCode(bld)); -} - -static bool renameBuilding(df::building *bld, std::string name) -{ - char code = getBuildingCode(bld); - if (code == 0 && !name.empty()) - return false; - - if (!name.empty() && !is_enabled_building(code)) - { - auto entry = World::GetPersistentData("rename/building_types", NULL); - if (!entry.isValid()) - return false; - - if (!enable_building_rename(code, true)) - return false; - - entry.val().push_back(code); - } - - bld->name = name; - return true; -} - -static df::squad *getSquadByIndex(unsigned idx) -{ - auto entity = df::historical_entity::find(plotinfo->group_id); - if (!entity) - return NULL; - - if (idx >= entity->squads.size()) - return NULL; - - return df::squad::find(entity->squads[idx]); -} - -static command_result RenameSquad(color_ostream &stream, const RenameSquadIn *in) -{ - df::squad *squad = df::squad::find(in->squad_id()); - if (!squad) - return CR_NOT_FOUND; - - if (in->has_nickname()) - Translation::setNickname(&squad->name, UTF2DF(in->nickname())); - if (in->has_alias()) - squad->alias = UTF2DF(in->alias()); - - return CR_OK; -} - -static command_result RenameUnit(color_ostream &stream, const RenameUnitIn *in) -{ - df::unit *unit = df::unit::find(in->unit_id()); - if (!unit) - return CR_NOT_FOUND; - - if (in->has_nickname()) - Units::setNickname(unit, UTF2DF(in->nickname())); - if (in->has_profession()) - unit->custom_profession = UTF2DF(in->profession()); - - return CR_OK; -} - -static command_result RenameBuilding(color_ostream &stream, const RenameBuildingIn *in) -{ - auto building = df::building::find(in->building_id()); - if (!building) - return CR_NOT_FOUND; - - if (in->has_name()) - { - if (!renameBuilding(building, in->name())) - return CR_FAILURE; - } - - return CR_OK; -} - -DFhackCExport RPCService *plugin_rpcconnect(color_ostream &) -{ - RPCService *svc = new RPCService(); - svc->addFunction("RenameSquad", RenameSquad); - svc->addFunction("RenameUnit", RenameUnit); - svc->addFunction("RenameBuilding", RenameBuilding); - return svc; -} - -DFHACK_PLUGIN_LUA_FUNCTIONS { - DFHACK_LUA_FUNCTION(canRenameBuilding), - DFHACK_LUA_FUNCTION(isRenamingBuilding), - DFHACK_LUA_FUNCTION(renameBuilding), - DFHACK_LUA_END -}; - -static command_result rename(color_ostream &out, vector ¶meters) -{ - string cmd; - if (!parameters.empty()) - cmd = parameters[0]; - - if (cmd == "squad") - { - if (parameters.size() != 3) - return CR_WRONG_USAGE; - - int id = atoi(parameters[1].c_str()); - df::squad *squad = getSquadByIndex(id-1); - - if (!squad) { - out.printerr("Couldn't find squad with index %d.\n", id); - return CR_WRONG_USAGE; - } - - squad->alias = parameters[2]; - } - else if (cmd == "hotkey") - { - if (parameters.size() != 3) - return CR_WRONG_USAGE; - - int id = atoi(parameters[1].c_str()); - if (id < 1 || id > 16) { - out.printerr("Invalid hotkey index\n"); - return CR_WRONG_USAGE; - } - - plotinfo->main.hotkeys[id-1].name = parameters[2]; - } - else if (cmd == "unit") - { - if (parameters.size() != 2) - return CR_WRONG_USAGE; - - df::unit *unit = Gui::getSelectedUnit(out, true); - if (!unit) - return CR_WRONG_USAGE; - - Units::setNickname(unit, parameters[1]); - } - else if (cmd == "unit-profession") - { - if (parameters.size() != 2) - return CR_WRONG_USAGE; - - df::unit *unit = Gui::getSelectedUnit(out, true); - if (!unit) - return CR_WRONG_USAGE; - - unit->custom_profession = parameters[1]; - } - else if (cmd == "building") - { - if (parameters.size() != 2) - return CR_WRONG_USAGE; - - df::building *bld = Gui::getSelectedBuilding(out, true); - if (!bld) - return CR_WRONG_USAGE; - - if (!renameBuilding(bld, parameters[1])) - { - out.printerr("This type of building is not supported.\n"); - return CR_FAILURE; - } - } - else - { - if (!parameters.empty() && cmd != "?") - out.printerr("Invalid command: %s\n", cmd.c_str()); - return CR_WRONG_USAGE; - } - - return CR_OK; -}