Merge branch 'master' of git://github.com/peterix/dfhack.git

develop
mizipzor 2010-02-16 20:55:35 +01:00
commit a448504e4a
34 changed files with 1430 additions and 717 deletions

@ -29,4 +29,5 @@ include_directories (${CMAKE_SOURCE_DIR}/shmserver/)
add_subdirectory (library)
add_subdirectory (tools)
add_subdirectory (examples)
add_subdirectory (shmserver)

@ -4,6 +4,7 @@ Here's how you build dfhack!
First, there is one dependency, regardless of the OS you use:
cmake - it's the build system
Building on Linux:
--------------------
@ -30,8 +31,7 @@ library to $CMAKE_INSTALL_PREFIX/lib
executables to $CMAKE_INSTALL_PREFIX/bin
The Memory.xml file to /usr/share/dfhack
A special library for adding a shared memory interface to DF is also compiled (libdfconnect.so)
It can be put into DF/libs and preloaded using LD_PRELOAD
See the section on the shared memory hook library (SHM).
Building on Windows:
--------------------
@ -51,9 +51,6 @@ You'll have to add C:\MinGW\ to your PATH variable.
cmake .. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE:string=Release
mingw32-make
A special library for adding a shared memory interface to DF is also compiled (SDL.dll)
You can use it with DF by renaming the original SDL.dll to SDLreal.dll and dropping in the newly compiled library.
* Using MSVC
open up cmd and navigate to the dfhack\build folder, run cmake:
@ -64,22 +61,73 @@ This will generate MSVC solution and project files. Note that: you are working i
Files added to projects will end up there! (and that's wrong). Any changes to the build system should
be done by changing cmake configs and running cmake on them!
A special library for adding a shared memory interface to DF is also compiled (SDL.dll)
You can use it with DF by renaming the original SDL.dll to SDLreal.dll and dropping in the newly compiled library.
* Using some other compiler:
I'm afraid you are on your own. dfhack wasn't tested with any other compiler.
Try using a different cmake generator that's intended for your tools.
Building the shared memory hook library (SHM)
---------------------------------------------
Unlike the rest of DFHack, The SHM needs special treatment when it comes to compilation.
Because it shares the memory space with DF itself, it has to be built with the same tools as DF
and use the same C and C++/STL libraries.
For DF 40d15 - 40d17 on Windows, use MSVC 2008. You can get the Express edition for free from Microsoft.
Windows dependencies can be determined by a tool like depends.exe (google it). Both the fake SDL.dll
and DF have to use the same version of the C runtime (MSVCRT).
The SHM can't be debugged, because debug builds in MSVC use a different CRT!
Linux dependencies can be determined by setting the LD_DEBUG variable and running ./df:
export LD_DEBUG=versions
./df
Example of (a part of a) relevant output from a working SHM installation:
24472: checking for version `GLIBC_2.0' in file /opt/lib32/lib/libpthread.so.0 [0] required by file ./dwarfort.exe [0]
24472: checking for version `GCC_3.0' in file ./libs/libgcc_s.so.1 [0] required by file ./dwarfort.exe [0]
24472: checking for version `GLIBC_2.0' in file ./libs/libgcc_s.so.1 [0] required by file ./dwarfort.exe [0]
24472: checking for version `GLIBC_2.1' in file /opt/lib32/lib/libm.so.6 [0] required by file ./dwarfort.exe [0]
24472: checking for version `GLIBC_2.0' in file /opt/lib32/lib/libm.so.6 [0] required by file ./dwarfort.exe [0]
24472: checking for version `GLIBC_2.1.3' in file /opt/lib32/lib/libc.so.6 [0] required by file ./dwarfort.exe [0]
24472: checking for version `GLIBC_2.3.4' in file /opt/lib32/lib/libc.so.6 [0] required by file ./dwarfort.exe [0]
24472: checking for version `GLIBC_2.4' in file /opt/lib32/lib/libc.so.6 [0] required by file ./dwarfort.exe [0]
24472: checking for version `GLIBC_2.0' in file /opt/lib32/lib/libc.so.6 [0] required by file ./dwarfort.exe [0]
24472: checking for version `GLIBCXX_3.4.9' in file ./libs/libstdc++.so.6 [0] required by file ./dwarfort.exe [0]
24472: checking for version `CXXABI_1.3' in file ./libs/libstdc++.so.6 [0] required by file ./dwarfort.exe [0]
24472: checking for version `GLIBCXX_3.4' in file ./libs/libstdc++.so.6 [0] required by file ./dwarfort.exe [0]
24472: checking for version `CXXABI_1.3' in file ./libs/libstdc++.so.6 [0] required by file ./libs/libdfconnect.so [0]
24472: checking for version `GLIBCXX_3.4' in file ./libs/libstdc++.so.6 [0] required by file ./libs/libdfconnect.so [0]
24472: checking for version `GLIBC_2.1.3' in file /opt/lib32/lib/libc.so.6 [0] required by file ./libs/libdfconnect.so [0]
24472: checking for version `GLIBC_2.2' in file /opt/lib32/lib/libc.so.6 [0] required by file ./libs/libdfconnect.so [0]
24472: checking for version `GLIBC_2.3.4' in file /opt/lib32/lib/libc.so.6 [0] required by file ./libs/libdfconnect.so [0]
24472: checking for version `GLIBC_2.0' in file /opt/lib32/lib/libc.so.6 [0] required by file ./libs/libdfconnect.so [0]
libdfconnect is the SHM. Both are compiled against the same C++ library and share the same CXXABI version.
Precompiled SHM libraries are provided in binary releases.
* Checking strings support
Strings are one of the important C++ types and a great indicator that the SHM works. Tools like Dwarf Therapist depend
on string support. Reading of strings can be checked by running any of the tools that deal with materials.
String writing is best tested with a fresh throw-away fort and dfrenamer. Embark, give one dwarf a very long name using dfrenamer
and save/exit. If DF crashes during the save sequence, your SHM is not compatible with DF and the throw-away fort is lost.
Build targets
-------------
dfhack has a few build targets. If you're only after the library run 'make dfhack'.
'make' will build everything.
'make expbench' will build the expbench throughput testing program and the library.
Build types
-----------
cmake allows you to pick a build type by changing this variable: CMAKE_BUILD_TYPE
cmake .. -DCMAKE_BUILD_TYPE:string=BUILD_TYPE

126
README

@ -1,66 +1,84 @@
Introduction
------------
DFHack is a Dwarf Fortress memory access library and a set of basic tools using this library.
The library is a work in progress, so things might change as more tools are written for it.
It is an attempt to unite the various ways tools access DF memory and allow for easier development
of new tools.
DFHack is a Dwarf Fortress memory access library and a set of basic tools using
this library. The library is a work in progress, so things might change as more
tools are written for it.
It is an attempt to unite the various ways tools access DF memory and allow for
easier development of new tools.
Getting DFHack
----------------
You can get the code at DFHack's sourceforge site:
https://sourceforge.net/projects/dfhack/
* subversion access:
svn co https://dfhack.svn.sourceforge.net/svnroot/dfhack/trunk dfhack
It is also available on github:
http://github.com/peterix/dfhack
Compatibility
-------------
DFHack works on Windows XP, Vista, 7 or any modern Linux distribution.
Windows 2000 is currently *not supported* due to missing OS functionality. If you know how
to easily suspend processes, you can fix it :)
Windows 2000 is currently *not supported* due to missing OS functionality.
If you know how to easily suspend processes, you can fix it :)
OSX is also not supported due to lack of developers with a Mac.
Currently supported Dwarf Fortress versions:
* Windows
40d
40d9 - 40d16
40d9 - 40d17
* Linux
40d9 - 40d16
40d9 - 40d17
Using the library
-----------------
The library is compilable under Linux with GCC and under Windows with MinGW32 and MSVC compilers.
It is using the cmake build system. See COMPILE for details.
DFHack is using the zlib/libpng license. This makes it easy to link to it, use it in-source
or add your own extensions. Contributing back to the dfhack repository is welcome and the right
thing to do :)
The library is compilable under Linux with GCC and under Windows with MinGW32
and MSVC compilers. It is using the cmake build system. See COMPILE for details.
DFHack is using the zlib/libpng license. This makes it easy to link to it, use
it in-source or add your own extensions. Contributing back to the dfhack
repository is welcome and the right thing to do :)
At the time of writing there's no API reference or documentation. The code does
have a lot of comments though.
At the time of writing there's no API reference or documentation. The code does have a lot
of comments though.
Using DFHack Tools
------------------
The project comes with a special extra library you should add to your DF installation.
It's used to boost the transfer speed between DF and DFHack, and provide data consistency
and synchronization. DFHack will work without the library, but at suboptimal speeds
and the consistency of data written back to DF is questionable.
!!!!Please not that on Windows this currently only works with DF 40d15 and 40d16!!!!
On Linux, it works with the whole range of supported DF versions.
The project comes with a special extra library you should add to your DF
installation. It's used to boost the transfer speed between DF and DFHack, and
provide data consistency and synchronization. DFHack will work without the
library, but at suboptimal speeds and the consistency of data written back
to DF is questionable.
!!! on Windows this currently only works with DF 40d15, 40d16 and 40d17 !!!
On Linux, it works with the whole range of supported DF versions.
!!! use the pre-compiled library intended for your version of DF !!!
You can find them in the 'precompiled' folder.
** Installing on Windows
- Open your DF folder, locate SDL.dll and rename it to SDLreal.dll (making a backup of it is a good idea)
- Copy the DFHack SDL.dll into your DF folder.
- Restart DF if it is already running
- Open your DF folder, locate SDL.dll and rename it to SDLreal.dll (making
a backup of it is a good idea)
- Copy the right DFHack SDL.dll into your DF folder.
- Restart DF if it is running
** Unistalling on Windows
- Open your DF folder, locate SDL.dll and delete it
- Rename SDLreal.dll to SDl.dll
- Rename SDLreal.dll to SDL.dll
- Restart DF if it is running
@ -94,56 +112,40 @@ export LD_PRELOAD="./libs/libdfconnect.so" # Hack DF!
- Delete libdfconnect.so and the dfhacked startup script
- Go back to using the df startup script
Tools
-----
All the DFHack tools are terminal programs. This might seem strange to Windows users,
but these are meant mostly as examples for developers. Still, they can be useful and
are cross-platform just like the library itself.
If the tool writes back to DF's memory, make sure you are using the shared memory interface
mentioned in the previous section!
* expbench - just exports the map 1000 times over. Meant to test how fast the
DFHack<->DF interface is. This can take 3-30+ seconds, depending on
your system and the size of the map.
* reveal - plain old reveal tool. Demonstrates writing map data back to DF.
All the DFHack tools are terminal programs. This might seem strange to Windows
users, but these are meant mostly as examples for developers. Still, they can
be useful and are cross-platform just like the library itself.
* prospector - scans the map for minerals. by default it only scans only visible veins.
You can make it show hidden things with '-a' and base rock and soil layers
with '-b'. These can be combined ('-ab')
If the tool writes back to DF's memory, make sure you are using the shared
memory interface mentioned in the previous section!
* cleanmap - cleans mud, vomit, snow and all kinds of bloody mess from the map. It will
clean your irrigated farms too, so consider yourself warned.
* reveal - plain old reveal tool. It reveals all the map blocks already
initialized by DF.
* dfattachtest - Benchmark for the Attach, Detach, Suspend and Resume functions
* prospector - scans the map for minerals. by default it only scans only visible
veins. You can make it show hidden things with '-a' and base rock
and soil layers with '-b'. These can be combined ('-ab')
* dfbuildingsdump - exports some basic data about buildings of a given type on the game map
* cleanmap - cleans mud, vomit, snow and all kinds of mess from the map.
It will clean your irrigated farms too, so consider yourself
warned.
* dfcreaturedump - exports some basic data about all the dwarves
* dfincremental - incremental search utility.
* dfcustomCreatureNameProf - allws you to change nicknames and custom professions of your dwarves
* bauxite - converts all mechanisms into bauxite mechanisms.
* dfincremental - incremental search utility - linux only right now
* dfitemdump - lists items under the current DF cursor (40d16 only)
* dfmaterialtest - tries to load all the material types from DF, shows the first entry of each type
* dfposition - shows you the current view coordinates and window size in tiles
(may not be implemented for older DF versions)
* dfsuspend - tests the behavior of Suspend and Resume functions
* itemdesignator - Allows mass-designating items by type and material - dump,
forbid, melt and set on fire ;)
Memory offset definitions
-------------------------
The file with memory offset definitions used by dfhack can be found in the output folder.
It uses XML as the base format.
It allows entry versioning and basing newer entries on older ones. These newer versions
only have to specify the values that are different or a single 'rebase' value that is then
used as an offset for all the addresses or object identifiers.
This makes it possible to track the small d## releases pretty quickly.
The file with memory offset definitions used by dfhack can be found in the
output folder.
~ EOF ~

