Ported autodump tool

develop
Petr Mrázek 2011-08-04 04:04:46 +02:00
parent ff4d545ae7
commit a8543f5ef0
9 changed files with 216 additions and 293 deletions

@ -143,3 +143,4 @@ DFHACK_PLUGIN(mode mode.cpp)
#DFHACK_PLUGIN(tiles tiles.cpp) #DFHACK_PLUGIN(tiles tiles.cpp)
DFHACK_PLUGIN(liquids liquids.cpp) DFHACK_PLUGIN(liquids liquids.cpp)
DFHACK_PLUGIN(tubefill tubefill.cpp) DFHACK_PLUGIN(tubefill tubefill.cpp)
DFHACK_PLUGIN(autodump autodump.cpp)

@ -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;
}

@ -46,85 +46,7 @@ DFhackCExport command_result plugin_shutdown ( Core * c )
{ {
return CR_OK; return CR_OK;
} }
/*
bool parseOptions(vector<string> &params, bool &showBlock, bool &showDesig,
bool &showOccup, bool &showTile, bool &showMisc)
{
// With no options set, show everything.
showBlock = true;
showDesig = true;
showOccup = true;
showTile = true;
showMisc = true;
bool _showBlock = false;
bool _showDesig = false;
bool _showOccup = false;
bool _showTile = false;
bool _showMisc = false;
char c;
xgetopt opt(params, "bdotm");
opt.opterr = 0;
while ((c = opt()) != -1)
{
switch (c)
{
case 'b':
_showBlock = true;
break;
case 'd':
_showDesig = true;
break;
case 'o':
_showOccup = true;
break;
case 't':
_showTile = true;
break;
case 'm':
_showMisc = true;
break;
case '?':
switch (opt.optopt)
{
// For when we take arguments
default:
if (isprint(opt.optopt))
std::cerr << "Unknown option -" << opt.optopt << "!"
<< std::endl;
else
std::cerr << "Unknown option character " << (int) opt.optopt << "!"
<< std::endl;
}
default:
// Um.....
return false;
}
}
// If any options set, show only those requested via options.
if(_showBlock || _showDesig || _showOccup || _showTile || _showMisc)
{
showBlock = false;
showDesig = false;
showOccup = false;
showTile = false;
showMisc = false;
showBlock = _showBlock;
showDesig = _showDesig;
showOccup = _showOccup;
showTile = _showTile;
showMisc = _showMisc;
}
return true;
}
*/
using namespace DFHack;
DFhackCExport command_result df_probe (Core * c, vector <string> & parameters) DFhackCExport command_result df_probe (Core * c, vector <string> & parameters)
{ {
//bool showBlock, showDesig, showOccup, showTile, showMisc; //bool showBlock, showDesig, showOccup, showTile, showMisc;

@ -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;
}