From d1170d54c3f008d4845d8748def5d2eb10e12180 Mon Sep 17 00:00:00 2001 From: Matthew Cline Date: Tue, 12 Jul 2011 23:17:51 -0700 Subject: [PATCH 1/3] Vermin module and colonies plugin This is the start of the vermin module. Right now it just gets a list of the positions at which vermin are created (spawn points). Most spawn points are invisible and transient, but colonies (ant hills and such) are permanent and visible. The address of the spawn points vector is only provided for Linux 0.31.25 The colonies plugin uses the vermin module to list the location and species of colonies, and can either wipe them all out or turn them all into honey bee colonies. --- Memory.xml | 22 +++ library/CMakeLists.txt | 1 + library/Core.cpp | 3 +- library/include/dfhack/Core.h | 6 +- library/include/dfhack/modules/Vermin.h | 86 +++++++++++ library/modules/Vermin.cpp | 191 ++++++++++++++++++++++++ library/private/ModuleFactory.h | 3 +- plugins/CMakeLists.txt | 1 + plugins/colonies.cpp | 163 ++++++++++++++++++++ 9 files changed, 473 insertions(+), 3 deletions(-) create mode 100644 library/include/dfhack/modules/Vermin.h create mode 100644 library/modules/Vermin.cpp create mode 100644 plugins/colonies.cpp diff --git a/Memory.xml b/Memory.xml index a41125537..f651c07df 100644 --- a/Memory.xml +++ b/Memory.xml @@ -990,6 +990,17 @@ + + +
+ + + + + + to what??? + +
@@ -3029,6 +3040,17 @@ + + +
+ + + + + + + +
diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 25e4bb2ab..c378115d1 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -75,6 +75,7 @@ modules/Maps.cpp modules/Materials.cpp modules/Translation.cpp modules/Vegetation.cpp +modules/Vermin.cpp modules/World.cpp ) diff --git a/library/Core.cpp b/library/Core.cpp index ea8d26084..ec1ae20b9 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -443,4 +443,5 @@ MODULE_GETTER(Items); MODULE_GETTER(Translation); MODULE_GETTER(Vegetation); MODULE_GETTER(Buildings); -MODULE_GETTER(Constructions); \ No newline at end of file +MODULE_GETTER(Constructions); +MODULE_GETTER(Vermin); diff --git a/library/include/dfhack/Core.h b/library/include/dfhack/Core.h index 1f9615d9e..a74a192fb 100644 --- a/library/include/dfhack/Core.h +++ b/library/include/dfhack/Core.h @@ -48,6 +48,7 @@ namespace DFHack class Vegetation; class Buildings; class Constructions; + class Vermin; class VersionInfo; class VersionInfoFactory; class Console; @@ -105,6 +106,8 @@ namespace DFHack Buildings * getBuildings(); /// get the constructions module Constructions * getConstructions(); + /// get the vermin module + Vermin * getVermin(); /// sets the current hotkey command bool setHotkeyCmd( std::string cmd ); /// removes the hotkey command and gives it to the caller thread @@ -144,6 +147,7 @@ namespace DFHack Vegetation * pVegetation; Buildings * pBuildings; Constructions * pConstructions; + Vermin * pVermin; } s_mods; std::vector allModules; DFHack::PluginManager * plug_mgr; @@ -156,4 +160,4 @@ namespace DFHack // Very important! bool started; }; -} \ No newline at end of file +} diff --git a/library/include/dfhack/modules/Vermin.h b/library/include/dfhack/modules/Vermin.h new file mode 100644 index 000000000..f5eaac583 --- /dev/null +++ b/library/include/dfhack/modules/Vermin.h @@ -0,0 +1,86 @@ +#pragma once +#ifndef CL_MOD_VERMIN +#define CL_MOD_VERMIN +/** + * \defgroup grp_vermin Wild vermin (ants, bees, etc) + * @ingroup grp_vermin + */ +#include "dfhack/Export.h" +#include "dfhack/Module.h" + +#ifdef __cplusplus +namespace DFHack +{ +#endif + /** + * Structure for holding a read DF vermin spawn point object + * \ingroup grp_vermin + */ + struct t_spawnPoint + { + uint32_t origin; + uint16_t race; + uint16_t type; + uint16_t x; + uint16_t y; + uint16_t z; + bool in_use; + uint8_t unknown; + uint32_t countdown; + }; + +#ifdef __cplusplus + class DFContextShared; + class SpawnPoints; + + /** + * The Vermin module - allows reading DF vermin + * \ingroup grp_modules + * \ingroup grp_vermin + */ + class DFHACK_EXPORT Vermin : public Module + { + public: + Vermin(); + ~Vermin(); + + bool Finish(); + + // NOTE: caller must call delete on result when done. + SpawnPoints* getSpawnPoints(); + + private: + struct Private; + Private *d; + + friend class SpawnPoints; + }; + + class DFHACK_EXPORT SpawnPoints + { + public: + static const uint16_t TYPE_WILD_COLONY = 0xFFFF; + + protected: + SpawnPoints(Vermin * v); + + public: + ~SpawnPoints(); + + size_t size(); + bool Read (const uint32_t index, t_spawnPoint & point); + bool Write (const uint32_t index, t_spawnPoint & point); + bool isValid(); + + static bool isWildColony(t_spawnPoint & point); + + private: + Vermin* v; + std::vector * p_sp; + + friend class Vermin; + }; +} +#endif // __cplusplus + +#endif diff --git a/library/modules/Vermin.cpp b/library/modules/Vermin.cpp new file mode 100644 index 000000000..67fd623e4 --- /dev/null +++ b/library/modules/Vermin.cpp @@ -0,0 +1,191 @@ +/* +www.sourceforge.net/projects/dfhack +Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#include "Internal.h" + +#include +#include +#include +using namespace std; + +#include "dfhack/VersionInfo.h" +#include "dfhack/Types.h" +#include "dfhack/Error.h" +#include "dfhack/Process.h" +#include "dfhack/modules/Vermin.h" +#include "ModuleFactory.h" +#include "dfhack/Core.h" +using namespace DFHack; + +struct Vermin::Private +{ + uint32_t spawn_points_vector; + uint32_t race_offset; + uint32_t type_offset; + uint32_t position_offset; + uint32_t in_use_offset; + uint32_t unknown_offset; + uint32_t countdown_offset; + Process * owner; + bool Inited; + bool Started; +}; + +Module* DFHack::createVermin() +{ + return new Vermin(); +} + +#include + +Vermin::Vermin() +{ + Core & c = Core::getInstance(); + + d = new Private; + d->owner = c.p; + d->Inited = d->Started = false; + VersionInfo * mem = c.vinfo; + OffsetGroup * OG_vermin = mem->getGroup("Vermin"); + OffsetGroup * OG_spawn = OG_vermin->getGroup("Spawn Points"); + d->Inited = true; + try + { + d->spawn_points_vector = OG_spawn->getAddress("vector"); + + d->race_offset = OG_spawn->getOffset("race"); + d->type_offset = OG_spawn->getOffset("type"); + d->position_offset = OG_spawn->getOffset("position"); + d->in_use_offset = OG_spawn->getOffset("in_use"); + d->unknown_offset = OG_spawn->getOffset("unknown"); + d->countdown_offset = OG_spawn->getOffset("countdown"); + } + catch(DFHack::Error::AllMemdef &e) + { + cerr << "Vermin not available... " << e.what() << endl; + d->Inited = false; + } +} + +bool Vermin::Finish() +{ + return true; +} + +Vermin::~Vermin() +{ + delete d; +} + +// NOTE: caller must call delete on result when done. +SpawnPoints* Vermin::getSpawnPoints() +{ + if (!d->Inited) + { + cerr << "Couldn't get spawn points: Vermin module not inited" << endl; + return NULL; + } + + return new SpawnPoints(this); +} + +SpawnPoints::SpawnPoints(Vermin* v_) +{ + v = v_; + p_sp = NULL; + + if (!v->d->Inited) + { + cerr << "Couldn't get spawn points: Vermin module not inited" << endl; + return; + } + + //p_sp = new DfVector (v->d->spawn_points_vector); + //p_sp = new vector (v->d->spawn_points_vector); + p_sp = (vector *) (v->d->spawn_points_vector); +} + +SpawnPoints::~SpawnPoints() +{ + // Do NOT delete p_sp; it's a pointer to memory the game owns. +} + +size_t SpawnPoints::size() +{ + if (!isValid()) + return 0; + + return p_sp->size(); +} + +bool SpawnPoints::Read (const uint32_t index, t_spawnPoint & sp) +{ + if(!isValid()) + return false; + + // read pointer from vector at position + uint32_t temp = (uint32_t) p_sp->at (index); + + sp.origin = temp; + sp.race = v->d->owner->readWord(temp + v->d->race_offset); + sp.type = v->d->owner->readWord(temp + v->d->type_offset); + sp.in_use = v->d->owner->readByte(temp + v->d->in_use_offset); + sp.unknown = v->d->owner->readByte(temp + v->d->unknown_offset); + sp.countdown = v->d->owner->readDWord(temp + v->d->countdown_offset); + + // Three consecutive 16 bit numbers for x/y/z + v->d->owner->read(temp + v->d->position_offset, 6, (uint8_t*) &sp.x); + + return true; +} + +bool SpawnPoints::Write (const uint32_t index, t_spawnPoint & sp) +{ + if(!isValid()) + return false; + + // read pointer from vector at position + uint32_t temp = (uint32_t) p_sp->at (index); + + v->d->owner->writeWord(temp + v->d->race_offset, sp.race); + v->d->owner->writeWord(temp + v->d->type_offset, sp.type); + v->d->owner->writeByte(temp + v->d->in_use_offset, sp.in_use); + v->d->owner->writeByte(temp + v->d->unknown_offset, sp.unknown); + v->d->owner->writeDWord(temp + v->d->countdown_offset, sp.countdown); + + // Three consecutive 16 bit numbers for x/y/z + v->d->owner->write(temp + v->d->position_offset, 6, (uint8_t*) &sp.x); + + return true; +} + +bool SpawnPoints::isWildColony(t_spawnPoint & point) +{ + return (point.type == TYPE_WILD_COLONY); +} + +bool SpawnPoints::isValid() +{ + return (v != NULL && v->d->Inited && p_sp != NULL); +} diff --git a/library/private/ModuleFactory.h b/library/private/ModuleFactory.h index f3ca601dc..cd1ef73a2 100644 --- a/library/private/ModuleFactory.h +++ b/library/private/ModuleFactory.h @@ -41,5 +41,6 @@ namespace DFHack Module* createBuildings(); Module* createConstructions(); Module* createMaps(); + Module* createVermin(); } -#endif \ No newline at end of file +#endif diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 25fb0471b..ff7daf24f 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -33,3 +33,4 @@ DFHACK_PLUGIN(prospector prospector.cpp) DFHACK_PLUGIN(cleanmap cleanmap.cpp) DFHACK_PLUGIN(weather weather.cpp) DFHACK_PLUGIN(vdig vdig.cpp) +DFHACK_PLUGIN(colonies colonies.cpp) diff --git a/plugins/colonies.cpp b/plugins/colonies.cpp new file mode 100644 index 000000000..e386d5270 --- /dev/null +++ b/plugins/colonies.cpp @@ -0,0 +1,163 @@ +#include +#include +#include +#include +#include +#include +#include + +using std::vector; +using std::string; +using namespace DFHack; +#include + +DFhackCExport command_result colonies (Core * c, vector & parameters); + +DFhackCExport const char * plugin_name ( void ) +{ + return "colonies"; +} + +DFhackCExport command_result plugin_init ( Core * c, std::vector &commands) +{ + commands.clear(); + commands.push_back(PluginCommand("colonies", + "List or change wild colonies (ants hills and such)\ +\n Options: 'kill' = destroy all colonies\ +\n 'bees' = change all colonies to honey bees", + colonies)); + return CR_OK; +} + +DFhackCExport command_result plugin_shutdown ( Core * c ) +{ + return CR_OK; +} + +void destroyColonies(DFHack::SpawnPoints *points); +void convertColonies(DFHack::SpawnPoints *points, DFHack::Materials *Materials); +void showColonies(DFHack::SpawnPoints *points, DFHack::Materials *Materials); + +DFhackCExport command_result colonies (Core * c, vector & parameters) +{ + bool destroy = false; + bool convert = false; + + for(int i = 0; i < parameters.size();i++) + { + if(parameters[i] == "kill") + destroy = true; + else if(parameters[i] == "bees") + convert = true; + } + + if (destroy && convert) + { + + dfout << "Kill or make bees? DECIDE!" << std::endl; + return CR_FAILURE; + } + + c->Suspend(); + + Vermin * vermin = c->getVermin(); + Materials * materials = c->getMaterials(); + + SpawnPoints *points = vermin->getSpawnPoints(); + + if(!points->isValid()) + { + std::cerr << "vermin not supported for this DF version" << std::endl; + return CR_FAILURE; + } + + materials->ReadCreatureTypesEx(); + + if (destroy) + destroyColonies(points); + else if (convert) + convertColonies(points, materials); + else + showColonies(points, materials); + + delete points; + + vermin->Finish(); + materials->Finish(); + + c->Resume(); + return CR_OK; +} + +void destroyColonies(DFHack::SpawnPoints *points) +{ + uint32_t numSpawnPoints = points->size(); + for (uint32_t i = 0; i < numSpawnPoints; i++) + { + DFHack::t_spawnPoint sp; + points->Read(i, sp); + + if (sp.in_use && DFHack::SpawnPoints::isWildColony(sp)) + { + sp.in_use = false; + points->Write(i, sp); + } + } +} + +// Convert all colonies to honey bees. +void convertColonies(DFHack::SpawnPoints *points, DFHack::Materials *Materials) +{ + int bee_idx = -1; + for (size_t i = 0; i < Materials->raceEx.size(); i++) + if (strcmp(Materials->raceEx[i].rawname, "HONEY_BEE") == 0) + { + bee_idx = i; + break; + } + + if (bee_idx == -1) + { + std::cerr << "Honey bees not present in game." << std::endl; + return; + } + + uint32_t numSpawnPoints = points->size(); + for (uint32_t i = 0; i < numSpawnPoints; i++) + { + DFHack::t_spawnPoint sp; + points->Read(i, sp); + + if (sp.in_use && DFHack::SpawnPoints::isWildColony(sp)) + { + sp.race = bee_idx; + points->Write(i, sp); + } + } +} + +void showColonies(DFHack::SpawnPoints *points, DFHack::Materials *Materials) +{ + uint32_t numSpawnPoints = points->size(); + int numColonies = 0; + for (uint32_t i = 0; i < numSpawnPoints; i++) + { + DFHack::t_spawnPoint sp; + + points->Read(i, sp); + + if (sp.in_use && DFHack::SpawnPoints::isWildColony(sp)) + { + numColonies++; + string race="(no race)"; + if (Materials->raceEx[sp.race].rawname[0]) + race = Materials->raceEx[sp.race].rawname; + + fprintf(dfout_C, "Spawn point %u: %s at %d:%d:%d\n", + i, race.c_str(), sp.x, sp.y, sp.z); + } + } + + if (numColonies == 0) + dfout << "No colonies present." << std::endl; +} From fed916bf8d774e0f1c678f18dc7e5e2cb8242162 Mon Sep 17 00:00:00 2001 From: Matthew Cline Date: Tue, 12 Jul 2011 23:37:49 -0700 Subject: [PATCH 2/3] Linux launch script: gdb and terminal reset 1) Giving "-g" or "--gdb" as the first argument to the dfhack script will launch DF under gdb. 2) "reset -I" is called after DF finishes, to return the terminal to a sane state in case DF crashed or was killed. --- package/linux/dfhack | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/package/linux/dfhack b/package/linux/dfhack index 8484a3e5e..35e9cfeb2 100755 --- a/package/linux/dfhack +++ b/package/linux/dfhack @@ -2,6 +2,8 @@ # NOTE: This is dfhack's modification of the normal invocation script, # changed to properly set LD_PRELOAD so as to run DFHACK. +# +# You can run DF under gdb by passing -g or --gdb as the first argument. DF_DIR=$(dirname "$0") cd "${DF_DIR}" @@ -10,4 +12,19 @@ export SDL_DISABLE_LOCK_KEYS=1 # Work around for bug in Debian/Ubuntu SDL patch. export LD_PRELOAD=./libdfhack.so -./libs/Dwarf_Fortress $* # Go, go, go! :) +case "$1" in + -g | --gdb) + shift + gdb ./libs/Dwarf_Fortress $* + ret=$? + ;; + *) + ./libs/Dwarf_Fortress $* + ret=$? + ;; +esac + +# Reset terminal to sane state in case of a crash +reset -I + +exit $ret From d7213da5a3644028a7808e534b99203707030f71 Mon Sep 17 00:00:00 2001 From: Matthew Cline Date: Wed, 13 Jul 2011 17:36:39 -0700 Subject: [PATCH 3/3] Fix colonies to use new console output stuff --- plugins/colonies.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/plugins/colonies.cpp b/plugins/colonies.cpp index e386d5270..bd5bfe839 100644 --- a/plugins/colonies.cpp +++ b/plugins/colonies.cpp @@ -36,7 +36,8 @@ DFhackCExport command_result plugin_shutdown ( Core * c ) void destroyColonies(DFHack::SpawnPoints *points); void convertColonies(DFHack::SpawnPoints *points, DFHack::Materials *Materials); -void showColonies(DFHack::SpawnPoints *points, DFHack::Materials *Materials); +void showColonies(Core *c, DFHack::SpawnPoints *points, + DFHack::Materials *Materials); DFhackCExport command_result colonies (Core * c, vector & parameters) { @@ -54,7 +55,7 @@ DFhackCExport command_result colonies (Core * c, vector & parameters) if (destroy && convert) { - dfout << "Kill or make bees? DECIDE!" << std::endl; + c->con << "Kill or make bees? DECIDE!" << std::endl; return CR_FAILURE; } @@ -67,7 +68,7 @@ DFhackCExport command_result colonies (Core * c, vector & parameters) if(!points->isValid()) { - std::cerr << "vermin not supported for this DF version" << std::endl; + c->con << "vermin not supported for this DF version" << std::endl; return CR_FAILURE; } @@ -78,7 +79,7 @@ DFhackCExport command_result colonies (Core * c, vector & parameters) else if (convert) convertColonies(points, materials); else - showColonies(points, materials); + showColonies(c, points, materials); delete points; @@ -136,7 +137,8 @@ void convertColonies(DFHack::SpawnPoints *points, DFHack::Materials *Materials) } } -void showColonies(DFHack::SpawnPoints *points, DFHack::Materials *Materials) +void showColonies(Core *c, DFHack::SpawnPoints *points, + DFHack::Materials *Materials) { uint32_t numSpawnPoints = points->size(); int numColonies = 0; @@ -153,11 +155,11 @@ void showColonies(DFHack::SpawnPoints *points, DFHack::Materials *Materials) if (Materials->raceEx[sp.race].rawname[0]) race = Materials->raceEx[sp.race].rawname; - fprintf(dfout_C, "Spawn point %u: %s at %d:%d:%d\n", - i, race.c_str(), sp.x, sp.y, sp.z); + c->con.print("Spawn point %u: %s at %d:%d:%d\n", i, + race.c_str(), sp.x, sp.y, sp.z); } } if (numColonies == 0) - dfout << "No colonies present." << std::endl; + c->con << "No colonies present." << std::endl; }