@ -0,0 +1,63 @@
# don't use this file directly. use the one in the root folder of the project
# this is required to ensure we use the right configuration for the system.
IF(UNIX)
add_definitions(-DLINUX_BUILD)
ENDIF(UNIX)
# attachtest - 100x attach/detach, suspend/resume
ADD_EXECUTABLE(dfattachtest attachtest.cpp)
TARGET_LINK_LIBRARIES(dfattachtest dfhack)
# a benchmark program, reads the map 1000x
ADD_EXECUTABLE(dfexpbench expbench.cpp)
TARGET_LINK_LIBRARIES(dfexpbench dfhack)
# creaturedump - basic creature dump - a test of the creature related exports
ADD_EXECUTABLE(dfcreaturedump creaturedump.cpp)
TARGET_LINK_LIBRARIES(dfcreaturedump dfhack)
# buildingsdump - dump buildings and their raw data filtered by type
ADD_EXECUTABLE(dfbuildingsdump buildingsdump.cpp)
TARGET_LINK_LIBRARIES(dfbuildingsdump dfhack)
# materialtest - just list the first material of each type
ADD_EXECUTABLE(dfmaterialtest materialtest.cpp)
TARGET_LINK_LIBRARIES(dfmaterialtest dfhack)
# position - check the DF window and cursor parameters
ADD_EXECUTABLE(dfposition position.cpp)
TARGET_LINK_LIBRARIES(dfposition dfhack)
# suspendtest - test if suspend works. df should stop responding when suspended by dfhack
ADD_EXECUTABLE(dfsuspend suspendtest.cpp)
TARGET_LINK_LIBRARIES(dfsuspend dfhack)
# itemdump - dump the item under the cursor
ADD_EXECUTABLE(dfitemdump dfitemdump.cpp)
TARGET_LINK_LIBRARIES(dfitemdump dfhack)
# digger - designate for digging by tile class
# Author: mizipzor
ADD_EXECUTABLE(dfdigger digger.cpp)
TARGET_LINK_LIBRARIES(dfdigger dfhack)
# renamer - change the custom names and professions of creatures, sends keys to df directly
ADD_EXECUTABLE(dfrenamer renamer.cpp)
TARGET_LINK_LIBRARIES(dfrenamer dfhack)
IF(UNIX)
install(TARGETS
dfattachtest
dfbuildingsdump
dfcreaturedump
dfitemdump
dfdigger
dfexpbench
dfmaterialtest
dfposition
dfrenamer
dfsuspend
RUNTIME DESTINATION bin
)
ENDIF(UNIX)

