Ported autodump tool
parent
ff4d545ae7
commit
a8543f5ef0
@ -0,0 +1,215 @@
|
||||
// Quick Dumper : Moves items marked as "dump" to cursor
|
||||
// FIXME: local item cache in map blocks needs to be fixed after teleporting items
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <climits>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
using namespace std;
|
||||
|
||||
#include <dfhack/Core.h>
|
||||
#include <dfhack/Console.h>
|
||||
#include <dfhack/Export.h>
|
||||
#include <dfhack/PluginManager.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <dfhack/modules/Maps.h>
|
||||
#include <dfhack/modules/Gui.h>
|
||||
#include <dfhack/modules/Items.h>
|
||||
#include <dfhack/modules/Materials.h>
|
||||
#include <dfhack/extra/MapExtras.h>
|
||||
|
||||
using namespace DFHack;
|
||||
using MapExtras::Block;
|
||||
using MapExtras::MapCache;
|
||||
|
||||
DFhackCExport command_result df_autodump (Core * c, vector <string> & parameters);
|
||||
|
||||
DFhackCExport const char * plugin_name ( void )
|
||||
{
|
||||
return "autodump";
|
||||
}
|
||||
|
||||
DFhackCExport command_result plugin_init ( Core * c, std::vector <PluginCommand> &commands)
|
||||
{
|
||||
commands.clear();
|
||||
commands.push_back(PluginCommand("autodump",
|
||||
"Teleport items marked for dumping to the cursor.",
|
||||
df_autodump));
|
||||
return CR_OK;
|
||||
}
|
||||
|
||||
DFhackCExport command_result plugin_shutdown ( Core * c )
|
||||
{
|
||||
return CR_OK;
|
||||
}
|
||||
|
||||
typedef std::map <DFCoord, uint32_t> coordmap;
|
||||
|
||||
DFhackCExport command_result df_autodump (Core * c, vector <string> & parameters)
|
||||
{
|
||||
// Command line options
|
||||
bool destroy = false;
|
||||
if(parameters.size() > 0)
|
||||
{
|
||||
string & p = parameters[0];
|
||||
if(p == "destroy")
|
||||
destroy = true;
|
||||
else if(p == "?" || p == "help")
|
||||
{
|
||||
c->con.print(
|
||||
"This utility lets you quickly move all items designated to be dumped.\n"
|
||||
"Items are instantly moved to the cursor position, the dump flag is unset,\n"
|
||||
"and the forbid flag is set, as if it had been dumped normally.\n"
|
||||
"Be aware that any active dump item tasks still point at the item.\n\n"
|
||||
);
|
||||
return CR_OK;
|
||||
}
|
||||
}
|
||||
c->Suspend();
|
||||
DFHack::occupancies40d * occupancies;
|
||||
DFHack::VersionInfo *mem = c->vinfo;
|
||||
DFHack::Gui * Gui = c->getGui();
|
||||
DFHack::Items * Items = c->getItems();
|
||||
DFHack::Maps *Maps = c->getMaps();
|
||||
|
||||
vector <t_item*> p_items;
|
||||
if(!Items->readItemVector(p_items))
|
||||
{
|
||||
c->con.printerr("Can't access the item vector.\n");
|
||||
c->Resume();
|
||||
return CR_FAILURE;
|
||||
}
|
||||
std::size_t numItems = p_items.size();
|
||||
|
||||
// init the map
|
||||
if(!Maps->Start())
|
||||
{
|
||||
c->con.printerr("Can't initialize map.\n");
|
||||
c->Resume();
|
||||
return CR_FAILURE;
|
||||
}
|
||||
MapCache MC (Maps);
|
||||
int i = 0;
|
||||
int dumped_total = 0;
|
||||
|
||||
int cx, cy, cz;
|
||||
DFCoord pos_cursor;
|
||||
if(!destroy)
|
||||
{
|
||||
if (!Gui->getCursorCoords(cx,cy,cz))
|
||||
{
|
||||
c->con.printerr("Cursor position not found. Please enabled the cursor.\n");
|
||||
c->Resume();
|
||||
return CR_FAILURE;
|
||||
}
|
||||
pos_cursor = DFCoord(cx,cy,cz);
|
||||
{
|
||||
Block * b = MC.BlockAt(pos_cursor / 16);
|
||||
if(!b)
|
||||
{
|
||||
c->con.printerr("Cursor is in an invalid/uninitialized area. Place it over a floor.\n");
|
||||
c->Resume();
|
||||
return CR_FAILURE;
|
||||
}
|
||||
uint16_t ttype = MC.tiletypeAt(pos_cursor);
|
||||
if(!DFHack::isFloorTerrain(ttype))
|
||||
{
|
||||
c->con.printerr("Cursor should be placed over a floor.\n");
|
||||
c->Resume();
|
||||
return CR_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
coordmap counts;
|
||||
// proceed with the dumpification operation
|
||||
for(std::size_t i=0; i< numItems; i++)
|
||||
{
|
||||
t_item * itm = p_items[i];
|
||||
DFCoord pos_item(itm->x, itm->y, itm->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 ( !itm->flags.dump
|
||||
|| !itm->flags.on_ground
|
||||
|| itm->flags.construction
|
||||
|| itm->flags.hidden
|
||||
|| itm->flags.in_building
|
||||
|| itm->flags.in_chest
|
||||
|| itm->flags.in_inventory
|
||||
|| itm->flags.construction
|
||||
)
|
||||
continue;
|
||||
|
||||
if(!destroy) // move to cursor
|
||||
{
|
||||
// Change flags to indicate the dump was completed, as if by super-dwarfs
|
||||
itm->flags.dump = false;
|
||||
itm->flags.forbid = true;
|
||||
|
||||
// Don't move items if they're already at the cursor
|
||||
if (pos_cursor == pos_item)
|
||||
continue;
|
||||
|
||||
// Move the item
|
||||
itm->x = pos_cursor.x;
|
||||
itm->y = pos_cursor.y;
|
||||
itm->z = pos_cursor.z;
|
||||
}
|
||||
else // destroy
|
||||
{
|
||||
itm->flags.garbage_colect = true;
|
||||
}
|
||||
// keeping track of item pile sizes ;)
|
||||
it->second --;
|
||||
dumped_total++;
|
||||
}
|
||||
if(!destroy) // TODO: do we have to do any of this when destroying items?
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
c->Resume();
|
||||
c->con.print("Done. %d items %s.\n", dumped_total, destroy ? "marked for desctruction" : "quickdumped");
|
||||
return CR_OK;
|
||||
}
|
@ -1,215 +0,0 @@
|
||||
// Quick Dumper : Moves items marked as "dump" to cursor
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <climits>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
using namespace std;
|
||||
|
||||
#include <DFHack.h>
|
||||
#include <dfhack/DFVector.h>
|
||||
#include <dfhack/extra/MapExtras.h> // map cache for the win.
|
||||
#include <dfhack/extra/termutil.h>
|
||||
using namespace DFHack;
|
||||
using MapExtras::Block;
|
||||
using MapExtras::MapCache;
|
||||
|
||||
typedef std::map <DFCoord, uint32_t> coordmap;
|
||||
|
||||
int main (int argc, char * argv[])
|
||||
{
|
||||
bool temporary_terminal = TemporaryTerminal();
|
||||
// Command line options
|
||||
bool destroy = false;
|
||||
if(argc > 1 && strcmp(argv[1],"-d") == 0)
|
||||
destroy = true;
|
||||
|
||||
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;
|
||||
|
||||
uint32_t vector_addr = 0;
|
||||
|
||||
try
|
||||
{
|
||||
DF = CM.getSingleContext();
|
||||
DF->Attach();
|
||||
mem = DF->getMemoryInfo();
|
||||
Gui = DF->getGui();
|
||||
Items = DF->getItems();
|
||||
Maps = DF->getMaps();
|
||||
DFHack::OffsetGroup* itemGroup = mem->getGroup("Items");
|
||||
vector_addr = itemGroup->getAddress("items_vector");
|
||||
}
|
||||
catch (exception& e)
|
||||
{
|
||||
cerr << e.what() << endl;
|
||||
if(temporary_terminal)
|
||||
cin.ignore();
|
||||
return 1;
|
||||
}
|
||||
|
||||
DFHack::Process * p = DF->getProcess();
|
||||
DFHack::DfVector <uint32_t> p_items (p, vector_addr);
|
||||
uint32_t numItems = p_items.size();
|
||||
|
||||
// init the map
|
||||
if(!Maps->Start())
|
||||
{
|
||||
cerr << "Can't initialize map." << endl;
|
||||
if(temporary_terminal)
|
||||
cin.ignore();
|
||||
return 1;
|
||||
}
|
||||
MapCache MC (Maps);
|
||||
|
||||
int i = 0;
|
||||
int dumped_total = 0;
|
||||
|
||||
int cx, cy, cz;
|
||||
DFCoord pos_cursor;
|
||||
if(!destroy)
|
||||
{
|
||||
if (!Gui->getCursorCoords(cx,cy,cz))
|
||||
{
|
||||
cerr << "Cursor position not found. Please enabled the cursor." << endl;
|
||||
if(temporary_terminal)
|
||||
cin.ignore();
|
||||
return 1;
|
||||
}
|
||||
pos_cursor = DFCoord(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;
|
||||
if(temporary_terminal)
|
||||
cin.ignore();
|
||||
return 1;
|
||||
}
|
||||
uint16_t ttype = MC.tiletypeAt(pos_cursor);
|
||||
if(!DFHack::isFloorTerrain(ttype))
|
||||
{
|
||||
cerr << "Cursor should be placed over a floor." << endl;
|
||||
if(temporary_terminal)
|
||||
cin.ignore();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
|| temp.base.flags.construction
|
||||
|| temp.base.flags.hidden
|
||||
|| temp.base.flags.in_building
|
||||
|| temp.base.flags.in_chest
|
||||
|| temp.base.flags.in_inventory
|
||||
|| temp.base.flags.construction
|
||||
)
|
||||
continue;
|
||||
|
||||
if(!destroy) // move to cursor
|
||||
{
|
||||
// Change flags to indicate the dump was completed, as if by super-dwarfs
|
||||
temp.base.flags.dump = false;
|
||||
temp.base.flags.forbid = true;
|
||||
|
||||
// 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;
|
||||
}
|
||||
else // destroy
|
||||
{
|
||||
temp.base.flags.garbage_colect = true;
|
||||
}
|
||||
Items->writeItem(temp);
|
||||
// keeping track of item pile sizes ;)
|
||||
it->second --;
|
||||
dumped_total++;
|
||||
}
|
||||
if(!destroy) // TODO: do we have to do any of this when destroying items?
|
||||
{
|
||||
// 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();
|
||||
if(!destroy)
|
||||
{
|
||||
cout << "Done. " << dumped_total << " items quickdumped." << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "Done. " << dumped_total << " items marked for destruction." << endl;
|
||||
}
|
||||
if(temporary_terminal)
|
||||
{
|
||||
cout << "Press any key to continue" << endl;
|
||||
cin.ignore();
|
||||
}
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue