diff --git a/CMake/Modules/CMakeVS10FindMake.cmake b/CMake/Modules/CMakeVS10FindMake.cmake new file mode 100644 index 000000000..460de25e5 --- /dev/null +++ b/CMake/Modules/CMakeVS10FindMake.cmake @@ -0,0 +1,28 @@ + +#============================================================================= +# Copyright 2009 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distributed this file outside of CMake, substitute the full +# License text for the above reference.) + +# We use MSBuild as the build tool for VS 10 +FIND_PROGRAM(CMAKE_MAKE_PROGRAM + NAMES MSBuild + HINTS + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\10.0\\Setup\\VS;ProductDir] + "$ENV{SYSTEMROOT}/Microsoft.NET/Framework/[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\10.0;CLR Version]/" + "c:/WINDOWS/Microsoft.NET/Framework/[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\10.0;CLR Version]/" + "$ENV{SYSTEMROOT}/Microsoft.NET/Framework/[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\10.0;CLR Version]/" + ) + +MARK_AS_ADVANCED(CMAKE_MAKE_PROGRAM) +SET(MSVC10 1) +SET(MSVC_VERSION 1600) + diff --git a/CMakeLists.txt b/CMakeLists.txt index e4dc7ab5e..a03f7d6cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,7 @@ PROJECT (dfhack) cmake_minimum_required(VERSION 2.6) SET(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/CMake/Modules) +SET ( DFHACK_VERSION "0.4.1.0-dev" ) # disable warning, autosearch if(COMMAND cmake_policy) @@ -18,6 +19,13 @@ ENDIF(NOT DEFINED CMAKE_BUILD_TYPE) SET( LIBRARY_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/output CACHE PATH "Output directory for the dfhack library" ) SET( EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/output CACHE PATH "Output directory for the dfhack tools" ) +SET( DATA_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/output CACHE PATH "Output directory for the dfhack data (offset files)" ) + +OPTION(BUILD_DFHACK_DOCUMENTATION "Create doxygen documentation for developers" OFF) +OPTION(BUILD_DFHACK_EXAMPLES "Build example tools" OFF) +OPTION(BUILD_DFHACK_PLAYGROUND "Build tools from the playground folder" OFF) +OPTION(BUILD_DFHACK_C_BINDIGS "Build the C portion of the library" ON) +OPTION(BUILD_OFFSET_EDITOR "Build the Offset GUI editor (not ready for use)." OFF) include_directories (${CMAKE_SOURCE_DIR}/library/include/) include_directories (${CMAKE_SOURCE_DIR}/library/shm/) @@ -26,7 +34,13 @@ include_directories (${CMAKE_SOURCE_DIR}/library/depends/tinyxml/) include_directories (${CMAKE_SOURCE_DIR}/library/depends/argstream/) add_subdirectory (library) -#add_subdirectory (dfhack/python) + +IF(BUILD_OFFSET_EDITOR) + add_subdirectory (offsetedit) +ENDIF(BUILD_OFFSET_EDITOR) + +add_subdirectory (library/shm) add_subdirectory (tools/examples) add_subdirectory (tools/playground) add_subdirectory (tools/supported) +add_subdirectory (doc) \ No newline at end of file diff --git a/COMPILE b/COMPILE deleted file mode 100644 index a4da697ba..000000000 --- a/COMPILE +++ /dev/null @@ -1,159 +0,0 @@ -Here's how you build dfhack! ----------------------------- - -Dependencies -============ - -You'll need cmake and 'a' compiler for building the main lib and the various tools. -(Linux only) Veinlook requires the wide-character ncurses library (libncursesw) - -Building on Linux: --------------------- - -* To run in the output folder (without installing): - -building the library is simple. Enter the build folder, run the tools. Like this: - -cd build -cmake .. -DCMAKE_BUILD_TYPE:string=Release -make - -This will build the library and its tools and place them in /output. -You can also use a cmake-friendly IDE like KDevelop 4 or the cmake GUI program. - -* To be installed into the system or packaged - -cd build -cmake -DCMAKE_BUILD_TYPE:string=Release -DCMAKE_INSTALL_PREFIX=/usr -DMEMXML_DATA_PATH:path=/usr/share/dfhack .. -make -make install - -With this dfhack installs: -library to $CMAKE_INSTALL_PREFIX/lib -executables to $CMAKE_INSTALL_PREFIX/bin -The Memory.xml file to /usr/share/dfhack - -See the section on the shared memory hook library (SHM). - -Building on Windows: --------------------- - -You need cmake. Get the win32 installer version from the official site: -http://www.cmake.org/cmake/resources/software.html -It has the usual installer wizard thing. - - -* Using mingw: - -You also need a compiler. I build dfhack using mingw. You can get it from the mingw site: -Get the automated installer, it will download newest version of mingw and set things up nicely. -You'll have to add C:\MinGW\ to your PATH variable. - - - Building: - open up cmd and navigate to the dfhack\build folder, run cmake and the mingw version of make: - cd build - cmake .. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE:string=Release - mingw32-make - - -* Using MSVC - -open up cmd and navigate to the dfhack\build folder, run cmake: -cd build -cmake .. - -This will generate MSVC solution and project files. -Note that: you are working in the /build folder. 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! - -Alo, you'll have to copy the Memory.xml file to the build output folders -MSVC generates. For example from 'output/' to 'output/Release/' - - -* 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. - -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 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 - -Without specifying a build type or 'None', cmake uses the CMAKE_CXX_FLAGS -variable for building. -Valid an useful build types include 'Release', 'Debug' and 'RelWithDebInfo'. -There are others, but they aren't really that useful. - -Have fun. - --------------------------------------------------------------------------------- -**Deprecated*Deprecated*Deprecated*Deprecated*Deprecated*Deprecated*Deprecated** --------------------------------------------------------------------------------- - -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 - 40d19_2 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 only be debugged using a RelWithDebInfo build! - -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 most probably lost. diff --git a/COMPILE.rst b/COMPILE.rst new file mode 100644 index 000000000..dc07456f0 --- /dev/null +++ b/COMPILE.rst @@ -0,0 +1,147 @@ +################ +Compiling DFHACK +################ + +============================ +Here's how you build dfhack! +============================ + +.. contents:: + + +Dependencies +============ +* ``cmake`` +* A compiler for building the main lib and the various tools. +* (Linux only) Veinlook requires the wide-character ncurses library (libncursesw) +* (Linux only) You'll need X11 dev libraries. + +Building on Linux +================= +To run in the output folder (without installing) building the library +is simple. Enter the build folder, run the tools. Like this:: + + cd build + cmake .. -DCMAKE_BUILD_TYPE:string=Release + make + +This will build the library and its tools and place them in ``/output``. +You can also use a cmake-friendly IDE like KDevelop 4 or the cmake GUI +program. + +To be installed into the system or packaged:: + + cd build + cmake -DCMAKE_BUILD_TYPE:string=Release \ + -DCMAKE_INSTALL_PREFIX=/usr \ + -DMEMXML_DATA_PATH:path=/usr/share/dfhack .. + make + make install + +With this dfhack installs: + +* library to ``$CMAKE_INSTALL_PREFIX/lib`` +* executables to ``$CMAKE_INSTALL_PREFIX/bin`` +* The ``Memory.xml`` file to ``/usr/share/dfhack`` + +See the section on the shared memory hook library (SHM). + +Building on Windows +=================== +You need ``cmake``. Get the win32 installer version from the official +site: http://www.cmake.org/cmake/resources/software.html + +It has the usual installer wizard thing. + +----------- +Using mingw +----------- +You also need a compiler. I build dfhack using mingw. You can get it +from the mingw site: http://www.mingw.org/ + +Get the automated installer, it will download newest version of mingw +and set things up nicely. + +You'll have to add ``C:\MinGW\`` to your PATH variable. + +Building +-------- +open up cmd and navigate to the ``dfhack\build`` folder, run ``cmake`` +and the mingw version of make:: + + cd build + cmake .. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE:string=Release + mingw32-make + +---------- +Using MSVC +---------- +open up ``cmd`` and navigate to the ``dfhack\build`` folder, run +``cmake``:: + + cd build + cmake .. + +This will generate MSVC solution and project files. + +.. note:: + + You are working in the ``/build`` folder. Files added to + projects from within MSVC 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! + +------------------------- +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. + +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 testing program and the + library. +* Some of the utilities and the doxygen documentation won't be + normally built. You can enable them by specifying some extra + CMake variables:: + + BUILD_DFHACK_DOCUMENTATION - generate the documentation (really bad) + BUILD_DFHACK_EXAMPLES - build tools from tools/examples + BUILD_DFHACK_PLAYGROUND - build tools from tools/playground + + Example:: + + cmake .. -DBUILD_DFHACK_EXAMPLES=ON + +Build types +=========== +``cmake`` allows you to pick a build type by changing this +variable: ``CMAKE_BUILD_TYPE`` + +:: + + cmake .. -DCMAKE_BUILD_TYPE:string=BUILD_TYPE + +Without specifying a build type or 'None', cmake uses the +``CMAKE_CXX_FLAGS`` variable for building. + +Valid an useful build types include 'Release', 'Debug' and +'RelWithDebInfo'. There are others, but they aren't really that useful. + +Have fun. + +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 31.01 - 31.12 on Windows, use MSVC 2008. You can get the Express +edition for free from Microsoft. diff --git a/Compile.html b/Compile.html new file mode 100644 index 000000000..d7bb44ce7 --- /dev/null +++ b/Compile.html @@ -0,0 +1,471 @@ + + + + + + +Compiling DFHACK + + + +
+

Compiling DFHACK

+

Here's how you build dfhack!

+ +
+

Contents

+ +
+
+

Dependencies

+ +
+
+

Building on Linux

+

To run in the output folder (without installing) building the library +is simple. Enter the build folder, run the tools. Like this:

+
+cd build
+cmake .. -DCMAKE_BUILD_TYPE:string=Release
+make
+
+

This will build the library and its tools and place them in /output. +You can also use a cmake-friendly IDE like KDevelop 4 or the cmake GUI +program.

+

To be installed into the system or packaged:

+
+cd build
+cmake -DCMAKE_BUILD_TYPE:string=Release \
+    -DCMAKE_INSTALL_PREFIX=/usr \
+    -DMEMXML_DATA_PATH:path=/usr/share/dfhack ..
+make
+make install
+
+

With this dfhack installs:

+ +

See the section on the shared memory hook library (SHM).

+
+
+

Building on Windows

+

You need cmake. Get the win32 installer version from the official +site: http://www.cmake.org/cmake/resources/software.html

+

It has the usual installer wizard thing.

+
+

Using mingw

+

You also need a compiler. I build dfhack using mingw. You can get it +from the mingw site: http://www.mingw.org/

+

Get the automated installer, it will download newest version of mingw +and set things up nicely.

+

You'll have to add C:\MinGW\ to your PATH variable.

+
+

Building

+

open up cmd and navigate to the dfhack\build folder, run cmake +and the mingw version of make:

+
+cd build
+cmake .. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE:string=Release
+mingw32-make
+
+
+
+
+

Using MSVC

+

open up cmd and navigate to the dfhack\build folder, run +cmake:

+
+cd build
+cmake ..
+
+

This will generate MSVC solution and project files.

+
+

Note

+

You are working in the /build folder. Files added to +projects from within MSVC 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!

+
+
+
+

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.

+
+
+
+

Build targets

+

dfhack has a few build targets:

+ +
+
+

Build types

+

cmake allows you to pick a build type by changing this +variable: CMAKE_BUILD_TYPE

+
+cmake .. -DCMAKE_BUILD_TYPE:string=BUILD_TYPE
+
+

Without specifying a build type or 'None', cmake uses the +CMAKE_CXX_FLAGS variable for building.

+

Valid an useful build types include 'Release', 'Debug' and +'RelWithDebInfo'. There are others, but they aren't really that useful.

+

Have fun.

+
+
+

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 31.01 - 31.12 on Windows, use MSVC 2008. You can get the Express +edition for free from Microsoft.

+
+
+ + diff --git a/README b/README deleted file mode 100644 index 56c5c4d7d..000000000 --- a/README +++ /dev/null @@ -1,174 +0,0 @@ -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. - -Getting DFHack ----------------- -The project is currently hosted on github, for both source and binaries: - http://github.com/peterix/dfhack - -* Packages - -The library and tools are packaged for Archlinux and are available both in AUR -and the arch-games repository. - -The package name is dfhack-git :) - -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 :) - -OSX is also not supported due to lack of developers with a Mac. - -Currently supported Dwarf Fortress versions: -* Windows - 0.31.01 - 0.31.03 - -* Linux - wine together with the Windows versions - -Using the library as a developer --------------------------------- - -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 (and getting better all the time). - -Contributing to DFHack ----------------------- - -Several things should be kept in mind when contributing to DFHack. - -**** Coding style **** - -DFhack uses ANSI formatting and four spaces as indentation. Line endings are -UNIX. The files use UTF-8 encoding. Code not following this won't make me happy, -because I'll have to fix it. There's a good chance I'll make *you* fix it ;) - -**** How to get new code into DFHack **** - -You can send patches or make a clone of the github repo and ask me on the -IRC channel to pull your code in. I'll review it and see if there are any -problems. I'll fix them if they are minor. - -Fixes are higher in priority. If you want to work on something, but don't -know what, check out http://github.com/peterix/dfhack/issues -- this is also -a good place to dump new ideas and/or bugs that need fixing. - -**** Layout for tools **** - -Tools live in the tools/ folder. There, they are split into three categories: - -distributed: these tools get distributed with binary releases and are installed - by doing 'make install' on linux. They are supposed to be stable - and supported. Experimental, useless, buggy or untested stuff - doesn't belong here. -examples : examples are tools that aren't very useful, but show how DF - and DFHack work. They should use only DFHack API functions. - No actual hacking or 'magic offsets' are allowed. -playground : This is a catch-all folder for tools that aren't ready to be - examples or be distributed in binary releases. All new tools - should start here. They can contain actual hacking, magic values - and other nasty business. - -**** Modules - what are they? **** - -DFHack uses modules to partition sets of features into manageable chunks. -A module can have both client and server side. - -Client side is the part that goes into the main library and is generally -written in C++. It is exposed to the users of DFHack. - -Server side is used inside DF and serves to accelerate the client modules. -This is written mostly in C style. - -There's a Core module that shouldn't be changed, because it defines -the basic commands like reading and writing raw data. The client parts -for the Core module are the various implementations of the Process -interface. - -A good example of a module is Maps. Named the same in both client and -server, it allows accelerating the reading of map blocks. - -Communication between modules happens by using shared memory. This is -pretty fast, but needs quite a bit of care to not break. - -**** Dependencies **** - -Internal : either part of the codebase or statically linked. -External : linked as dynamic loaded libraries (.dll, .so, etc.) - -If you want to add dependencies, think twice about it. All internal dependencies -for core dfhack should be either public domain or require attribution at most. -Internal dependencies for tools can be either that, or any Free Software -licenses. - -** Current internal dependencies ** - -tinyxml : used by core dfhack to read offset definitions from Memory.xml -md5 : an implementation of the MD5 hash algorithm. Used for identifying - DF binaries on Linux. -argstream: Allows reading terminal application arguments. GPL! - -** Current external dependencies ** - -wide-character ncurses : used for the veinlook tool on Linux. -python 2.6 : required for building and using the python bindings. - -** Build-time dependencies ** -cmake: you need cmake to generate the build system and some configuration - headers - - -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. - - - dfcleanmap : Cleans all the splatter that get scattered all over the map. - Only exception is mud. It leaves mud alone. - - dfexpbench : Just a simple benchmark of the data export speed. - - dfliquids : A command prompt for liquid creation and manipulation - (the Moses effect included!) - Also allows painting obsidian walls directly. - Note: - Spawning and deleting liquids can F up pathing data and - temperatures (creating heat traps). You've been warned. - - dfposition : Prints the current DF window properties and cursor position. - - dfprospector: Lists all available minerals on the map and how much - of them there is. - - dfreveal : Reveals the whole map, waits for input and hides it again. - If you close the tool while it waits, the map remains revealed. - - dfsuspend : Test of the process suspend/resume mechanism. - - dfunstuck : Use if you prematurely close any of the tools and DF - appears to be stuck. - - dfvdig : Designates a whole vein for digging. Point the cursor at a vein - and run this thing :) - - - Your tool here: Write one ;) - - -Memory offset definitions -------------------------- - -The file with memory offset definitions used by dfhack can be found in the -output folder. - -~ EOF ~ diff --git a/README.rst b/README.rst new file mode 100644 index 000000000..1e479d107 --- /dev/null +++ b/README.rst @@ -0,0 +1,260 @@ +============ +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. + +.. contents:: + + +============== +Getting DFHack +============== +The project is currently hosted on github_, for both source and +binaries at http://github.com/peterix/dfhack + +.. _github: http://www.github.com/ + +Packages +======== +The library and tools are packaged for Archlinux and are available both +in AUR and the arch-games repository. + +The package name is dfhack-git :) + +============= +Compatibility +============= +DFHack works on Windows XP, Vista, 7 or any modern Linux distribution. + +OSX is not supported due to lack of developers with a Mac. + +Currently supported Dwarf Fortress versions are Windows and Linux. + +Windows +======= +.. note:: + + Windows 2000 is currently *not supported* due to missing OS + functionality. If you know how to easily suspend processes, you can + fix it :) + +0.31.01 - 0.31.03 legacy +0.31.04 - 0.31.12 SDL + +Linux +===== +0.31.05 - 0.31.12 native. +There are missing offsets but Map tools should be OK. Linux support is +a bit lacking, I'm working on it. All supported Windows versions +running in wine can be used with native DFHack binaries. + +===== +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. + +dfcleanmap +========== +Cleans all the splatter that get scattered all over the map. +Only exception is mud. It leaves mud alone. + +dfliquids +========= +A command prompt for liquid creation and manipulation (the Moses +effect included!) Also allows painting obsidian walls directly. + +.. note:: + + Spawning and deleting liquids can F up pathing data and + temperatures (creating heat traps). You've been warned. + +dfposition +========== +Prints the current DF window properties and cursor position. + +dfprospector +============ +Lists all available minerals on the map and how much of them there is. + +dfprobe +============ +Can be used to determine tile properties. + +dfreveal +======== +Reveals the whole map, waits for input and hides it again. If you close +the tool while it waits, the map remains revealed. + +dfunstuck +========= +Use if you prematurely close any of the tools and DF appears to be +stuck. + +dfvdig +====== +Designates a whole vein for digging. Point the cursor at a vein and run +this thing :) + +dfflows +======= +A tool for checking how many liquid tiles are actively checked for +flows. + +dfattachtest +============ +Test of the process attach/detach mechanism. + +dfsuspend +========= +Test of the process suspend/resume mechanism. + +dfexpbench +========== +Just a simple benchmark of the data export speed. + +dfdoffsets +========== +Dumps the offsets for the currently running DF version into the terminal. + +dfcleartask +=========== +Solves the problem of unusable items after reclaim by clearing the 'in_job' bit of all items. + +Your tool here +============== +Write one ;) + +================================ +Using the library as a developer +================================ +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 (and getting better all the +time). + +Contributing to DFHack +====================== + +Several things should be kept in mind when contributing to DFHack. + +------------ +Coding style +------------ +DFhack uses ANSI formatting and four spaces as indentation. Line +endings are UNIX. The files use UTF-8 encoding. Code not following this +won't make me happy, because I'll have to fix it. There's a good chance +I'll make *you* fix it ;) + +------------------------------- +How to get new code into DFHack +------------------------------- +You can send patches or make a clone of the github repo and ask me on +the IRC channel to pull your code in. I'll review it and see if there +are any problems. I'll fix them if they are minor. + +Fixes are higher in priority. If you want to work on something, but +don't know what, check out http://github.com/peterix/dfhack/issues -- +this is also a good place to dump new ideas and/or bugs that need +fixing. + +---------------- +Layout for tools +---------------- +Tools live in the tools/ folder. There, they are split into three +categories. + +distributed + these tools get distributed with binary releases and are installed + by doing 'make install' on linux. They are supposed to be stable + and supported. Experimental, useless, buggy or untested stuff + doesn't belong here. +examples + examples are tools that aren't very useful, but show how DF and + DFHack work. They should use only DFHack API functions. No actual + hacking or 'magic offsets' are allowed. +playground + This is a catch-all folder for tools that aren't ready to be + examples or be distributed in binary releases. All new tools should + start here. They can contain actual hacking, magic values and other + nasty business. + +------------------------ +Modules - what are they? +------------------------ +DFHack uses modules to partition sets of features into manageable +chunks. A module can have both client and server side. + +Client side is the part that goes into the main library and is +generally written in C++. It is exposed to the users of DFHack. + +Server side is used inside DF and serves to accelerate the client +modules. This is written mostly in C style. + +There's a Core module that shouldn't be changed, because it defines the +basic commands like reading and writing raw data. The client parts for +the Core module are the various implementations of the Process +interface. + +A good example of a module is Maps. Named the same in both client and +server, it allows accelerating the reading of map blocks. + +Communication between modules happens by using shared memory. This is +pretty fast, but needs quite a bit of care to not break. + +------------ +Dependencies +------------ +Internal + either part of the codebase or statically linked. +External + linked as dynamic loaded libraries (.dll, .so, etc.) + +If you want to add dependencies, think twice about it. All internal +dependencies for core dfhack should be either public domain or require +attribution at most. External dependencies for tools can be either +that, or any Free Software licenses. + +Current internal dependencies +----------------------------- +tinyxml + used by core dfhack to read offset definitions from Memory.xml +md5 + an implementation of the MD5 hash algorithm. Used for identifying + DF binaries on Linux. +argstream + Allows reading terminal application arguments. GPL! + +Current external dependencies +----------------------------- +wide-character ncurses + used for the veinlook tool on Linux. +x11 libraries + used for sending key events on linux + +Build-time dependencies +----------------------- +cmake + you need cmake to generate the build system and some configuration + headers + +========================= +Memory offset definitions +========================= +The files with memory offset definitions used by dfhack can be found in the +data folder. + diff --git a/Readme.html b/Readme.html new file mode 100644 index 000000000..98eb64c8a --- /dev/null +++ b/Readme.html @@ -0,0 +1,601 @@ + + + + + + + + + + +
+ + +
+

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.

+ +
+
+

Getting DFHack

+

The project is currently hosted on github, for both source and +binaries at http://github.com/peterix/dfhack

+
+

Packages

+

The library and tools are packaged for Archlinux and are available both +in AUR and the arch-games repository.

+

The package name is dfhack-git :)

+
+
+
+

Compatibility

+

DFHack works on Windows XP, Vista, 7 or any modern Linux distribution.

+

OSX is not supported due to lack of developers with a Mac.

+

Currently supported Dwarf Fortress versions are Windows and Linux.

+
+

Windows

+
+

Note

+

Windows 2000 is currently not supported due to missing OS +functionality. If you know how to easily suspend processes, you can +fix it :)

+
+

0.31.01 - 0.31.03 legacy +0.31.04 - 0.31.12 SDL

+
+
+

Linux

+

0.31.05 - 0.31.12 native. +There are missing offsets but Map tools should be OK. Linux support is +a bit lacking, I'm working on it. All supported Windows versions +running in wine can be used with native DFHack binaries.

+
+
+
+

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.

+
+

dfcleanmap

+

Cleans all the splatter that get scattered all over the map. +Only exception is mud. It leaves mud alone.

+
+
+

dfliquids

+

A command prompt for liquid creation and manipulation (the Moses +effect included!) Also allows painting obsidian walls directly.

+
+

Note

+

Spawning and deleting liquids can F up pathing data and +temperatures (creating heat traps). You've been warned.

+
+
+
+

dfposition

+

Prints the current DF window properties and cursor position.

+
+
+

dfprospector

+

Lists all available minerals on the map and how much of them there is.

+
+
+

dfreveal

+

Reveals the whole map, waits for input and hides it again. If you close +the tool while it waits, the map remains revealed.

+
+
+

dfunstuck

+

Use if you prematurely close any of the tools and DF appears to be +stuck.

+
+
+

dfvdig

+

Designates a whole vein for digging. Point the cursor at a vein and run +this thing :)

+
+
+

dfflows

+

A tool for checking how many liquid tiles are actively checked for +flows.

+
+
+

dfattachtest

+

Test of the process attach/detach mechanism.

+
+
+

dfsuspend

+

Test of the process suspend/resume mechanism.

+
+
+

dfexpbench

+

Just a simple benchmark of the data export speed.

+
+
+

dfdoffsets

+

Dumps the offsets for the currently running DF version into the terminal.

+
+
+

dfcleartask

+

Solves the problem of unusable items after reclaim by clearing the 'in_job' bit of all items.

+
+
+

Your tool here

+

Write one ;)

+
+
+
+

Using the library as a developer

+

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 (and getting better all the +time).

+
+

Contributing to DFHack

+

Several things should be kept in mind when contributing to DFHack.

+
+

Coding style

+

DFhack uses ANSI formatting and four spaces as indentation. Line +endings are UNIX. The files use UTF-8 encoding. Code not following this +won't make me happy, because I'll have to fix it. There's a good chance +I'll make you fix it ;)

+
+
+

How to get new code into DFHack

+

You can send patches or make a clone of the github repo and ask me on +the IRC channel to pull your code in. I'll review it and see if there +are any problems. I'll fix them if they are minor.

+

Fixes are higher in priority. If you want to work on something, but +don't know what, check out http://github.com/peterix/dfhack/issues -- +this is also a good place to dump new ideas and/or bugs that need +fixing.

+
+
+

Layout for tools

+

Tools live in the tools/ folder. There, they are split into three +categories.

+
+
distributed
+
these tools get distributed with binary releases and are installed +by doing 'make install' on linux. They are supposed to be stable +and supported. Experimental, useless, buggy or untested stuff +doesn't belong here.
+
examples
+
examples are tools that aren't very useful, but show how DF and +DFHack work. They should use only DFHack API functions. No actual +hacking or 'magic offsets' are allowed.
+
playground
+
This is a catch-all folder for tools that aren't ready to be +examples or be distributed in binary releases. All new tools should +start here. They can contain actual hacking, magic values and other +nasty business.
+
+
+
+

Modules - what are they?

+

DFHack uses modules to partition sets of features into manageable +chunks. A module can have both client and server side.

+

Client side is the part that goes into the main library and is +generally written in C++. It is exposed to the users of DFHack.

+

Server side is used inside DF and serves to accelerate the client +modules. This is written mostly in C style.

+

There's a Core module that shouldn't be changed, because it defines the +basic commands like reading and writing raw data. The client parts for +the Core module are the various implementations of the Process +interface.

+

A good example of a module is Maps. Named the same in both client and +server, it allows accelerating the reading of map blocks.

+

Communication between modules happens by using shared memory. This is +pretty fast, but needs quite a bit of care to not break.

+
+
+

Dependencies

+
+
Internal
+
either part of the codebase or statically linked.
+
External
+
linked as dynamic loaded libraries (.dll, .so, etc.)
+
+

If you want to add dependencies, think twice about it. All internal +dependencies for core dfhack should be either public domain or require +attribution at most. External dependencies for tools can be either +that, or any Free Software licenses.

+
+

Current internal dependencies

+
+
tinyxml
+
used by core dfhack to read offset definitions from Memory.xml
+
md5
+
an implementation of the MD5 hash algorithm. Used for identifying +DF binaries on Linux.
+
argstream
+
Allows reading terminal application arguments. GPL!
+
+
+
+

Current external dependencies

+
+
wide-character ncurses
+
used for the veinlook tool on Linux.
+
x11 libraries
+
used for sending key events on linux
+
+
+
+

Build-time dependencies

+
+
cmake
+
you need cmake to generate the build system and some configuration +headers
+
+
+
+
+
+
+

Memory offset definitions

+

The files with memory offset definitions used by dfhack can be found in the +data folder.

+
+
+ + diff --git a/build/generate-MSVC-2002.bat b/build/generate-MSVC-2002.bat deleted file mode 100644 index 4f6b68065..000000000 --- a/build/generate-MSVC-2002.bat +++ /dev/null @@ -1,4 +0,0 @@ -mkdir build-real -cd build-real -cmake ..\.. -G"Visual Studio 7" -pause \ No newline at end of file diff --git a/build/generate-MSVC-2003.bat b/build/generate-MSVC-2003.bat deleted file mode 100644 index c45e02e4f..000000000 --- a/build/generate-MSVC-2003.bat +++ /dev/null @@ -1,4 +0,0 @@ -mkdir build-real -cd build-real -cmake ..\.. -G"Visual Studio 7 .NET 2003" -pause \ No newline at end of file diff --git a/output/Memory-40d.xml b/data/Memory-40d.xml similarity index 100% rename from output/Memory-40d.xml rename to data/Memory-40d.xml diff --git a/data/Memory-ng.xml b/data/Memory-ng.xml new file mode 100644 index 000000000..294886988 --- /dev/null +++ b/data/Memory-ng.xml @@ -0,0 +1,1665 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + TODO: Parse this and turn it into Job tags + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+ + + + + + .,:rsr, + :2;,;r2A@@5 + @2::s5A#@@@ @r. . + sd;:riXA#@@ :@@@Gir;;AS9 + Bs::sS3A#@2 @@#AhXirsS#; + iHrLr5d#@@@ .@#95sr;;rie + i*' `*@3 @@A2sr;:;r#5 + :..:rll: @@A5sr::r3@ + @Hr;iZ#@@@@ `:rr;;;;: + S@r.;i2#@@@ @s. .. + @2::ri2A@@# B@G2ir:...5i + :@r,r3X##@@ @G5sr:..,:A + .@Ar;;rSB@@# H#2sr;,..,is + .' `* ,@ASs;:..,:B + ;rr;:,..,:. + `''' + W I N D O W S + and + W I N E + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + +
+ + + + + +
+ + + + + +
+
+ + + + + vector + vector + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + the skill that will be increased at the end of the mood (or not) + + seems to be indexes in the list of possible colors defined in the raws for each group + + + + + + + + + + + + + + + + + Incrementaly assigned + seems to be just like the old occupations + + + like mood materials, 0=bars, 4=stone, 5=wood, 57=cloth, 54=leather ... + subsubtype ? + subtype ? + index of material (for example, 2 is for silver) + set only for shell / bone mood requirements ? + + + + +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+
+ + + +
+ + + +
+ +
+ + + + +
+ + + + + + + + + + + + + + + + WORLD: 0x0165c1d0 ? + +
Was 0x17f5ab8 + + +
+
+
+
+
+
+
+
+
+
+
+
+ + +
+ + +
+ + + +
+
+ + + +
+ + + + + + + + + + + +
+
+
+
+
+
+ +
+ + +
+ + + +
+ + + +
+ + +
+
+ + +
+ + + +
+
+ + +
+ List of offsets in the VTable : + + + + + + + + + + (in the vtable) + + +
+
+ + + + + + + + +
+
+
+ + +
+
+
+
+
+
+ +
+
+
+ + + +
+
+ + +
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+ + +
+ + +
+ + + +
+
+ + + +
+ + +
+ + +
+ + +
+ + +
+
+
+
+
+ + + + + + + + +
+
BOGUS! + + +
+
+
+
+
+ + +
+
+ + + + + + + +
+ + + + + + + +
+
+
+
+
+ + + + + + + + +
+ + + + + + + + +
+ + +
+
+ + +
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ + + + + + + + + .-"""-. + ' \ + |,. ,-. | _________________________ + |()L( ()| | \ \ + |,' `".| | /_ Argh !!! \ + |.___.',| ` \________________________\ + .j `--"' ` `. + / ' ' \ + / / ` `. + / / ` . + / / l | + . , L I N U X | | + ,"`. .| | + _.' ``. | `..-'l + | `.`, | `. + | `. __.j ) + |__ |--""___| ,-' + `"--...,+"""" `._,.-' + + + + + + + +
+ + + + + + + + + + + + + + +
+
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + +
+ + + + + +
+
+ + + + + vector + vector + + + +
+
+
+ + + + + + + + + + + + + + CHMOD + VERIFY! + + + chmod + + + + + + + + + + + + + + + CHMOD + + + + + Incrementaly assigned + seems to be just like the old occupations + + + like mood materials, 0=bars, 4=stone, 5=wood, 57=cloth, 54=leather ... + subsubtype ? + subtype ? + index of material (for example, 2 is for silver) + set only for shell / bone mood requirements ? + + + + +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + +
+ + + +
+
+ + + +
+ + + +
+
+ + + + + + +
+ +
VERIFIED + + Creatures + ========= + WORLD + 0x139E0 + 0x92d79d4 + 0x92d79e0 = real one? seems like it + 0x92d7a10 + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + +
VERIFIED +
VERIFIED +
VERIFIED +
VERIFIED + + + + + + + + diff --git a/output/Memory.xml b/data/Memory.xml old mode 100755 new mode 100644 similarity index 78% rename from output/Memory.xml rename to data/Memory.xml index fa97b261a..fd0072623 --- a/output/Memory.xml +++ b/data/Memory.xml @@ -4,6 +4,7 @@ 0x0 + ==================================================================== T R A I T S ==================================================================== @@ -217,6 +218,17 @@ level_2="Often does the first thing that comes to mind" level_1="Acts impulsively" level_0="Always acts without considering alternatives or thinking through possibilities">29 + + ==================================================================== + M O O D S + ==================================================================== + + + + + + + ==================================================================== P R O F E S S I O N S ==================================================================== @@ -322,6 +334,7 @@ 88 89 90 + ==================================================================== J O B S ==================================================================== @@ -792,7 +805,32 @@ size=212 62 63 64 - + + ==================================================================== + L E V E L S + ==================================================================== + + + + + + + + + + + + + + + + + TODO verify level 16 and up's existence in DF2010 + + + + -1 for no cap + ==================================================================== L A B O R S ==================================================================== @@ -1427,6 +1465,8 @@ map_data_1b60_offset 0x1B9c 0x288 0x298 0x29C + 0x390 + 0x394 the skill that will be increased at the end of the mood (or not) 0x464 - 0x390 - 0x394 the skill that will be increased at the end of the mood (or not) 0x604 0x6D4 0x774 @@ -1447,20 +1485,23 @@ map_data_1b60_offset 0x1B9c Castes ====== - 0x70 - 0x64 - 0x68 0x51C - 0xACC 0x654 + 0xACC - Body Parts - ========== - 0x0 - 0x1C - 0x44 - 0x78 - 0x90 + Color Mods + ========== + 0x70 + 0x64 + 0x68 + + Body Parts + ========== + 0x0 + 0x1C + 0x44 + 0x78 + 0x90 Materials ========= @@ -1597,7 +1638,90 @@ map_data_1b60_offset 0x1B9c 0x0 Why do i have to redefine this ??? - + + 394ff63fc00fedd5df0b36e4beb589bc + 0x4c091569 +
0x014abee4
CHMOD +
0x1471FB0
BOGUS! +
0x180b10c
LOOKS O.K. +
0xe6c0dc
VERIFIED +
0xe9a1b0
VERIFIED +
0xe9a18c
VERIFIED +
0xaf12cc
VERIFIED +
0xE80780
LOOKS O.K. +
0xEB2878
LOOKS O.K. + 0x0 Why do i have to redefine this ??? + ... what? +
+ + c4b7e37dafa2716e31d29110968ac64e + 0x4c0f83d5 +
0xaf12d0
+
+ + 1c0b5254af1b8ff9a34b51c3f6609da3 + 0x4c1cbe4b +
0xaf32d8
0xaf12d0 +
0x180d11c
0x180b10c +
0xe6e0ec
+
0xe9c1c0
+
0xe9c19c
+ map size X: 0x16c4b10 + map size Y: 0x16c4b14 +
+ + a83e6b21307cf41fb54c315fa40dec86 + 0x4c1d69fe +
0x14acee8
+ +
+ rebase="0xD030" + + + 1a85839ab03df082974dc5629d3fbc26 + 0x4C3897C0 +
0xaff2d8
+
0x16D33CC
+
0x16D33FC
+ 0x4c + + Creatures + ========= +
0x168E73C
+
0x014b9f1c
+ 0X1F4 + 0x4AC + 0x64c + 0x71c + 0x7Bc + 0x0788 + 0x07A0 + 0x87c +
+ + 349d1ad6eda7b6c5e87f8e4726a0999a + 0x4C398089 + + + 552cfa417fd131204ebfee66aefc4adb + 0x4C496D93 +
0xB062D8
+
0xe81114
VERIFIED +
0xeAF1E8
VERIFIED +
0xeAF1C4
VERIFIED +
+ + f0459165a426a9f2dd8d957e9fa7f01d + 0x4C4C32E7 + .-"""-. ' \ |,. ,-. | _________________________ @@ -1615,185 +1739,229 @@ map_data_1b60_offset 0x1B9c | `.`, | `. | `. __.j ) |__ |--""___| ,-' - `"--...,+"""" `._,.-' - - + `"--...,+"""" `._,.-' + - - 1d759a11af258263ef5c139d6d9a3e15 + Basic things ============ - 0xC - 0x0 - 0x4 - + 0xC VERIFIED + 0x0 VERIFIED + 0x4 VERIFIED + + MAP BLOCK OFFSETS + ================= + 0x08 VERIFIED + 0x20 VERIFIED + 0x24 VERIFIED + 0x006A VERIFIED + 0x026C VERIFIED + 0x066c VERIFIED + 0x156c VERIFIED + 0x176c VERIFIED + 0x1D6C VERIFIED + 0x0D6c VERIFIED + + MAP FEATURE OFFSETS + =================== + 0x94 VERIFIED + 0x28 VERIFIED + 0x2C VERIFIED + + 0x24 VERIFIED + 0x28 VERIFIED + + values for the region structure + =============================== + 0x58 VERIFIED + 0x54 VERIFIED + geoblock offsets + ================ + 0x4 VERIFIED + 0x4 VERIFIED + Name struct + =========== + 0x0 VERIFIED + 0x4 VERIFIED + 0x8 VERIFIED + + Creature offsets + ================ + 0x0 VERIFIED + 0x3c CHMOD + 0x40 CHMOD + 0x44 CHMOD + 0x90 BAD!! + 0x8C CHMOD + 0x90 CHMOD + 0xA4 VERIFY + 0xA6 CHMOD + 0xA8 CHMOD + 0xB4 VERIFY! + 0X144 CHMOD + 0x18C VERIFY! + 0x19C VERIFY! + 0x1A0 VERIFY! + 0x464 BAD! + 0x258 CHMOD + 0x394 VERIFY! + the skill that will be increased at the end of the mood (or not) + 0x604 BAD! + 0x6D4 BAD! + 0x51C CHMOD + 0x0500 CHMOD + 0x0758 BAD! + 0x5AC CHMOD + + Souls + ===== + 0x0 + 0x1C4 CHMOD + 0x1DC CHMOD + 0x88 BAD! + + Body Parts + ========== + 0x0 + 0x1C + 0x44 + 0x78 + 0x90 + + Job structure + ============= + 0x0 Incrementaly assigned + 0x8 seems to be just like the old occupations + 0xa4 + + Job materials + ============= + 0x0 like mood materials, 0=bars, 4=stone, 5=wood, 57=cloth, 54=leather ... + 0x2 subsubtype ? + 0x4 subtype ? + 0x8 index of material (for example, 2 is for silver) + 0x18 set only for shell / bone mood requirements ? + + Creature type offsets + ===================== + 0x60 VERIFIED + from 0.31.08 + Toad: 0xaf75b68 + Toad: rawname = 0x0 + Toad: character (not reliable) = 0x20 + Toad: caste vector = 0x60 + Toad: extract? vector = 0x18f4 + Toad: colors = 0x36 + 0x18f4 VERIFIED + 0x20 VERIFIED + 0x36 LOOKS OK + + Castes + ====== + 0x70 + 0x64 + 0x68 + 0x51C + 0xACC + 0x654 + + + + Color descriptors + ================= + 0x0 VERIFIED + 0x1C VERIFIED + 0x24 VERIFIED + 0x28 VERIFIED + 0x2C VERIFIED + + Language tables + =============== + 0x1C VERIFIED + + Constructions + ============= + 0x14 + + + + 1d759a11af258263ef5c139d6d9a3e15 -
0x92D00C0
0x0165B188 +
0x92D00C0
Position and window dimensions ============================== -
0x8cd3b18
0xe32798 -
0x8cd3b1c
0xe60838 -
0x8cd3b20
0xe60814 -
0x8b17370
0xae82cc +
0x8cd3b18
+
0x8cd3b1c
+
0x8cd3b20
+
0x8b17370
+
0x9464d6c
-
0x9464d6c
0x17f5ab8 GUI State ========= -
0x92c971c
0x146e45f - - Map stuff + Map data =========
0x9322d20
WORLD + 0x52C60 - 0x08 - 0x20 - 0x24 - 0x006A - 0x026C - 0x066c - 0x156c - 0x176c - 0x1D6C - 0x0D6c Map Features ============ WORLD + 0x5487C
0x932493C
- 0x94 - 0x28 - 0x2C WORLD + 0x548F4
0x93249B4
- 0x24 - 0x28 * map size in blocks * -
0x9322d34
0x016ad738 -
0x9322d38
0x016ad73C -
0x9322d3C
0x016ad740 +
0x9322d34
+
0x9322d38
+
0x9322d3C
* map size in tiles * -
0x9322d40
0x016ad744 -
0x9322d44
0x016ad748 -
0x9322d48
0x016ad74C +
0x9322d40
+
0x9322d44
+
0x9322d48
* region coords * WORLD + 0x525C8 -
0x9322d4C
0x016ad750 +
0x9322d4C
WORLD + 0x525CC -
0x9322d50
0x016ad754 +
0x9322d50
WORLD + 0x525D0 -
0x9322d54
0x016ad758 +
0x9322d54
* World size * (WORDs) WORLD + 0x542E0 -
0x93243A0
0x016AEDD4 +
0x93243A0
WORLD + 0x542E2 -
0x93243A2
0x016AEDD6 +
0x93243A2
WORLD + 0x54894 -
0x9324954
FIX 0x16AF52C +
0x9324954
WORLD + 0x548B8 -
0x9324978
FIX 0x16AF574 - - values for the region structure - =============================== - 0x58 0x64 FIX - 0x54 0x60 FIX - geoblock offsets - ================ - 0x4 vector - 0x4 vector - - Name struct - =========== - 0x0 - 0x4 - 0x8 +
0x9324978
Creatures =========
0x092E3AA0
0x092CB608
0x092CB5FC
- 0x0 - 0x6c - 0x3c * - 0x44 * - 0x90 - 0x8C * - 0x90 * - 0x110 - 0xA6 * - 0x114 - 0XB4 * - 0X1F4 - 0X21C - - 0x18C * - 0x19C * - 0x1A0 * - 0x464 - 0x390 from chmod - 0x394 the skill that will be increased at the end of the mood (or not) - 0x604 - 0x6D4 - 0x774 - 0x0740 - 0x0758 - 0x834 - - Souls - ===== - 0x0 - 0x1F4 - 0x224 - 0x88 - - Castes - ====== - 0x70 - 0x64 - 0x68 - 0x51C - 0xACC - 0x654 - - Body Parts - ========== - 0x0 - 0x1C - 0x44 - 0x78 - 0x90 - - Job structure - ============= - 0x0 Incrementaly assigned - 0x8 seems to be just like the old occupations - 0xa4 - - Job materials - ============= - 0x0 like mood materials, 0=bars, 4=stone, 5=wood, 57=cloth, 54=leather ... - 0x2 subsubtype ? - 0x4 subtype ? - 0x8 index of material (for example, 2 is for silver) - 0x18 set only for shell / bone mood requirements ? Materials ========= @@ -1812,32 +1980,29 @@ map_data_1b60_offset 0x1B9c creature types actually used for creatures,
0x09324F14
- 0x138 - 0x1A14 - 0xE0 - 0xF6 + + Color descriptors + ================= +
0x9329378
VERIFIED +
0x9329390
VERIFIED Translations ============ WORLD + 0x54E50 -
23
+
0x9324fd4
WORLD + 0x54E80 -
24
- 0x4C +
0x9324fec
Constructions ============= WORLD + 0x84
0x92D0144
0x165b290 - 0x14 + + Time + ==== +
0x92C9680
+
0x92C9688
+
+ + fea3801a26538b1741f3cc9294139fca + +
0x92C60E0
MOST PROBABLY BOGUS! + + Position and window dimensions + ============================== +
0x8cc9b38
VERIFIED +
0x8cc9b3c
VERIFIED +
0x8cc9b40
VERIFIED +
0x8b0d36c
VERIFIED +
0x945ad8c
VERIFIED + GUI State + ========= +
0x92bf73c
VERIFIED + + Map data + ======== + WORLD + 0x52C60? +
0x9318D40
VERIFIED + + Map Features + ============ + WORLD + 0x5487C? +
0x931A95C
VERIFIED + WORLD + 0x548F4? +
0x931A9D4
VERIFIED + + * map size in blocks * +
0x9318D54
VERIFIED +
0x9318D58
VERIFIED +
0x9318D5C
VERIFIED + + * map size in tiles * +
0x9318D60
VERIFIED +
0x9318D64
VERIFIED +
0x9318D68
VERIFIED + + * region coords * + WORLD + 0x525C8 +
0x9318D6C
VERIFIED + WORLD + 0x525CC +
0x9318D70
VERIFIED + WORLD + 0x525D0 +
0x9318D74
VERIFIED (old = 0x9322d54) + + * World size * (WORDs) + WORLD + 0x542E0 +
0x931A3C0
VERIFIED + WORLD + 0x542E2 +
0x931A3C2
VERIFIED + WORLD + 0x54894 +
0x931A974
VERIFIED + WORLD + 0x548B8 +
0x931A998
VERIFIED + + Materials + ========= + soil, stone, metal + inorganics vector +
0x931ae88
VERIFIED + + wood and plant matter +
0x931ae94
VERIFIED + + plant matter +
0x931aea0
VERIFIED + + just wood +
0x931aeb8
VERIFIED + + creature types actually used for creatures, +
0x931af34
VERIFIED + + Color descriptors + ================= +
0x931f398
VERIFIED +
0x931f3b0
VERIFIED + + Translations + ============ + WORLD + 0x54E50 +
0x931aff4
+ WORLD + 0x54E80 +
0x931b00c
+ + Creatures + ========= +
0x92D9AC0
+
0x92C1628
0x092CB608 +
0x92C161C
0x092CB5FC + Time ==== -
0x92C9688
-
0x92C9680
+
0x92BF6A0
+
0x92BF6A8
+ YEAR 0x92BF6A0, WORLD - 0x6A40 + TICKS 0x92BF6A8, WORLD - 0x6A40 + 0x08 + +
+ + 13a1c19e8f59b74e307e094e2a0f28c3 +
0x8b0b328
VERIFIED + WORLD = 0x92C4000 + Creatures + ========= + WORLD + 0x139E0 + 0x92d79d4 + 0x92d79e0 = real one? seems like it + 0x92d7a10 +
+ + b31979551782e89c049b11db8d2d86d7 + + + e37750890350d7b9d8203879aff8fa5c + + + + + 4f1f988bc1b425d4193d3d8b7b0579a5 + stealing memory... + looking for vectors... + ------------------- + !!LANGUAGE TABLES!! + ------------------- + translation vector: 0x932bf2c + lang vector: 0x932bf14 + word table offset: 0x1c + ------------- + !!MATERIALS!! + ------------- + inorganics: + 0x932bda8 + organics: + 0x932bdb4 + trees: + 0x932bdd8 + plants: + 0x932bdc0 + color descriptors: + 0x93302b8 + Amber color:0xaf842e0 + all descriptors: + 0x93302d0 + toad-first creature types: + 0x932be54 + all creature types: + 0x932be2c + 0x932be54 + Toad: 0xb076f88 + Toad: rawname = 0x0 + Toad: character (not reliable) = 0x20 + Toad: caste vector = 0x60 + Toad: extract? vector = 0x18f4 + Toad: colors = 0x36 + + + 3e7bea269018a6fb88ef53715685aa64 + ------------------- + !!LANGUAGE TABLES!! + ------------------- + translation vector: 0x932bf2c + lang vector: 0x932bf14 + word table offset: 0x1c + ------------- + !!MATERIALS!! + ------------- + inorganics: + 0x932bda8 + organics: + 0x932bdb4 + trees: + 0x932bdd8 + plants: + 0x932bdc0 + color descriptors: + 0x93302b8 + Amber color:0xcc3a770 + all descriptors: + 0x93302d0 + toad-first creature types: + 0x932be54 + elephant-first creature types: + all creature types: + 0x932be2c + 0x932be54 + Toad: 0xc77d798 + Toad: rawname = 0x0 + Toad: character (not reliable) = 0x20 + Toad: caste vector = 0x60 + Toad: extract? vector = 0x18f4 + Toad: colors = 0x36 + + Buildings + ========= +
0x92eb068
+ 0xE0 + +
0x93302e8
+ 0x4 + 0x8 + + + + + + +
+ + + 7b04ad536b8b657588ac209a7f95e1d1 +
0x8cf7a58
VERIFIED +
0x8cf7a5C
VERIFIED +
0x8cf7a60
VERIFIED +
0x8b3b328
VERIFIED + ------------------- + !!LANGUAGE TABLES!! + ------------------- + translation vector: 0x9348f4c + lang vector: 0x9348f34 + word table offset: 0x1c + ------------- + !!MATERIALS!! + ------------- + inorganics: + 0x9348dc8 + organics: + 0x9348dd4 + trees: + 0x9348df8 + plants: + 0x9348de0 + color descriptors: + 0x934d2d8 + Amber color:0xac014c0 + all descriptors: + 0x934d2f0 + toad-first creature types: + 0x9348e74 + all creature types: + 0x9348e4c + 0x9348e74 + Toad: 0xadae390 + Toad: rawname = 0x0 + Toad: character (not reliable) = 0x20 + Toad: caste vector = 0x60 + Toad: extract? vector = 0x18f4 + Toad: colors = 0x36 +
+ + e79cead03187ecb692961b316b7cdcd4
diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt new file mode 100644 index 000000000..1ced1fd7b --- /dev/null +++ b/doc/CMakeLists.txt @@ -0,0 +1,68 @@ +# repurposed from libnoise: http://github.com/qknight/libnoise/tree/master/doc/ +# following code and comments is by the original author, with some changes by +# me (peterix) +# ------------------------------------------------------------------------------ +# +# many thanks go to Philippe Poilbarbe for writing the code this file is based on +# http://www.cmake.org/pipermail/cmake/2006-August/010794.html +# +# much later i also found this: +# http://tobias.rautenkranz.ch/cmake/doxygen/ +# but it is hard to understand... + +IF (BUILD_DFHACK_DOCUMENTATION) + +FIND_PACKAGE(Doxygen) + +IF(DOXYGEN_FOUND) + SET(DOXYGEN_LANGUAGE "English" CACHE STRING "Language used by doxygen") + MARK_AS_ADVANCED(DOXYGEN_LANGUAGE) + + # you could also set the version with this, see Doxygen.in + # there you will find a line like this: + # PROJECT_NUMBER = @DFHACK_VERSION@ + # @DFHACK_VERSION@ is then replaced by our global DFHACK_VERSION + # + # for instance you could uncomment the next 3 lines and change the version for testing + # SET(DFHACK_VERSION + # "1.2.3-foo500" + # ) + + # doxygen can reference external images with IMAGE_PATH, this is how we set it dynamically + SET( CMAKE_DOXYGEN_IMAGE_PATH + "${CMAKE_CURRENT_SOURCE_DIR}/img" + ) + + # doxygen searches for source code (defined in FILE_PATTERNS, for example: *.cpp *.h) + # with DOXYGEN_SOURCE_DIR we fill a list of directories and later we write it into + # the Doxyfile with a REGEX REPLACE (see below) + SET( DOXYGEN_SOURCE_DIR + # "${CMAKE_SOURCE_DIR}/library" + "${CMAKE_SOURCE_DIR}/doc/index.dxgen" + "${CMAKE_SOURCE_DIR}/library/include" + "${CMAKE_SOURCE_DIR}/library/include/dfhack" + "${CMAKE_SOURCE_DIR}/library/include/dfhack/modules" + "${CMAKE_SOURCE_DIR}/library/include/dfhack-c" + "${CMAKE_SOURCE_DIR}/library/include/dfhack-c/modules" +# "${CMAKE_SOURCE_DIR}/library/modules" +# "${CMAKE_SOURCE_DIR}/library/shm" +# "${CMAKE_SOURCE_DIR}/library/private" + ) + + SET(DOXYGEN_OUTPUT_DIR html) + STRING(REGEX REPLACE ";" " " CMAKE_DOXYGEN_INPUT_LIST "${DOXYGEN_SOURCE_DIR}") + + CONFIGURE_FILE(Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) + SET(HTML_TARGET "html" ) + + ADD_CUSTOM_TARGET(${HTML_TARGET} ALL + /usr/bin/doxygen ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) + + INSTALL( DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/html/" DESTINATION "/usr/share/doc/dfhack-${DFHACK_VERSION}" ) + +ELSE(DOXYGEN_FOUND) + MESSAGE (FATAL_ERROR "doxygen binary couldn't be found") +ENDIF(DOXYGEN_FOUND) + +ENDIF (BUILD_DFHACK_DOCUMENTATION) \ No newline at end of file diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in new file mode 100644 index 000000000..7c4302fa2 --- /dev/null +++ b/doc/Doxyfile.in @@ -0,0 +1,212 @@ +# Doxyfile 1.3.9.1 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = dfhack +PROJECT_NUMBER = @DFHACK_VERSION@ +OUTPUT_DIRECTORY = . +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +USE_WINDOWS_ENCODING = NO +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = NO +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = YES +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = YES +INHERIT_DOCS = YES +DISTRIBUTE_GROUP_DOC = NO +TAB_SIZE = 4 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +SUBGROUPING = YES +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = NO +EXTRACT_LOCAL_METHODS = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = YES +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = @CMAKE_DOXYGEN_INPUT_LIST@ +FILE_PATTERNS = *.cpp *.h *.dxgen +RECURSIVE = NO +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = @CMAKE_DOXYGEN_IMAGE_PATH@ +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html + +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 8 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = NO +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = DOXYGEN_SHOULD_SKIP_THIS +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = YES +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = YES +GRAPHICAL_HIERARCHY = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +MAX_DOT_GRAPH_WIDTH = 1024 +MAX_DOT_GRAPH_HEIGHT = 1024 +MAX_DOT_GRAPH_DEPTH = 0 +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/doc/img/.dot b/doc/img/.dot new file mode 100644 index 000000000..e69de29bb diff --git a/doc/index.dxgen b/doc/index.dxgen new file mode 100644 index 000000000..d356131f6 --- /dev/null +++ b/doc/index.dxgen @@ -0,0 +1,73 @@ +/******************************************************************************* +www.sourceforge.net/projects/dfhack +Copyright (c) 2009 Petr Mrázek (peterix) + +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. +*/ + +/*! \page index +
+\htmlonly +

DFHack

+ +\endhtmlonly +
+ +

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. In general, you can use it to move memory +objects in and out of Dwarf Fortress really fast, regardless of DF version or OS. + +First part of the manual deals with the basic of using DFHack as a library: +
    +PLACEHOLDER TERRITORY! + +
  • Section \ref blah discusses some weird stuff + this is a link +
  • Section \ref starting tells you how to cromulate at a distance! +
+ +Second part has some details on DFHack development: + +
    +
  • Section \ref starting tells you how to cromulate at a distance! +
+ +The third part describes how to use the supported DFHack utilities + +
    +
  • Section \ref dfattachtest shows how to use the \c dfattachtest program +
  • Section \ref dfcleanmap shows how to use the \c dfcleanmap program +
  • Section \ref dfexpbench shows how to use the \c dfexpbench program +
  • Section \ref dfflows shows how to use the \c dfflows program +
  • Section \ref dfliquids shows how to use the \c dfliquids program +
  • Section \ref dfprobe shows how to use the \c dfprobe program +
  • Section \ref dfprospector shows how to use the \c dfprospector program +
  • Section \ref dfreveal shows how to use the \c dfreveal program +
  • Section \ref dfsuspend shows how to use the \c dfsuspend program +
  • Section \ref dfunstuck shows how to use the \c dfunstuck program +
  • Section \ref dfvdig shows how to use the \c dfvdig program +
+*/ + diff --git a/fixTexts.sh b/fixTexts.sh new file mode 100755 index 000000000..30ee0c52c --- /dev/null +++ b/fixTexts.sh @@ -0,0 +1,3 @@ +#!/bin/bash +rst2html README.rst > Readme.html +rst2html COMPILE.rst > Compile.html diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index ce44079cf..8e09a2203 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -27,9 +27,11 @@ include_directories (${CMAKE_SOURCE_DIR}/library/depends/argstream/) include_directories (${CMAKE_SOURCE_DIR}/library/private/) SET(PROJECT_HDRS +private/DFMemInfoManager.h +private/ContextShared.h +private/Internal.h include/dfhack/DFError.h include/dfhack/DFMemInfo.h -include/dfhack/DFMemInfoManager.h include/dfhack/DFProcessEnumerator.h include/dfhack/DFProcess.h include/dfhack/DFTileTypes.h @@ -52,14 +54,18 @@ include/dfhack/modules/WindowIO.h include/dfhack/modules/World.h ) +SET(PROJECT_C_HDRS +include/dfhack-c/DFTypes_C.h +include/dfhack-c/DFContext_C.h +) + SET(PROJECT_SRCS DFMemInfo.cpp DFMemInfoManager.cpp DFContextManager.cpp DFContext.cpp +DFProcessEnumerator.cpp ContextShared.cpp -DFContext_C.cpp -DFTypes_C.cpp depends/md5/md5.cpp depends/md5/md5wrapper.cpp @@ -80,6 +86,11 @@ modules/Position.cpp modules/Translation.cpp modules/Vegetation.cpp modules/World.cpp +) + +SET(PROJECT_C_SRCS +DFContext_C.cpp +DFTypes_C.cpp modules/Buildings_C.cpp modules/Constructions_C.cpp @@ -91,6 +102,8 @@ modules/Position_C.cpp modules/Materials_C.cpp modules/Translation_C.cpp modules/Vegetation_C.cpp +modules/WindowIO_C.cpp +modules/World_C.cpp ) SET(PROJECT_HDRS_LINUX @@ -105,14 +118,12 @@ DFProcess-linux.cpp DFProcess-linux-SHM.cpp DFProcess-linux-wine.cpp modules/WindowIO-linux.cpp -DFProcessEnumerator-linux.cpp ) SET(PROJECT_SRCS_WINDOWS DFProcess-windows.cpp DFProcess-windows-SHM.cpp modules/WindowIO-windows.cpp -DFProcessEnumerator-windows.cpp ) IF(UNIX) @@ -123,6 +134,11 @@ ELSE(UNIX) LIST(APPEND PROJECT_SRCS ${PROJECT_SRCS_WINDOWS}) ENDIF(UNIX) +IF(BUILD_DFHACK_C_BINDIGS) + LIST(APPEND PROJECT_HDRS ${PROJECT_C_HDRS}) + LIST(APPEND PROJECT_SRCS ${PROJECT_C_SRCS}) +ENDIF(BUILD_DFHACK_C_BINDIGS) + SET_SOURCE_FILES_PROPERTIES( ${PROJECT_HDRS} PROPERTIES HEADER_FILE_ONLY TRUE ) LIST(APPEND PROJECT_SRCS ${PROJECT_HDRS}) @@ -161,65 +177,29 @@ SET_TARGET_PROPERTIES(dfhack PROPERTIES DEBUG_POSTFIX "-debug" ) TARGET_LINK_LIBRARIES(dfhack ${PROJECT_LIBS}) +if(MSVC) + # This is a MSVC hack used for copying files into the target directory + # of build target set in MSVC. + # It exploits the fact that MSVC has some variables in .vcproj files, much like cmake does here. + # + # So, $(TargetDir) is ignored by cmake, and replaced with the actual output directory by MSVC + ADD_CUSTOM_COMMAND(TARGET dfhack POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/data/Memory.xml $(TargetDir)/Memory.xml + ) + ADD_CUSTOM_COMMAND(TARGET dfhack POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/Compile.html $(TargetDir)/Compile.html + ) + ADD_CUSTOM_COMMAND(TARGET dfhack POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/Readme.html $(TargetDir)/Readme.html + ) +else(MSVC) + # Just put the file in the output directory on Linux and Mac + configure_file(${CMAKE_SOURCE_DIR}/data/Memory.xml ${DATA_OUTPUT_PATH}/Memory.xml COPYONLY) + configure_file(${CMAKE_SOURCE_DIR}/Compile.html ${DATA_OUTPUT_PATH}/Compile.html COPYONLY) + configure_file(${CMAKE_SOURCE_DIR}/Readme.html ${DATA_OUTPUT_PATH}/Readme.html COPYONLY) +endif(MSVC) + IF(UNIX) install(TARGETS dfhack LIBRARY DESTINATION lib) install(FILES ${CMAKE_SOURCE_DIR}/output/Memory.xml DESTINATION share/dfhack) ENDIF(UNIX) - -################################################################################ -# DFCONNECT -### - -SET(DFCONNECT_HDRS -shm/shms.h -shm/mod-core.h -shm/mod-maps.h -) - -SET(PROJECT_SRCS -shm/mod-core.cpp -shm/mod-maps.cpp -#mod-creature40d.cpp -) - -SET(PROJECT_HDRS_LINUX -) - -SET(PROJECT_HDRS_WINDOWS -) - -SET(PROJECT_SRCS_LINUX -shm/shms-linux.cpp -) - -SET(PROJECT_SRCS_WINDOWS -shm/shms-windows.cpp -) - -IF(UNIX) - LIST(APPEND PROJECT_HDRS ${PROJECT_HDRS_LINUX}) - LIST(APPEND PROJECT_SRCS ${PROJECT_SRCS_LINUX}) -ELSE(UNIX) - LIST(APPEND PROJECT_HDRS ${PROJECT_HDRS_WINDOWS}) - LIST(APPEND PROJECT_SRCS ${PROJECT_SRCS_WINDOWS}) -ENDIF(UNIX) - - -SET_SOURCE_FILES_PROPERTIES( ${PROJECT_HDRS} PROPERTIES HEADER_FILE_ONLY TRUE ) - -LIST(APPEND PROJECT_SRCS ${PROJECT_HDRS}) - -#IF(CMAKE_SIZEOF_VOID_P EQUAL 4) - IF(UNIX) - add_definitions(-DLINUX_BUILD) - SET(PROJECT_LIBS rt) - SET(CMAKE_CXX_FLAGS "-fvisibility=hidden") - ADD_LIBRARY(dfconnect SHARED ${PROJECT_SRCS}) - TARGET_LINK_LIBRARIES(dfconnect ${PROJECT_LIBS}) - ELSE(UNIX) - # SET(PROJECT_LIBS psapi) - ADD_LIBRARY(SDL SHARED ${PROJECT_SRCS}) - TARGET_LINK_LIBRARIES(SDL ${PROJECT_LIBS}) - ENDIF(UNIX) -#ENDIF(CMAKE_SIZEOF_VOID_P EQUAL 4) - diff --git a/library/ContextShared.cpp b/library/ContextShared.cpp index 7798cc85f..cf49a489b 100644 --- a/library/ContextShared.cpp +++ b/library/ContextShared.cpp @@ -24,33 +24,18 @@ using namespace DFHack; DFContextShared::DFContextShared() { // init modules - creatures = 0; - maps = 0; - position = 0; - gui = 0; - world = 0; - materials = 0; - translation = 0; - vegetation = 0; - buildings = 0; - constructions = 0; - items = 0; - windowio = 0; + allModules.clear(); + memset(&(s_mods), 0, sizeof(s_mods)); } DFContextShared::~DFContextShared() { - if(creatures) delete creatures; - if(maps) delete maps; - if(position) delete position; - if(gui) delete gui; - if(materials) delete materials; - if(translation) delete translation; - if(vegetation) delete vegetation; - if(buildings) delete buildings; - if(constructions) delete constructions; - if(world) delete world; - if(windowio) delete windowio; + // invalidate all modules + for(int i = 0 ; i < allModules.size(); i++) + { + delete allModules[i]; + } + allModules.clear(); } bool DFContextShared::InitReadNames() diff --git a/library/DFContext.cpp b/library/DFContext.cpp index fe2d5002e..d46302426 100644 --- a/library/DFContext.cpp +++ b/library/DFContext.cpp @@ -27,7 +27,6 @@ distribution. #include "dfhack/DFProcess.h" #include "dfhack/DFProcessEnumerator.h" #include "dfhack/DFContext.h" -#include "dfhack/DFContext.h" #include "dfhack/DFError.h" #include @@ -89,10 +88,18 @@ bool Context::Detach() { if (!d->p->detach()) { + cerr << "Context::Detach failed!" << endl; return false; } d->shm_start = 0; // invalidate all modules + for(int i = 0 ; i < d->allModules.size(); i++) + { + delete d->allModules[i]; + } + d->allModules.clear(); + memset(&(d->s_mods), 0, sizeof(d->s_mods)); + /* if(d->creatures) { delete d->creatures; @@ -147,7 +154,7 @@ bool Context::Detach() { delete d->translation; d->translation = 0; - } + }*/ return true; } @@ -167,6 +174,10 @@ bool Context::AsyncSuspend() bool Context::Resume() { + for(int i = 0 ; i < d->allModules.size(); i++) + { + d->allModules[i]->OnResume(); + } return d->p->resume(); } bool Context::ForceResume() @@ -201,13 +212,39 @@ Process * Context::getProcess() /******************************************************************************* M O D U L E S *******************************************************************************/ + +#define MODULE_GETTER(TYPE) \ +TYPE * Context::get##TYPE() \ +{ \ + if(!d->s_mods.p##TYPE)\ + {\ + d->s_mods.p##TYPE = new TYPE(d);\ + d->allModules.push_back(d->s_mods.p##TYPE);\ + }\ + return d->s_mods.p##TYPE;\ +} + +MODULE_GETTER(Creatures); +MODULE_GETTER(Maps); +MODULE_GETTER(Gui); +MODULE_GETTER(WindowIO); +MODULE_GETTER(World); +MODULE_GETTER(Position); +MODULE_GETTER(Materials); +MODULE_GETTER(Items); +MODULE_GETTER(Translation); +MODULE_GETTER(Vegetation); +MODULE_GETTER(Buildings); +MODULE_GETTER(Constructions); +/* Creatures * Context::getCreatures() { if(!d->creatures) d->creatures = new Creatures(d); return d->creatures; } - +*/ +/* Maps * Context::getMaps() { if(!d->maps) @@ -284,7 +321,7 @@ Constructions * Context::getConstructions() d->constructions = new Constructions(d); return d->constructions; } - +*/ /* // returns number of buildings, expects v_buildingtypes that will later map t_building.type to its name diff --git a/library/DFContextManager.cpp b/library/DFContextManager.cpp index 636325bdc..46814d90e 100644 --- a/library/DFContextManager.cpp +++ b/library/DFContextManager.cpp @@ -23,10 +23,10 @@ distribution. */ #include "Internal.h" +#include "DFMemInfoManager.h" #include "dfhack/DFProcess.h" #include "dfhack/DFProcessEnumerator.h" -#include "dfhack/DFMemInfoManager.h" #include "dfhack/DFError.h" #include "dfhack/DFContext.h" @@ -41,61 +41,186 @@ distribution. using namespace DFHack; namespace DFHack { - class DFContextMgrPrivate + class ContextManager::Private { public: - DFContextMgrPrivate(){}; - ~DFContextMgrPrivate(){}; + Private(){}; + ~Private(){}; string xml; // path to xml vector contexts; ProcessEnumerator * pEnum; }; } +class DFHack::BadContexts::Private +{ + public: + Private(){}; + vector bad; +}; + + +BadContexts::BadContexts():d(new Private()){} + +BadContexts::~BadContexts() +{ + clear(); + delete d; +} + +bool BadContexts::Contains(Process* p) +{ + for(int i = 0; i < d->bad.size(); i++) + { + if((d->bad[i])->getProcess() == p) + return true; + } + return false; +} -ContextManager::ContextManager (const string path_to_xml) : d (new DFContextMgrPrivate()) +bool BadContexts::Contains(Context* c) +{ + for(int i = 0; i < d->bad.size(); i++) + { + if(d->bad[i] == c) + return true; + } + return false; +} + +uint32_t BadContexts::size() +{ + return d->bad.size(); +} + +void BadContexts::clear() +{ + for(int i = 0; i < d->bad.size(); i++) + { + // delete both Process and Context! + // process has to be deleted after context, because Context does some + // cleanup on delete (detach, etc.) + Process * to_kill = d->bad[i]->getProcess(); + delete d->bad[i]; + delete to_kill; + } + d->bad.clear(); +} + +void BadContexts::push_back(Context* c) +{ + if(c) + d->bad.push_back(c); +} + +Context * BadContexts::operator[](uint32_t index) +{ + if(index < d->bad.size()) + return d->bad[index]; + return 0; +} + +ContextManager::ContextManager (const string path_to_xml) : d (new Private()) { - d->pEnum = 0; d->xml = QUOT (MEMXML_DATA_PATH); d->xml += "/"; d->xml += path_to_xml; + d->pEnum = new ProcessEnumerator(d->xml); } ContextManager::~ContextManager() { purge(); + // process enumerator has to be destroyed after we detach from processes + // because it tracks and destroys them + if(d->pEnum) + { + delete d->pEnum; + d->pEnum = 0; + } delete d; } -uint32_t ContextManager::Refresh() +uint32_t ContextManager::Refresh( BadContexts* bad_contexts ) { - purge(); - if(d->pEnum != 0) - d->pEnum = new ProcessEnumerator(d->xml); - else + // handle expired processes, remove stale Contexts { - delete d->pEnum; - d->pEnum = new ProcessEnumerator(d->xml); + BadProcesses expired; + // get new list od living and expired Process objects + d->pEnum->Refresh(&expired); + + // scan expired, kill contexts if necessary + vector ::iterator it = d->contexts.begin();; + while(it != d->contexts.end()) + { + Process * test = (*it)->getProcess(); + if(expired.Contains(test)) + { + // ok. we have an expired context here. + if(!bad_contexts) + { + // with nowhere to put the context, we have to destroy it + delete *it; + // stop tracking it and advance the iterator + it = d->contexts.erase(it); + continue; + } + else + { + // we stuff the context into bad_contexts + bad_contexts->push_back(*it); + // stop tracking it and advance the iterator + it = d->contexts.erase(it); + // remove process from the 'expired' container, it is tracked by bad_contexts now + // (which is responsible for freeing it). + expired.excise(test); + continue; + } + } + else it++; // not expired, just advance to next one + } + // no expired contexts are in the d->contexts vector now + // all processes remaining in 'expired' are now destroyed along with it } - d->pEnum->purge(); - d->pEnum->findProcessess(); int numProcesses = d->pEnum->size(); + int numContexts = d->contexts.size(); + vector newContexts; + // enumerate valid processes for(int i = 0; i < numProcesses; i++) { - Context * c = new Context(d->pEnum->operator[](i)); - d->contexts.push_back(c); + Process * test = d->pEnum->operator[](i); + bool exists = false; + // scan context vector for this process + for(int j = 0; j < numContexts; j++) + { + if((d->contexts[j])->getProcess() == test) + { + // already have that one, skip + exists = true; + } + } + if(!exists) + { + // new process needs a new context + Context * c = new Context(d->pEnum->operator[](i)); + newContexts.push_back(c); + } } + d->contexts.insert(d->contexts.end(), newContexts.begin(), newContexts.end()); return d->contexts.size(); } + uint32_t ContextManager::size() { return d->contexts.size(); } + Context * ContextManager::operator[](uint32_t index) { if (index < d->contexts.size()) return d->contexts[index]; return 0; } + Context * ContextManager::getSingleContext() { if(!d->contexts.size()) @@ -111,16 +236,11 @@ Context * ContextManager::getSingleContext() } throw DFHack::Error::NoProcess(); } + void ContextManager::purge(void) { for(int i = 0; i < d->contexts.size();i++) delete d->contexts[i]; d->contexts.clear(); - // process enumerator has to be destroyed after we detach from processes - // because it tracks and destroys them - if(d->pEnum) - { - delete d->pEnum; - d->pEnum = 0; - } + d->pEnum->purge(); } \ No newline at end of file diff --git a/library/DFContext_C.cpp b/library/DFContext_C.cpp index 3de599df0..e6406c5be 100644 --- a/library/DFContext_C.cpp +++ b/library/DFContext_C.cpp @@ -240,7 +240,7 @@ DFHackObject* Context_getWindow(DFHackObject* context) { if(context != NULL) { - return (DFHackObject*)((DFHack::Context*)context)->getWindow(); + return (DFHackObject*)((DFHack::Context*)context)->getWindowIO(); } return NULL; diff --git a/library/DFMemInfo.cpp b/library/DFMemInfo.cpp index 8ac0a2c94..ca7c58d03 100644 --- a/library/DFMemInfo.cpp +++ b/library/DFMemInfo.cpp @@ -27,8 +27,60 @@ distribution. #include "dfhack/DFError.h" #include "dfhack/DFProcess.h" +//Inital amount of space in levels vector (since we usually know the number, efficent!) +#define NUM_RESERVE_LVLS 20 +#define NUM_RESERVE_MOODS 6 using namespace DFHack; +/* +* Common data types +*/ +namespace DFHack +{ + struct t_type + { + t_type(uint32_t assign, uint32_t type, std::string classname) + :classname(classname),assign(assign),type(type){}; + std::string classname; + uint32_t assign; + uint32_t type; + }; + + struct t_class + { + t_class(const t_class &old) + { + classname = old.classname; + vtable = old.vtable; + assign = old.assign; + type_offset = old.type_offset; + for(uint32_t i = 0; i < old.subs.size();i++) + { + t_type * t = new t_type (*old.subs[i]); + subs.push_back(t); + } + } + t_class () + { + vtable = 0; + assign = 0; + type_offset = 0; + } + ~t_class() + { + for(uint32_t i = 0; i < subs.size();i++) + { + delete subs[i]; + } + subs.clear(); + } + std::string classname; + uint32_t vtable; + uint32_t assign;// index to typeclass array if multiclass. return value if not. + uint32_t type_offset; // offset of type data for multiclass + std::vector subs; + }; +} /* * Private data */ @@ -43,7 +95,9 @@ class memory_info::Private vector professions; vector jobs; vector skills; + vector levels; vector< vector > traits; + vector moods; map labors; // storage for class and multiclass @@ -71,6 +125,8 @@ memory_info::memory_info() d->base = 0; d->p = 0; d->classindex = 0; + d->levels.reserve(NUM_RESERVE_LVLS); + d->moods.reserve(NUM_RESERVE_MOODS); } // copy constructor @@ -97,6 +153,8 @@ memory_info::memory_info(const memory_info &old) d->skills = old.d->skills; d->traits = old.d->traits; d->labors = old.d->labors; + d->levels = old.d->levels; + d->moods = old.d->moods; } void memory_info::setParentProcess(Process * _p) { @@ -251,6 +309,30 @@ void memory_info::setSkill (const string & key, const string & value) d->skills[keyInt] = value; } +void memory_info::setLevel(const std::string &nLevel, + const std::string &nName, + const std::string &nXp) +{ + uint32_t keyInt = strtol(nLevel.c_str(), NULL, 10); + + if(d->levels.size() <= keyInt) + d->levels.resize(keyInt+1); + + d->levels[keyInt].level = keyInt; + d->levels[keyInt].name = nName; + d->levels[keyInt].xpNxtLvl = strtol(nXp.c_str(), NULL, 10); +} + +void memory_info::setMood(const std::string &id, const std::string &mood) +{ + uint32_t keyInt = strtol(id.c_str(), NULL, 10); + + if(d->moods.size() <= keyInt) + d->moods.resize(keyInt+1); + + d->moods[keyInt] = mood; +} + void memory_info::setTrait(const string & key, const string & value, const string & zero, @@ -564,6 +646,7 @@ string memory_info::getProfession (const uint32_t key) const string memory_info::getJob (const uint32_t key) const { if(d->jobs.size() > key) + { return d->jobs[key]; } @@ -579,6 +662,15 @@ string memory_info::getSkill (const uint32_t key) const throw Error::MissingMemoryDefinition("skill", key); } +DFHack::t_level memory_info::getLevelInfo(const uint32_t level) const +{ + if(d->levels.size() > level) + { + return d->levels[level]; + } + throw Error::MissingMemoryDefinition("Level", level); +} + // FIXME: ugly hack that needs to die int absolute (int number) { @@ -621,6 +713,11 @@ string memory_info::getTraitName(const uint32_t traitIdx) const throw Error::MissingMemoryDefinition("traitname", traitIdx); } +std::vector< std::vector > const& memory_info::getAllTraits() +{ + return d->traits; +} + string memory_info::getLabor (const uint32_t laborIdx) { if(d->labors.count(laborIdx)) @@ -630,3 +727,52 @@ string memory_info::getLabor (const uint32_t laborIdx) throw Error::MissingMemoryDefinition("labor", laborIdx); } +std::string memory_info::getMood(const uint32_t moodID) +{ + if(d->moods.size() > moodID) + { + return d->moods[moodID]; + } + throw Error::MissingMemoryDefinition("Mood", moodID); +} + +std::string memory_info::PrintOffsets() +{ + ostringstream ss; + ss << "" << endl; + switch (getOS()) + { + case OS_LINUX: + ss << "" << endl; + break; + case OS_WINDOWS: + ss << "" << endl; + ss << "" << endl; + break; + default: + ss << " UNKNOWN" << endl; + } + ss << "" << endl; + map::const_iterator iter; + for(iter = d->addresses.begin(); iter != d->addresses.end(); iter++) + { + ss << "
" << endl; + } + map::const_iterator iter2; + for(iter2 = d->offsets.begin(); iter2 != d->offsets.end(); iter2++) + { + ss << " " << endl; + } + for(iter = d->hexvals.begin(); iter != d->hexvals.end(); iter++) + { + ss << " " << endl; + } + map::const_iterator iter3; + for(iter3 = d->strings.begin(); iter3 != d->strings.end(); iter3++) + { + ss << " " << endl; + } + ss << "" << endl; + ss << "" << endl; + return ss.str(); +} \ No newline at end of file diff --git a/library/DFMemInfoManager.cpp b/library/DFMemInfoManager.cpp index 4b7f537e0..cc4c5de4a 100644 --- a/library/DFMemInfoManager.cpp +++ b/library/DFMemInfoManager.cpp @@ -23,8 +23,9 @@ distribution. */ #include "Internal.h" +#include "DFMemInfoManager.h" + #include "dfhack/DFMemInfo.h" -#include "dfhack/DFMemInfoManager.h" #include "dfhack/DFError.h" using namespace DFHack; @@ -151,8 +152,12 @@ void MemInfoManager::ParseEntry (TiXmlElement* entry, memory_info* mem, map Value(); - const char *cstr_name = pMemEntry->Attribute("name"); + const char *cstr_name = pMemEntry->Attribute("name"); const char *cstr_value = pMemEntry->GetText(); + + if(!cstr_value) + cstr_value = pMemEntry->Attribute("id"); + // check for missing parts string type, name, value; type = cstr_type; @@ -203,6 +208,14 @@ void MemInfoManager::ParseEntry (TiXmlElement* entry, memory_info* mem, map setLabor(value,name); } + else if (type == "Level") + { + mem->setLevel(value, name, pMemEntry->Attribute("xpNxtLvl")); + } + else if (type == "Mood") + { + mem->setMood(value, name); + } else { throw Error::MemoryXmlUnknownType(type.c_str()); diff --git a/library/DFProcess-linux-SHM.cpp b/library/DFProcess-linux-SHM.cpp index d4f90db93..acf519ecf 100644 --- a/library/DFProcess-linux-SHM.cpp +++ b/library/DFProcess-linux-SHM.cpp @@ -569,10 +569,7 @@ bool SHMProcess::attach() bool SHMProcess::detach() { - if(!d->attached) - { - return false; - } + if(!d->attached) return true; if(d->locked) { resume(); @@ -714,7 +711,7 @@ float SHMProcess::readFloat (const uint32_t offset) D_SHMHDR->address = offset; gcc_barrier d->SetAndWait(CORE_READ_DWORD); - return D_SHMHDR->value; + return reinterpret_cast (D_SHMHDR->value); } void SHMProcess::readFloat (const uint32_t offset, float &val) { @@ -723,7 +720,7 @@ void SHMProcess::readFloat (const uint32_t offset, float &val) D_SHMHDR->address = offset; gcc_barrier d->SetAndWait(CORE_READ_DWORD); - val = D_SHMHDR->value; + val = reinterpret_cast (D_SHMHDR->value); } /* diff --git a/library/DFProcess-linux-wine.cpp b/library/DFProcess-linux-wine.cpp index b9ef2339b..b71e2266f 100644 --- a/library/DFProcess-linux-wine.cpp +++ b/library/DFProcess-linux-wine.cpp @@ -331,7 +331,7 @@ bool WineProcess::attach() bool WineProcess::detach() { - if(!d->attached) return false; + if(!d->attached) return true; if(!d->suspended) suspend(); int result = 0; // close /proc/PID/mem @@ -367,9 +367,11 @@ void WineProcess::read (const uint32_t offset, const uint32_t size, uint8_t *tar if(size == 0) return; ssize_t result; - result = pread(d->memFileHandle, target,size,offset); - if(result != size) + ssize_t total = 0; + ssize_t remaining = size; + while (total != size) { + result = pread(d->memFileHandle, target + total ,remaining,offset + total); if(result == -1) { cerr << "pread failed: can't read " << size << " bytes at addres " << offset << endl; @@ -379,7 +381,8 @@ void WineProcess::read (const uint32_t offset, const uint32_t size, uint8_t *tar } else { - read(offset + result, size - result, target + result); + total += result; + remaining -= result; } } } diff --git a/library/DFProcess-linux.cpp b/library/DFProcess-linux.cpp index 343985a3d..25dfa0d8c 100644 --- a/library/DFProcess-linux.cpp +++ b/library/DFProcess-linux.cpp @@ -86,7 +86,7 @@ NormalProcess::NormalProcess(uint32_t pid, vector< memory_info* >& known_version target_name[target_result] = 0; // is this the regular linux DF? - if (strstr(target_name, "dwarfort.exe") != NULL) + if (strstr(target_name, "dwarfort.exe") != 0 || strstr(target_name,"Dwarf_Fortress") != 0) { // create linux process, add it to the vector d->identified = d->validate(target_name,pid,mem_name,known_versions ); @@ -318,7 +318,7 @@ bool NormalProcess::attach() bool NormalProcess::detach() { - if(!d->attached) return false; + if(!d->attached) return true; if(!d->suspended) suspend(); int result = 0; // close /proc/PID/mem diff --git a/library/DFProcess-windows-SHM.cpp b/library/DFProcess-windows-SHM.cpp index 9a8bd8d4f..5bb100e34 100644 --- a/library/DFProcess-windows-SHM.cpp +++ b/library/DFProcess-windows-SHM.cpp @@ -632,10 +632,7 @@ bool SHMProcess::attach() bool SHMProcess::detach() { - if(!d->attached) - { - return false; - } + if(!d->attached) return true; //cerr << "detach" << endl;// FIXME: throw if(d->locked) { @@ -756,7 +753,7 @@ float SHMProcess::readFloat (const uint32_t offset) D_SHMHDR->address = offset; full_barrier d->SetAndWait(CORE_READ_DWORD); - return (float) D_SHMHDR->value; + return reinterpret_cast (D_SHMHDR->value); } void SHMProcess::readFloat (const uint32_t offset, float &val) { @@ -765,7 +762,7 @@ void SHMProcess::readFloat (const uint32_t offset, float &val) D_SHMHDR->address = offset; full_barrier d->SetAndWait(CORE_READ_DWORD); - val = (float) D_SHMHDR->value; + val = reinterpret_cast (D_SHMHDR->value); } uint64_t SHMProcess::readQuad (const uint32_t offset) { diff --git a/library/DFProcess-windows.cpp b/library/DFProcess-windows.cpp index da44a0f32..dad67b135 100644 --- a/library/DFProcess-windows.cpp +++ b/library/DFProcess-windows.cpp @@ -249,10 +249,7 @@ bool NormalProcess::attach() bool NormalProcess::detach() { - if(!d->attached) - { - return false; - } + if(!d->attached) return true; resume(); d->attached = false; return true; diff --git a/library/DFProcessEnumerator-linux.cpp b/library/DFProcessEnumerator-linux.cpp deleted file mode 100644 index 3ee14ef80..000000000 --- a/library/DFProcessEnumerator-linux.cpp +++ /dev/null @@ -1,135 +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 "Internal.h" -#include "dfhack/DFProcessEnumerator.h" -#include "dfhack/DFProcess.h" -#include "dfhack/DFMemInfo.h" -#include "dfhack/DFMemInfoManager.h" -#include -#include -#include -#include -#include "shms.h" - -using namespace DFHack; - -class DFHack::ProcessEnumerator::Private -{ - public: - Private(){}; - MemInfoManager *meminfo; - std::vector processes; -}; - -bool ProcessEnumerator::findProcessess() -{ - DIR *dir_p; - struct dirent *dir_entry_p; - // Open /proc/ directory - dir_p = opendir("/proc/"); - // Reading /proc/ entries - while(NULL != (dir_entry_p = readdir(dir_p))) - { - // Only PID folders (numbers) - if (strspn(dir_entry_p->d_name, "0123456789") != strlen(dir_entry_p->d_name)) - { - continue; - } - Process *p1 = new SHMProcess(atoi(dir_entry_p->d_name),d->meminfo->meminfo); - if(p1->isIdentified()) - { - d->processes.push_back(p1); - continue; - } - else - { - delete p1; - } - Process *p2 = new NormalProcess(atoi(dir_entry_p->d_name),d->meminfo->meminfo); - 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 - if(d->processes.size()) - { - return true; - } - return false; -} - -uint32_t ProcessEnumerator::size() -{ - return d->processes.size(); -} - - -Process * ProcessEnumerator::operator[](uint32_t index) -{ - assert(index < d->processes.size()); - return d->processes[index]; -} - - -ProcessEnumerator::ProcessEnumerator( string path_to_xml ) -: d(new Private()) -{ - d->meminfo = new MemInfoManager(path_to_xml); -} - -void ProcessEnumerator::purge() -{ - for(uint32_t i = 0;i < d->processes.size();i++) - { - delete d->processes[i]; - } - d->processes.clear(); -} - -ProcessEnumerator::~ProcessEnumerator() -{ - // delete all processes - purge(); - delete d->meminfo; - delete d; -} diff --git a/library/DFProcessEnumerator-windows.cpp b/library/DFProcessEnumerator-windows.cpp deleted file mode 100644 index bec67361d..000000000 --- a/library/DFProcessEnumerator-windows.cpp +++ /dev/null @@ -1,147 +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 "Internal.h" -#include "dfhack/DFProcessEnumerator.h" -#include "dfhack/DFProcess.h" -#include "dfhack/DFMemInfo.h" -#include "dfhack/DFMemInfoManager.h" -using namespace DFHack; - -class DFHack::ProcessEnumerator::Private -{ - public: - Private(){}; - MemInfoManager *meminfo; - std::vector processes; -}; - -// some magic - will come in handy when we start doing debugger stuff on Windows -bool EnableDebugPriv() -{ - bool bRET = FALSE; - TOKEN_PRIVILEGES tp; - HANDLE hToken; - - if (LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid)) - { - if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) - { - if (hToken != INVALID_HANDLE_VALUE) - { - tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; - tp.PrivilegeCount = 1; - if (AdjustTokenPrivileges(hToken, FALSE, &tp, 0, 0, 0)) - { - bRET = TRUE; - } - CloseHandle(hToken); - } - } - } - return bRET; -} - -// WINDOWS version of the process finder -bool ProcessEnumerator::findProcessess() -{ - // Get the list of process identifiers. - DWORD ProcArray[2048], memoryNeeded, numProccesses; - //EnableDebugPriv(); - if ( !EnumProcesses( ProcArray, sizeof(ProcArray), &memoryNeeded ) ) - { - cout << "EnumProcesses fail'd" << endl; - return false; - } - - // Calculate how many process identifiers were returned. - numProccesses = memoryNeeded / sizeof(DWORD); - EnableDebugPriv(); - - // iterate through processes - for ( int i = 0; i < (int)numProccesses; i++ ) - { - Process *p = new SHMProcess(ProcArray[i],d->meminfo->meminfo); - if(p->isIdentified()) - { - d->processes.push_back(p); - continue; - } - else - { - delete p; - p = 0; - } - p = new NormalProcess(ProcArray[i],d->meminfo->meminfo); - if(p->isIdentified()) - { - d->processes.push_back(p); - continue; - } - else - { - delete p; - p = 0; - } - } - if(d->processes.size()) - return true; - return false; -} - -uint32_t ProcessEnumerator::size() -{ - return d->processes.size(); -}; - - -Process * ProcessEnumerator::operator[](uint32_t index) -{ - assert(index < d->processes.size()); - return d->processes[index]; -}; - - -ProcessEnumerator::ProcessEnumerator( string path_to_xml ) -: d(new Private()) -{ - d->meminfo = new MemInfoManager(path_to_xml); -} - -void ProcessEnumerator::purge() -{ - for(uint32_t i = 0;i < d->processes.size();i++) - { - delete d->processes[i]; - } - d->processes.clear(); -} - -ProcessEnumerator::~ProcessEnumerator() -{ - // delete all processes - purge(); - delete d->meminfo; - delete d; -} diff --git a/library/DFProcessEnumerator.cpp b/library/DFProcessEnumerator.cpp new file mode 100644 index 000000000..c060d2182 --- /dev/null +++ b/library/DFProcessEnumerator.cpp @@ -0,0 +1,380 @@ +/* +www.sourceforge.net/projects/dfhack +Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#include "Internal.h" +#include "DFMemInfoManager.h" + +#include "dfhack/DFProcessEnumerator.h" +#include "dfhack/DFProcess.h" +#include "dfhack/DFMemInfo.h" + + +using namespace DFHack; + +typedef std::vector PROC_V; +typedef std::map PID2PROC; + +class DFHack::ProcessEnumerator::Private +{ + public: + Private(){}; + MemInfoManager *meminfo; + PROC_V Processes; + PID2PROC ProcMap; + Process *GetProcessObject(ProcessID ID); + void EnumPIDs (vector &PIDs); +}; + +class DFHack::BadProcesses::Private +{ + public: + Private(){}; + PROC_V bad; +}; + +BadProcesses::BadProcesses():d(new Private()){} + +BadProcesses::~BadProcesses() +{ + clear(); + delete d; +} + +bool BadProcesses::Contains(Process* p) +{ + for(int i = 0; i < d->bad.size(); i++) + { + if(d->bad[i] == p) + return true; + } + return false; +} + +bool BadProcesses::excise(Process* p) +{ + vector::iterator it = d->bad.begin(); + while(it != d->bad.end()) + { + if((*it) == p) + { + d->bad.erase(it); + return true; + } + else + { + it++; + } + } + return false; +} + +uint32_t BadProcesses::size() +{ + return d->bad.size(); +} + +void BadProcesses::clear() +{ + for(int i = 0; i < d->bad.size(); i++) + { + delete d->bad[i]; + } + d->bad.clear(); +} + +void BadProcesses::push_back(Process* p) +{ + if(p) + d->bad.push_back(p); +} + +Process * BadProcesses::operator[](uint32_t index) +{ + if(index < d->bad.size()) + return d->bad[index]; + return 0; +} + +//FIXME: wasteful +Process *ProcessEnumerator::Private::GetProcessObject(ProcessID ID) +{ + + Process *p1 = new SHMProcess(ID.pid,meminfo->meminfo); + if(p1->isIdentified()) + return p1; + else + delete p1; + + Process *p2 = new NormalProcess(ID.pid,meminfo->meminfo); + if(p2->isIdentified()) + return p2; + else + delete p2; +#ifdef LINUX_BUILD + Process *p3 = new WineProcess(ID.pid,meminfo->meminfo); + if(p3->isIdentified()) + return p3; + else + delete p3; +#endif + return 0; +} + +#ifdef LINUX_BUILD +void ProcessEnumerator::Private::EnumPIDs (vector &PIDs) +{ + DIR *dir_p; + struct dirent *dir_entry_p; + struct stat st; + char fullname[512]; + fullname[0] = 0; + PIDs.clear(); // make sure the vector is clear + + // Open /proc/ directory + dir_p = opendir("/proc/"); + // Reading /proc/ entries + while(NULL != (dir_entry_p = readdir(dir_p))) + { + // Only PID folders (numbers) + if (strspn(dir_entry_p->d_name, "0123456789") != strlen(dir_entry_p->d_name)) + { + continue; + } + sprintf(fullname, "/proc/%s", dir_entry_p->d_name); + int ierr = stat (fullname, &st); + if (ierr != 0) + { + printf("Cannot stat %s: ierr= %d\n", fullname, ierr); + continue; + } + uint64_t Pnum = atoi(dir_entry_p->d_name); + uint64_t ctime = st.st_ctime; + PIDs.push_back(ProcessID(ctime,Pnum)); + } + closedir(dir_p); +} +#endif + +#ifndef LINUX_BUILD +// some magic - will come in handy when we start doing debugger stuff on Windows +bool EnableDebugPriv() +{ + bool bRET = FALSE; + TOKEN_PRIVILEGES tp; + HANDLE hToken; + + if (LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid)) + { + if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) + { + if (hToken != INVALID_HANDLE_VALUE) + { + tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + tp.PrivilegeCount = 1; + if (AdjustTokenPrivileges(hToken, FALSE, &tp, 0, 0, 0)) + { + bRET = TRUE; + } + CloseHandle(hToken); + } + } + } + return bRET; +} + +typedef union +{ + struct + { + uint32_t LowDword; + uint32_t HighDword; + }; + uint64_t Quad; +} TWO_DWORDS; + +// Convert Windows FileTime structs to POSIX timestamp +// from http://frenk.wordpress.com/2009/12/14/convert-filetime-to-unix-timestamp/ +uint64_t FileTime_to_POSIX(FILETIME ft) +{ + // takes the last modified date + TWO_DWORDS date, adjust; + date.HighDword = ft.dwHighDateTime; + date.LowDword = ft.dwLowDateTime; + + // 100-nanoseconds = milliseconds * 10000 + adjust.Quad = 11644473600000LL * 10000LL; + + // removes the diff between 1970 and 1601 + date.Quad -= adjust.Quad; + + // converts back from 100-nanoseconds to seconds + return date.Quad / 10000000LL; +} + +void ProcessEnumerator::Private::EnumPIDs (vector &PIDs) +{ + FILETIME ftCreate, ftExit, ftKernel, ftUser; + + PIDs.clear(); // make sure the vector is clear + + // Get the list of process identifiers. + DWORD ProcArray[2048], memoryNeeded, numProccesses; + //EnableDebugPriv(); + if ( !EnumProcesses( ProcArray, sizeof(ProcArray), &memoryNeeded ) ) + { + cout << "EnumProcesses fail'd" << endl; + return; + } + // Calculate how many process identifiers were returned. + numProccesses = memoryNeeded / sizeof(DWORD); + EnableDebugPriv(); + // iterate through processes + for ( int i = 0; i < (int)numProccesses; i++ ) + { + HANDLE proc = OpenProcess (PROCESS_QUERY_INFORMATION, false, ProcArray[i]); + if(!proc) + continue; + if(GetProcessTimes(proc, &ftCreate, &ftExit, &ftKernel, &ftUser)) + { + uint64_t ctime = FileTime_to_POSIX(ftCreate); + uint64_t Pnum = ProcArray[i]; + PIDs.push_back(ProcessID(ctime,Pnum)); + } + CloseHandle(proc); + } +} +#endif + +bool ProcessEnumerator::Refresh( BadProcesses* invalidated_processes ) +{ + // PIDs to process + vector PIDs; + // this will be the new process map + PID2PROC temporary; + // clear the vector + d->Processes.clear(); + if(invalidated_processes) + invalidated_processes->clear(); + + d->EnumPIDs(PIDs); + + for(uint64_t i = 0; i < PIDs.size();i++) + { + ProcessID & PID = PIDs[i]; + // check if we know about the OS process already + PID2PROC::iterator found= d->ProcMap.find(PID); + if( found != d->ProcMap.end()) + { + // we do + // check if it does have a DFHack Process object associated with it + Process * p = (*found).second; + if(p) + { + // add it back to the vector we export + d->Processes.push_back(p); + } + // remove the OS Process from ProcMap + d->ProcMap.erase(found); + // add the OS Process to what will be the new ProcMap + temporary[PID] = p; + } + else + { + // an OS process we don't know yet! + // try to make a DFHack Process object for it + if(Process*p = d->GetProcessObject(PID)) + { + // allright. this is something that can be used + d->Processes.push_back(p); + temporary[PID] = p; + } + else + { + // just a process. we track it anyway. Why not. + temporary[PID] = 0; + } + } + } + // now the vector we export is filled again and a temporary map with valid processes is created. + // we iterate over the old Process map and destroy all the processes that are dead. + for(PID2PROC::const_iterator idx = d->ProcMap.begin(); idx != d->ProcMap.end();++idx) + { + Process * p = (*idx).second; + if(p) + { + if(invalidated_processes) + { + invalidated_processes->push_back(p); + } + else + { + delete p; + } + } + } + d->ProcMap.swap(temporary); + // return value depends on if we found some DF processes + if(d->Processes.size()) + { + return true; + } + return false; +} + +uint32_t ProcessEnumerator::size() +{ + return d->Processes.size(); +} + + +Process * ProcessEnumerator::operator[](uint32_t index) +{ + assert(index < d->Processes.size()); + return d->Processes[index]; +} + + +ProcessEnumerator::ProcessEnumerator( string path_to_xml ) +: d(new Private()) +{ + d->meminfo = new MemInfoManager(path_to_xml); +} + +void ProcessEnumerator::purge() +{ + for(uint32_t i = 0;i < d->Processes.size();i++) + { + delete d->Processes[i]; + } + d->ProcMap.clear(); + d->Processes.clear(); +} + +ProcessEnumerator::~ProcessEnumerator() +{ + // delete all processes + purge(); + delete d->meminfo; + delete d; +} diff --git a/library/DFTypes_C.cpp b/library/DFTypes_C.cpp index 2a27ad292..dc7d946aa 100644 --- a/library/DFTypes_C.cpp +++ b/library/DFTypes_C.cpp @@ -23,6 +23,7 @@ distribution. */ #include "dfhack/DFIntegers.h" +#include "dfhack/DFTileTypes.h" #include #include "string.h" #include @@ -41,31 +42,65 @@ using namespace DFHack; extern "C" { #endif -int8_t* (*alloc_byte_buffer_callback)(uint32_t) = NULL; -int16_t* (*alloc_short_buffer_callback)(uint32_t) = NULL; -int32_t* (*alloc_int_buffer_callback)(uint32_t) = NULL; +int (*alloc_byte_buffer_callback)(int8_t*, uint32_t) = NULL; +int (*alloc_short_buffer_callback)(int16_t*, uint32_t) = NULL; +int (*alloc_int_buffer_callback)(int32_t*, uint32_t) = NULL; -uint8_t* (*alloc_ubyte_buffer_callback)(uint32_t) = NULL; -uint16_t* (*alloc_ushort_buffer_callback)(uint32_t) = NULL; -uint32_t* (*alloc_uint_buffer_callback)(uint32_t) = NULL; +int (*alloc_ubyte_buffer_callback)(uint8_t*, uint32_t) = NULL; +int (*alloc_ushort_buffer_callback)(uint16_t*, uint32_t) = NULL; +int (*alloc_uint_buffer_callback)(uint32_t*, uint32_t) = NULL; -char* (*alloc_char_buffer_callback)(uint32_t) = NULL; +int (*alloc_char_buffer_callback)(char*, uint32_t) = NULL; -t_matgloss* (*alloc_matgloss_buffer_callback)(int) = NULL; -t_descriptor_color* (*alloc_descriptor_buffer_callback)(int) = NULL; -t_matglossOther* (*alloc_matgloss_other_buffer_callback)(int) = NULL; +int (*alloc_matgloss_buffer_callback)(t_matgloss*, uint32_t) = NULL; +int (*alloc_descriptor_buffer_callback)(t_descriptor_color*, uint32_t) = NULL; +int (*alloc_matgloss_other_buffer_callback)(t_matglossOther*, uint32_t) = NULL; -c_colormodifier* (*alloc_empty_colormodifier_callback)(void) = NULL; -c_colormodifier* (*alloc_colormodifier_callback)(const char*, uint32_t) = NULL; -c_colormodifier* (*alloc_colormodifier_buffer_callback)(uint32_t) = NULL; +int (*alloc_empty_colormodifier_callback)(c_colormodifier*) = NULL; +int (*alloc_colormodifier_callback)(c_colormodifier*, const char*, uint32_t) = NULL; +int (*alloc_colormodifier_buffer_callback)(c_colormodifier*, uint32_t) = NULL; -c_creaturecaste* (*alloc_empty_creaturecaste_callback)(void) = NULL; -c_creaturecaste* (*alloc_creaturecaste_callback)(const char*, const char*, const char*, const char*, uint32_t, uint32_t) = NULL; -c_creaturecaste* (*alloc_creaturecaste_buffer_callback)(uint32_t) = NULL; +int (*alloc_empty_creaturecaste_callback)(c_creaturecaste*)= NULL; +int (*alloc_creaturecaste_callback)(c_creaturecaste*, const char*, const char*, const char*, const char*, uint32_t, uint32_t) = NULL; +int (*alloc_creaturecaste_buffer_callback)(c_creaturecaste*, uint32_t) = NULL; -c_creaturetype* (*alloc_empty_creaturetype_callback)(void) = NULL; -c_creaturetype* (*alloc_creaturetype_callback)(const char*, uint32_t, uint32_t, uint8_t, uint16_t, uint16_t, uint16_t) = NULL; -c_creaturetype* (*alloc_creaturetype_buffer_callback)(uint32_t) = NULL; +int (*alloc_empty_creaturetype_callback)(c_creaturetype*) = NULL; +int (*alloc_creaturetype_callback)(c_creaturetype*, const char*, uint32_t, uint32_t, uint8_t, uint16_t, uint16_t, uint16_t) = NULL; +int (*alloc_creaturetype_buffer_callback)(c_creaturetype*, uint32_t) = NULL; + +int (*alloc_vein_buffer_callback)(t_vein*, uint32_t) = NULL; +int (*alloc_frozenliquidvein_buffer_callback)(t_frozenliquidvein*, uint32_t) = NULL; +int (*alloc_spattervein_buffer_callback)(t_spattervein*, uint32_t) = NULL; + +int DFHack_isWallTerrain(int in) +{ + return DFHack::isWallTerrain(in); +} + +int DFHack_isFloorTerrain(int in) +{ + return DFHack::isFloorTerrain(in); +} + +int DFHack_isRampTerrain(int in) +{ + return DFHack::isRampTerrain(in); +} + +int DFHack_isStairTerrain(int in) +{ + return DFHack::isStairTerrain(in); +} + +int DFHack_isOpenTerrain(int in) +{ + return DFHack::isOpenTerrain(in); +} + +int DFHack_getVegetationType(int in) +{ + return DFHack::getVegetationType(in); +} #ifdef __cplusplus } @@ -76,7 +111,7 @@ int ColorListConvert(t_colormodifier* src, c_colormodifier* dest) if(src == NULL) return -1; - dest = ((*alloc_colormodifier_callback)(src->part, src->colorlist.size())); + ((*alloc_colormodifier_callback)(dest, src->part, src->colorlist.size())); copy(src->colorlist.begin(), src->colorlist.end(), dest->colorlist); @@ -88,7 +123,7 @@ int CreatureCasteConvert(t_creaturecaste* src, c_creaturecaste* dest) if(src == NULL) return -1; - dest = ((*alloc_creaturecaste_callback)(src->rawname, src->singular, src->plural, src->adjective, src->ColorModifier.size(), src->bodypart.size())); + ((*alloc_creaturecaste_callback)(dest, src->rawname, src->singular, src->plural, src->adjective, src->ColorModifier.size(), src->bodypart.size())); for(int i = 0; i < dest->colorModifierLength; i++) ColorListConvert(&src->ColorModifier[i], &dest->ColorModifier[i]); @@ -103,7 +138,7 @@ int CreatureTypeConvert(t_creaturetype* src, c_creaturetype* dest) if(src == NULL) return -1; - dest = ((*alloc_creaturetype_callback)(src->rawname, src->castes.size(), src->extract.size(), src->tile_character, src->tilecolor.fore, src->tilecolor.back, src->tilecolor.bright)); + ((*alloc_creaturetype_callback)(dest, src->rawname, src->castes.size(), src->extract.size(), src->tile_character, src->tilecolor.fore, src->tilecolor.back, src->tilecolor.bright)); for(int i = 0; i < dest->castesCount; i++) CreatureCasteConvert(&src->castes[i], &dest->castes[i]); diff --git a/library/include/DFHack.h b/library/include/DFHack.h index 22a332522..3ccaf0b83 100644 --- a/library/include/DFHack.h +++ b/library/include/DFHack.h @@ -1,6 +1,17 @@ #ifndef DFHACK_API_H #define DFHACK_API_H +// Defines +#ifdef __GNUC__ +#define DEPRECATED(func) func __attribute__ ((deprecated)) +#elif defined(_MSC_VER) +#define DEPRECATED(func) __declspec(deprecated) func +#else +#pragma message("WARNING: You need to implement DEPRECATED for this compiler") +#define DEPRECATED(func) func +#endif + +// DFHack core classes and types #include "dfhack/DFIntegers.h" #include "dfhack/DFGlobal.h" #include "dfhack/DFError.h" @@ -10,7 +21,7 @@ #include "dfhack/DFProcess.h" #include "dfhack/DFTypes.h" - +// DFHack modules #include "dfhack/modules/Buildings.h" #include "dfhack/modules/Materials.h" #include "dfhack/modules/Position.h" @@ -22,5 +33,16 @@ #include "dfhack/modules/Vegetation.h" #include "dfhack/modules/Maps.h" -#include "dfhack/DFMiscUtils.h" -#endif \ No newline at end of file +/* + * This is a header full of ugly, volatile things. + * Only for use of official DFHack tools! + */ +#ifdef DFHACK_WANT_MISCUTILS + #include "dfhack/DFMiscUtils.h" +#endif + +// define this to get the static tiletype->properties mapping +#ifdef DFHACK_WANT_TILETYPES + #include "dfhack/DFTileTypes.h" +#endif +#endif diff --git a/library/include/DFHack_C.h b/library/include/DFHack_C.h index 8eb381595..6c5dd004f 100644 --- a/library/include/DFHack_C.h +++ b/library/include/DFHack_C.h @@ -25,12 +25,20 @@ distribution. #ifndef DFHACK_C_API #define DFHACK_C_API -typedef void DFHackObject; +#include +#include +#include +#include +#include +#include "dfhack/DFGlobal.h" #include "dfhack/DFExport.h" #include "dfhack/DFIntegers.h" -#include "dfhack-c/DFContext_C.h" -#include "dfhack-c/DFTypes_C.h" + + +using namespace DFHack; + +typedef void DFHackObject; #ifdef __cplusplus extern "C" { diff --git a/library/include/dfhack-c/DFContext_C.h b/library/include/dfhack-c/DFContext_C.h index 32ecca9e9..365c235b9 100644 --- a/library/include/dfhack-c/DFContext_C.h +++ b/library/include/dfhack-c/DFContext_C.h @@ -25,10 +25,7 @@ distribution. #ifndef DFHACK_C_CONTEXT #define DFHACK_C_CONTEXT -#include "dfhack/DFExport.h" -#include "dfhack/DFIntegers.h" - -typedef void DFHackObject; +#include "DFHack_C.h" #ifdef __cplusplus extern "C" { diff --git a/library/include/dfhack-c/DFTypes_C.h b/library/include/dfhack-c/DFTypes_C.h index 18c8de3b3..fbd883ead 100644 --- a/library/include/dfhack-c/DFTypes_C.h +++ b/library/include/dfhack-c/DFTypes_C.h @@ -25,30 +25,28 @@ distribution. #ifndef TYPES_C_API #define TYPES_C_API -#include "dfhack/DFExport.h" -#include "dfhack/DFIntegers.h" +#include "DFHack_C.h" #include "dfhack/DFTypes.h" +#include "dfhack/modules/Maps.h" #include "dfhack/modules/Materials.h" -using namespace DFHack; - #ifdef __cplusplus extern "C" { #endif -DFHACK_EXPORT extern int8_t* (*alloc_byte_buffer_callback)(uint32_t); -DFHACK_EXPORT extern int16_t* (*alloc_short_buffer_callback)(uint32_t); -DFHACK_EXPORT extern int32_t* (*alloc_int_buffer_callback)(uint32_t); +DFHACK_EXPORT extern int (*alloc_byte_buffer_callback)(int8_t*, uint32_t); +DFHACK_EXPORT extern int (*alloc_short_buffer_callback)(int16_t*, uint32_t); +DFHACK_EXPORT extern int (*alloc_int_buffer_callback)(int32_t*, uint32_t); -DFHACK_EXPORT extern uint8_t* (*alloc_ubyte_buffer_callback)(uint32_t); -DFHACK_EXPORT extern uint16_t* (*alloc_ushort_buffer_callback)(uint32_t); -DFHACK_EXPORT extern uint32_t* (*alloc_uint_buffer_callback)(uint32_t); +DFHACK_EXPORT extern int (*alloc_ubyte_buffer_callback)(uint8_t*, uint32_t); +DFHACK_EXPORT extern int (*alloc_ushort_buffer_callback)(uint16_t*, uint32_t); +DFHACK_EXPORT extern int (*alloc_uint_buffer_callback)(uint32_t*, uint32_t); -DFHACK_EXPORT extern char* (*alloc_char_buffer_callback)(uint32_t); +DFHACK_EXPORT extern int (*alloc_char_buffer_callback)(char*, uint32_t); -DFHACK_EXPORT extern t_matgloss* (*alloc_matgloss_buffer_callback)(int); -DFHACK_EXPORT extern t_descriptor_color* (*alloc_descriptor_buffer_callback)(int); -DFHACK_EXPORT extern t_matglossOther* (*alloc_matgloss_other_buffer_callback)(int); +DFHACK_EXPORT extern int (*alloc_matgloss_buffer_callback)(t_matgloss*, uint32_t); +DFHACK_EXPORT extern int (*alloc_descriptor_buffer_callback)(t_descriptor_color*, uint32_t); +DFHACK_EXPORT extern int (*alloc_matgloss_other_buffer_callback)(t_matglossOther*, uint32_t); struct c_colormodifier { @@ -57,9 +55,9 @@ struct c_colormodifier uint32_t colorlistLength; }; -DFHACK_EXPORT extern c_colormodifier* (*alloc_empty_colormodifier_callback)(void); -DFHACK_EXPORT extern c_colormodifier* (*alloc_colormodifier_callback)(const char*, uint32_t); -DFHACK_EXPORT extern c_colormodifier* (*alloc_colormodifier_buffer_callback)(uint32_t); +DFHACK_EXPORT extern int (*alloc_empty_colormodifier_callback)(c_colormodifier*); +DFHACK_EXPORT extern int (*alloc_colormodifier_callback)(c_colormodifier*, const char*, uint32_t); +DFHACK_EXPORT extern int (*alloc_colormodifier_buffer_callback)(c_colormodifier*, uint32_t); struct c_creaturecaste { @@ -75,9 +73,9 @@ struct c_creaturecaste uint32_t bodypartLength; }; -DFHACK_EXPORT extern c_creaturecaste* (*alloc_empty_creaturecaste_callback)(void); -DFHACK_EXPORT extern c_creaturecaste* (*alloc_creaturecaste_callback)(const char*, const char*, const char*, const char*, uint32_t, uint32_t); -DFHACK_EXPORT extern c_creaturecaste* (*alloc_creaturecaste_buffer_callback)(uint32_t); +DFHACK_EXPORT extern int (*alloc_empty_creaturecaste_callback)(c_creaturecaste*); +DFHACK_EXPORT extern int (*alloc_creaturecaste_callback)(c_creaturecaste*, const char*, const char*, const char*, const char*, uint32_t, uint32_t); +DFHACK_EXPORT extern int (*alloc_creaturecaste_buffer_callback)(c_creaturecaste*, uint32_t); struct c_creaturetype { @@ -99,9 +97,20 @@ struct c_creaturetype } tilecolor; }; -DFHACK_EXPORT extern c_creaturetype* (*alloc_empty_creaturetype_callback)(void); -DFHACK_EXPORT extern c_creaturetype* (*alloc_creaturetype_callback)(const char*, uint32_t, uint32_t, uint8_t, uint16_t, uint16_t, uint16_t); -DFHACK_EXPORT extern c_creaturetype* (*alloc_creaturetype_buffer_callback)(uint32_t); +DFHACK_EXPORT extern int (*alloc_empty_creaturetype_callback)(c_creaturetype*); +DFHACK_EXPORT extern int (*alloc_creaturetype_callback)(c_creaturetype*, const char*, uint32_t, uint32_t, uint8_t, uint16_t, uint16_t, uint16_t); +DFHACK_EXPORT extern int (*alloc_creaturetype_buffer_callback)(c_creaturetype*, uint32_t); + +DFHACK_EXPORT extern int (*alloc_vein_buffer_callback)(t_vein*, uint32_t); +DFHACK_EXPORT extern int (*alloc_frozenliquidvein_buffer_callback)(t_frozenliquidvein*, uint32_t); +DFHACK_EXPORT extern int (*alloc_spattervein_buffer_callback)(t_spattervein*, uint32_t); + +DFHACK_EXPORT extern int DFHack_isWallTerrain(int in); +DFHACK_EXPORT extern int DFHack_isFloorTerrain(int in); +DFHACK_EXPORT extern int DFHack_isRampTerrain(int in); +DFHACK_EXPORT extern int DFHack_isStairTerrain(int in); +DFHACK_EXPORT extern int DFHack_isOpenTerrain(int in); +DFHACK_EXPORT extern int DFHack_getVegetationType(int in); #ifdef __cplusplus } diff --git a/library/include/dfhack-c/modules/Buildings_C.h b/library/include/dfhack-c/modules/Buildings_C.h index c69da83e0..6b1632dd2 100644 --- a/library/include/dfhack-c/modules/Buildings_C.h +++ b/library/include/dfhack-c/modules/Buildings_C.h @@ -25,13 +25,9 @@ distribution. #ifndef BUILDINGS_C_API #define BUILDINGS_C_API -#include "dfhack/DFExport.h" -#include "dfhack/DFIntegers.h" +#include "DFHack_C.h" #include "dfhack/DFTypes.h" #include "dfhack/modules/Buildings.h" -#include "DFHack_C.h" - -using namespace DFHack; #ifdef __cplusplus extern "C" { diff --git a/library/include/dfhack-c/modules/Constructions_C.h b/library/include/dfhack-c/modules/Constructions_C.h index c34527b1d..f339b6bcc 100644 --- a/library/include/dfhack-c/modules/Constructions_C.h +++ b/library/include/dfhack-c/modules/Constructions_C.h @@ -25,13 +25,9 @@ distribution. #ifndef CONSTRUCTIONS_C_API #define CONSTRUCTIONS_C_API -#include "dfhack/DFExport.h" -#include "dfhack/DFIntegers.h" +#include "DFHack_C.h" #include "dfhack/DFTypes.h" #include "dfhack/modules/Constructions.h" -#include "DFHack_C.h" - -using namespace DFHack; #ifdef __cplusplus extern "C" { diff --git a/library/include/dfhack-c/modules/Creatures_C.h b/library/include/dfhack-c/modules/Creatures_C.h index 93502ffe6..bbc9e6f54 100644 --- a/library/include/dfhack-c/modules/Creatures_C.h +++ b/library/include/dfhack-c/modules/Creatures_C.h @@ -25,15 +25,11 @@ distribution. #ifndef CREATURES_C_API #define CREATURES_C_API -#include "dfhack/DFExport.h" -#include "dfhack/DFIntegers.h" #include "DFHack_C.h" #include "dfhack/DFTypes.h" #include "dfhack/modules/Materials.h" #include "dfhack/modules/Creatures.h" -using namespace DFHack; - #ifdef __cplusplus extern "C" { #endif diff --git a/library/include/dfhack-c/modules/Gui_C.h b/library/include/dfhack-c/modules/Gui_C.h index 0bd68f3fc..2373d458d 100644 --- a/library/include/dfhack-c/modules/Gui_C.h +++ b/library/include/dfhack-c/modules/Gui_C.h @@ -25,11 +25,9 @@ distribution. #ifndef GUI_C_API #define GUI_C_API -#include "dfhack/DFExport.h" -#include "dfhack/DFIntegers.h" +#include "DFHack_C.h" #include "dfhack/DFTypes.h" - -using namespace DFHack; +#include "dfhack/modules/Gui.h" #ifdef __cplusplus extern "C" { diff --git a/library/include/dfhack-c/modules/Items_C.h b/library/include/dfhack-c/modules/Items_C.h index 0568e9088..5c1e08e48 100644 --- a/library/include/dfhack-c/modules/Items_C.h +++ b/library/include/dfhack-c/modules/Items_C.h @@ -25,15 +25,10 @@ distribution. #ifndef ITEMS_C_API #define ITEMS_C_API -#include "dfhack/DFExport.h" -#include "dfhack/DFIntegers.h" -#include "Internal.h" - -using namespace DFHack; - -#include "dfhack/DFTypes.h" -#include "dfhack/modules/Items.h" #include "DFHack_C.h" +#include "dfhack/DFProcess.h" +#include "dfhack-c/DFTypes_C.h" +#include "dfhack/modules/Items.h" #ifdef __cplusplus extern "C" { diff --git a/library/include/dfhack-c/modules/Maps_C.h b/library/include/dfhack-c/modules/Maps_C.h index e37d3640a..d1bad823e 100644 --- a/library/include/dfhack-c/modules/Maps_C.h +++ b/library/include/dfhack-c/modules/Maps_C.h @@ -25,19 +25,9 @@ distribution. #ifndef MAPS_C_API #define MAPS_C_API -#include "dfhack/DFExport.h" -#include "dfhack/DFIntegers.h" -#include -#include -#include - -using namespace std; - +#include "DFHack_C.h" #include "dfhack/DFTypes.h" #include "dfhack/modules/Maps.h" -#include "DFHack_C.h" - -using namespace DFHack; #ifdef __cplusplus extern "C" { @@ -79,6 +69,10 @@ DFHACK_EXPORT int Maps_WriteBlockFlags(DFHackObject* maps, uint32_t x, uint32_t DFHACK_EXPORT int Maps_ReadRegionOffsets(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, biome_indices40d* buffer); +DFHACK_EXPORT t_vein* Maps_ReadStandardVeins(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z); +DFHACK_EXPORT t_frozenliquidvein* Maps_ReadFrozenVeins(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z); +DFHACK_EXPORT t_spattervein* Maps_ReadSpatterVeins(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z); + #ifdef __cplusplus } #endif diff --git a/library/include/dfhack-c/modules/Materials_C.h b/library/include/dfhack-c/modules/Materials_C.h index ef56ac627..25a9a7df3 100644 --- a/library/include/dfhack-c/modules/Materials_C.h +++ b/library/include/dfhack-c/modules/Materials_C.h @@ -25,14 +25,9 @@ distribution. #ifndef MATERIALS_C_API #define MATERIALS_C_API -#include "dfhack/DFExport.h" -#include "dfhack/DFIntegers.h" -#include "dfhack/DFTypes.h" -#include "dfhack/modules/Materials.h" #include "DFHack_C.h" #include "dfhack-c/DFTypes_C.h" - -using namespace DFHack; +#include "dfhack/modules/Materials.h" #ifdef __cplusplus extern "C" { diff --git a/library/include/dfhack-c/modules/Position_C.h b/library/include/dfhack-c/modules/Position_C.h index 3b2f1dc0b..665e400bf 100644 --- a/library/include/dfhack-c/modules/Position_C.h +++ b/library/include/dfhack-c/modules/Position_C.h @@ -25,8 +25,8 @@ distribution. #ifndef POSITION_C_API #define POSITION_C_API -#include "dfhack/DFExport.h" #include "DFHack_C.h" +#include "dfhack/modules/Position.h" #ifdef __cplusplus extern "C" { diff --git a/library/include/dfhack-c/modules/Translation_C.h b/library/include/dfhack-c/modules/Translation_C.h index 2e1aaf457..8cbcf4e91 100644 --- a/library/include/dfhack-c/modules/Translation_C.h +++ b/library/include/dfhack-c/modules/Translation_C.h @@ -25,13 +25,9 @@ distribution. #ifndef TRANSLATION_C_API #define TRANSLATION_C_API -#include "dfhack/DFExport.h" -#include "dfhack/DFIntegers.h" +#include "DFHack_C.h" #include "dfhack/DFTypes.h" #include "dfhack/modules/Translation.h" -#include "DFHack_C.h" - -using namespace DFHack; #ifdef __cplusplus extern "C" { diff --git a/library/include/dfhack-c/modules/Vegetation_C.h b/library/include/dfhack-c/modules/Vegetation_C.h index c57c3948a..017d30a7b 100644 --- a/library/include/dfhack-c/modules/Vegetation_C.h +++ b/library/include/dfhack-c/modules/Vegetation_C.h @@ -25,13 +25,9 @@ distribution. #ifndef VEGETATION_C_API #define VEGETATION_C_API -#include "dfhack/DFExport.h" -#include "dfhack/DFIntegers.h" +#include "DFHack_C.h" #include "dfhack/DFTypes.h" #include "dfhack/modules/Vegetation.h" -#include "DFHack_C.h" - -using namespace DFHack; #ifdef __cplusplus extern "C" { diff --git a/library/include/dfhack-c/modules/WindowIO_C.h b/library/include/dfhack-c/modules/WindowIO_C.h new file mode 100644 index 000000000..072a4f352 --- /dev/null +++ b/library/include/dfhack-c/modules/WindowIO_C.h @@ -0,0 +1,43 @@ +/* +www.sourceforge.net/projects/dfhack +Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild + +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 WINDOWIO_C_API +#define WINDOWIO_C_API + +#include "DFHack_C.h" +#include "dfhack/modules/WindowIO.h" + +#ifdef __cplusplus +extern "C" { +#endif + +DFHACK_EXPORT int WindowIO_TypeStr(DFHackObject* window, const char* input, int delay, bool useShift); + +DFHACK_EXPORT int WindowIO_TypeSpecial(DFHackObject* window, t_special command, int count, int delay); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/library/include/dfhack-c/modules/World_C.h b/library/include/dfhack-c/modules/World_C.h new file mode 100644 index 000000000..f6261a738 --- /dev/null +++ b/library/include/dfhack-c/modules/World_C.h @@ -0,0 +1,47 @@ +/* +www.sourceforge.net/projects/dfhack +Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild + +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 WORLD_C_API +#define WORLD_C_API + +#include "DFHack_C.h" +#include "dfhack/modules/World.h" + +#ifdef __cplusplus +extern "C" { +#endif + +DFHACK_EXPORT int World_Start(DFHackObject* world); +DFHACK_EXPORT int World_Finish(DFHackObject* world); + +DFHACK_EXPORT int World_ReadCurrentTick(DFHackObject* world, uint32_t* tick); +DFHACK_EXPORT int World_ReadCurrentYear(DFHackObject* world, uint32_t* year); +DFHACK_EXPORT int World_ReadCurrentMonth(DFHackObject* world, uint32_t* month); +DFHACK_EXPORT int World_ReadCurrentDay(DFHackObject* world, uint32_t* day); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/library/include/dfhack/DFContext.h b/library/include/dfhack/DFContext.h index 658d90ee1..9c092cc38 100644 --- a/library/include/dfhack/DFContext.h +++ b/library/include/dfhack/DFContext.h @@ -44,74 +44,78 @@ namespace DFHack class DFContextShared; class WindowIO; class Process; - + class DFHACK_EXPORT Context { public: Context(Process * p); ~Context(); - + bool isValid(); - + bool Attach(); bool Detach(); bool isAttached(); - + /// stop the tracked process bool Suspend(); + /// @return true if the process is stopped bool isSuspended(); - + /// stop the tracked process, asynchronous bool AsyncSuspend(); - + /// resume the tracked process bool Resume(); - + /// forces resume on Windows. This can be a bad thing with multiple tools running! bool ForceResume(); - + memory_info *getMemoryInfo(); Process* getProcess(); - + void ReadRaw (const uint32_t offset, const uint32_t size, uint8_t *target); void WriteRaw (const uint32_t offset, const uint32_t size, uint8_t *source); // FIXME: this is crap. - // get the creatures module + + /// get the creatures module Creatures * getCreatures(); - - // get the maps module + + /// get the maps module Maps * getMaps(); - - // get the gui module + + /// get the gui module Gui * getGui(); - // get the world module + /// get the world module World * getWorld(); - - // get the position module + + /// get the position module Position * getPosition(); - - // get the materials module + + /// get the materials module Materials * getMaterials(); - // get the items module + /// get the items module Items * getItems(); - - // get the translation module + + /// get the translation module Translation * getTranslation(); - - // get the vegetation module + + /// get the vegetation module Vegetation * getVegetation(); - - // get the buildings module + + /// get the buildings module Buildings * getBuildings(); - - // get the constructions module + + /// get the constructions module Constructions * getConstructions(); - - // get the Window management and I/O module - WindowIO * getWindow(); + + /// get the Window management and I/O module + WindowIO * getWindowIO(); + + // DEAD CODE, WAITING TO BE UPDATED TO DF2010 /* * Effects like mist, dragonfire or dust */ diff --git a/library/include/dfhack/DFContextManager.h b/library/include/dfhack/DFContextManager.h index 3337755d7..804b7c48a 100644 --- a/library/include/dfhack/DFContextManager.h +++ b/library/include/dfhack/DFContextManager.h @@ -35,18 +35,111 @@ distribution. namespace DFHack { class Context; - class DFContextMgrPrivate; + class BadContexts; + class Process; + /** + * Used to enumerate, create and destroy Contexts. The very base of DFHack. + * @see DFHack::Context + */ class DFHACK_EXPORT ContextManager { - DFContextMgrPrivate * const d; + class Private; + Private * const d; public: + /** + * Constructs the ContextManager. + * @param path_to_xml the path to the file that defines memory offsets. (Memory.xml) + */ ContextManager(const std::string path_to_xml); + + /** + * Destroys the ContextManager. + */ ~ContextManager(); - uint32_t Refresh(); + + /** + * Refresh the internal list of valid Context objects. + * @param bad_contexts pointer to a BadContexts object. Not required. All contexts are automatically destroyed if the object is not provided. + * @see DFHack::BadContexts + * @return Number of tracked contexts + */ + uint32_t Refresh(BadContexts* bad_contexts = 0); + + /** + * Get the number of tracked contexts. + * @return Number of tracked contexts + */ uint32_t size(); + + /** + * Get a context by index + * @param index index of the context to be returned + * @return pointer to a Context. 0 if the index is out of range. + */ Context * operator[](uint32_t index); + + /** + * Convenience method to return a single valid Context + * @return pointer to a Context + */ Context * getSingleContext(); + + /** + * Destroy all tracked Context objects + * Normally called during object destruction. Calling this from outside ContextManager is nasty. + */ void purge(void); }; + + /** + * Class used for holding a set of invalidated Context AND Process objects temporarily and destroy them safely. + * @see DFHack::Context + * @see DFHack::Process + */ + class DFHACK_EXPORT BadContexts + { + class Private; + Private * const d; + void push_back(Context * c); + friend class ContextManager; + void clear(); + public: + BadContexts(); + /** + * Destructor. + * All Processes and Contexts tracked by the BadContexts object will be destroyed also. + */ + ~BadContexts(); + + /** + * Test if a Context is among the invalidated Contexts + * @param c pointer to a Context to be checked + * @return true if the Context is among the invalidated. false otherwise. + */ + bool Contains(Context* c); + + /** + * Test if a Process is among the invalidated Processes/Contexts + * @param p pointer to a Process to be checked + * @see DFHack::Process + * @return true if the Process is among the invalidated. false otherwise. + */ + bool Contains(Process* p); + + // TODO: Add excise(Context *) method + + /** + * Get the number of tracked invalid contexts. + * @return Number of tracked invalid contexts + */ + uint32_t size(); + + /** + * Get an invalid Context by index + * @param index index of the invalid Context to be returned + * @return pointer to an invalid Context + */ + Context * operator[](uint32_t index); + }; } // namespace DFHack #endif // CONTEXTMANAGER_H_INCLUDED diff --git a/library/include/dfhack/DFError.h b/library/include/dfhack/DFError.h index d838c5623..79823a9fa 100644 --- a/library/include/dfhack/DFError.h +++ b/library/include/dfhack/DFError.h @@ -297,6 +297,16 @@ namespace DFHack return "SHM ATTACH FAILURE"; } }; + class DFHACK_EXPORT ModuleNotInitialized : public std::exception + { + public: + ModuleNotInitialized() {} + virtual ~ModuleNotInitialized() throw(){}; + virtual const char* what() const throw() + { + return "Programmer error: module not initialized!"; + } + }; } } diff --git a/library/include/dfhack/DFMemInfo.h b/library/include/dfhack/DFMemInfo.h index 765483ecc..e40ecbf11 100644 --- a/library/include/dfhack/DFMemInfo.h +++ b/library/include/dfhack/DFMemInfo.h @@ -27,70 +27,21 @@ distribution. #include "DFPragma.h" #include "DFExport.h" -#include -#include -#include +#include "dfhack/DFTypes.h" namespace DFHack { /* * Stubs */ - class Process; - - /* - * Common data types - */ - struct t_type - { - t_type(uint32_t assign, uint32_t type, std::string classname) - :classname(classname),assign(assign),type(type){}; - std::string classname; - uint32_t assign; - uint32_t type; - }; + struct t_class; - struct t_class - { - t_class(const t_class &old) - { - classname = old.classname; - vtable = old.vtable; - assign = old.assign; - type_offset = old.type_offset; - for(uint32_t i = 0; i < old.subs.size();i++) - { - t_type * t = new t_type (*old.subs[i]); - subs.push_back(t); - } - } - t_class () - { - vtable = 0; - assign = 0; - type_offset = 0; - } - ~t_class() - { - for(uint32_t i = 0; i < subs.size();i++) - { - delete subs[i]; - } - subs.clear(); - } - std::string classname; - uint32_t vtable; - uint32_t assign;// index to typeclass array if multiclass. return value if not. - uint32_t type_offset; // offset of type data for multiclass - vector subs; - }; - class DFHACK_EXPORT memory_info { private: class Private; - Private * d; + Private * d; public: enum OSType { @@ -114,7 +65,8 @@ namespace DFHack int32_t getOffset (const char *); uint32_t getAddress (const char *); uint32_t getHexValue (const char *); - + + std::string getMood(const uint32_t moodID); std::string getString (const std::string&); std::string getProfession(const uint32_t) const; std::string getJob(const uint32_t) const; @@ -122,6 +74,9 @@ namespace DFHack std::string getTrait (const uint32_t, const uint32_t) const; std::string getTraitName(const uint32_t) const; std::string getLabor (const uint32_t); + std::vector< std::vector > const& getAllTraits(); + + DFHack::t_level getLevelInfo(const uint32_t level) const; void setVersion(const char *); void setVersion(const std::string&); @@ -149,42 +104,52 @@ namespace DFHack void setProfession(const std::string &, const std::string &); void setJob(const std::string &, const std::string &); void setSkill(const std::string &, const std::string &); - void setTrait(const std::string &,const std::string &,const std::string &,const std::string &,const std::string &,const std::string &,const std::string &,const std::string &); + void setTrait(const std::string &, const std::string &, const std::string &, + const std::string &, const std::string &, + const std::string &, const std::string &, const std::string &); void setLabor(const std::string &, const std::string &); + void setLevel(const std::string &nLevel, const std::string &nName, + const std::string &nXp); + void setMood(const std::string &id, const std::string &mood); void RebaseVTable(const int32_t offset); void setParentProcess(Process * _p); - + t_class * setClass (const char * classname, uint32_t vptr = 0, uint32_t typeoffset = 0); void setClassChild (t_class * parent, const char * classname, const char * type); - /* + /** * Get a classID from an address. The address has to point to the start of a virtual object (one with a virtual base class) * uses memory reading directly, needs suspend. input = address of the object * fails if it's unable to read from memory */ bool resolveObjectToClassID (const uint32_t address, int32_t & classID); - - /* + + /** * Get a ClassID when you know the classname. can fail if the class is not in the cache */ bool resolveClassnameToClassID (const std::string classname, int32_t & classID); - - /* + + /** * Get a vptr from a classname. Can fail if the type is not in the cache * limited to normal classes, variable-dependent types will resolve to the base class */ bool resolveClassnameToVPtr ( const std::string classname, uint32_t & vptr ); - - /* + + /** * Get a classname from a previous classID. Can fail if the type is not in the cache (you use bogus classID) */ bool resolveClassIDToClassname (const int32_t classID, std::string & classname); - - /* + + /** * Get the internal classID->classname mapping (for speed). DO NOT MANIPULATE THE VECTOR! */ - const vector * getClassIDMapping(); + const std::vector * getClassIDMapping(); + + /** + * Get a string with all addresses and offsets + */ + std::string PrintOffsets(); }; } #endif // MEMINFO_H_INCLUDED diff --git a/library/include/dfhack/DFMiscUtils.h b/library/include/dfhack/DFMiscUtils.h index 14f192e6a..04676a769 100644 --- a/library/include/dfhack/DFMiscUtils.h +++ b/library/include/dfhack/DFMiscUtils.h @@ -8,17 +8,13 @@ #include #include #include + using namespace std; #include #include #include -/* - * This is a header full of ugly, volatile things. - * Only for use of official DFHack tools! - */ - void DumpObjStr0Vector (const char * name, DFHack::Process *p, uint32_t addr) { cout << "----==== " << name << " ====----" << endl; diff --git a/library/include/dfhack/DFModule.h b/library/include/dfhack/DFModule.h new file mode 100644 index 000000000..7ed3e6738 --- /dev/null +++ b/library/include/dfhack/DFModule.h @@ -0,0 +1,54 @@ + +/* +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 MODULE_H_INCLUDED +#define MODULE_H_INCLUDED + +#include "DFExport.h" +namespace DFHack +{ + class Context; + class DFHACK_EXPORT Module + { + public: + virtual ~Module(){}; + virtual bool Start(){return true;};// default start... + virtual bool Finish() = 0;// everything should have a Finish() + // should Context call Finish when Resume is called? + virtual bool OnResume() + { + Finish(); + return true; + }; + // Finish when map change is detected? + // TODO: implement + virtual bool OnMapChange() + { + return false; + }; + }; +} +#endif //MODULE_H_INCLUDED + diff --git a/library/include/dfhack/DFProcess.h b/library/include/dfhack/DFProcess.h index 686d7cc40..25ac51997 100644 --- a/library/include/dfhack/DFProcess.h +++ b/library/include/dfhack/DFProcess.h @@ -35,6 +35,25 @@ namespace DFHack class Process; class Window; + struct ProcessID + { + ProcessID(const uint64_t _time, const uint64_t _pid): time(_time), pid(_pid){}; + bool operator==(const ProcessID &other) const + { + return (other.time == time && other.pid == pid); + } + bool operator< (const ProcessID& ms) const + { + if (time < ms.time) + return true; + else if(time == ms.time) + return pid < ms.pid ; + return false; + } + uint64_t time; + uint64_t pid; + }; + // structure describing a memory range struct DFHACK_EXPORT t_memrange { @@ -53,100 +72,117 @@ namespace DFHack if (address >= start && address <= end) return true; return false; } - inline void print() - { - std::cout << std::hex << start << " - " << end << "|" << (read ? "r" : "-") << (write ? "w" : "-") << (execute ? "x" : "-") << "|" << name << std::endl; - } + uint8_t * buffer; }; class DFHACK_EXPORT Process { public: - // this is the single most important destructor ever. ~px + /// this is the single most important destructor ever. ~px virtual ~Process(){}; - // Set up stuff so we can read memory, suspends synchronously + /// Set up stuff so we can read memory, suspends synchronously virtual bool attach() = 0; - // detach from DF, resume its execution if it's suspended + /// detach from DF, resume its execution if it's suspended virtual bool detach() = 0; - - // synchronous suspend - // waits for DF to be actually suspended, - // this might take a while depending on implementation + /** + * synchronous suspend + * waits for DF to be actually suspended, + * this might take a while depending on implementation + */ virtual bool suspend() = 0; - // asynchronous suspend to use together with polling and timers + /// asynchronous suspend to use together with polling and timers virtual bool asyncSuspend() = 0; - // resume DF execution + /// resume DF execution virtual bool resume() = 0; - // force-resume DF execution + /// force-resume DF execution virtual bool forceresume() = 0; - + + /// read a 8-byte integer virtual uint64_t readQuad(const uint32_t address) = 0; + /// read a 8-byte integer virtual void readQuad(const uint32_t address, uint64_t & value) = 0; + /// write a 8-byte integer virtual void writeQuad(const uint32_t address, const uint64_t value) = 0; - + + /// read a 4-byte integer virtual uint32_t readDWord(const uint32_t address) = 0; + /// read a 4-byte integer virtual void readDWord(const uint32_t address, uint32_t & value) = 0; + /// write a 4-byte integer virtual void writeDWord(const uint32_t address, const uint32_t value) = 0; - + + /// read a float virtual float readFloat(const uint32_t address) = 0; + /// write a float virtual void readFloat(const uint32_t address, float & value) = 0; - + + /// read a 2-byte integer virtual uint16_t readWord(const uint32_t address) = 0; + /// read a 2-byte integer virtual void readWord(const uint32_t address, uint16_t & value) = 0; + /// write a 2-byte integer virtual void writeWord(const uint32_t address, const uint16_t value) = 0; - + + /// read a byte virtual uint8_t readByte(const uint32_t address) = 0; + /// read a byte virtual void readByte(const uint32_t address, uint8_t & value) = 0; + /// write a byte virtual void writeByte(const uint32_t address, const uint8_t value) = 0; - + + /// read an arbitrary amount of bytes virtual void read( uint32_t address, uint32_t length, uint8_t* buffer) = 0; + /// write an arbitrary amount of bytes virtual void write(uint32_t address, uint32_t length, uint8_t* buffer) = 0; - - // read a string - virtual const string readSTLString (uint32_t offset) = 0; + + /// read an STL string + virtual const std::string readSTLString (uint32_t offset) = 0; + /// read an STL string virtual size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) = 0; + /// write an STL string virtual void writeSTLString(const uint32_t address, const std::string writeString) = 0; - // get class name of an object with rtti/type info - virtual string readClassName(uint32_t vptr) = 0; - + /// get class name of an object with rtti/type info + virtual std::string readClassName(uint32_t vptr) = 0; + + /// read a null-terminated C string virtual const std::string readCString (uint32_t offset) = 0; - + + /// @return true if the process is suspended virtual bool isSuspended() = 0; + /// @return true if the process is attached virtual bool isAttached() = 0; + /// @return true if the process is identified -- has a Memory.xml entry virtual bool isIdentified() = 0; - - // find the thread IDs of the process - virtual bool getThreadIDs(vector & threads ) = 0; - // get virtual memory ranges of the process (what is mapped where) - virtual void getMemRanges( vector & ranges ) = 0; - - // get the flattened Memory.xml entry of this process + + /// find the thread IDs of the process + virtual bool getThreadIDs(std::vector & threads ) = 0; + /// get virtual memory ranges of the process (what is mapped where) + virtual void getMemRanges(std::vector & ranges ) = 0; + + /// get the flattened Memory.xml entry of this process virtual memory_info *getDescriptor() = 0; - // get the DF Process ID + /// get the DF Process ID virtual int getPID() = 0; - // get module index by name and version. bool 1 = error + /// get module index by name and version. bool 1 = error virtual bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) = 0; - // get the SHM start if available + /// get the SHM start if available virtual char * getSHMStart (void) = 0; - // set a SHM command and wait for a response, return 0 on error or throw exception + /// set a SHM command and wait for a response, return 0 on error or throw exception virtual bool SetAndWait (uint32_t state) = 0; - /* - // wait while SHM command == state. returns 0 without the SHM - virtual bool waitWhile (uint32_t state) = 0; - // set SHM command. - virtual void setCmd (uint32_t newstate) = 0; - */ }; + //////////////////////////////////////////////////////////////////////////// + // Compiler appeasement area. Not worth a look really... // + //////////////////////////////////////////////////////////////////////////// + class DFHACK_EXPORT NormalProcess : virtual public Process { friend class ProcessEnumerator; class Private; private: Private * const d; - public: - NormalProcess(uint32_t pid, vector & known_versions); + NormalProcess(uint32_t pid, std::vector & known_versions); ~NormalProcess(); bool attach(); bool detach(); @@ -178,11 +214,11 @@ namespace DFHack void read( uint32_t address, uint32_t length, uint8_t* buffer); void write(uint32_t address, uint32_t length, uint8_t* buffer); - const string readSTLString (uint32_t offset); + const std::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){}; // get class name of an object with rtti/type info - string readClassName(uint32_t vptr); + std::string readClassName(uint32_t vptr); const std::string readCString (uint32_t offset); @@ -190,8 +226,8 @@ namespace DFHack bool isAttached(); bool isIdentified(); - bool getThreadIDs(vector & threads ); - void getMemRanges( vector & ranges ); + bool getThreadIDs(std::vector & threads ); + void getMemRanges(std::vector & ranges ); memory_info *getDescriptor(); int getPID(); // get module index by name and version. bool 1 = error @@ -200,12 +236,6 @@ namespace DFHack char * getSHMStart (void){return 0;}; // set a SHM command and wait for a response bool SetAndWait (uint32_t state){return false;}; - /* - // wait for a SHM state. returns 0 without the SHM - bool waitWhile (uint32_t state){return false;}; - // set SHM command. - void setCmd (uint32_t newstate){}; - */ }; class DFHACK_EXPORT SHMProcess : virtual public Process @@ -216,7 +246,7 @@ namespace DFHack Private * const d; public: - SHMProcess(uint32_t PID, vector & known_versions); + SHMProcess(uint32_t PID, std::vector & known_versions); ~SHMProcess(); // Set up stuff so we can read memory bool attach(); @@ -249,11 +279,11 @@ namespace DFHack void read( uint32_t address, uint32_t length, uint8_t* buffer); void write(uint32_t address, uint32_t length, uint8_t* buffer); - const string readSTLString (uint32_t offset); + const std::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); // get class name of an object with rtti/type info - string readClassName(uint32_t vptr); + std::string readClassName(uint32_t vptr); const std::string readCString (uint32_t offset); @@ -261,8 +291,8 @@ namespace DFHack bool isAttached(); bool isIdentified(); - bool getThreadIDs(vector & threads ); - void getMemRanges( vector & ranges ); + bool getThreadIDs(std::vector & threads ); + void getMemRanges(std::vector & ranges ); memory_info *getDescriptor(); int getPID(); // get module index by name and version. bool 1 = error @@ -270,12 +300,6 @@ namespace DFHack // get the SHM start if available char * getSHMStart (void); bool SetAndWait (uint32_t state); - /* - // wait for a SHM state. returns 0 without the SHM - bool waitWhile (uint32_t state); - // set SHM command. - void setCmd (uint32_t newstate); - */ }; #ifdef LINUX_BUILD @@ -287,7 +311,7 @@ namespace DFHack Private * const d; public: - WineProcess(uint32_t pid, vector & known_versions); + WineProcess(uint32_t pid, std::vector & known_versions); ~WineProcess(); bool attach(); bool detach(); @@ -319,11 +343,11 @@ namespace DFHack void read( uint32_t address, uint32_t length, uint8_t* buffer); void write(uint32_t address, uint32_t length, uint8_t* buffer); - const string readSTLString (uint32_t offset); + const std::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){}; // get class name of an object with rtti/type info - string readClassName(uint32_t vptr); + std::string readClassName(uint32_t vptr); const std::string readCString (uint32_t offset); @@ -331,8 +355,8 @@ namespace DFHack bool isAttached(); bool isIdentified(); - bool getThreadIDs(vector & threads ); - void getMemRanges( vector & ranges ); + bool getThreadIDs(std::vector & threads ); + void getMemRanges(std::vector & ranges ); memory_info *getDescriptor(); int getPID(); // get module index by name and version. bool 1 = error @@ -340,12 +364,6 @@ namespace DFHack // get the SHM start if available char * getSHMStart (void){return 0;}; bool SetAndWait (uint32_t state){return false;}; - /* - // wait for a SHM state. returns 0 without the SHM - bool waitWhile (uint32_t state){return false;}; - // set SHM command. - void setCmd (uint32_t newstate){}; - */ }; #endif } diff --git a/library/include/dfhack/DFProcessEnumerator.h b/library/include/dfhack/DFProcessEnumerator.h index c40253c15..0422367d5 100644 --- a/library/include/dfhack/DFProcessEnumerator.h +++ b/library/include/dfhack/DFProcessEnumerator.h @@ -28,27 +28,105 @@ distribution. #include "DFPragma.h" #include "DFExport.h" -class TiXmlElement; - namespace DFHack { class memory_info; class Process; - - /* - * Process manager + class BadProcesses; + /** + * Process enumerator + * Used to enumerate, create and destroy Processes. + * @see DFHack::Process */ class DFHACK_EXPORT ProcessEnumerator { class Private; Private * const d; public: - ProcessEnumerator( string path_to_xml); + /** + * Constructs the ProcessEnumerator. + * @param path_to_xml the path to the file that defines memory offsets. (Memory.xml) + */ + ProcessEnumerator( string path_to_xml ); + + /** + * Destroys the ProcessEnumerator. + */ ~ProcessEnumerator(); - bool findProcessess(); + + /** + * Refresh the internal list of valid Process objects. + * @param invalidated_processes pointer to a BadProcesses object. Not required. All processes are automatically destroyed if the object is not provided. + * @see DFHack::BadProcesses + * @return true if there's at least one valit Process + */ + bool Refresh(BadProcesses * invalidated_processes = 0); + + /** + * @return Number of tracked processes + */ uint32_t size(); + + /** + * Get a Process by index + * @param index index of the Process to be returned + * @return pointer to a Process. 0 if the index is out of range. + */ Process * operator[](uint32_t index); + + /** + * Destroy all tracked Process objects + * Normally called during object destruction. Calling this from outside ProcessManager is nasty. + */ void purge(void); }; + + /** + * Class used for holding a set of invalidated Process objects temporarily and destroy them safely. + * @see DFHack::Process + */ + class DFHACK_EXPORT BadProcesses + { + class Private; + Private * const d; + void push_back(Process * p); + friend class ProcessEnumerator; + void clear(); + public: + BadProcesses(); + /** + * Destructor. + * All Processes tracked by the BadProcesses object will be destroyed also. + */ + ~BadProcesses(); + + /** + * Test if a Process is among the invalidated Processes + * @param p pointer to a Process to be checked + * @return true if the Process is among the invalidated. false otherwise. + */ + bool Contains(Process* p); + + /** + * Remove a Process from the tracked invalidated Processes. Used by BadContexts. + * @param p pointer to a Process to be excised + * @see DFHack::BadContexts + * @return true if the Process was among the invalidated. false otherwise. + */ + bool excise (Process* p); + + /** + * Get the number of tracked invalid contexts. + * @return Number of tracked invalid contexts + */ + uint32_t size(); + + /** + * Get an invalid Process by index + * @param index index of the invalid Process to be returned + * @return pointer to an invalid Process + */ + Process * operator[](uint32_t index); + }; } #endif // PROCESSMANAGER_H_INCLUDED diff --git a/library/include/dfhack/DFTileTypes.h b/library/include/dfhack/DFTileTypes.h index 920c1541f..df0e3c873 100644 --- a/library/include/dfhack/DFTileTypes.h +++ b/library/include/dfhack/DFTileTypes.h @@ -29,9 +29,10 @@ distribution. namespace DFHack { + // tile class -- determines the general shape of the tile enum TileClass { - EMPTY, + EMPTY,// empty WALL, PILLAR, @@ -41,10 +42,10 @@ namespace DFHack STAIR_DOWN, STAIR_UPDOWN, - RAMP, - RAMP_TOP, + RAMP,// ramps have no direction + RAMP_TOP,// the top of a ramp. I assume it's used for path finding. - FLOOR, + FLOOR,// generic floor TREE_DEAD, TREE_OK, SAPLING_DEAD, @@ -54,29 +55,31 @@ namespace DFHack BOULDER, PEBBLES }; + // material -- what material the tile is made of enum TileMaterial { - AIR, - SOIL, - STONE, - FEATSTONE, // whatever it is - OBSIDIAN, - - VEIN, - ICE, - GRASS, - GRASS2, - GRASS_DEAD, - GRASS_DRY, - DRIFTWOOD, - HFS, - MAGMA, - CAMPFIRE, - FIRE, - ASHES, - CONSTRUCTED, - CYAN_GLOW + AIR,// empty + SOIL,// ordinary soil. material depends on geology + STONE,// ordinary layer stone. material depends on geology + FEATSTONE,// map feature stone. used for things like hell, the hell temple or adamantine tubes. material depends on local/global feature + OBSIDIAN,// cast obsidian + + VEIN,// vein stone. material depends on mineral veins present + ICE,// frozen water... not much to say. you can determine what was on the tile before it froze by looking into the 'ice vein' objects + GRASS,// grass (has 4 variants) + GRASS2,// grass (has 4 variants) + GRASS_DEAD,// dead grass (has 4 variants) + GRASS_DRY,// dry grass (has 4 variants) + DRIFTWOOD,// non-specified wood - normally on top of the local layer stone/soil. + HFS,// the stuff demon pits are made of - this makes them different from ordinary pits. + MAGMA,// material for semi-molten rock and 'magma flow' tiles + CAMPFIRE,// human armies make them when they siege. The original tile may be lost? + FIRE,// burning grass + ASHES,// what remains from a FIRE + CONSTRUCTED,// tile material depends on the construction present + CYAN_GLOW// the glowy stuff that disappears from the demon temple when you take the sword. }; + // variants are used for tiles, where there are multiple variants of the same - like grass floors enum TileVariant { VAR_1, diff --git a/library/include/dfhack/DFTypes.h b/library/include/dfhack/DFTypes.h index 95ab11ccd..52c7826b7 100644 --- a/library/include/dfhack/DFTypes.h +++ b/library/include/dfhack/DFTypes.h @@ -203,7 +203,7 @@ struct t_settlement struct t_attrib { uint32_t level; - uint32_t field_4; + uint32_t field_4; // offset from beginning, purpose unknown uint32_t field_8; uint32_t field_C; uint32_t leveldiff; @@ -211,5 +211,12 @@ struct t_attrib uint32_t field_18; }; +struct t_level +{ + uint32_t level; + std::string name; + uint32_t xpNxtLvl; +}; + }// namespace DFHack #endif // TYPES_H_INCLUDED diff --git a/library/include/dfhack/modules/Buildings.h b/library/include/dfhack/modules/Buildings.h index a9dc04494..f16f03953 100644 --- a/library/include/dfhack/modules/Buildings.h +++ b/library/include/dfhack/modules/Buildings.h @@ -4,6 +4,7 @@ * Buildings - also includes zones and stockpiles */ #include "dfhack/DFExport.h" +#include "dfhack/DFModule.h" namespace DFHack { struct t_building @@ -26,7 +27,7 @@ namespace DFHack }; class DFContextShared; - class DFHACK_EXPORT Buildings + class DFHACK_EXPORT Buildings : public Module { public: Buildings(DFContextShared * d); @@ -37,7 +38,7 @@ namespace DFHack bool Finish(); // read a vector of names - bool ReadCustomWorkshopTypes(map & btypes); + bool ReadCustomWorkshopTypes(std::map & btypes); // returns -1 on error, >= 0 for real value int32_t GetCustomWorkshopType(t_building & building); diff --git a/library/include/dfhack/modules/Constructions.h b/library/include/dfhack/modules/Constructions.h index e4f029591..76384fc7b 100644 --- a/library/include/dfhack/modules/Constructions.h +++ b/library/include/dfhack/modules/Constructions.h @@ -4,6 +4,7 @@ * DF constructions */ #include "dfhack/DFExport.h" +#include "dfhack/DFModule.h" namespace DFHack { // type of item the construction is made of @@ -40,7 +41,7 @@ namespace DFHack }; #pragma pack (pop) class DFContextShared; - class DFHACK_EXPORT Constructions + class DFHACK_EXPORT Constructions : public Module { public: Constructions(DFContextShared * d); diff --git a/library/include/dfhack/modules/Creatures.h b/library/include/dfhack/modules/Creatures.h index 7e0d48cb5..1686be281 100644 --- a/library/include/dfhack/modules/Creatures.h +++ b/library/include/dfhack/modules/Creatures.h @@ -4,6 +4,7 @@ * Creatures */ #include "dfhack/DFExport.h" +#include "dfhack/DFModule.h" namespace DFHack { /* @@ -49,12 +50,12 @@ namespace DFHack unsigned int dead : 1; // might also be set for incoming/leaving critters that are alive unsigned int has_mood : 1; // Currently in mood unsigned int had_mood : 1; // Had a mood - + unsigned int marauder : 1; // wide class of invader/inside creature attackers unsigned int drowning : 1; unsigned int merchant : 1; // active merchant unsigned int forest : 1; // used for units no longer linked to merchant/diplomacy, they just try to leave mostly - + unsigned int left : 1; // left the map unsigned int rider : 1; unsigned int incoming : 1; @@ -64,12 +65,12 @@ namespace DFHack unsigned int skeleton : 1; unsigned int can_swap : 1; // Can swap tiles during movement (prevents multiple swaps) unsigned int on_ground : 1; // can be conscious - + unsigned int projectile : 1; unsigned int active_invader : 1; // for organized ones unsigned int hidden_in_ambush : 1; unsigned int invader_origin : 1; // could be inactive and fleeing - + unsigned int coward : 1; // Will flee if invasion turns around unsigned int hidden_ambusher : 1; // maybe unsigned int invades : 1; // Active marauder/invader moving inward @@ -80,7 +81,7 @@ namespace DFHack unsigned int caged : 1; unsigned int tame : 1; unsigned int chained : 1; - + unsigned int royal_guard : 1; unsigned int fortress_guard : 1; unsigned int suppress_wield : 1; // Suppress wield for beatings/etc @@ -142,43 +143,43 @@ namespace DFHack unsigned int sparring : 1; unsigned int no_notify : 1; // Do not notify about level gains (for embark etc) unsigned int unused : 1; - + unsigned int calculated_nerves : 1; unsigned int calculated_bodyparts : 1; unsigned int important_historical_figure : 1; // slight variation unsigned int killed : 1; // killed by kill() function - + unsigned int cleanup_1 : 1; // Must be forgotten by forget function (just cleanup) unsigned int cleanup_2 : 1; // Must be deleted (cleanup) unsigned int cleanup_3 : 1; // Recently forgotten (cleanup) unsigned int for_trade : 1; // Offered for trade - + unsigned int trade_resolved : 1; unsigned int has_breaks : 1; unsigned int gutted : 1; unsigned int circulatory_spray : 1; - + unsigned int locked_in_for_trading : 1; unsigned int slaughter : 1; // marked for slaughter unsigned int underworld : 1; // Underworld creature unsigned int resident : 1; // Current resident - + unsigned int cleanup_4 : 1; // Marked for special cleanup as unused load from unit block on disk unsigned int calculated_insulation : 1; // Insulation from clothing calculated unsigned int visitor_uninvited : 1; // Uninvited guest unsigned int visitor : 1; // visitor - + unsigned int calculated_inventory : 1; // Inventory order calculated unsigned int vision_good : 1; // Vision -- have good part unsigned int vision_damaged : 1; // Vision -- have damaged part unsigned int vision_missing : 1; // Vision -- have missing part - + unsigned int breathing_good : 1; // Breathing -- have good part unsigned int breathing_problem : 1; // Breathing -- having a problem unsigned int roaming_wilderness_population_source : 1; unsigned int roaming_wilderness_population_source_not_a_map_feature : 1; }; - + union t_creaturflags2 { uint32_t whole; @@ -188,84 +189,84 @@ namespace DFHack /* struct t_labor { - string name; - uint8_t value; - t_labor() { - value =0; - } - t_labor(const t_labor & b){ - name=b.name; - value=b.value; - } - t_labor & operator=(const t_labor &b){ - name=b.name; - value=b.value; - return *this; - } + string name; + uint8_t value; + t_labor() { + value =0; + } + t_labor(const t_labor & b){ + name=b.name; + value=b.value; + } + t_labor & operator=(const t_labor &b){ + name=b.name; + value=b.value; + return *this; + } }; struct t_skill { - string name; - uint16_t id; - uint32_t experience; - uint16_t rating; - t_skill(){ - id=rating=0; - experience=0; - } - t_skill(const t_skill & b) - { - name=b.name; - id=b.id; - experience=b.experience; - rating=b.rating; - } - t_skill & operator=(const t_skill &b) - { - name=b.name; - id=b.id; - experience=b.experience; - rating=b.rating; - return *this; - } + string name; + uint16_t id; + uint32_t experience; + uint16_t rating; + t_skill(){ + id=rating=0; + experience=0; + } + t_skill(const t_skill & b) + { + name=b.name; + id=b.id; + experience=b.experience; + rating=b.rating; + } + t_skill & operator=(const t_skill &b) + { + name=b.name; + id=b.id; + experience=b.experience; + rating=b.rating; + return *this; + } }; struct t_trait { - uint16_t value; - string displayTxt; - string name; - t_trait(){ - value=0; - } - t_trait(const t_trait &b) - { - name=b.name; - displayTxt=b.displayTxt; - value=b.value; - } - t_trait & operator=(const t_trait &b) - { - name=b.name; - displayTxt=b.displayTxt; - value=b.value; - return *this; - } + uint16_t value; + string displayTxt; + string name; + t_trait(){ + value=0; + } + t_trait(const t_trait &b) + { + name=b.name; + displayTxt=b.displayTxt; + value=b.value; + } + t_trait & operator=(const t_trait &b) + { + name=b.name; + displayTxt=b.displayTxt; + value=b.value; + return *this; + } }; */ struct t_skill { - uint16_t id; + uint32_t id; + uint32_t rating; uint32_t experience; - uint16_t rating; }; struct t_job { bool active; uint32_t jobId; uint8_t jobType; - uint32_t occupationPtr; + uint32_t occupationPtr; }; struct t_like { @@ -280,7 +281,9 @@ namespace DFHack // FIXME: define in Memory.xml instead? #define NUM_CREATURE_TRAITS 30 #define NUM_CREATURE_LABORS 102 - + #define NUM_CREATURE_MENTAL_ATTRIBUTES 13 + #define NUM_CREATURE_PHYSICAL_ATTRIBUTES 6 + struct t_soul { uint8_t numSkills; @@ -305,7 +308,7 @@ namespace DFHack t_attrib social_awareness; }; -#define MAX_COLORS 15 + #define MAX_COLORS 15 struct t_creature { @@ -315,23 +318,23 @@ namespace DFHack uint16_t z; uint32_t race; int32_t civ; - + t_creaturflags1 flags1; t_creaturflags2 flags2; - + t_name name; - + int16_t mood; int16_t mood_skill; t_name artifact_name; - + uint8_t profession; char custom_profession[128]; - + // enabled labors uint8_t labors[NUM_CREATURE_LABORS]; t_job current_job; - + uint32_t happiness; uint32_t id; t_attrib strength; @@ -352,29 +355,45 @@ namespace DFHack uint32_t birth_year; uint32_t birth_time; }; - + class DFContextShared; struct t_creature; - class DFHACK_EXPORT Creatures + class DFHACK_EXPORT Creatures : public Module { - public: + public: Creatures(DFHack::DFContextShared * d); ~Creatures(); - bool Start( uint32_t & numCreatures); + bool Start( uint32_t & numCreatures ); bool Finish(); - + + /* Read Functions */ // Read creatures in a box, starting with index. Returns -1 if no more creatures // found. Call repeatedly do get all creatures in a specified box (uses tile coords) int32_t ReadCreatureInBox(const int32_t index, t_creature & furball, - const uint16_t x1, const uint16_t y1,const uint16_t z1, - const uint16_t x2, const uint16_t y2,const uint16_t z2); + const uint16_t x1, const uint16_t y1,const uint16_t z1, + const uint16_t x2, const uint16_t y2,const uint16_t z2); bool ReadCreature(const int32_t index, t_creature & furball); - /// write labors of a creature (for Dwarf Therapist) - bool WriteLabors(const uint32_t index, uint8_t labors[NUM_CREATURE_LABORS]); + bool ReadJob(const t_creature * furball, std::vector & mat); + + /* Getters */ uint32_t GetDwarfRaceIndex ( void ); int32_t GetDwarfCivId ( void ); - bool ReadJob(const t_creature * furball, std::vector & mat); - private: + + /* Write Functions */ + bool WriteLabors(const uint32_t index, uint8_t labors[NUM_CREATURE_LABORS]); + bool WriteHappiness(const uint32_t index, const uint32_t happinessValue); + bool WriteFlags(const uint32_t index, const uint32_t flags1, const uint32_t flags2); + bool WriteSkills(const uint32_t index, const t_soul &soul); + bool WriteAttributes(const uint32_t index, const t_creature &creature); + bool WriteSex(const uint32_t index, const uint8_t sex); + bool WriteTraits(const uint32_t index, const t_soul &soul); + bool WriteMood(const uint32_t index, const uint16_t mood); + bool WriteMoodSkill(const uint32_t index, const uint16_t moodSkill); + bool WriteJob(const t_creature * furball, std::vector const& mat); + bool WritePos(const uint32_t index, const t_creature &creature); + bool WriteCiv(const uint32_t index, const int32_t civ); + + private: struct Private; Private *d; }; diff --git a/library/include/dfhack/modules/Gui.h b/library/include/dfhack/modules/Gui.h index abc33cff2..0ef170d3f 100644 --- a/library/include/dfhack/modules/Gui.h +++ b/library/include/dfhack/modules/Gui.h @@ -5,12 +5,13 @@ * Gui: Query the DF's GUI state */ #include "dfhack/DFExport.h" +#include "dfhack/DFModule.h" namespace DFHack { class DFContextShared; struct t_viewscreen; - class DFHACK_EXPORT Gui + class DFHACK_EXPORT Gui: public Module { public: diff --git a/library/include/dfhack/modules/Items.h b/library/include/dfhack/modules/Items.h index 90db2bbf6..9b2dba8fe 100644 --- a/library/include/dfhack/modules/Items.h +++ b/library/include/dfhack/modules/Items.h @@ -4,89 +4,39 @@ * Creatures */ #include "dfhack/DFExport.h" +#include "dfhack/DFModule.h" namespace DFHack { class Context; class DFContextShared; - -enum accessor_type {ACCESSOR_CONSTANT, ACCESSOR_INDIRECT, ACCESSOR_DOUBLE_INDIRECT}; - -/* this is used to store data about the way accessors work */ -class DFHACK_EXPORT Accessor -{ -private: - accessor_type type; - int32_t constant; - uint32_t offset1; - uint32_t offset2; - Process * p; - uint32_t dataWidth; -public: - Accessor(uint32_t function, Process * p); - Accessor(accessor_type type, int32_t constant, uint32_t offset1, uint32_t offset2, uint32_t dataWidth, Process * p); - int32_t getValue(uint32_t objectPtr); - bool isConstant(); -}; - struct t_item { - t_material matdesc; - int32_t quantity; - int32_t quality; + t_material matdesc; + int32_t quantity; + int32_t quality; }; struct t_improvement { - t_material matdesc; - int32_t quality; -}; - -class DFHACK_EXPORT ItemImprovementDesc -{ -private: - Accessor * AType; - Process * p; -public: - ItemImprovementDesc(uint32_t VTable, Process * p); - bool getImprovement(uint32_t descptr, t_improvement & imp); - uint32_t vtable; - uint32_t maintype; -}; - -class DFHACK_EXPORT ItemDesc -{ -private: - Accessor * AMainType; - Accessor * ASubType; - Accessor * ASubIndex; - Accessor * AIndex; - Accessor * AQuality; - Process * p; - bool hasDecoration; -public: - ItemDesc(uint32_t VTable, Process * p); - bool getItem(uint32_t itemptr, t_item & item); - std::string className; - uint32_t vtable; - uint32_t mainType; - std::vector improvement; + t_material matdesc; + int32_t quality; }; -class DFHACK_EXPORT Items +class DFHACK_EXPORT Items : public Module { public: - Items(DFContextShared * _d); - ~Items(); - std::string getItemDescription(uint32_t itemptr, Materials * Materials); - std::string getItemClass(int32_t index); - bool getItemData(uint32_t itemptr, t_item & item); + Items(DFContextShared * _d); + ~Items(); + bool Start(); + bool Finish(); + std::string getItemDescription(uint32_t itemptr, Materials * Materials); + std::string getItemClass(int32_t index); + bool getItemData(uint32_t itemptr, t_item & item); private: - class Private; - Private* d; - std::map descType; - std::map descVTable; + class Private; + Private* d; }; } #endif diff --git a/library/include/dfhack/modules/Maps.h b/library/include/dfhack/modules/Maps.h index cfdb31d43..d1957c6b8 100644 --- a/library/include/dfhack/modules/Maps.h +++ b/library/include/dfhack/modules/Maps.h @@ -6,12 +6,13 @@ #define CL_MOD_MAPS #include "dfhack/DFExport.h" +#include "dfhack/DFModule.h" namespace DFHack { /*************************************************************************** T Y P E S ***************************************************************************/ - + enum e_feature { feature_Other, @@ -19,6 +20,7 @@ namespace DFHack feature_Underworld, feature_Hell_Temple }; + static const char * sa_feature[]= { (char*)"Other", @@ -26,6 +28,8 @@ namespace DFHack (char*)"Underworld", (char*)"Hell Temple" }; + + /// used as a key for the local feature map. combines X an Y coords. union planecoord { uint32_t xy; @@ -40,40 +44,60 @@ namespace DFHack return false; } }; + struct t_feature { e_feature type; + /// main material type - decides between stuff like bodily fluids, inorganics, vomit, amber, etc. int16_t main_material; + /// generally some index to a vector of material types. int32_t sub_material; - bool discovered; // placeholder. + /// placeholder + bool discovered; + /// this is NOT part of the DF feature, but an address of the feature as seen by DFhack. uint32_t origin; }; - + + /// mineral vein object struct t_vein { uint32_t vtable; + /// index into the inorganic material vector int32_t type; - int16_t assignment[16]; + /// bit mask describing how the vein maps to the map block + /// assignment[y] & (1 << x) describes the tile (x, y) of the block + int16_t assignment[16]; uint32_t flags; - uint32_t address_of; // this is NOT part of the DF vein, but an address of the vein as seen by DFhack. + /// this is NOT part of the DF vein, but an address of the vein as seen by DFhack. + uint32_t address_of; }; - // stores what tiles should appear when the ice melts + + /// stores what tiles should appear when the ice melts struct t_frozenliquidvein { uint32_t vtable; + /// a 16x16 array of the original tile types int16_t tiles[16][16]; - uint32_t address_of; // this is NOT part of the DF vein, but an address of the vein as seen by DFhack. + /// this is NOT part of the DF vein, but an address of the vein as seen by DFhack. + uint32_t address_of; }; - + + /// a 'spattervein' defines what coverings the individual map tiles have (snow, blood, etc) + /// @see PrintSplatterType in DFMiscUtils.h -- incomplete, but illustrative struct t_spattervein { uint32_t vtable; + /// generic material. uint16_t mat1; uint16_t unk1; + /// material vector index uint32_t mat2; + /// something even more specific? uint16_t mat3; + /// 16x16 array of covering 'intensity' uint8_t intensity[16][16]; - uint32_t address_of; // this is NOT part of the DF vein, but an address of the vein as seen by DFhack. + /// this is NOT part of the DF vein, but an address of the vein as seen by DFhack. + uint32_t address_of; }; enum BiomeOffset @@ -98,16 +122,25 @@ namespace DFHack traffic_restricted }; + /// type of a designation for a tile enum e_designation { + /// no designation designation_no, - designation_default, // dig walls, remove stairs and ramps, gather plants, fell trees - designation_ud_stair, // dig up/down stairs - designation_channel, // dig a channel - designation_ramp, // dig ramp out of a wall - designation_d_stair, // dig a stair down - designation_u_stair, // dig a stair up - designation_7 // whatever + /// dig walls, remove stairs and ramps, gather plants, fell trees. depends on tile type + designation_default, + /// dig up/down stairs + designation_ud_stair, + /// dig a channel + designation_channel, + /// dig ramp out of a wall + designation_ramp, + /// dig a stair down + designation_d_stair, + /// dig a stair up + designation_u_stair, + /// whatever. for completenes I guess + designation_7 }; enum e_liquidtype @@ -120,41 +153,43 @@ namespace DFHack { unsigned int flow_size : 3; // how much liquid is here? unsigned int pile : 1; // stockpile? - /* - * All the different dig designations... needs more info, probably an enum - */ + /// All the different dig designations e_designation dig : 3; unsigned int smooth : 2; unsigned int hidden : 1; - /* + /** * This one is rather involved, but necessary to retrieve the base layer matgloss index - * see http://www.bay12games.com/forum/index.php?topic=608.msg253284#msg253284 for details + * @see http://www.bay12games.com/forum/index.php?topic=608.msg253284#msg253284 */ unsigned int geolayer_index :4; unsigned int light : 1; unsigned int subterranean : 1; // never seen the light of day? unsigned int skyview : 1; // sky is visible now, it rains in here when it rains - /* + /** * Probably similar to the geolayer_index. Only with a different set of offsets and different data. * we don't use this yet */ unsigned int biome : 4; - /* + /** * 0 = water * 1 = magma */ e_liquidtype liquid_type : 1; unsigned int water_table : 1; // srsly. wtf? unsigned int rained : 1; // does this mean actual rain (as in the blue blocks) or a wet tile? - e_traffic traffic : 2; // needs enum - unsigned int flow_forbid : 1; // what? + e_traffic traffic : 2; + /// the tile is not evaluated when calculating flows? + unsigned int flow_forbid : 1; + /// no liquid spreading unsigned int liquid_static : 1; - unsigned int feature_local : 1; // this tile is a part of a feature - unsigned int feature_global : 1; // this tile is a part of a feature - unsigned int liquid_character : 2; // those ripples on streams? - + /// this tile is a part of a local feature. can be combined with 'featstone' tiles + unsigned int feature_local : 1; + /// this tile is a part of a global feature. can be combined with 'featstone' tiles + unsigned int feature_global : 1; + /// those ripples on streams? + unsigned int liquid_character : 2; }; union t_designation @@ -166,12 +201,16 @@ namespace DFHack // occupancy flags (rat,dwarf,horse,built wall,not build wall,etc) struct naked_occupancy { - unsigned int building : 3;// building type... should be an enum? + // building type... should be an enum? // 7 = door + unsigned int building : 3; + /// the tile contains a standing? creature unsigned int unit : 1; + /// the tile contains a prone creature unsigned int unit_grounded : 1; + /// the tile contains an item unsigned int item : 1; - // splatter. everyone loves splatter. + /// splatter. everyone loves splatter. this doesn't seem to be used anymore unsigned int mud : 1; unsigned int vomit :1; unsigned int broken_arrows_color :4; @@ -199,12 +238,14 @@ namespace DFHack struct naked_occupancy_grouped { - unsigned int building : 3;// building type... should be an enum? - // 7 = door + unsigned int building : 3; + /// the tile contains a standing? creature unsigned int unit : 1; + /// the tile contains a prone creature unsigned int unit_grounded : 1; + /// the tile contains an item unsigned int item : 1; - // splatter. everyone loves splatter. + /// splatter. everyone loves splatter. this doesn't seem to be used anymore unsigned int splatter : 26; }; @@ -218,12 +259,15 @@ namespace DFHack // map block flags struct naked_blockflags { - unsigned int designated : 1;// designated for jobs (digging and stuff like that) - unsigned int unk_1 : 1; // possibly related to the designated flag - // two flags required for liquid flow. no idea why + /// designated for jobs (digging and stuff like that) + unsigned int designated : 1; + /// possibly related to the designated flag + unsigned int unk_1 : 1; + /// two flags required for liquid flow. unsigned int liquid_1 : 1; unsigned int liquid_2 : 1; - unsigned int unk_2: 28; // rest of the flags is completely unknown + /// rest of the flags is completely unknown + unsigned int unk_2: 28; // there's a possibility that this flags field is shorter than 32 bits }; @@ -241,23 +285,30 @@ namespace DFHack typedef struct { + /// type of the tiles tiletypes40d tiletypes; + /// flags determining the state of the tiles designations40d designation; + /// flags determining what's on the tiles occupancies40d occupancy; + /// values used for geology/biome assignment biome_indices40d biome_indices; - uint32_t origin; // the address where it came from + /// the address where the block came from + uint32_t origin; t_blockflags blockflags; + /// index into the global feature vector int16_t global_feature; + /// index into the local feature vector... complicated int16_t local_feature; } mapblock40d; /*************************************************************************** C L I E N T M O D U L E ***************************************************************************/ - + #ifndef BUILD_SHM class DFContextShared; struct t_viewscreen; - class DFHACK_EXPORT Maps + class DFHACK_EXPORT Maps : public Module { public: @@ -321,6 +372,7 @@ namespace DFHack * Return false/0 on failure, buffer allocated by client app, 256 items long */ bool isValidBlock(uint32_t blockx, uint32_t blocky, uint32_t blockz); + /** * Get the address of a block or 0 if block is not valid */ @@ -340,7 +392,7 @@ namespace DFHack /// read/write temperatures bool ReadTemperatures(uint32_t blockx, uint32_t blocky, uint32_t blockz, t_temperatures *temp1, t_temperatures *temp2); bool WriteTemperatures (uint32_t blockx, uint32_t blocky, uint32_t blockz, t_temperatures *temp1, t_temperatures *temp2); - + /// read/write block occupancies bool ReadOccupancy(uint32_t blockx, uint32_t blocky, uint32_t blockz, occupancies40d *buffer); bool WriteOccupancy(uint32_t blockx, uint32_t blocky, uint32_t blockz, occupancies40d *buffer); @@ -350,10 +402,8 @@ namespace DFHack bool WriteDirtyBit(uint32_t blockx, uint32_t blocky, uint32_t blockz, bool dirtybit); /// read/write the block flags - bool ReadBlockFlags(uint32_t blockx, uint32_t blocky, uint32_t blockz, - t_blockflags &blockflags); - bool WriteBlockFlags(uint32_t blockx, uint32_t blocky, uint32_t blockz, - t_blockflags blockflags); + bool ReadBlockFlags(uint32_t blockx, uint32_t blocky, uint32_t blockz, t_blockflags &blockflags); + bool WriteBlockFlags(uint32_t blockx, uint32_t blocky, uint32_t blockz, t_blockflags blockflags); /// read/write features bool ReadFeatures(uint32_t blockx, uint32_t blocky, uint32_t blockz, int16_t & local, int16_t & global); bool WriteLocalFeature(uint32_t blockx, uint32_t blocky, uint32_t blockz, int16_t local = -1); @@ -368,10 +418,11 @@ namespace DFHack std::vector* veins, std::vector* ices = 0, std::vector* splatter = 0); - + private: struct Private; Private *d; }; + #endif } #endif diff --git a/library/include/dfhack/modules/Materials.h b/library/include/dfhack/modules/Materials.h index af2e16941..f3ac6425c 100644 --- a/library/include/dfhack/modules/Materials.h +++ b/library/include/dfhack/modules/Materials.h @@ -1,13 +1,14 @@ #ifndef CL_MOD_MATERIALS #define CL_MOD_MATERIALS /* -* Creatures -*/ + * Materials + */ #include "dfhack/DFExport.h" +#include "dfhack/DFModule.h" namespace DFHack { class DFContextShared; - + struct t_matgloss { char id[128]; //the id in the raws @@ -53,7 +54,7 @@ namespace DFHack uint32_t startdate; /* in days */ uint32_t enddate; /* in days */ }; - + struct t_creaturecaste { char rawname[128]; @@ -84,81 +85,72 @@ namespace DFHack struct t_matglossOther { - char rawname[128]; + char rawname[128]; }; struct t_creatureextract { - char rawname[128]; + char rawname[128]; }; // this doesn't transfer well across the shm gap... struct t_creaturetype { char rawname[128]; - std::vector castes; - std::vector extract; - uint8_t tile_character; - struct - { - uint16_t fore; - uint16_t back; - uint16_t bright; - } tilecolor; + std::vector castes; + std::vector extract; + uint8_t tile_character; + struct + { + uint16_t fore; + uint16_t back; + uint16_t bright; + } tilecolor; }; // this structure describes what are things made of in the DF world struct t_material { - int16_t itemType; - int16_t subType; - int16_t subIndex; - int32_t index; - uint32_t flags; + int16_t itemType; + int16_t subType; + int16_t subIndex; + int32_t index; + uint32_t flags; }; - - class DFHACK_EXPORT Materials + + class DFHACK_EXPORT Materials : public Module { - public: - Materials(DFHack::DFContextShared * _d); - ~Materials(); - - std::vector inorganic; - std::vector organic; - std::vector tree; - std::vector plant; - std::vector race; - std::vector raceEx; - std::vector color; - std::vector other; - std::vector alldesc; - - bool ReadInorganicMaterials (void); - bool ReadOrganicMaterials (void); - bool ReadWoodMaterials (void); - bool ReadPlantMaterials (void); - bool ReadCreatureTypes (void); - bool ReadCreatureTypesEx (void); - bool ReadDescriptorColors(void); - bool ReadOthers (void); - - void ReadAllMaterials(void); - - std::string getDescription(t_material & mat); - /* - bool ReadInorganicMaterials (std::vector & output); - bool ReadOrganicMaterials (std::vector & output); - bool ReadWoodMaterials (std::vector & output); - bool ReadPlantMaterials (std::vector & output); - - // TODO: maybe move to creatures? - bool ReadCreatureTypes (std::vector & output); - bool ReadCreatureTypesEx (vector & creatures); - bool ReadDescriptorColors(std::vector & output); - */ - private: - class Private; - Private* d; - }; + public: + Materials(DFHack::DFContextShared * _d); + ~Materials(); + bool Finish(); + + std::vector inorganic; + std::vector organic; + std::vector tree; + std::vector plant; + std::vector race; + std::vector raceEx; + std::vector color; + std::vector other; + std::vector alldesc; + + bool ReadInorganicMaterials (void); + bool ReadOrganicMaterials (void); + bool ReadWoodMaterials (void); + bool ReadPlantMaterials (void); + bool ReadCreatureTypes (void); + bool ReadCreatureTypesEx (void); + bool ReadDescriptorColors(void); + bool ReadOthers (void); + + void ReadAllMaterials(void); + + std::string getType(t_material & mat); + std::string getDescription(t_material & mat); + private: + class Private; + Private* d; + }; } #endif diff --git a/library/include/dfhack/modules/Position.h b/library/include/dfhack/modules/Position.h index b70387e66..376208df2 100644 --- a/library/include/dfhack/modules/Position.h +++ b/library/include/dfhack/modules/Position.h @@ -4,6 +4,7 @@ * View position and size and cursor position */ #include "dfhack/DFExport.h" +#include "dfhack/DFModule.h" namespace DFHack { #define NUM_HOTKEYS 16 @@ -15,33 +16,49 @@ namespace DFHack int32_t y; int32_t z; }; - + + struct t_screen + { + uint8_t symbol; + uint8_t foreground; + uint8_t background; + uint8_t bright; + uint8_t gtile; + uint8_t grayscale; + }; + class DFContextShared; - class DFHACK_EXPORT Position + class DFHACK_EXPORT Position : public Module { public: - + Position(DFContextShared * d); ~Position(); + bool Finish(){return true;}; /* * Cursor and window coords */ bool getViewCoords (int32_t &x, int32_t &y, int32_t &z); bool setViewCoords (const int32_t x, const int32_t y, const int32_t z); - + bool getCursorCoords (int32_t &x, int32_t &y, int32_t &z); bool setCursorCoords (const int32_t x, const int32_t y, const int32_t z); - + /* * Hotkeys (DF's zoom locations) */ bool ReadHotkeys(t_hotkey hotkeys[]); - + /* * Window size in tiles */ bool getWindowSize(int32_t & width, int32_t & height); - + + /* + * Screen tiles + */ + bool getScreenTiles(int32_t width, int32_t height, t_screen screen[]); + private: struct Private; Private *d; diff --git a/library/include/dfhack/modules/Translation.h b/library/include/dfhack/modules/Translation.h index a7e186990..5b562bc77 100644 --- a/library/include/dfhack/modules/Translation.h +++ b/library/include/dfhack/modules/Translation.h @@ -4,6 +4,7 @@ * DF translation tables and name translation */ #include "dfhack/DFExport.h" +#include "dfhack/DFModule.h" namespace DFHack { class DFContextShared; @@ -13,8 +14,8 @@ namespace DFHack DFDict translations; DFDict foreign_languages; } Dicts; - - class DFHACK_EXPORT Translation + + class DFHACK_EXPORT Translation : public Module { public: Translation(DFContextShared * d); @@ -26,7 +27,7 @@ namespace DFHack Dicts * getDicts(); // translate a name using the loaded dictionaries std::string TranslateName(const DFHack::t_name& name, bool inEnglish = true); - + private: struct Private; Private *d; diff --git a/library/include/dfhack/modules/Vegetation.h b/library/include/dfhack/modules/Vegetation.h index b81bb81c1..9ab390e7f 100644 --- a/library/include/dfhack/modules/Vegetation.h +++ b/library/include/dfhack/modules/Vegetation.h @@ -4,6 +4,7 @@ * DF vegetation - stuff that grows and gets cut down or trampled by dwarves */ #include "dfhack/DFExport.h" +#include "dfhack/DFModule.h" namespace DFHack { /* @@ -28,7 +29,7 @@ namespace DFHack }; class DFContextShared; - class DFHACK_EXPORT Vegetation + class DFHACK_EXPORT Vegetation : public Module { public: Vegetation(DFContextShared * d); diff --git a/library/include/dfhack/modules/WindowIO.h b/library/include/dfhack/modules/WindowIO.h index 146029ca0..6e1af9fcb 100644 --- a/library/include/dfhack/modules/WindowIO.h +++ b/library/include/dfhack/modules/WindowIO.h @@ -27,6 +27,7 @@ distribution. #include "dfhack/DFPragma.h" #include "dfhack/DFExport.h" +#include "dfhack/DFModule.h" namespace DFHack { @@ -88,12 +89,13 @@ enum t_special NUM_SPECIALS }; class DFContextShared; -class DFHACK_EXPORT WindowIO +class DFHACK_EXPORT WindowIO : public Module { class Private; private: Private * d; public: + bool Finish(){return true;}; WindowIO(DFHack::DFContextShared * d); ~WindowIO(); void TypeStr (const char *input, int delay = 0, bool useShift = false); diff --git a/library/include/dfhack/modules/World.h b/library/include/dfhack/modules/World.h index 21300bfd5..fdb08baf7 100644 --- a/library/include/dfhack/modules/World.h +++ b/library/include/dfhack/modules/World.h @@ -5,11 +5,12 @@ * World: all kind of stuff related to the current world state */ #include "dfhack/DFExport.h" +#include "dfhack/DFModule.h" namespace DFHack { class DFContextShared; - class DFHACK_EXPORT World + class DFHACK_EXPORT World : public Module { public: diff --git a/library/modules/Buildings_C.cpp b/library/modules/Buildings_C.cpp index 18bd77922..d7b7d940e 100644 --- a/library/modules/Buildings_C.cpp +++ b/library/modules/Buildings_C.cpp @@ -22,20 +22,8 @@ must not be misrepresented as being the original software. distribution. */ -#include "dfhack/DFIntegers.h" -#include -#include -#include "stdio.h" - -using namespace std; - -#include "Internal.h" -#include "dfhack/DFTypes.h" -#include "dfhack/modules/Buildings.h" #include "dfhack-c/modules/Buildings_C.h" - -using namespace DFHack; - +using namespace std; #ifdef __cplusplus extern "C" { #endif @@ -82,33 +70,27 @@ int Buildings_GetCustomWorkshopType(DFHackObject* b_Ptr, t_building* building) int Buildings_ReadCustomWorkshopTypes(DFHackObject* b_Ptr, void* (*t_customWorkshop_buffer_create)(uint32_t)) { - if(b_Ptr != NULL) - { - int i; - t_customWorkshop* cw_Ptr; - map bTypes; - map::iterator bIter; - - bool result = ((DFHack::Buildings*)b_Ptr)->ReadCustomWorkshopTypes(bTypes); - - if(!result) - return 0; - - cw_Ptr = (t_customWorkshop*)((*t_customWorkshop_buffer_create)(bTypes.size())); - - for(i = 0, bIter = bTypes.begin(); bIter != bTypes.end(); bIter++, i++) - { - cw_Ptr[i].index = (*bIter).first; - - size_t length = (*bIter).second.copy(cw_Ptr[i].name, 256); - - cw_Ptr[i].name[length] = '\0'; - } - - return 1; - } - - return -1; + if(b_Ptr != NULL) + { + int i; + t_customWorkshop* cw_Ptr; + std::map bTypes; + map::iterator bIter; + + if(!((DFHack::Buildings*)b_Ptr)->ReadCustomWorkshopTypes(bTypes)) + return 0; + + cw_Ptr = (t_customWorkshop*)((*t_customWorkshop_buffer_create)(bTypes.size())); + for(i = 0, bIter = bTypes.begin(); bIter != bTypes.end(); bIter++, i++) + { + cw_Ptr[i].index = (*bIter).first; + size_t length = (*bIter).second.copy(cw_Ptr[i].name, 256); + cw_Ptr[i].name[length] = '\0'; + } + return 1; + } + + return -1; } #ifdef __cplusplus diff --git a/library/modules/Constructions_C.cpp b/library/modules/Constructions_C.cpp index 93afdae01..03e89ca23 100644 --- a/library/modules/Constructions_C.cpp +++ b/library/modules/Constructions_C.cpp @@ -22,15 +22,8 @@ must not be misrepresented as being the original software. distribution. */ -#include "dfhack/DFIntegers.h" - -#include "Internal.h" -#include "dfhack/DFTypes.h" -#include "dfhack/modules/Constructions.h" #include "dfhack-c/modules/Constructions_C.h" -using namespace DFHack; - #ifdef __cplusplus extern "C" { #endif diff --git a/library/modules/Creatures.cpp b/library/modules/Creatures.cpp index b7e39a95f..2e9e319cd 100644 --- a/library/modules/Creatures.cpp +++ b/library/modules/Creatures.cpp @@ -92,19 +92,19 @@ Creatures::Creatures(DFContextShared* _d) creatures.mood_offset = minfo->getOffset("creature_mood"); creatures.mood_skill_offset = minfo->getOffset("creature_mood_skill"); creatures.pickup_equipment_bit = minfo->getOffset("creature_pickup_equipment_bit"); - creatures.current_job_offset = minfo->getOffset("creature_current_job"); + creatures.current_job_offset = minfo->getOffset("creature_current_job"); // soul offsets creatures.soul_skills_vector_offset = minfo->getOffset("soul_skills_vector"); creatures.soul_mental_offset = minfo->getOffset("soul_mental"); creatures.soul_traits_offset = minfo->getOffset("soul_traits"); - + // appearance creatures.appearance_vector_offset = minfo->getOffset("creature_appearance_vector"); //birth creatures.birth_year_offset = minfo->getOffset("creature_birth_year"); creatures.birth_time_offset = minfo->getOffset("creature_birth_time"); - + // name offsets for the creature module creatures.name_firstname_offset = minfo->getOffset("name_firstname"); creatures.name_nickname_offset = minfo->getOffset("name_nickname"); @@ -172,17 +172,17 @@ bool Creatures::ReadCreature (const int32_t index, t_creature & furball) */ // non-SHM slow path memory_info * minfo = d->d->offset_descriptor; - + // read pointer from vector at position uint32_t temp = d->p_cre->at (index); furball.origin = temp; Creatures2010::creature_offsets &offs = d->creatures; - + //read creature from memory - + // name d->d->readName(furball.name,temp + offs.name_offset); - + // basic stuff p->readDWord (temp + offs.happiness_offset, furball.happiness); p->readDWord (temp + offs.id_offset, furball.id); @@ -193,22 +193,24 @@ bool Creatures::ReadCreature (const int32_t index, t_creature & furball) p->readWord (temp + offs.caste_offset, furball.caste); p->readDWord (temp + offs.flags1_offset, furball.flags1.whole); p->readDWord (temp + offs.flags2_offset, furball.flags2.whole); - + // physical attributes - p->read(temp + offs.physical_offset, sizeof(t_attrib) * 6, (uint8_t *)&furball.strength); - + p->read(temp + offs.physical_offset, + sizeof(t_attrib) * NUM_CREATURE_PHYSICAL_ATTRIBUTES, + (uint8_t *)&furball.strength); + // mood stuff furball.mood = (int16_t) p->readWord (temp + offs.mood_offset); furball.mood_skill = p->readWord (temp + offs.mood_skill_offset); - d->d->readName(furball.artifact_name, temp + offs.artifact_name_offset); - + d->d->readName(furball.artifact_name, temp + offs.artifact_name_offset); + // custom profession p->readSTLString(temp + offs.custom_profession_offset, furball.custom_profession, sizeof(furball.custom_profession)); //fill_char_buf (furball.custom_profession, p->readSTLString (temp + offs.custom_profession_offset)); // labors p->read (temp + offs.labors_offset, NUM_CREATURE_LABORS, furball.labors); - + // profession furball.profession = p->readByte (temp + offs.profession_offset); @@ -252,25 +254,34 @@ bool Creatures::ReadCreature (const int32_t index, t_creature & furball) */ uint32_t soul = p->readDWord(temp + offs.default_soul_offset); furball.has_default_soul = false; + if(soul) { furball.has_default_soul = true; // get first soul's skills DfVector skills(p, soul + offs.soul_skills_vector_offset); furball.defaultSoul.numSkills = skills.size(); + for (uint32_t i = 0; i < furball.defaultSoul.numSkills;i++) { uint32_t temp2 = skills[i]; // a byte: this gives us 256 skills maximum. furball.defaultSoul.skills[i].id = p->readByte (temp2); - furball.defaultSoul.skills[i].rating = p->readByte (temp2 + 4); - furball.defaultSoul.skills[i].experience = p->readWord (temp2 + 8); + furball.defaultSoul.skills[i].rating = + p->readByte (temp2 + offsetof(t_skill, rating)); + furball.defaultSoul.skills[i].experience = + p->readWord (temp2 + offsetof(t_skill, experience)); } + // mental attributes are part of the soul - p->read(soul + offs.soul_mental_offset, sizeof(t_attrib) * 13, (uint8_t *)&furball.defaultSoul.analytical_ability); - + p->read(soul + offs.soul_mental_offset, + sizeof(t_attrib) * NUM_CREATURE_MENTAL_ATTRIBUTES, + (uint8_t *)&furball.defaultSoul.analytical_ability); + // traits as well - p->read(soul + offs.soul_traits_offset, sizeof (uint16_t) * NUM_CREATURE_TRAITS, (uint8_t *) &furball.defaultSoul.traits); + p->read(soul + offs.soul_traits_offset, + sizeof (uint16_t) * NUM_CREATURE_TRAITS, + (uint8_t *) &furball.defaultSoul.traits); } DfVector app(p, temp + offs.appearance_vector_offset); @@ -301,7 +312,7 @@ int32_t Creatures::ReadCreatureInBox (int32_t index, t_creature & furball, { if (!d->Started) return -1; - + Process *p = d->owner; /* if(d->creature_module) @@ -346,14 +357,15 @@ int32_t Creatures::ReadCreatureInBox (int32_t index, t_creature & furball, } } - - bool Creatures::WriteLabors(const uint32_t index, uint8_t labors[NUM_CREATURE_LABORS]) { - if(!d->Started) return false; + if(!d->Started) + { + return false; + } uint32_t temp = d->p_cre->at (index); Process * p = d->owner; - + p->write(temp + d->creatures.labors_offset, NUM_CREATURE_LABORS, labors); uint32_t pickup_equip; p->readDWord(temp + d->creatures.pickup_equipment_bit, pickup_equip); @@ -362,6 +374,198 @@ bool Creatures::WriteLabors(const uint32_t index, uint8_t labors[NUM_CREATURE_LA return true; } +bool Creatures::WriteHappiness(const uint32_t index, const uint32_t happinessValue) +{ + if(!d->Started) + { + return false; + } + uint32_t temp = d->p_cre->at (index); + Process * p = d->owner; + p->writeDWord (temp + d->creatures.happiness_offset, happinessValue); + return true; +} + +bool Creatures::WriteFlags(const uint32_t index, + const uint32_t flags1, + const uint32_t flags2) +{ + if(!d->Started) + { + return false; + } + uint32_t temp = d->p_cre->at (index); + Process * p = d->owner; + p->writeDWord (temp + d->creatures.flags1_offset, flags1); + p->writeDWord (temp + d->creatures.flags2_offset, flags2); + return true; +} + +bool Creatures::WriteSkills(const uint32_t index, const t_soul &soul) +{ + if(!d->Started) + { + return false; + } + + uint32_t temp = d->p_cre->at (index); + Process * p = d->owner; + uint32_t souloff = p->readDWord(temp + d->creatures.default_soul_offset); + + if(!souloff) + { + return false; + } + + DfVector skills(p, souloff + d->creatures.soul_skills_vector_offset); + + for (uint32_t i=0; iwriteByte(temp2 + offsetof(t_skill, rating), soul.skills[i].rating); + p->writeWord(temp2 + offsetof(t_skill, experience), soul.skills[i].experience); + } + + return true; +} + +bool Creatures::WriteAttributes(const uint32_t index, const t_creature &creature) +{ + if(!d->Started) + { + return false; + } + + uint32_t temp = d->p_cre->at (index); + Process * p = d->owner; + uint32_t souloff = p->readDWord(temp + d->creatures.default_soul_offset); + + if(!souloff) + { + return false; + } + + // physical attributes + p->write(temp + d->creatures.physical_offset, + sizeof(t_attrib) * NUM_CREATURE_PHYSICAL_ATTRIBUTES, + (uint8_t *)&creature.strength); + + // mental attributes are part of the soul + p->write(souloff + d->creatures.soul_mental_offset, + sizeof(t_attrib) * NUM_CREATURE_MENTAL_ATTRIBUTES, + (uint8_t *)&creature.defaultSoul.analytical_ability); + + return true; +} + +bool Creatures::WriteSex(const uint32_t index, const uint8_t sex) +{ + if(!d->Started) + { + return false; + } + + uint32_t temp = d->p_cre->at (index); + Process * p = d->owner; + p->writeByte (temp + d->creatures.sex_offset, sex); +} + +bool Creatures::WriteTraits(const uint32_t index, const t_soul &soul) +{ + if(!d->Started) + { + return false; + } + + uint32_t temp = d->p_cre->at (index); + Process * p = d->owner; + uint32_t souloff = p->readDWord(temp + d->creatures.default_soul_offset); + + if(!souloff) + { + return false; + } + + p->write(souloff + d->creatures.soul_traits_offset, + sizeof (uint16_t) * NUM_CREATURE_TRAITS, + (uint8_t *) &soul.traits); + + return true; +} + +bool Creatures::WriteMood(const uint32_t index, const uint16_t mood) +{ + if(!d->Started) + { + return false; + } + + uint32_t temp = d->p_cre->at (index); + Process * p = d->owner; + p->writeWord(temp + d->creatures.mood_offset, mood); + return true; +} + +bool Creatures::WriteMoodSkill(const uint32_t index, const uint16_t moodSkill) +{ + if(!d->Started) + { + return false; + } + + uint32_t temp = d->p_cre->at (index); + Process * p = d->owner; + p->writeWord(temp + d->creatures.mood_skill_offset, moodSkill); + return true; +} + +bool Creatures::WriteJob(const t_creature * furball, std::vector const& mat) +{ + unsigned int i; + if(!d->Inited) return false; + if(!furball->current_job.active) return false; + Process * p = d->owner; + memory_info * minfo = d->d->offset_descriptor; + + DfVector cmats(p, furball->current_job.occupationPtr + minfo->getOffset("job_materials_vector")); + + for(i=0;iwriteWord(cmats[i] + minfo->getOffset("job_material_maintype"), mat[i].itemType); + p->writeWord(cmats[i] + minfo->getOffset("job_material_sectype1"), mat[i].subType); + p->writeWord(cmats[i] + minfo->getOffset("job_material_sectype2"), mat[i].subIndex); + p->writeDWord(cmats[i] + minfo->getOffset("job_material_sectype3"), mat[i].index); + p->writeDWord(cmats[i] + minfo->getOffset("job_material_flags"), mat[i].flags); + } + return true; +} + +bool Creatures::WritePos(const uint32_t index, const t_creature &creature) +{ + if(!d->Started) + { + return false; + } + + uint32_t temp = d->p_cre->at (index); + Process * p = d->owner; + p->write (temp + d->creatures.pos_offset, 3 * sizeof (uint16_t), (uint8_t *) & (creature.x)); + return true; +} + +bool Creatures::WriteCiv(const uint32_t index, const int32_t civ) +{ + if(!d->Started) + { + return false; + } + + uint32_t temp = d->p_cre->at (index); + Process * p = d->owner; + p->writeDWord(temp + d->creatures.civ_offset, civ); + return true; +} + uint32_t Creatures::GetDwarfRaceIndex() { if(!d->Inited) return 0; diff --git a/library/modules/Creatures_C.cpp b/library/modules/Creatures_C.cpp index 1aac93110..731ac8611 100644 --- a/library/modules/Creatures_C.cpp +++ b/library/modules/Creatures_C.cpp @@ -22,21 +22,7 @@ must not be misrepresented as being the original software. distribution. */ -#include "dfhack/DFExport.h" -#include "dfhack/DFIntegers.h" -#include -#include -#include - -using namespace std; - -#include "dfhack/DFTypes.h" -#include "dfhack/modules/Materials.h" -#include "dfhack/modules/Creatures.h" #include "dfhack-c/modules/Creatures_C.h" -#include "DFHack_C.h" - -using namespace DFHack; #ifdef __cplusplus extern "C" { diff --git a/library/modules/Gui_C.cpp b/library/modules/Gui_C.cpp index 586eb1dd0..da17d2a18 100644 --- a/library/modules/Gui_C.cpp +++ b/library/modules/Gui_C.cpp @@ -21,16 +21,8 @@ must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ -#include -#include -#include "DFHack_C.h" -#include "dfhack-c/modules/Gui_C.h" -#include "dfhack/DFIntegers.h" - -#include "Internal.h" -#include "dfhack/modules/Gui.h" -using namespace DFHack; +#include "dfhack-c/modules/Gui_C.h" #ifdef __cplusplus extern "C" { diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp index 66e2720ac..2419bbf40 100644 --- a/library/modules/Items.cpp +++ b/library/modules/Items.cpp @@ -33,235 +33,294 @@ distribution. using namespace DFHack; -class Items::Private +enum accessor_type {ACCESSOR_CONSTANT, ACCESSOR_INDIRECT, ACCESSOR_DOUBLE_INDIRECT}; + +/* this is used to store data about the way accessors work */ +class DFHACK_EXPORT Accessor { - public: - DFContextShared *d; - Process * owner; - /* - bool Inited; - bool Started; - */ +private: + accessor_type type; + int32_t constant; + uint32_t offset1; + uint32_t offset2; + Process * p; + uint32_t dataWidth; +public: + Accessor(uint32_t function, Process * p); + Accessor(accessor_type type, int32_t constant, uint32_t offset1, uint32_t offset2, uint32_t dataWidth, Process * p); + int32_t getValue(uint32_t objectPtr); + bool isConstant(); }; - -Items::Items(DFContextShared * d_) +class DFHACK_EXPORT ItemImprovementDesc { - d = new Private; - d->d = d_; - d->owner = d_->p; -} -Items::~Items() +private: + Accessor * AType; + Process * p; +public: + ItemImprovementDesc(uint32_t VTable, Process * p); + bool getImprovement(uint32_t descptr, t_improvement & imp); + uint32_t vtable; + uint32_t maintype; +}; + +class DFHACK_EXPORT ItemDesc { - delete d; - /* TODO : delete all item descs */ -} +private: + Accessor * AMainType; + Accessor * ASubType; + Accessor * ASubIndex; + Accessor * AIndex; + Accessor * AQuality; + Process * p; + bool hasDecoration; +public: + ItemDesc(uint32_t VTable, Process * p); + bool getItem(uint32_t itemptr, t_item & item); + std::string className; + uint32_t vtable; + uint32_t mainType; + std::vector improvement; +}; + +// FIXME: this is crazy Accessor::Accessor(uint32_t function, Process *p) { - this->p = p; - this->constant = 0; - this->offset1 = 0; - this->offset2 = 0; - this->type = ACCESSOR_CONSTANT; - this->dataWidth = 2; - uint64_t funcText = p->readQuad(function); - if( funcText == 0xCCCCCCCCCCC3C033LL ) - { - return; - } - if( funcText == 0xCCCCCCCCC3FFC883LL ) - { - /* or eax,-1; ret; */ - this->constant = -1; - return; - } - if( (funcText&0xFFFFFFFFFF0000FFLL) == 0xCCCCC300000000B8LL ) - { - /* mov eax, xx; ret; */ - this->constant = (funcText>>8) & 0xffff; - return; - } - if( (funcText&0xFFFFFF0000FFFFFFLL) == 0xC300000000818B66LL ) - { - /* mov ax, [ecx+xx]; ret; */ - this->type = ACCESSOR_INDIRECT; - this->offset1 = (funcText>>24) & 0xffff; - return; - } - if( (funcText&0xFFFFFFFF0000FFFFLL) == 0x8B6600000000818BLL ) - { - uint64_t funcText2 = p->readQuad(function+8); - if( (funcText2&0xFFFFFFFFFFFF00FFLL) == 0xCCCCCCCCCCC30040LL ) + this->p = p; + this->constant = 0; + this->offset1 = 0; + this->offset2 = 0; + this->type = ACCESSOR_CONSTANT; + this->dataWidth = 2; + uint64_t funcText = p->readQuad(function); + if( funcText == 0xCCCCCCCCCCC3C033LL ) + { + return; + } + if( funcText == 0xCCCCCCCCC3FFC883LL ) + { + /* or eax,-1; ret; */ + this->constant = -1; + return; + } + if( (funcText&0xFFFFFFFFFF0000FFLL) == 0xCCCCC300000000B8LL ) + { + /* mov eax, xx; ret; */ + this->constant = (funcText>>8) & 0xffff; + return; + } + if( (funcText&0xFFFFFF0000FFFFFFLL) == 0xC300000000818B66LL ) + { + /* mov ax, [ecx+xx]; ret; */ + this->type = ACCESSOR_INDIRECT; + this->offset1 = (funcText>>24) & 0xffff; + return; + } + if( (funcText&0xFFFFFFFF0000FFFFLL) == 0x8B6600000000818BLL ) + { + uint64_t funcText2 = p->readQuad(function+8); + if( (funcText2&0xFFFFFFFFFFFF00FFLL) == 0xCCCCCCCCCCC30040LL ) { - this->type = ACCESSOR_DOUBLE_INDIRECT; - this->offset1 = (funcText>>16) & 0xffff; - this->offset2 = (funcText2>>8) & 0xff; - return; - } - } - if( (funcText&0xFFFFFF0000FFFFFFLL) == 0xC30000000081BF0FLL ) - { - /* movsx eax, word ptr [ecx+xx]; ret */ - this->type = ACCESSOR_INDIRECT; - this->offset1 = (funcText>>24) & 0xffff; - return; - } - if( (funcText&0xFFFFFFFF0000FFFFLL) == 0xCCC300000000818BLL ) - { - /* mov eax, [ecx+xx]; ret; */ - this->type = ACCESSOR_INDIRECT; - this->offset1 = (funcText>>16) & 0xffff; - this->dataWidth = 4; - return; - } - printf("bad accessor @0x%x\n", function); + this->type = ACCESSOR_DOUBLE_INDIRECT; + this->offset1 = (funcText>>16) & 0xffff; + this->offset2 = (funcText2>>8) & 0xff; + return; + } + } + if( (funcText&0xFFFFFF0000FFFFFFLL) == 0xC30000000081BF0FLL ) + { + /* movsx eax, word ptr [ecx+xx]; ret */ + this->type = ACCESSOR_INDIRECT; + this->offset1 = (funcText>>24) & 0xffff; + return; + } + if( (funcText&0xFFFFFFFF0000FFFFLL) == 0xCCC300000000818BLL ) + { + /* mov eax, [ecx+xx]; ret; */ + this->type = ACCESSOR_INDIRECT; + this->offset1 = (funcText>>16) & 0xffff; + this->dataWidth = 4; + return; + } + printf("bad accessor @0x%x\n", function); } bool Accessor::isConstant() { - if(this->type == ACCESSOR_CONSTANT) - return true; - else - return false; + if(this->type == ACCESSOR_CONSTANT) + return true; + else + return false; } int32_t Accessor::getValue(uint32_t objectPtr) { - switch(this->type) - { - case ACCESSOR_CONSTANT: - return this->constant; - break; - case ACCESSOR_INDIRECT: - switch(this->dataWidth) - { - case 2: - return (int16_t) p->readWord(objectPtr + this->offset1); - case 4: - return p->readDWord(objectPtr + this->offset1); - default: - return -1; - } - break; - case ACCESSOR_DOUBLE_INDIRECT: - switch(this->dataWidth) - { - case 2: - return (int16_t) p->readWord(p->readDWord(objectPtr + this->offset1) + this->offset2); - case 4: - return p->readDWord(p->readDWord(objectPtr + this->offset1) + this->offset2); - default: - return -1; - } - break; - default: - return -1; - } + switch(this->type) + { + case ACCESSOR_CONSTANT: + return this->constant; + break; + case ACCESSOR_INDIRECT: + switch(this->dataWidth) + { + case 2: + return (int16_t) p->readWord(objectPtr + this->offset1); + case 4: + return p->readDWord(objectPtr + this->offset1); + default: + return -1; + } + break; + case ACCESSOR_DOUBLE_INDIRECT: + switch(this->dataWidth) + { + case 2: + return (int16_t) p->readWord(p->readDWord(objectPtr + this->offset1) + this->offset2); + case 4: + return p->readDWord(p->readDWord(objectPtr + this->offset1) + this->offset2); + default: + return -1; + } + break; + default: + return -1; + } } ItemDesc::ItemDesc(uint32_t VTable, Process *p) { - uint32_t funcOffsetA = p->getDescriptor()->getOffset("item_type_accessor"); - uint32_t funcOffsetB = p->getDescriptor()->getOffset("item_subtype_accessor"); - uint32_t funcOffsetC = p->getDescriptor()->getOffset("item_subindex_accessor"); - uint32_t funcOffsetD = p->getDescriptor()->getOffset("item_index_accessor"); - uint32_t funcOffsetQuality = p->getDescriptor()->getOffset("item_quality_accessor"); - this->vtable = VTable; - this->p = p; - this->className = p->readClassName(VTable).substr(5); - this->className.resize(this->className.size()-2); - this->AMainType = new Accessor( p->readDWord( VTable + funcOffsetA ), p); - this->ASubType = new Accessor( p->readDWord( VTable + funcOffsetB ), p); - this->ASubIndex = new Accessor( p->readDWord( VTable + funcOffsetC ), p); - this->AIndex = new Accessor( p->readDWord( VTable + funcOffsetD ), p); - this->AQuality = new Accessor( p->readDWord( VTable + funcOffsetQuality ), p); - this->hasDecoration = false; - if(this->AMainType->isConstant()) - this->mainType = this->AMainType->getValue(0); - else - { - fprintf(stderr, "Bad item main type at function %p\n", (void*) p->readDWord( VTable + funcOffsetA )); - this->mainType = 0; - } + uint32_t funcOffsetA = p->getDescriptor()->getOffset("item_type_accessor"); + uint32_t funcOffsetB = p->getDescriptor()->getOffset("item_subtype_accessor"); + uint32_t funcOffsetC = p->getDescriptor()->getOffset("item_subindex_accessor"); + uint32_t funcOffsetD = p->getDescriptor()->getOffset("item_index_accessor"); + uint32_t funcOffsetQuality = p->getDescriptor()->getOffset("item_quality_accessor"); + this->vtable = VTable; + this->p = p; + this->className = p->readClassName(VTable).substr(5); + this->className.resize(this->className.size()-2); + this->AMainType = new Accessor( p->readDWord( VTable + funcOffsetA ), p); + this->ASubType = new Accessor( p->readDWord( VTable + funcOffsetB ), p); + this->ASubIndex = new Accessor( p->readDWord( VTable + funcOffsetC ), p); + this->AIndex = new Accessor( p->readDWord( VTable + funcOffsetD ), p); + this->AQuality = new Accessor( p->readDWord( VTable + funcOffsetQuality ), p); + this->hasDecoration = false; + if(this->AMainType->isConstant()) + this->mainType = this->AMainType->getValue(0); + else + { + fprintf(stderr, "Bad item main type at function %p\n", (void*) p->readDWord( VTable + funcOffsetA )); + this->mainType = 0; + } } bool ItemDesc::getItem(uint32_t itemptr, DFHack::t_item &item) { - item.matdesc.itemType = this->AMainType->getValue(itemptr); - item.matdesc.subType = this->ASubType->getValue(itemptr); - item.matdesc.subIndex = this->ASubIndex->getValue(itemptr); - item.matdesc.index = this->AIndex->getValue(itemptr); - item.quality = this->AQuality->getValue(itemptr); - item.quantity = 1; /* TODO */ - return true; + item.matdesc.itemType = this->AMainType->getValue(itemptr); + item.matdesc.subType = this->ASubType->getValue(itemptr); + item.matdesc.subIndex = this->ASubIndex->getValue(itemptr); + item.matdesc.index = this->AIndex->getValue(itemptr); + item.quality = this->AQuality->getValue(itemptr); + item.quantity = 1; /* TODO */ + return true; +} + +class Items::Private +{ + public: + DFContextShared *d; + Process * owner; + std::map descType; + std::map descVTable; +}; + +Items::Items(DFContextShared * d_) +{ + d = new Private; + d->d = d_; + d->owner = d_->p; +} +bool Items::Start(){return true;} +bool Items::Finish(){return true;} +Items::~Items() +{ + Finish(); + std::map::iterator it; + it = d->descVTable.begin(); + while (it != d->descVTable.end()) + { + delete (*it).second; + } + d->descType.clear(); + d->descVTable.clear(); + delete d; } bool Items::getItemData(uint32_t itemptr, DFHack::t_item &item) { - std::map::iterator it; - Process * p = d->owner; - ItemDesc * desc; + std::map::iterator it; + Process * p = d->owner; + ItemDesc * desc; - it = this->descVTable.find(itemptr); - if(it==descVTable.end()) - { - uint32_t vtable = p->readDWord(itemptr); - desc = new ItemDesc(vtable, p); - this->descVTable[vtable] = desc; - this->descType[desc->mainType] = desc; - } - else - desc = it->second; + it = d->descVTable.find(itemptr); + if(it==d->descVTable.end()) + { + uint32_t vtable = p->readDWord(itemptr); + desc = new ItemDesc(vtable, p); + d->descVTable[vtable] = desc; + d->descType[desc->mainType] = desc; + } + else + desc = it->second; - return desc->getItem(itemptr, item); + return desc->getItem(itemptr, item); } std::string Items::getItemClass(int32_t index) { - std::map::iterator it; - std::string out; + std::map::iterator it; + std::string out; - it = this->descType.find(index); - if(it==this->descType.end()) - { - /* these are dummy values for mood decoding */ - switch(index) - { - case 0: return "bar"; - case 1: return "cut gem"; - case 2: return "block"; - case 3: return "raw gem"; - case 4: return "raw stone"; - case 5: return "log"; - case 54: return "leather"; - case 57: return "cloth"; - case -1: return "probably bone or shell, but I really don't know"; - default: return "unknown"; - } - } - out = it->second->className; - return out; + it = d->descType.find(index); + if(it==d->descType.end()) + { + /* these are dummy values for mood decoding */ + switch(index) + { + case 0: return "bar"; + case 1: return "cut gem"; + case 2: return "block"; + case 3: return "raw gem"; + case 4: return "raw stone"; + case 5: return "log"; + case 54: return "leather"; + case 57: return "cloth"; + case -1: return "probably bone or shell, but I really don't know"; + default: return "unknown"; + } + } + out = it->second->className; + return out; } std::string Items::getItemDescription(uint32_t itemptr, Materials * Materials) { - DFHack::t_item item; - std::string out; + DFHack::t_item item; + std::string out; - if(!this->getItemData(itemptr, item)) - return "??"; - switch(item.quality) - { - case 0: break; - case 1: out.append("Well crafted "); break; - case 2: out.append("Finely crafted "); break; - case 3: out.append("Superior quality "); break; - case 4: out.append("Exceptionnal "); break; - case 5: out.append("Masterful "); break; - default: out.append("Crazy quality "); break; - } - out.append(Materials->getDescription(item.matdesc)); - out.append(" "); - out.append(this->getItemClass(item.matdesc.itemType)); - return out; + if(!this->getItemData(itemptr, item)) + return "??"; + switch(item.quality) + { + case 0: break; + case 1: out.append("Well crafted "); break; + case 2: out.append("Finely crafted "); break; + case 3: out.append("Superior quality "); break; + case 4: out.append("Exceptionnal "); break; + case 5: out.append("Masterful "); break; + default: out.append("Crazy quality "); break; + } + out.append(Materials->getDescription(item.matdesc)); + out.append(" "); + out.append(this->getItemClass(item.matdesc.itemType)); + return out; } diff --git a/library/modules/Items_C.cpp b/library/modules/Items_C.cpp index 3ac54c46a..b9978f962 100644 --- a/library/modules/Items_C.cpp +++ b/library/modules/Items_C.cpp @@ -22,29 +22,14 @@ must not be misrepresented as being the original software. distribution. */ -#include -#include -#include -#include "dfhack/DFExport.h" -#include "dfhack/DFIntegers.h" -#include "DFHack_C.h" - -#include "dfhack/DFTypes.h" - -using namespace std; -using namespace DFHack; - -#include "dfhack/DFProcess.h" -#include "dfhack/modules/Materials.h" -#include "dfhack/modules/Items.h" -#include "dfhack-c/DFTypes_C.h" #include "dfhack-c/modules/Items_C.h" - #ifdef __cplusplus extern "C" { #endif +//FIXME: beware of bad null-termination! I haven't tested anything here, but it seems that it could be corrupting or truncating strings. + char* Items_getItemDescription(DFHackObject* items, uint32_t itemptr, DFHackObject* mats) { if(items != NULL && mats != NULL) @@ -53,7 +38,8 @@ char* Items_getItemDescription(DFHackObject* items, uint32_t itemptr, DFHackObje if(desc.size() > 0) { - char* buf = (*alloc_char_buffer_callback)(desc.size()); + char* buf; + (*alloc_char_buffer_callback)(buf,desc.size()); if(buf != NULL) { @@ -80,8 +66,8 @@ char* Items_getItemClass(DFHackObject* items, int32_t index) if(iclass.size() > 0) { - char* buf = (*alloc_char_buffer_callback)(iclass.size()); - + char* buf; + (*alloc_char_buffer_callback)(buf, iclass.size()); if(buf != NULL) { size_t len = iclass.copy(buf, iclass.size()); diff --git a/library/modules/Maps.cpp b/library/modules/Maps.cpp index af0a8be9b..0cf3588a1 100644 --- a/library/modules/Maps.cpp +++ b/library/modules/Maps.cpp @@ -37,7 +37,7 @@ distribution. #define SHMCMD(num) ((shm_cmd *)d->d->shm_start)[num]->pingpong #define SHMHDR ((shm_core_hdr *)d->d->shm_start) #define SHMDATA(type) ((type *)(d->d->shm_start + SHM_HEADER)) - +#define MAPS_GUARD if(!d->Started) throw DFHack::Error::ModuleNotInitialized(); using namespace DFHack; struct Maps::Private @@ -49,15 +49,15 @@ struct Maps::Private uint32_t maps_module; Server::Maps::maps_offsets offsets; - + DFContextShared *d; Process * owner; bool Inited; bool Started; - + // map between feature address and the read object map local_feature_store; - + vector v_geology[eBiomeCount]; }; @@ -67,10 +67,10 @@ Maps::Maps(DFContextShared* _d) d->d = _d; Process *p = d->owner = _d->p; d->Inited = d->Started = false; - + DFHack::memory_info * mem = p->getDescriptor(); Server::Maps::maps_offsets &off = d->offsets; - + // get the offsets once here off.map_offset = mem->getAddress ("map_data"); off.x_count_offset = mem->getAddress ("x_count_block"); @@ -83,27 +83,23 @@ Maps::Maps(DFContextShared* _d) off.veinvector = mem->getOffset ("map_data_vein_vector"); off.local_feature_offset = mem->getOffset ("map_data_feature_local"); off.global_feature_offset = mem->getOffset ("map_data_feature_global"); - + off.temperature1_offset = mem->getOffset ("map_data_temperature1_offset"); off.temperature2_offset = mem->getOffset ("map_data_temperature2_offset"); off.region_x_offset = mem->getAddress ("region_x"); off.region_y_offset = mem->getAddress ("region_y"); off.region_z_offset = mem->getAddress ("region_z"); - - + off.world_regions = mem->getAddress ("ptr2_region_array"); off.region_size = mem->getHexValue ("region_size"); off.region_geo_index_offset = mem->getOffset ("region_geo_index_off"); off.geolayer_geoblock_offset = mem->getOffset ("geolayer_geoblock_offset"); off.world_geoblocks_vector = mem->getAddress ("geoblock_vector"); off.type_inside_geolayer = mem->getOffset ("type_inside_geolayer"); - + off.world_size_x = mem->getAddress ("world_size_x"); off.world_size_y = mem->getAddress ("world_size_y"); - - - - + // these can fail and will be found when looking at the actual veins later // basically a cache off.vein_ice_vptr = 0; @@ -129,6 +125,7 @@ Maps::~Maps() { if(d->Started) Finish(); + delete d; } /*-----------------------------------* @@ -140,15 +137,17 @@ bool Maps::Start() return false; if(d->Started) Finish(); + Process *p = d->owner; Server::Maps::maps_offsets &off = d->offsets; + // get the map pointer uint32_t x_array_loc = p->readDWord (off.map_offset); if (!x_array_loc) { return false; } - + // get the size uint32_t mx, my, mz; mx = d->x_block_count = p->readDWord (off.x_count_offset); @@ -193,6 +192,7 @@ bool Maps::Start() // getter for map size void Maps::getSize (uint32_t& x, uint32_t& y, uint32_t& z) { + MAPS_GUARD x = d->x_block_count; y = d->y_block_count; z = d->z_block_count; @@ -216,6 +216,7 @@ bool Maps::Finish() bool Maps::isValidBlock (uint32_t x, uint32_t y, uint32_t z) { + MAPS_GUARD if ( x >= d->x_block_count || y >= d->y_block_count || z >= d->z_block_count) return false; return d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z] != 0; @@ -223,6 +224,7 @@ bool Maps::isValidBlock (uint32_t x, uint32_t y, uint32_t z) uint32_t Maps::getBlockPtr (uint32_t x, uint32_t y, uint32_t z) { + MAPS_GUARD if ( x >= d->x_block_count || y >= d->y_block_count || z >= d->z_block_count) return 0; return d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; @@ -230,6 +232,7 @@ uint32_t Maps::getBlockPtr (uint32_t x, uint32_t y, uint32_t z) bool Maps::ReadBlock40d(uint32_t x, uint32_t y, uint32_t z, mapblock40d * buffer) { + MAPS_GUARD Process *p = d->owner; if(d->d->shm_start && d->maps_module) // ACCELERATE! { @@ -264,10 +267,11 @@ bool Maps::ReadBlock40d(uint32_t x, uint32_t y, uint32_t z, mapblock40d * buffer /* * Tiletypes - */ + */ bool Maps::ReadTileTypes (uint32_t x, uint32_t y, uint32_t z, tiletypes40d *buffer) { + MAPS_GUARD uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if (addr) { @@ -279,6 +283,7 @@ bool Maps::ReadTileTypes (uint32_t x, uint32_t y, uint32_t z, tiletypes40d *buff bool Maps::WriteTileTypes (uint32_t x, uint32_t y, uint32_t z, tiletypes40d *buffer) { + MAPS_GUARD uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if (addr) { @@ -289,11 +294,12 @@ bool Maps::WriteTileTypes (uint32_t x, uint32_t y, uint32_t z, tiletypes40d *buf } /* - * Dirty flags - */ + * Dirty bit + */ bool Maps::ReadDirtyBit(uint32_t x, uint32_t y, uint32_t z, bool &dirtybit) { + MAPS_GUARD uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if(addr) { @@ -307,6 +313,7 @@ bool Maps::ReadDirtyBit(uint32_t x, uint32_t y, uint32_t z, bool &dirtybit) bool Maps::WriteDirtyBit(uint32_t x, uint32_t y, uint32_t z, bool dirtybit) { + MAPS_GUARD uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if (addr) { @@ -321,9 +328,12 @@ bool Maps::WriteDirtyBit(uint32_t x, uint32_t y, uint32_t z, bool dirtybit) return false; } -/// read/write the block flags +/* + * Block flags + */ bool Maps::ReadBlockFlags(uint32_t x, uint32_t y, uint32_t z, t_blockflags &blockflags) { + MAPS_GUARD uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if(addr) { @@ -336,6 +346,7 @@ bool Maps::ReadBlockFlags(uint32_t x, uint32_t y, uint32_t z, t_blockflags &bloc } bool Maps::WriteBlockFlags(uint32_t x, uint32_t y, uint32_t z, t_blockflags blockflags) { + MAPS_GUARD uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if (addr) { @@ -349,10 +360,10 @@ bool Maps::WriteBlockFlags(uint32_t x, uint32_t y, uint32_t z, t_blockflags bloc /* * Designations - */ - + */ bool Maps::ReadDesignations (uint32_t x, uint32_t y, uint32_t z, designations40d *buffer) { + MAPS_GUARD uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if (addr) { @@ -364,6 +375,7 @@ bool Maps::ReadDesignations (uint32_t x, uint32_t y, uint32_t z, designations40d bool Maps::WriteDesignations (uint32_t x, uint32_t y, uint32_t z, designations40d *buffer) { + MAPS_GUARD uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if (addr) { @@ -375,10 +387,10 @@ bool Maps::WriteDesignations (uint32_t x, uint32_t y, uint32_t z, designations40 /* * Occupancies - */ - + */ bool Maps::ReadOccupancy (uint32_t x, uint32_t y, uint32_t z, occupancies40d *buffer) { + MAPS_GUARD uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if (addr) { @@ -390,6 +402,7 @@ bool Maps::ReadOccupancy (uint32_t x, uint32_t y, uint32_t z, occupancies40d *bu bool Maps::WriteOccupancy (uint32_t x, uint32_t y, uint32_t z, occupancies40d *buffer) { + MAPS_GUARD uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if (addr) { @@ -401,9 +414,10 @@ bool Maps::WriteOccupancy (uint32_t x, uint32_t y, uint32_t z, occupancies40d *b /* * Temperatures - */ + */ bool Maps::ReadTemperatures(uint32_t x, uint32_t y, uint32_t z, t_temperatures *temp1, t_temperatures *temp2) { + MAPS_GUARD uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if (addr) { @@ -417,6 +431,7 @@ bool Maps::ReadTemperatures(uint32_t x, uint32_t y, uint32_t z, t_temperatures * } bool Maps::WriteTemperatures (uint32_t x, uint32_t y, uint32_t z, t_temperatures *temp1, t_temperatures *temp2) { + MAPS_GUARD uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if (addr) { @@ -434,6 +449,7 @@ bool Maps::WriteTemperatures (uint32_t x, uint32_t y, uint32_t z, t_temperatures */ bool Maps::ReadRegionOffsets (uint32_t x, uint32_t y, uint32_t z, biome_indices40d *buffer) { + MAPS_GUARD uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if (addr) { @@ -445,6 +461,7 @@ bool Maps::ReadRegionOffsets (uint32_t x, uint32_t y, uint32_t z, biome_indices4 bool Maps::ReadFeatures(uint32_t x, uint32_t y, uint32_t z, int16_t & local, int16_t & global) { + MAPS_GUARD uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if (addr) { @@ -458,6 +475,7 @@ bool Maps::ReadFeatures(uint32_t x, uint32_t y, uint32_t z, int16_t & local, int bool Maps::WriteLocalFeature(uint32_t x, uint32_t y, uint32_t z, int16_t local) { + MAPS_GUARD uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if (addr) { @@ -470,6 +488,7 @@ bool Maps::WriteLocalFeature(uint32_t x, uint32_t y, uint32_t z, int16_t local) bool Maps::WriteGlobalFeature(uint32_t x, uint32_t y, uint32_t z, int16_t global) { + MAPS_GUARD uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if (addr) { @@ -485,6 +504,7 @@ bool Maps::WriteGlobalFeature(uint32_t x, uint32_t y, uint32_t z, int16_t global */ bool Maps::ReadVeins(uint32_t x, uint32_t y, uint32_t z, vector * veins, vector * ices, vector *splatter) { + MAPS_GUARD t_vein v; t_frozenliquidvein fv; t_spattervein sv; @@ -625,6 +645,7 @@ __int16 __userpurge GetGeologicalRegion(__int16 block_X, int X, __i */ bool Maps::ReadGeology (vector < vector >& assign) { + MAPS_GUARD memory_info * minfo = d->d->offset_descriptor; Process *p = d->owner; // get needed addresses and offsets. Now this is what I call crazy. @@ -694,10 +715,11 @@ bool Maps::ReadGeology (vector < vector >& assign) bool Maps::ReadLocalFeatures( std::map > & local_features ) { + MAPS_GUARD // can't be used without a map! if(!d->block) return false; - + Process * p = d->owner; memory_info * mem = p->getDescriptor(); // deref pointer to the humongo-structure @@ -709,32 +731,26 @@ bool Maps::ReadLocalFeatures( std::map > & const uint32_t offset_elem = 4; const uint32_t main_mat_offset = mem->getOffset("local_feature_mat"); // 0x30 const uint32_t sub_mat_offset = mem->getOffset("local_feature_submat"); // 0x34 - + local_features.clear(); - + for(uint32_t blockX = 0; blockX < d->x_block_count; blockX ++) for(uint32_t blockY = 0; blockY < d->x_block_count; blockY ++) { - //uint64_t block48_x = blockX / 3 + d->regionX; - //uint16_t region_x_plus8 = ( block48_x + 8 ) / 16; - - // region X coord offset by 8 big blocks (48x48 tiles) - uint16_t region_x_plus8 = ( (blockX / 3 ) + d->regionX /*+ 8*/ ) / 16; - //((BYTE4(region_x_local) & 0xF) + (_DWORD)region_x_local) >> 4; - //int16_t region_x_local = (blockX / 3) + d->regionX; - //int16_t region_x_plus8 = ((region_x_local & 0xF) + region_x_local) >> 4; - // plain region Y coord + // region X coord (48x48 tiles) + uint16_t region_x_local = ( (blockX / 3) + d->regionX ) / 16; + // region Y coord (48x48 tiles) uint64_t region_y_local = ( (blockY / 3) + d->regionY ) / 16; - + // this is just a few pointers to arrays of 16B (4 DWORD) structs - uint32_t array_elem = p->readDWord(base + (region_x_plus8 / 16) * 4); - + uint32_t array_elem = p->readDWord(base + (region_x_local / 16) * 4); + // 16B structs, second DWORD of the struct is a pointer uint32_t wtf = p->readDWord(array_elem + ( sizeof_elem * ( (uint32_t)region_y_local/16)) + offset_elem); if(wtf) { // wtf + sizeof(vector) * crap; - uint32_t feat_vector = wtf + sizeof_vec * (16 * (region_x_plus8 % 16) + (region_y_local % 16)); + uint32_t feat_vector = wtf + sizeof_vec * (16 * (region_x_local % 16) + (region_y_local % 16)); DfVector p_features(p, feat_vector); uint32_t size = p_features.size(); planecoord pc; @@ -744,7 +760,7 @@ bool Maps::ReadLocalFeatures( std::map > & for(uint32_t i = 0; i < size; i++) { uint32_t cur_ptr = p_features[i]; - + map ::iterator it; it = d->local_feature_store.find(cur_ptr); // do we already have the feature? @@ -792,19 +808,20 @@ bool Maps::ReadLocalFeatures( std::map > & bool Maps::ReadGlobalFeatures( std::vector & features) { + MAPS_GUARD // can't be used without a map! if(!d->block) return false; - + Process * p = d->owner; memory_info * mem = p->getDescriptor(); - + uint32_t global_feature_vector = mem->getAddress("global_feature_vector"); uint32_t global_feature_funcptr = mem->getOffset("global_feature_funcptr_"); const uint32_t main_mat_offset = mem->getOffset("global_feature_mat"); // 0x34 const uint32_t sub_mat_offset = mem->getOffset("global_feature_submat"); // 0x38 DfVector p_features (p,global_feature_vector); - + features.clear(); uint32_t size = p_features.size(); features.reserve(size); @@ -815,7 +832,7 @@ bool Maps::ReadGlobalFeatures( std::vector & features) temp.origin = feat_ptr; //temp.discovered = p->readDWord( feat_ptr + 4 ); // maybe, placeholder temp.discovered = false; - + // FIXME: use the memory_info cache mechanisms string name = p->readClassName(p->readDWord( feat_ptr)); if(name == "feature_init_underworld_from_layerst") diff --git a/library/modules/Maps_C.cpp b/library/modules/Maps_C.cpp index ccac26447..09a7dc065 100644 --- a/library/modules/Maps_C.cpp +++ b/library/modules/Maps_C.cpp @@ -22,20 +22,14 @@ must not be misrepresented as being the original software. distribution. */ -#include "dfhack/DFIntegers.h" #include -#include -#include +#include using namespace std; -#include "Internal.h" -#include "dfhack/DFTypes.h" -#include "dfhack/modules/Maps.h" +#include "dfhack-c/DFTypes_C.h" #include "dfhack-c/modules/Maps_C.h" -using namespace DFHack; - #ifdef __cplusplus extern "C" { #endif @@ -280,6 +274,98 @@ int Maps_ReadRegionOffsets(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t return -1; } +t_vein* Maps_ReadStandardVeins(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z) +{ + if(maps != NULL) + { + if(alloc_vein_buffer_callback == NULL) + return NULL; + + vector veins; + bool result = ((DFHack::Maps*)maps)->ReadVeins(x, y, z, &veins); + + if(result) + { + t_vein* v_buf = NULL; + + if(veins.size() > 0) + { + ((*alloc_vein_buffer_callback)(v_buf, veins.size())); + + copy(veins.begin(), veins.end(), v_buf); + } + + return v_buf; + } + else + return NULL; + } + + return NULL; +} + +t_frozenliquidvein* Maps_ReadFrozenVeins(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z) +{ + if(maps != NULL) + { + if(alloc_frozenliquidvein_buffer_callback == NULL) + return NULL; + + vector veins; + vector frozen_veins; + bool result = ((DFHack::Maps*)maps)->ReadVeins(x, y, z, &veins, &frozen_veins); + + if(result) + { + t_frozenliquidvein* fv_buf = NULL; + + if(frozen_veins.size() > 0) + { + ((*alloc_frozenliquidvein_buffer_callback)(fv_buf, frozen_veins.size())); + + copy(frozen_veins.begin(), frozen_veins.end(), fv_buf); + } + + return fv_buf; + } + else + return NULL; + } + + return NULL; +} + +t_spattervein* Maps_ReadSpatterVeins(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z) +{ + if(maps != NULL) + { + if(alloc_spattervein_buffer_callback == NULL) + return NULL; + + vector veins; + vector spatter_veins; + bool result = ((DFHack::Maps*)maps)->ReadVeins(x, y, z, &veins, 0, &spatter_veins); + + if(result) + { + t_spattervein* sv_buf = NULL; + + if(spatter_veins.size() > 0) + { + ((*alloc_spattervein_buffer_callback)(sv_buf, spatter_veins.size())); + + copy(spatter_veins.begin(), spatter_veins.end(), sv_buf); + } + + return sv_buf; + } + else + return NULL; + } + + return NULL; +} + #ifdef __cplusplus } #endif diff --git a/library/modules/Materials.cpp b/library/modules/Materials.cpp index 3567bb0d0..fe8e3f339 100644 --- a/library/modules/Materials.cpp +++ b/library/modules/Materials.cpp @@ -53,6 +53,21 @@ Materials::~Materials() { delete d; } + +bool Materials::Finish() +{ + inorganic.clear(); + organic.clear(); + tree.clear(); + plant.clear(); + race.clear(); + raceEx.clear(); + color.clear(); + other.clear(); + alldesc.clear(); + return true; +} + /* { LABEL_53: @@ -243,24 +258,24 @@ bool Materials::ReadCreatureTypes (void) bool Materials::ReadOthers(void) { - Process * p = d->owner; - uint32_t matBase = p->getDescriptor()->getAddress ("mat_other"); - uint32_t i = 0; - uint32_t ptr; + Process * p = d->owner; + uint32_t matBase = p->getDescriptor()->getAddress ("mat_other"); + uint32_t i = 0; + uint32_t ptr; - other.clear(); + other.clear(); - while(1) - { - t_matglossOther mat; - ptr = p->readDWord(matBase + i*4); - if(ptr==0) - break; - p->readSTLString(ptr, mat.rawname, sizeof(mat.rawname)); - other.push_back(mat); - i++; - } - return true; + while(1) + { + t_matglossOther mat; + ptr = p->readDWord(matBase + i*4); + if(ptr==0) + break; + p->readSTLString(ptr, mat.rawname, sizeof(mat.rawname)); + other.push_back(mat); + i++; + } + return true; } bool Materials::ReadDescriptorColors (void) @@ -301,8 +316,8 @@ bool Materials::ReadCreatureTypesEx (void) uint32_t bodypart_id_offset = mem->getOffset ("bodypart_id"); uint32_t bodypart_category_offset = mem->getOffset ("bodypart_category"); uint32_t bodypart_layers_offset = mem->getOffset ("bodypart_layers_vector"); - uint32_t bodypart_singular_offset = mem->getOffset ("bodypart_singular_vector"); - uint32_t bodypart_plural_offset = mem->getOffset ("bodypart_plural_vector"); + uint32_t bodypart_singular_offset = mem->getOffset ("bodypart_singular_vector"); // unused + uint32_t bodypart_plural_offset = mem->getOffset ("bodypart_plural_vector"); // unused uint32_t color_modifier_part_offset = mem->getOffset ("color_modifier_part"); uint32_t color_modifier_startdate_offset = mem->getOffset ("color_modifier_startdate"); uint32_t color_modifier_enddate_offset = mem->getOffset ("color_modifier_enddate"); @@ -318,7 +333,18 @@ bool Materials::ReadCreatureTypesEx (void) for (uint32_t i = 0; i < size;i++) { t_creaturetype mat; + // FROM race READ + // std::string rawname AT 0, + // char tile_character AT tile_offset, + // word tilecolor.fore : tile_color_offset, + // word tilecolor.back : tile_color_offset + 2, + // word tilecolor.bright : tile_color_offset + 4 p->readSTLString (p_races[i], mat.rawname, sizeof(mat.rawname)); + mat.tile_character = p->readByte( p_races[i] + tile_offset ); + mat.tilecolor.fore = p->readWord( p_races[i] + tile_color_offset ); + mat.tilecolor.back = p->readWord( p_races[i] + tile_color_offset + 2 ); + mat.tilecolor.bright = p->readWord( p_races[i] + tile_color_offset + 4 ); + DfVector p_castes(p, p_races[i] + castes_vector_offset); sizecas = p_castes.size(); for (uint32_t j = 0; j < sizecas;j++) @@ -364,11 +390,6 @@ bool Materials::ReadCreatureTypesEx (void) mat.castes.push_back(caste); } - mat.tile_character = p->readByte( p_races[i] + tile_offset ); - mat.tilecolor.fore = p->readWord( p_races[i] + tile_color_offset ); - mat.tilecolor.back = p->readWord( p_races[i] + tile_color_offset + 2 ); - mat.tilecolor.bright = p->readWord( p_races[i] + tile_color_offset + 4 ); - DfVector p_extract(p, p_races[i] + extract_vector_offset); for(uint32_t j = 0; j < p_extract.size(); j++) { @@ -395,10 +416,10 @@ void Materials::ReadAllMaterials(void) std::string Materials::getDescription(t_material & mat) { - std::string out; - int32_t typeC; + std::string out; + int32_t typeC; - if ( (mat.subIndex<419) || (mat.subIndex>618) ) + if ( (mat.subIndex<419) || (mat.subIndex>618) ) { if ( (mat.subIndex<19) || (mat.subIndex>218) ) { @@ -408,13 +429,13 @@ std::string Materials::getDescription(t_material & mat) else { if (mat.subIndex>=this->other.size()) - { - if(mat.subIndex<0) - return "any"; - if(mat.subIndex>=this->raceEx.size()) - return "stuff"; - return this->raceEx[mat.subIndex].rawname; - } + { + if(mat.subIndex<0) + return "any"; + if(mat.subIndex>=this->raceEx.size()) + return "stuff"; + return this->raceEx[mat.subIndex].rawname; + } else { if (mat.index==-1) @@ -424,17 +445,17 @@ std::string Materials::getDescription(t_material & mat) } } else - if(mat.index<0) - return "any inorganic"; - else - return this->inorganic[mat.index].id; + if(mat.index<0) + return "any inorganic"; + else + return this->inorganic[mat.index].id; } else { if (mat.index>=this->raceEx.size()) return "unknown race"; typeC = mat.subIndex; - typeC -=19; + typeC -=19; if ((typeC<0) || (typeC>=this->raceEx[mat.index].extract.size())) { return string(this->raceEx[mat.index].rawname).append(" extract"); @@ -446,6 +467,56 @@ std::string Materials::getDescription(t_material & mat) { return this->organic[mat.index].id; } - return out; + return out; } +//type of material only so we know which vector to retrieve +std::string Materials::getType(t_material & mat) +{ + if((mat.subIndex<419) || (mat.subIndex>618)) + { + if((mat.subIndex<19) || (mat.subIndex>218)) + { + if(mat.subIndex) + { + if(mat.subIndex>0x292) + { + return "unknown"; + } + else + { + if(mat.subIndex>=this->other.size()) + { + if(mat.subIndex<0) + return "any"; + + if(mat.subIndex>=this->raceEx.size()) + return "unknown"; + + return "racex"; + } + else + { + if (mat.index==-1) + return "other"; + else + return "other derivate"; + } + } + } + else + return "inorganic"; + } + else + { + if (mat.index>=this->raceEx.size()) + return "unknown"; + + return "racex extract"; + } + } + else + { + return "organic"; + } +} \ No newline at end of file diff --git a/library/modules/Materials_C.cpp b/library/modules/Materials_C.cpp index dee99fbaa..1d70f8716 100644 --- a/library/modules/Materials_C.cpp +++ b/library/modules/Materials_C.cpp @@ -22,21 +22,8 @@ must not be misrepresented as being the original software. distribution. */ -#include "dfhack/DFIntegers.h" -#include -#include -#include - -using namespace std; - -#include "Internal.h" -#include "dfhack/DFTypes.h" -#include "dfhack/modules/Materials.h" -#include "dfhack-c/DFTypes_C.h" #include "dfhack-c/modules/Materials_C.h" -using namespace DFHack; - #ifdef __cplusplus extern "C" { #endif @@ -233,7 +220,9 @@ t_matgloss* Materials_getInorganic(DFHackObject* mat) if(materials->inorganic.size() > 0) { - t_matgloss* buf = ((*alloc_matgloss_buffer_callback)(materials->inorganic.size())); + t_matgloss* buf; + + ((*alloc_matgloss_buffer_callback)(buf, materials->inorganic.size())); if(buf != NULL) { @@ -255,7 +244,9 @@ t_matgloss* Materials_getOrganic(DFHackObject* mat) if(materials->organic.size() > 0) { - t_matgloss* buf = ((*alloc_matgloss_buffer_callback)(materials->organic.size())); + t_matgloss* buf; + + ((*alloc_matgloss_buffer_callback)(buf, materials->organic.size())); if(buf != NULL) { @@ -277,7 +268,9 @@ t_matgloss* Materials_getTree(DFHackObject* mat) if(materials->tree.size() > 0) { - t_matgloss* buf = ((*alloc_matgloss_buffer_callback)(materials->tree.size())); + t_matgloss* buf; + + ((*alloc_matgloss_buffer_callback)(buf, materials->tree.size())); if(buf != NULL) { @@ -299,7 +292,9 @@ t_matgloss* Materials_getPlant(DFHackObject* mat) if(materials->plant.size() > 0) { - t_matgloss* buf = ((*alloc_matgloss_buffer_callback)(materials->plant.size())); + t_matgloss* buf; + + ((*alloc_matgloss_buffer_callback)(buf, materials->plant.size())); if(buf != NULL) { @@ -321,7 +316,9 @@ t_matgloss* Materials_getRace(DFHackObject* mat) if(materials->race.size() > 0) { - t_matgloss* buf = ((*alloc_matgloss_buffer_callback)(materials->race.size())); + t_matgloss* buf; + + ((*alloc_matgloss_buffer_callback)(buf, materials->race.size())); if(buf != NULL) { @@ -345,7 +342,9 @@ c_creaturetype* Materials_getRaceEx(DFHackObject* mat) if(matSize > 0) { - c_creaturetype* buf = ((*alloc_creaturetype_buffer_callback)(matSize)); + c_creaturetype* buf; + + ((*alloc_creaturetype_buffer_callback)(buf, matSize)); if(buf != NULL) { @@ -368,7 +367,9 @@ t_descriptor_color* Materials_getColor(DFHackObject* mat) if(materials->color.size() > 0) { - t_descriptor_color* buf = ((*alloc_descriptor_buffer_callback)(materials->color.size())); + t_descriptor_color* buf; + + ((*alloc_descriptor_buffer_callback)(buf, materials->color.size())); if(buf != NULL) { @@ -390,7 +391,9 @@ t_matglossOther* Materials_getOther(DFHackObject* mat) if(materials->other.size() > 0) { - t_matglossOther* buf = ((*alloc_matgloss_other_buffer_callback)(materials->other.size())); + t_matglossOther* buf; + + ((*alloc_matgloss_other_buffer_callback)(buf, materials->other.size())); if(buf != NULL) { diff --git a/library/modules/Position.cpp b/library/modules/Position.cpp index 0d3ae1819..ab3fccba3 100644 --- a/library/modules/Position.cpp +++ b/library/modules/Position.cpp @@ -41,12 +41,15 @@ struct Position::Private uint32_t hotkey_mode_offset; uint32_t hotkey_xyz_offset; uint32_t hotkey_size; + + uint32_t screen_tiles_ptr_offset; DFContextShared *d; Process * owner; bool Inited; bool Started; bool StartedHotkeys; + bool StartedScreen; }; Position::Position(DFContextShared * d_) @@ -55,7 +58,7 @@ Position::Position(DFContextShared * d_) d->d = d_; d->owner = d_->p; d->Inited = true; - d->StartedHotkeys = d->Started = false; + d->StartedHotkeys = d->Started = d->StartedScreen = false; memory_info * mem; try { @@ -66,7 +69,10 @@ Position::Position(DFContextShared * d_) d->cursor_xyz_offset = mem->getAddress ("cursor_xyz"); d->window_dims_offset = mem->getAddress ("window_dims"); d->Started = true; - + } + catch(exception &){}; + try + { d->hotkey_start = mem->getAddress("hotkey_start"); d->hotkey_mode_offset = mem->getOffset ("hotkey_mode"); d->hotkey_xyz_offset = mem->getOffset("hotkey_xyz"); @@ -74,6 +80,12 @@ Position::Position(DFContextShared * d_) d->StartedHotkeys = true; } catch(exception &){}; + try + { + d->screen_tiles_ptr_offset = mem->getAddress ("screen_tiles_pointer"); + d->StartedScreen = true; + } + catch(exception &){}; } Position::~Position() @@ -158,3 +170,33 @@ bool Position::getWindowSize (int32_t &width, int32_t &height) return true; } + +bool Position::getScreenTiles (int32_t width, int32_t height, t_screen screen[]) +{ + if(!d->Inited) return false; + if(!d->StartedScreen) return false; + + uint32_t screen_addr; + d->owner->read (d->screen_tiles_ptr_offset, sizeof(uint32_t), (uint8_t *) screen_addr); + + uint8_t* tiles = new uint8_t[width*height*4/* + 80 + width*height*4*/]; + + d->owner->read (screen_addr, (width*height*4/* + 80 + width*height*4*/), (uint8_t *) tiles); + + for(int32_t iy=0; iy -#include #include "dfhack-c/modules/Position_C.h" -#include "dfhack/DFIntegers.h" - -#include "Internal.h" -#include "dfhack/modules/Position.h" - -using namespace DFHack; #ifdef __cplusplus extern "C" { diff --git a/library/modules/Translation.cpp b/library/modules/Translation.cpp index 80412c690..ae0c8b7ed 100644 --- a/library/modules/Translation.cpp +++ b/library/modules/Translation.cpp @@ -72,6 +72,7 @@ bool Translation::Start() if(!d->Inited) return false; Process * p = d->d->p; + Finish(); DfVector genericVec (p, d->genericAddress); DfVector transVec (p, d->transAddress); DFDict & translations = d->dicts.translations; @@ -92,7 +93,6 @@ bool Translation::Start() for (uint32_t i = 0; i < transVec.size();i++) { uint32_t transPtr = transVec.at(i); - DfVector trans_names_vec (p, transPtr + d->word_table_offset); for (uint32_t j = 0;j < trans_names_vec.size();j++) { diff --git a/library/modules/WindowIO_C.cpp b/library/modules/WindowIO_C.cpp new file mode 100644 index 000000000..31c6e4739 --- /dev/null +++ b/library/modules/WindowIO_C.cpp @@ -0,0 +1,67 @@ +/* +www.sourceforge.net/projects/dfhack +Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild + +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 +#include +#include +using namespace std; + +#include "dfhack/DFIntegers.h" +#include "DFHack.h" +#include "DFHack_C.h" +#include "dfhack/modules/WindowIO.h" +#include "dfhack-c/modules/WindowIO_C.h" + +using namespace DFHack; + + +#ifdef __cplusplus +extern "C" { +#endif + +int WindowIO_TypeStr(DFHackObject* window, const char* input, int delay, bool useShift) +{ + if(window != NULL) + { + ((DFHack::WindowIO*)window)->TypeStr(input, delay, useShift); + return 1; + } + + return -1; +} + +int WindowIO_TypeSpecial(DFHackObject* window, t_special command, int count, int delay) +{ + if(window != NULL) + { + ((DFHack::WindowIO*)window)->TypeSpecial(command, count, delay); + return 1; + } + + return -1; +} + +#ifdef __cplusplus +} +#endif diff --git a/library/modules/World.cpp b/library/modules/World.cpp index 47f4d200d..92c8606d4 100644 --- a/library/modules/World.cpp +++ b/library/modules/World.cpp @@ -95,12 +95,22 @@ uint32_t World::ReadCurrentTick() return 0; } +// FIX'D according to this: +/* +World::ReadCurrentMonth and World::ReadCurrentDay +« Sent to: peterix on: June 04, 2010, 04:44:30 » +« You have forwarded or responded to this message. » +ReplyQuoteRemove +Shouldn't these be /28 and %28 instead of 24? There're 28 days in a DF month. +Using 28 and doing the calculation on the value stored at the memory location +specified by memory.xml gets me the current month/date. +*/ uint32_t World::ReadCurrentMonth() { - return this->ReadCurrentTick() / 1200 / 24; + return this->ReadCurrentTick() / 1200 / 28; } uint32_t World::ReadCurrentDay() { - return ((this->ReadCurrentTick() / 1200) % 24) + 1; + return ((this->ReadCurrentTick() / 1200) % 28) + 1; } diff --git a/library/modules/World_C.cpp b/library/modules/World_C.cpp new file mode 100644 index 000000000..a5be3bcd0 --- /dev/null +++ b/library/modules/World_C.cpp @@ -0,0 +1,105 @@ +/* +www.sourceforge.net/projects/dfhack +Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild + +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 "DFHack_C.h" +#include "dfhack/modules/World.h" +#include "dfhack-c/modules/World_C.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int World_Start(DFHackObject* world) +{ + if(world != NULL) + { + if(((DFHack::World*)world)->Start()) + return 1; + else + return 0; + } + + return -1; +} + +int World_Finish(DFHackObject* world) +{ + if(world != NULL) + { + if(((DFHack::World*)world)->Finish()) + return 1; + else + return 0; + } + + return -1; +} + +int World_ReadCurrentTick(DFHackObject* world, uint32_t* tick) +{ + if(world != NULL) + { + *tick = ((DFHack::World*)world)->ReadCurrentTick(); + return 1; + } + + return -1; +} + +int World_ReadCurrentYear(DFHackObject* world, uint32_t* year) +{ + if(world != NULL) + { + *year = ((DFHack::World*)world)->ReadCurrentYear(); + return 1; + } + + return -1; +} + +int World_ReadCurrentMonth(DFHackObject* world, uint32_t* month) +{ + if(world != NULL) + { + *month = ((DFHack::World*)world)->ReadCurrentMonth(); + return 1; + } + + return -1; +} + +int World_ReadCurrentDay(DFHackObject* world, uint32_t* day) +{ + if(world != NULL) + { + *day = ((DFHack::World*)world)->ReadCurrentDay(); + return 1; + } + + return -1; +} + +#ifdef __cplusplus +} +#endif diff --git a/library/private/ContextShared.h b/library/private/ContextShared.h index f3c506880..361ccc45d 100644 --- a/library/private/ContextShared.h +++ b/library/private/ContextShared.h @@ -31,20 +31,23 @@ distribution. namespace DFHack { - class Materials; + class Module; + + class Creatures; + class Maps; + class Position; class Gui; class World; - class Position; - class Maps; - class Creatures; + class Materials; class Items; class Translation; + class Vegetation; class Buildings; + class Constructions; + class WindowIO; + class ProcessEnumerator; class Process; - class WindowIO; - class Vegetation; - class Constructions; class memory_info; struct t_name; class DFContextShared @@ -52,7 +55,7 @@ namespace DFHack public: DFContextShared(); ~DFContextShared(); - + // names, used by a few other modules. void readName(t_name & name, uint32_t address); // get the name offsets @@ -61,27 +64,30 @@ namespace DFHack uint32_t name_nickname_offset; uint32_t name_words_offset; bool namesInited; - + ProcessEnumerator* pm; Process* p; char * shm_start; memory_info* offset_descriptor; string xml; - - // Modules - Creatures * creatures; - Maps * maps; - Position * position; - Gui * gui; - World * world; - Materials * materials; - Items * items; - Translation * translation; - Vegetation * vegetation; - Buildings * buildings; - Constructions * constructions; - WindowIO * windowio; + // Modules + struct + { + Creatures * pCreatures; + Maps * pMaps; + Position * pPosition; + Gui * pGui; + World * pWorld; + Materials * pMaterials; + Items * pItems; + Translation * pTranslation; + Vegetation * pVegetation; + Buildings * pBuildings; + Constructions * pConstructions; + WindowIO * pWindowIO; + } s_mods; + std::vector allModules; /* uint32_t item_material_offset; @@ -93,7 +99,7 @@ namespace DFHack uint32_t settlement_name_offset; uint32_t settlement_world_xy_offset; uint32_t settlement_local_xy_offset; - + uint32_t dwarf_lang_table_offset; DfVector *p_effect; diff --git a/library/include/dfhack/DFMemInfoManager.h b/library/private/DFMemInfoManager.h similarity index 95% rename from library/include/dfhack/DFMemInfoManager.h rename to library/private/DFMemInfoManager.h index 99c34afe1..60563d228 100644 --- a/library/include/dfhack/DFMemInfoManager.h +++ b/library/private/DFMemInfoManager.h @@ -25,10 +25,12 @@ distribution. #ifndef MEMINFO_MANAGER_H_INCLUDED #define MEMINFO_MANAGER_H_INCLUDED -#include "DFPragma.h" +#include "dfhack/DFPragma.h" +class TiXmlElement; namespace DFHack { + class memory_info; class MemInfoManager { friend class ProcessEnumerator; @@ -38,8 +40,8 @@ namespace DFHack // memory info entries loaded from a file bool loadFile( string path_to_xml); bool isInErrorState() const {return error;}; - private: std::vector meminfo; + private: void ParseVTable(TiXmlElement* vtable, memory_info* mem); void ParseEntry (TiXmlElement* entry, memory_info* mem, map & knownEntries); bool error; diff --git a/library/python/c api/gui.py b/library/python/c api/gui.py deleted file mode 100644 index 09a7c5c94..000000000 --- a/library/python/c api/gui.py +++ /dev/null @@ -1,25 +0,0 @@ -from ctypes import * -from pydfhack import libdfhack, ViewScreen - -libdfhack.Gui_ReadViewScreen.argtypes = [ c_void_p, c_void_p ] - -class Gui(object): - def __init__(self, ptr): - self._gui_ptr = ptr - - def start(self): - return libdfhack.Gui_Start(self._gui_ptr) - - def finish(self): - return libdfhack.Gui_Finish(self._gui_ptr) - - def read_pause_state(self): - return libdfhack.Gui_ReadPauseState(self._pos_ptr) > 0 - - def read_view_screen(self): - s = ViewScreen() - - if libdfhack.Gui_ReadViewScreen(self._gui_ptr, byref(s)) > 0: - return s - else: - return None diff --git a/library/python/c api/materials.py b/library/python/c api/materials.py deleted file mode 100644 index 04d82fddb..000000000 --- a/library/python/c api/materials.py +++ /dev/null @@ -1,141 +0,0 @@ -from ctypes import * -from pydftypes import libdfhack -from util import * - -_get_arg_types = [ c_void_p, _arr_create_func ] - -libdfhack.Materials_getInorganic.argtypes = _get_arg_types -libdfhack.Materials_getOrganic.argtypes = _get_arg_types -libdfhack.Materials_getTree.argtypes = _get_arg_types -libdfhack.Materials_getPlant.argtypes = _get_arg_types -libdfhack.Materials_getRace.argtypes = _get_arg_types -#libdfhack.Materials_getRaceEx.argtypes = _get_arg_types -libdfhack.Materials_getColor.argtypes = _get_arg_types -libdfhack.Materials_getOther.argtypes = _get_arg_types - -class Materials(object): - def __init__(self, ptr): - self._mat_ptr = ptr - - self.inorganic = None - self.organic = None - self.tree = None - self.plant = None - self.race = None - self.race_ex = None - self.color = None - self.other = None - - def read_inorganic(self): - return libdfhack.Materials_ReadInorganicMaterials(self._mat_ptr) - - def read_organic(self): - return libdfhack.Materials_ReadOrganicMaterials(self._mat_ptr) - - def read_wood(self): - return libdfhack.Materials_ReadWoodMaterials(self._mat_ptr) - - def read_plant(self): - return libdfhack.Materials_ReadPlantMaterials(self._mat_ptr) - - def read_creature_types(self): - return libdfhack.Materials_ReadCreatureTypes(self._mat_ptr) - - def read_creature_types_ex(self): - return libdfhack.Materials_ReadCreatureTypesEx(self._mat_ptr) - - def read_descriptor_colors(self): - return libdfhack.Materials_ReadDescriptorColors(self._mat_ptr) - - def read_others(self): - return libdfhack.Materials_ReadOthers(self._mat_ptr) - - def read_all(self): - libdfhack.Materials_ReadAllMaterials(self._mat_ptr) - - def get_description(self, material): - return libdfhack.Materials_getDescription(self._mat_ptr, byref(material)) - - def update_inorganic_cache(self): - def update_callback(count): - allocated = _allocate_array(Matgloss, count) - - self.inorganic = allocated[0] - - return allocated[1] - - callback = _arr_create_func(update_callback) - - return libdfhack.Materials_getInorganic(self._mat_ptr, callback) - - def update_organic_cache(self): - def update_callback(count): - allocated = _allocate_array(Matgloss, count) - - self.organic = allocated[0] - - return allocated[1] - - callback = _arr_create_func(update_callback) - - return libdfhack.Materials_getOrganic(self._mat_ptr, callback) - - def update_tree_cache(self): - def update_callback(count): - allocated = _allocate_array(Matgloss, count) - - self.tree = allocated[0] - - return allocated[1] - - callback = _arr_create_func(update_callback) - - return libdfhack.Materials_getTree(self._mat_ptr, callback) - - def update_plant_cache(self): - def update_callback(count): - allocated = _allocate_array(Matgloss, count) - - self.plant = allocated[0] - - return allocated[1] - - callback = _arr_create_func(update_callback) - - return libdfhack.Materials_getPlant(self._mat_ptr, callback) - - def update_race_cache(self): - def update_callback(count): - allocated = _allocate_array(Matgloss, count) - - self.race = allocated[0] - - return allocated[1] - - callback = _arr_create_func(update_callback) - - return libdfhack.Materials_getRace(self._mat_ptr, callback) - - def update_color_cache(self): - def update_callback(count): - allocated = _allocate_array(DescriptorColor, count) - - self.color = allocated[0] - - return allocated[1] - - callback = _arr_create_func(update_callback) - - return libdfhack.Materials_getColor(self._mat_ptr, callback) - - def update_other_cache(self): - def update_callback(count): - allocated = _allocate_array(MatglossOther, count) - - self.other = allocated[0] - - return allocated[1] - - callback = _arr_create_func(update_callback) - - return libdfhack.Materials_getOther(self._mat_ptr, callback) diff --git a/library/python/c api/position.py b/library/python/c api/position.py deleted file mode 100644 index ffa758150..000000000 --- a/library/python/c api/position.py +++ /dev/null @@ -1,43 +0,0 @@ -from ctypes import * -from pydftypes import libdfhack - -class Position(object): - def __init__(self, ptr): - self._pos_ptr = ptr - - self._vx, self._vy, self._vz = c_int(), c_int(), c_int() - self._cx, self._cy, self._cz = c_int(), c_int(), c_int() - self._ww, self._wh = c_int(), c_int() - - def get_view_coords(self): - if libdfhack.Position_getViewCoords(self._pos_ptr, byref(self._vx), byref(self._vy), byref(self._vz)) > 0: - return (self._vx.value, self._vy.value, self._vz.value) - else: - return (-1, -1, -1) - - def set_view_coords(self, v_coords): - self._vx.value, self._vy.value, self._vz.value = v_coords - - libdfhack.Position_setViewCoords(self._pos_ptr, self._vx, self._vy, self._vz) - - view_coords = property(get_view_coords, set_view_coords) - - def get_cursor_coords(self): - if libdfhack.Position_getCursorCoords(self._pos_ptr, byref(self._cx), byref(self._cy), byref(self._cz)) > 0: - return (self._cx.value, self._cy.value, self._cz.value) - else: - return (-1, -1, -1) - - def set_cursor_coords(self, c_coords): - self._cx.value, self._cy.value, self_cz.value = c_coords - - libdfhack.Position_setCursorCoords(self._pos_ptr, self._cx, self._cy, self._cz) - - cursor_coords = property(get_cursor_coords, set_cursor_coords) - - @property - def window_size(self): - if libdfhack.Position_getWindowSize(self._pos_ptr, byref(self._ww), byref(self._wh)) > 0: - return (self._ww.value, self._wh.value) - else: - return (-1, -1) diff --git a/library/python/c api/util.py b/library/python/c api/util.py deleted file mode 100644 index 4f3f06958..000000000 --- a/library/python/c api/util.py +++ /dev/null @@ -1,66 +0,0 @@ -from ctypes import * - -def _uintify(x, y, z): - return (c_uint(x), c_uint(y), c_uint(z)) - -def _allocate_array(t_type, count): - arr_type = t_type * count - - arr = arr_type() - - ptr = c_void_p() - ptr = addressof(arr) - - return (arr, ptr) - -def _alloc_int_buffer(count): - a = _allocate_array(c_int, count) - - return a[1] - -alloc_int_buffer = CFUNCTYPE(POINTER(c_int), c_uint)(_alloc_int_buffer) - -def _alloc_uint_buffer(count): - a = _allocate_array(c_uint, count) - - return a[1] - -alloc_uint_buffer = CFUNCTYPE(POINTER(c_uint), c_uint)(_alloc_uint_buffer) - -def _alloc_short_buffer(count): - a = _allocate_array(c_short, count) - - return a[1] - -alloc_short_buffer = CFUNCTYPE(POINTER(c_short), c_uint)(_alloc_short_buffer) - -def _alloc_ushort_buffer(count): - a = _allocate_array(c_ushort, count) - - return a[1] - -alloc_ushort_buffer = CFUNCTYPE(POINTER(c_ushort), c_uint)(_alloc_ushort_buffer) - -def _alloc_byte_buffer(count): - a = _allocate_array(c_byte, count) - - return a[1] - -alloc_byte_buffer = CFUNCTYPE(POINTER(c_byte), c_uint)(_alloc_byte_buffer) - -def _alloc_ubyte_buffer(count): - a = _allocate_array(c_ubyte, count) - - return a[1] - -alloc_ubyte_buffer = CFUNCTYPE(POINTER(c_ubyte), c_uint)(_alloc_ubyte_buffer) - -def _alloc_char_buffer(count): - c = create_string_buffer(count) - - ptr = c_void_p() - ptr = addressof(c) - - return ptr - -alloc_char_buffer = CFUNCTYPE(POINTER(c_char), c_uint)(_alloc_char_buffer) diff --git a/library/python/c api/vegetation.py b/library/python/c api/vegetation.py deleted file mode 100644 index 0c22d26b5..000000000 --- a/library/python/c api/vegetation.py +++ /dev/null @@ -1,25 +0,0 @@ -from ctypes import * -from pydftypes import libdfhack, Tree - -class Vegetation(object): - def __init__(self, ptr): - self._v_ptr = ptr - - def start(self): - n = c_uint(0) - - if libdfhack.Vegetation_Start(self._v_ptr, byref(n)) > 0: - return int(n.value) - else: - return -1 - - def finish(self): - return libdfhack.Vegetation_Finish(self._v_ptr) > 0 - - def read(self, index): - t = Tree() - - if libdfhack.Vegetation_Read(self._v_ptr, c_uint(index), byref(t)) > 0: - return t - else: - return None diff --git a/library/python/CMakeLists.txt b/library/python/deprecated/CMakeLists.txt similarity index 100% rename from library/python/CMakeLists.txt rename to library/python/deprecated/CMakeLists.txt diff --git a/library/python/DF_API.cpp b/library/python/deprecated/DF_API.cpp similarity index 100% rename from library/python/DF_API.cpp rename to library/python/deprecated/DF_API.cpp diff --git a/library/python/DF_Buildings.cpp b/library/python/deprecated/DF_Buildings.cpp similarity index 100% rename from library/python/DF_Buildings.cpp rename to library/python/deprecated/DF_Buildings.cpp diff --git a/library/python/DF_Constructions.cpp b/library/python/deprecated/DF_Constructions.cpp similarity index 100% rename from library/python/DF_Constructions.cpp rename to library/python/deprecated/DF_Constructions.cpp diff --git a/library/python/DF_CreatureManager.cpp b/library/python/deprecated/DF_CreatureManager.cpp similarity index 100% rename from library/python/DF_CreatureManager.cpp rename to library/python/deprecated/DF_CreatureManager.cpp diff --git a/library/python/DF_CreatureType.cpp b/library/python/deprecated/DF_CreatureType.cpp similarity index 100% rename from library/python/DF_CreatureType.cpp rename to library/python/deprecated/DF_CreatureType.cpp diff --git a/library/python/DF_GUI.cpp b/library/python/deprecated/DF_GUI.cpp similarity index 100% rename from library/python/DF_GUI.cpp rename to library/python/deprecated/DF_GUI.cpp diff --git a/library/python/DF_Helpers.cpp b/library/python/deprecated/DF_Helpers.cpp similarity index 100% rename from library/python/DF_Helpers.cpp rename to library/python/deprecated/DF_Helpers.cpp diff --git a/library/python/DF_Imports.cpp b/library/python/deprecated/DF_Imports.cpp similarity index 100% rename from library/python/DF_Imports.cpp rename to library/python/deprecated/DF_Imports.cpp diff --git a/library/python/DF_Maps.cpp b/library/python/deprecated/DF_Maps.cpp similarity index 100% rename from library/python/DF_Maps.cpp rename to library/python/deprecated/DF_Maps.cpp diff --git a/library/python/DF_Material.cpp b/library/python/deprecated/DF_Material.cpp similarity index 100% rename from library/python/DF_Material.cpp rename to library/python/deprecated/DF_Material.cpp diff --git a/library/python/DF_MemInfo.cpp b/library/python/deprecated/DF_MemInfo.cpp similarity index 100% rename from library/python/DF_MemInfo.cpp rename to library/python/deprecated/DF_MemInfo.cpp diff --git a/library/python/DF_Position.cpp b/library/python/deprecated/DF_Position.cpp similarity index 100% rename from library/python/DF_Position.cpp rename to library/python/deprecated/DF_Position.cpp diff --git a/library/python/DF_Translate.cpp b/library/python/deprecated/DF_Translate.cpp similarity index 100% rename from library/python/DF_Translate.cpp rename to library/python/deprecated/DF_Translate.cpp diff --git a/library/python/DF_Vegetation.cpp b/library/python/deprecated/DF_Vegetation.cpp similarity index 100% rename from library/python/DF_Vegetation.cpp rename to library/python/deprecated/DF_Vegetation.cpp diff --git a/library/python/build-linux b/library/python/deprecated/build-linux similarity index 100% rename from library/python/build-linux rename to library/python/deprecated/build-linux diff --git a/library/python/build.bat b/library/python/deprecated/build.bat similarity index 100% rename from library/python/build.bat rename to library/python/deprecated/build.bat diff --git a/library/python/dfhack_api_ctypes.py b/library/python/deprecated/dfhack_api_ctypes.py similarity index 100% rename from library/python/dfhack_api_ctypes.py rename to library/python/deprecated/dfhack_api_ctypes.py diff --git a/library/python/examples/attachtest.py b/library/python/deprecated/examples/attachtest.py similarity index 100% rename from library/python/examples/attachtest.py rename to library/python/deprecated/examples/attachtest.py diff --git a/library/python/examples/miscutils.py b/library/python/deprecated/examples/miscutils.py similarity index 100% rename from library/python/examples/miscutils.py rename to library/python/deprecated/examples/miscutils.py diff --git a/library/python/examples/position.py b/library/python/deprecated/examples/position.py similarity index 100% rename from library/python/examples/position.py rename to library/python/deprecated/examples/position.py diff --git a/library/python/examples/settlementdump.py b/library/python/deprecated/examples/settlementdump.py similarity index 100% rename from library/python/examples/settlementdump.py rename to library/python/deprecated/examples/settlementdump.py diff --git a/library/python/examples/suspendtest.py b/library/python/deprecated/examples/suspendtest.py similarity index 100% rename from library/python/examples/suspendtest.py rename to library/python/deprecated/examples/suspendtest.py diff --git a/library/python/examples/treedump.py b/library/python/deprecated/examples/treedump.py similarity index 100% rename from library/python/examples/treedump.py rename to library/python/deprecated/examples/treedump.py diff --git a/library/python/ez_setup.py b/library/python/deprecated/ez_setup.py similarity index 100% rename from library/python/ez_setup.py rename to library/python/deprecated/ez_setup.py diff --git a/library/python/linsetup.py b/library/python/deprecated/linsetup.py similarity index 100% rename from library/python/linsetup.py rename to library/python/deprecated/linsetup.py diff --git a/library/python/pydfhack.cpp b/library/python/deprecated/pydfhack.cpp similarity index 100% rename from library/python/pydfhack.cpp rename to library/python/deprecated/pydfhack.cpp diff --git a/library/python/deprecated/pydfhack/__init__.py b/library/python/deprecated/pydfhack/__init__.py new file mode 100644 index 000000000..1f17c8569 --- /dev/null +++ b/library/python/deprecated/pydfhack/__init__.py @@ -0,0 +1 @@ +from .pydfapi import API diff --git a/library/python/pydfhack/blocks.py b/library/python/deprecated/pydfhack/blocks.py similarity index 100% rename from library/python/pydfhack/blocks.py rename to library/python/deprecated/pydfhack/blocks.py diff --git a/library/python/pydfhack/construction.py b/library/python/deprecated/pydfhack/construction.py similarity index 100% rename from library/python/pydfhack/construction.py rename to library/python/deprecated/pydfhack/construction.py diff --git a/library/python/pydfhack/creature.py b/library/python/deprecated/pydfhack/creature.py similarity index 100% rename from library/python/pydfhack/creature.py rename to library/python/deprecated/pydfhack/creature.py diff --git a/library/python/pydfhack/decorators.py b/library/python/deprecated/pydfhack/decorators.py similarity index 100% rename from library/python/pydfhack/decorators.py rename to library/python/deprecated/pydfhack/decorators.py diff --git a/library/python/deprecated/pydfhack/gui.py b/library/python/deprecated/pydfhack/gui.py new file mode 100644 index 000000000..07192f67c --- /dev/null +++ b/library/python/deprecated/pydfhack/gui.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +""" +Python class for DF_Hack::GUI +""" +from ._pydfhack import _GUIManager +class GUI(_GUIManager): + api = None + started = False + def __init__(self, api, *args, **kwds): + _GUIManager.__init__(self, args, kwds) + self.api = api + + def prepare(self): + """ + Enforce Suspend/Start + """ + if self.api.prepare(): + if not self.started: + self.started = self.Start() + return self.started + else: + return False + + + diff --git a/library/python/pydfhack/map.py b/library/python/deprecated/pydfhack/map.py similarity index 100% rename from library/python/pydfhack/map.py rename to library/python/deprecated/pydfhack/map.py diff --git a/library/python/deprecated/pydfhack/materials.py b/library/python/deprecated/pydfhack/materials.py new file mode 100644 index 000000000..13e02c682 --- /dev/null +++ b/library/python/deprecated/pydfhack/materials.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +""" +Python class for DF_Hack::Materials +""" +from ._pydfhack import _MaterialsManager +from .mixins import NoStart +from .decorators import suspend + +class Materials(NoStart, _MaterialsManager): + api = None + cls = _MaterialsManager + def __init__(self, api, *args, **kwds): + cls.__init__(self, args, kwds) + self.api = api + + @suspend + def Read_Wood_Materials(self, *args, **kw): + return self.cls.Read_Wood_Materials(self, *args, **kw) + + @suspend + def Read_Plant_Materials(self, *args, **kw): + return self.cls.Read_Plant_Materials(self, *args, **kw) + + @suspend + def Read_Inorganic_Materials(self, *args, **kw): + return self.cls.Read_Inorganic_Materials(self, *args, **kw) + + @suspend + def Read_Descriptor_Colors(self, *args, **kw): + return self.cls.Read_Descriptor_Colors(self, *args, **kw) + + @suspend + def Read_Creature_Types(self, *args, **kw): + return self.cls.Read_Creature_Types(self, *args, **kw) + + @suspend + def Read_Organic_Materials(self, *args, **kw): + return self.cls.Read_Organic_Materials(self, *args, **kw) + + @suspend + def Read_Creature_Types_Ex(self, *args, **kw): + return self.cls.Read_Creature_Types_Ex(self, *args, **kw) diff --git a/library/python/pydfhack/meminfo.py b/library/python/deprecated/pydfhack/meminfo.py similarity index 100% rename from library/python/pydfhack/meminfo.py rename to library/python/deprecated/pydfhack/meminfo.py diff --git a/library/python/pydfhack/mixins.py b/library/python/deprecated/pydfhack/mixins.py similarity index 100% rename from library/python/pydfhack/mixins.py rename to library/python/deprecated/pydfhack/mixins.py diff --git a/library/python/deprecated/pydfhack/position.py b/library/python/deprecated/pydfhack/position.py new file mode 100644 index 000000000..7956ea812 --- /dev/null +++ b/library/python/deprecated/pydfhack/position.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +""" +Python class for DF_Hack::Position +""" +from ._pydfhack import _PositionManager +from .blocks import Point, Block +from .mixins import NoStart +from .decorators import suspend + +class Position(NoStart, _PositionManager): + api = None + cls = _PositionManager + def __init__(self, api, *args, **kwds): + self.cls.__init__(self, args, kwds) + self.api = api + + @suspend + def get_cursor(self): + coords = self.cursor_coords + if coords: + return Point(*coords) + else: + return None + + @suspend + def get_window_size(self): + wsize = self.window_size + return wsize + + @suspend + def get_view_coords(self): + coords = self.view_coords + return Point(*coords) + + @suspend + def get_cursor_tile(self): + point = self.get_cursor() + if point: + tile = self.api.maps.get_tile(point=point) + return tile + else: + return None diff --git a/library/python/pydfhack/pydfapi.py b/library/python/deprecated/pydfhack/pydfapi.py similarity index 100% rename from library/python/pydfhack/pydfapi.py rename to library/python/deprecated/pydfhack/pydfapi.py diff --git a/library/python/pydfhack/pydfhackflags.py b/library/python/deprecated/pydfhack/pydfhackflags.py similarity index 100% rename from library/python/pydfhack/pydfhackflags.py rename to library/python/deprecated/pydfhack/pydfhackflags.py diff --git a/library/python/pydfhack/pydftypes.py b/library/python/deprecated/pydfhack/pydftypes.py similarity index 100% rename from library/python/pydfhack/pydftypes.py rename to library/python/deprecated/pydfhack/pydftypes.py diff --git a/library/python/pydfhack/translation.py b/library/python/deprecated/pydfhack/translation.py similarity index 100% rename from library/python/pydfhack/translation.py rename to library/python/deprecated/pydfhack/translation.py diff --git a/library/python/deprecated/pydfhack/vegetation.py b/library/python/deprecated/pydfhack/vegetation.py new file mode 100644 index 000000000..ce1262a13 --- /dev/null +++ b/library/python/deprecated/pydfhack/vegetation.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +""" +Python class for DF_Hack::Vegetation +""" +from ._pydfhack import _VegetationManager +from .mixins import NeedsStart +from .decorators import suspend + +class Vegetation(NeedsStart, _VegetationManager): + api = None + cls = _VegetationManager + def __init__(self, api, *args, **kwds): + self.cls.__init__(self, args, kwds) + self.api = api + + @suspend + def Read(self, *args, **kw): + return self.cls.Read(self, *args, **kw) diff --git a/library/python/setup.py b/library/python/deprecated/setup.py similarity index 100% rename from library/python/setup.py rename to library/python/deprecated/setup.py diff --git a/library/python/test.py b/library/python/deprecated/test.py similarity index 100% rename from library/python/test.py rename to library/python/deprecated/test.py diff --git a/library/python/tools/shell.py b/library/python/deprecated/tools/shell.py similarity index 100% rename from library/python/tools/shell.py rename to library/python/deprecated/tools/shell.py diff --git a/library/python/tools/trees.py b/library/python/deprecated/tools/trees.py similarity index 100% rename from library/python/tools/trees.py rename to library/python/deprecated/tools/trees.py diff --git a/library/python/pydfhack/__init__.py b/library/python/pydfhack/__init__.py index 1f17c8569..99cf04305 100644 --- a/library/python/pydfhack/__init__.py +++ b/library/python/pydfhack/__init__.py @@ -1 +1,14 @@ -from .pydfapi import API +import context + +__all__ = [ "buildings", + "constructions", + "context", + "creatures", + "dftypes", + "flags", + "gui", + "items", + "maps", + "materials", + "position" + "vegetation" ] \ No newline at end of file diff --git a/library/python/c api/buildings.py b/library/python/pydfhack/buildings.py similarity index 98% rename from library/python/c api/buildings.py rename to library/python/pydfhack/buildings.py index c61fd9f2b..32c330201 100644 --- a/library/python/c api/buildings.py +++ b/library/python/pydfhack/buildings.py @@ -4,7 +4,7 @@ import util libdfhack.Buildings_GetCustomWorkshopType.argtypes = [ c_void_p, POINTER(CustomWorkshop) ] -def Buildings(object): +class Buildings(object): def __init__(self, ptr): self._b_ptr = ptr diff --git a/library/python/c api/constructions.py b/library/python/pydfhack/constructions.py similarity index 100% rename from library/python/c api/constructions.py rename to library/python/pydfhack/constructions.py diff --git a/library/python/c api/context.py b/library/python/pydfhack/context.py similarity index 89% rename from library/python/c api/context.py rename to library/python/pydfhack/context.py index 592359f57..0afc2cf25 100644 --- a/library/python/c api/context.py +++ b/library/python/pydfhack/context.py @@ -167,29 +167,4 @@ class Context(object): if self._tran_obj is None: self._tran_obj = translation.Translation(libdfhack.Context_getTranslation(self._c_ptr)) - return self._tran_obj - -def reveal(): - df = API("Memory.xml") - df.attach() - - m = df.maps - - m.start() - - m_x, m_y, m_z = m.size - - for x in xrange(m_x): - for y in xrange(m_y): - for z in xrange(m_z): - if m.is_valid_block(x, y, z): - d = m.read_designations(x, y, z) - - for i in d: - for j in i: - j.bits.hidden = 0 - - m.write_designations(x, y, z, d) - - m.finish() - df.detach() + return self._tran_obj \ No newline at end of file diff --git a/library/python/c api/creatures.py b/library/python/pydfhack/creatures.py similarity index 100% rename from library/python/c api/creatures.py rename to library/python/pydfhack/creatures.py diff --git a/library/python/c api/dfhack_api_ctypes.py b/library/python/pydfhack/dfhack_api_ctypes.py similarity index 100% rename from library/python/c api/dfhack_api_ctypes.py rename to library/python/pydfhack/dfhack_api_ctypes.py diff --git a/library/python/c api/pydftypes.py b/library/python/pydfhack/dftypes.py similarity index 89% rename from library/python/c api/pydftypes.py rename to library/python/pydfhack/dftypes.py index 78a90e57f..376d99238 100644 --- a/library/python/c api/pydftypes.py +++ b/library/python/pydfhack/dftypes.py @@ -87,12 +87,15 @@ class Matgloss(Structure): ("bright", c_byte), ("name", c_char * 128)] -def _alloc_matgloss_buffer_callback(count): +def _alloc_matgloss_buffer_callback(ptr, count): allocated = _allocate_array(Matgloss, count) - return allocated[1] + ptr = addressof(allocated[0]) -libdfhack.alloc_matgloss_buffer_callback = CFUNCTYPE(POINTER(Matgloss), c_int)(_alloc_matgloss_buffer_callback) + return 1 + +_matgloss_functype = CFUNCTYPE(c_int, POINTER(Matgloss), c_uint) +libdfhack.alloc_matgloss_buffer_callback = _matgloss_functype(_alloc_matgloss_buffer_callback) class MatglossPair(Structure): _fields_ = [("type", c_short), @@ -105,12 +108,15 @@ class DescriptorColor(Structure): ("b", c_float), ("name", c_char * 128)] -def _alloc_descriptor_buffer_callback(count): +def _alloc_descriptor_buffer_callback(ptr, count): allocated = _allocate_array(DescriptorColor, count) - return allocated[1] + ptr = addressof(allocated[0]) + + return 1 -libdfhack.alloc_descriptor_buffer_callback = CFUNCTYPE(POINTER(DescriptorColor), c_int)(_alloc_descriptor_buffer_callback) +_descriptor_functype = CFUNCTYPE(c_int, POINTER(DescriptorColor), c_uint) +libdfhack.alloc_descriptor_buffer_callback = _descriptor_functype(_alloc_descriptor_buffer_callback) class MatglossOther(Structure): _fields_ = [("rawname", c_char * 128)] @@ -118,9 +124,12 @@ class MatglossOther(Structure): def _alloc_matgloss_other_buffer_callback(count): allocated = _allocate_array(MatglossOther, count) - return allocated[1] + ptr = addressof(allocated[0]) -libdfhack.alloc_matgloss_other_buffer_callback = CFUNCTYPE(POINTER(MatglossOther), c_int)(_alloc_matgloss_other_buffer_callback) + return 1 + +_matgloss_other_functype = CFUNCTYPE(c_int, POINTER(MatglossOther), c_uint) +libdfhack.alloc_matgloss_other_buffer_callback = _matgloss_other_functype(_alloc_matgloss_other_buffer_callback) class Building(Structure): _fields_ = [("origin", c_uint), @@ -297,7 +306,10 @@ class ColorModifier(Structure): ColorModifierPtr = POINTER(ColorModifier) -def _alloc_empty_colormodifier_callback(): - return ColorModifierPtr(ColorModifier()) +def _alloc_empty_colormodifier_callback(ptr): + ptr = ColorModifierPtr(ColorModifier()) + + return 1 -libdfhack.alloc_empty_colormodifier_callback = CFUNCTYPE(ColorModifierPtr)(_alloc_empty_colormodifier_callback) +_empty_colormodifier_functype = CFUNCTYPE(c_int, ColorModifierPtr) +libdfhack.alloc_empty_colormodifier_callback = _empty_colormodifier_functype(_alloc_empty_colormodifier_callback) diff --git a/library/python/c api/enum.py b/library/python/pydfhack/enum.py similarity index 100% rename from library/python/c api/enum.py rename to library/python/pydfhack/enum.py diff --git a/library/python/c api/pydfhackflags.py b/library/python/pydfhack/flags.py similarity index 100% rename from library/python/c api/pydfhackflags.py rename to library/python/pydfhack/flags.py diff --git a/library/python/pydfhack/gui.py b/library/python/pydfhack/gui.py index 07192f67c..09a7c5c94 100644 --- a/library/python/pydfhack/gui.py +++ b/library/python/pydfhack/gui.py @@ -1,25 +1,25 @@ -# -*- coding: utf-8 -*- -""" -Python class for DF_Hack::GUI -""" -from ._pydfhack import _GUIManager -class GUI(_GUIManager): - api = None - started = False - def __init__(self, api, *args, **kwds): - _GUIManager.__init__(self, args, kwds) - self.api = api +from ctypes import * +from pydfhack import libdfhack, ViewScreen - def prepare(self): - """ - Enforce Suspend/Start - """ - if self.api.prepare(): - if not self.started: - self.started = self.Start() - return self.started - else: - return False - - +libdfhack.Gui_ReadViewScreen.argtypes = [ c_void_p, c_void_p ] + +class Gui(object): + def __init__(self, ptr): + self._gui_ptr = ptr + + def start(self): + return libdfhack.Gui_Start(self._gui_ptr) + + def finish(self): + return libdfhack.Gui_Finish(self._gui_ptr) + def read_pause_state(self): + return libdfhack.Gui_ReadPauseState(self._pos_ptr) > 0 + + def read_view_screen(self): + s = ViewScreen() + + if libdfhack.Gui_ReadViewScreen(self._gui_ptr, byref(s)) > 0: + return s + else: + return None diff --git a/library/python/c api/items.py b/library/python/pydfhack/items.py similarity index 100% rename from library/python/c api/items.py rename to library/python/pydfhack/items.py diff --git a/library/python/c api/maps.py b/library/python/pydfhack/maps.py similarity index 72% rename from library/python/c api/maps.py rename to library/python/pydfhack/maps.py index 1db1985d8..c889719e8 100644 --- a/library/python/c api/maps.py +++ b/library/python/pydfhack/maps.py @@ -1,6 +1,9 @@ from ctypes import * -from pydftypes import libdfhack -from util import _uintify +from pydftypes import * +from util import _uintify, uint_ptr + +_MAX_DIM = 0x300 +_MAX_DIM_SQR = _MAX_DIM * _MAX_DIM libdfhack.Maps_getSize.argtypes = [ c_void_p, uint_ptr, uint_ptr, uint_ptr ] libdfhack.Maps_ReadTileTypes.argtypes = [ c_void_p, c_uint, c_uint, c_uint, POINTER(TileTypes40d) ] @@ -161,3 +164,63 @@ class Maps(object): return (int(x.value), int(y.value), int(z.value)) else: return (-1, -1, -1) + +class MapPoint(object): + __slots__ = ["_x", "_y", "_z", "_cmp_val"] + + def __init__(self, x = 0, y = 0, z = 0): + self._x, self._y, self._z = x, y, z + + self._cmp_val = self._get_cmp_value() + + def _val_set(self, which, val): + if which == 0: + self._x = val + elif which == 1: + self._y = val + elif which == 2: + self._z = val + + self._cmp_val = self._get_cmp_value() + + x = property(fget = lambda self: self._x, fset = lambda self, v: self._val_set(0, v)) + y = property(fget = lambda self: self._y, fset = lambda self, v: self._val_set(1, v)) + z = property(fget = lambda self: self._z, fset = lambda self, v: self._val_set(2, v)) + + def _get_cmp_value(self): + return (self.z * _MAX_DIM_SQR) + (self.y * _MAX_DIM) + self.x + + #comparison operators + def __eq__(self, other): + return self.x == other.x and self.y == other.y and self.z == other.z + + def __ne__(self, other): + return not self == other + + def __lt__(self, other): + return self._cmp_val < other._cmp_val + + def __le__(self, other): + return self < other or self == other + + def __gt__(self, other): + return self._cmp_val > other._cmp_val + + def __ge__(self, other): + return self > other or self == other + + #arithmetic operators + def __add__(self, num): + return MapPoint(self.x, self.y, self.z + num) + + def __sub__(self, num): + return MapPoint(self.x, self.y, self.z - num) + + def __div__(self, num): + return MapPoint(self.x / num, self.y / num, self.z) + + def __mul__(self, num): + return MapPoint(self.x * num, self.y * num, self.z) + + def __mod__(self, num): + return MapPoint(self.x % num, self.y % num, self.z) \ No newline at end of file diff --git a/library/python/pydfhack/materials.py b/library/python/pydfhack/materials.py index 13e02c682..04d82fddb 100644 --- a/library/python/pydfhack/materials.py +++ b/library/python/pydfhack/materials.py @@ -1,42 +1,141 @@ -# -*- coding: utf-8 -*- -""" -Python class for DF_Hack::Materials -""" -from ._pydfhack import _MaterialsManager -from .mixins import NoStart -from .decorators import suspend - -class Materials(NoStart, _MaterialsManager): - api = None - cls = _MaterialsManager - def __init__(self, api, *args, **kwds): - cls.__init__(self, args, kwds) - self.api = api - - @suspend - def Read_Wood_Materials(self, *args, **kw): - return self.cls.Read_Wood_Materials(self, *args, **kw) - - @suspend - def Read_Plant_Materials(self, *args, **kw): - return self.cls.Read_Plant_Materials(self, *args, **kw) - - @suspend - def Read_Inorganic_Materials(self, *args, **kw): - return self.cls.Read_Inorganic_Materials(self, *args, **kw) - - @suspend - def Read_Descriptor_Colors(self, *args, **kw): - return self.cls.Read_Descriptor_Colors(self, *args, **kw) - - @suspend - def Read_Creature_Types(self, *args, **kw): - return self.cls.Read_Creature_Types(self, *args, **kw) - - @suspend - def Read_Organic_Materials(self, *args, **kw): - return self.cls.Read_Organic_Materials(self, *args, **kw) - - @suspend - def Read_Creature_Types_Ex(self, *args, **kw): - return self.cls.Read_Creature_Types_Ex(self, *args, **kw) +from ctypes import * +from pydftypes import libdfhack +from util import * + +_get_arg_types = [ c_void_p, _arr_create_func ] + +libdfhack.Materials_getInorganic.argtypes = _get_arg_types +libdfhack.Materials_getOrganic.argtypes = _get_arg_types +libdfhack.Materials_getTree.argtypes = _get_arg_types +libdfhack.Materials_getPlant.argtypes = _get_arg_types +libdfhack.Materials_getRace.argtypes = _get_arg_types +#libdfhack.Materials_getRaceEx.argtypes = _get_arg_types +libdfhack.Materials_getColor.argtypes = _get_arg_types +libdfhack.Materials_getOther.argtypes = _get_arg_types + +class Materials(object): + def __init__(self, ptr): + self._mat_ptr = ptr + + self.inorganic = None + self.organic = None + self.tree = None + self.plant = None + self.race = None + self.race_ex = None + self.color = None + self.other = None + + def read_inorganic(self): + return libdfhack.Materials_ReadInorganicMaterials(self._mat_ptr) + + def read_organic(self): + return libdfhack.Materials_ReadOrganicMaterials(self._mat_ptr) + + def read_wood(self): + return libdfhack.Materials_ReadWoodMaterials(self._mat_ptr) + + def read_plant(self): + return libdfhack.Materials_ReadPlantMaterials(self._mat_ptr) + + def read_creature_types(self): + return libdfhack.Materials_ReadCreatureTypes(self._mat_ptr) + + def read_creature_types_ex(self): + return libdfhack.Materials_ReadCreatureTypesEx(self._mat_ptr) + + def read_descriptor_colors(self): + return libdfhack.Materials_ReadDescriptorColors(self._mat_ptr) + + def read_others(self): + return libdfhack.Materials_ReadOthers(self._mat_ptr) + + def read_all(self): + libdfhack.Materials_ReadAllMaterials(self._mat_ptr) + + def get_description(self, material): + return libdfhack.Materials_getDescription(self._mat_ptr, byref(material)) + + def update_inorganic_cache(self): + def update_callback(count): + allocated = _allocate_array(Matgloss, count) + + self.inorganic = allocated[0] + + return allocated[1] + + callback = _arr_create_func(update_callback) + + return libdfhack.Materials_getInorganic(self._mat_ptr, callback) + + def update_organic_cache(self): + def update_callback(count): + allocated = _allocate_array(Matgloss, count) + + self.organic = allocated[0] + + return allocated[1] + + callback = _arr_create_func(update_callback) + + return libdfhack.Materials_getOrganic(self._mat_ptr, callback) + + def update_tree_cache(self): + def update_callback(count): + allocated = _allocate_array(Matgloss, count) + + self.tree = allocated[0] + + return allocated[1] + + callback = _arr_create_func(update_callback) + + return libdfhack.Materials_getTree(self._mat_ptr, callback) + + def update_plant_cache(self): + def update_callback(count): + allocated = _allocate_array(Matgloss, count) + + self.plant = allocated[0] + + return allocated[1] + + callback = _arr_create_func(update_callback) + + return libdfhack.Materials_getPlant(self._mat_ptr, callback) + + def update_race_cache(self): + def update_callback(count): + allocated = _allocate_array(Matgloss, count) + + self.race = allocated[0] + + return allocated[1] + + callback = _arr_create_func(update_callback) + + return libdfhack.Materials_getRace(self._mat_ptr, callback) + + def update_color_cache(self): + def update_callback(count): + allocated = _allocate_array(DescriptorColor, count) + + self.color = allocated[0] + + return allocated[1] + + callback = _arr_create_func(update_callback) + + return libdfhack.Materials_getColor(self._mat_ptr, callback) + + def update_other_cache(self): + def update_callback(count): + allocated = _allocate_array(MatglossOther, count) + + self.other = allocated[0] + + return allocated[1] + + callback = _arr_create_func(update_callback) + + return libdfhack.Materials_getOther(self._mat_ptr, callback) diff --git a/library/python/pydfhack/position.py b/library/python/pydfhack/position.py index 7956ea812..ffa758150 100644 --- a/library/python/pydfhack/position.py +++ b/library/python/pydfhack/position.py @@ -1,42 +1,43 @@ -# -*- coding: utf-8 -*- -""" -Python class for DF_Hack::Position -""" -from ._pydfhack import _PositionManager -from .blocks import Point, Block -from .mixins import NoStart -from .decorators import suspend - -class Position(NoStart, _PositionManager): - api = None - cls = _PositionManager - def __init__(self, api, *args, **kwds): - self.cls.__init__(self, args, kwds) - self.api = api - - @suspend - def get_cursor(self): - coords = self.cursor_coords - if coords: - return Point(*coords) - else: - return None +from ctypes import * +from pydftypes import libdfhack + +class Position(object): + def __init__(self, ptr): + self._pos_ptr = ptr - @suspend - def get_window_size(self): - wsize = self.window_size - return wsize + self._vx, self._vy, self._vz = c_int(), c_int(), c_int() + self._cx, self._cy, self._cz = c_int(), c_int(), c_int() + self._ww, self._wh = c_int(), c_int() - @suspend def get_view_coords(self): - coords = self.view_coords - return Point(*coords) - - @suspend - def get_cursor_tile(self): - point = self.get_cursor() - if point: - tile = self.api.maps.get_tile(point=point) - return tile + if libdfhack.Position_getViewCoords(self._pos_ptr, byref(self._vx), byref(self._vy), byref(self._vz)) > 0: + return (self._vx.value, self._vy.value, self._vz.value) + else: + return (-1, -1, -1) + + def set_view_coords(self, v_coords): + self._vx.value, self._vy.value, self._vz.value = v_coords + + libdfhack.Position_setViewCoords(self._pos_ptr, self._vx, self._vy, self._vz) + + view_coords = property(get_view_coords, set_view_coords) + + def get_cursor_coords(self): + if libdfhack.Position_getCursorCoords(self._pos_ptr, byref(self._cx), byref(self._cy), byref(self._cz)) > 0: + return (self._cx.value, self._cy.value, self._cz.value) + else: + return (-1, -1, -1) + + def set_cursor_coords(self, c_coords): + self._cx.value, self._cy.value, self_cz.value = c_coords + + libdfhack.Position_setCursorCoords(self._pos_ptr, self._cx, self._cy, self._cz) + + cursor_coords = property(get_cursor_coords, set_cursor_coords) + + @property + def window_size(self): + if libdfhack.Position_getWindowSize(self._pos_ptr, byref(self._ww), byref(self._wh)) > 0: + return (self._ww.value, self._wh.value) else: - return None + return (-1, -1) diff --git a/library/python/pydfhack/util.py b/library/python/pydfhack/util.py new file mode 100644 index 000000000..d0849b1d8 --- /dev/null +++ b/library/python/pydfhack/util.py @@ -0,0 +1,90 @@ +from ctypes import * + +uint_ptr = POINTER(c_uint) +int_ptr = POINTER(c_int) + +def _uintify(x, y, z): + return (c_uint(x), c_uint(y), c_uint(z)) + +def _allocate_array(t_type, count): + arr_type = t_type * count + + arr = arr_type() + + ptr = c_void_p() + ptr = addressof(arr) + + return (arr, ptr) + +def _alloc_int_buffer(ptr, count): + a = _allocate_array(c_int, count) + + ptr = addressof(a[0]) + + return 1 + +_int_functype = CFUNCTYPE(c_int, POINTER(c_int), c_uint) +alloc_int_buffer = _int_functype(_alloc_int_buffer) + +def _alloc_uint_buffer(ptr, count): + a = _allocate_array(c_uint, count) + + ptr = addressof(a[0]) + + return 1 + +_uint_functype = CFUNCTYPE(c_int, POINTER(c_uint), c_uint) +alloc_uint_buffer = _uint_functype(_alloc_uint_buffer) + +def _alloc_short_buffer(ptr, count): + a = _allocate_array(c_short, count) + + ptr = addressof(a[0]) + + return 1 + +_short_functype = CFUNCTYPE(c_int, POINTER(c_short), c_uint) +alloc_short_buffer = _short_functype(_alloc_short_buffer) + +def _alloc_ushort_buffer(ptr, count): + a = _allocate_array(c_ushort, count) + + ptr = addressof(a[0]) + + return 1 + +_ushort_functype = CFUNCTYPE(c_int, POINTER(c_ushort), c_uint) +alloc_ushort_buffer = _ushort_functype(_alloc_ushort_buffer) + +def _alloc_byte_buffer(ptr, count): + a = _allocate_array(c_byte, count) + + ptr = addressof(a[0]) + + return 1 + +_byte_functype = CFUNCTYPE(c_int, POINTER(c_byte), c_uint) +alloc_byte_buffer = _byte_functype(_alloc_byte_buffer) + +def _alloc_ubyte_buffer(ptr, count): + a = _allocate_array(c_ubyte, count) + + ptr = addressof(a[0]) + + return 1 + +_ubyte_functype = CFUNCTYPE(c_int, POINTER(c_ubyte), c_uint) +alloc_ubyte_buffer = _ubyte_functype(_alloc_ubyte_buffer) + +def _alloc_char_buffer(ptr, count): + c = create_string_buffer(count) + + if ptr is None: + ptr = c_void_p + + ptr = addressof(c) + + return 1 + +_char_functype = CFUNCTYPE(c_int, POINTER(c_char), c_uint) +alloc_char_buffer = _char_functype(_alloc_char_buffer) diff --git a/library/python/pydfhack/vegetation.py b/library/python/pydfhack/vegetation.py index ce1262a13..0c22d26b5 100644 --- a/library/python/pydfhack/vegetation.py +++ b/library/python/pydfhack/vegetation.py @@ -1,18 +1,25 @@ -# -*- coding: utf-8 -*- -""" -Python class for DF_Hack::Vegetation -""" -from ._pydfhack import _VegetationManager -from .mixins import NeedsStart -from .decorators import suspend +from ctypes import * +from pydftypes import libdfhack, Tree -class Vegetation(NeedsStart, _VegetationManager): - api = None - cls = _VegetationManager - def __init__(self, api, *args, **kwds): - self.cls.__init__(self, args, kwds) - self.api = api +class Vegetation(object): + def __init__(self, ptr): + self._v_ptr = ptr + + def start(self): + n = c_uint(0) - @suspend - def Read(self, *args, **kw): - return self.cls.Read(self, *args, **kw) + if libdfhack.Vegetation_Start(self._v_ptr, byref(n)) > 0: + return int(n.value) + else: + return -1 + + def finish(self): + return libdfhack.Vegetation_Finish(self._v_ptr) > 0 + + def read(self, index): + t = Tree() + + if libdfhack.Vegetation_Read(self._v_ptr, c_uint(index), byref(t)) > 0: + return t + else: + return None diff --git a/library/shm/CMakeLists.txt b/library/shm/CMakeLists.txt new file mode 100644 index 000000000..0f712cad3 --- /dev/null +++ b/library/shm/CMakeLists.txt @@ -0,0 +1,56 @@ +################################################################################ +# DFCONNECT +### +SET(DFCONNECT_HDRS +shms.h +mod-core.h +mod-maps.h +) + +SET(PROJECT_SRCS +mod-core.cpp +mod-maps.cpp +#mod-creature40d.cpp +) + +SET(PROJECT_HDRS_LINUX +) + +SET(PROJECT_HDRS_WINDOWS +) + +SET(PROJECT_SRCS_LINUX +shms-linux.cpp +) + +SET(PROJECT_SRCS_WINDOWS +shms-windows.cpp +) + +IF(UNIX) + LIST(APPEND PROJECT_HDRS ${PROJECT_HDRS_LINUX}) + LIST(APPEND PROJECT_SRCS ${PROJECT_SRCS_LINUX}) +ELSE(UNIX) + LIST(APPEND PROJECT_HDRS ${PROJECT_HDRS_WINDOWS}) + LIST(APPEND PROJECT_SRCS ${PROJECT_SRCS_WINDOWS}) +ENDIF(UNIX) + + +SET_SOURCE_FILES_PROPERTIES( ${PROJECT_HDRS} PROPERTIES HEADER_FILE_ONLY TRUE ) + +LIST(APPEND PROJECT_SRCS ${PROJECT_HDRS}) + +#IF(CMAKE_SIZEOF_VOID_P EQUAL 4) + add_definitions(-DBUILD_SHM) + IF(UNIX) + add_definitions(-DLINUX_BUILD) + SET(PROJECT_LIBS rt) + SET(CMAKE_CXX_FLAGS "-fvisibility=hidden") + ADD_LIBRARY(dfconnect SHARED ${PROJECT_SRCS}) + TARGET_LINK_LIBRARIES(dfconnect ${PROJECT_LIBS}) + ELSE(UNIX) + # SET(PROJECT_LIBS psapi) + ADD_LIBRARY(SDL SHARED ${PROJECT_SRCS}) + TARGET_LINK_LIBRARIES(SDL ${PROJECT_LIBS}) + ENDIF(UNIX) +#ENDIF(CMAKE_SIZEOF_VOID_P EQUAL 4) diff --git a/library/shm/shms-windows.cpp b/library/shm/shms-windows.cpp index 007612438..1173de74a 100644 --- a/library/shm/shms-windows.cpp +++ b/library/shm/shms-windows.cpp @@ -510,6 +510,21 @@ DFhackCExport void * SDL_DisplayFormat(void *surface) return _SDL_DisplayFormat(surface); } +// SDL_Surface *SDL_DisplayFormatAlpha(SDL_Surface *surface); +static void * (*_SDL_DisplayFormatAlpha)( void * surface ) = 0; +DFhackCExport void * SDL_DisplayFormatAlpha(void *surface) +{ + return _SDL_DisplayFormatAlpha(surface); +} + +//void SDL_GetRGBA(Uint32 pixel, SDL_PixelFormat *fmt, Uint8 *r, Uint8 *g, Uint8 *b, Uint8 *a); + +static void (*_SDL_GetRGBA)(uint32_t pixel, void * fmt, uint8_t * r, uint8_t * g, uint8_t * b, uint8_t *a) = 0; +DFhackCExport void SDL_GetRGBA(uint32_t pixel, void * fmt, uint8_t * r, uint8_t * g, uint8_t * b, uint8_t *a) +{ + return _SDL_GetRGBA(pixel, fmt, r, g, b, a); +} + static int (*_SDL_GL_GetAttribute)(int attr, int * value) = 0; DFhackCExport int SDL_GL_GetAttribute(int attr, int * value) { @@ -889,6 +904,8 @@ bool FirstCall() _SDL_EnableUNICODE = (int (*)(int))GetProcAddress(realSDLlib,"SDL_EnableUNICODE"); _SDL_GetVideoSurface = (void*(*)())GetProcAddress(realSDLlib,"SDL_GetVideoSurface"); _SDL_DisplayFormat = (void * (*) (void *))GetProcAddress(realSDLlib,"SDL_DisplayFormat"); + _SDL_DisplayFormatAlpha = (void * (*) (void *))GetProcAddress(realSDLlib,"SDL_DisplayFormatAlpha"); + _SDL_GetRGBA = (void (*) (uint32_t, void *, uint8_t *, uint8_t *, uint8_t *, uint8_t *))GetProcAddress(realSDLlib,"SDL_GetRGBA"); _SDL_FreeSurface = (void (*)(void*))GetProcAddress(realSDLlib,"SDL_FreeSurface"); _SDL_GL_GetAttribute = (int (*)(int, int*))GetProcAddress(realSDLlib,"SDL_GL_GetAttribute"); _SDL_GL_SetAttribute = (int (*)(int, int))GetProcAddress(realSDLlib,"SDL_GL_SetAttribute"); diff --git a/offsetedit/CMakeLists.txt b/offsetedit/CMakeLists.txt new file mode 100644 index 000000000..f8065bc4c --- /dev/null +++ b/offsetedit/CMakeLists.txt @@ -0,0 +1,9 @@ + +project(dfoffsetedit) +cmake_minimum_required(VERSION 2.6) +find_package(Qt4 QUIET) +if(QT4_FOUND) + add_subdirectory (src) +else(QT4_FOUND) + MESSAGE(STATUS "Qt4 libraries not found - offset editor can't be built.") +endif(QT4_FOUND) diff --git a/offsetedit/src/CMakeLists.txt b/offsetedit/src/CMakeLists.txt new file mode 100644 index 000000000..9a2218413 --- /dev/null +++ b/offsetedit/src/CMakeLists.txt @@ -0,0 +1,25 @@ +include_directories(${QT_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR}) + +set ( dfoffsetedit_SRCS + dfedit.cpp + memxmlModel.cpp + main.cpp +) + +SET ( dfoffsetedit_UI + gui/main.ui +) + +SET( dfoffsetedit_RCS + gui/resources.qrc +) + +# this command will generate rules that will run rcc on all files from dfoffsetedit_RCS +# in result dfoffsetedit_RC_SRCS variable will contain paths to files produced by rcc +QT4_ADD_RESOURCES( dfoffsetedit_RC_SRCS ${dfoffsetedit_RCS} ) + +QT4_WRAP_UI(dfoffsetedit_UI_h ${dfoffsetedit_UI}) +qt4_automoc(${dfoffsetedit_SRCS}) + +add_executable(dfoffsetedit ${dfoffsetedit_SRCS} ${dfoffsetedit_RC_SRCS} ${dfoffsetedit_UI_h}) +target_link_libraries(dfoffsetedit ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} ${QT_QTXML_LIBRARY} ) \ No newline at end of file diff --git a/offsetedit/src/dfedit.cpp b/offsetedit/src/dfedit.cpp new file mode 100644 index 000000000..f7ac3e7a4 --- /dev/null +++ b/offsetedit/src/dfedit.cpp @@ -0,0 +1,95 @@ +#include "dfedit.h" +#include +#include +#include "memxmlModel.h" + +dfedit::dfedit(QWidget *parent): QMainWindow(parent) +{ + ui.setupUi(this); + connect(ui.actionOpen,SIGNAL(triggered(bool)),this,SLOT(slotOpen(bool))); + connect(ui.actionQuit,SIGNAL(triggered(bool)),this,SLOT(slotQuit(bool))); + connect(ui.actionRun_DF,SIGNAL(triggered(bool)),this,SLOT(slotRunDF(bool))); + connect(ui.actionSave,SIGNAL(triggered(bool)),this,SLOT(slotSave(bool))); + connect(ui.actionSave_As,SIGNAL(triggered(bool)),this,SLOT(slotSaveAs(bool))); + connect(ui.actionSetup_DF_executables,SIGNAL(triggered(bool)),this,SLOT(slotSetupDFs(bool))); + ui.actionOpen->setIcon(QIcon::fromTheme("document-open")); + ui.actionOpen->setIconText(tr("Open")); + ui.actionSave->setIcon(QIcon::fromTheme("document-save")); + ui.actionSave->setIconText(tr("Save")); + ui.actionSave_As->setIcon(QIcon::fromTheme("document-save-as")); + ui.actionSave_As->setIconText(tr("Save As")); + ui.actionRun_DF->setIcon(QIcon::fromTheme("system-run")); + ui.actionRun_DF->setIconText(tr("Run DF")); + ui.actionQuit->setIcon(QIcon::fromTheme("application-exit")); + ui.actionQuit->setIconText(tr("Run DF")); +} + +dfedit::~dfedit() +{} + +void dfedit::slotOpen(bool ) +{ + QFileDialog fd(this,tr("Locate the Memoxy.xml file")); + fd.setNameFilter(tr("Memory definition (*.xml)")); + fd.setFileMode(QFileDialog::ExistingFile); + fd.setAcceptMode(QFileDialog::AcceptOpen); + int result = fd.exec(); + if(result == QDialog::Accepted) + { + QStringList files = fd.selectedFiles(); + QString fileName = files[0]; + QDomDocument doc("memxml"); + QFile file(fileName); + if(!file.open(QIODevice::ReadOnly)) + { + return; + } + if(!doc.setContent(&file)) + { + file.close(); + return; + } + mod = new MemXMLModel(doc,this); + ui.entryView->setModel(mod); + file.close(); + } +} + +void dfedit::slotQuit(bool ) +{ + close(); +} + +void dfedit::slotSave(bool ) +{ + // blah +} + +void dfedit::slotRunDF(bool ) +{ + // blah +} + +void dfedit::slotSaveAs(bool ) +{ + QFileDialog fd(this,tr("Choose file to save as...")); + fd.setNameFilter(tr("Memory definition (*.xml)")); + fd.setFileMode(QFileDialog::AnyFile); + fd.selectFile("Memory.xml"); + fd.setAcceptMode(QFileDialog::AcceptSave); + int result = fd.exec(); + if(result == QDialog::Accepted) + { + QStringList files = fd.selectedFiles(); + QString file = files[0]; + qDebug() << "File:" << file; + } +} + +void dfedit::slotSetupDFs(bool ) +{ + // dialog showing all the versions in Memory.xml that lets the user set up ways to run those versions... + // currently unimplemented +} + +#include "dfedit.moc" diff --git a/offsetedit/src/dfedit.h b/offsetedit/src/dfedit.h new file mode 100644 index 000000000..2a30ef7aa --- /dev/null +++ b/offsetedit/src/dfedit.h @@ -0,0 +1,26 @@ +#ifndef dfedit_H +#define dfedit_H + +#include +#include "ui_main.h" +#include "memxmlModel.h" + +class dfedit : public QMainWindow +{ + Q_OBJECT +public: + dfedit(QWidget *parent = 0); + virtual ~dfedit(); + +private: + Ui::MainWindow ui; + MemXMLModel * mod; +public slots: + void slotOpen(bool); + void slotQuit(bool); + void slotSave(bool); + void slotSaveAs(bool); + void slotRunDF(bool); + void slotSetupDFs(bool); +}; +#endif // dfedit_H diff --git a/offsetedit/src/gui/dIsForDwarf.svg b/offsetedit/src/gui/dIsForDwarf.svg new file mode 100644 index 000000000..51b7acf0f --- /dev/null +++ b/offsetedit/src/gui/dIsForDwarf.svg @@ -0,0 +1,1621 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D + D + + + + + + X + + + + + X + + + + + + + + + + + + + 32 x 32 + 16 x 16 + X + + + + + X + + + + + + diff --git a/offsetedit/src/gui/main.ui b/offsetedit/src/gui/main.ui new file mode 100644 index 000000000..dfff8fa02 --- /dev/null +++ b/offsetedit/src/gui/main.ui @@ -0,0 +1,195 @@ + + + MainWindow + + + + 0 + 0 + 633 + 622 + + + + MainWindow + + + + :/main_icon/main_64.png:/main_icon/main_64.png + + + + + + + + + + + + toolBar + + + TopToolBarArea + + + false + + + + + + + + + QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable + + + Qt::LeftDockWidgetArea|Qt::RightDockWidgetArea + + + Description + + + 2 + + + + + + + + 1 + 1 + + + + + 0 + 0 + + + + QFrame::NoFrame + + + QFrame::Raised + + + 1 + + + 0 + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:10pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:18px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:xx-large; font-weight:600;">Title text</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Some other text.</p></body></html> + + + Qt::AutoText + + + false + + + Qt::AlignTop + + + true + + + + + + + + + false + + + QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable + + + Qt::LeftDockWidgetArea|Qt::RightDockWidgetArea + + + Entries + + + 1 + + + + + + + + + + + + + 0 + 0 + 633 + 22 + + + + + File + + + + + + + + + Settings + + + + + + + + + Open + + + + + Save + + + + + Save As + + + + + Quit + + + + + Run DF + + + + + Setup DF executables + + + + + + + + diff --git a/offsetedit/src/gui/main_16.png b/offsetedit/src/gui/main_16.png new file mode 100644 index 000000000..04367e58d Binary files /dev/null and b/offsetedit/src/gui/main_16.png differ diff --git a/offsetedit/src/gui/main_32.png b/offsetedit/src/gui/main_32.png new file mode 100644 index 000000000..39137fed1 Binary files /dev/null and b/offsetedit/src/gui/main_32.png differ diff --git a/offsetedit/src/gui/main_64.png b/offsetedit/src/gui/main_64.png new file mode 100644 index 000000000..e6823a94f Binary files /dev/null and b/offsetedit/src/gui/main_64.png differ diff --git a/offsetedit/src/gui/resources.qrc b/offsetedit/src/gui/resources.qrc new file mode 100644 index 000000000..707294060 --- /dev/null +++ b/offsetedit/src/gui/resources.qrc @@ -0,0 +1,7 @@ + + + main_64.png + main_16.png + main_32.png + + diff --git a/offsetedit/src/main.cpp b/offsetedit/src/main.cpp new file mode 100644 index 000000000..36334656d --- /dev/null +++ b/offsetedit/src/main.cpp @@ -0,0 +1,11 @@ +#include +#include "dfedit.h" + + +int main(int argc, char** argv) +{ + QApplication app(argc, argv); + dfedit appGui; + appGui.show(); + return app.exec(); +} diff --git a/offsetedit/src/memxmlModel.cpp b/offsetedit/src/memxmlModel.cpp new file mode 100644 index 000000000..3df8849bf --- /dev/null +++ b/offsetedit/src/memxmlModel.cpp @@ -0,0 +1,210 @@ +/**************************************************************************** +** +** Copyright (C) 2005-2006 Trolltech ASA. All rights reserved. +** +** This file was part of the example classes of the Qt Toolkit. +** Now it's being hacked into some other shape... :) +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#include "memxmlModel.h" +#include +#include +#include +#include + +class DomItem +{ +public: + DomItem(QDomNode &node, int row, DomItem *parent = 0); + ~DomItem(); + DomItem *child(int i); + DomItem *parent(); + QDomNode node() const; + int row(); + +private: + QDomNode domNode; + QHash childItems; + DomItem *parentItem; + int rowNumber; +}; + +DomItem::DomItem(QDomNode &node, int row, DomItem *parent) +{ + domNode = node; + // Record the item's location within its parent. + rowNumber = row; + parentItem = parent; +} + +DomItem::~DomItem() +{ + QHash::iterator it; + for (it = childItems.begin(); it != childItems.end(); ++it) + delete it.value(); +} + +QDomNode DomItem::node() const +{ + return domNode; +} + +DomItem *DomItem::parent() +{ + return parentItem; +} + +DomItem *DomItem::child(int i) +{ + if (childItems.contains(i)) + return childItems[i]; + + if (i >= 0 && i < domNode.childNodes().count()) { + QDomNode childNode = domNode.childNodes().item(i); + DomItem *childItem = new DomItem(childNode, i, this); + childItems[i] = childItem; + return childItem; + } + return 0; +} + +int DomItem::row() +{ + return rowNumber; +} + +MemXMLModel::MemXMLModel(QDomDocument document, QObject *parent) + : QAbstractItemModel(parent), domDocument(document) +{ + rootItem = new DomItem(domDocument, 0); +} + +MemXMLModel::~MemXMLModel() +{ + delete rootItem; +} + +int MemXMLModel::columnCount(const QModelIndex & parent) const +{ + Q_UNUSED(parent); + return 3; +} + +QVariant MemXMLModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if (role != Qt::DisplayRole) + return QVariant(); + + DomItem *item = static_cast(index.internalPointer()); + + QDomNode node = item->node(); + QStringList attributes; + QDomNamedNodeMap attributeMap = node.attributes(); + + switch (index.column()) { + case 0: + return node.nodeName(); + case 1: + for (int i = 0; (unsigned int)(i) < attributeMap.count(); ++i) + { + QDomNode attribute = attributeMap.item(i); + attributes << attribute.nodeName() + "=\"" +attribute.nodeValue() + "\""; + } + return attributes.join(" "); + case 2: + return node.nodeValue().split("\n").join(" "); + default: + return QVariant(); + } +} + +Qt::ItemFlags MemXMLModel::flags(const QModelIndex &index) const +{ + if (!index.isValid()) + { + return Qt::ItemIsEnabled; + } + + return Qt::ItemIsEnabled | Qt::ItemIsSelectable; +} + +QVariant MemXMLModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { + switch (section) { + case 0: + return tr("Name"); + case 1: + return tr("Attributes"); + case 2: + return tr("Value"); + default: + return QVariant(); + } + } + + return QVariant(); +} + +QModelIndex MemXMLModel::index(int row, int column, const QModelIndex &parent) const +{ + DomItem *parentItem; + + if (!parent.isValid()) + parentItem = rootItem; + else + parentItem = static_cast(parent.internalPointer()); + + DomItem *childItem = parentItem->child(row); + if (childItem) + return createIndex(row, column, childItem); + else + return QModelIndex(); +} + +QModelIndex MemXMLModel::parent(const QModelIndex &child) const +{ + if (!child.isValid()) + return QModelIndex(); + + DomItem *childItem = static_cast(child.internalPointer()); + DomItem *parentItem = childItem->parent(); + + if (!parentItem || parentItem == rootItem) + return QModelIndex(); + + return createIndex(parentItem->row(), 0, parentItem); +} + +int MemXMLModel::rowCount(const QModelIndex &parent) const +{ + DomItem *parentItem; + + if (!parent.isValid()) + parentItem = rootItem; + else + parentItem = static_cast(parent.internalPointer()); + + return parentItem->node().childNodes().count(); +} + +#include "memxmlModel.moc" diff --git a/offsetedit/src/memxmlModel.h b/offsetedit/src/memxmlModel.h new file mode 100644 index 000000000..2879f4b5f --- /dev/null +++ b/offsetedit/src/memxmlModel.h @@ -0,0 +1,30 @@ +#ifndef memxmlModel_H +#define memxmlModel_H + +#include +#include + +class DomItem; + +class MemXMLModel : public QAbstractItemModel +{ + Q_OBJECT +public: + MemXMLModel(QDomDocument document, QObject *parent = 0); + ~MemXMLModel(); + + QVariant data(const QModelIndex &index, int role) const; + Qt::ItemFlags flags(const QModelIndex &index) const; + QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const; + QModelIndex index(int row, int column, + const QModelIndex &parent = QModelIndex()) const; + QModelIndex parent(const QModelIndex &child) const; + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + +private: + QDomDocument domDocument; + DomItem *rootItem; +}; +#endif // memxmlModel diff --git a/precompiled/linux/libdfconnect.so b/precompiled/linux/libdfconnect.so index 633f5c5e5..4b3a2a846 100755 Binary files a/precompiled/linux/libdfconnect.so and b/precompiled/linux/libdfconnect.so differ diff --git a/precompiled/windows/SDL.dll b/precompiled/windows/SDL.dll index 4b9815255..e436f4e9e 100644 Binary files a/precompiled/windows/SDL.dll and b/precompiled/windows/SDL.dll differ diff --git a/tools/examples/CMakeLists.txt b/tools/examples/CMakeLists.txt index 3662181b4..05d03e3d8 100644 --- a/tools/examples/CMakeLists.txt +++ b/tools/examples/CMakeLists.txt @@ -1,5 +1,8 @@ # don't use this file directly. use the one in the root folder of the project +# only build this stuff when BUILD_DFHACK_EXAMPLES is set to ON +IF (BUILD_DFHACK_EXAMPLES) + # this is required to ensure we use the right configuration for the system. IF(UNIX) add_definitions(-DLINUX_BUILD) @@ -21,10 +24,6 @@ TARGET_LINK_LIBRARIES(dfcreaturedump dfhack) 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) - # itemdump - dump the item under the cursor ADD_EXECUTABLE(dfitemdump dfitemdump.cpp) TARGET_LINK_LIBRARIES(dfitemdump dfhack) @@ -47,38 +46,20 @@ TARGET_LINK_LIBRARIES(dftreedump dfhack) ADD_EXECUTABLE(dfspatterdump spatterdump.cpp) TARGET_LINK_LIBRARIES(dfspatterdump dfhack) -IF(UNIX) - SET(CURSES_NEED_WIDE "YES") - SET(CURSES_NEED_NCURSES "NO") - find_package(Curses QUIET) - - IF(CURSES_FOUND) - if(CURSES_HAVE_NCURSESW_NCURSES_H) - SET(NCURSES_H "ncursesw/ncurses.h") - elseif(CURSES_HAVE_NCURSESW_CURSES_H) - SET(NCURSES_H "ncursesw/curses.h") - elseif(CURSES_HAVE_NCURSESW_H) - SET(NCURSES_H "ncursesw.h") - elseif(CURSES_HAVE_CURSESW_H) - SET(NCURSES_H "cursesw.h") - endif(CURSES_HAVE_NCURSESW_NCURSES_H) - IF(NCURSES_H) - # OPTION( VARIABLE "Description" Initial state) - #OPTION( WITH_FOO "Enable FOO support" ON ) - #OPTION( WITH_BAR "Enable BAR component" OFF ) - #SET( BAZ 18 ) - CONFIGURE_FILE( ${CMAKE_CURRENT_SOURCE_DIR}/fake-curses.h.cmake ${CMAKE_CURRENT_SOURCE_DIR}/fake-curses.h ) - - # veinlook - look at the map... sort of - ADD_EXECUTABLE(dfveinlook veinlook.cpp) - INCLUDE_DIRECTORIES(${CURSES_INCLUDE_DIR}) - TARGET_LINK_LIBRARIES(dfveinlook dfhack ${CURSES_LIBRARIES}) - install(TARGETS - dfveinlook - RUNTIME DESTINATION bin - ) - ENDIF(NCURSES_H) - ELSE(CURSES_FOUND) - MESSAGE(STATUS "Wide-character ncurses library not found - veinlook can't be built") - ENDIF(CURSES_FOUND) -ENDIF(UNIX) \ No newline at end of file +# processenum - demonstrates the use of ProcessEnumerator +ADD_EXECUTABLE(dfprocessenum processenum.cpp) +TARGET_LINK_LIBRARIES(dfprocessenum dfhack) + +install(TARGETS +dfbuildingsdump +dfconstructiondump +dfcreaturedump +dfmaterialtest +dfitemdump +dfhotkeynotedump +dftreedump +dfspatterdump +dfprocessenum +RUNTIME DESTINATION bin +) +ENDIF (BUILD_DFHACK_EXAMPLES) \ No newline at end of file diff --git a/tools/examples/buildingsdump.cpp b/tools/examples/buildingsdump.cpp index 1f0be6fc7..bfb747685 100644 --- a/tools/examples/buildingsdump.cpp +++ b/tools/examples/buildingsdump.cpp @@ -5,8 +5,10 @@ #include #include #include -using namespace std; +#include +//using namespace std; +#define DFHACK_WANT_MISCUTILS #include int main (int argc,const char* argv[]) @@ -27,14 +29,14 @@ int main (int argc,const char* argv[]) } else if(argc == 3) { - string s = argv[2]; //blah. I don't care - istringstream ins; // Declare an input string stream. + std::string s = argv[2]; //blah. I don't care + std::istringstream ins; // Declare an input string stream. ins.str(s); // Specify string to read. ins >> lines; // Reads the integers from the string. mode = 1; } - map custom_workshop_types; + std::map custom_workshop_types; DFHack::ContextManager DFMgr ("Memory.xml"); DFHack::Context *DF; @@ -43,9 +45,9 @@ int main (int argc,const char* argv[]) DF = DFMgr.getSingleContext(); DF->Attach(); } - catch (exception& e) + catch (std::exception& e) { - cerr << e.what() << endl; + std::cerr << e.what() << std::endl; #ifndef LINUX_BUILD cin.ignore(); #endif @@ -62,17 +64,17 @@ int main (int argc,const char* argv[]) Bld->ReadCustomWorkshopTypes(custom_workshop_types); if(mode) { - cout << numBuildings << endl; - vector < uint32_t > addresses; + std::cout << numBuildings << std::endl; + std::vector < uint32_t > addresses; for(uint32_t i = 0; i < numBuildings; i++) { DFHack::t_building temp; Bld->Read(i, temp); if(temp.type != 0xFFFFFFFF) // check if type isn't invalid { - string typestr; + std::string typestr; mem->resolveClassIDToClassname(temp.type, typestr); - cout << typestr << endl; + std::cout << typestr << std::endl; if(typestr == argv[1]) { //cout << buildingtypes[temp.type] << " 0x" << hex << temp.origin << endl; @@ -83,7 +85,7 @@ int main (int argc,const char* argv[]) else { // couldn't translate type, print out the vtable - cout << "unknown vtable: " << temp.vtable << endl; + std::cout << "unknown vtable: " << temp.vtable << std::endl; } } interleave_hex(DF,addresses,lines / 4); @@ -105,7 +107,7 @@ int main (int argc,const char* argv[]) && (uint32_t)z == temp.z ) { - string typestr; + std::string typestr; mem->resolveClassIDToClassname(temp.type, typestr); printf("Address 0x%x, type %d (%s), %d/%d/%d\n",temp.origin, temp.type, typestr.c_str(), temp.x1,temp.y1,temp.z); printf("Material %d %d\n", temp.material.type, temp.material.index); @@ -120,12 +122,12 @@ int main (int argc,const char* argv[]) } else { - cout << numBuildings << endl; + std::cout << numBuildings << std::endl; for(uint32_t i = 0; i < numBuildings; i++) { DFHack::t_building temp; Bld->Read(i, temp); - string typestr; + std::string typestr; mem->resolveClassIDToClassname(temp.type, typestr); printf("Address 0x%x, type %d (%s), %d/%d/%d\n",temp.origin, temp.type, typestr.c_str(), temp.x1,temp.y1,temp.z); } @@ -135,12 +137,12 @@ int main (int argc,const char* argv[]) } else { - cerr << "buildings not supported for this DF version" << endl; + std::cerr << "buildings not supported for this DF version" << std::endl; } DF->Detach(); #ifndef LINUX_BUILD - cout << "Done. Press any key to continue" << endl; + std::cout << "Done. Press any key to continue" << std::endl; cin.ignore(); #endif return 0; diff --git a/tools/examples/construction_dump.cpp b/tools/examples/construction_dump.cpp index a48b4e6a9..4eee39ed8 100644 --- a/tools/examples/construction_dump.cpp +++ b/tools/examples/construction_dump.cpp @@ -7,8 +7,9 @@ #include #include #include -using namespace std; +#include +#define DFHACK_WANT_MISCUTILS #include using namespace DFHack; @@ -21,9 +22,9 @@ int main (int numargs, const char ** args) DF = DFMgr.getSingleContext(); DF->Attach(); } - catch (exception& e) + catch (std::exception& e) { - cerr << e.what() << endl; + std::cerr << e.what() << std::endl; #ifndef LINUX_BUILD cin.ignore(); #endif @@ -35,6 +36,7 @@ int main (int numargs, const char ** args) DFHack::Constructions *Cons = DF->getConstructions(); DFHack::Materials *Mats = DF->getMaterials(); Mats->ReadInorganicMaterials(); + Mats->ReadOrganicMaterials(); uint32_t numConstr; Cons->Start(numConstr); @@ -51,13 +53,19 @@ int main (int numargs, const char ** args) printf("Construction %d/%d/%d @ 0x%x\n", con.x, con.y, con.z,con.origin); // inorganic stuff - we can recognize that printf("Material: form %d, type %d, index %d\n",con.form, con.mat_type, con.mat_idx); - string matstr = "unknown"; + std::string matstr = "unknown"; if(con.mat_type == 0) { if(con.mat_idx != 0xffffffff) matstr = Mats->inorganic[con.mat_idx].id; else matstr = "inorganic"; } + if(con.mat_type == 420) + { + if(con.mat_idx != 0xffffffff) + matstr = Mats->organic[con.mat_idx].id; + else matstr = "organic"; + } switch(con.form) { case constr_bar: diff --git a/tools/examples/creaturedump.cpp b/tools/examples/creaturedump.cpp index f8b63b51f..81fc3da8d 100644 --- a/tools/examples/creaturedump.cpp +++ b/tools/examples/creaturedump.cpp @@ -4,8 +4,10 @@ #include #include #include +#include using namespace std; +#define DFHACK_WANT_MISCUTILS #include enum likeType @@ -168,6 +170,11 @@ void printCreature(DFHack::Context * DF, const DFHack::t_creature & creature) addendl=true; } + if(creature.civ) + { + cout << "civilization: " << creature.civ; + addendl = true; + } /* cout << ", likes: "; diff --git a/tools/examples/dfitemdump.cpp b/tools/examples/dfitemdump.cpp index 0ed6413b2..cf1778326 100644 --- a/tools/examples/dfitemdump.cpp +++ b/tools/examples/dfitemdump.cpp @@ -11,6 +11,7 @@ using namespace std; #include +#include DFHack::Materials * Materials; diff --git a/tools/examples/processenum.cpp b/tools/examples/processenum.cpp new file mode 100644 index 000000000..745e94371 --- /dev/null +++ b/tools/examples/processenum.cpp @@ -0,0 +1,146 @@ +// Demonstrates the use of ProcessEnumerator +// queries the Enumerator for all DF Processes on user input. Prints them to the terminal. +// also tracks processes that were invalidated + +#include +#include +#include +#include +using namespace std; + +#include +#include +using namespace DFHack; +#ifndef LINUX_BUILD +#endif + +void printhelp () +{ + cout << "enter empty line for next try." << endl; + cout << "enter 'next' or 'n' for next test." << endl; + cout << "enter 'help' to show this text again." << endl; +} + +int inputwait (const char * prompt) +{ +inputwait_reset: + string command = ""; + cout <<"[" << prompt << "]# "; + getline(cin, command); + if(command == "help") + { + printhelp(); + goto inputwait_reset; + } + else if(command == "") + { + return 1; + } + else if(command == "next") + { + return 0; + } + else + { + cout << "Command not recognized. Try 'help' for a list of valid commands." << endl; + goto inputwait_reset; + } + return 0; +} + +int main (void) +{ + printhelp(); + cout << endl; + // first test ProcessEnumerator and BadProcesses + { + cout << "Testing ProcessEnumerator" << endl; + ProcessEnumerator Penum("Memory.xml"); + memory_info * mem; + do + { + // make the ProcessEnumerator update its list of Processes + // by passing the pointer to 'inval', we make it export expired + // processes instead of destroying them outright + // (processes expire when the OS kills them for whatever reason) + BadProcesses inval; + Penum.Refresh(&inval); + int nProc = Penum.size(); + int nInval = inval.size(); + + cout << "Processes:" << endl; + for(int i = 0; i < nProc; i++) + { + mem = Penum[i]->getDescriptor(); + cout << "DF instance: " << Penum[i]->getPID() + << ", " << mem->getVersion() << endl; + } + + cout << "Invalidated:" << endl; + for(int i = 0; i < nInval; i++) + { + mem = inval[i]->getDescriptor(); + cout << "DF instance: " << inval[i]->getPID() + << ", " << mem->getVersion() << endl; + } + } + while(inputwait("ProcessEnumerator")); + } + // next test ContextManager and BadContexts + { + cout << "Testing ContextManager" << endl; + ContextManager Cman("Memory.xml"); + memory_info * mem; + do + { + // make the ContextManager update its list of Contexts + // by passing the pointer to 'inval', we make it export expired + // contexts instead of destroying them outright + // (contexts expire when the OS kills their process for whatever + // reason) + BadContexts inval; + Cman.Refresh(&inval); + int nCont = Cman.size(); + int nInval = inval.size(); + DFHack::Context * cont = Cman.getSingleContext(); + if(cont) + { + if(cont->Attach()) + { + DFHack::Maps * mapz = cont->getMaps(); + cont->Suspend(); + mapz->Start(); + cont->Resume(); + } + + bool result = cont->Detach(); + if(!result) + { + cerr << "Something went horribly wrong during detach" << endl; + } + } + + cout << "Contexts:" << endl; + for(int i = 0; i < nCont; i++) + { + mem = Cman[i]->getMemoryInfo(); + cout << "DF instance: " << Cman[i]->getProcess()->getPID() + << ", " << mem->getVersion() << endl; + } + + cout << "Invalidated:" << endl; + for(int i = 0; i < nInval; i++) + { + mem = inval[i]->getMemoryInfo(); + cout << "DF instance: " << inval[i]->getProcess()->getPID() + << ", " << mem->getVersion() << endl; + } + } + while(inputwait("ContextManager")); + } + #ifndef LINUX_BUILD + cout << "Done. Press any key to continue" << endl; + cin.ignore(); + #endif + return 0; +} diff --git a/tools/examples/spatterdump.cpp b/tools/examples/spatterdump.cpp index 3d3b92102..3a2ba82b2 100644 --- a/tools/examples/spatterdump.cpp +++ b/tools/examples/spatterdump.cpp @@ -8,7 +8,7 @@ #include #include using namespace std; - +#define DFHACK_WANT_MISCUTILS #include using namespace DFHack; diff --git a/tools/examples/treedump.cpp b/tools/examples/treedump.cpp index 7e54db674..71b386220 100644 --- a/tools/examples/treedump.cpp +++ b/tools/examples/treedump.cpp @@ -9,6 +9,7 @@ #include using namespace std; +#define DFHACK_WANT_MISCUTILS #include int main (int numargs, const char ** args) @@ -34,18 +35,17 @@ int main (int numargs, const char ** args) #endif return 1; } - + DFHack::Process* p = DF->getProcess(); DFHack::memory_info* mem = DF->getMemoryInfo(); DFHack::Position * pos = DF->getPosition(); DFHack::Vegetation * v = DF->getVegetation(); DFHack::Materials * mat = DF->getMaterials(); mat->ReadOrganicMaterials(); - + int32_t x,y,z; pos->getCursorCoords(x,y,z); - - + uint32_t numVegs = 0; v->Start(numVegs); if(x == -30000) @@ -89,7 +89,7 @@ int main (int numargs, const char ** args) } } v->Finish(); - + #ifndef LINUX_BUILD cout << "Done. Press any key to continue" << endl; cin.ignore(); diff --git a/tools/playground/CMakeLists.txt b/tools/playground/CMakeLists.txt index ee43d8c20..a28597475 100644 --- a/tools/playground/CMakeLists.txt +++ b/tools/playground/CMakeLists.txt @@ -1,5 +1,8 @@ # don't use this file directly. use the one in the root folder of the project +# only build this stuff when BUILD_DFHACK_PLAYGROUND is set to ON +IF (BUILD_DFHACK_PLAYGROUND) + # this is required to ensure we use the right configuration for the system. IF(UNIX) add_definitions(-DLINUX_BUILD) @@ -9,10 +12,6 @@ ENDIF(UNIX) ADD_EXECUTABLE(dfmoodump moodump.cpp) TARGET_LINK_LIBRARIES(dfmoodump dfhack) -# for trying out some 'stuff' -ADD_EXECUTABLE(dftest test.cpp) -TARGET_LINK_LIBRARIES(dftest dfhack) - # bauxite - turn all mechanisms into bauxite mechanisms # Author: Alex Legg #ADD_EXECUTABLE(dfbauxite dfbauxite.cpp) @@ -55,4 +54,30 @@ TARGET_LINK_LIBRARIES(dfcatsplosion dfhack) # df directly # Author: belal #ADD_EXECUTABLE(dfrenamer renamer.cpp) -#TARGET_LINK_LIBRARIES(dfrenamer dfhack) \ No newline at end of file +#TARGET_LINK_LIBRARIES(dfrenamer dfhack) + +# this needs the C bindings +IF(BUILD_DFHACK_C_BINDIGS) + # for trying out some 'stuff' + ADD_EXECUTABLE(dftest test.cpp) + TARGET_LINK_LIBRARIES(dftest dfhack) + install(TARGETS + dftest + RUNTIME DESTINATION bin + ) +ENDIF(BUILD_DFHACK_C_BINDIGS) + +install(TARGETS +dfmoodump +dfdigger +dfdigger2 +dfcatsplosion +RUNTIME DESTINATION bin +) +IF(UNIX) + install(TARGETS + dfincremental + RUNTIME DESTINATION bin + ) +ENDIF(UNIX) +ENDIF (BUILD_DFHACK_PLAYGROUND) \ No newline at end of file diff --git a/tools/playground/SegmentedFinder.h b/tools/playground/SegmentedFinder.h new file mode 100644 index 000000000..c50cc4c6f --- /dev/null +++ b/tools/playground/SegmentedFinder.h @@ -0,0 +1,314 @@ +#ifndef SEGMENTED_FINDER_H +#define SEGMENTED_FINDER_H + +class SegmentedFinder; +class SegmentFinder +{ + public: + SegmentFinder(DFHack::t_memrange & mr, DFHack::Context * DF, SegmentedFinder * SF) + { + _DF = DF; + mr_ = mr; + mr_.buffer = (uint8_t *)malloc (mr_.end - mr_.start); + DF->ReadRaw(mr_.start,(mr_.end - mr_.start),mr_.buffer); + _SF = SF; + } + ~SegmentFinder() + { + delete mr_.buffer; + } + + template + bool Find (needleType needle, const uint8_t increment , vector &newfound, comparator oper) + { + //loop + for(uint64_t offset = 0; offset < (mr_.end - mr_.start) - sizeof(hayType); offset += increment) + { + if( oper(_SF,(hayType *)(mr_.buffer + offset), needle) ) + newfound.push_back(mr_.start + offset); + } + return !newfound.empty(); + } + + template < class needleType, class hayType, typename comparator > + uint64_t FindInRange (needleType needle, comparator oper, uint64_t start, uint64_t length) + { + uint64_t stopper = min((mr_.end - mr_.start) - sizeof(hayType), (start - mr_.start) - sizeof(hayType) + length); + //loop + for(uint64_t offset = start - mr_.start; offset < stopper; offset +=1) + { + if( oper(_SF,(hayType *)(mr_.buffer + offset), needle) ) + return mr_.start + offset; + } + return 0; + } + + template + bool Filter (needleType needle, vector &found, vector &newfound, comparator oper) + { + for( uint64_t i = 0; i < found.size(); i++) + { + if(mr_.isInRange(found[i])) + { + uint64_t corrected = found[i] - mr_.start; + if( oper(_SF,(hayType *)(mr_.buffer + corrected), needle) ) + newfound.push_back(found[i]); + } + } + return !newfound.empty(); + } + private: + friend class SegmentedFinder; + SegmentedFinder * _SF; + DFHack::Context * _DF; + DFHack::t_memrange mr_; +}; + +class SegmentedFinder +{ + public: + SegmentedFinder(vector & ranges, DFHack::Context * DF) + { + _DF = DF; + for(int i = 0; i < ranges.size(); i++) + { + segments.push_back(new SegmentFinder(ranges[i], DF, this)); + } + } + ~SegmentedFinder() + { + for(int i = 0; i < segments.size(); i++) + { + delete segments[i]; + } + } + SegmentFinder * getSegmentForAddress (uint64_t addr) + { + for(int i = 0; i < segments.size(); i++) + { + if(segments[i]->mr_.isInRange(addr)) + { + return segments[i]; + } + } + return 0; + } + template + bool Find (const needleType needle, const uint8_t increment, vector &found, comparator oper) + { + found.clear(); + for(int i = 0; i < segments.size(); i++) + { + segments[i]->Find(needle, increment, found, oper); + } + return !(found.empty()); + } + + template < class needleType, class hayType, typename comparator > + uint64_t FindInRange (needleType needle, comparator oper, uint64_t start, uint64_t length) + { + SegmentFinder * sf = getSegmentForAddress(start); + if(sf) + { + return sf->FindInRange(needle, oper, start, length); + } + return 0; + } + + template + bool Filter (const needleType needle, vector &found, comparator oper) + { + vector newfound; + for(int i = 0; i < segments.size(); i++) + { + segments[i]->Filter(needle, found, newfound, oper); + } + found.clear(); + found = newfound; + return !(found.empty()); + } + + template + bool Incremental (needleType needle, const uint8_t increment ,vector &found, comparator oper) + { + if(found.empty()) + { + return Find (needle,increment,found,oper); + } + else + { + return Filter (needle,found,oper); + } + } + + template + T * Translate(uint64_t address) + { + for(int i = 0; i < segments.size(); i++) + { + if(segments[i]->mr_.isInRange(address)) + { + return (T *) (segments[i]->mr_.buffer + address - segments[i]->mr_.start); + } + } + return 0; + } + + template + T Read(uint64_t address) + { + return *Translate(address); + } + + template + bool Read(uint64_t address, T& target) + { + T * test = Translate(address); + if(test) + { + target = *test; + return true; + } + return false; + } + private: + DFHack::Context * _DF; + vector segments; +}; + +template +bool equalityP (SegmentedFinder* s, T *x, T y) +{ + return (*x) == y; +} + +struct vecTriplet +{ + uint32_t start; + uint32_t finish; + uint32_t alloc_finish; +}; + +template +bool vectorLength (SegmentedFinder* s, vecTriplet *x, Needle &y) +{ + if(x->start <= x->finish && x->finish <= x->alloc_finish) + if((x->finish - x->start) == y) + return true; + return false; +} + +// find a vector of 32bit pointers, where an object pointed to has a string 'y' as the first member +bool vectorString (SegmentedFinder* s, vecTriplet *x, const char *y) +{ + uint32_t object_ptr; + uint32_t idx = x->start; + // iterate over vector of pointers + for(uint32_t idx = x->start; idx < x->finish; idx += sizeof(uint32_t)) + { + // deref ptr idx, get ptr to object + if(!s->Read(idx,object_ptr)) + { + return false; + } + // deref ptr to first object, get ptr to string + uint32_t string_ptr; + if(!s->Read(object_ptr,string_ptr)) + return false; + // get string location in our local cache + char * str = s->Translate(string_ptr); + if(!str) + return false; + if(strcmp(y, str) == 0) + return true; + } + return false; +} + +// find a vector of 32bit pointers, where the first object pointed to has a string 'y' as the first member +bool vectorStringFirst (SegmentedFinder* s, vecTriplet *x, const char *y) +{ + uint32_t object_ptr; + uint32_t idx = x->start; + // deref ptr idx, get ptr to object + if(!s->Read(idx,object_ptr)) + { + return false; + } + // deref ptr to first object, get ptr to string + uint32_t string_ptr; + if(!s->Read(object_ptr,string_ptr)) + return false; + // get string location in our local cache + char * str = s->Translate(string_ptr); + if(!str) + return false; + if(strcmp(y, str) == 0) + return true; + return false; +} + +// test if the address is between vector.start and vector.finish +// not very useful alone, but could be a good step to filter some things +bool vectorAddrWithin (SegmentedFinder* s, vecTriplet *x, uint32_t address) +{ + if(address < x->finish && address >= x->start) + return true; + return false; +} + +// test if an object address is within the vector of pointers +// +bool vectorOfPtrWithin (SegmentedFinder* s, vecTriplet *x, uint32_t address) +{ + uint32_t object_ptr; + uint32_t idx = x->start; + for(uint32_t idx = x->start; idx < x->finish; idx += sizeof(uint32_t)) + { + if(!s->Read(idx,object_ptr)) + { + return false; + } + if(object_ptr == address) + return true; + } + return false; +} + +bool vectorAll (SegmentedFinder* s, vecTriplet *x, int ) +{ + if(x->start <= x->finish && x->finish <= x->alloc_finish) + { + if(s->getSegmentForAddress(x->start) == s->getSegmentForAddress(x->finish) + && s->getSegmentForAddress(x->finish) == s->getSegmentForAddress(x->alloc_finish)) + return true; + } + return false; +} + +struct Bytestream +{ + uint32_t length; + void * object; +}; + +bool findBytestream (SegmentedFinder* s, void *addr, Bytestream compare ) +{ + if(memcmp(addr, compare.object, compare.length) == 0) + return true; + return false; +} + +bool findString (SegmentedFinder* s, uint32_t *addr, const char * compare ) +{ + // read string pointer, translate to local scheme + char *str = s->Translate(*addr); + // verify + if(!str) + return false; + if(strcmp(str, compare) == 0) + return true; + return false; +} + +#endif // SEGMENTED_FINDER_H \ No newline at end of file diff --git a/tools/playground/hexsearch2.c b/tools/playground/hexsearch2.c new file mode 100644 index 000000000..44872e2d1 --- /dev/null +++ b/tools/playground/hexsearch2.c @@ -0,0 +1,1355 @@ +/* + * Author: Silas Dunsmore aka 0x517A5D vim:ts=4:sw=4 + * + * Released under the MIT X11 license; feel free to use some or all of this + * code, as long as you include the copyright and license statement (below) + * in all copies of the source code. In fact, I truly encourage reuse. + * + * If you do use large portions of this code, I suggest but do not require + * that you keep this code in a seperate file (such as this hexsearch.c file) + * so that it is clear that the terms of the license do not also apply to + * your code. + * + * Should you make fundamental changes, or bugfixes, to this code, I would + * appreciate it if you would give me a copy of your changes. + * + * + * Be advised that I use several advanced idioms of the C language: + * macro expansion, stringification, and variable argument functions. + * You do not need to understand them. Usage should be obvious. + * + * + * Lots of logging output is sent to OutputDebugString(). + * The Sysinternals' DebugView program is very useful in monitering this. + * + * + * Copyright (C) 2007-2008 Silas Dunsmore + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * See also: http://www.opensource.org/licenses/mit-license.php + * and http://en.wikipedia.org/wiki/MIT_License + */ + +#include // va_list and friends +#include // vsnprintf() +#include // atexit() +#include +#define WINVER 0x0500 // OpenThread() +#define WIN32_LEAN_AND_MEAN +#include +#include +#include "hexsearch2.h" + + +#define SKIPME 0xFEDCBA98 // token for internal use only. + + +// exported globals +HANDLE df_h_process, df_h_thread; +DWORD df_pid, df_main_win_tid; +DWORD here[16]; +DWORD target[16]; +char *errormessage; +DWORD df_memory_base, df_memory_start, df_memory_end; + + +// local globals +static BOOL change_page_permissions; +static BOOL suspended; +static BYTE *copy_of_df_memory; +static int nexthere; +static int nexttarget; +static DWORD searchmemstart, searchmemend; + + +#define dump(x) d_printf("%-32s == %08X\n", #x, (x)); +#define dumps(x) d_printf("%-32s == '%s'\n", #x, (x)); + + +// ============================================================================ +// send info to KERNEL32:OutputDebugString(), useful for non-console programs. +// you can watch this with SysInternals' DebugView. +// http://www.microsoft.com/technet/sysinternals/Miscellaneous/DebugView.mspx +// +void d_printf(const char *format, ...) +{ + va_list va; + char debugstring[4096]; // debug strings can be up to 4K. + + va_start(va, format); + _vsnprintf(debugstring, sizeof(debugstring) - 2, format, va); + va_end(va); + + OutputDebugString(debugstring); +} + + +// ============================================================================ +BOOL isvalidaddress(DWORD address) +{ + MEMORY_BASIC_INFORMATION mbi; + return (VirtualQueryEx(df_h_process, (void *)address, &mbi, sizeof(mbi)) + == sizeof(mbi) && mbi.State == MEM_COMMIT); +} + + +// ---------------------------------------------------------------------------- +BOOL peekarb(DWORD address, OUT void *data, DWORD len) +{ + BOOL ok = FALSE; + DWORD succ = 0; + DWORD OldProtect; + MEMORY_BASIC_INFORMATION mbi = {0, 0, 0, 0, 0, 0, 0}; + + errormessage = ""; + + // do {} while(0) is a construct that lets you abort a piece of code + // in the middle without using gotos. + + do + { + + if ((succ = VirtualQueryEx(df_h_process, (BYTE *)address + len - 1, + &mbi, sizeof(mbi))) != sizeof(mbi)) + { + dump(address + len - 1); + dump(succ); + errormessage = "peekarb(): VirtualQueryEx() on end address failed"; + break; + } + if (mbi.State != MEM_COMMIT) + { + dump(mbi.State); + errormessage = "peekarb(): VirtualQueryEx() says end address " + "is not MEM_COMMIT"; + break; + } + + if ((succ = VirtualQueryEx(df_h_process, (void *)address, &mbi, + sizeof(mbi))) != sizeof(mbi)) + { + dump(address); + dump(succ); + errormessage ="peekarb(): VirtualQueryEx() on start address failed"; + break; + } + if (mbi.State != MEM_COMMIT) + { + dump(mbi.State); + errormessage = "peekarb(): VirtualQueryEx() says start address is " + "not MEM_COMMIT"; + break; + } + + if (change_page_permissions) + { + if (!VirtualProtectEx(df_h_process, mbi.AllocationBase, + mbi.RegionSize, PAGE_READWRITE, &OldProtect)) + { + errormessage = "peekarb(): VirtualProtectEx() failed"; + break; + } + } + + if (!ReadProcessMemory(df_h_process, (void *)address, data, len, &succ)) + { + errormessage = "peekarb(): ReadProcessMemory() failed"; + + // note that we do NOT break here, as we want to restore the + // page protection. + } + else if (len != succ) + { + errormessage = "peekarb(): ReadProcessMemory() returned " + "partial read"; + } + else ok = TRUE; + + if (change_page_permissions) + { + if (!VirtualProtectEx(df_h_process, mbi.AllocationBase, + mbi.RegionSize, OldProtect, &OldProtect)) + { + errormessage = "peekarb(): undo VirtualProtectEx() failed"; + break; + } + } + } while (0); + + if (errormessage != NULL && strlen(errormessage) != 0) + { + d_printf("%s\n", errormessage); + dump(address); + //dump(len); + //dump(succ); + //dump(mbi.AllocationBase); + } + + return(ok); +} + + +// ---------------------------------------------------------------------------- +BYTE peekb(DWORD address) +{ + BYTE data; + return(peekarb(address, &data, sizeof(data)) ? data : 0); + // pop quiz: why don't we set errormessage? +} + + +// ---------------------------------------------------------------------------- +WORD peekw(DWORD address) +{ + WORD data; + return(peekarb(address, &data, sizeof(data)) ? data : 0); +} + + +// ---------------------------------------------------------------------------- +DWORD peekd(DWORD address) +{ + DWORD data; + return(peekarb(address, &data, sizeof(data)) ? data : 0); +} + + +// ---------------------------------------------------------------------------- +char *peekstr(DWORD address, OUT char *data, DWORD maxlen) +{ + BYTE c; + int i = 0; + + data[0] = '\0'; + if (!isvalidaddress(address)) return(data); + + while (--maxlen && (c = peekb(address++)) >= ' ' && c <= '~') + { + if (!isvalidaddress(address)) return(data); + data[i++] = c; + data[i] = '\0'; + } + // for convenience + return(data); +} + + +// ---------------------------------------------------------------------------- +char *peekwstr(DWORD address, OUT char *data, DWORD maxlen) +{ + BYTE c; + int i = 0; + + data[0] = '\0'; + if (!isvalidaddress(address)) return(data); + + while (--maxlen && (c = peekb(address++)) >= ' ' && c <= '~' && peekb(address++) == 0) + { + if (!isvalidaddress(address)) + { + return(data); + } + data[i++] = c; + data[i] = '\0'; + } + // for convenience + return(data); +} + + +// ---------------------------------------------------------------------------- +BOOL pokearb(DWORD address, const void *data, DWORD len) +{ + BOOL ok = FALSE; + DWORD succ = 0; + DWORD OldProtect; + MEMORY_BASIC_INFORMATION mbi; + + errormessage = ""; + + do + { + if (!isvalidaddress(address)) + { + errormessage = "pokearb() failed: invalid address"; + break; + } + + if (!isvalidaddress(address + len - 1)) + { + errormessage = "pokearb() failed: invalid end address"; + break; + } + + if (change_page_permissions) + { + if (VirtualQueryEx(df_h_process, (void *)address, &mbi, sizeof(mbi)) != sizeof(mbi)) + { + errormessage = "pokearb(): VirtualQueryEx() failed"; + break; + } + + if (!VirtualProtectEx(df_h_process, mbi.AllocationBase, mbi.RegionSize, PAGE_READWRITE, &OldProtect)) + { + errormessage = "pokearb(): VirtualProtectEx() failed"; + break; + } + } + + if (!WriteProcessMemory(df_h_process, (void *)address, data, len, &succ)) + { + errormessage = "pokearb(): WriteProcessMemory() failed"; + // note that we do NOT break here, as we want to restore the + // page protection. + } + else if (len != succ) + { + errormessage = "pokearb(): WriteProcessMemory() did partial write"; + } + else + { + ok = TRUE; + } + + if (change_page_permissions) + { + if (!VirtualProtectEx(df_h_process, mbi.AllocationBase, mbi.RegionSize, OldProtect, &OldProtect)) + { + errormessage = "pokearb(): undo VirtualProtectEx() failed"; + break; + } + } + } while (0); + + if (errormessage != NULL && strlen(errormessage) != 0) + { + d_printf("%s\n", errormessage); + dump(address); + //dump(len); + //dump(succ); + //dump(mbi.AllocationBase); + } + + return(ok); +} + + +// ---------------------------------------------------------------------------- +BOOL pokeb(DWORD address, BYTE data) +{ + return(pokearb(address, &data, sizeof(data))); +} + + +// ---------------------------------------------------------------------------- +BOOL pokew(DWORD address, WORD data) +{ + return(pokearb(address, &data, sizeof(data))); +} + + +// ---------------------------------------------------------------------------- +BOOL poked(DWORD address, DWORD data) +{ + return(pokearb(address, &data, sizeof(data))); +} + + +// ---------------------------------------------------------------------------- +BOOL pokestr(DWORD address, const BYTE *data) +{ +// can't include a "\x00" in the string, obviously. + return(pokearb(address, data, strlen((const char *)data))); +} + + +// ---------------------------------------------------------------------------- +// helper function for hexsearch. recursive, with backtracking. +// this checks if a particular memory offset matches the given pattern. +// returns location of start of match (in the cached copy of DF memory). +// returns NULL on mismatch. +// +// TODO: there is a harmless bug in the recursion related to the very first +// recursive call, probably on each level of recursion. +static BYTE *hexsearch_match2(BYTE *p, DWORD token1, va_list va) +{ + static DWORD recursion_level = 0; + DWORD tokensprocessed = 0; + DWORD token = 0x4DECADE5, b1, b2, lo, hi; + BYTE *retval = p; + BOOL ok = FALSE, lookedahead; + int savenexthere = nexthere; + int savenexttarget = nexttarget; + + // TODO token is being used without being inited on recursion. + + //if (recursion_level) dump(recursion_level); + //if (recursion_level) dump(p); + //if (recursion_level) dump(tokensprocessed); + + if (token1 != SKIPME) + { + lookedahead = TRUE; + token = token1; + tokensprocessed = 1; + } + + while (1) + { + // if the previous argument looked ahead, token is already set. + // peekahead is currently unused. + if (!lookedahead) + { + token = va_arg(va, unsigned int); + tokensprocessed++; + } + lookedahead = FALSE; + + // exact-match a byte, advance. + if (token <= 0xFF) + { + if (token != *p++) break; + } + + // the remaining tokens (the metas) ought to be a switch. + // but that would make it hard to break out of the while(1). + + // if we hit an EOL, the match succeeded. + else if (token == EOL) + { + ok = TRUE; + break; + } + + // match any byte, advance. + else if (token == ANYBYTE) + { + p++; + } + + // return the address of the next matching byte instead of the + // address of the start of the pattern. don't advance. + else if (token == HERE) + { + retval = p; + here[nexthere++] = (DWORD)p; // needs postprocessing. + } + + // accept either of the next two parameters as a match. advance. + // note that this does not count as peeking. + else if (token == EITHER) + { + if ((b1 = va_arg(va, unsigned int)) > 0xFF) + { + d_printf("EITHER: not followed by a legal token (byte1): %08X\n", b1); + break; + } + tokensprocessed++; + if ((b2 = va_arg(va, unsigned int)) > 0xFF) + { + d_printf("EITHER: not followed by a legal token (byte2): %08X\n", b2); + break; + } + tokensprocessed++; + if (!(*p == b1 || *p == b2)) break; + p++; + } + + #ifdef FF_OR_00 //DEPRECATED + // accept either 0x00 or 0xFF. advance. + else if (token == FF_OR_00) + { + if (!(*p == 0x00 || *p == 0xFF)) + { + break; + } + p++; + } + #endif + + // set low value for range comparison. don't advance. DEPRECATED. + else if (token == RANGE_LO) + { + if ((lo = va_arg(va, unsigned int)) > 0xFF) + { + d_printf("RANGE_LO: not followed by a legal token: %08X\n", lo); + break; + } + tokensprocessed++; + // Q: peek here to ensure next token is RANGE_HI ? + } + + // set high value for range comparison, and do comparison. advance. + // DEPRECATED. + else if (token == RANGE_HI) + { + if ((hi = va_arg(va, unsigned int)) > 0xFF) { + d_printf("RANGE_HI: not followed by a legal token: %08X\n", hi); + break; + } + if (*p < lo || *p > hi) + { + break; + } + p++; + tokensprocessed++; + } + + // do a byte-size range comparison + else if (token == BYTERANGE) + { + if ((lo = va_arg(va, unsigned int)) > 0xFF) + { + d_printf("BYTERANGE: not followed by a legal token: %08X\n", lo); + break; + } + tokensprocessed++; + + if ((hi = va_arg(va, unsigned int)) > 0xFF) + { + d_printf("BYTERANGE: not followed by a legal token: %08X\n", hi); + break; + } + if (*p < lo || *p > hi) + { + break; + } + p++; + tokensprocessed++; + } + + // do a dword-size range comparison + else if (token == DWORDRANGE) + { + lo = va_arg(va, unsigned int); + tokensprocessed++; + + hi = va_arg(va, unsigned int); + if (*(DWORD *)p < lo || *(DWORD *)p > hi) + { + break; + } + p++; + tokensprocessed++; + } + + // this is the fun one. this is where we recurse. + else if (token == SKIP_UP_TO) + { + DWORD len; + BYTE * subretval; + + len = va_arg(va, unsigned int) + 1; + tokensprocessed++; + + while (len) + { + // um. This is a kludge. It ought to work to not set any + // heres or targets if we're in a recursion. (not tested) + int savenexthere; + int savenexttarget; + + // I think it's not technically legal to copy va_lists; + // but it should work on any stack-based machine, which is + // everything except old Crays and weird dataflow processors. + + savenexthere = nexthere; + savenexttarget = nexttarget; + //dump(tokensprocessed); + //dump(recursion_level); + //dumps("-->"); + recursion_level++; + subretval = hexsearch_match2(p, SKIPME, va); + recursion_level--; + //dumps("<--"); + //dump(recursion_level); + //dump(tokensprocessed); + nexthere = savenexthere; + nexttarget = savenexttarget; + if (subretval != NULL) { + // okay, we now know that the bytes starting at p + // match the remainder of the pattern. + // Nonetheless, for ease of programming, we will + // go through the motions instead of trying to + // early-out. (Basically done for HERE tokens.) + break; + } + + p++; + len--; + } + if (subretval != NULL) + { + continue; + } + // no match within nn bytes, abort. + break; + } + + // exact-match a dword. advance 4. + else if (token == DWORD_) + { + DWORD d = va_arg(va, unsigned int); + if (*(DWORD *)p != d) break; + p += 4; + tokensprocessed++; + } + + // match any dword. advance 4. + else if (token == ANYDWORD) + { + p += 4; + } + + // match any legal address in + else if (token == ADDRESS) + { + // program text. advance 4. + if (*(DWORD *)p < df_memory_start) + { + break; + } + if (*(DWORD *)p > df_memory_end) + { + break; + } + p += 4; + } + + // match any call. advance 5. + else if (token == CALL) + { + if (*p++ != 0xE8) + { + break; + } + target[nexttarget++] = *(DWORD *)p + (DWORD)p + 4; +#if 0 + if (*(DWORD *)p > DF_CODE_SIZE + && *(DWORD *)p < (DWORD)-DF_CODE_SIZE) + break; +#endif + p += 4; + } + + // match any short or near jump. + else if (token == JUMP) + { + // advance 2 or 5 respectively. + if (*p == 0xEB) + { + target[nexttarget++] = *(signed char *)(p+1) + (DWORD)p + 1; + p += 2; + continue; + } + + if (*p++ != 0xE9) + { + break; + } + + target[nexttarget++] = *(DWORD *)p + (DWORD)p + 4; +#if 0 + if (*(DWORD *)p > DF_CODE_SIZE + && *(DWORD *)p < (DWORD)-DF_CODE_SIZE) + break; +#endif + p += 4; + } + + // match a JZ instruction + else if (token == JZ) + { + if (*p == 0x74) + { + target[nexttarget++] = *(signed char *)(p+1) + (DWORD)p + 2; + p += 2; + continue; + } + else if (*p == 0x0F && *(p+1) == 0x84 + && (*(p+4) == 0x00 || *(p+4) == 0xFF) // assume dist < 64k + && (*(p+5) == 0x00 || *(p+5) == 0xFF)) + { + target[nexttarget++] = *(DWORD *)(p+2) + (DWORD)p + 6; + p += 6; + continue; + } + else break; + } + + // match a JNZ instruction + else if (token == JNZ) + { + if (*p == 0x75) { + target[nexttarget++] = *(signed char *)(p+1) + (DWORD)p + 2; + p += 2; + continue; + } + else if (*p == 0x0F && *(p+1) == 0x85 + && (*(p+4) == 0x00 || *(p+4) == 0xFF) // assume dist < 64k + && (*(p+5) == 0x00 || *(p+5) == 0xFF) + ) { + target[nexttarget++] = *(DWORD *)(p+2) + (DWORD)p + 6; + p += 6; + continue; + } + else break; + } + + // match any conditional jump + else if (token == JCC) + { + if (*p >= 0x70 && *p <= 0x7F) + { + target[nexttarget++] = *(signed char *)(p+1) + (DWORD)p + 2; + p += 2; + continue; + } + else if (*p == 0x0F && *(p+1) >= 0x80 && *(p+1) <= 0x8F + && (*(p+4) == 0x00 || *(p+4) == 0xFF) // assume dist < 64k + && (*(p+5) == 0x00 || *(p+5) == 0xFF)) + { + target[nexttarget++] = *(DWORD *)(p+2) + (DWORD)p + 6; + p += 6; + continue; + } + else break; + } + + // unknown token, abort + else + { + d_printf("unknown token: %08X\n", token); + dump(p); + dump(recursion_level); + break; + } // end of huge if-else + + } // end of while(1) + + if (!ok) + { + retval = NULL; + nexthere = savenexthere; + nexttarget = savenexttarget; + } + return (retval); +} + + +// ============================================================================ +// The name has changed because the API HAS CHANGED! +// +// Now instead of returning HERE, it always returns the start of the match. +// +// However, there is an array, here[], that is filled with the locations of +// the HERE tokens. +// (Starting at 1. here[0] is a copy of the start of the match.) +// +// The here[] array, starting at 1, is filled with the locations of the +// HERE token. +// here[0] is a copy of the start of the match. +// +// Also, the target[] array, starting at 1, is filled with the target +// addresses of all CALL, JMP, JZ, JNZ, and JCC tokens. +// +// Finally, you no longer pass it a search length. Instead, each set of +// search terms must end with an EOL. +// +// +// +// Okay, I admit this one is complicated. Treat it as a black box. +// +// Search Dwarf Fortress's code and initialized data segments for a pattern. +// (Does not search stack, heap, or thread-local memory.) +// +// Parameters: any number of search tokens, all unsigned ints. +// The last token must be EOL. +// +// 0x00 - 0xFF: Match this byte. +// EOL: End-of-list. The match succeeds when this token is reached. +// ANYBYTE: Match any byte. +// DWORD_: Followed by a dword. Exact-match the dword. +// Equivalent to 4 match-this-byte tokens. +// ANYDWORD: Match any dword. Equivalant to 4 ANYBYTEs. +// HERE: Put the current address into the here[] array. +// SKIP_UP_TO, nn: Allow up to nn bytes between the previous match +// and the next match. The next token must be a match-this-byte +// token. There is sweet, sweet backtracking. +// EITHER: Accept either of the next two tokens as a match. +// Both must be match-this-byte tokens. +// RANGE_LO, nn: Set low byte for a range comparison. DEPRECATED. +// RANGE_HI, nn: Set high byte for a range comparison, and do the +// comparison. Should immediately follow a RANGE_LO. DEPRECATED. +// BYTERANGE, nn, mm: followed by two bytes, the low and high limits +// of the range. This is the new way to do ranges. +// DWORDRANGE, nnnnnnnn, mmmmmmmm: works like BYTERANGE. +// ADDRESS: Accept any legal address in the program's text. +// DOES NOT accept pointers into heap space and such. +// CALL: Match a near call instruction to a reasonable address. +// JUMP: Match a short or near unconditional jump to a reasonable +// address. +// JZ: Match a short or long jz (jump if zero) instruction. +// JNZ: Match a short or long jnz (jump if not zero) instruction. +// JCC: Match any short or long conditional jump instruction. +// More tokens can easily be added. +// +// Returns the offset in Dwarf Fortress of the first match of the pattern. +// Also sets global variables here[] and target[]. +// +// Note: starting a pattern with ANYBYTE, ANYDWORD, SKIP_UP_TO, or EOL +// is explicitly illegal. +// +// +// implementation detail: search() uses a cached copy of the memory, so +// poke()s and patch()s will not be reflected in the searches. +// +// implementation detail: Q: why don't we discard count and always use EOL? +// A: because we need a fixed parameter to start the va_list. +// (Hmm, could we grab address of a local variable, walk the stack +// until we see &hexsearch, and use that address to init va_list?) +// (No, dummy, because &hexsearch is not on the stack. The stack +// holds the return address.) +// (Could we grab the EBP register and treat it as a stack frame?) +// (Maybe, but the compiler decides if EBP really is a stack frame, +// so that would be an implementation dependency. Don't do it.) +// +// TODO: should be a way to repeat a search in case we want the second or +// eleventh occurance. +// +// TODO: allow EITHER to accept arbitrary (sets of) tokens. +// (How would that work? Have two sub-patterns, each terminating +// with EOL?) +// +DWORD hexsearch2(DWORD token1, ...) +{ + DWORD size; + BYTE *nextoffset, *foundit; + DWORD token; + int i; + va_list va; + + for (i = 0; i < 16; i++) here[i] = 0; + for (i = 0; i < 16; i++) target[i] = 0; + + nexthere = 1; + nexttarget = 1; + + if ( token1 == ANYBYTE + || token1 == ANYDWORD + || token1 == SKIP_UP_TO + || token1 == HERE + || token1 == EOL ) + { + return 0; + } + + dump(searchmemstart); + dump(searchmemend); + dump(df_memory_start); + dump(copy_of_df_memory); + nextoffset = copy_of_df_memory; + nextoffset += (searchmemstart - df_memory_start); + dump(nextoffset); + size = searchmemend - searchmemstart; + dump(size); + + while (1) + { + // for speed, if we start with a raw byte, use a builtin function + // to skip ahead to the next actual occurance. + if (token1 <= 0xFF) + { + nextoffset = (BYTE *)memchr(nextoffset, token1, + size - (nextoffset - copy_of_df_memory)); + if (nextoffset == NULL) break; + } + + va_start(va, token1); + foundit = hexsearch_match2(nextoffset, token1, va); + va_end(va); + + if (foundit) + { + break; + } + + if ((DWORD)(++nextoffset - copy_of_df_memory - (searchmemstart - df_memory_start)) >= size) + { + break; + } + + } + + if (!foundit) + { + d_printf("hexsearch2(%X", token1); + i = 0; + va_start(va, token1); + do + { + d_printf(",%X", token = va_arg(va, DWORD)); + } while (EOL != token && i++ < 64); + va_end(va); + if (i >= 64) d_printf("..."); + d_printf(")\n"); + d_printf("search failed!\n"); + for (i = 0; i < 16; i++) + { + here[i] = 0; + target[i] = 0; + } + return 0; + } + + here[0] = (DWORD)foundit; + for (i = 0; i < 16; i++) + { + if (i < nexthere && here[i] != 0) + { + here[i] += df_memory_start - (DWORD)copy_of_df_memory; + } + else here[i] = 0; + } + for (i = 0; i < 16; i++) + { + if (i < nexttarget && target[i] != 0) + { + target[i] += df_memory_start - (DWORD)copy_of_df_memory; + } + else target[i] = 0; + } + + return df_memory_start + (foundit - copy_of_df_memory); +} + + +// ---------------------------------------------------------------------------- +void set_hexsearch2_limits(DWORD start, DWORD end) +{ + if (end < start) end = start; + + searchmemstart = start >= df_memory_start ? start : df_memory_start; + searchmemend = end >= df_memory_start && end <= df_memory_end ? + end : df_memory_end; +} + + +// ============================================================================ +// helper function for patch and verify. does the actual work. +static BOOL vpatchengine(BOOL mode, DWORD address, va_list va) +{ + // mode: TRUE == patch, FALSE == verify + DWORD next = address, a, c; + // a is token, c is helper value, b is asm instruction byte to use. + BYTE b; + BOOL ok = FALSE; + + while (1) + { + //if (length == 0) { ok = TRUE; break; } + //length--; + a = va_arg(va, unsigned int); + + if (a == EOL) + { + ok = TRUE; + break; + } + + if (a == DWORD_) + { + //if (length-- == 0) break; + c = va_arg(va, unsigned int); + if (mode ? !poked(next, c) : c != peekd(next)) break; + next += 4; + continue; + } + + if (a == CALL || a == JUMP) + { + b = (a == CALL ? 0xE8 : 0xE9); + //if (length-- == 0) break; + c = va_arg(va, unsigned int) - (next + 5); + if (mode ? !pokeb(next, b) : b != peekb(next)) break; + // do NOT merge the next++ into the previous if statement. + next++; + if (mode ? !poked(next, c) : c != peekd(next)) break; + next += 4; + continue; + } + + if (a == JZ || a == JNZ) + { + b = (a == JZ ? 0x84 : 0x85); + //if (length-- == 0) break; + c = va_arg(va, unsigned int) - (next + 6); + if (mode ? !pokeb(next, 0x0F) : 0x0F != peekb(next)) break; + next++; + if (mode ? !pokeb(next, b) : b != peekb(next)) break; + next++; + if (mode ? !poked(next, c) : c != peekd(next)) break; + next += 4; + continue; + } + + if (a <= 0xFF) + { + if (mode ? !pokeb(next, a) : a != peekb(next)) break; + next++; + continue; + } + + d_printf("vpatchengine: unsupported token: %08X\n", a); + break; // unsupported token + } + +// d_printf("vpatchengine returning %d, length is %d, next is %08X\n", +// ok, length, next); + return(ok); +} + + +// ---------------------------------------------------------------------------- +// patch() and verify() support a modified subset of hex_search() tokens: +// +// 0x00 - 0xFF: poke the byte. +// EOL: end-of-list. terminate when this token is reached. +// DWORD_: Followed by a DWORD, not a byte. Poke the DWORD. +// CALL: given an _address_; pokes near call with the proper _delta_. +// JUMP: given an _address_; pokes near jump with the proper _delta_. +// JZ: given an _address_; assembles a near (not short) jz & delta. +// JNZ: given an _address_; assembles a near jnz & delta. +// +// Particularly note that, unlike hex_search(), CALL, JUMP, JZ, and JNZ +// are followed by a dword-sized target address. +// +// Note that patch() does its own verify(), so you don't have to. +// +// TODO: doing so many individual pokes and peeks is slow. Consider +// building a copy, then doing a pokearb/peekarb. + +// Make an offset in Dwarf Fortress have certain bytes. +BOOL patch2(DWORD address, ...) +{ + va_list va; + BOOL ok; + + va_start(va, address); + ok = vpatchengine(TRUE, address, va); + va_end(va); + + va_start(va, address); + if (ok) ok = vpatchengine(FALSE, address, va); + va_end(va); + return(ok); +} + + +// ---------------------------------------------------------------------------- +// Check that an offset in Dwarf Fortress has certain bytes. +// +// See patch() documentation. +BOOL verify2(DWORD address, ...) +{ + BOOL ok; + va_list va; + va_start(va, address); + ok = vpatchengine(FALSE, address, va); + va_end(va); + return(ok); +} + +// ---------------------------------------------------------------------------- +// Get the exe name of the DF executable +static DWORD get_exe_base(DWORD pid) +{ + HANDLE snap = INVALID_HANDLE_VALUE; + PROCESSENTRY32 process = {0}; + MODULEENTRY32 module = {0}; + + do + { + snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (snap == INVALID_HANDLE_VALUE) + { + errormessage = "CreateToolhelp32Snapshot(Process) failed."; + break; + } + + // Get the process exe name + process.dwSize = sizeof(PROCESSENTRY32); + if (!Process32First(snap, &process)) + { + errormessage = "Process32First(snapshot) failed."; + break; + } + do + { + if (process.th32ProcessID == pid) + { + break; + } + else + { + //d_printf("Process: %d \"%.*s\"", process.th32ProcessID, MAX_PATH, process.szExeFile); + } + } while (Process32Next(snap, &process)); + if (process.th32ProcessID != pid) + { + errormessage = "Process32List(snapshot) Couldn't find the target process in the snapshot?"; + break; + } + + d_printf("Target Process: %d \"%.*s\"", process.th32ProcessID, MAX_PATH, process.szExeFile); + CloseHandle(snap); + + snap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid); + if (snap == INVALID_HANDLE_VALUE) + { + errormessage = "CreateToolhelp32Snapshot(Modules) failed."; + break; + } + + // Now find the module + module.dwSize = sizeof(MODULEENTRY32); + if (!Module32First(snap, &module)) + { + errormessage = "Module32First(snapshot) failed."; + break; + } + do + { + if (!stricmp(module.szModule, process.szExeFile)) + { + break; + } + else + { + //d_printf("Module: %08X \"%.*s\" \"%.*s\"", (DWORD)(SIZE_T)module.modBaseAddr, MAX_MODULE_NAME32 + 1, module.szModule, MAX_PATH, module.szExePath); + } + } while (Module32Next(snap, &module)); + if (stricmp(module.szModule, process.szExeFile)) + { + errormessage = "Module32List(snapshot) Couldn't find the target module in the snapshot?"; + break; + } + d_printf("Target Module: %08X \"%.*s\" \"%.*s\"", (DWORD)(SIZE_T)module.modBaseAddr, MAX_MODULE_NAME32 + 1, module.szModule, MAX_PATH, module.szExePath); + } while (0); + + if (snap != INVALID_HANDLE_VALUE) + { + CloseHandle(snap); + } + + if (errormessage != NULL && strlen(errormessage) != 0) + { + d_printf("%s\n", errormessage); + return 0; + } + + return (DWORD)(SIZE_T)module.modBaseAddr; +} + +// ============================================================================ +void cleanup(void) +{ + + if (copy_of_df_memory != NULL) + { + GlobalFree(copy_of_df_memory); + copy_of_df_memory = NULL; + } + + if (suspended) + { + if ((DWORD)-1 == ResumeThread(df_h_thread)) + { + // do what? apologise? + } + else suspended = FALSE; + } +#if 0 + // do this incase earlier runs crashed without executing the atexit handler. + // TODO: trap exceptions? + ResumeThread(df_h_thread); + ResumeThread(df_h_thread); + ResumeThread(df_h_thread); + ResumeThread(df_h_thread); + ResumeThread(df_h_thread); + ResumeThread(df_h_thread); + ResumeThread(df_h_thread); + ResumeThread(df_h_thread); + ResumeThread(df_h_thread); + ResumeThread(df_h_thread); + ResumeThread(df_h_thread); + ResumeThread(df_h_thread); +#endif + + if (df_h_thread != NULL) + { + CloseHandle(df_h_thread); + df_h_thread = NULL; + } + if (df_h_process != NULL) + { + CloseHandle(df_h_process); + df_h_process = NULL; + } +} + + +// ---------------------------------------------------------------------------- +BOOL open_dwarf_fortress(void) +{ + HANDLE df_main_wh; + char *state; + + change_page_permissions = FALSE; + + atexit(cleanup); + + df_memory_base = 0x400000; // executables start here unless + // explicitly relocated. + errormessage = ""; + + + // trigger a GPF + //*(char *)(0) = '!'; + + // trigger an invalid instruction (or DEP on newer processors). + // 0F 0B is the UD1 pseudo-instruction, explicitly reserved as an invalid + // instruction to trigger faults. + //asm(".fill 1, 1, 0x0F; .fill 1, 1, 0x0B"); + + state = "calling FindWindow()... "; + d_printf(state); + df_main_wh = FindWindow("OpenGL","Dwarf Fortress"); + d_printf("done\n"); + dump(df_main_wh); + if (df_main_wh == 0) + { + df_main_wh = FindWindow("SDL_app","Dwarf Fortress"); + if (df_main_wh == 0) + { + errormessage = "FindWindow(Dwarf Fortress) failed.\nIs the game running?"; + return FALSE; + } + } + + state = "calling GetWindowThreadProcessId()... "; + d_printf(state); + df_main_win_tid = GetWindowThreadProcessId(df_main_wh, &df_pid); + d_printf("done\n"); + dump(df_pid); + dump(df_main_win_tid); + + if (df_main_win_tid == 0) { + errormessage = + "GetWindowThreadProcessId(Dwarf Fortress) failed.\n" + "That should not have happened!"; + return FALSE; + } + + state = "calling OpenProcess()... "; + d_printf(state); + df_h_process = OpenProcess(PROCESS_VM_WRITE | PROCESS_VM_READ | PROCESS_VM_OPERATION | PROCESS_SUSPEND_RESUME | PROCESS_QUERY_INFORMATION, FALSE, df_pid); + d_printf("done\n"); + dump(df_h_process); + if (df_h_process == NULL) + { + errormessage = "OpenProcess(Dwarf Fortress) failed.\n" + "Are you the same user that started the game?"; + return(FALSE); + } + + state = "calling OpenThread()... "; + d_printf(state); + df_h_thread = OpenThread(THREAD_ALL_ACCESS, FALSE, df_main_win_tid); + d_printf("done\n"); + dump(df_h_thread); + if (df_h_thread == NULL) + { + errormessage = "OpenThread(Dwarf Fortress) failed."; + return(FALSE); + } + + // TODO enum and suspend all threads? + state = "calling SuspendThread()... "; + d_printf(state); + if ((DWORD)-1 == SuspendThread(df_h_thread)) + { + errormessage = "SuspendThread(Dwarf Fortress) failed."; + return(FALSE); + } + d_printf("done\n"); + suspended = TRUE; + + // get the base of the df executable + df_memory_base = get_exe_base(df_pid); + if (!df_memory_base) + { + errormessage = "GetModuleBase(Dwarf Fortress) failed."; + return(FALSE); + } + dump(df_memory_base); + + // we could get this from the PE header, but why bother? + df_memory_start = df_memory_base + 0x1000; + dump(df_memory_start); + + // df_memory_end is based on the SizeOfImage field from the in-memory + // copy of the PE header. + df_memory_end = df_memory_base + peekd(df_memory_base+peekd(df_memory_base+0x3C)+0x50)-1; + dump(df_memory_end); + + state = "calling GlobalAlloc(huge)... "; + d_printf(state); + dump(df_memory_end - df_memory_start + 0x100); + if (NULL == (copy_of_df_memory = (BYTE *)GlobalAlloc(GPTR, df_memory_end - df_memory_start + 0x100))) + { + errormessage = "GlobalAlloc() of copy_of_df_memory failed"; + return FALSE; + } + d_printf("done\n"); + + state = "copying memory... "; + if (!peekarb(df_memory_start, copy_of_df_memory, df_memory_end-df_memory_start)) + { + d_printf("peekarb(entire program) for search()'s use failed\n"); + return FALSE; + } + + set_hexsearch2_limits(0, 0); + + return(TRUE); +} + + +// not (normally) necessary because it is done at exit time by atexit(). +// however you can call this to resume DF before putting up a dialog box. +void close_dwarf_fortress(void) +{ + cleanup(); +} + diff --git a/tools/playground/hexsearch2.h b/tools/playground/hexsearch2.h new file mode 100644 index 000000000..8cff56b90 --- /dev/null +++ b/tools/playground/hexsearch2.h @@ -0,0 +1,219 @@ +/* + * Author: Silas Dunsmore aka 0x517A5D vim:ts=4:sw=4 + * + * Released under the MIT X11 license; feel free to use some or all of this + * code, as long as you include the copyright and license statement (below) + * in all copies of the source code. In fact, I truly encourage reuse. + * + * If you do use large portions of this code, I suggest but do not require + * that you keep this code in a seperate file (such as this hexsearch.h file) + * so that it is clear that the terms of the license do not also apply to + * your code. + * + * Should you make fundamental changes, or bugfixes, to this code, I would + * appreciate it if you would give me a copy of your changes. + * + * + * Copyright (C) 2007-2008 Silas Dunsmore + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * See also: http://www.opensource.org/licenses/mit-license.php + * and http://en.wikipedia.org/wiki/MIT_License + */ + + +#ifndef HEXSEARCH_H +#define HEXSEARCH_H +#ifdef __cplusplus +extern "C" +{ +#endif + + +extern DWORD df_memory_base, df_memory_start, df_memory_end; +extern HANDLE df_h_process, df_h_thread; +extern DWORD df_pid, df_main_win_tid; + +extern DWORD here[16]; +extern DWORD target[16]; + +// ============================================================================ +// export these in case you need to work with them directly. +//extern HANDLE df_h_process, df_h_thread; +//extern DWORD df_pid, df_main_win_tid; +extern char *errormessage; + + +// ============================================================================ +// send info to KERNEL32:OutputDebugString(), useful for non-console programs. +// (you can watch this with SysInternals' DebugView.) +// http://www.microsoft.com/technet/sysinternals/Miscellaneous/DebugView.mspx +void d_printf(const char *format, ...); +// it turned out that dprintf() is semi-standard to printf to a file descriptor. + + +// ============================================================================ +// encapsulate the housekeeping. +BOOL open_dwarf_fortress(void); +void close_dwarf_fortress(void); // is not (normally) necessary because + // it is done at exit time. + + +// ============================================================================ +// memory reads and writes (peeks and pokes, in old BASIC terminology) +BOOL isvalidaddress(DWORD ea); +BOOL peekarb(DWORD ea, OUT void *data, DWORD len); +BYTE peekb(DWORD ea); +WORD peekw(DWORD ea); +DWORD peekd(DWORD ea); +char *peekstr(DWORD ea, OUT char *data, DWORD maxlen); +char *peekustr(DWORD ea, OUT char *data, DWORD maxlen); +BOOL pokearb(DWORD ea, const void *data, DWORD len); +BOOL pokeb(DWORD ea, BYTE data); +BOOL pokew(DWORD ea, WORD data); +BOOL poked(DWORD ea, DWORD data); +BOOL pokestr(DWORD ea, const BYTE *data); + + +// ============================================================================ +// The name has changed because the API HAS CHANGED! +// +// Now instead of returning HERE, it always returns the start of the match. +// +// However, there is an array, here[], that is filled with the locations of +// the HERE tokens. +// (Starting at 1. here[0] is a copy of the start of the match.) +// +// The here[] array, starting at 1, is filled with the locations of the +// HERE token. +// here[0] is a copy of the start of the match. +// +// Also, the target[] array, starting at 1, is filled with the target +// addresses of all CALL, JMP, JZ, JNZ, and JCC tokens. +// +// Finally, you no longer pass it a search length. Instead, each set of +// search terms must end with an EOL. +// +// +// +// Okay, I admit this one is complicated. Treat it as a black box. +// +// Search Dwarf Fortress's code and initialized data segments for a pattern. +// (Does not search stack, heap, or thread-local memory.) +// +// Parameters: any number of search tokens, all unsigned ints. +// The last token must be EOL. +// +// 0x00 - 0xFF: Match this byte. +// EOL: End-of-list. The match succeeds when this token is reached. +// ANYBYTE: Match any byte. +// DWORD_: Followed by a dword. Exact-match the dword. +// Equivalent to 4 match-this-byte tokens. +// ANYDWORD: Match any dword. Equivalant to 4 ANYBYTEs. +// HERE: Put the current address into the here[] array. +// SKIP_UP_TO, nn: Allow up to nn bytes between the previous match +// and the next match. The next token must be a match-this-byte +// token. There is sweet, sweet backtracking. +// EITHER: Accept either of the next two tokens as a match. +// Both must be match-this-byte tokens. +// RANGE_LO, nn: Set low byte for a range comparison. DEPRECATED. +// RANGE_HI, nn: Set high byte for a range comparison, and do the +// comparison. Should immediately follow a RANGE_LO. DEPRECATED. +// BYTERANGE, nn, mm: followed by two bytes, the low and high limits +// of the range. This is the new way to do ranges. +// DWORDRANGE, nnnnnnnn, mmmmmmmm: works like BYTERANGE. +// ADDRESS: Accept any legal address in the program's text. +// DOES NOT accept pointers into heap space and such. +// CALL: Match a near call instruction to a reasonable address. +// JUMP: Match a short or near unconditional jump to a reasonable +// address. +// JZ: Match a short or long jz (jump if zero) instruction. +// JNZ: Match a short or long jnz (jump if not zero) instruction. +// JCC: Match any short or long conditional jump instruction. +// More tokens can easily be added. +// +// Returns the offset in Dwarf Fortress of the first match of the pattern. +// Also sets global variables here[] and target[]. +// +// Note: starting a pattern with ANYBYTE, ANYDWORD, SKIP_UP_TO, or EOL +// is explicitly illegal. +// +#define EOL 0x100 +#define ANYBYTE 0x101 +//#define FF_OR_00 0x102 // deprecated +#define HERE 0x103 +#define EITHER 0x104 +#define SKIP_UP_TO 0x105 +#define RANGE_LO 0x106 // deprecated +#define RANGE_HI 0x107 // deprecated +#define DWORD_ 0x108 +#define ANYDWORD 0x109 +#define ADDRESS 0x10A +#define BYTERANGE 0x10B +#define DWORDRANGE 0x10C +#define JZ 0x174 +#define JNZ 0x175 +#define JCC 0x170 +#define CALL 0x1E8 +#define JUMP 0x1E9 + + +DWORD hexsearch2(DWORD token1, ...); + +// You can use this to limit the search to a particular part of memory. +// Use 0 for start to search from the very start of Dwarf Fortress. +// Use 0 for end to stop searching at the very end of Dwarf Fortress. +void set_hexsearch2_limits(DWORD start, DWORD end); + + +// ============================================================================ +// patch2() and verify2() support a modified subset of hex_search2() tokens: +// The names changed because the API HAS CHANGED! +// +// 0x00 - 0xFF: pokes the byte. +// EOL: End-of-list. Allows you to specify count as 10000 or so +// and terminate (with success) when this token is reached. +// DWORD_: Followed by a DWORD. Pokes the DWORD. +// CALL: given an _address_; pokes near call with the proper _delta_. +// JUMP: given an _address_; pokes near jump with the proper _delta_. +// JZ: given an _address_; assembles a near (not short) jz & delta. +// JNZ: given an _address_; assembles a near jnz & delta. +// +// Particularly note that, unlike hex_search(), CALL, JUMP, JZ, and JNZ +// are followed by a dword-sized target address. +// +// Note that patch2() does its own verify(), so you don't have to. + +// TODO: is verify() useful enough to maintain? + +// Make an offset in Dwarf Fortress have certain bytes. +BOOL patch2(DWORD offset, ...); +// Check that an offset in Dwarf Fortress has certain bytes. +BOOL verify2(DWORD offset, ...); + + + +#ifdef __cplusplus +} +#endif +#endif // HEXSEARCH_H \ No newline at end of file diff --git a/tools/playground/incrementalsearch.cpp b/tools/playground/incrementalsearch.cpp index cc047466c..0e9529cf1 100644 --- a/tools/playground/incrementalsearch.cpp +++ b/tools/playground/incrementalsearch.cpp @@ -1,5 +1,5 @@ -// this will be an incremental search tool in the future. now it is just a memory region dump thing - +// this is an incremental search tool. It only works on Linux. +// here be dragons... and ugly code :P #include #include #include @@ -19,347 +19,827 @@ using namespace std; #endif #include +#include "SegmentedFinder.h" +template +class holder +{ + public: + vector values; + SegmentedFinder & sf; + holder(SegmentedFinder& sff):sf(sff){}; + bool isValid(size_t idx) + { + + }; +}; -//TODO: lots of optimization -void searchLoop(DFHack::ContextManager & DFMgr, vector & ranges, int size, int alignment) +class address { - int32_t test1; - int32_t test2; - vector found; - vector newfound; - found.reserve(100000); - newfound.reserve(100000); - //bool initial = 1; - cout << "search ready - insert integers, 'p' for results" << endl; - string select; - while (1) + public: + uint64_t addr_; + unsigned int valid : 1; + virtual void print(SegmentedFinder& sff) { - cout << ">>"; - std::getline(cin, select); - if(select == "p") + cout << hex << "0x" << addr_ << endl; + }; + address(const uint64_t addr) + { + addr_ = addr; + valid = false; + } + virtual address & operator=(const uint64_t in) + { + addr_ = in; + valid = false; + return *this; + } + virtual bool isValid(SegmentedFinder& sff) + { + if(valid) return true; + if(sff.getSegmentForAddress(addr_)) { - cout << "Found addresses:" << endl; - for(int i = 0; i < found.size();i++) - { - cout << hex << "0x" << found[i] << endl; - } + valid = 1; } - else if(sscanf(select.c_str(),"%d", &test1) == 1) + } + virtual bool equals (SegmentedFinder & sf, address & rhs) + { + return rhs.addr_ == addr_; + } +}; + +// pointer to a null-terminated byte string +class Cstr: public address +{ + void print(SegmentedFinder & sf) + { + cout << hex << "0x" << addr_ << ": \"" << sf.Translate(addr_) << "\"" << endl; + } + bool equals(SegmentedFinder & sf,const char * rhs) + { + uint32_t addr2 = *(sf.Translate(addr_)); + return strcmp(sf.Translate(addr2), rhs) == 0; + } + template + bool equalsP(SegmentedFinder & sf,inType rhs) + { + return Predicate(addr_, sf, rhs); + } + bool isValid(SegmentedFinder& sf) + { + if (address::isValid(sf)) { - // refresh the list of processes, get first suitable, attach - DFMgr.Refresh(); - DFHack::Context * DF = DFMgr.getSingleContext(); - DF->Attach(); - - newfound.clear(); - bool initial = found.empty(); - if(initial) - { - // for each range - for (int i = 0; i < ranges.size();i++) - { - // can't read? range is invalid to us - if(!ranges[i].read) - continue; - //loop - for(uint64_t offset = ranges[i].start;offset <= ranges[i].end - size; offset+=alignment) - { - DF->ReadRaw(offset, size, (uint8_t *) &test2); - if(test1 == test2 ) - found.push_back(offset); - } - } - cout << "found " << found.size() << " addresses" << endl; - } - else - { - for(int j = 0; j < found.size();j++) - { - DF->ReadRaw(found[j], size, (uint8_t *) &test2); - if(test1 == test2) - { - newfound.push_back(found[j]); - } - } - cout << "matched " << newfound.size() << " addresses out of " << found.size() << endl; - found = newfound; - } - DF->Detach(); + // read the pointer + uint32_t addr2 = *(sf.Translate(addr_)); + // is it a real pointer? a pretty weak test, but whatever. + if(sf.getSegmentForAddress(addr2)) + return true; } - else break; + return false; } +}; + +// STL STRING +#ifdef LINUX_BUILD +class STLstr: public address +{ + +}; +#endif +#ifndef LINUX_BUILD +class STLstr: public address +{ + +}; +#endif + +// STL VECTOR +#ifdef LINUX_BUILD +class Vector: public address +{ + +}; +#endif +#ifndef LINUX_BUILD +class Vector: public address +{ + +}; +#endif +class Int64: public address{}; +class Int32: public address{}; +class Int16: public address{}; +class Int8: public address{}; + +inline void printRange(DFHack::t_memrange * tpr) +{ + std::cout << std::hex << tpr->start << " - " << tpr->end << "|" << (tpr->read ? "r" : "-") << (tpr->write ? "w" : "-") << (tpr->execute ? "x" : "-") << "|" << tpr->name << std::endl; } -typedef struct +string rdWinString( char * offset, SegmentedFinder & sf ) { - uint32_t start; - uint32_t finish; - uint32_t alloc_finish; -} vecTriplet; + char * start_offset = offset + 4; + uint32_t length = *(uint32_t *)(offset + 20); + uint32_t capacity = *(uint32_t *)(offset + 24); + char * temp = new char[capacity+1]; -void searchLoopVector(DFHack::ContextManager & DFMgr, vector & ranges, uint32_t element_size) + // read data from inside the string structure + if(capacity < 16) + { + memcpy(temp, start_offset,capacity); + //read(start_offset, capacity, (uint8_t *)temp); + } + else // read data from what the offset + 4 dword points to + { + start_offset = sf.Translate(*(uint32_t*)start_offset); + memcpy(temp, start_offset,capacity); + } + + temp[length] = 0; + string ret = temp; + delete temp; + return ret; +} + +bool getRanges(DFHack::Process * p, vector & selected_ranges) { - vecTriplet load; - uint32_t length; - vector found; - vector newfound; - found.reserve(100000); - newfound.reserve(100000); - //bool initial = 1; - cout << "search ready - insert vector length" << endl; - string select; - while (1) + vector ranges; + selected_ranges.clear(); + p->getMemRanges(ranges); + cout << "Which range to search? (default is 1-4)" << endl; + for(int i = 0; i< ranges.size();i++) + { + cout << dec << "(" << i << ") "; + printRange(&(ranges[i])); + } + int start, end; + while(1) { + string select; cout << ">>"; std::getline(cin, select); - if(select == "p") + if(select.empty()) { - cout << "Found vectors:" << endl; - for(int i = 0; i < found.size();i++) + // empty input, assume default. observe the length of the memory range vector + // these are hardcoded values, intended for my convenience only + if(p->getDescriptor()->getOS() == DFHack::memory_info::OS_WINDOWS) { - cout << hex << "0x" << found[i] << endl; + start = min(11, (int)ranges.size()); + end = min(14, (int)ranges.size()); } - } - else if(sscanf(select.c_str(),"%d", &length) == 1) - { - // refresh the list of processes, get first suitable, attach - DFMgr.Refresh(); - DFHack::Context * DF = DFMgr.getSingleContext(); - DF->Attach(); - - // clear the list of found addresses - found.clear(); - - // for each range - for (int i = 0; i < ranges.size();i++) + else if(p->getDescriptor()->getOS() == DFHack::memory_info::OS_LINUX) { - // can't read? range is invalid to us - if(!ranges[i].read) - continue; - //loop - for(uint64_t offset = ranges[i].start;offset <= ranges[i].end - sizeof(vecTriplet); offset+=4) - { - DF->ReadRaw(offset, sizeof(vecTriplet), (uint8_t *) &load); - if(load.start <= load.finish && load.finish <= load.alloc_finish) - if((load.finish - load.start) / element_size == length) - found.push_back(offset); - } + start = min(2, (int)ranges.size()); + end = min(4, (int)ranges.size()); } - cout << "found " << found.size() << " addresses" << endl; - - // detach again - DF->Detach(); + else + { + start = 1; + end = 1; + } + break; } - else + // I like the C variants here. much less object clutter + else if(sscanf(select.c_str(), "%d-%d", &start, &end) == 2) { + start = min(start, (int)ranges.size()); + end = min(end, (int)ranges.size()); break; } + else + { + continue; + } + break; + } + end++; + cout << "selected ranges:" <::iterator it; + it = ranges.begin() + start; + while (it != ranges.begin() + end) + { + // check if readable + if((*it).read) + { + selected_ranges.push_back(*it); + printRange(&*it); + } + it++; } } -void mkcopy(DFHack::ContextManager & DFMgr, vector & ranges, uint32_t element_size) + +bool getNumber (string prompt, int & output, int def, bool pdef = true) { - DFMgr.Refresh(); - DFHack::Context * DF = DFMgr.getSingleContext(); - DF->Attach(); - for (int i = 0; i < ranges.size();i++) + cout << prompt; + if(pdef) + cout << " default=" << def << endl; + while (1) { - // can't read? range is invalid to us - if(!ranges[i].read) - continue; - char * buffah = (char *) malloc(ranges[i].end - ranges[i].start); - if(buffah) + string select; + cout << ">>"; + std::getline(cin, select); + if(select.empty()) { - DF->ReadRaw(ranges[i].start,ranges[i].end - ranges[i].start, (uint8_t *) buffah); - cerr << "buffer for range " << i << " allocated and filled" << endl; - free(buffah); - cerr << "and freed" << endl; + output = def; + break; + } + else if( sscanf(select.c_str(), "%d", &output) == 1 ) + { + break; } else - cerr << "buffer for range " << i << " failed to allocate" << endl; - //loop - /* - for(uint64_t offset = ranges[i].start;offset <= ranges[i].end - sizeof(vecTriplet); offset+=4) { - DF->ReadRaw(offset, sizeof(vecTriplet), (uint8_t *) &load); - if(load.start <= load.finish && load.finish <= load.alloc_finish) - if((load.finish - load.start) / element_size == length) - found.push_back(offset); + continue; } - */ } - DF->Detach(); - DFMgr.purge(); + return true; } -int main (void) +bool getString (string prompt, string & output) { + cout << prompt; + cout << ">>"; string select; - DFHack::ContextManager DFMgr("Memory.xml"); - DFHack::Context * DF = DFMgr.getSingleContext(); - try + std::getline(cin, select); + if(select.empty()) { - DF->Attach(); + return false; } - catch (exception& e) + else { - cerr << e.what() << endl; - #ifndef LINUX_BUILD - cin.ignore(); - #endif - return 1; + output = select; + return true; } - DFHack::Process * p = DF->getProcess(); - vector ranges; - vector selected_ranges; - p->getMemRanges(ranges); - cout << "Which range to search? (default is 1-4)" << endl; - for(int i = 0; i< ranges.size();i++) +} + +template +bool Incremental ( vector &found, const char * what, T& output, + const char *singular = "address", const char *plural = "addresses" ) +{ + string select; + if(found.empty()) { - cout << dec << "(" << i << ") "; - ranges[i].print(); + cout << "search ready - insert " << what << ", 'p' for results, 'p #' to limit number of results" << endl; } - - try_again_ranges: + else if( found.size() == 1) + { + cout << "Found single "<< singular <<"!" << endl; + cout << hex << "0x" << found[0] << endl; + } + else + { + cout << "Found " << dec << found.size() << " " << plural <<"." << endl; + } + incremental_more: cout << ">>"; std::getline(cin, select); - int start, end; - if(select.empty()) + size_t num = 0; + if( sscanf(select.c_str(),"p %d", &num) && num > 0) { - // empty input, assume default. observe the length of the memory range vector - // these are hardcoded values, intended for my convenience only - if(p->getDescriptor()->getOS() == DFHack::memory_info::OS_WINDOWS) + cout << "Found "<< plural <<":" << endl; + for(int i = 0; i < min(found.size(), num);i++) { - start = min(11, (int)ranges.size()); - end = min(14, (int)ranges.size()); + cout << hex << "0x" << found[i] << endl; } - else if(p->getDescriptor()->getOS() == DFHack::memory_info::OS_LINUX) + goto incremental_more; + } + else if(select == "p") + { + cout << "Found "<< plural <<":" << endl; + for(int i = 0; i < found.size();i++) { - start = min(11, (int)ranges.size()); - end = min(14, (int)ranges.size()); + cout << hex << "0x" << found[i] << endl; } - else + goto incremental_more; + } + else if(select.empty()) + { + return false; + } + else + { + if( sscanf(select.c_str(),"0x%x", &output) == 1 ) + { + //cout << dec << output << endl; + return true; + } + if( sscanf(select.c_str(),"%d", &output) == 1 ) { - start = 1; - end = 1; + //cout << dec << output << endl; + return true; } + + stringstream ss (stringstream::in | stringstream::out); + ss << select; + ss >> output; + if(!ss.fail()) + { + return true; + } + cout << "not a valid value for type: " << what << endl; + goto incremental_more; } - // I like the C variants here. much less object clutter - else if(sscanf(select.c_str(), "%d-%d", &start, &end) == 2) +} + +void FindIntegers(DFHack::ContextManager & DFMgr, vector & ranges) +{ + // input / validation of variable size + int size; + do + { + getNumber("Select variable size (1,2,4 bytes)",size, 4); + } while (size != 1 && size != 2 && size != 4); + // input / validation of variable alignment (default is to use the same alignment as size) + int alignment; + do { - start = min(start, (int)ranges.size()); - end = min(end, (int)ranges.size()); + getNumber("Select variable alignment (1,2,4 bytes)",alignment, size); + } while (alignment != 1 && alignment != 2 && alignment != 4); + + uint32_t test1; + vector found; + found.reserve(100); + while(Incremental(found, "integer",test1)) + { + DFMgr.Refresh(); + DFHack::Context * DF = DFMgr.getSingleContext(); + DF->Attach(); + SegmentedFinder sf(ranges,DF); + switch(size) + { + case 1: + sf.Incremental(test1,alignment,found, equalityP); + break; + case 2: + sf.Incremental(test1,alignment,found, equalityP); + break; + case 4: + sf.Incremental(test1,alignment,found, equalityP); + break; + } + DF->Detach(); } - else +} + +void FindVectorByLength(DFHack::ContextManager & DFMgr, vector & ranges ) +{ + int element_size; + do + { + getNumber("Select searched vector item size in bytes",element_size, 4); + } while (element_size < 1); + + uint32_t length; + vector found; + found.reserve(100); + while (Incremental(found, "vector length",length,"vector","vectors")) { - goto try_again_ranges; // yes, this is a goto. bite me. + DFMgr.Refresh(); + DFHack::Context * DF = DFMgr.getSingleContext(); + DF->Attach(); + SegmentedFinder sf(ranges,DF); + //sf.Incremental(0,4,found,vectorAll); + //sf.Filter(length * element_size,found,vectorLength); + sf.Incremental(length * element_size, 4 , found, vectorLength); + DF->Detach(); } - end++; - cout << "selected ranges:" <& ranges) +{ + vector found; + string select; + while (Incremental(found, "raw name",select,"vector","vectors")) { - selected_ranges[i].print(); + DFMgr.Refresh(); + DFHack::Context * DF = DFMgr.getSingleContext(); + DF->Attach(); + SegmentedFinder sf(ranges,DF); + sf.Find(0,4,found, vectorAll); + sf.Filter(select.c_str(),found, vectorString); + DF->Detach(); } - try_again_type: - cout << "Select search type: 1=number(default), 2=vector, 3=string" << endl; - cout << ">>"; - std::getline(cin, select); - int mode; - if(select.empty()) +} + +void FindVectorByFirstObjectRawname(DFHack::ContextManager & DFMgr, vector & ranges) +{ + vector found; + string select; + while (Incremental(found, "raw name",select,"vector","vectors")) { - mode = 1; + DFMgr.Refresh(); + DFHack::Context * DF = DFMgr.getSingleContext(); + DF->Attach(); + SegmentedFinder sf(ranges,DF); + sf.Find(0,4,found, vectorAll); + sf.Filter(select.c_str(),found, vectorStringFirst); + DF->Detach(); } - else if( sscanf(select.c_str(), "%d", &mode) == 1 ) +} + +struct VectorSizeFunctor : public binary_function +{ + VectorSizeFunctor(SegmentedFinder & sf):sf_(sf){} + bool operator()( uint64_t lhs, uint64_t rhs) { - if(mode != 1 && mode != 2 && mode != 3) - { - goto try_again_type; - } + vecTriplet* left = sf_.Translate(lhs); + vecTriplet* right = sf_.Translate(rhs); + return ((left->finish - left->start) < (right->finish - right->start)); } - else + SegmentedFinder & sf_; +}; + +void FindVectorByBounds(DFHack::ContextManager & DFMgr, vector & ranges) +{ + vector found; + uint32_t select; + while (Incremental(found, "address between vector.start and vector.end",select,"vector","vectors")) { - goto try_again_type; + DFMgr.Refresh(); + DFHack::Context * DF = DFMgr.getSingleContext(); + DF->Attach(); + SegmentedFinder sf(ranges,DF); + sf.Find(0,4,found, vectorAll); + sf.Filter(select,found, vectorAddrWithin); + // sort by size of vector + std::sort(found.begin(), found.end(), VectorSizeFunctor(sf)); + DF->Detach(); } - if(mode == 1) +} + +void FindPtrVectorsByObjectAddress(DFHack::ContextManager & DFMgr, vector & ranges) +{ + vector found; + uint32_t select; + while (Incremental(found, "object address",select,"vector","vectors")) { - // input / validation of variable size - try_again_size: - cout << "Select searched variable size (1,2,4 bytes, default is 4)" << endl; - cout << ">>"; - std::getline(cin, select); - int size; - if(select.empty()) + DFMgr.Refresh(); + DFHack::Context * DF = DFMgr.getSingleContext(); + DF->Attach(); + SegmentedFinder sf(ranges,DF); + sf.Find(0,4,found, vectorAll); + sf.Filter(select,found, vectorOfPtrWithin); + DF->Detach(); + } +} + + +void FindStrings(DFHack::ContextManager & DFMgr, vector & ranges) +{ + vector found; + string select; + while (Incremental(found,"string",select,"string","strings")) + { + DFMgr.Refresh(); + DFHack::Context * DF = DFMgr.getSingleContext(); + DF->Attach(); + SegmentedFinder sf(ranges,DF); + sf.Incremental< const char * ,uint32_t>(select.c_str(),1,found, findString); + DF->Detach(); + } +} + +void printFound(vector &found, const char * what) +{ + cout << what << ":" << endl; + for(int i = 0; i < found.size();i++) + { + cout << hex << "0x" << found[i] << endl; + } +} + +void printFoundStrVec(vector &found, const char * what, SegmentedFinder & s) +{ + cout << what << ":" << endl; + for(int i = 0; i < found.size();i++) + { + cout << hex << "0x" << found[i] << endl; + cout << "--------------------------" << endl; + vecTriplet * vt = s.Translate(found[i]); + if(vt) + { + int j = 0; + for(uint32_t idx = vt->start; idx < vt->finish; idx += sizeof(uint32_t)) + { + uint32_t object_ptr; + // deref ptr idx, get ptr to object + if(!s.Read(idx,object_ptr)) + { + cout << "BAD!" << endl; + break; + } + // deref ptr to first object, get ptr to string + uint32_t string_ptr; + if(!s.Read(object_ptr,string_ptr)) + { + cout << "BAD!" << endl; + break; + } + // get string location in our local cache + char * str = s.Translate(string_ptr); + if(!str) + { + cout << "BAD!" << endl; + break; + } + cout << dec << j << ":" << hex << "0x" << object_ptr << " : " << str << endl; + j++; + } + } + else { - size = 4; + cout << "BAD!" << endl; + break; } - else if( sscanf(select.c_str(), "%d", &size) == 1 ) + cout << "--------------------------" << endl; + } +} + +// meh +#pragma pack(1) +struct tilecolors +{ + uint16_t fore; + uint16_t back; + uint16_t bright; +}; +#pragma pack() + +void automatedLangtables(DFHack::Context * DF, vector & ranges) +{ + vector allVectors; + vector filtVectors; + vector to_filter; + + cout << "stealing memory..." << endl; + SegmentedFinder sf(ranges, DF); + cout << "looking for vectors..." << endl; + sf.Find(0,4,allVectors, vectorAll); +/* + // trim vectors. anything with > 10000 entries is not interesting + for(uint64_t i = 0; i < allVectors.size();i++) + { + vecTriplet* vtrip = sf.Translate(allVectors[i]); + if(vtrip) { - if(/*size != 8 &&*/ size != 4 && size != 2 && size != 1) + uint64_t length = (vtrip->finish - vtrip->start) / 4; + if(length < 10000 ) { - goto try_again_size; + filtVectors.push_back(allVectors[i]); } } - else + } +*/ + filtVectors = allVectors; + cout << "-------------------" << endl; + cout << "!!LANGUAGE TABLES!!" << endl; + cout << "-------------------" << endl; + + uint64_t kulet_vector; + uint64_t word_table_offset; + uint64_t DWARF_vector; + uint64_t DWARF_object; + + // find lang vector (neutral word table) + to_filter = filtVectors; + sf.Filter("ABBEY",to_filter, vectorStringFirst); + uint64_t lang_addr = to_filter[0]; + + // find dwarven language word table + to_filter = filtVectors; + sf.Filter("kulet",to_filter, vectorStringFirst); + kulet_vector = to_filter[0]; + + // find vector of languages + to_filter = filtVectors; + sf.Filter("DWARF",to_filter, vectorStringFirst); + + // verify + for(int i = 0; i < to_filter.size(); i++) + { + vecTriplet * vec = sf.Translate(to_filter[i]); + if(((vec->finish - vec->start) / 4) == 4) // verified { - goto try_again_size; + DWARF_vector = to_filter[i]; + DWARF_object = sf.Read(vec->start); + // compute word table offset from dwarf word table and dwarf language object addresses + word_table_offset = kulet_vector - DWARF_object; + break; } + } + cout << "translation vector: " << hex << "0x" << DWARF_vector << endl; + cout << "lang vector: " << hex << "0x" << lang_addr << endl; + cout << "word table offset: " << hex << "0x" << word_table_offset << endl; - // input / validation of variable alignment (default is to use the same alignment as size) - try_again_align: - cout << "Variable alignment (1,2,4 bytes, default is " << size << ")" << endl; - cout << ">>"; - std::getline(cin, select); - int alignment = size; - if(select.empty()) + cout << "-------------" << endl; + cout << "!!MATERIALS!!" << endl; + cout << "-------------" << endl; + // inorganics vector + to_filter = filtVectors; + //sf.Find(257 * 4,4,to_filter,vectorLength); + sf.Filter("IRON",to_filter, vectorString); + sf.Filter("ONYX",to_filter, vectorString); + sf.Filter("RAW_ADAMANTINE",to_filter, vectorString); + sf.Filter("BLOODSTONE",to_filter, vectorString); + printFound(to_filter,"inorganics"); + + // organics vector + to_filter = filtVectors; + sf.Filter(52 * 4,to_filter,vectorLength); + sf.Filter("MUSHROOM_HELMET_PLUMP",to_filter, vectorStringFirst); + printFound(to_filter,"organics"); + + // tree vector + to_filter = filtVectors; + sf.Filter(31 * 4,to_filter,vectorLength); + sf.Filter("MANGROVE",to_filter, vectorStringFirst); + printFound(to_filter,"trees"); + + // plant vector + to_filter = filtVectors; + sf.Filter(21 * 4,to_filter,vectorLength); + sf.Filter("MUSHROOM_HELMET_PLUMP",to_filter, vectorStringFirst); + printFound(to_filter,"plants"); + + // color descriptors + //AMBER, 112 + to_filter = filtVectors; + sf.Filter(112 * 4,to_filter,vectorLength); + sf.Filter("AMBER",to_filter, vectorStringFirst); + printFound(to_filter,"color descriptors"); + if(!to_filter.empty()) + { + uint64_t vec = to_filter[0]; + vecTriplet *vtColors = sf.Translate(vec); + uint32_t colorObj = sf.Read(vtColors->start); + cout << "Amber color:" << hex << "0x" << colorObj << endl; + // TODO: find string 'amber', the floats + } + + // all descriptors + //AMBER, 338 + to_filter = filtVectors; + sf.Filter(338 * 4,to_filter,vectorLength); + sf.Filter("AMBER",to_filter, vectorStringFirst); + printFound(to_filter,"all descriptors"); + + // creature type + //ELEPHANT, ?? (demons abound) + to_filter = filtVectors; + //sf.Find(338 * 4,4,to_filter,vectorLength); + sf.Filter("ELEPHANT",to_filter, vectorString); + sf.Filter("CAT",to_filter, vectorString); + sf.Filter("DWARF",to_filter, vectorString); + sf.Filter("WAMBLER_FLUFFY",to_filter, vectorString); + sf.Filter("TOAD",to_filter, vectorString); + sf.Filter("DEMON_1",to_filter, vectorString); + + vector toad_first = to_filter; + vector elephant_first = to_filter; + sf.Filter("TOAD",toad_first, vectorStringFirst); + sf.Filter("ELEPHANT",elephant_first, vectorStringFirst); + printFoundStrVec(toad_first,"toad-first creature types",sf); + printFound(elephant_first,"elephant-first creature types"); + printFound(to_filter,"all creature types"); + + uint64_t to_use = 0; + if(!elephant_first.empty()) + { + to_use = elephant_first[0]; + vecTriplet *vtCretypes = sf.Translate(to_use); + uint32_t elephant = sf.Read(vtCretypes->start); + uint64_t Eoffset; + cout << "Elephant: 0x" << hex << elephant << endl; + cout << "Elephant: rawname = 0x0" << endl; + Eoffset = sf.FindInRange ('E',equalityP, elephant, 0x300 ); + if(Eoffset) { - alignment = size; + cout << "Elephant: big E = 0x" << hex << Eoffset - elephant << endl; } - else if( sscanf(select.c_str(), "%d", &alignment) == 1 ) + Eoffset = sf.FindInRange ("FEMALE",vectorStringFirst, elephant, 0x300 ); + if(Eoffset) { - if(/*alignment != 8 &&*/ alignment != 4 && alignment != 2 && alignment != 1) - { - goto try_again_align; - } + cout << "Elephant: caste vector = 0x" << hex << Eoffset - elephant << endl; } - else + Eoffset = sf.FindInRange ("SKIN",vectorStringFirst, elephant, 0x2000 ); + if(Eoffset) { - goto try_again_align; + cout << "Elephant: extract? vector = 0x" << hex << Eoffset - elephant << endl; } - // we detach, searchLoop looks for the process again. - DF->Detach(); - searchLoop(DFMgr, selected_ranges, size, alignment); + tilecolors eletc = {7,0,0}; + Bytestream bs_eletc = {sizeof(tilecolors), &eletc}; + Eoffset = sf.FindInRange (bs_eletc, findBytestream, elephant, 0x300 ); + if(Eoffset) + { + cout << "Elephant: colors = 0x" << hex << Eoffset - elephant << endl; + } + //cout << "Amber color:" << hex << "0x" << colorObj << endl; + // TODO: find string 'amber', the floats } - else if(mode == 2)// vector + if(!toad_first.empty()) { - // input / validation of variable size - try_again_vsize: - cout << "Select searched vector item size (in bytes, default is 4)" << endl; - cout << ">>"; - std::getline(cin, select); - uint32_t size; - if(select.empty()) + to_use = toad_first[0]; + vecTriplet *vtCretypes = sf.Translate(to_use); + uint32_t toad = sf.Read(vtCretypes->start); + uint64_t Eoffset; + cout << "Toad: 0x" << hex << toad << endl; + cout << "Toad: rawname = 0x0" << endl; + Eoffset = sf.FindInRange (0xF9,equalityP, toad, 0x300 ); + if(Eoffset) { - size = 4; + cout << "Toad: character (not reliable) = 0x" << hex << Eoffset - toad << endl; } - else if( sscanf(select.c_str(), "%d", &size) == 1 ) + Eoffset = sf.FindInRange ("FEMALE",vectorStringFirst, toad, 0x300 ); + if(Eoffset) { - if(size == 0) - { - goto try_again_vsize; - } + cout << "Toad: caste vector = 0x" << hex << Eoffset - toad << endl; } - else + Eoffset = sf.FindInRange ("SKIN",vectorStringFirst, toad, 0x2000 ); + if(Eoffset) { - goto try_again_vsize; + cout << "Toad: extract? vector = 0x" << hex << Eoffset - toad << endl; + } + tilecolors toadtc = {2,0,0}; + Bytestream bs_toadc = {sizeof(tilecolors), &toadtc}; + Eoffset = sf.FindInRange (bs_toadc, findBytestream, toad, 0x300 ); + if(Eoffset) + { + cout << "Toad: colors = 0x" << hex << Eoffset - toad << endl; } - // we detach, searchLoop looks for the process again. - DF->Detach(); - searchLoopVector(DFMgr, selected_ranges,size); } - else if(mode == 3)// string + if(to_use) { - mkcopy(DFMgr, selected_ranges,0); - //searchLoopString(DF, selected_ranges); + + } +} + +int main (void) +{ + string select; + DFHack::ContextManager DFMgr("Memory.xml"); + DFHack::Context * DF = DFMgr.getSingleContext(); + try + { + DF->Attach(); + } + catch (exception& e) + { + cerr << e.what() << endl; + #ifndef LINUX_BUILD + cin.ignore(); + #endif + return 1; + } + DFHack::Process * p = DF->getProcess(); + vector selected_ranges; + getRanges(p,selected_ranges); + + DFHack::memory_info *minfo = DF->getMemoryInfo(); + DFHack::memory_info::OSType os = minfo->getOS(); + + string prompt = + "Select search type: 1=number(default), 2=vector by length, 3=vector>object>string,\n" + " 4=string, 5=automated offset search, 6=vector by address in its array,\n" + " 7=pointer vector by address of an object, 8=vector>first object>string\n"; + int mode; + do + { + getNumber(prompt,mode, 1, false); + } while (mode < 1 || mode > 8 ); + switch (mode) + { + case 1: + DF->Detach(); + FindIntegers(DFMgr, selected_ranges); + break; + case 2: + DF->Detach(); + FindVectorByLength(DFMgr, selected_ranges); + break; + case 3: + DF->Detach(); + FindVectorByObjectRawname(DFMgr, selected_ranges); + break; + case 4: + DF->Detach(); + FindStrings(DFMgr, selected_ranges); + break; + case 5: + automatedLangtables(DF,selected_ranges); + break; + case 6: + DF->Detach(); + FindVectorByBounds(DFMgr,selected_ranges); + break; + case 7: + DF->Detach(); + FindPtrVectorsByObjectAddress(DFMgr,selected_ranges); + break; + case 8: + DF->Detach(); + FindVectorByFirstObjectRawname(DFMgr, selected_ranges); + break; + default: + cout << "not implemented :(" << endl; } #ifndef LINUX_BUILD cout << "Done. Press any key to continue" << endl; diff --git a/tools/playground/test.cpp b/tools/playground/test.cpp index e62b35d2a..b67608f9a 100644 --- a/tools/playground/test.cpp +++ b/tools/playground/test.cpp @@ -8,10 +8,32 @@ using namespace std; #include +#include +#include +#include +#include using namespace DFHack; int main (int numargs, const char ** args) { + printf("From C: "); + DFHackObject* cman = ContextManager_Alloc("Memory.xml"); + DFHackObject* context = ContextManager_getSingleContext(cman); + if(context) + { + Context_Attach(context); + DFHackObject * maps = Context_getMaps(context); + if(maps) + { + Maps_Start(maps); + uint32_t x,y,z; + Maps_getSize(maps, &x, &y, &z); + printf("Map size: %d, %d, %d\n", x,y,z); + } + } + ContextManager_Free(cman); + + cout << "From C++:"; DFHack::ContextManager DFMgr("Memory.xml"); DFHack::Context * DF; try @@ -29,6 +51,11 @@ int main (int numargs, const char ** args) } // DO STUFF HERE + Maps * m = DF->getMaps(); + m->Start(); + uint32_t x,y,z; + m->getSize(x,y,z); + cout << "Map size " << x << ", "<< y << ", " << z << endl; #ifndef LINUX_BUILD cout << "Done. Press any key to continue" << endl; diff --git a/tools/playground/typeblocks.cpp b/tools/playground/typeblocks.cpp new file mode 100644 index 000000000..3a0b88f31 --- /dev/null +++ b/tools/playground/typeblocks.cpp @@ -0,0 +1,43 @@ +#include +#include +#include +#include +#include +#include +#include +using namespace std; + +#include +using namespace DFHack; + +namespace TBlocks +{ + +} + +int main (int numargs, const char ** args) +{ + DFHack::ContextManager DFMgr("Memory.xml"); + DFHack::Context * DF; + try + { + DF = DFMgr.getSingleContext(); + DF->Attach(); + } + catch (exception& e) + { + cerr << e.what() << endl; + #ifndef LINUX_BUILD + cin.ignore(); + #endif + return 1; + } + + // DO STUFF HERE + + #ifndef LINUX_BUILD + cout << "Done. Press any key to continue" << endl; + cin.ignore(); + #endif + return 0; +} diff --git a/tools/supported/CMakeLists.txt b/tools/supported/CMakeLists.txt index c8b278997..f7006aeb2 100644 --- a/tools/supported/CMakeLists.txt +++ b/tools/supported/CMakeLists.txt @@ -51,19 +51,74 @@ TARGET_LINK_LIBRARIES(dfflows dfhack) ADD_EXECUTABLE(dfliquids liquids.cpp) TARGET_LINK_LIBRARIES(dfliquids dfhack) +# Solves the problem of unusable items after reclaim by clearing the 'in_job' bit of all items. +# Original author: Quietust +ADD_EXECUTABLE(dfcleartask cleartask.cpp) +TARGET_LINK_LIBRARIES(dfcleartask dfhack) + +# position - check the DF window and cursor parameters +ADD_EXECUTABLE(dfposition position.cpp) +TARGET_LINK_LIBRARIES(dfposition dfhack) + +# just dump offsets of the current version +ADD_EXECUTABLE(dfdoffsets dumpoffsets.cpp) +TARGET_LINK_LIBRARIES(dfdoffsets dfhack) + IF(UNIX) + SET(CURSES_NEED_WIDE "YES") + SET(CURSES_NEED_NCURSES "NO") + find_package(Curses QUIET) + IF(CURSES_FOUND) + if(CURSES_HAVE_NCURSESW_NCURSES_H) + SET(NCURSES_H "ncursesw/ncurses.h") + elseif(CURSES_HAVE_NCURSESW_CURSES_H) + SET(NCURSES_H "ncursesw/curses.h") + elseif(CURSES_HAVE_NCURSESW_H) + SET(NCURSES_H "ncursesw.h") + elseif(CURSES_HAVE_CURSESW_H) + SET(NCURSES_H "cursesw.h") + endif(CURSES_HAVE_NCURSESW_NCURSES_H) + IF(NCURSES_H) + # OPTION( VARIABLE "Description" Initial state) + #OPTION( WITH_FOO "Enable FOO support" ON ) + #OPTION( WITH_BAR "Enable BAR component" OFF ) + #SET( BAZ 18 ) + CONFIGURE_FILE( ${CMAKE_CURRENT_SOURCE_DIR}/fake-curses.h.cmake ${CMAKE_CURRENT_SOURCE_DIR}/fake-curses.h ) + # veinlook - look at the map... sort of + ADD_EXECUTABLE(dfveinlook veinlook.cpp) + INCLUDE_DIRECTORIES(${CURSES_INCLUDE_DIR}) + TARGET_LINK_LIBRARIES(dfveinlook dfhack ${CURSES_LIBRARIES}) + install(TARGETS + dfveinlook + RUNTIME DESTINATION bin + ) + ENDIF(NCURSES_H) + ELSE(CURSES_FOUND) + MESSAGE(STATUS "Wide-character ncurses library not found - veinlook can't be built") + ENDIF(CURSES_FOUND) +ENDIF(UNIX) + + install(TARGETS dfreveal dfprospector +dfposition dfvdig dfcleanmap dfunstuck dfprobe +dfdoffsets dfattachtest +dfcleartask dfexpbench dfsuspend dfflows dfliquids RUNTIME DESTINATION bin ) +IF(UNIX) + install(TARGETS + dfveinlook + RUNTIME DESTINATION bin + ) ENDIF(UNIX) diff --git a/tools/supported/cleartask.cpp b/tools/supported/cleartask.cpp new file mode 100644 index 000000000..267a686ff --- /dev/null +++ b/tools/supported/cleartask.cpp @@ -0,0 +1,73 @@ +// clears the "tasked" flag on all items +// original code by Quietust (http://www.bay12forums.com/smf/index.php?action=profile;u=18111) +#include +#include +#include +#include +#include +#include +using namespace std; + +#include +#include +#include + +int main () +{ + DFHack::Process * p; + unsigned int i; + DFHack::ContextManager DFMgr("Memory.xml"); + DFHack::Context * DF; + try + { + DF = DFMgr.getSingleContext(); + DF->Attach(); + } + catch (exception& e) + { + cerr << e.what() << endl; +#ifndef LINUX_BUILD + cin.ignore(); +#endif + return 1; + } + + DFHack::memory_info * mem = DF->getMemoryInfo(); + p = DF->getProcess(); + uint32_t item_vec_offset = 0; + try + { + item_vec_offset = p->getDescriptor()->getAddress ("items_vector"); + } + catch(DFHack::Error::MissingMemoryDefinition & e) + { + cerr << "missing offset for the item vector, exiting :(" << endl; + #ifndef LINUX_BUILD + cin.ignore(); + #endif + return 1; + } + + DFHack::DfVector p_items (p, item_vec_offset); + uint32_t size = p_items.size(); + + int numtasked = 0; + for (i=0;ireadDWord(p_items[i] + 0x0C); + if (flags.bits.in_job) + { + flags.bits.in_job = 0; + p->writeDWord(p_items[i] + 0x0C, flags.whole); + numtasked++; + } + } + cout << "Found and untasked " << numtasked << " items." << endl; + +#ifndef LINUX_BUILD + cout << "Done. Press any key to continue" << endl; + cin.ignore(); +#endif + return 0; +} \ No newline at end of file diff --git a/tools/supported/dumpoffsets.cpp b/tools/supported/dumpoffsets.cpp new file mode 100644 index 000000000..2257ca1de --- /dev/null +++ b/tools/supported/dumpoffsets.cpp @@ -0,0 +1,38 @@ +#include +#include +#include +#include +#include +#include +#include +using namespace std; + +#include +using namespace DFHack; + +int main (int numargs, const char ** args) +{ + DFHack::ContextManager DFMgr("Memory.xml"); + DFHack::Context * DF; + try + { + DF = DFMgr.getSingleContext(); + DF->Attach(); + } + catch (exception& e) + { + cerr << e.what() << endl; + #ifndef LINUX_BUILD + cin.ignore(); + #endif + return 1; + } + memory_info * minfo = DF->getMemoryInfo(); + if(minfo) + cout << minfo->PrintOffsets(); + #ifndef LINUX_BUILD + cout << "Done. Press any key to continue" << endl; + cin.ignore(); + #endif + return 0; +} diff --git a/tools/examples/fake-curses.h.cmake b/tools/supported/fake-curses.h.cmake similarity index 100% rename from tools/examples/fake-curses.h.cmake rename to tools/supported/fake-curses.h.cmake diff --git a/tools/supported/liquids.cpp b/tools/supported/liquids.cpp index d125c7ad1..b93c6cc29 100644 --- a/tools/supported/liquids.cpp +++ b/tools/supported/liquids.cpp @@ -26,6 +26,8 @@ int main (void) DF=DFMgr.getSingleContext(); DF->Attach(); Maps = DF->getMaps(); + Maps->Start(); + Maps->getSize(x_max,y_max,z_max); Position = DF->getPosition(); } catch (exception& e) @@ -44,7 +46,6 @@ int main (void) int amount = 7; while(!end) { - Maps->getSize(x_max,y_max,z_max); DF->Resume(); string command = ""; cout <<"[" << mode << ":" << amount << ":" << flowmode << "]# "; @@ -71,7 +72,6 @@ int main (void) << endl << "Usage: point the DF cursor at a tile you want to modify" << endl << "and use the commands available :)" << endl; - } else if(command == "m") { diff --git a/tools/examples/position.cpp b/tools/supported/position.cpp similarity index 100% rename from tools/examples/position.cpp rename to tools/supported/position.cpp diff --git a/tools/supported/probe.cpp b/tools/supported/probe.cpp index 4353d48ba..832562dc5 100644 --- a/tools/supported/probe.cpp +++ b/tools/supported/probe.cpp @@ -7,10 +7,10 @@ #include #include #include -using namespace std; +#define DFHACK_WANT_MISCUTILS +#define DFHACK_WANT_TILETYPES #include -#include using namespace DFHack; int main (int numargs, const char ** args) @@ -22,9 +22,9 @@ int main (int numargs, const char ** args) { DF->Attach(); } - catch (exception& e) + catch (std::exception& e) { - cerr << e.what() << endl; + std::cerr << e.what() << std::endl; #ifndef LINUX_BUILD cin.ignore(); #endif @@ -68,59 +68,59 @@ int main (int numargs, const char ** args) int16_t tiletype = block.tiletypes[tileX][tileY]; naked_designation &des = block.designation[tileX][tileY].bits; uint32_t &desw = block.designation[tileX][tileY].whole; - print_bits(block.designation[tileX][tileY].whole,cout); - cout << endl; - print_bits(block.occupancy[tileX][tileY].whole,cout); - cout << endl; + print_bits(block.designation[tileX][tileY].whole,std::cout); + std::cout << endl; + print_bits(block.occupancy[tileX][tileY].whole,std::cout); + std::cout << endl; // tiletype - cout <<"tiletype: " << tiletype; + std::cout <<"tiletype: " << tiletype; if(tileTypeTable[tiletype].name) - cout << " = " << tileTypeTable[tiletype].name; - cout << endl; + std::cout << " = " << tileTypeTable[tiletype].name; + std::cout << std::endl; - cout <<"temperature1: " << tmpb1[tileX][tileY] << " U" << endl; - cout <<"temperature2: " << tmpb2[tileX][tileY] << " U" << endl; + std::cout <<"temperature1: " << tmpb1[tileX][tileY] << " U" << std::endl; + std::cout <<"temperature2: " << tmpb2[tileX][tileY] << " U" << std::endl; // biome, geolayer - cout << "biome: " << des.biome << endl; - cout << "geolayer: " << des.geolayer_index << endl; + std::cout << "biome: " << des.biome << std::endl; + std::cout << "geolayer: " << des.geolayer_index << std::endl; // liquids if(des.flow_size) { if(des.liquid_type == DFHack::liquid_magma) - cout <<"magma: "; - else cout <<"water: "; - cout << des.flow_size << endl; + std::cout <<"magma: "; + else std::cout <<"water: "; + std::cout << des.flow_size << std::endl; } if(des.flow_forbid) - cout << "flow forbid" << endl; + std::cout << "flow forbid" << std::endl; if(des.pile) - cout << "stockpile?" << endl; + std::cout << "stockpile?" << std::endl; if(des.rained) - cout << "rained?" << endl; + std::cout << "rained?" << std::endl; if(des.smooth) - cout << "smooth?" << endl; + std::cout << "smooth?" << std::endl; uint32_t designato = block.origin + designatus + (tileX * 16 + tileY) * sizeof(t_designation); printf("designation offset: 0x%x\n", designato); if(des.light) - cout << "Light "; + std::cout << "Light "; else - cout << " "; + std::cout << " "; if(des.skyview) - cout << "SkyView "; + std::cout << "SkyView "; else - cout << " "; + std::cout << " "; if(des.subterranean) - cout << "Underground "; + std::cout << "Underground "; else - cout << " "; - cout << endl; + std::cout << " "; + std::cout << std::endl; } } #ifndef LINUX_BUILD - cout << "Done. Press any key to continue" << endl; + std::cout << "Done. Press any key to continue" << std::endl; cin.ignore(); #endif return 0; diff --git a/tools/supported/prospector.cpp b/tools/supported/prospector.cpp index 514be1e3e..e7e0e9237 100644 --- a/tools/supported/prospector.cpp +++ b/tools/supported/prospector.cpp @@ -13,11 +13,32 @@ #include #include #include +#include using namespace std; #include #include +template