From 923c8cae9c8b19d0c0349e0a868e781d5894bd46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Thu, 28 Apr 2011 01:36:31 +0200 Subject: [PATCH] Occupancy support in MapCache. Added the item dumper tool mentioned on irc (autodump). --- library/include/dfhack/extra/MapExtras.h | 41 ++++++ tools/supported/CMakeLists.txt | 4 + tools/supported/autodump.cpp | 178 +++++++++++++++++++++++ 3 files changed, 223 insertions(+) create mode 100644 tools/supported/autodump.cpp diff --git a/library/include/dfhack/extra/MapExtras.h b/library/include/dfhack/extra/MapExtras.h index 57601fa4b..b701d37c9 100644 --- a/library/include/dfhack/extra/MapExtras.h +++ b/library/include/dfhack/extra/MapExtras.h @@ -64,6 +64,7 @@ class Block dirty_tiletypes = false; dirty_temperatures = false; dirty_blockflags = false; + dirty_occupancies = false; valid = false; bcoord = _bcoord; if(m->ReadBlock40d(bcoord.x,bcoord.y,bcoord.z,&raw)) @@ -140,6 +141,18 @@ class Block return true; } + DFHack::t_occupancy OccupancyAt(DFHack::DFCoord p) + { + return raw.occupancy[p.x][p.y]; + } + bool setOccupancyAt(DFHack::DFCoord p, DFHack::t_occupancy des) + { + if(!valid) return false; + dirty_occupancies = true; + raw.occupancy[p.x][p.y] = des; + return true; + } + DFHack::t_blockflags BlockFlags() { return raw.blockflags; @@ -177,6 +190,11 @@ class Block m->WriteBlockFlags(bcoord.x,bcoord.y,bcoord.z,raw.blockflags); dirty_blockflags = false; } + if(dirty_occupancies) + { + m->WriteOccupancy(bcoord.x,bcoord.y,bcoord.z,&raw.occupancy); + dirty_occupancies = false; + } return true; } bool valid:1; @@ -184,6 +202,7 @@ class Block bool dirty_tiletypes:1; bool dirty_temperatures:1; bool dirty_blockflags:1; + bool dirty_occupancies:1; DFHack::Maps * m; DFHack::mapblock40d raw; DFHack::DFCoord bcoord; @@ -347,6 +366,28 @@ class MapCache return false; } + DFHack::t_occupancy occupancyAt (DFHack::DFCoord tilecoord) + { + Block * b= BlockAt(tilecoord / 16); + if(b && b->valid) + { + return b->OccupancyAt(tilecoord % 16); + } + DFHack:: t_occupancy temp; + temp.whole = 0; + return temp; + } + bool setOccupancyAt (DFHack::DFCoord tilecoord, DFHack::t_occupancy occ) + { + Block * b= BlockAt(tilecoord / 16); + if(b && b->valid) + { + b->setOccupancyAt(tilecoord % 16, occ); + return true; + } + return false; + } + bool testCoord (DFHack::DFCoord tilecoord) { Block * b= BlockAt(tilecoord / 16); diff --git a/tools/supported/CMakeLists.txt b/tools/supported/CMakeLists.txt index bc6a01506..838773dae 100644 --- a/tools/supported/CMakeLists.txt +++ b/tools/supported/CMakeLists.txt @@ -96,6 +96,10 @@ DFHACK_TOOL(dfderamp deramp.cpp) #DFHACK_TOOL(dfautosearch autosearch.cpp) DFHACK_TOOL(dfincremental incrementalsearch.cpp) +# auto dump. dumps all items marked for dumping at the cursor position without the need for dwarf labor. +# ... or just kills the items? :P +DFHACK_TOOL(dfautodump autodump.cpp) + # veinlook - look at the map... sort of IF(UNIX) SET(VEINLOOK_BUILT "NO") diff --git a/tools/supported/autodump.cpp b/tools/supported/autodump.cpp new file mode 100644 index 000000000..84791d82a --- /dev/null +++ b/tools/supported/autodump.cpp @@ -0,0 +1,178 @@ +// Quick Dumper : Moves items marked as "dump" to cursor + +#include +#include +#include +#include +#include +#include +using namespace std; + +#include +#include +#include // map cache for the win. +using namespace DFHack; +using MapExtras::Block; +using MapExtras::MapCache; + +typedef std::map coordmap; + +int main () +{ + + DFHack::ContextManager CM ("Memory.xml"); + DFHack::Context * DF; + DFHack::VersionInfo *mem; + DFHack::Gui * Gui; + DFHack::Items * Items; + DFHack::Maps *Maps; + DFHack::occupancies40d * occupancies; + + cout << "This utility lets you quickly move all items designated to be dumped." << endl + << "Items are instantly moved to the cursor position, the dump flag is unset," << endl + << "and the forbid flag is set, as if it had been dumped normally." << endl + << "Be aware that any active dump item tasks still point at the item." << endl << endl; + try + { + DF = CM.getSingleContext(); + DF->Attach(); + mem = DF->getMemoryInfo(); + Gui = DF->getGui(); + Items = DF->getItems(); + Maps = DF->getMaps(); + } + catch (exception& e) + { + cerr << e.what() << endl; + #ifndef LINUX_BUILD + cin.ignore(); + #endif + return 1; + } + + DFHack::Process * p = DF->getProcess(); + + // FIXME: these can fail and should be wrapped in a try-catch + DFHack::OffsetGroup* itemGroup = mem->getGroup("Items"); + unsigned vector_addr = itemGroup->getAddress("items_vector"); + DFHack::DfVector p_items (p, vector_addr); + + uint32_t numItems = p_items.size(); + + // init the map + if(!Maps->Start()) + { + cerr << "Can't initialize map." << endl; + #ifndef LINUX_BUILD + cin.ignore(); + #endif + return 1; + } + MapCache MC (Maps); + + int i = 0; + int dumped_total = 0; + + int cx, cy, cz; + + if (!Gui->getCursorCoords(cx,cy,cz)) + { + cerr << "Cursor position not found. Please enabled the cursor." << endl; + #ifndef LINUX_BUILD + cin.ignore(); + #endif + return 1; + } + DFCoord pos_cursor(cx,cy,cz); + { + Block * b = MC.BlockAt(pos_cursor / 16); + if(!b) + { + cerr << "Cursor is in an invalid area. Place it over something save first." << endl; + #ifndef LINUX_BUILD + cin.ignore(); + #endif + return 1; + } + // TODO: check if the target is floor? maybe? + } + coordmap counts; + // proceed with the dumpification operation + for(uint32_t i=0; i< numItems; i++) + { + DFHack::dfh_item temp; + Items->readItem(p_items[i],temp); + DFCoord pos_item(temp.base.x, temp.base.y, temp.base.z); + + // keep track how many items are at places. all items. + coordmap::iterator it = counts.find(pos_item); + if(it == counts.end()) + { + std::pair< coordmap::iterator, bool > inserted = counts.insert(std::make_pair(pos_item,1)); + it = inserted.first; + } + else + { + it->second ++; + } + // iterator is valid here, we use it later to decrement the pile counter if the item is moved + + // only dump the stuff marked for dumping and laying on the ground + if (!temp.base.flags.dump || !temp.base.flags.on_ground) + continue; + + // Change flags to indicate the dump was completed, as if by super-dwarfs + temp.base.flags.dump = 0; + temp.base.flags.forbid = 1; + + // Don't move items if they're already at the cursor + if (pos_cursor == pos_item) + continue; + + // Move the item + temp.base.x = pos_cursor.x; + temp.base.y = pos_cursor.y; + temp.base.z = pos_cursor.z; + Items->writeItem(temp); + // keeping track of item pile sizes ;) + it->second --; + dumped_total++; + } + // for each item pile, see if it reached zero. if so, unset item flag on the tile it's on + coordmap::iterator it = counts.begin(); + coordmap::iterator end = counts.end(); + while(it != end) + { + if(it->second == 0) + { + t_occupancy occ = MC.occupancyAt(it->first); + occ.bits.item = false; + MC.setOccupancyAt(it->first, occ); + } + it++; + } + // Set "item here" flag on target tile, if we moved any items to the target tile. + if (dumped_total > 0) + { + // assume there is a possibility the cursor points at some weird location with missing block data + Block * b = MC.BlockAt(pos_cursor / 16); + if(b) + { + t_occupancy occ = MC.occupancyAt(pos_cursor); + occ.bits.item = 1; + MC.setOccupancyAt(pos_cursor,occ); + } + } + // write map changes back to DF. + MC.WriteAll(); + // Is this necessary? Is "forbid" a dirtyable attribute like "dig" is? + Maps->WriteDirtyBit(cx/16, cy/16, cz, true); + + DF->Detach(); + cout << "Done. " << dumped_total << " items quickdumped." << endl; +#ifndef LINUX_BUILD + cout << "Press any key to continue" << endl; + cin.ignore(); +#endif + return 0; +} \ No newline at end of file