@ -10,13 +10,15 @@ using namespace std;
#include <DFTypes.h>
#include <DFHackAPI.h>
#include <DFMemInfo.h>
#include <DFProcess.h>
template <typename T>
void print_bits ( T val, std::ostream& out )
{
T n_bits = sizeof ( val ) * CHAR_BIT;
for ( unsigned i = 0; i < n_bits; ++i ) {
for ( unsigned i = 0; i < n_bits; ++i )
{
out<< !!( val & 1 ) << " ";
val >>= 1;
}
@ -28,26 +30,30 @@ vector<DFHack::t_matgloss> creaturestypes;
void printDwarves(DFHack::API & DF)
{
int dwarfCounter = 0;
for(uint32_t i = 0; i < numCreatures; i++)
for (uint32_t i = 0; i < numCreatures; i++)
{
DFHack::t_creature temp;
DF.ReadCreature(i, temp);
string type = creaturestypes[temp.type].id;
if(type == "DWARF" && !temp.flags1.bits.dead && !temp.flags2.bits.killed){
if (type == "DWARF" && !temp.flags1.bits.dead && !temp.flags2.bits.killed)
{
cout << i << ":";
if(temp.nick_name[0])
if (temp.nick_name[0])
{
cout << temp.nick_name;
}
else{
else
{
cout << temp.first_name;
}
string transName = DF.TranslateName(temp.last_name,names,creaturestypes[temp.type].id);
cout << " " << temp.custom_profession; //transName;
if(dwarfCounter%3 != 2){
if (dwarfCounter%3 != 2)
{
cout << '\t';
}
else{
else
{
cout << endl;
}
dwarfCounter++;
@ -59,29 +65,29 @@ bool getDwarfSelection(DFHack::API & DF, DFHack::t_creature & toChange,string &
{
static string lastText;
bool dwarfSuccess = false;
while(!dwarfSuccess)
while (!dwarfSuccess)
{
string input;
cout << "\nSelect Dwarf to Change or q to Quit" << endl;
DF.Resume();
getline (cin, input);
DF.Suspend();
if(input == "q")
if (input == "q")
{
return false;
}
else if(input == "r")
else if (input == "r")
{
printDwarves(DF);
}
else if(!input.empty())
else if (!input.empty())
{
int num;
stringstream(input) >> num;//= atol(input.c_str());
dwarfSuccess = DF.ReadCreature(num,toChange);
string type = creaturestypes[toChange.type].id;
if(type != "DWARF")
if (type != "DWARF")
{
dwarfSuccess = false;
}
@ -92,21 +98,24 @@ bool getDwarfSelection(DFHack::API & DF, DFHack::t_creature & toChange,string &
}
}
bool changeType = false;
while(!changeType)
while (!changeType)
{
string input;
cout << "\n(n)ickname or (p)rofession?" << endl;
getline(cin, input);
if(input == "q"){
if (input == "q")
{
return false;
}
if(input == "n"){
if (input == "n")
{
commandString = "pzyn";
eraseAmount = string(toChange.nick_name).length();
changeType = true;
isName = true;
}
else if(input == "p"){
else if (input == "p")
{
commandString = "pzyp";
eraseAmount = string(toChange.custom_profession).length();
changeType = true;
@ -114,18 +123,21 @@ bool getDwarfSelection(DFHack::API & DF, DFHack::t_creature & toChange,string &
}
}
bool changeValue = false;
while(!changeValue)
while (!changeValue)
{
string input;
cout << "value to change to?" << endl;
getline(cin, input);
if(input == "q"){
if (input == "q")
{
return false;
}
if(!lastText.empty() && input.empty()){
if (!lastText.empty() && input.empty())
{
changeValue = true;
}
else if( !input.empty()){
else if ( !input.empty())
{
lastText = input;
changeValue = true;
}
@ -140,9 +152,9 @@ bool waitTillChanged(DFHack::API &DF, int creatureToCheck, string changeValue, b
DFHack::t_creature testCre;
DF.ReadCreature(creatureToCheck,testCre);
int tryCount = 0;
if(isName)
if (isName)
{
while(testCre.nick_name != changeValue && tryCount <50)
while (testCre.nick_name != changeValue && tryCount <50)
{
DF.Resume();
w->TypeSpecial(DFHack::WAIT,1,100);
@ -153,7 +165,7 @@ bool waitTillChanged(DFHack::API &DF, int creatureToCheck, string changeValue, b
}
else
{
while(testCre.custom_profession != changeValue && tryCount < 50)
while (testCre.custom_profession != changeValue && tryCount < 50)
{
DF.Resume();
w->TypeSpecial(DFHack::WAIT,1,100);
@ -162,13 +174,16 @@ bool waitTillChanged(DFHack::API &DF, int creatureToCheck, string changeValue, b
tryCount++;
}
}
if(tryCount >= 50){
if (tryCount >= 50)
{
cerr << "Something went wrong, make sure that DF is at the correct screen";
return false;
}
DF.Resume();
return true;
}
bool waitTillScreenState(DFHack::API &DF, string screenState,bool EqualTo=true)
{
DFHack::DFWindow * w = DF.getWindow();
@ -176,7 +191,7 @@ bool waitTillScreenState(DFHack::API &DF, string screenState,bool EqualTo=true)
DF.Suspend();
DF.ReadViewScreen(current);
int tryCount = 0;
while(((EqualTo && objecttypes[current.type] != screenState) || (!EqualTo && objecttypes[current.type] == screenState)) && tryCount < 50)
while (((EqualTo && objecttypes[current.type] != screenState) || (!EqualTo && objecttypes[current.type] == screenState)) && tryCount < 50)
{
DF.Resume();
w->TypeSpecial(DFHack::WAIT,1,100);
@ -184,7 +199,7 @@ bool waitTillScreenState(DFHack::API &DF, string screenState,bool EqualTo=true)
DF.ReadViewScreen(current);
tryCount++;
}
if(tryCount >= 50){
if (tryCount >= 50) {
cerr << "Something went wrong, DF at " << objecttypes[current.type] << endl;
return false;
}
@ -192,6 +207,7 @@ bool waitTillScreenState(DFHack::API &DF, string screenState,bool EqualTo=true)
return true;
}
bool waitTillCursorState(DFHack::API &DF, bool On)
{
DFHack::DFWindow * w = DF.getWindow();
@ -199,7 +215,7 @@ bool waitTillCursorState(DFHack::API &DF, bool On)
int tryCount = 0;
DF.Suspend();
bool cursorResult = DF.getCursorCoords(x,y,z);
while(tryCount < 50 && On && !cursorResult || !On && cursorResult)
while (tryCount < 50 && On && !cursorResult || !On && cursorResult)
{
DF.Resume();
w->TypeSpecial(DFHack::WAIT,1,100);
@ -207,7 +223,7 @@ bool waitTillCursorState(DFHack::API &DF, bool On)
DF.Suspend();
cursorResult = DF.getCursorCoords(x,y,z);
}
if(tryCount >= 50)
if (tryCount >= 50)
{
cerr << "Something went wrong, cursor at x: " << x << " y: " << y << " z: " << z << endl;
return false;
@ -215,13 +231,15 @@ bool waitTillCursorState(DFHack::API &DF, bool On)
DF.Resume();
return true;
}
bool waitTillMenuState(DFHack::API &DF, uint32_t menuState,bool EqualTo=true)
{
int tryCount = 0;
DFHack::DFWindow * w = DF.getWindow();
DF.Suspend();
uint32_t testState = DF.ReadMenuState();
while(tryCount < 50 && ((EqualTo && menuState != testState) || (!EqualTo && menuState == testState)))
while (tryCount < 50 && ((EqualTo && menuState != testState) || (!EqualTo && menuState == testState)))
{
DF.Resume();
w->TypeSpecial(DFHack::WAIT,1,100);
@ -229,7 +247,7 @@ bool waitTillMenuState(DFHack::API &DF, uint32_t menuState,bool EqualTo=true)
DF.Suspend();
testState = DF.ReadMenuState();
}
if(tryCount >= 50)
if (tryCount >= 50)
{
cerr << "Something went wrong, menuState: "<<testState << endl;
return false;
@ -237,28 +255,32 @@ bool waitTillMenuState(DFHack::API &DF, uint32_t menuState,bool EqualTo=true)
DF.Resume();
return true;
}
bool moveToBaseWindow(DFHack::API &DF)
{
DFHack::DFWindow * w = DF.getWindow();
DFHack::t_viewscreen current;
DF.ReadViewScreen(current);
while(objecttypes[current.type] != string("viewscreen_dwarfmode"))
while (objecttypes[current.type] != string("viewscreen_dwarfmode"))
{
w->TypeSpecial(DFHack::F9); // cancel out of text input in names
// DF.TypeSpecial(DFHack::ENTER); // cancel out of text input in hotkeys
w->TypeSpecial(DFHack::SPACE); // should move up a level
if(!waitTillScreenState(DF,objecttypes[current.type],false)) return false; // wait until screen changes from current
if (!waitTillScreenState(DF,objecttypes[current.type],false)) return false; // wait until screen changes from current
DF.ReadViewScreen(current);
}
if(DF.ReadMenuState() != 0){// if menu state != 0 then there is a menu, so escape it
w->TypeSpecial(DFHack::F9);w->TypeSpecial(DFHack::ENTER); // exit out of any text prompts
if (DF.ReadMenuState() != 0) {// if menu state != 0 then there is a menu, so escape it
w->TypeSpecial(DFHack::F9);
w->TypeSpecial(DFHack::ENTER); // exit out of any text prompts
w->TypeSpecial(DFHack::SPACE); // go back to base state
if(!waitTillMenuState(DF,0))return false;
if (!waitTillMenuState(DF,0))return false;
}
DF.Resume();
return true;
}
bool setCursorToCreature(DFHack::API &DF)
{
DFHack::DFWindow * w = DF.getWindow();
@ -266,125 +288,158 @@ bool setCursorToCreature(DFHack::API &DF)
DF.Suspend();
DF.getCursorCoords(x,y,z);
DF.Resume();
if(x == -30000){
if (x == -30000) {
w->TypeStr("v");
if(!waitTillCursorState(DF,true)) return false;
if (!waitTillCursorState(DF,true)) return false;
}
else{ // reset the cursor to be the creature cursor
else { // reset the cursor to be the creature cursor
w->TypeSpecial(DFHack::SPACE);
if(!waitTillCursorState(DF,false)) return false;
if (!waitTillCursorState(DF,false)) return false;
w->TypeStr("v");
if(!waitTillCursorState(DF,true)) return false;
if (!waitTillCursorState(DF,true)) return false;
}
return true;
}
int main (void)
{
{
DFHack::API DF("Memory.xml");
if(!DF.Attach())
if (!DF.Attach())
{
cerr << "DF not found" << endl;
return 1;
}
DF.Suspend();
if(!DF.getClassIDMapping(objecttypes))
if (!DF.getClassIDMapping(objecttypes))
{
cerr << "Can't get type info" << endl;
return 1;
}
DFHack::memory_info mem = DF.getMemoryInfo();
if(!DF.ReadCreatureMatgloss(creaturestypes))
if (!DF.ReadCreatureMatgloss(creaturestypes))
{
cerr << "Can't get the creature types." << endl;
return 1;
return 1;
}
DF.InitReadNameTables(names);
DF.InitReadCreatures(numCreatures);
DF.InitViewAndCursor();
printDwarves(DF);
DFHack::Process * p = DF.getProcess();
DFHack::DFWindow * w = DF.getWindow();
DFHack::t_creature toChange;
string changeString,commandString;
int eraseAmount;
int toChangeNum;
bool isName;
DFHack::DFWindow * w = DF.getWindow();
while(getDwarfSelection(DF,toChange,changeString,commandString,eraseAmount,toChangeNum,isName))
bool useKeys = true;
string input2;
// use key event emulation or direct writing?
cout << "\nUse \n1:Key simulation\n2:Direct Writing" << endl;
getline(cin,input2);
if (input2 == "1")
{
useKeys = true;
}
else {
useKeys = false;
}
printDwarves(DF);
while (getDwarfSelection(DF,toChange,changeString,commandString,eraseAmount,toChangeNum,isName))
{
// limit length, DF doesn't accept input after this point
if(changeString.size() > 39)
if (changeString.size() > 39)
{
changeString.resize(39);
}
start:
start:
bool completed = false;
if(moveToBaseWindow(DF) && setCursorToCreature(DF))
{
DF.Suspend();
DF.setCursorCoords(toChange.x, toChange.y,toChange.z);
vector<uint32_t> underCursor;
while(!DF.getCurrentCursorCreatures(underCursor))
if (useKeys) {
if (moveToBaseWindow(DF) && setCursorToCreature(DF))
{
DF.Resume();
w->TypeSpecial(DFHack::WAIT,1,100);
DF.Suspend();
DF.setCursorCoords(toChange.x, toChange.y,toChange.z);
DF.ReadCreature(toChangeNum,toChange);
}
//CurrentCursorCreatures gives the creatures in the order that you see them with the 'k' cursor.
//The 'v' cursor displays them in the order of last, then first,second,third and so on
//Pretty weird, but it works
//The only place that seems to display which creature is currently selected is on the stack, whose location is likely not static, so not usable
if(underCursor[underCursor.size()-1] != toChange.origin)
{
for(int i = 0;i<underCursor.size()-1;i++)
vector<uint32_t> underCursor;
while (!DF.getCurrentCursorCreatures(underCursor))
{
DF.Resume();
w->TypeStr("v",100);
if(underCursor[i] == toChange.origin)
w->TypeSpecial(DFHack::WAIT,1,100);
DF.Suspend();
DF.setCursorCoords(toChange.x, toChange.y,toChange.z);
DF.ReadCreature(toChangeNum,toChange);
}
//CurrentCursorCreatures gives the creatures in the order that you see them with the 'k' cursor.
//The 'v' cursor displays them in the order of last, then first,second,third and so on
//Pretty weird, but it works
//The only place that seems to display which creature is currently selected is on the stack, whose location is likely not static, so not usable
if (underCursor[underCursor.size()-1] != toChange.origin)
{
for (int i = 0;i<underCursor.size()-1;i++)
{
break;
DF.Resume();
w->TypeStr("v",100);
if (underCursor[i] == toChange.origin)
{
break;
}
}
}
}
DF.Resume();
w->TypeStr(commandString.c_str());
if(waitTillScreenState(DF,"viewscreen_customize_unit"))
{
DF.Resume();
w->TypeSpecial(DFHack::BACK_SPACE,eraseAmount);
if(waitTillChanged(DF,toChangeNum,"",isName))
w->TypeStr(commandString.c_str());
if (waitTillScreenState(DF,"viewscreen_customize_unit"))
{
DF.Resume();
w->TypeStr(changeString.c_str());
if(waitTillChanged(DF,toChangeNum,changeString,isName))
w->TypeSpecial(DFHack::BACK_SPACE,eraseAmount);
if (waitTillChanged(DF,toChangeNum,"",isName))
{
DF.Resume();
w->TypeSpecial(DFHack::ENTER);
w->TypeSpecial(DFHack::SPACE); // should take you to unit screen if everything worked
if(waitTillScreenState(DF,"viewscreen_unit"))
w->TypeStr(changeString.c_str());
if (waitTillChanged(DF,toChangeNum,changeString,isName))
{
DF.Resume();
w->TypeSpecial(DFHack::SPACE);
if(waitTillScreenState(DF,"viewscreen_dwarfmode"))
w->TypeSpecial(DFHack::ENTER);
w->TypeSpecial(DFHack::SPACE); // should take you to unit screen if everything worked
if (waitTillScreenState(DF,"viewscreen_unit"))
{
DF.Resume();
w->TypeSpecial(DFHack::SPACE);
if(waitTillCursorState(DF,false))
if (waitTillScreenState(DF,"viewscreen_dwarfmode"))
{
completed = true;
DF.Resume();
w->TypeSpecial(DFHack::SPACE);
if (waitTillCursorState(DF,false))
{
completed = true;
}
}
}
}
}
}
}
if (!completed) {
cerr << "Something went wrong, please reset DF to its original state, then press any key to continue" << endl;
goto start;
}
}
if(!completed){
cerr << "Something went wrong, please reset DF to its original state, then press any key to continue" << endl;
goto start;
else
{
// will only work with the shm probably should check for it, but I don't know how,
// I have the writeString function do nothing for normal mode
if (commandString == "pzyn") // change nickname
{
p->writeSTLString(toChange.origin+mem.getOffset("creature_nick_name"),changeString);
}
else
{
p->writeSTLString(toChange.origin+mem.getOffset("creature_custom_profession"),changeString);
}
}
DF.Suspend();
printDwarves(DF);

@ -2,7 +2,6 @@
SET(PROJECT_HDRS
DFCommonInternal.h
DFDataModel.h
DFHackAPI.h
DFMemInfo.h
DFMemInfoManager.h
@ -24,7 +23,6 @@ tinyxml/tinyxml.h
)
SET(PROJECT_SRCS
DFDataModel.cpp
DFMemInfo.cpp
DFMemInfoManager.cpp
DFHackAPI.cpp
@ -47,6 +45,7 @@ stdint_win.h
SET(PROJECT_SRCS_LINUX
DFProcess-linux.cpp
DFProcess-linux-SHM.cpp
DFProcess-linux-wine.cpp
DFWindow-linux.cpp
DFProcessEnumerator-linux.cpp
)

@ -92,7 +92,7 @@ namespace DFHack
#endif
#include "DFTypes.h"
#include "DFDataModel.h"
//#include "DFDataModel.h"
#include "DFProcess.h"
#include "DFWindow.h"
#include "DFProcessEnumerator.h"

@ -1,164 +0,0 @@
/*
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 "DFCommonInternal.h"
using namespace DFHack;
DfVector DMWindows40d::readVector (uint32_t offset, uint32_t item_size)
{
/*
MSVC++ vector is four pointers long
ptr allocator
ptr start
ptr end
ptr alloc_end
we don't care about alloc_end because we don't try to add stuff
we also don't care about the allocator thing in front
*/
uint32_t start = g_pProcess->readDWord(offset+4);
uint32_t end = g_pProcess->readDWord(offset+8);
uint32_t size = (end - start) /4;
return DfVector(start,size,item_size);
}
size_t DMWindows40d::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
{
/*
MSVC++ string
ptr allocator
union
{
char[16] start;
char * start_ptr
}
Uint32 length
Uint32 capacity
*/
uint32_t start_offset = offset + 4;
size_t length = g_pProcess->readDWord(offset + 20);
size_t capacity = g_pProcess->readDWord(offset + 24);
size_t read_real = min(length, bufcapacity-1);// keep space for null termination
// read data from inside the string structure
if(capacity < 16)
{
g_pProcess->read(start_offset, read_real , (uint8_t *)buffer);
}
else // read data from what the offset + 4 dword points to
{
start_offset = g_pProcess->readDWord(start_offset);// dereference the start offset
g_pProcess->read(start_offset, read_real, (uint8_t *)buffer);
}
buffer[read_real] = 0;
return read_real;
}
const string DMWindows40d::readSTLString (uint32_t offset)
{
/*
MSVC++ string
ptr allocator
union
{
char[16] start;
char * start_ptr
}
Uint32 length
Uint32 capacity
*/
uint32_t start_offset = offset + 4;
uint32_t length = g_pProcess->readDWord(offset + 20);
uint32_t capacity = g_pProcess->readDWord(offset + 24);
char * temp = new char[capacity+1];
// read data from inside the string structure
if(capacity < 16)
{
g_pProcess->read(start_offset, capacity, (uint8_t *)temp);
}
else // read data from what the offset + 4 dword points to
{
start_offset = g_pProcess->readDWord(start_offset);// dereference the start offset
g_pProcess->read(start_offset, capacity, (uint8_t *)temp);
}
temp[length] = 0;
string ret = temp;
delete temp;
return ret;
}
DfVector DMLinux40d::readVector (uint32_t offset, uint32_t item_size)
{
/*
GNU libstdc++ vector is three pointers long
ptr start
ptr end
ptr alloc_end
we don't care about alloc_end because we don't try to add stuff
*/
uint32_t start = g_pProcess->readDWord(offset);
uint32_t end = g_pProcess->readDWord(offset+4);
uint32_t size = (end - start) /4;
return DfVector(start,size,item_size);
}
struct _Rep_base
{
uint32_t _M_length;
uint32_t _M_capacity;
uint32_t _M_refcount;
};
size_t DMLinux40d::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
{
_Rep_base header;
offset = g_pProcess->readDWord(offset);
g_pProcess->read(offset - sizeof(_Rep_base),sizeof(_Rep_base),(uint8_t *)&header);
size_t read_real = min((size_t)header._M_length, bufcapacity-1);// keep space for null termination
g_pProcess->read(offset,read_real,(uint8_t * )buffer);
buffer[read_real] = 0;
return read_real;
}
const string DMLinux40d::readSTLString (uint32_t offset)
{
_Rep_base header;
offset = g_pProcess->readDWord(offset);
g_pProcess->read(offset - sizeof(_Rep_base),sizeof(_Rep_base),(uint8_t *)&header);
// FIXME: use char* everywhere, avoid string
char * temp = new char[header._M_length+1];
g_pProcess->read(offset,header._M_length+1,(uint8_t * )temp);
string ret(temp);
delete temp;
return ret;
}

@ -1,60 +0,0 @@
/*
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.
*/
#ifndef DATAMODEL_H_INCLUDED
#define DATAMODEL_H_INCLUDED
namespace DFHack
{
class DfVector;
// let's go pure virtual.
class DataModel
{
public:
// read a string
virtual const string readSTLString (uint32_t offset) = 0;
virtual size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) = 0;
// read a vector from memory
//template <class T>
virtual DfVector readVector (uint32_t offset, uint32_t item_size) = 0;
};
class DMWindows40d : public DataModel
{
virtual const string readSTLString (uint32_t offset);
virtual size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity);
// read a vector from memory
virtual DfVector readVector (uint32_t offset, uint32_t item_size);
};
class DMLinux40d : public DataModel
{
virtual const string readSTLString (uint32_t offset);
virtual size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity);
// read a vector from memory
virtual DfVector readVector (uint32_t offset, uint32_t item_size);
};
}
#endif // DATAMODEL_H_INCLUDED

@ -30,7 +30,7 @@ class API::Private
public:
Private()
: block (NULL)
, pm (NULL), p (NULL), dm (NULL), offset_descriptor (NULL)
, pm (NULL), p (NULL), offset_descriptor (NULL)
, p_cons (NULL), p_bld (NULL), p_veg (NULL)
{}
uint32_t * block;
@ -87,7 +87,6 @@ public:
ProcessEnumerator* pm;
Process* p;
DataModel* dm;
memory_info* offset_descriptor;
vector<uint16_t> v_geology[eBiomeCount];
string xml;
@ -265,7 +264,7 @@ bool API::WriteTileTypes (uint32_t x, uint32_t y, uint32_t z, uint16_t *buffer)
bool API::getCurrentCursorCreatures (vector<uint32_t> &addresses)
{
assert (d->cursorWindowInited);
DfVector creUnderCursor = d->dm->readVector (d->current_cursor_creature_offset, 4);
DfVector creUnderCursor = d->p->readVector (d->current_cursor_creature_offset, 4);
if (creUnderCursor.getSize() == 0)
{
return false;
@ -328,7 +327,7 @@ bool API::ReadVeins (uint32_t x, uint32_t y, uint32_t z, vector <t_vein> & veins
{
// veins are stored as a vector of pointers to veins
/*pointer is 4 bytes! we work with a 32bit program here, no matter what architecture we compile khazad for*/
DfVector p_veins = d->dm->readVector (addr + d->veinvector, 4);
DfVector p_veins = d->p->readVector (addr + d->veinvector, 4);
uint32_t size = p_veins.getSize();
veins.reserve (size);
@ -364,7 +363,7 @@ bool API::ReadWoodMatgloss (vector<t_matgloss> & woods)
int matgloss_address = d->offset_descriptor->getAddress ("matgloss");
int matgloss_wood_name_offset = d->offset_descriptor->getOffset("matgloss_wood_name");
// TODO: find flag for autumnal coloring?
DfVector p_matgloss = d->dm->readVector (matgloss_address, 4);
DfVector p_matgloss = d->p->readVector (matgloss_address, 4);
woods.clear();
@ -380,10 +379,10 @@ bool API::ReadWoodMatgloss (vector<t_matgloss> & woods)
uint32_t temp = * (uint32_t *) p_matgloss[i];
// read the string pointed at by
/*
fill_char_buf(mat.id, d->dm->readSTLString(temp)); // reads a C string given an address
fill_char_buf(mat.id, d->p->readSTLString(temp)); // reads a C string given an address
*/
d->dm->readSTLString (temp, mat.id, 128);
d->dm->readSTLString (temp+matgloss_wood_name_offset, mat.name, 128);
d->p->readSTLString (temp, mat.id, 128);
d->p->readSTLString (temp+matgloss_wood_name_offset, mat.name, 128);
woods.push_back (mat);
}
return true;
@ -397,7 +396,7 @@ bool API::ReadStoneMatgloss (vector<t_matgloss> & stones)
int matgloss_colors = minfo->getOffset ("matgloss_stone_color");
int matgloss_stone_name_offset = minfo->getOffset("matgloss_stone_name");
DfVector p_matgloss = d->dm->readVector (matgloss_address + matgloss_offset, 4);
DfVector p_matgloss = d->p->readVector (matgloss_address + matgloss_offset, 4);
uint32_t size = p_matgloss.getSize();
stones.resize (0);
@ -408,9 +407,9 @@ bool API::ReadStoneMatgloss (vector<t_matgloss> & stones)
uint32_t temp = * (uint32_t *) p_matgloss[i];
// read the string pointed at by
t_matgloss mat;
//fill_char_buf(mat.id, d->dm->readSTLString(temp)); // reads a C string given an address
d->dm->readSTLString (temp, mat.id, 128);
d->dm->readSTLString (temp+matgloss_stone_name_offset, mat.name, 128);
//fill_char_buf(mat.id, d->p->readSTLString(temp)); // reads a C string given an address
d->p->readSTLString (temp, mat.id, 128);
d->p->readSTLString (temp+matgloss_stone_name_offset, mat.name, 128);
mat.fore = (uint8_t) g_pProcess->readWord (temp + matgloss_colors);
mat.back = (uint8_t) g_pProcess->readWord (temp + matgloss_colors + 2);
mat.bright = (uint8_t) g_pProcess->readWord (temp + matgloss_colors + 4);
@ -427,7 +426,7 @@ bool API::ReadMetalMatgloss (vector<t_matgloss> & metals)
int matgloss_offset = minfo->getHexValue ("matgloss_skip");
int matgloss_colors = minfo->getOffset ("matgloss_metal_color");
int matgloss_metal_name_offset = minfo->getOffset("matgloss_metal_name");
DfVector p_matgloss = d->dm->readVector (matgloss_address + matgloss_offset * 3, 4);
DfVector p_matgloss = d->p->readVector (matgloss_address + matgloss_offset * 3, 4);
metals.clear();
@ -437,9 +436,9 @@ bool API::ReadMetalMatgloss (vector<t_matgloss> & metals)
uint32_t temp = * (uint32_t *) p_matgloss[i];
// read the string pointed at by
t_matgloss mat;
//fill_char_buf(mat.id, d->dm->readSTLString(temp)); // reads a C string given an address
d->dm->readSTLString (temp, mat.id, 128);
d->dm->readSTLString (temp+matgloss_metal_name_offset, mat.name, 128);
//fill_char_buf(mat.id, d->p->readSTLString(temp)); // reads a C string given an address
d->p->readSTLString (temp, mat.id, 128);
d->p->readSTLString (temp+matgloss_metal_name_offset, mat.name, 128);
mat.fore = (uint8_t) g_pProcess->readWord (temp + matgloss_colors);
mat.back = (uint8_t) g_pProcess->readWord (temp + matgloss_colors + 2);
mat.bright = (uint8_t) g_pProcess->readWord (temp + matgloss_colors + 4);
@ -454,7 +453,7 @@ bool API::ReadPlantMatgloss (vector<t_matgloss> & plants)
int matgloss_address = minfo->getAddress ("matgloss");
int matgloss_offset = minfo->getHexValue ("matgloss_skip");
int matgloss_plant_name_offset = minfo->getOffset("matgloss_plant_name");
DfVector p_matgloss = d->dm->readVector (matgloss_address + matgloss_offset * 2, 4);
DfVector p_matgloss = d->p->readVector (matgloss_address + matgloss_offset * 2, 4);
plants.clear();
@ -468,9 +467,9 @@ bool API::ReadPlantMatgloss (vector<t_matgloss> & plants)
// read the matgloss pointer from the vector into temp
uint32_t temp = * (uint32_t *) p_matgloss[i];
// read the string pointed at by
//fill_char_buf(mat.id, d->dm->readSTLString(temp)); // reads a C string given an address
d->dm->readSTLString (temp, mat.id, 128);
d->dm->readSTLString (temp+matgloss_plant_name_offset, mat.name, 128);
//fill_char_buf(mat.id, d->p->readSTLString(temp)); // reads a C string given an address
d->p->readSTLString (temp, mat.id, 128);
d->p->readSTLString (temp+matgloss_plant_name_offset, mat.name, 128);
plants.push_back (mat);
}
return true;
@ -485,7 +484,7 @@ bool API::ReadPlantMatgloss (vector<t_matglossPlant> & plants)
int matgloss_plant_drink_offset = minfo->getOffset("matgloss_plant_drink");
int matgloss_plant_food_offset = minfo->getOffset("matgloss_plant_food");
int matgloss_plant_extract_offset = minfo->getOffset("matgloss_plant_extract");
DfVector p_matgloss = d->dm->readVector (matgloss_address + matgloss_offset * 2, 4);
DfVector p_matgloss = d->p->readVector (matgloss_address + matgloss_offset * 2, 4);
plants.clear();
@ -499,14 +498,14 @@ bool API::ReadPlantMatgloss (vector<t_matglossPlant> & plants)
// read the matgloss pointer from the vector into temp
uint32_t temp = * (uint32_t *) p_matgloss[i];
// read the string pointed at by
//fill_char_buf(mat.id, d->dm->readSTLString(temp)); // reads a C string given an address
d->dm->readSTLString (temp, mat.id, 128);
d->dm->readSTLString (temp+matgloss_plant_name_offset, mat.name, 128);
d->dm->readSTLString (temp+matgloss_plant_drink_offset, mat.drink_name, 128);
d->dm->readSTLString (temp+matgloss_plant_food_offset, mat.food_name, 128);
d->dm->readSTLString (temp+matgloss_plant_extract_offset, mat.extract_name, 128);
//fill_char_buf(mat.id, d->p->readSTLString(temp)); // reads a C string given an address
d->p->readSTLString (temp, mat.id, 128);
d->p->readSTLString (temp+matgloss_plant_name_offset, mat.name, 128);
d->p->readSTLString (temp+matgloss_plant_drink_offset, mat.drink_name, 128);
d->p->readSTLString (temp+matgloss_plant_food_offset, mat.food_name, 128);
d->p->readSTLString (temp+matgloss_plant_extract_offset, mat.extract_name, 128);
//d->dm->readSTLString (temp
//d->p->readSTLString (temp
plants.push_back (mat);
}
return true;
@ -518,7 +517,7 @@ bool API::ReadCreatureMatgloss (vector<t_matgloss> & creatures)
int matgloss_address = minfo->getAddress ("matgloss");
int matgloss_offset = minfo->getHexValue ("matgloss_skip");
int matgloss_creature_name_offset = minfo->getOffset("matgloss_creature_name");
DfVector p_matgloss = d->dm->readVector (matgloss_address + matgloss_offset * 6, 4);
DfVector p_matgloss = d->p->readVector (matgloss_address + matgloss_offset * 6, 4);
creatures.clear();
@ -532,9 +531,9 @@ bool API::ReadCreatureMatgloss (vector<t_matgloss> & creatures)
// read the matgloss pointer from the vector into temp
uint32_t temp = * (uint32_t *) p_matgloss[i];
// read the string pointed at by
//fill_char_buf(mat.id, d->dm->readSTLString(temp)); // reads a C string given an address
d->dm->readSTLString (temp, mat.id, 128);
d->dm->readSTLString (temp+matgloss_creature_name_offset, mat.name, 128);
//fill_char_buf(mat.id, d->p->readSTLString(temp)); // reads a C string given an address
d->p->readSTLString (temp, mat.id, 128);
d->p->readSTLString (temp+matgloss_creature_name_offset, mat.name, 128);
creatures.push_back (mat);
}
return true;
@ -587,7 +586,7 @@ bool API::ReadGeology (vector < vector <uint16_t> >& assign)
uint32_t regions = g_pProcess->readDWord (world_offset + world_regions_offset);
// read the geoblock vector
DfVector geoblocks = d->dm->readVector (world_offset + world_geoblocks_offset, 4);
DfVector geoblocks = d->p->readVector (world_offset + world_geoblocks_offset, 4);
// iterate over 8 surrounding regions + local region
for (int i = eNorthWest; i < eBiomeCount; i++)
@ -613,7 +612,7 @@ bool API::ReadGeology (vector < vector <uint16_t> >& assign)
uint32_t geoblock_off = * (uint32_t *) geoblocks[geoindex];
// get the vector with pointer to layers
DfVector geolayers = d->dm->readVector (geoblock_off + geolayer_geoblock_offset , 4); // let's hope
DfVector geolayers = d->p->readVector (geoblock_off + geolayer_geoblock_offset , 4); // let's hope
// make sure we don't load crap
assert (geolayers.getSize() > 0 && geolayers.getSize() <= 16);
@ -645,7 +644,7 @@ bool API::InitReadBuildings ( uint32_t& numbuildings )
if(buildings)
{
d->buildingsInited = true;
d->p_bld = new DfVector (d->dm->readVector (buildings, 4));
d->p_bld = new DfVector (d->p->readVector (buildings, 4));
return true;
}
else
@ -703,7 +702,7 @@ bool API::InitReadConstructions(uint32_t & numconstructions)
int constructions = d->offset_descriptor->getAddress ("constructions");
if(constructions)
{
d->p_cons = new DfVector (d->dm->readVector (constructions, 4));
d->p_cons = new DfVector (d->p->readVector (constructions, 4));
d->constructionsInited = true;
numconstructions = d->p_cons->getSize();
return true;
@ -753,7 +752,7 @@ bool API::InitReadVegetation(uint32_t & numplants)
if(vegetation && d->tree_offset)
{
d->vegetationInited = true;
d->p_veg = new DfVector (d->dm->readVector (vegetation, 4));
d->p_veg = new DfVector (d->p->readVector (vegetation, 4));
numplants = d->p_veg->getSize();
return true;
}
@ -840,7 +839,7 @@ bool API::InitReadCreatures( uint32_t &numcreatures )
// && d->creature_likes_offset
)
{
d->p_cre = new DfVector (d->dm->readVector (creatures, 4));
d->p_cre = new DfVector (d->p->readVector (creatures, 4));
//InitReadNameTables();
d->creaturesInited = true;
numcreatures = d->p_cre->getSize();
@ -925,11 +924,11 @@ bool API::ReadCreature (const int32_t &index, t_creature & furball)
g_pProcess->readDWord (temp + d->creature_flags1_offset, furball.flags1.whole);
g_pProcess->readDWord (temp + d->creature_flags2_offset, furball.flags2.whole);
// normal names
d->dm->readSTLString (temp + d->creature_first_name_offset, furball.first_name, 128);
d->dm->readSTLString (temp + d->creature_nick_name_offset, furball.nick_name, 128);
d->p->readSTLString (temp + d->creature_first_name_offset, furball.first_name, 128);
d->p->readSTLString (temp + d->creature_nick_name_offset, furball.nick_name, 128);
// custom profession
d->dm->readSTLString (temp + d->creature_nick_name_offset, furball.nick_name, 128);
fill_char_buf (furball.custom_profession, d->dm->readSTLString (temp + d->creature_custom_profession_offset));
d->p->readSTLString (temp + d->creature_nick_name_offset, furball.nick_name, 128);
fill_char_buf (furball.custom_profession, d->p->readSTLString (temp + d->creature_custom_profession_offset));
// crazy composited names
g_pProcess->read (temp + d->creature_last_name_offset, sizeof (t_lastname), (uint8_t *) &furball.last_name);
g_pProcess->read (temp + d->creature_squad_name_offset, sizeof (t_squadname), (uint8_t *) &furball.squad_name);
@ -941,7 +940,7 @@ bool API::ReadCreature (const int32_t &index, t_creature & furball)
// traits
g_pProcess->read (temp + d->creature_traits_offset, sizeof (uint16_t) * NUM_CREATURE_TRAITS, (uint8_t *) &furball.traits);
// learned skills
DfVector skills (d->dm->readVector (temp + d->creature_skills_offset, 4));
DfVector skills (d->p->readVector (temp + d->creature_skills_offset, 4));
furball.numSkills = skills.getSize();
for (uint32_t i = 0; i < furball.numSkills;i++)
{
@ -963,7 +962,7 @@ bool API::ReadCreature (const int32_t &index, t_creature & furball)
}
//likes
DfVector likes(d->dm->readVector(temp+d->creature_likes_offset,4));
DfVector likes(d->p->readVector(temp+d->creature_likes_offset,4));
furball.numLikes = likes.getSize();
for(uint32_t i = 0;i<furball.numLikes;i++)
{
@ -996,25 +995,25 @@ bool API::InitReadNameTables (map< string, vector<string> > & nameTable)
if(genericAddress && transAddress && word_table_offset)
{
DfVector genericVec (d->dm->readVector (genericAddress, 4));
DfVector transVec (d->dm->readVector (transAddress, 4));
DfVector genericVec (d->p->readVector (genericAddress, 4));
DfVector transVec (d->p->readVector (transAddress, 4));
for (uint32_t i = 0;i < genericVec.getSize();i++)
{
uint32_t genericNamePtr = * (uint32_t *) genericVec.at (i);
string genericName = d->dm->readSTLString (genericNamePtr);
string genericName = d->p->readSTLString (genericNamePtr);
nameTable["GENERIC"].push_back (genericName);
}
for (uint32_t i = 0; i < transVec.getSize();i++)
{
uint32_t transPtr = * (uint32_t *) transVec.at (i);
string transName = d->dm->readSTLString (transPtr);
DfVector trans_names_vec (d->dm->readVector (transPtr + word_table_offset, 4));
string transName = d->p->readSTLString (transPtr);
DfVector trans_names_vec (d->p->readVector (transPtr + word_table_offset, 4));
for (uint32_t j = 0;j < trans_names_vec.getSize();j++)
{
uint32_t transNamePtr = * (uint32_t *) trans_names_vec.at (j);
string name = d->dm->readSTLString (transNamePtr);
string name = d->p->readSTLString (transNamePtr);
nameTable[transName].push_back (name);
}
}
@ -1113,7 +1112,6 @@ bool API::Attach()
return false; // couldn't attach to process, no go
}
d->offset_descriptor = d->p->getDescriptor();
d->dm = d->p->getDataModel();
// process is attached, everything went just fine... hopefully
return true;
}
@ -1132,13 +1130,12 @@ bool API::Detach()
d->pm = NULL;
d->p = NULL;
d->offset_descriptor = NULL;
d->dm = NULL;
return true;
}
bool API::isAttached()
{
return d->dm != NULL;
return d->p != NULL;
}
bool API::Suspend()
@ -1290,7 +1287,7 @@ bool API::InitReadItems(uint32_t & numitems)
if(items && d->item_material_offset)
{
d->p_itm = new DfVector (d->dm->readVector (items, 4));
d->p_itm = new DfVector (d->p->readVector (items, 4));
d->itemsInited = true;
numitems = d->p_itm->getSize();
return true;
@ -1304,7 +1301,7 @@ bool API::InitReadItems(uint32_t & numitems)
}
bool API::ReadItem (const uint32_t &index, t_item & item)
{
assert (d->buildingsInited && d->itemsInited); //should change to the generic init rather than buildings
assert (d->itemsInited); //should change to the generic init rather than buildings
t_item_df40d item_40d;
// read pointer from vector at position
@ -1375,15 +1372,15 @@ bool API::ReadItemTypes(vector< vector< t_itemType > > & itemTypes)
int matgloss_skip = minfo->getHexValue("matgloss_skip");
int item_type_name_offset = minfo->getOffset("item_type_name");
for(int i = 8;i<20;i++){
DfVector p_temp = d->dm->readVector(matgloss_address + i*matgloss_skip,4);
DfVector p_temp = d->p->readVector(matgloss_address + i*matgloss_skip,4);
vector< t_itemType > typesForVec;
for(uint32_t j =0; j<p_temp.getSize();j++)
{
t_itemType currType;
uint32_t temp = *(uint32_t *) p_temp[j];
// Mread(temp+40,sizeof(name),(uint8_t *) name);
d->dm->readSTLString(temp+4,currType.id,128);
d->dm->readSTLString(temp+item_type_name_offset,currType.name,128);
d->p->readSTLString(temp+4,currType.id,128);
d->p->readSTLString(temp+item_type_name_offset,currType.name,128);
//stringsForVec.push_back(string(name));
typesForVec.push_back(currType);
}
@ -1400,44 +1397,44 @@ bool API::ReadAllMatgloss(vector< vector< string > > & all)
int matgloss_address = minfo->getAddress("matgloss");
int matgloss_skip = minfo->getHexValue("matgloss_skip");
for(int i = 0;i<7;i++){
DfVector p_temp = d->dm->readVector(matgloss_address + i*matgloss_skip,4);
DfVector p_temp = d->p->readVector(matgloss_address + i*matgloss_skip,4);
vector< string > stringsForVec;
for(uint32_t j =0; j<p_temp.getSize();j++)
{
uint32_t temp = *(uint32_t *) p_temp[j];
string tempStr = d->dm->readSTLString(temp);
string tempStr = d->p->readSTLString(temp);
stringsForVec.push_back(tempStr);
}
all.push_back(stringsForVec);
}
for(int i = 7;i<22;i++){
DfVector p_temp = d->dm->readVector(matgloss_address + i*matgloss_skip,4);
DfVector p_temp = d->p->readVector(matgloss_address + i*matgloss_skip,4);
vector< string > stringsForVec;
for(uint32_t j =0; j<p_temp.getSize();j++)
{
uint32_t temp = *(uint32_t *) p_temp[j];
string tempStr = d->dm->readSTLString(temp+4);
string tempStr = d->p->readSTLString(temp+4);
stringsForVec.push_back(tempStr);
}
all.push_back(stringsForVec);
}
for(int i = 22;i<25;i++){
DfVector p_temp = d->dm->readVector(matgloss_address + i*matgloss_skip,4);
DfVector p_temp = d->p->readVector(matgloss_address + i*matgloss_skip,4);
vector< string > stringsForVec;
for(uint32_t j =0; j<p_temp.getSize();j++)
{
uint32_t temp = *(uint32_t *) p_temp[j];
string tempStr = d->dm->readSTLString(temp);
string tempStr = d->p->readSTLString(temp);
stringsForVec.push_back(tempStr);
}
all.push_back(stringsForVec);
}
DfVector p_temp = d->dm->readVector(0x01604104,4);
DfVector p_temp = d->p->readVector(0x01604104,4);
vector< string > stringsForVec;
for(uint32_t j =0; j<p_temp.getSize();j++)
{
uint32_t temp = *(uint32_t *) p_temp[j];
string tempStr = d->dm->readSTLString(temp);
string tempStr = d->p->readSTLString(temp);
stringsForVec.push_back(tempStr);
}
all.push_back(stringsForVec);

@ -40,7 +40,6 @@ class SHMProcess::Private
public:
Private()
{
my_datamodel = NULL;
my_descriptor = NULL;
my_pid = 0;
my_shm = 0;
@ -51,7 +50,6 @@ class SHMProcess::Private
identified = false;
};
~Private(){};
DataModel* my_datamodel;
memory_info * my_descriptor;
DFWindow * my_window;
pid_t my_pid;
@ -229,7 +227,6 @@ bool SHMProcess::Private::validate(char * exe_file, uint32_t pid, vector <memory
if(hash == (*it).getString("md5")) // are the md5 hashes the same?
{
memory_info * m = &*it;
my_datamodel = new DMLinux40d();
my_descriptor = m;
my_pid = pid;
identified = true;
@ -247,10 +244,6 @@ SHMProcess::~SHMProcess()
detach();
}
// destroy data model. this is assigned by processmanager
if(d->my_datamodel)
{
delete d->my_datamodel;
}
if(d->my_window)
{
delete d->my_window;
@ -262,12 +255,6 @@ SHMProcess::~SHMProcess()
delete d;
}
DataModel *SHMProcess::getDataModel()
{
return d->my_datamodel;
}
memory_info * SHMProcess::getDescriptor()
{
return d->my_descriptor;
@ -603,3 +590,50 @@ const std::string SHMProcess::readCString (uint32_t offset)
return temp;
}
DfVector SHMProcess::readVector (uint32_t offset, uint32_t item_size)
{
/*
GNU libstdc++ vector is three pointers long
ptr start
ptr end
ptr alloc_end
we don't care about alloc_end because we don't try to add stuff
*/
uint32_t start = g_pProcess->readDWord(offset);
uint32_t end = g_pProcess->readDWord(offset+4);
uint32_t size = (end - start) /4;
return DfVector(start,size,item_size);
}
const std::string SHMProcess::readSTLString(uint32_t offset)
{
((shm_read_small *)d->my_shm)->address = offset;
full_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_STL_STRING;
d->waitWhile(DFPP_READ_STL_STRING);
//int length = ((shm_retval *)d->my_shm)->value;
return(string( (char *)d->my_shm+SHM_HEADER));
}
size_t SHMProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
{
((shm_read_small *)d->my_shm)->address = offset;
full_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_STL_STRING;
d->waitWhile(DFPP_READ_STL_STRING);
size_t length = ((shm_retval *)d->my_shm)->value;
size_t fit = min(bufcapacity - 1, length);
strncpy(buffer,(char *)d->my_shm+SHM_HEADER,fit);
buffer[fit] = 0;
return fit;
}
void SHMProcess::writeSTLString(const uint32_t address, const std::string writeString)
{
((shm_write_small *)d->my_shm)->address = address;
strncpy(d->my_shm+SHM_HEADER,writeString.c_str(),writeString.length()+1); // length + 1 for the null terminator
full_barrier
((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_STL_STRING;
d->waitWhile(DFPP_WRITE_STL_STRING);
}

@ -0,0 +1,584 @@
/*
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 "DFCommonInternal.h"
#include <errno.h>
#include <sys/ptrace.h>
using namespace DFHack;
class WineProcess::Private
{
public:
Private()
{
my_descriptor = NULL;
my_handle = NULL;
my_window = NULL;
my_pid = 0;
attached = false;
suspended = false;
memFileHandle = 0;
};
~Private(){};
DFWindow* my_window;
memory_info * my_descriptor;
ProcessHandle my_handle;
uint32_t my_pid;
string memFile;
int memFileHandle;
bool attached;
bool suspended;
bool identified;
bool validate(char * exe_file, uint32_t pid, char * mem_file, vector <memory_info> & known_versions);
};
WineProcess::WineProcess(uint32_t pid, vector <memory_info> & known_versions)
: d(new Private())
{
char dir_name [256];
char exe_link_name [256];
char mem_name [256];
char cwd_name [256];
char cmdline_name [256];
char target_name[1024];
int target_result;
d->identified = false;
sprintf(dir_name,"/proc/%d/", pid);
sprintf(exe_link_name,"/proc/%d/exe", pid);
sprintf(mem_name,"/proc/%d/mem", pid);
sprintf(cwd_name,"/proc/%d/cwd", pid);
sprintf(cmdline_name,"/proc/%d/cmdline", pid);
// resolve /proc/PID/exe link
target_result = readlink(exe_link_name, target_name, sizeof(target_name)-1);
if (target_result == -1)
{
return;
}
// make sure we have a null terminated string...
target_name[target_result] = 0;
// is this the regular linux DF?
if (strstr(target_name, "dwarfort.exe") != NULL)
{
// create linux process, add it to the vector
d->identified = d->validate(target_name,pid,mem_name,known_versions );
d->my_window = new DFWindow(this);
return;
}
// FIXME: this fails when the wine process isn't started from the 'current working directory'. strip path data from cmdline
// is this windows version of Df running in wine?
if(strstr(target_name, "wine-preloader")!= NULL)
{
// get working directory
target_result = readlink(cwd_name, target_name, sizeof(target_name)-1);
target_name[target_result] = 0;
// got path to executable, do the same for its name
ifstream ifs ( cmdline_name , ifstream::in );
string cmdline;
getline(ifs,cmdline);
if (cmdline.find("dwarfort-w.exe") != string::npos || cmdline.find("dwarfort.exe") != string::npos || cmdline.find("Dwarf Fortress.exe") != string::npos)
{
char exe_link[1024];
// put executable name and path together
sprintf(exe_link,"%s/%s",target_name,cmdline.c_str());
// create wine process, add it to the vector
d->identified = d->validate(exe_link,pid,mem_name,known_versions);
d->my_window = new DFWindow(this);
return;
}
}
}
bool WineProcess::isSuspended()
{
return d->suspended;
}
bool WineProcess::isAttached()
{
return d->attached;
}
bool WineProcess::isIdentified()
{
return d->identified;
}
bool WineProcess::Private::validate(char * exe_file,uint32_t pid, char * memFile, vector <memory_info> & known_versions)
{
md5wrapper md5;
// get hash of the running DF process
string hash = md5.getHashFromFile(exe_file);
vector<memory_info>::iterator it;
// iterate over the list of memory locations
for ( it=known_versions.begin() ; it < known_versions.end(); it++ )
{
// are the md5 hashes the same?
if(memory_info::OS_WINDOWS == (*it).getOS() && hash == (*it).getString("md5"))
{
memory_info * m = &*it;
my_descriptor = m;
my_handle = my_pid = pid;
// tell WineProcess about the /proc/PID/mem file
this->memFile = memFile;
identified = true;
return true;
}
}
return false;
}
WineProcess::~WineProcess()
{
if(d->attached)
{
detach();
}
if(d->my_window)
delete d->my_window;
delete d;
}
memory_info * WineProcess::getDescriptor()
{
return d->my_descriptor;
}
DFWindow * WineProcess::getWindow()
{
return d->my_window;
}
int WineProcess::getPID()
{
return d->my_pid;
}
//FIXME: implement
bool WineProcess::getThreadIDs(vector<uint32_t> & threads )
{
return false;
}
//FIXME: cross-reference with ELF segment entries?
void WineProcess::getMemRanges( vector<t_memrange> & ranges )
{
char buffer[1024];
char permissions[5]; // r/-, w/-, x/-, p/s, 0
sprintf(buffer, "/proc/%lu/maps", d->my_pid);
FILE *mapFile = ::fopen(buffer, "r");
uint64_t offset, device1, device2, node;
while (fgets(buffer, 1024, mapFile))
{
t_memrange temp;
temp.name[0] = 0;
sscanf(buffer, "%llx-%llx %s %llx %2llu:%2llu %llu %s",
&temp.start,
&temp.end,
(char*)&permissions,
&offset, &device1, &device2, &node,
(char*)&temp.name);
temp.read = permissions[0] == 'r';
temp.write = permissions[1] == 'w';
temp.execute = permissions[2] == 'x';
ranges.push_back(temp);
}
}
bool WineProcess::asyncSuspend()
{
return suspend();
}
bool WineProcess::suspend()
{
int status;
if(!d->attached)
return false;
if(d->suspended)
return true;
if (kill(d->my_handle, SIGSTOP) == -1)
{
// no, we got an error
perror("kill SIGSTOP error");
return false;
}
while(true)
{
// we wait on the pid
pid_t w = waitpid(d->my_handle, &status, 0);
if (w == -1)
{
// child died
perror("DF exited during suspend call");
return false;
}
// stopped -> let's continue
if (WIFSTOPPED(status))
{
break;
}
}
d->suspended = true;
return true;
}
bool WineProcess::forceresume()
{
return resume();
}
bool WineProcess::resume()
{
if(!d->attached)
return false;
if(!d->suspended)
return true;
if (ptrace(PTRACE_CONT, d->my_handle, NULL, NULL) == -1)
{
// no, we got an error
perror("ptrace resume error");
return false;
}
d->suspended = false;
return true;
}
bool WineProcess::attach()
{
int status;
if(g_pProcess != NULL)
{
return false;
}
// can we attach?
if (ptrace(PTRACE_ATTACH , d->my_handle, NULL, NULL) == -1)
{
// no, we got an error
perror("ptrace attach error");
cerr << "attach failed on pid " << d->my_handle << endl;
return false;
}
while(true)
{
// we wait on the pid
pid_t w = waitpid(d->my_handle, &status, 0);
if (w == -1)
{
// child died
perror("wait inside attach()");
return false;
}
// stopped -> let's continue
if (WIFSTOPPED(status))
{
break;
}
}
d->suspended = true;
int proc_pid_mem = open(d->memFile.c_str(),O_RDONLY);
if(proc_pid_mem == -1)
{
ptrace(PTRACE_DETACH, d->my_handle, NULL, NULL);
cerr << "couldn't open /proc/" << d->my_handle << "/mem" << endl;
perror("open(memFile.c_str(),O_RDONLY)");
return false;
}
else
{
d->attached = true;
g_pProcess = this;
d->memFileHandle = proc_pid_mem;
return true; // we are attached
}
}
bool WineProcess::detach()
{
if(!d->attached) return false;
if(!d->suspended) suspend();
int result = 0;
// close /proc/PID/mem
result = close(d->memFileHandle);
if(result == -1)
{
cerr << "couldn't close /proc/"<< d->my_handle <<"/mem" << endl;
perror("mem file close");
return false;
}
else
{
// detach
result = ptrace(PTRACE_DETACH, d->my_handle, NULL, NULL);
if(result == -1)
{
cerr << "couldn't detach from process pid" << d->my_handle << endl;
perror("ptrace detach");
return false;
}
else
{
d->attached = false;
g_pProcess = NULL;
return true;
}
}
}
// danger: uses recursion!
void WineProcess::read (const uint32_t offset, const uint32_t size, uint8_t *target)
{
if(size == 0) return;
ssize_t result;
result = pread(d->memFileHandle, target,size,offset);
if(result != size)
{
if(result == -1)
{
cerr << "pread failed: can't read " << size << " bytes at addres " << offset << endl;
cerr << "errno: " << errno << endl;
errno = 0;
}
else
{
read(offset + result, size - result, target + result);
}
}
}
uint8_t WineProcess::readByte (const uint32_t offset)
{
uint8_t val;
read(offset, 1, &val);
return val;
}
void WineProcess::readByte (const uint32_t offset, uint8_t &val )
{
read(offset, 1, &val);
}
uint16_t WineProcess::readWord (const uint32_t offset)
{
uint16_t val;
read(offset, 2, (uint8_t *) &val);
return val;
}
void WineProcess::readWord (const uint32_t offset, uint16_t &val)
{
read(offset, 2, (uint8_t *) &val);
}
uint32_t WineProcess::readDWord (const uint32_t offset)
{
uint32_t val;
read(offset, 4, (uint8_t *) &val);
return val;
}
void WineProcess::readDWord (const uint32_t offset, uint32_t &val)
{
read(offset, 4, (uint8_t *) &val);
}
/*
* WRITING
*/
void WineProcess::writeDWord (uint32_t offset, uint32_t data)
{
ptrace(PTRACE_POKEDATA,d->my_handle, offset, data);
}
// using these is expensive.
void WineProcess::writeWord (uint32_t offset, uint16_t data)
{
uint32_t orig = readDWord(offset);
orig &= 0xFFFF0000;
orig |= data;
/*
orig |= 0x0000FFFF;
orig &= data;
*/
ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig);
}
void WineProcess::writeByte (uint32_t offset, uint8_t data)
{
uint32_t orig = readDWord(offset);
orig &= 0xFFFFFF00;
orig |= data;
/*
orig |= 0x000000FF;
orig &= data;
*/
ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig);
}
// blah. I hate the kernel devs for crippling /proc/PID/mem. THIS IS RIDICULOUS
void WineProcess::write (uint32_t offset, uint32_t size, uint8_t *source)
{
uint32_t indexptr = 0;
while (size > 0)
{
// default: we push 4 bytes
if(size >= 4)
{
writeDWord(offset, *(uint32_t *) (source + indexptr));
offset +=4;
indexptr +=4;
size -=4;
}
// last is either three or 2 bytes
else if(size >= 2)
{
writeWord(offset, *(uint16_t *) (source + indexptr));
offset +=2;
indexptr +=2;
size -=2;
}
// finishing move
else if(size == 1)
{
writeByte(offset, *(uint8_t *) (source + indexptr));
return;
}
}
}
const std::string WineProcess::readCString (uint32_t offset)
{
std::string temp;
char temp_c[256];
int counter = 0;
char r;
do
{
r = readByte(offset+counter);
temp_c[counter] = r;
counter++;
} while (r && counter < 255);
temp_c[counter] = 0;
temp = temp_c;
return temp;
}
DfVector WineProcess::readVector (uint32_t offset, uint32_t item_size)
{
/*
MSVC++ vector is four pointers long
ptr allocator
ptr start
ptr end
ptr alloc_end
we don't care about alloc_end because we don't try to add stuff
we also don't care about the allocator thing in front
*/
uint32_t start = g_pProcess->readDWord(offset+4);
uint32_t end = g_pProcess->readDWord(offset+8);
uint32_t size = (end - start) /4;
return DfVector(start,size,item_size);
}
size_t WineProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
{
/*
MSVC++ string
ptr allocator
union
{
char[16] start;
char * start_ptr
}
Uint32 length
Uint32 capacity
*/
uint32_t start_offset = offset + 4;
size_t length = g_pProcess->readDWord(offset + 20);
size_t capacity = g_pProcess->readDWord(offset + 24);
size_t read_real = min(length, bufcapacity-1);// keep space for null termination
// read data from inside the string structure
if(capacity < 16)
{
g_pProcess->read(start_offset, read_real , (uint8_t *)buffer);
}
else // read data from what the offset + 4 dword points to
{
start_offset = g_pProcess->readDWord(start_offset);// dereference the start offset
g_pProcess->read(start_offset, read_real, (uint8_t *)buffer);
}
buffer[read_real] = 0;
return read_real;
}
const string WineProcess::readSTLString (uint32_t offset)
{
/*
MSVC++ string
ptr allocator
union
{
char[16] start;
char * start_ptr
}
Uint32 length
Uint32 capacity
*/
uint32_t start_offset = offset + 4;
uint32_t length = g_pProcess->readDWord(offset + 20);
uint32_t capacity = g_pProcess->readDWord(offset + 24);
char * temp = new char[capacity+1];
// read data from inside the string structure
if(capacity < 16)
{
g_pProcess->read(start_offset, capacity, (uint8_t *)temp);
}
else // read data from what the offset + 4 dword points to
{
start_offset = g_pProcess->readDWord(start_offset);// dereference the start offset
g_pProcess->read(start_offset, capacity, (uint8_t *)temp);
}
temp[length] = 0;
string ret = temp;
delete temp;
return ret;
}

@ -31,7 +31,6 @@ class NormalProcess::Private
public:
Private()
{
my_datamodel = NULL;
my_descriptor = NULL;
my_handle = NULL;
my_window = NULL;
@ -41,7 +40,6 @@ class NormalProcess::Private
memFileHandle = 0;
};
~Private(){};
DataModel* my_datamodel;
DFWindow* my_window;
memory_info * my_descriptor;
ProcessHandle my_handle;
@ -90,31 +88,6 @@ NormalProcess::NormalProcess(uint32_t pid, vector <memory_info> & known_versions
d->my_window = new DFWindow(this);
return;
}
// FIXME: this fails when the wine process isn't started from the 'current working directory'. strip path data from cmdline
// is this windows version of Df running in wine?
if(strstr(target_name, "wine-preloader")!= NULL)
{
// get working directory
target_result = readlink(cwd_name, target_name, sizeof(target_name)-1);
target_name[target_result] = 0;
// got path to executable, do the same for its name
ifstream ifs ( cmdline_name , ifstream::in );
string cmdline;
getline(ifs,cmdline);
if (cmdline.find("dwarfort-w.exe") != string::npos || cmdline.find("dwarfort.exe") != string::npos || cmdline.find("Dwarf Fortress.exe") != string::npos)
{
char exe_link[1024];
// put executable name and path together
sprintf(exe_link,"%s/%s",target_name,cmdline.c_str());
// create wine process, add it to the vector
d->identified = d->validate(exe_link,pid,mem_name,known_versions);
d->my_window = new DFWindow(this);
return;
}
}
}
bool NormalProcess::isSuspended()
@ -144,16 +117,8 @@ bool NormalProcess::Private::validate(char * exe_file,uint32_t pid, char * memFi
if(hash == (*it).getString("md5")) // are the md5 hashes the same?
{
memory_info * m = &*it;
// df can run under wine on Linux
if(memory_info::OS_WINDOWS == (*it).getOS())
if (memory_info::OS_LINUX == (*it).getOS())
{
my_datamodel =new DMWindows40d();
my_descriptor = m;
my_handle = my_pid = pid;
}
else if (memory_info::OS_LINUX == (*it).getOS())
{
my_datamodel =new DMLinux40d();
my_descriptor = m;
my_handle = my_pid = pid;
}
@ -178,19 +143,11 @@ NormalProcess::~NormalProcess()
detach();
}
// destroy data model. this is assigned by processmanager
if(d->my_datamodel)
delete d->my_datamodel;
if(d->my_window)
delete d->my_window;
delete d;
}
DataModel *NormalProcess::getDataModel()
{
return d->my_datamodel;
}
memory_info * NormalProcess::getDescriptor()
{
return d->my_descriptor;
@ -522,3 +479,51 @@ const std::string NormalProcess::readCString (uint32_t offset)
return temp;
}
DfVector NormalProcess::readVector (uint32_t offset, uint32_t item_size)
{
/*
GNU libstdc++ vector is three pointers long
ptr start
ptr end
ptr alloc_end
we don't care about alloc_end because we don't try to add stuff
*/
uint32_t start = g_pProcess->readDWord(offset);
uint32_t end = g_pProcess->readDWord(offset+4);
uint32_t size = (end - start) /4;
return DfVector(start,size,item_size);
}
struct _Rep_base
{
uint32_t _M_length;
uint32_t _M_capacity;
uint32_t _M_refcount;
};
size_t NormalProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
{
_Rep_base header;
offset = g_pProcess->readDWord(offset);
g_pProcess->read(offset - sizeof(_Rep_base),sizeof(_Rep_base),(uint8_t *)&header);
size_t read_real = min((size_t)header._M_length, bufcapacity-1);// keep space for null termination
g_pProcess->read(offset,read_real,(uint8_t * )buffer);
buffer[read_real] = 0;
return read_real;
}
const string NormalProcess::readSTLString (uint32_t offset)
{
_Rep_base header;
offset = g_pProcess->readDWord(offset);
g_pProcess->read(offset - sizeof(_Rep_base),sizeof(_Rep_base),(uint8_t *)&header);
// FIXME: use char* everywhere, avoid string
char * temp = new char[header._M_length+1];
g_pProcess->read(offset,header._M_length+1,(uint8_t * )temp);
string ret(temp);
delete temp;
return ret;
}

@ -31,7 +31,6 @@ class SHMProcess::Private
public:
Private()
{
my_datamodel = NULL;
my_descriptor = NULL;
my_pid = 0;
my_shm = 0;
@ -43,7 +42,6 @@ class SHMProcess::Private
DFCLMutex = 0;
};
~Private(){};
DataModel* my_datamodel;
memory_info * my_descriptor;
DFWindow * my_window;
uint32_t my_pid;
@ -153,122 +151,119 @@ SHMProcess::SHMProcess(vector <memory_info> & known_versions)
char exe_link_name [256];
char target_name[1024];
int target_result;
do
// get server and client mutex
d->DFSVMutex = OpenMutex(SYNCHRONIZE,false, "DFSVMutex");
if(d->DFSVMutex == 0)
{
// get server and client mutex
d->DFSVMutex = OpenMutex(SYNCHRONIZE,false, "DFSVMutex");
if(d->DFSVMutex == 0)
{
break;
}
d->DFCLMutex = OpenMutex(SYNCHRONIZE,false, "DFCLMutex");
if(d->DFCLMutex == 0)
{
break;
}
if(!attach())
{
break;
}
// All seems to be OK so far. Attached and connected to something that looks like DF
return;
}
d->DFCLMutex = OpenMutex(SYNCHRONIZE,false, "DFCLMutex");
if(d->DFCLMutex == 0)
{
return;
}
if(!attach())
{
return;
}
// All seems to be OK so far. Attached and connected to something that looks like DF
// Test bridge version, will also detect when we connect to something that doesn't respond
bool bridgeOK;
if(!d->DF_TestBridgeVersion(bridgeOK))
{
fprintf(stderr,"DF terminated during reading\n");
UnmapViewOfFile(d->my_shm);
ReleaseMutex(d->DFCLMutex);
CloseHandle(d->DFSVMutex);
d->DFSVMutex = 0;
CloseHandle(d->DFCLMutex);
d->DFCLMutex = 0;
return;
}
if(!bridgeOK)
{
fprintf(stderr,"SHM bridge version mismatch\n");
((shm_cmd *)d->my_shm)->pingpong = DFPP_RUNNING;
UnmapViewOfFile(d->my_shm);
ReleaseMutex(d->DFCLMutex);
CloseHandle(d->DFSVMutex);
d->DFSVMutex = 0;
CloseHandle(d->DFCLMutex);
d->DFCLMutex = 0;
return;
}
/*
* get the PID from DF
*/
if(d->DF_GetPID(d->my_pid))
{
// try to identify the DF version
do // glorified goto
{
IMAGE_NT_HEADERS32 pe_header;
IMAGE_SECTION_HEADER sections[16];
HMODULE hmod = NULL;
DWORD junk;
HANDLE hProcess;
bool found = false;
d->identified = false;
// open process, we only need the process open
hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, d->my_pid );
if (NULL == hProcess)
break;
// try getting the first module of the process
if(EnumProcessModules(hProcess, &hmod, 1 * sizeof(HMODULE), &junk) == 0)
{
CloseHandle(hProcess);
cout << "EnumProcessModules fail'd" << endl;
break;
}
// got base ;)
uint32_t base = (uint32_t)hmod;
// read from this process
uint32_t pe_offset = readDWord(base+0x3C);
read(base + pe_offset , sizeof(pe_header), (uint8_t *)&pe_header);
read(base + pe_offset+ sizeof(pe_header), sizeof(sections) , (uint8_t *)&sections );
// iterate over the list of memory locations
vector<memory_info>::iterator it;
for ( it=known_versions.begin() ; it < known_versions.end(); it++ )
{
uint32_t pe_timestamp = (*it).getHexValue("pe_timestamp");
if (pe_timestamp == pe_header.FileHeader.TimeDateStamp)
{
memory_info *m = new memory_info(*it);
m->RebaseAll(base);
d->my_descriptor = m;
d->identified = true;
cerr << "identified " << m->getVersion() << endl;
break;
}
}
CloseHandle(hProcess);
} while (0); // glorified goto end
// Test bridge version, will also detect when we connect to something that doesn't respond
bool bridgeOK;
if(!d->DF_TestBridgeVersion(bridgeOK))
if(d->identified)
{
fprintf(stderr,"DF terminated during reading\n");
UnmapViewOfFile(d->my_shm);
ReleaseMutex(d->DFCLMutex);
CloseHandle(d->DFSVMutex);
d->DFSVMutex = 0;
CloseHandle(d->DFCLMutex);
d->DFCLMutex = 0;
break;
d->my_window = new DFWindow(this);
}
if(!bridgeOK)
else
{
fprintf(stderr,"SHM bridge version mismatch\n");
((shm_cmd *)d->my_shm)->pingpong = DFPP_RUNNING;
UnmapViewOfFile(d->my_shm);
d->my_shm = 0;
ReleaseMutex(d->DFCLMutex);
CloseHandle(d->DFSVMutex);
d->DFSVMutex = 0;
CloseHandle(d->DFCLMutex);
d->DFCLMutex = 0;
break;
return;
}
/*
* get the PID from DF
*/
if(d->DF_GetPID(d->my_pid))
{
// try to identify the DF version
do // glorified goto
{
IMAGE_NT_HEADERS32 pe_header;
IMAGE_SECTION_HEADER sections[16];
HMODULE hmod = NULL;
DWORD junk;
HANDLE hProcess;
bool found = false;
d->identified = false;
// open process, we only need the process open
hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, d->my_pid );
if (NULL == hProcess)
break;
// try getting the first module of the process
if(EnumProcessModules(hProcess, &hmod, 1 * sizeof(HMODULE), &junk) == 0)
{
CloseHandle(hProcess);
cout << "EnumProcessModules fail'd" << endl;
break;
}
// got base ;)
uint32_t base = (uint32_t)hmod;
// read from this process
uint32_t pe_offset = readDWord(base+0x3C);
read(base + pe_offset , sizeof(pe_header), (uint8_t *)&pe_header);
read(base + pe_offset+ sizeof(pe_header), sizeof(sections) , (uint8_t *)&sections );
// iterate over the list of memory locations
vector<memory_info>::iterator it;
for ( it=known_versions.begin() ; it < known_versions.end(); it++ )
{
uint32_t pe_timestamp = (*it).getHexValue("pe_timestamp");
if (pe_timestamp == pe_header.FileHeader.TimeDateStamp)
{
memory_info *m = new memory_info(*it);
m->RebaseAll(base);
d->my_datamodel = new DMWindows40d();
d->my_descriptor = m;
d->identified = true;
cerr << "identified " << m->getVersion() << endl;
break;
}
}
CloseHandle(hProcess);
} while (0); // glorified goto end
if(d->identified)
{
d->my_window = new DFWindow(this);
}
else
{
((shm_cmd *)d->my_shm)->pingpong = DFPP_RUNNING;
UnmapViewOfFile(d->my_shm);
ReleaseMutex(d->DFCLMutex);
CloseHandle(d->DFSVMutex);
d->DFSVMutex = 0;
CloseHandle(d->DFCLMutex);
d->DFCLMutex = 0;
break;
}
}
} while (0);
}
full_barrier
// at this point, DF is attached and suspended, make it run
detach();
@ -295,10 +290,6 @@ SHMProcess::~SHMProcess()
detach();
}
// destroy data model. this is assigned by processmanager
if(d->my_datamodel)
{
delete d->my_datamodel;
}
if(d->my_descriptor)
{
delete d->my_descriptor;
@ -319,12 +310,6 @@ SHMProcess::~SHMProcess()
delete d;
}
DataModel *SHMProcess::getDataModel()
{
return d->my_datamodel;
}
memory_info * SHMProcess::getDescriptor()
{
return d->my_descriptor;
@ -686,3 +671,56 @@ const std::string SHMProcess::readCString (uint32_t offset)
return temp;
}
DfVector SHMProcess::readVector (uint32_t offset, uint32_t item_size)
{
/*
MSVC++ vector is four pointers long
ptr allocator
ptr start
ptr end
ptr alloc_end
we don't care about alloc_end because we don't try to add stuff
we also don't care about the allocator thing in front
*/
uint32_t start = g_pProcess->readDWord(offset+4);
uint32_t end = g_pProcess->readDWord(offset+8);
uint32_t size = (end - start) /4;
return DfVector(start,size,item_size);
}
const std::string SHMProcess::readSTLString(uint32_t offset)
{
//offset -= 4; //msvc std::string pointers are 8 bytes ahead of their data, not 4
((shm_read_small *)d->my_shm)->address = offset;
full_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_STL_STRING;
d->waitWhile(DFPP_READ_STL_STRING);
int length = ((shm_retval *)d->my_shm)->value;
// char temp_c[256];
// strncpy(temp_c, d->my_shm+SHM_HEADER,length+1); // length + 1 for the null terminator
return(string(d->my_shm+SHM_HEADER));
}
size_t SHMProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
{
//offset -= 4; //msvc std::string pointers are 8 bytes ahead of their data, not 4
((shm_read_small *)d->my_shm)->address = offset;
full_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_STL_STRING;
d->waitWhile(DFPP_READ_STL_STRING);
size_t length = ((shm_retval *)d->my_shm)->value;
size_t real = min(length, bufcapacity - 1);
strncpy(buffer, d->my_shm+SHM_HEADER,real); // length + 1 for the null terminator
buffer[real] = 0;
return real;
}
void SHMProcess::writeSTLString(const uint32_t address, const std::string writeString)
{
((shm_write_small *)d->my_shm)->address = address/*-4*/;
strncpy(d->my_shm+SHM_HEADER,writeString.c_str(),writeString.length()+1); // length + 1 for the null terminator
full_barrier
((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_STL_STRING;
d->waitWhile(DFPP_WRITE_STL_STRING);
}

@ -29,7 +29,6 @@ class NormalProcess::Private
public:
Private()
{
my_datamodel = NULL;
my_descriptor = NULL;
my_handle = NULL;
my_main_thread = NULL;
@ -39,7 +38,6 @@ class NormalProcess::Private
suspended = false;
};
~Private(){};
DataModel* my_datamodel;
memory_info * my_descriptor;
DFWindow * my_window;
ProcessHandle my_handle;
@ -109,7 +107,6 @@ NormalProcess::NormalProcess(uint32_t pid, vector <memory_info> & known_versions
// keep track of created memory_info object so we can destroy it later
d->my_descriptor = m;
// process is responsible for destroying its data model
d->my_datamodel = new DMWindows40d();
d->my_pid = pid;
d->my_handle = hProcess;
d->identified = true;
@ -142,8 +139,6 @@ NormalProcess::~NormalProcess()
{
detach();
}
// destroy data model. this is assigned by processmanager
delete d->my_datamodel;
// destroy our rebased copy of the memory descriptor
delete d->my_descriptor;
if(d->my_handle != NULL)
@ -161,13 +156,6 @@ NormalProcess::~NormalProcess()
delete d;
}
DataModel *NormalProcess::getDataModel()
{
return d->my_datamodel;
}
memory_info * NormalProcess::getDescriptor()
{
return d->my_descriptor;
@ -390,3 +378,89 @@ const string NormalProcess::readCString (const uint32_t offset)
return temp;
}
DfVector NormalProcess::readVector (uint32_t offset, uint32_t item_size)
{
/*
MSVC++ vector is four pointers long
ptr allocator
ptr start
ptr end
ptr alloc_end
we don't care about alloc_end because we don't try to add stuff
we also don't care about the allocator thing in front
*/
uint32_t start = g_pProcess->readDWord(offset+4);
uint32_t end = g_pProcess->readDWord(offset+8);
uint32_t size = (end - start) /4;
return DfVector(start,size,item_size);
}
size_t NormalProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
{
/*
MSVC++ string
ptr allocator
union
{
char[16] start;
char * start_ptr
}
Uint32 length
Uint32 capacity
*/
uint32_t start_offset = offset + 4;
size_t length = g_pProcess->readDWord(offset + 20);
size_t capacity = g_pProcess->readDWord(offset + 24);
size_t read_real = min(length, bufcapacity-1);// keep space for null termination
// read data from inside the string structure
if(capacity < 16)
{
g_pProcess->read(start_offset, read_real , (uint8_t *)buffer);
}
else // read data from what the offset + 4 dword points to
{
start_offset = g_pProcess->readDWord(start_offset);// dereference the start offset
g_pProcess->read(start_offset, read_real, (uint8_t *)buffer);
}
buffer[read_real] = 0;
return read_real;
}
const string NormalProcess::readSTLString (uint32_t offset)
{
/*
MSVC++ string
ptr allocator
union
{
char[16] start;
char * start_ptr
}
Uint32 length
Uint32 capacity
*/
uint32_t start_offset = offset + 4;
uint32_t length = g_pProcess->readDWord(offset + 20);
uint32_t capacity = g_pProcess->readDWord(offset + 24);
char * temp = new char[capacity+1];
// read data from inside the string structure
if(capacity < 16)
{
g_pProcess->read(start_offset, capacity, (uint8_t *)temp);
}
else // read data from what the offset + 4 dword points to
{
start_offset = g_pProcess->readDWord(start_offset);// dereference the start offset
g_pProcess->read(start_offset, capacity, (uint8_t *)temp);
}
temp[length] = 0;
string ret = temp;
delete temp;
return ret;
}

@ -30,9 +30,9 @@ distribution.
namespace DFHack
{
class memory_info;
class DataModel;
class Process;
class DFWindow;
class DfVector;
// structure describing a memory range
struct DFHACK_EXPORT t_memrange
@ -90,6 +90,13 @@ namespace DFHack
virtual void writeByte(const uint32_t address, const uint8_t value) = 0;
virtual void write(uint32_t address, uint32_t length, uint8_t* buffer) = 0;
// read a string
virtual const string readSTLString (uint32_t offset) = 0;
virtual size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) = 0;
virtual void writeSTLString(const uint32_t address, const std::string writeString) = 0;
// read a vector from memory
virtual DfVector readVector (uint32_t offset, uint32_t item_size) = 0;
virtual const std::string readCString (uint32_t offset) = 0;
virtual bool isSuspended() = 0;
@ -103,8 +110,6 @@ namespace DFHack
// get the flattened Memory.xml entry of this process
virtual memory_info *getDescriptor() = 0;
// get the DataModel for reading stl containers (depends on the version of stl DF was compiled with)
virtual DataModel *getDataModel() = 0;
// get the DF's window (first that can be found ~_~)
virtual DFWindow * getWindow() = 0;
// get the DF Process ID
@ -142,6 +147,12 @@ namespace DFHack
void writeByte(const uint32_t address, const uint8_t value);
void write(uint32_t address, uint32_t length, uint8_t* buffer);
const string readSTLString (uint32_t offset);
size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity);
void writeSTLString(const uint32_t address, const std::string writeString){};
// read a vector from memory
DfVector readVector (uint32_t offset, uint32_t item_size);
const std::string readCString (uint32_t offset);
bool isSuspended();
@ -151,7 +162,6 @@ namespace DFHack
bool getThreadIDs(vector<uint32_t> & threads );
void getMemRanges( vector<t_memrange> & ranges );
memory_info *getDescriptor();
DataModel *getDataModel();
DFWindow * getWindow();
int getPID();
};
@ -183,11 +193,68 @@ namespace DFHack
void readByte(const uint32_t address, uint8_t & value);
void read( uint32_t address, uint32_t length, uint8_t* buffer);
void writeDWord(const uint32_t address, const uint32_t value);
void writeWord(const uint32_t address, const uint16_t value);
void writeByte(const uint32_t address, const uint8_t value);
void write(uint32_t address, uint32_t length, uint8_t* buffer);
const string readSTLString (uint32_t offset);
size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity);
void writeSTLString(const uint32_t address, const std::string writeString);
// read a vector from memory
DfVector readVector (uint32_t offset, uint32_t item_size);
const std::string readCString (uint32_t offset);
bool isSuspended();
bool isAttached();
bool isIdentified();
bool getThreadIDs(vector<uint32_t> & threads );
void getMemRanges( vector<t_memrange> & ranges );
memory_info *getDescriptor();
DFWindow * getWindow();
int getPID();
};
#ifdef LINUX_BUILD
class DFHACK_EXPORT WineProcess : virtual public Process
{
friend class ProcessEnumerator;
class Private;
private:
Private * const d;
public:
WineProcess(uint32_t pid, vector <memory_info> & known_versions);
~WineProcess();
bool attach();
bool detach();
bool suspend();
bool asyncSuspend();
bool resume();
bool forceresume();
uint32_t readDWord(const uint32_t address);
void readDWord(const uint32_t address, uint32_t & value);
uint16_t readWord(const uint32_t address);
void readWord(const uint32_t address, uint16_t & value);
uint8_t readByte(const uint32_t address);
void readByte(const uint32_t address, uint8_t & value);
void read( uint32_t address, uint32_t length, uint8_t* buffer);
void writeDWord(const uint32_t address, const uint32_t value);
void writeWord(const uint32_t address, const uint16_t value);
void writeByte(const uint32_t address, const uint8_t value);
void write(uint32_t address, uint32_t length, uint8_t* buffer);
const string readSTLString (uint32_t offset);
size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity);
void writeSTLString(const uint32_t address, const std::string writeString){};
// read a vector from memory
DfVector readVector (uint32_t offset, uint32_t item_size);
const std::string readCString (uint32_t offset);
bool isSuspended();
@ -197,9 +264,9 @@ namespace DFHack
bool getThreadIDs(vector<uint32_t> & threads );
void getMemRanges( vector<t_memrange> & ranges );
memory_info *getDescriptor();
DataModel *getDataModel();
DFWindow * getWindow();
int getPID();
};
#endif
}
#endif

@ -76,11 +76,22 @@ bool ProcessEnumerator::findProcessess()
if(p2->isIdentified())
{
d->processes.push_back(p2);
continue;
}
else
{
delete p2;
}
Process *p3 = new WineProcess(atoi(dir_entry_p->d_name),d->meminfo->meminfo);
if(p3->isIdentified())
{
d->processes.push_back(p3);
continue;
}
else
{
delete p3;
}
}
closedir(dir_p);
// return value depends on if we found some DF processes

@ -103,6 +103,7 @@ bool ProcessEnumerator::findProcessess()
else
{
delete q;
q = 0;
}
}
if(d->processes.size())

@ -32,7 +32,6 @@ class TiXmlElement;
namespace DFHack
{
class memory_info;
class DataModel;
class Process;
/*

Binary file not shown.

Binary file not shown.

@ -29,6 +29,7 @@ distribution.
#include "../library/integers.h"
#include <stdlib.h>
#include <string.h>
#include <string>
//#include <unistd.h>
#include "shms.h"
// various crud
@ -45,6 +46,7 @@ void SHM_Act (void)
uint32_t numwaits = 0;
uint32_t length;
uint32_t address;
std::string * myStringPtr;
check_again: // goto target!!!
SCHED_YIELD // yield the CPU, valid only on single-core CPUs
if(numwaits == 10000)
@ -69,6 +71,7 @@ void SHM_Act (void)
case DFPP_RET_DWORD:
case DFPP_RET_WORD:
case DFPP_RET_BYTE:
case DFPP_RET_STRING:
case DFPP_SUSPENDED:
case DFPP_RET_PID:
case DFPP_SV_ERROR:
@ -159,21 +162,22 @@ void SHM_Act (void)
//MessageBox(0,"Broke out of loop properly","FUN", MB_OK);
break;
// client requests contents of STL string at address
/*case DFPP_READ_STL_STRING:
char * real = *(char **)((shm_read_small *)shm)->address;
strncpy(shm + SHM_HEADER,real,1024*1024-1);
case DFPP_READ_STL_STRING:
myStringPtr = (std::string *) ((shm_read_small *)shm)->address;
((shm_retval *)shm)->value = myStringPtr->length();
strncpy(shm+SHM_HEADER,myStringPtr->c_str(),myStringPtr->length()+1);// length + 1 for the null terminator
full_barrier
((shm_retval *)shm)->pingpong = DFPP_RET_STRING;
goto check_again;
*/
// client requests contents of a C string at address, max length (0 means zero terminated)
/* case DFPP_READ_C_STRING:
break;
// sv -> cl length + string contents
// client wants to set STL string at address to something
case DFPP_WRITE_STL_STRING:
break;*/
myStringPtr = (std::string *) ((shm_write *)shm)->address;
myStringPtr->assign((const char *) (shm + SHM_HEADER));
full_barrier
((shm_cmd *)shm)->pingpong = DFPP_SUSPENDED;
goto check_again;
default:
((shm_retval *)shm)->value = DFEE_INVALID_COMMAND;
full_barrier

@ -1,7 +1,7 @@
#ifndef DFCONNECT_H
#define DFCONNECT_H
#define PINGPONG_VERSION 1
#define PINGPONG_VERSION 2
#define SHM_KEY 123466
#define SHM_HEADER 1024
#define SHM_BODY 1024*1024
@ -139,6 +139,13 @@ typedef struct
uint32_t value;
} shm_retval;
typedef struct
{
volatile uint32_t pingpong;
uint32_t length;
} shm_retstr;
void SHM_Act (void);
bool isValidSHM();
uint32_t getPID();

@ -5,10 +5,6 @@ IF(UNIX)
add_definitions(-DLINUX_BUILD)
ENDIF(UNIX)
# a benchmark program, reads the map 1000x
ADD_EXECUTABLE(dfexpbench expbench.cpp)
TARGET_LINK_LIBRARIES(dfexpbench dfhack)
# a reveal clone
ADD_EXECUTABLE(dfreveal reveal.cpp)
TARGET_LINK_LIBRARIES(dfreveal dfhack)
@ -21,75 +17,27 @@ TARGET_LINK_LIBRARIES(dfprospector dfhack)
ADD_EXECUTABLE(dfcleanmap cleanmap.cpp)
TARGET_LINK_LIBRARIES(dfcleanmap dfhack)
# creaturedump - basic creature dump - a test of the creature related exports
ADD_EXECUTABLE(dfcreaturedump creaturedump.cpp)
TARGET_LINK_LIBRARIES(dfcreaturedump dfhack)
# buildingsdump - dump buildings and their raw data filtered by type
ADD_EXECUTABLE(dfbuildingsdump buildingsdump.cpp)
TARGET_LINK_LIBRARIES(dfbuildingsdump dfhack)
# attachtest - 100x attach/detach, 100x reads, 100x writes
ADD_EXECUTABLE(dfattachtest attachtest.cpp)
TARGET_LINK_LIBRARIES(dfattachtest dfhack)
# materialtest - just list the first material of each type
ADD_EXECUTABLE(dfmaterialtest materialtest.cpp)
TARGET_LINK_LIBRARIES(dfmaterialtest dfhack)
# materialtest - just list the first material of each type
ADD_EXECUTABLE(dfposition position.cpp)
TARGET_LINK_LIBRARIES(dfposition dfhack)
#currently only stable on linux
IF(UNIX)
# incremental - incremental memory search tool, a foreshadowing of the future direction of dfhack
ADD_EXECUTABLE(dfincremental incrementalsearch.cpp)
TARGET_LINK_LIBRARIES(dfincremental dfhack)
ENDIF(UNIX)
# suspendtest - test if suspend works. df should stop responding when suspended by dfhack
ADD_EXECUTABLE(dfsuspend suspendtest.cpp)
TARGET_LINK_LIBRARIES(dfsuspend dfhack)
# itemdump - dump the item under the cursor
ADD_EXECUTABLE(dfitemdump dfitemdump.cpp)
TARGET_LINK_LIBRARIES(dfitemdump dfhack)
# incrementalsearch - a bit like cheat engine, only DF-specific and very basic
ADD_EXECUTABLE(dfincremental incrementalsearch.cpp)
TARGET_LINK_LIBRARIES(dfincremental dfhack)
# bauxite - turn all mechanisms into bauxite mechanisms
# Author: Alex Legg
ADD_EXECUTABLE(dfbauxite dfbauxite.cpp)
TARGET_LINK_LIBRARIES(dfbauxite dfhack)
# digger - designate for digging by tile class
# Author: mizipzor
ADD_EXECUTABLE(dfdigger digger.cpp)
TARGET_LINK_LIBRARIES(dfdigger dfhack)
# itemdesignator - change some item designations (dump, forbid, on-fire) for all items of a given type and material
ADD_EXECUTABLE(dfitemdesignator itemdesignator.cpp)
TARGET_LINK_LIBRARIES(dfitemdesignator dfhack)
# customCtreatureNameProf - change the custom names and professions of creatures, sends keys to df directly
ADD_EXECUTABLE(dfcustomCreatureNameProf customCreatureNameProf.cpp)
TARGET_LINK_LIBRARIES(dfcustomCreatureNameProf dfhack)
IF(UNIX)
install(TARGETS
dfexpbench
dfreveal
dfreveal
dfprospector
dfcleanmap
dfcreaturedump
dfattachtest
dfmaterialtest
dfbuildingsdump
dfposition
dfincremental
dfitemdump
dfsuspend
dfbauxite
dfitemdesignator
RUNTIME DESTINATION bin
)
ENDIF(UNIX)

@ -91,7 +91,7 @@ int main ()
return EXIT_FAILURE;
}
items_vector = new DFHack::DfVector (proc->getDataModel()->readVector (items, 4));
items_vector = new DFHack::DfVector (proc->readVector (items, 4));
for(uint32_t i = 0; i < items_vector->getSize(); i++)
{
// get pointer to object