diff --git a/.gitignore b/.gitignore index 5abcc3138..356bf6399 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ output/* # a file generated by cmake dfhack/include/config.h +library/private/config.h # any build folders build*/ diff --git a/CMakeLists.txt b/CMakeLists.txt index a03f7d6cc..b794b7143 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,11 @@ cmake_minimum_required(VERSION 2.6) SET(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/CMake/Modules) SET ( DFHACK_VERSION "0.4.1.0-dev" ) +# Set this to project source dir. When dfhack is used +# as a submodule, CMAKE_SOURCE_DIR is not pointing to +# the root where this particular CMakeLists.txt file sits. +SET(CMAKE_SOURCE_DIR ${PROJECT_SOURCE_DIR}) + # disable warning, autosearch if(COMMAND cmake_policy) cmake_policy(SET CMP0003 NEW) @@ -26,6 +31,8 @@ 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) +OPTION(BUILD_DFHACK_SUPPORTED "Build the supported toold." ON) +OPTION(BUILD_DFHACK_SHM "Build the SHM." OFF) include_directories (${CMAKE_SOURCE_DIR}/library/include/) include_directories (${CMAKE_SOURCE_DIR}/library/shm/) @@ -35,12 +42,26 @@ include_directories (${CMAKE_SOURCE_DIR}/library/depends/argstream/) add_subdirectory (library) +IF(BUILD_DFHACK_SUPPORTED) + add_subdirectory (tools/supported) +ENDIF(BUILD_DFHACK_SUPPORTED) + 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 +IF(BUILD_DFHACK_SHM) + add_subdirectory (library/shm) +ENDIF(BUILD_DFHACK_SHM) + +IF(BUILD_DFHACK_EXAMPLES) + add_subdirectory (tools/examples) +ENDIF(BUILD_DFHACK_EXAMPLES) + +IF(BUILD_DFHACK_PLAYGROUND) + add_subdirectory (tools/playground) +ENDIF(BUILD_DFHACK_PLAYGROUND) + +IF(BUILD_DFHACK_DOCUMENTATION) + add_subdirectory (doc) +ENDIF(BUILD_DFHACK_DOCUMENTATION) diff --git a/build/build-MinGW32-release-trace.bat b/build/build-MinGW32-release-trace.bat index f75da5ff8..ca7df86d3 100644 --- a/build/build-MinGW32-release-trace.bat +++ b/build/build-MinGW32-release-trace.bat @@ -1,6 +1,6 @@ -mkdir build-real -cd build-real -cmake ..\.. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE:string=Release --trace > trace-stdout.txt 2> trace-stderr.txt -mingw32-make 2> log.txt -pause +mkdir build-real +cd build-real +cmake ..\.. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE:string=Release --trace > trace-stdout.txt 2> trace-stderr.txt +mingw32-make 2> log.txt +pause dir file.xxx \ No newline at end of file diff --git a/build/generate-MSVC-2010.bat b/build/generate-MSVC-2010.bat index 588051bc6..50828f7ea 100644 --- a/build/generate-MSVC-2010.bat +++ b/build/generate-MSVC-2010.bat @@ -1,4 +1,4 @@ -mkdir build-real -cd build-real -cmake ..\.. -G"Visual Studio 10" +mkdir build-real +cd build-real +cmake ..\.. -G"Visual Studio 10" pause \ No newline at end of file diff --git a/data/Memory-ng.xml b/data/Memory-ng.xml index 294886988..fdb84d2b1 100644 --- a/data/Memory-ng.xml +++ b/data/Memory-ng.xml @@ -144,363 +144,216 @@ - TODO: Parse this and turn it into Job tags - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -813,20 +666,242 @@ +
+ + + + + + + + + + +
- +
+
+ + +
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + +
+ + + + + +
+
+ + + + + vector + vector + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + +
+ + + +
+ + + +
+
+ + + +
+ + + +
+ +
+ + + + +
+ + + + + + +
+ List of offsets in the VTable : + + + + + + + + + + (in the vtable) + + +
+
+
@@ -879,6 +954,11 @@ + + + + + @@ -963,7 +1043,7 @@ -
+
@@ -1009,11 +1089,11 @@ 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 ? + 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 ? @@ -1057,7 +1137,7 @@ -
+
@@ -1145,7 +1225,7 @@ -
+
@@ -1157,12 +1237,12 @@ -
-
-
-
-
+
+
+
+
+
@@ -1214,21 +1294,22 @@ -
+
-
-
-
-
-
+
+ +
+
+
+
-
-
-
+
+
+
@@ -1257,7 +1338,7 @@
-
+
@@ -1266,10 +1347,10 @@ -
+
-
+
@@ -1348,10 +1429,11 @@
-
+
+ @@ -1383,8 +1465,170 @@ + + +
+ + +
+ + + + + + +
+ + + + + + + + + + + + + + 0x01482874 - current race + +
+
+
+
+
+
+ + +
+ + +
+ + +
+ + +
+
+
+
+
+
+
+
+ +
+ +
+ +
+
+ + + +
+ + + +
+ + + + +
+
+ + + + +
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + +
+ + +
+
+
+ + + + + 31.13 WEATHER_START 0147E94E .-"""-. ' \ |,. ,-. | _________________________ @@ -1407,7 +1651,7 @@ - +
@@ -1438,9 +1682,6 @@
-
-
-
@@ -1462,8 +1703,8 @@ - - + + @@ -1488,11 +1729,11 @@ vector - vector + vector -
+
@@ -1500,7 +1741,7 @@ - + @@ -1508,8 +1749,8 @@ - CHMOD - VERIFY! + CHMOD + VERIFY! chmod @@ -1523,26 +1764,29 @@ - + +
@@ -1555,6 +1799,8 @@ + @@ -1584,26 +1831,18 @@
- -
- -
- -
- -
- +
@@ -1618,18 +1857,36 @@ 0x92d7a10 - + - + - + + + + + + + + + + + + + + + CHMOD + + + + - + @@ -1647,18 +1904,104 @@ - + -
VERIFIED -
VERIFIED -
VERIFIED -
VERIFIED + +
VERIFIED +
VERIFIED +
VERIFIED +
VERIFIED + - + + + + +
+ + +
+ + +
+ + + +
+ + +
+ + + +
+ + + + + + + +
+ + +
+ + +
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+ + +
+ + +
+ + + +
+
+ + + +
+
+
+
+
+
+ + +
+ + +
+ + +
+
+
+ + diff --git a/data/Memory.xml b/data/Memory.xml index fd0072623..381e39708 100644 --- a/data/Memory.xml +++ b/data/Memory.xml @@ -1698,6 +1698,7 @@ map_data_1b60_offset 0x1B9c
0x168E73C
0x014b9f1c
0X1F4 + 0x2FC 0x4AC 0x64c 0x71c @@ -1721,6 +1722,7 @@ map_data_1b60_offset 0x1B9c f0459165a426a9f2dd8d957e9fa7f01d 0x4C4C32E7 +
0x18313D0
.-"""-. ' \ @@ -2359,6 +2361,7 @@ map_data_1b60_offset 0x1B9c e79cead03187ecb692961b316b7cdcd4 +
0x09487970
diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 1ced1fd7b..c1f2cdaca 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -10,8 +10,6 @@ # http://tobias.rautenkranz.ch/cmake/doxygen/ # but it is hard to understand... -IF (BUILD_DFHACK_DOCUMENTATION) - FIND_PACKAGE(Doxygen) IF(DOXYGEN_FOUND) @@ -63,6 +61,4 @@ IF(DOXYGEN_FOUND) 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 +ENDIF(DOXYGEN_FOUND) \ No newline at end of file diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 8e09a2203..813d356dc 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -26,20 +26,29 @@ include_directories (${CMAKE_SOURCE_DIR}/library/depends/tinyxml/) include_directories (${CMAKE_SOURCE_DIR}/library/depends/argstream/) include_directories (${CMAKE_SOURCE_DIR}/library/private/) +SET(PROJECT_HDRS_INTERNAL + private/ContextShared.h + private/Internal.h +) + SET(PROJECT_HDRS -private/DFMemInfoManager.h -private/ContextShared.h -private/Internal.h +include/DFHack.h +include/dfhack/DFContext.h +include/dfhack/DFContextManager.h include/dfhack/DFError.h -include/dfhack/DFMemInfo.h -include/dfhack/DFProcessEnumerator.h +include/dfhack/DFExport.h +include/dfhack/DFGlobal.h +include/dfhack/DFIntegers.h +include/dfhack/DFMiscUtils.h +include/dfhack/DFModule.h +include/dfhack/DFPragma.h include/dfhack/DFProcess.h +include/dfhack/DFProcessEnumerator.h include/dfhack/DFTileTypes.h include/dfhack/DFTypes.h include/dfhack/DFVector.h -include/dfhack-c/DFTypes_C.h -include/dfhack-c/DFContext_C.h -include/dfhack/DFIntegers.h +include/dfhack/VersionInfoFactory.h +include/dfhack/VersionInfo.h include/dfhack/modules/Buildings.h include/dfhack/modules/Constructions.h include/dfhack/modules/Creatures.h @@ -55,13 +64,26 @@ include/dfhack/modules/World.h ) SET(PROJECT_C_HDRS +include/DFHack_C.h include/dfhack-c/DFTypes_C.h include/dfhack-c/DFContext_C.h +include/dfhack-c/modules/Buildings_C.h +include/dfhack-c/modules/Constructions_C.h +include/dfhack-c/modules/Creatures_C.h +include/dfhack-c/modules/Gui_C.h +include/dfhack-c/modules/Items_C.h +include/dfhack-c/modules/Maps_C.h +include/dfhack-c/modules/Materials_C.h +include/dfhack-c/modules/Position_C.h +include/dfhack-c/modules/Translation_C.h +include/dfhack-c/modules/Vegetation_C.h +include/dfhack-c/modules/WindowIO_C.h +include/dfhack-c/modules/World_C.h ) SET(PROJECT_SRCS -DFMemInfo.cpp -DFMemInfoManager.cpp +VersionInfo.cpp +VersionInfoFactory.cpp DFContextManager.cpp DFContext.cpp DFProcessEnumerator.cpp @@ -134,10 +156,10 @@ ELSE(UNIX) LIST(APPEND PROJECT_SRCS ${PROJECT_SRCS_WINDOWS}) ENDIF(UNIX) -IF(BUILD_DFHACK_C_BINDIGS) +IF(BUILD_DFHACK_C_BINDINGS) LIST(APPEND PROJECT_HDRS ${PROJECT_C_HDRS}) LIST(APPEND PROJECT_SRCS ${PROJECT_C_SRCS}) -ENDIF(BUILD_DFHACK_C_BINDIGS) +ENDIF(BUILD_DFHACK_C_BINDINGS) SET_SOURCE_FILES_PROPERTIES( ${PROJECT_HDRS} PROPERTIES HEADER_FILE_ONLY TRUE ) @@ -147,7 +169,7 @@ SET( MEMXML_DATA_PATH . CACHE PATH "search path for Memory.xml") # OPTION( VARIABLE "Description" Initial state) #OPTION( WITH_FOO "Enable FOO support" ON ) #OPTION( WITH_BAR "Enable BAR component" OFF ) - + # Are we 64bit? (Damn you, ptrace()!) IF( CMAKE_SIZEOF_VOID_P MATCHES 4 ) SET( HAVE_64_BIT 0 ) @@ -165,7 +187,7 @@ IF(UNIX) find_library(X11_LIBRARY X11) SET(CMAKE_CXX_FLAGS_DEBUG "-g -Wall") SET(CMAKE_CXX_FLAGS "-fvisibility=hidden") - + SET(PROJECT_LIBS ${X11_LIBRARY} rt ) #dfhack-md5 dfhack-tixml ELSE(UNIX) SET(PROJECT_LIBS psapi) @@ -184,7 +206,7 @@ if(MSVC) # # 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 + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/data/Memory-ng.xml $(TargetDir)/Memory.xml ) ADD_CUSTOM_COMMAND(TARGET dfhack POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/Compile.html $(TargetDir)/Compile.html @@ -192,14 +214,19 @@ if(MSVC) ADD_CUSTOM_COMMAND(TARGET dfhack POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/Readme.html $(TargetDir)/Readme.html ) + ADD_CUSTOM_COMMAND(TARGET dfhack POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/LICENSE $(TargetDir)/LICENSE.txt + ) 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}/data/Memory-ng.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) + configure_file(${CMAKE_SOURCE_DIR}/LICENSE ${DATA_OUTPUT_PATH}/LICENSE.txt COPYONLY) endif(MSVC) IF(UNIX) install(TARGETS dfhack LIBRARY DESTINATION lib) install(FILES ${CMAKE_SOURCE_DIR}/output/Memory.xml DESTINATION share/dfhack) + install(DIRECTORY ${CMAKE_SOURCE_DIR}/library/include/ DESTINATION include FILES_MATCHING PATTERN "*.h") ENDIF(UNIX) diff --git a/library/ContextShared.cpp b/library/ContextShared.cpp index cf49a489b..62ca3fff1 100644 --- a/library/ContextShared.cpp +++ b/library/ContextShared.cpp @@ -4,7 +4,7 @@ #include #include #include "private/ContextShared.h" -#include "dfhack/DFMemInfo.h" +#include "dfhack/VersionInfo.h" #include "dfhack/DFProcess.h" #include "dfhack/modules/Materials.h" @@ -40,9 +40,10 @@ DFContextShared::~DFContextShared() bool DFContextShared::InitReadNames() { - name_firstname_offset = offset_descriptor->getOffset("name_firstname"); - name_nickname_offset = offset_descriptor->getOffset("name_nickname"); - name_words_offset = offset_descriptor->getOffset("name_words"); + OffsetGroup * OG = offset_descriptor->getGroup("name"); + name_firstname_offset = OG->getOffset("first"); + name_nickname_offset = OG->getOffset("nick"); + name_words_offset = OG->getOffset("second_words"); return true; } diff --git a/library/DFContext.cpp b/library/DFContext.cpp index d46302426..8b67f193f 100644 --- a/library/DFContext.cpp +++ b/library/DFContext.cpp @@ -199,7 +199,7 @@ void Context::WriteRaw (const uint32_t offset, const uint32_t size, uint8_t *sou d->p->write (offset, size, source); } -memory_info *Context::getMemoryInfo() +VersionInfo *Context::getMemoryInfo() { return d->offset_descriptor; } diff --git a/library/DFContextManager.cpp b/library/DFContextManager.cpp index 46814d90e..f338ce6ee 100644 --- a/library/DFContextManager.cpp +++ b/library/DFContextManager.cpp @@ -23,8 +23,8 @@ distribution. */ #include "Internal.h" -#include "DFMemInfoManager.h" +#include "dfhack/VersionInfoFactory.h" #include "dfhack/DFProcess.h" #include "dfhack/DFProcessEnumerator.h" #include "dfhack/DFError.h" @@ -142,7 +142,7 @@ ContextManager::~ContextManager() uint32_t ContextManager::Refresh( BadContexts* bad_contexts ) { - // handle expired processes, remove stale Contexts + // handle expired processes, remove stale Contexts { BadProcesses expired; // get new list od living and expired Process objects diff --git a/library/DFMemInfo.cpp b/library/DFMemInfo.cpp deleted file mode 100644 index ca7c58d03..000000000 --- a/library/DFMemInfo.cpp +++ /dev/null @@ -1,778 +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/DFMemInfo.h" -#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 - */ -class memory_info::Private -{ - public: - map addresses; - map offsets; - map hexvals; - map strings; - - vector professions; - vector jobs; - vector skills; - vector levels; - vector< vector > traits; - vector moods; - map labors; - - // storage for class and multiclass - vector classes; - - // cache for faster name lookup, indexed by classID - vector classnames; - // map between vptr and class id, needs further type id lookup for multi-classes, not inherited - map classIDs; - - // index for the next added class - uint32_t classindex; - - int32_t base; - Process * p; // the process this belongs to - - string version; - OSType OS; -}; - -// normal constructor -memory_info::memory_info() -:d(new Private) -{ - d->base = 0; - d->p = 0; - d->classindex = 0; - d->levels.reserve(NUM_RESERVE_LVLS); - d->moods.reserve(NUM_RESERVE_MOODS); -} - -// copy constructor -memory_info::memory_info(const memory_info &old) -:d(new Private) -{ - d->version = old.d->version; - d->OS = old.d->OS; - d->addresses = old.d->addresses; - d->offsets = old.d->offsets; - d->hexvals = old.d->hexvals; - d->strings = old.d->strings; - d->base = old.d->base; - //d->classes = old.d->classes; - for(uint32_t i = 0; i < old.d->classes.size(); i++) - { - t_class * copy = new t_class(*old.d->classes[i]); - d->classes.push_back(copy); - } - d->classnames = old.d->classnames; - d->classindex = old.d->classindex; - d->professions = old.d->professions; - d->jobs = old.d->jobs; - 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) -{ - d->p = _p; -} - -// destructor -memory_info::~memory_info() -{ - // delete the vtables - for(uint32_t i = 0; i < d->classes.size();i++) - { - delete d->classes[i]; - } - // delete our data - delete d; -} - -void memory_info::setVersion(const char * v) -{ - d->version = v; -} - - -void memory_info::setVersion(const string &v) -{ - d->version = v; -} - - -string memory_info::getVersion() -{ - return d->version; -} - - -void memory_info::setOS(const char *os) -{ - string oss = os; - if(oss == "windows") - d->OS = OS_WINDOWS; - else if(oss == "linux") - d->OS = OS_LINUX; - else - d->OS = OS_BAD; -} - - -void memory_info::setOS(const string &os) -{ - if(os == "windows") - d->OS = OS_WINDOWS; - else if(os == "linux") - d->OS = OS_LINUX; - else - d->OS = OS_BAD; -} - - -void memory_info::setOS(OSType os) -{ - if(os >= OS_WINDOWS && os < OS_BAD) - { - d->OS = os; - return; - } - d->OS = OS_BAD; -} - - -memory_info::OSType memory_info::getOS() const -{ - return d->OS; -} - -uint32_t memory_info::getBase () const -{ - return d->base; -} - - -void memory_info::setBase (const string &s) -{ - d->base = strtol(s.c_str(), NULL, 16); -} - - -void memory_info::setBase (const uint32_t b) -{ - d->base = b; -} - - -void memory_info::setOffset (const string & key, const string & value) -{ - int32_t offset = strtol(value.c_str(), NULL, 16); - d->offsets[key] = offset; -} - - -void memory_info::setAddress (const string & key, const string & value) -{ - uint32_t address = strtol(value.c_str(), NULL, 16); - d->addresses[key] = address; -} - - -void memory_info::setHexValue (const string & key, const string & value) -{ - uint32_t hexval = strtol(value.c_str(), NULL, 16); - d->hexvals[key] = hexval; -} - - -void memory_info::setString (const string & key, const string & value) -{ - d->strings[key] = value; -} - -void memory_info::setLabor(const string & key, const string & value) -{ - uint32_t keyInt = strtol(key.c_str(), NULL, 10); - d->labors[keyInt] = value; -} - -void memory_info::setProfession (const string & key, const string & value) -{ - uint32_t keyInt = strtol(key.c_str(), NULL, 10); - if(d->professions.size() <= keyInt) - { - d->professions.resize(keyInt+1,""); - } - d->professions[keyInt] = value; -} - -void memory_info::setJob (const string & key, const string & value) -{ - uint32_t keyInt = strtol(key.c_str(), NULL, 10); - if(d->jobs.size() <= keyInt) - { - d->jobs.resize(keyInt+1); - } - d->jobs[keyInt] = value; -} - -void memory_info::setSkill (const string & key, const string & value) -{ - uint32_t keyInt = strtol(key.c_str(), NULL, 10); - if(d->skills.size() <= keyInt){ - d->skills.resize(keyInt+1); - } - 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, - const string & one, - const string & two, - const string & three, - const string & four, - const string & five) -{ - uint32_t keyInt = strtol(key.c_str(), NULL, 10); - if(d->traits.size() <= keyInt) - { - d->traits.resize(keyInt+1); - } - d->traits[keyInt].push_back(zero); - d->traits[keyInt].push_back(one); - d->traits[keyInt].push_back(two); - d->traits[keyInt].push_back(three); - d->traits[keyInt].push_back(four); - d->traits[keyInt].push_back(five); - d->traits[keyInt].push_back(value); -} - -// FIXME: next three methods should use some kind of custom container so it doesn't have to search so much. -t_class * memory_info::setClass (const char * name, uint32_t vtable, uint32_t typeoffset) -{ - if(name == 0) - return 0; - for (uint32_t i=0; iclasses.size(); i++) - { - if(d->classes[i]->classname == name) - { - if(vtable != 0) - d->classes[i]->vtable = vtable; - if(typeoffset != 0) - d->classes[i]->type_offset = typeoffset; - return d->classes[i]; - } - } - - t_class *cls = new t_class(); - // get an unique ID and add ourselves to the index - cls->assign = d->classindex; - cls->classname = name; - d->classnames.push_back(name); - - // vtables no longer a requirement - cls->vtable = vtable; - - // multi class yes/no - cls->type_offset = typeoffset; - - d->classes.push_back(cls); - d->classindex++; - return cls; - -} - - -void memory_info::setClassChild (t_class * parent, const char * name, const char * type) -{ - vector & vec = parent->subs; - for (uint32_t i=0; iclassname == name) - { - vec[i]->type = strtol(type, NULL, 16); - return; - } - } - // new multiclass child - t_type *mcc = new t_type(d->classindex,strtol(type, NULL, 16),name); - d->classnames.push_back(name); - vec.push_back(mcc); - d->classindex++; - - //cout << " classtype " << name << ", assign " << mcc->assign << ", vtable " << mcc->type << endl; -} - -// FIXME: stupid. we need a better container -bool memory_info::resolveObjectToClassID(const uint32_t address, int32_t & classid) -{ - uint32_t vtable = d->p->readDWord(address); - // try to find the vtable in our cache - map::iterator it; - it = d->classIDs.find(vtable); - t_class * cl; - - // class found in cache? - if(it != d->classIDs.end()) - { - cl = (*it).second; - } - else// couldn't find? - { - // we set up the class for the first time - string classname = d->p->readClassName(vtable); - d->classIDs[vtable] = cl = setClass(classname.c_str(),vtable); - } - // and isn't a multi-class - if(!cl->type_offset) - { - // return - classid = cl->assign; - return true; - } - // and is a multiclass - else - { - // find the type - vector & vec = cl->subs; - uint32_t type = d->p->readWord(address + cl->type_offset); - // return typed building if successful - //FIXME: the vector should map directly to the type IDs here, so we don't have to mess with O(n) search - for (uint32_t k = 0; k < vec.size();k++) - { - if(vec[k]->type == type) - { - //cout << " multi " << address + classes[i].type_offset << " " << vec[k].classname << endl; - classid = vec[k]->assign; - return true; - } - } - // couldn't find the type... now what do we do here? throw? - // this is a case where it might be a good idea, because it uncovers some deeper problems - // we return the parent class instead, it doesn't change the API semantics and sort-of makes sense - classid = cl->assign; - return true; - } -} - -//ALERT: doesn't care about multiclasses -bool memory_info::resolveClassnameToVPtr(const string classname, uint32_t & vptr) -{ - // FIXME: another stupid search. - for(uint32_t i = 0;i< d->classes.size();i++) - { - //if(classes[i].) - if(d->classes[i]->classname == classname) // got class - { - vptr = d->classes[i]->vtable; - return true; - } - } - // we failed to find anything that would match - return false; -} - -bool memory_info::resolveClassnameToClassID (const string classname, int32_t & classID) -{ - // FIXME: another stupid search. - classID = -1; - for(uint32_t i = 0;i< d->classnames.size();i++) - { - if(d->classnames[i] == classname) - { - classID = i; - return true; - } - } - // we failed to find anything that would match - return false; -} - -bool memory_info::resolveClassIDToClassname (const int32_t classID, string & classname) -{ - if (classID >=0 && (uint32_t)classID < d->classnames.size()) - { - classname = d->classnames[classID]; - return true; - } - return false; -} - - -// return pointer to our internal classID -> className mapping -const vector * memory_info::getClassIDMapping() -{ - return &d->classnames; -} - - -// change base of all addresses -void memory_info::RebaseAddresses(const int32_t new_base) -{ - map::iterator iter; - int32_t rebase = - (int32_t)d->base + new_base; - for(iter = d->addresses.begin(); iter != d->addresses.end(); iter++) - { - d->addresses[iter->first] = iter->second + rebase; - } -} - - -// change base of all addresses *and* vtable entries -void memory_info::RebaseAll(int32_t new_base) -{ - map::iterator iter; - int32_t rebase = - (int32_t)d->base + new_base; - for(iter = d->addresses.begin(); iter != d->addresses.end(); iter++) - { - d->addresses[iter->first] = iter->second + rebase; - } - RebaseVTable(rebase); -} - - -// change all vtable entries by offset -void memory_info::RebaseVTable(int32_t offset) -{ - vector::iterator iter; - for(iter = d->classes.begin(); iter != d->classes.end(); iter++) - { - (*iter)->vtable += offset; - } -} - -// Get named address -uint32_t memory_info::getAddress (const char *key) -{ - map ::iterator iter = d->addresses.find(key); - - if(iter != d->addresses.end()) - { - return (*iter).second; - } - throw Error::MissingMemoryDefinition("address", key); -} - - -// Get named offset -int32_t memory_info::getOffset (const char *key) -{ - map ::iterator iter = d->offsets.find(key); - if(iter != d->offsets.end()) - { - return (*iter).second; - } - throw Error::MissingMemoryDefinition("offset", key); -} - -// Get named numerical value -uint32_t memory_info::getHexValue (const char *key) -{ - map ::iterator iter = d->hexvals.find(key); - if(iter != d->hexvals.end()) - { - return (*iter).second; - } - throw Error::MissingMemoryDefinition("hexvalue", key); -} - - -// Get named address -uint32_t memory_info::getAddress (const string &key) -{ - map ::iterator iter = d->addresses.find(key); - - if(iter != d->addresses.end()) - { - return (*iter).second; - } - throw Error::MissingMemoryDefinition("address", key.c_str()); -} - - -// Get named offset -int32_t memory_info::getOffset (const string &key) -{ - map ::iterator iter = d->offsets.find(key); - if(iter != d->offsets.end()) - { - return (*iter).second; - } - throw Error::MissingMemoryDefinition("offset", key.c_str()); -} - -// Get named numerical value -uint32_t memory_info::getHexValue (const string &key) -{ - map ::iterator iter = d->hexvals.find(key); - if(iter != d->hexvals.end()) - { - return (*iter).second; - } - throw Error::MissingMemoryDefinition("hexvalue", key.c_str()); -} - -// Get named string -std::string memory_info::getString (const string &key) -{ - map ::iterator iter = d->strings.find(key); - if(iter != d->strings.end()) - { - return (*iter).second; - } - throw Error::MissingMemoryDefinition("string", key.c_str()); -} - -// Get Profession -string memory_info::getProfession (const uint32_t key) const -{ - if(d->professions.size() > key) - { - return d->professions[key]; - } - throw Error::MissingMemoryDefinition("profession", key); -} - -// Get Job -string memory_info::getJob (const uint32_t key) const -{ - if(d->jobs.size() > key) - - { - return d->jobs[key]; - } - throw Error::MissingMemoryDefinition("job", key); -} - -string memory_info::getSkill (const uint32_t key) const -{ - if(d->skills.size() > key) - { - return d->skills[key]; - } - 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) -{ - if (number < 0) - return -number; - return number; -} - -string memory_info::getTrait (const uint32_t traitIdx, const uint32_t traitValue) const -{ - if(d->traits.size() > traitIdx) - { - int diff = absolute(traitValue-50); - if(diff < 10) - { - return string(""); - } - if (traitValue >= 91) - return d->traits[traitIdx][5]; - else if (traitValue >= 76) - return d->traits[traitIdx][4]; - else if (traitValue >= 61) - return d->traits[traitIdx][3]; - else if (traitValue >= 25) - return d->traits[traitIdx][2]; - else if (traitValue >= 10) - return d->traits[traitIdx][1]; - else - return d->traits[traitIdx][0]; - } - throw Error::MissingMemoryDefinition("trait", traitIdx); -} - -string memory_info::getTraitName(const uint32_t traitIdx) const -{ - if(d->traits.size() > traitIdx) - { - return d->traits[traitIdx][d->traits[traitIdx].size()-1]; - } - 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)) - { - return d->labors[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 deleted file mode 100644 index cc4c5de4a..000000000 --- a/library/DFMemInfoManager.cpp +++ /dev/null @@ -1,297 +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 "DFMemInfoManager.h" - -#include "dfhack/DFMemInfo.h" -#include "dfhack/DFError.h" - -using namespace DFHack; - -MemInfoManager::~MemInfoManager() -{ - // for each in std::vector meminfo;, delete - for(uint32_t i = 0; i < meminfo.size();i++) - { - delete meminfo[i]; - } - meminfo.clear(); -} - -void MemInfoManager::ParseVTable(TiXmlElement* vtable, memory_info* mem) -{ - TiXmlElement* pClassEntry; - TiXmlElement* pClassSubEntry; - // check for rebase, do rebase if check positive - const char * rebase = vtable->Attribute("rebase"); - if(rebase) - { - int32_t rebase_offset = strtol(rebase, NULL, 16); - mem->RebaseVTable(rebase_offset); - } - // parse vtable entries - pClassEntry = vtable->FirstChildElement(); - for(;pClassEntry;pClassEntry=pClassEntry->NextSiblingElement()) - { - string type = pClassEntry->Value(); - const char *cstr_name = pClassEntry->Attribute("name"); - const char *cstr_vtable = pClassEntry->Attribute("vtable"); - uint32_t vtable = 0; - if(cstr_vtable) - vtable = strtol(cstr_vtable, NULL, 16); - // it's a simple class - if(type== "class") - { - mem->setClass(cstr_name, vtable); - } - // it's a multi-type class - else if (type == "multiclass") - { - // get offset of the type variable - const char *cstr_typeoffset = pClassEntry->Attribute("typeoffset"); - uint32_t typeoffset = 0; - if(cstr_typeoffset) - typeoffset = strtol(cstr_typeoffset, NULL, 16); - t_class * mclass = mem->setClass(cstr_name, vtable, typeoffset); - // parse class sub-entries - pClassSubEntry = pClassEntry->FirstChildElement(); - for(;pClassSubEntry;pClassSubEntry=pClassSubEntry->NextSiblingElement()) - { - type = pClassSubEntry->Value(); - if(type== "class") - { - // type is a value loaded from type offset - cstr_name = pClassSubEntry->Attribute("name"); - const char *cstr_value = pClassSubEntry->Attribute("type"); - mem->setClassChild(mclass,cstr_name,cstr_value); - } - } - } - } -} - - - -void MemInfoManager::ParseEntry (TiXmlElement* entry, memory_info* mem, map & knownEntries) -{ - TiXmlElement* pMemEntry; - const char *cstr_version = entry->Attribute("version"); - const char *cstr_os = entry->Attribute("os"); - const char *cstr_base = entry->Attribute("base"); - const char *cstr_rebase = entry->Attribute("rebase"); - if(cstr_base) - { - string base = cstr_base; - ParseEntry(knownEntries[base], mem, knownEntries); - } - - if (!cstr_version) - throw Error::MemoryXmlBadAttribute("version"); - if (!cstr_os) - throw Error::MemoryXmlBadAttribute("os"); - - string os = cstr_os; - mem->setVersion(cstr_version); - mem->setOS(cstr_os); - - // offset inherited addresses by 'rebase'. - int32_t rebase = 0; - if(cstr_rebase) - { - rebase = mem->getBase() + strtol(cstr_rebase, NULL, 16); - mem->RebaseAddresses(rebase); - } - - //set base to default, we're overwriting this because the previous rebase could cause havoc on Vista/7 - if(os == "windows") - { - // set default image base. this is fixed for base relocation later - mem->setBase(0x400000); - } - else if(os == "linux") - { - // this is wrong... I'm not going to do base image relocation on linux though. - // users are free to use a sane kernel that doesn't do this kind of **** by default - mem->setBase(0x0); - } - else if ( os == "all") - { - // yay - } - else - { - throw Error::MemoryXmlBadAttribute("os"); - } - - // process additional entries - //cout << "Entry " << cstr_version << " " << cstr_os << endl; - pMemEntry = entry->FirstChildElement()->ToElement(); - for(;pMemEntry;pMemEntry=pMemEntry->NextSiblingElement()) - { - // only elements get processed - const char *cstr_type = pMemEntry->Value(); - 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; - if(type == "VTable") - { - ParseVTable(pMemEntry, mem); - continue; - } - if(!(cstr_name && cstr_value)) - { - throw Error::MemoryXmlUnderspecifiedEntry(cstr_version); - } - name = cstr_name; - value = cstr_value; - if (type == "HexValue") - { - mem->setHexValue(name, value); - } - else if (type == "Address") - { - mem->setAddress(name, value); - } - else if (type == "Offset") - { - mem->setOffset(name, value); - } - else if (type == "String") - { - mem->setString(name, value); - } - else if (type == "Profession") - { - mem->setProfession(value,name); - } - else if (type == "Job") - { - mem->setJob(value,name); - } - else if (type == "Skill") - { - mem->setSkill(value,name); - } - else if (type == "Trait") - { - mem->setTrait(value, name,pMemEntry->Attribute("level_0"),pMemEntry->Attribute("level_1"),pMemEntry->Attribute("level_2"),pMemEntry->Attribute("level_3"),pMemEntry->Attribute("level_4"),pMemEntry->Attribute("level_5")); - } - else if (type == "Labor") - { - mem->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()); - } - } // for -} // method - -MemInfoManager::MemInfoManager(string path_to_xml) -{ - error = false; - loadFile(path_to_xml); -} - -// load the XML file with offsets -bool MemInfoManager::loadFile(string path_to_xml) -{ - TiXmlDocument doc( path_to_xml.c_str() ); - //bool loadOkay = doc.LoadFile(); - if (!doc.LoadFile()) - { - error = true; - throw Error::MemoryXmlParse(doc.ErrorDesc(), doc.ErrorId(), doc.ErrorRow(), doc.ErrorCol()); - } - TiXmlHandle hDoc(&doc); - TiXmlElement* pElem; - TiXmlHandle hRoot(0); - memory_info mem; - - // block: name - { - pElem=hDoc.FirstChildElement().Element(); - // should always have a valid root but handle gracefully if it does - if (!pElem) - { - error = true; - throw Error::MemoryXmlNoRoot(); - } - string m_name=pElem->Value(); - if(m_name != "DFExtractor") - { - error = true; - throw Error::MemoryXmlNoDFExtractor(m_name.c_str()); - } - // save this for later - hRoot=TiXmlHandle(pElem); - } - // transform elements - { - // trash existing list - for(uint32_t i = 0; i < meminfo.size(); i++) - { - delete meminfo[i]; - } - meminfo.clear(); - TiXmlElement* pMemInfo=hRoot.FirstChild( "MemoryDescriptors" ).FirstChild( "Entry" ).Element(); - map map_pNamedEntries; - vector v_pEntries; - for( ; pMemInfo; pMemInfo=pMemInfo->NextSiblingElement("Entry")) - { - v_pEntries.push_back(pMemInfo); - const char *id = pMemInfo->Attribute("id"); - if(id) - { - string str_id = id; - map_pNamedEntries[str_id] = pMemInfo; - } - } - for(uint32_t i = 0; i< v_pEntries.size();i++) - { - memory_info *mem = new memory_info(); - //FIXME: add a set of entries processed in a step of this cycle, use it to check for infinite loops - /* recursive */ParseEntry( v_pEntries[i] , mem , map_pNamedEntries); - meminfo.push_back(mem); - } - // process found things here - } - error = false; - return true; -} diff --git a/library/DFProcess-linux-SHM.cpp b/library/DFProcess-linux-SHM.cpp index acf519ecf..ace2dacf8 100644 --- a/library/DFProcess-linux-SHM.cpp +++ b/library/DFProcess-linux-SHM.cpp @@ -23,7 +23,7 @@ distribution. */ #include "Internal.h" #include "dfhack/DFProcess.h" -#include "dfhack/DFMemInfo.h" +#include "dfhack/VersionInfo.h" #include "dfhack/DFError.h" #include @@ -63,7 +63,7 @@ class SHMProcess::Private self = self_; }; ~Private(){}; - memory_info * memdescriptor; + VersionInfo * memdescriptor; Process * self; pid_t process_ID; char *shm_addr; @@ -79,7 +79,7 @@ class SHMProcess::Private bool identified; bool useYield; - bool validate(std::vector< memory_info* >& known_versions); + bool validate(std::vector< VersionInfo* >& known_versions); bool Aux_Core_Attach(bool & versionOK, pid_t & PID); //bool waitWhile (uint32_t state); @@ -159,7 +159,7 @@ uint32_t OS_getAffinity() bool SHMProcess::Private::AreLocksOk() { // both locks are inited (we hold our lock) - if(client_lock != -1 && server_lock != -1) + if(client_lock != -1 && server_lock != -1) { if(lockf(server_lock,F_TEST,0) == -1) // and server holds its lock { @@ -204,7 +204,7 @@ bool SHMProcess::Private::GetLocks() // cerr << "can't open sv lock" << endl; return false; } - + if(lockf( server_lock, F_TEST, 0 ) != -1) { cerr << "sv lock not locked" << endl; @@ -212,7 +212,7 @@ bool SHMProcess::Private::GetLocks() server_lock = -1; return false; } - + for(int i = 0; i < SHM_MAX_CLIENTS; i++) { // open the client suspend locked @@ -258,7 +258,7 @@ bool SHMProcess::Private::GetLocks() return false; } -SHMProcess::SHMProcess(uint32_t PID, vector< memory_info* >& known_versions) +SHMProcess::SHMProcess(uint32_t PID, vector< VersionInfo* >& known_versions) : d(new Private(this)) { d->process_ID = PID; @@ -282,7 +282,7 @@ SHMProcess::SHMProcess(uint32_t PID, vector< memory_info* >& known_versions) detach(); throw Error::SHMVersionMismatch(); } - + // try to identify the DF version (md5 the binary, compare with known versions) d->validate(known_versions); // detach @@ -303,7 +303,7 @@ bool SHMProcess::isIdentified() return d->identified; } -bool SHMProcess::Private::validate(vector & known_versions) +bool SHMProcess::Private::validate(vector & known_versions) { char exe_link_name [256]; char target_name[1024]; @@ -319,19 +319,19 @@ bool SHMProcess::Private::validate(vector & known_versions) // make sure we have a null terminated string... // see http://www.opengroup.org/onlinepubs/000095399/functions/readlink.html target_name[target_result] = 0; - + md5wrapper md5; // get hash of the running DF process string hash = md5.getHashFromFile(target_name); - vector::iterator it; + vector::iterator it; // cerr << exe_file << " " << hash << endl; // iterate over the list of memory locations for ( it=known_versions.begin() ; it < known_versions.end(); it++ ) { try{ - if(hash == (*it)->getString("md5")) // are the md5 hashes the same? + if(hash == (*it)->getMD5()) // are the md5 hashes the same? { - memory_info *m = new memory_info(**it); + VersionInfo *m = new VersionInfo(**it); memdescriptor = m; m->setParentProcess(dynamic_cast( self )); identified = true; @@ -358,7 +358,7 @@ SHMProcess::~SHMProcess() delete d; } -memory_info * SHMProcess::getDescriptor() +VersionInfo * SHMProcess::getDescriptor() { return d->memdescriptor; } @@ -385,11 +385,11 @@ void SHMProcess::getMemRanges( vector & ranges ) { char buffer[1024]; char permissions[5]; // r/-, w/-, x/-, p/s, 0 - + sprintf(buffer, "/proc/%lu/maps", d->process_ID); FILE *mapFile = ::fopen(buffer, "r"); uint64_t offset, device1, device2, node; - + while (fgets(buffer, 1024, mapFile)) { t_memrange temp; @@ -417,7 +417,7 @@ bool SHMProcess::suspend() { return true; } - + // FIXME: this should be controlled on the server side // FIXME: IF server got CORE_RUN in this frame, interpret CORE_SUSPEND as CORE_STEP // did we just resume a moment ago? @@ -546,7 +546,7 @@ bool SHMProcess::attach() cerr << "can't find segment" << endl; // FIXME: throw return false; } - + /* * Attach the segment */ @@ -592,7 +592,7 @@ bool SHMProcess::detach() void SHMProcess::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer) { if(!d->locked) throw Error::MemoryAccessDenied(); - + // normal read under 1MB if(size <= SHM_BODY) { @@ -629,7 +629,7 @@ void SHMProcess::read (uint32_t src_address, uint32_t size, uint8_t *target_buff uint8_t SHMProcess::readByte (const uint32_t offset) { if(!d->locked) throw Error::MemoryAccessDenied(); - + D_SHMHDR->address = offset; gcc_barrier d->SetAndWait(CORE_READ_BYTE); @@ -639,7 +639,7 @@ uint8_t SHMProcess::readByte (const uint32_t offset) void SHMProcess::readByte (const uint32_t offset, uint8_t &val ) { if(!d->locked) throw Error::MemoryAccessDenied(); - + D_SHMHDR->address = offset; gcc_barrier d->SetAndWait(CORE_READ_BYTE); @@ -649,7 +649,7 @@ void SHMProcess::readByte (const uint32_t offset, uint8_t &val ) uint16_t SHMProcess::readWord (const uint32_t offset) { if(!d->locked) throw Error::MemoryAccessDenied(); - + D_SHMHDR->address = offset; gcc_barrier d->SetAndWait(CORE_READ_WORD); @@ -659,7 +659,7 @@ uint16_t SHMProcess::readWord (const uint32_t offset) void SHMProcess::readWord (const uint32_t offset, uint16_t &val) { if(!d->locked) throw Error::MemoryAccessDenied(); - + D_SHMHDR->address = offset; gcc_barrier d->SetAndWait(CORE_READ_WORD); @@ -669,7 +669,7 @@ void SHMProcess::readWord (const uint32_t offset, uint16_t &val) uint32_t SHMProcess::readDWord (const uint32_t offset) { if(!d->locked) throw Error::MemoryAccessDenied(); - + D_SHMHDR->address = offset; gcc_barrier d->SetAndWait(CORE_READ_DWORD); @@ -678,7 +678,7 @@ uint32_t SHMProcess::readDWord (const uint32_t offset) void SHMProcess::readDWord (const uint32_t offset, uint32_t &val) { if(!d->locked) throw Error::MemoryAccessDenied(); - + D_SHMHDR->address = offset; gcc_barrier d->SetAndWait(CORE_READ_DWORD); @@ -688,7 +688,7 @@ void SHMProcess::readDWord (const uint32_t offset, uint32_t &val) uint64_t SHMProcess::readQuad (const uint32_t offset) { if(!d->locked) throw Error::MemoryAccessDenied(); - + D_SHMHDR->address = offset; gcc_barrier d->SetAndWait(CORE_READ_QUAD); @@ -697,7 +697,7 @@ uint64_t SHMProcess::readQuad (const uint32_t offset) void SHMProcess::readQuad (const uint32_t offset, uint64_t &val) { if(!d->locked) throw Error::MemoryAccessDenied(); - + D_SHMHDR->address = offset; gcc_barrier d->SetAndWait(CORE_READ_QUAD); @@ -707,7 +707,7 @@ void SHMProcess::readQuad (const uint32_t offset, uint64_t &val) float SHMProcess::readFloat (const uint32_t offset) { if(!d->locked) throw Error::MemoryAccessDenied(); - + D_SHMHDR->address = offset; gcc_barrier d->SetAndWait(CORE_READ_DWORD); @@ -716,7 +716,7 @@ float SHMProcess::readFloat (const uint32_t offset) void SHMProcess::readFloat (const uint32_t offset, float &val) { if(!d->locked) throw Error::MemoryAccessDenied(); - + D_SHMHDR->address = offset; gcc_barrier d->SetAndWait(CORE_READ_DWORD); @@ -730,7 +730,7 @@ void SHMProcess::readFloat (const uint32_t offset, float &val) void SHMProcess::writeQuad (const uint32_t offset, const uint64_t data) { if(!d->locked) throw Error::MemoryAccessDenied(); - + D_SHMHDR->address = offset; D_SHMHDR->Qvalue = data; gcc_barrier @@ -740,7 +740,7 @@ void SHMProcess::writeQuad (const uint32_t offset, const uint64_t data) void SHMProcess::writeDWord (uint32_t offset, uint32_t data) { if(!d->locked) throw Error::MemoryAccessDenied(); - + D_SHMHDR->address = offset; D_SHMHDR->value = data; gcc_barrier @@ -751,7 +751,7 @@ void SHMProcess::writeDWord (uint32_t offset, uint32_t data) void SHMProcess::writeWord (uint32_t offset, uint16_t data) { if(!d->locked) throw Error::MemoryAccessDenied(); - + D_SHMHDR->address = offset; D_SHMHDR->value = data; gcc_barrier @@ -761,7 +761,7 @@ void SHMProcess::writeWord (uint32_t offset, uint16_t data) void SHMProcess::writeByte (uint32_t offset, uint8_t data) { if(!d->locked) throw Error::MemoryAccessDenied(); - + D_SHMHDR->address = offset; D_SHMHDR->value = data; gcc_barrier @@ -771,7 +771,7 @@ void SHMProcess::writeByte (uint32_t offset, uint8_t data) void SHMProcess::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer) { if(!d->locked) throw Error::MemoryAccessDenied(); - + // normal write under 1MB if(size <= SHM_BODY) { @@ -809,7 +809,7 @@ void SHMProcess::write (uint32_t dst_address, uint32_t size, uint8_t *source_buf const std::string SHMProcess::readCString (uint32_t offset) { if(!d->locked) throw Error::MemoryAccessDenied(); - + std::string temp; char temp_c[256]; int counter = 0; @@ -828,7 +828,7 @@ const std::string SHMProcess::readCString (uint32_t offset) const std::string SHMProcess::readSTLString(uint32_t offset) { if(!d->locked) throw Error::MemoryAccessDenied(); - + D_SHMHDR->address = offset; full_barrier d->SetAndWait(CORE_READ_STL_STRING); @@ -838,7 +838,7 @@ const std::string SHMProcess::readSTLString(uint32_t offset) size_t SHMProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) { if(!d->locked) throw Error::MemoryAccessDenied(); - + D_SHMHDR->address = offset; full_barrier d->SetAndWait(CORE_READ_STL_STRING); @@ -852,7 +852,7 @@ size_t SHMProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapa void SHMProcess::writeSTLString(const uint32_t address, const std::string writeString) { if(!d->locked) throw Error::MemoryAccessDenied(); - + D_SHMHDR->address = address; strncpy(D_SHMDATA(char),writeString.c_str(),writeString.length()+1); // length + 1 for the null terminator full_barrier @@ -862,7 +862,7 @@ void SHMProcess::writeSTLString(const uint32_t address, const std::string writeS string SHMProcess::readClassName (uint32_t vptr) { if(!d->locked) throw Error::MemoryAccessDenied(); - + int typeinfo = readDWord(vptr - 0x4); int typestring = readDWord(typeinfo + 0x4); string raw = readCString(typestring); @@ -875,13 +875,13 @@ string SHMProcess::readClassName (uint32_t vptr) bool SHMProcess::getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) { if(!d->locked) throw Error::MemoryAccessDenied(); - + modulelookup * payload = D_SHMDATA(modulelookup); payload->version = version; - + strncpy(payload->name,name,255); payload->name[255] = 0; - + if(!SetAndWait(CORE_ACQUIRE_MODULE)) { return false; // FIXME: throw a fatal exception instead @@ -898,14 +898,14 @@ bool SHMProcess::getModuleIndex (const char * name, const uint32_t version, uint char * SHMProcess::getSHMStart (void) { if(!d->locked) return 0; //THROW HERE! - + return /*d->shm_addr_with_cl_idx*/ d->shm_addr; } bool SHMProcess::Private::Aux_Core_Attach(bool & versionOK, pid_t & PID) { if(!locked) throw Error::MemoryAccessDenied(); - + SHMDATA(coreattach)->cl_affinity = OS_getAffinity(); if(!SetAndWait(CORE_ATTACH)) return false; /* diff --git a/library/DFProcess-linux-wine.cpp b/library/DFProcess-linux-wine.cpp index b71e2266f..891a4f820 100644 --- a/library/DFProcess-linux-wine.cpp +++ b/library/DFProcess-linux-wine.cpp @@ -23,7 +23,7 @@ distribution. */ #include "Internal.h" #include "dfhack/DFProcess.h" -#include "dfhack/DFMemInfo.h" +#include "dfhack/VersionInfo.h" #include "dfhack/DFError.h" #include #include @@ -44,7 +44,7 @@ class WineProcess::Private self = self_; }; ~Private(){}; - memory_info * my_descriptor; + VersionInfo * my_descriptor; Process * self; pid_t my_handle; uint32_t my_pid; @@ -53,10 +53,13 @@ class WineProcess::Private bool attached; bool suspended; bool identified; - bool validate(char * exe_file, uint32_t pid, char * mem_file, vector & known_versions); + uint32_t STLSTR_buf_off; + uint32_t STLSTR_size_off; + uint32_t STLSTR_cap_off; + bool validate(char * exe_file, uint32_t pid, char * mem_file, vector & known_versions); }; -WineProcess::WineProcess(uint32_t pid, vector & known_versions) +WineProcess::WineProcess(uint32_t pid, vector & known_versions) : d(new Private(this)) { char dir_name [256]; @@ -66,16 +69,16 @@ WineProcess::WineProcess(uint32_t pid, vector & known_versions) char cmdline_name [256]; char target_name[1024]; int target_result; - + d->identified = false; d->my_descriptor = 0; - + sprintf(dir_name,"/proc/%d/", pid); sprintf(exe_link_name,"/proc/%d/exe", pid); sprintf(mem_name,"/proc/%d/mem", pid); sprintf(cwd_name,"/proc/%d/cwd", pid); sprintf(cmdline_name,"/proc/%d/cmdline", pid); - + // resolve /proc/PID/exe link target_result = readlink(exe_link_name, target_name, sizeof(target_name)-1); if (target_result == -1) @@ -84,7 +87,7 @@ WineProcess::WineProcess(uint32_t pid, vector & known_versions) } // make sure we have a null terminated string... target_name[target_result] = 0; - + // FIXME: this fails when the wine process isn't started from the 'current working directory'. strip path data from cmdline // is this windows version of Df running in wine? if(strstr(target_name, "wine-preloader")!= NULL) @@ -92,7 +95,7 @@ WineProcess::WineProcess(uint32_t pid, vector & known_versions) // get working directory target_result = readlink(cwd_name, target_name, sizeof(target_name)-1); target_name[target_result] = 0; - + // got path to executable, do the same for its name ifstream ifs ( cmdline_name , ifstream::in ); string cmdline; @@ -102,7 +105,7 @@ WineProcess::WineProcess(uint32_t pid, vector & known_versions) char exe_link[1024]; // put executable name and path together sprintf(exe_link,"%s/%s",target_name,cmdline.c_str()); - + // create wine process, add it to the vector d->identified = d->validate(exe_link,pid,mem_name,known_versions); return; @@ -124,37 +127,41 @@ bool WineProcess::isIdentified() return d->identified; } -bool WineProcess::Private::validate(char* exe_file, uint32_t pid, char* mem_file, std::vector< memory_info* >& known_versions) +bool WineProcess::Private::validate(char* exe_file, uint32_t pid, char* mem_file, std::vector< VersionInfo* >& known_versions) { md5wrapper md5; // get hash of the running DF process string hash = md5.getHashFromFile(exe_file); - vector::iterator it; - + vector::iterator it; + // iterate over the list of memory locations for ( it=known_versions.begin() ; it < known_versions.end(); it++ ) { string thishash; try { - thishash = (*it)->getString("md5"); + thishash = (*it)->getMD5(); } catch (Error::MissingMemoryDefinition& e) { continue; } // are the md5 hashes the same? - if(memory_info::OS_WINDOWS == (*it)->getOS() && hash == thishash) + if(VersionInfo::OS_WINDOWS == (*it)->getOS() && hash == thishash) { - + // keep track of created memory_info object so we can destroy it later - memory_info *m = new memory_info(**it); + VersionInfo *m = new VersionInfo(**it); my_descriptor = m; m->setParentProcess(dynamic_cast( self )); my_handle = my_pid = pid; // tell WineProcess about the /proc/PID/mem file memFile = mem_file; identified = true; + OffsetGroup * strGrp = m->getGroup("string")->getGroup("MSVC"); + STLSTR_buf_off = strGrp->getOffset("buffer"); + STLSTR_size_off = strGrp->getOffset("size"); + STLSTR_cap_off = strGrp->getOffset("capacity"); return true; } } @@ -173,7 +180,7 @@ WineProcess::~WineProcess() delete d; } -memory_info * WineProcess::getDescriptor() +VersionInfo * WineProcess::getDescriptor() { return d->my_descriptor; } @@ -194,11 +201,11 @@ void WineProcess::getMemRanges( vector & ranges ) { char buffer[1024]; char permissions[5]; // r/-, w/-, x/-, p/s, 0 - + sprintf(buffer, "/proc/%lu/maps", d->my_pid); FILE *mapFile = ::fopen(buffer, "r"); uint64_t offset, device1, device2, node; - + while (fgets(buffer, 1024, mapFile)) { t_memrange temp; @@ -310,7 +317,7 @@ bool WineProcess::attach() } } d->suspended = true; - + int proc_pid_mem = open(d->memFile.c_str(),O_RDONLY); if(proc_pid_mem == -1) { @@ -323,7 +330,7 @@ bool WineProcess::attach() else { d->attached = true; - + d->memFileHandle = proc_pid_mem; return true; // we are attached } @@ -365,7 +372,7 @@ bool WineProcess::detach() void WineProcess::read (const uint32_t offset, const uint32_t size, uint8_t *target) { if(size == 0) return; - + ssize_t result; ssize_t total = 0; ssize_t remaining = size; @@ -563,23 +570,12 @@ const std::string WineProcess::readCString (uint32_t offset) size_t WineProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) { - /* - MSVC++ string - ptr allocator - union - { - char[16] start; - char * start_ptr - } - Uint32 length - Uint32 capacity - */ - uint32_t start_offset = offset + 4; - size_t length = readDWord(offset + 20); - - size_t capacity = readDWord(offset + 24); + uint32_t start_offset = offset + d->STLSTR_buf_off; + size_t length = readDWord(offset + d->STLSTR_size_off); + size_t capacity = readDWord(offset + d->STLSTR_cap_off); + size_t read_real = min(length, bufcapacity-1);// keep space for null termination - + // read data from inside the string structure if(capacity < 16) { @@ -590,29 +586,19 @@ size_t WineProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcap start_offset = readDWord(start_offset);// dereference the start offset read(start_offset, read_real, (uint8_t *)buffer); } - + buffer[read_real] = 0; return read_real; } const string WineProcess::readSTLString (uint32_t offset) { - /* - MSVC++ string - ptr allocator - union - { - char[16] start; - char * start_ptr - } - Uint32 length - Uint32 capacity - */ - uint32_t start_offset = offset + 4; - uint32_t length = readDWord(offset + 20); - uint32_t capacity = readDWord(offset + 24); + uint32_t start_offset = offset + d->STLSTR_buf_off; + size_t length = readDWord(offset + d->STLSTR_size_off); + size_t capacity = readDWord(offset + d->STLSTR_cap_off); + char * temp = new char[capacity+1]; - + // read data from inside the string structure if(capacity < 16) { @@ -623,7 +609,7 @@ const string WineProcess::readSTLString (uint32_t offset) start_offset = readDWord(start_offset);// dereference the start offset read(start_offset, capacity, (uint8_t *)temp); } - + temp[length] = 0; string ret = temp; delete temp; diff --git a/library/DFProcess-linux.cpp b/library/DFProcess-linux.cpp index 25dfa0d8c..164834543 100644 --- a/library/DFProcess-linux.cpp +++ b/library/DFProcess-linux.cpp @@ -23,7 +23,7 @@ distribution. */ #include "Internal.h" #include "dfhack/DFProcess.h" -#include "dfhack/DFMemInfo.h" +#include "dfhack/VersionInfo.h" #include "dfhack/DFError.h" #include #include @@ -44,7 +44,7 @@ class NormalProcess::Private }; ~Private(){}; Window* my_window; - memory_info * my_descriptor; + VersionInfo * my_descriptor; pid_t my_handle; uint32_t my_pid; string memFile; @@ -53,10 +53,10 @@ class NormalProcess::Private bool suspended; bool identified; Process * self; - bool validate(char * exe_file, uint32_t pid, char * mem_file, vector & known_versions); + bool validate(char * exe_file, uint32_t pid, char * mem_file, vector & known_versions); }; -NormalProcess::NormalProcess(uint32_t pid, vector< memory_info* >& known_versions) +NormalProcess::NormalProcess(uint32_t pid, vector< VersionInfo* >& known_versions) : d(new Private(this)) { char dir_name [256]; @@ -66,16 +66,16 @@ NormalProcess::NormalProcess(uint32_t pid, vector< memory_info* >& known_version char cmdline_name [256]; char target_name[1024]; int target_result; - + d->identified = false; d->my_descriptor = 0; - + sprintf(dir_name,"/proc/%d/", pid); sprintf(exe_link_name,"/proc/%d/exe", pid); sprintf(mem_name,"/proc/%d/mem", pid); sprintf(cwd_name,"/proc/%d/cwd", pid); sprintf(cmdline_name,"/proc/%d/cmdline", pid); - + // resolve /proc/PID/exe link target_result = readlink(exe_link_name, target_name, sizeof(target_name)-1); if (target_result == -1) @@ -84,7 +84,7 @@ NormalProcess::NormalProcess(uint32_t pid, vector< memory_info* >& known_version } // make sure we have a null terminated string... target_name[target_result] = 0; - + // is this the regular linux DF? if (strstr(target_name, "dwarfort.exe") != 0 || strstr(target_name,"Dwarf_Fortress") != 0) { @@ -108,24 +108,25 @@ bool NormalProcess::isIdentified() return d->identified; } -bool NormalProcess::Private::validate(char * exe_file,uint32_t pid, char * memFile, vector & known_versions) +bool NormalProcess::Private::validate(char * exe_file,uint32_t pid, char * memFile, vector & known_versions) { md5wrapper md5; // get hash of the running DF process string hash = md5.getHashFromFile(exe_file); - vector::iterator it; - + vector::iterator it; + // iterate over the list of memory locations for ( it=known_versions.begin() ; it < known_versions.end(); it++ ) { try { - if(hash == (*it)->getString("md5")) // are the md5 hashes the same? + //cout << hash << " ?= " << (*it)->getMD5() << endl; + if(hash == (*it)->getMD5()) // are the md5 hashes the same? { - memory_info * m = *it; - if (memory_info::OS_LINUX == m->getOS()) + VersionInfo * m = *it; + if (VersionInfo::OS_LINUX == m->getOS()) { - memory_info *m2 = new memory_info(*m); + VersionInfo *m2 = new VersionInfo(*m); my_descriptor = m2; m2->setParentProcess(dynamic_cast( self )); my_handle = my_pid = pid; @@ -161,7 +162,7 @@ NormalProcess::~NormalProcess() delete d; } -memory_info * NormalProcess::getDescriptor() +VersionInfo * NormalProcess::getDescriptor() { return d->my_descriptor; } @@ -182,11 +183,11 @@ void NormalProcess::getMemRanges( vector & ranges ) { char buffer[1024]; char permissions[5]; // r/-, w/-, x/-, p/s, 0 - + sprintf(buffer, "/proc/%lu/maps", d->my_pid); FILE *mapFile = ::fopen(buffer, "r"); uint64_t offset, device1, device2, node; - + while (fgets(buffer, 1024, mapFile)) { t_memrange temp; @@ -298,7 +299,7 @@ bool NormalProcess::attach() } } d->suspended = true; - + int proc_pid_mem = open(d->memFile.c_str(),O_RDONLY); if(proc_pid_mem == -1) { @@ -310,7 +311,7 @@ bool NormalProcess::attach() else { d->attached = true; - + d->memFileHandle = proc_pid_mem; return true; // we are attached } @@ -352,7 +353,7 @@ bool NormalProcess::detach() void NormalProcess::read (const uint32_t offset, const uint32_t size, uint8_t *target) { if(size == 0) return; - + ssize_t result; result = pread(d->memFileHandle, target,size,offset); if(result != size) @@ -564,10 +565,10 @@ size_t NormalProcess::readSTLString (uint32_t offset, char * buffer, size_t bufc const string NormalProcess::readSTLString (uint32_t offset) { _Rep_base header; - + offset = readDWord(offset); read(offset - sizeof(_Rep_base),sizeof(_Rep_base),(uint8_t *)&header); - + // FIXME: use char* everywhere, avoid string char * temp = new char[header._M_length+1]; read(offset,header._M_length+1,(uint8_t * )temp); diff --git a/library/DFProcess-windows-SHM.cpp b/library/DFProcess-windows-SHM.cpp index 5bb100e34..9742ceeca 100644 --- a/library/DFProcess-windows-SHM.cpp +++ b/library/DFProcess-windows-SHM.cpp @@ -23,7 +23,7 @@ distribution. */ #include "Internal.h" #include "dfhack/DFProcess.h" -#include "dfhack/DFMemInfo.h" +#include "dfhack/VersionInfo.h" #include "dfhack/DFError.h" #include "shms.h" #include "mod-core.h" @@ -48,7 +48,7 @@ class SHMProcess::Private attachmentIdx = -1; }; ~Private(){}; - memory_info * memdescriptor; + VersionInfo * memdescriptor; SHMProcess * self; uint32_t process_ID; char *shm_addr; @@ -56,14 +56,14 @@ class SHMProcess::Private HANDLE DFCLMutex; HANDLE DFCLSuspendMutex; int attachmentIdx; - + bool attached; bool locked; bool identified; bool useYield; - - bool validate(std::vector< memory_info* >& known_versions); - + + bool validate(std::vector< VersionInfo* >& known_versions); + bool Aux_Core_Attach(bool & versionOK, uint32_t & PID); bool SetAndWait (uint32_t state); bool GetLocks(); @@ -91,7 +91,7 @@ bool SHMProcess::Private::SetAndWait (uint32_t state) uint32_t cnt = 0; if(!attached) return false; SHMCMD = state; - + while (SHMCMD == state) { // yield the CPU, only on single-core CPUs @@ -176,7 +176,7 @@ bool SHMProcess::Private::GetLocks() DFSVMutex = 0; return false; } - + for(int i = 0; i < SHM_MAX_CLIENTS; i++) { // open the client suspend locked @@ -190,7 +190,7 @@ bool SHMProcess::Private::GetLocks() } // open the client lock, try to lock it - + sprintf(name,"DFCLMutex-%d-%d",process_ID,i); DFCLMutex = OpenMutex(SYNCHRONIZE,0,name); if(DFCLMutex == 0) @@ -226,7 +226,7 @@ bool SHMProcess::Private::GetLocks() bool SHMProcess::Private::AreLocksOk() { // both locks are inited (we hold our lock) - if(DFCLMutex != 0 && DFSVMutex != 0) + if(DFCLMutex != 0 && DFSVMutex != 0) { // try if CL mutex is free switch (WaitForSingleObject(DFSVMutex,0)) @@ -241,7 +241,7 @@ bool SHMProcess::Private::AreLocksOk() { // mutex is held by DF return true; - } + } default: case WAIT_FAILED: { @@ -257,10 +257,10 @@ bool SHMProcess::Private::AreLocksOk() /* char svmutexname [256]; - + char clmutexname [256]; sprintf(clmutexname,"DFCLMutex-%d",PID); - + // get server and client mutex d->DFSVMutex = OpenMutex(SYNCHRONIZE,false, svmutexname); if(d->DFSVMutex == 0) @@ -274,7 +274,7 @@ bool SHMProcess::Private::AreLocksOk() } */ -SHMProcess::SHMProcess(uint32_t PID, vector & known_versions) +SHMProcess::SHMProcess(uint32_t PID, vector & known_versions) : d(new Private()) { d->process_ID = PID; @@ -314,7 +314,7 @@ bool SHMProcess::isIdentified() { return d->identified; } -bool SHMProcess::Private::validate(vector & known_versions) +bool SHMProcess::Private::validate(vector & known_versions) { // try to identify the DF version IMAGE_NT_HEADERS32 pe_header; @@ -324,11 +324,11 @@ bool SHMProcess::Private::validate(vector & known_versions) HANDLE hProcess; bool found = false; identified = false; - // open process, we only need the process open + // open process, we only need the process open hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, process_ID ); if (NULL == hProcess) return false; - + // try getting the first module of the process if(EnumProcessModules(hProcess, &hmod, 1 * sizeof(HMODULE), &junk) == 0) { @@ -338,20 +338,20 @@ bool SHMProcess::Private::validate(vector & known_versions) } // got base ;) uint32_t base = (uint32_t)hmod; - + // read from this process uint32_t pe_offset = self->readDWord(base+0x3C); self->read(base + pe_offset , sizeof(pe_header), (uint8_t *)&pe_header); self->read(base + pe_offset+ sizeof(pe_header), sizeof(sections) , (uint8_t *)§ions ); - + // iterate over the list of memory locations - vector::iterator it; + vector::iterator it; for ( it=known_versions.begin() ; it < known_versions.end(); it++ ) { uint32_t pe_timestamp; try { - pe_timestamp = (*it)->getHexValue("pe_timestamp"); + pe_timestamp = (*it)->getPE(); } catch(Error::MissingMemoryDefinition&) { @@ -359,7 +359,7 @@ bool SHMProcess::Private::validate(vector & known_versions) } if (pe_timestamp == pe_header.FileHeader.TimeDateStamp) { - memory_info *m = new memory_info(**it); + VersionInfo *m = new VersionInfo(**it); m->RebaseAll(base); memdescriptor = m; m->setParentProcess(self); @@ -385,7 +385,7 @@ SHMProcess::~SHMProcess() delete d; } -memory_info * SHMProcess::getDescriptor() +VersionInfo * SHMProcess::getDescriptor() { return d->memdescriptor; } @@ -397,30 +397,30 @@ int SHMProcess::getPID() bool SHMProcess::getThreadIDs(vector & threads ) { - HANDLE AllThreads = INVALID_HANDLE_VALUE; + HANDLE AllThreads = INVALID_HANDLE_VALUE; THREADENTRY32 te32; - - AllThreads = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 ); - if( AllThreads == INVALID_HANDLE_VALUE ) + + AllThreads = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 ); + if( AllThreads == INVALID_HANDLE_VALUE ) { - return false; + return false; } - te32.dwSize = sizeof(THREADENTRY32 ); - - if( !Thread32First( AllThreads, &te32 ) ) + te32.dwSize = sizeof(THREADENTRY32 ); + + if( !Thread32First( AllThreads, &te32 ) ) { CloseHandle( AllThreads ); return false; } - - do - { + + do + { if( te32.th32OwnerProcessID == d->process_ID ) { threads.push_back(te32.th32ThreadID); } - } while( Thread32Next(AllThreads, &te32 ) ); - + } while( Thread32Next(AllThreads, &te32 ) ); + CloseHandle( AllThreads ); return true; } @@ -430,9 +430,9 @@ void SHMProcess::getMemRanges( vector & ranges ) { // code here is taken from hexsearch by Silas Dunmore. // As this IMHO isn't a 'sunstantial portion' of anything, I'm not including the MIT license here - + // I'm faking this, because there's no way I'm using VirtualQuery - + t_memrange temp; uint32_t base = d->memdescriptor->getBase(); temp.start = base + 0x1000; // more fakery. @@ -591,7 +591,7 @@ bool SHMProcess::attach() return false; // we couldn't lock it } */ - + /* * Locate the segment. */ @@ -613,12 +613,12 @@ bool SHMProcess::attach() { CloseHandle(shmHandle); //ReleaseMutex(d->DFCLMutex); - d->FreeLocks(); + d->FreeLocks(); return false; // we couldn't attach the mapping // FIXME: throw } // we close the handle right here - it's not needed anymore CloseHandle(shmHandle); - + d->attached = true; if(!suspend()) { @@ -653,7 +653,7 @@ bool SHMProcess::detach() void SHMProcess::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer) { if(!d->locked) throw Error::MemoryAccessDenied(); - + // normal read under 1MB if(size <= SHM_BODY) { @@ -690,7 +690,7 @@ void SHMProcess::read (uint32_t src_address, uint32_t size, uint8_t *target_buff uint8_t SHMProcess::readByte (const uint32_t offset) { if(!d->locked) throw Error::MemoryAccessDenied(); - + D_SHMHDR->address = offset; full_barrier d->SetAndWait(CORE_READ_BYTE); @@ -700,7 +700,7 @@ uint8_t SHMProcess::readByte (const uint32_t offset) void SHMProcess::readByte (const uint32_t offset, uint8_t &val ) { if(!d->locked) throw Error::MemoryAccessDenied(); - + D_SHMHDR->address = offset; full_barrier d->SetAndWait(CORE_READ_BYTE); @@ -710,7 +710,7 @@ void SHMProcess::readByte (const uint32_t offset, uint8_t &val ) uint16_t SHMProcess::readWord (const uint32_t offset) { if(!d->locked) throw Error::MemoryAccessDenied(); - + D_SHMHDR->address = offset; full_barrier d->SetAndWait(CORE_READ_WORD); @@ -720,7 +720,7 @@ uint16_t SHMProcess::readWord (const uint32_t offset) void SHMProcess::readWord (const uint32_t offset, uint16_t &val) { if(!d->locked) throw Error::MemoryAccessDenied(); - + D_SHMHDR->address = offset; full_barrier d->SetAndWait(CORE_READ_WORD); @@ -730,7 +730,7 @@ void SHMProcess::readWord (const uint32_t offset, uint16_t &val) uint32_t SHMProcess::readDWord (const uint32_t offset) { if(!d->locked) throw Error::MemoryAccessDenied(); - + D_SHMHDR->address = offset; full_barrier d->SetAndWait(CORE_READ_DWORD); @@ -739,7 +739,7 @@ uint32_t SHMProcess::readDWord (const uint32_t offset) void SHMProcess::readDWord (const uint32_t offset, uint32_t &val) { if(!d->locked) throw Error::MemoryAccessDenied(); - + D_SHMHDR->address = offset; full_barrier d->SetAndWait(CORE_READ_DWORD); @@ -749,7 +749,7 @@ void SHMProcess::readDWord (const uint32_t offset, uint32_t &val) float SHMProcess::readFloat (const uint32_t offset) { if(!d->locked) throw Error::MemoryAccessDenied(); - + D_SHMHDR->address = offset; full_barrier d->SetAndWait(CORE_READ_DWORD); @@ -758,7 +758,7 @@ float SHMProcess::readFloat (const uint32_t offset) void SHMProcess::readFloat (const uint32_t offset, float &val) { if(!d->locked) throw Error::MemoryAccessDenied(); - + D_SHMHDR->address = offset; full_barrier d->SetAndWait(CORE_READ_DWORD); @@ -767,7 +767,7 @@ void SHMProcess::readFloat (const uint32_t offset, float &val) uint64_t SHMProcess::readQuad (const uint32_t offset) { if(!d->locked) throw Error::MemoryAccessDenied(); - + D_SHMHDR->address = offset; full_barrier d->SetAndWait(CORE_READ_QUAD); @@ -776,7 +776,7 @@ uint64_t SHMProcess::readQuad (const uint32_t offset) void SHMProcess::readQuad (const uint32_t offset, uint64_t &val) { if(!d->locked) throw Error::MemoryAccessDenied(); - + D_SHMHDR->address = offset; full_barrier d->SetAndWait(CORE_READ_QUAD); @@ -790,7 +790,7 @@ void SHMProcess::readQuad (const uint32_t offset, uint64_t &val) void SHMProcess::writeQuad (uint32_t offset, uint64_t data) { if(!d->locked) throw Error::MemoryAccessDenied(); - + D_SHMHDR->address = offset; D_SHMHDR->Qvalue = data; full_barrier @@ -801,7 +801,7 @@ void SHMProcess::writeQuad (uint32_t offset, uint64_t data) void SHMProcess::writeDWord (uint32_t offset, uint32_t data) { if(!d->locked) throw Error::MemoryAccessDenied(); - + D_SHMHDR->address = offset; D_SHMHDR->value = data; full_barrier @@ -812,7 +812,7 @@ void SHMProcess::writeDWord (uint32_t offset, uint32_t data) void SHMProcess::writeWord (uint32_t offset, uint16_t data) { if(!d->locked) throw Error::MemoryAccessDenied(); - + D_SHMHDR->address = offset; D_SHMHDR->value = data; full_barrier @@ -822,7 +822,7 @@ void SHMProcess::writeWord (uint32_t offset, uint16_t data) void SHMProcess::writeByte (uint32_t offset, uint8_t data) { if(!d->locked) throw Error::MemoryAccessDenied(); - + D_SHMHDR->address = offset; D_SHMHDR->value = data; full_barrier @@ -832,7 +832,7 @@ void SHMProcess::writeByte (uint32_t offset, uint8_t data) void SHMProcess::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer) { if(!d->locked) throw Error::MemoryAccessDenied(); - + // normal write under 1MB if(size <= SHM_BODY) { @@ -870,7 +870,7 @@ void SHMProcess::write (uint32_t dst_address, uint32_t size, uint8_t *source_buf const std::string SHMProcess::readCString (uint32_t offset) { if(!d->locked) throw Error::MemoryAccessDenied(); - + std::string temp; char temp_c[256]; int counter = 0; @@ -889,7 +889,7 @@ const std::string SHMProcess::readCString (uint32_t offset) const std::string SHMProcess::readSTLString(uint32_t offset) { if(!d->locked) throw Error::MemoryAccessDenied(); - + D_SHMHDR->address = offset; full_barrier d->SetAndWait(CORE_READ_STL_STRING); @@ -899,7 +899,7 @@ const std::string SHMProcess::readSTLString(uint32_t offset) size_t SHMProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) { if(!d->locked) throw Error::MemoryAccessDenied(); - + D_SHMHDR->address = offset; full_barrier d->SetAndWait(CORE_READ_STL_STRING); @@ -913,7 +913,7 @@ size_t SHMProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapa void SHMProcess::writeSTLString(const uint32_t address, const std::string writeString) { if(!d->locked) throw Error::MemoryAccessDenied(); - + D_SHMHDR->address = address; strncpy(D_SHMDATA(char),writeString.c_str(),writeString.length()+1); // length + 1 for the null terminator full_barrier @@ -933,13 +933,13 @@ string SHMProcess::readClassName (uint32_t vptr) bool SHMProcess::getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) { if(!d->locked) throw Error::MemoryAccessDenied(); - + modulelookup * payload = D_SHMDATA(modulelookup); payload->version = version; - + strncpy(payload->name,name,255); payload->name[255] = 0; - + if(!SetAndWait(CORE_ACQUIRE_MODULE)) { return false; // FIXME: throw a fatal exception instead @@ -962,7 +962,7 @@ char * SHMProcess::getSHMStart (void) bool SHMProcess::Private::Aux_Core_Attach(bool & versionOK, uint32_t & PID) { if(!locked) throw Error::MemoryAccessDenied(); - + SHMDATA(coreattach)->cl_affinity = OS_getAffinity(); if(!SetAndWait(CORE_ATTACH)) return false; /* diff --git a/library/DFProcess-windows.cpp b/library/DFProcess-windows.cpp index dad67b135..0b3d7959d 100644 --- a/library/DFProcess-windows.cpp +++ b/library/DFProcess-windows.cpp @@ -23,7 +23,7 @@ distribution. */ #include "Internal.h" #include "dfhack/DFProcess.h" -#include "dfhack/DFMemInfo.h" +#include "dfhack/VersionInfo.h" #include "dfhack/DFError.h" using namespace DFHack; @@ -40,7 +40,7 @@ class NormalProcess::Private suspended = false; }; ~Private(){}; - memory_info * my_descriptor; + VersionInfo * my_descriptor; HANDLE my_handle; HANDLE my_main_thread; uint32_t my_pid; @@ -48,16 +48,19 @@ class NormalProcess::Private bool attached; bool suspended; bool identified; + uint32_t STLSTR_buf_off; + uint32_t STLSTR_size_off; + uint32_t STLSTR_cap_off; }; -NormalProcess::NormalProcess(uint32_t pid, vector & known_versions) +NormalProcess::NormalProcess(uint32_t pid, vector & known_versions) : d(new Private()) { HMODULE hmod = NULL; DWORD junk; HANDLE hProcess; bool found = false; - + IMAGE_NT_HEADERS32 pe_header; IMAGE_SECTION_HEADER sections[16]; d->identified = false; @@ -65,7 +68,7 @@ NormalProcess::NormalProcess(uint32_t pid, vector & known_versio hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pid ); if (NULL == hProcess) return; - + // try getting the first module of the process if(EnumProcessModules(hProcess, &hmod, 1 * sizeof(HMODULE), &junk) == 0) { @@ -73,10 +76,10 @@ NormalProcess::NormalProcess(uint32_t pid, vector & known_versio // cout << "EnumProcessModules fail'd" << endl; return; //if enumprocessModules fails, give up } - + // got base ;) uint32_t base = (uint32_t)hmod; - + // temporarily assign this to allow some checks d->my_handle = hProcess; d->my_main_thread = 0; @@ -94,19 +97,19 @@ NormalProcess::NormalProcess(uint32_t pid, vector & known_versio d->my_handle = 0; return; } - + // see if there's a version entry that matches this process - vector::iterator it; + vector::iterator it; for ( it=known_versions.begin() ; it < known_versions.end(); it++ ) { // filter by OS - if(memory_info::OS_WINDOWS != (*it)->getOS()) + if(VersionInfo::OS_WINDOWS != (*it)->getOS()) continue; uint32_t pe_timestamp; // filter by timestamp, skip entries without a timestamp try { - pe_timestamp = (*it)->getHexValue("pe_timestamp"); + pe_timestamp = (*it)->getPE(); } catch(Error::MissingMemoryDefinition&) { @@ -114,13 +117,13 @@ NormalProcess::NormalProcess(uint32_t pid, vector & known_versio } if (pe_timestamp != pe_header.FileHeader.TimeDateStamp) continue; - + // all went well { printf("Match found! Using version %s.\n", (*it)->getVersion().c_str()); d->identified = true; // give the process a data model and memory layout fixed for the base of first module - memory_info *m = new memory_info(**it); + VersionInfo *m = new VersionInfo(**it); m->RebaseAll(base); // keep track of created memory_info object so we can destroy it later d->my_descriptor = m; @@ -129,12 +132,15 @@ NormalProcess::NormalProcess(uint32_t pid, vector & known_versio d->my_pid = pid; d->my_handle = hProcess; d->identified = true; - + // TODO: detect errors in thread enumeration vector threads; getThreadIDs( threads ); d->my_main_thread = OpenThread(THREAD_ALL_ACCESS, FALSE, (DWORD) threads[0]); - + OffsetGroup * strGrp = m->getGroup("string")->getGroup("MSVC"); + d->STLSTR_buf_off = strGrp->getOffset("buffer"); + d->STLSTR_size_off = strGrp->getOffset("size"); + d->STLSTR_cap_off = strGrp->getOffset("capacity"); found = true; break; // break the iterator loop } @@ -167,7 +173,7 @@ NormalProcess::~NormalProcess() delete d; } -memory_info * NormalProcess::getDescriptor() +VersionInfo * NormalProcess::getDescriptor() { return d->my_descriptor; } @@ -257,30 +263,30 @@ bool NormalProcess::detach() bool NormalProcess::getThreadIDs(vector & threads ) { - HANDLE AllThreads = INVALID_HANDLE_VALUE; + HANDLE AllThreads = INVALID_HANDLE_VALUE; THREADENTRY32 te32; - - AllThreads = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 ); - if( AllThreads == INVALID_HANDLE_VALUE ) + + AllThreads = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 ); + if( AllThreads == INVALID_HANDLE_VALUE ) { - return false; + return false; } - te32.dwSize = sizeof(THREADENTRY32 ); - - if( !Thread32First( AllThreads, &te32 ) ) + te32.dwSize = sizeof(THREADENTRY32 ); + + if( !Thread32First( AllThreads, &te32 ) ) { CloseHandle( AllThreads ); return false; } - - do - { + + do + { if( te32.th32OwnerProcessID == d->my_pid ) { threads.push_back(te32.th32ThreadID); } - } while( Thread32Next(AllThreads, &te32 ) ); - + } while( Thread32Next(AllThreads, &te32 ) ); + CloseHandle( AllThreads ); return true; } @@ -290,9 +296,9 @@ void NormalProcess::getMemRanges( vector & ranges ) { // code here is taken from hexsearch by Silas Dunmore. // As this IMHO isn't a 'sunstantial portion' of anything, I'm not including the MIT license here - + // I'm faking this, because there's no way I'm using VirtualQuery - + t_memrange temp; uint32_t base = d->my_descriptor->getBase(); temp.start = base + 0x1000; // more fakery. @@ -430,23 +436,11 @@ const string NormalProcess::readCString (const uint32_t offset) size_t NormalProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) { - /* - MSVC++ string - ptr allocator - union - { - char[16] start; - char * start_ptr -} -Uint32 length -Uint32 capacity -*/ - uint32_t start_offset = offset + 4; - size_t length = readDWord(offset + 20); - - size_t capacity = readDWord(offset + 24); + uint32_t start_offset = offset + d->STLSTR_buf_off; + size_t length = readDWord(offset + d->STLSTR_size_off); + size_t capacity = readDWord(offset + d->STLSTR_cap_off); size_t read_real = min(length, bufcapacity-1);// keep space for null termination - + // read data from inside the string structure if(capacity < 16) { @@ -457,29 +451,18 @@ Uint32 capacity start_offset = readDWord(start_offset);// dereference the start offset read(start_offset, read_real, (uint8_t *)buffer); } - + buffer[read_real] = 0; return read_real; } const string NormalProcess::readSTLString (uint32_t offset) { - /* - MSVC++ string - ptr allocator - union - { - char[16] start; - char * start_ptr - } - Uint32 length - Uint32 capacity - */ - uint32_t start_offset = offset + 4; - uint32_t length = readDWord(offset + 20); - uint32_t capacity = readDWord(offset + 24); + uint32_t start_offset = offset + d->STLSTR_buf_off; + size_t length = readDWord(offset + d->STLSTR_size_off); + size_t capacity = readDWord(offset + d->STLSTR_cap_off); char * temp = new char[capacity+1]; - + // read data from inside the string structure if(capacity < 16) { @@ -490,7 +473,7 @@ const string NormalProcess::readSTLString (uint32_t offset) start_offset = readDWord(start_offset);// dereference the start offset read(start_offset, capacity, (uint8_t *)temp); } - + temp[length] = 0; string ret = temp; delete temp; diff --git a/library/DFProcessEnumerator.cpp b/library/DFProcessEnumerator.cpp index c060d2182..b790cb0dd 100644 --- a/library/DFProcessEnumerator.cpp +++ b/library/DFProcessEnumerator.cpp @@ -23,11 +23,11 @@ distribution. */ #include "Internal.h" -#include "DFMemInfoManager.h" +#include "dfhack/VersionInfoFactory.h" #include "dfhack/DFProcessEnumerator.h" #include "dfhack/DFProcess.h" -#include "dfhack/DFMemInfo.h" +#include "dfhack/VersionInfo.h" using namespace DFHack; @@ -39,7 +39,7 @@ class DFHack::ProcessEnumerator::Private { public: Private(){}; - MemInfoManager *meminfo; + VersionInfoFactory *meminfo; PROC_V Processes; PID2PROC ProcMap; Process *GetProcessObject(ProcessID ID); @@ -119,20 +119,20 @@ Process * BadProcesses::operator[](uint32_t index) //FIXME: wasteful Process *ProcessEnumerator::Private::GetProcessObject(ProcessID ID) { - - Process *p1 = new SHMProcess(ID.pid,meminfo->meminfo); + + Process *p1 = new SHMProcess(ID.pid,meminfo->versions); if(p1->isIdentified()) return p1; else delete p1; - - Process *p2 = new NormalProcess(ID.pid,meminfo->meminfo); + + Process *p2 = new NormalProcess(ID.pid,meminfo->versions); if(p2->isIdentified()) return p2; else delete p2; #ifdef LINUX_BUILD - Process *p3 = new WineProcess(ID.pid,meminfo->meminfo); + Process *p3 = new WineProcess(ID.pid,meminfo->versions); if(p3->isIdentified()) return p3; else @@ -358,7 +358,7 @@ Process * ProcessEnumerator::operator[](uint32_t index) ProcessEnumerator::ProcessEnumerator( string path_to_xml ) : d(new Private()) { - d->meminfo = new MemInfoManager(path_to_xml); + d->meminfo = new VersionInfoFactory(path_to_xml); } void ProcessEnumerator::purge() diff --git a/library/DFTypes_C.cpp b/library/DFTypes_C.cpp index 9957ef0a1..9677ae9f1 100644 --- a/library/DFTypes_C.cpp +++ b/library/DFTypes_C.cpp @@ -57,6 +57,10 @@ 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; +int (*alloc_t_feature_buffer_callback)(t_feature*, uint32_t) = NULL; +int (*alloc_t_hotkey_buffer_callback)(t_hotkey*, uint32_t) = NULL; +int (*alloc_t_screen_buffer_callback)(t_screen*, uint32_t) = NULL; + int (*alloc_t_customWorkshop_buffer_callback)(t_customWorkshop*, uint32_t) = NULL; int (*alloc_t_material_buffer_callback)(t_material*, uint32_t) = NULL; diff --git a/library/VersionInfo.cpp b/library/VersionInfo.cpp new file mode 100644 index 000000000..c0a3477af --- /dev/null +++ b/library/VersionInfo.cpp @@ -0,0 +1,1051 @@ +/* +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/VersionInfo.h" +#include "dfhack/DFError.h" +#include "dfhack/DFProcess.h" + +//Inital amount of space in levels vector (since we usually know the number, efficient!) +#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; + }; + class indentr + { + public: + friend std::basic_ostream& operator <<(std::basic_ostream&, const indentr &); + indentr(int ns = 0, int size = 4) + { + numspaces = ns; + step = size; + } + void indent () + { + numspaces += step; + if (numspaces < 0) numspaces = 0; + } + void unindent () + { + numspaces -= step; + if (numspaces < 0) numspaces = 0; + } + int get () + { + return numspaces; + } + void set (int ns) + { + numspaces = ns; + if (numspaces < 0) numspaces = 0; + } + private: + int step; + int numspaces; + }; + std::basic_ostream& operator<< (std::basic_ostream& os, const indentr & idtr) + { + for(int i = 0; i < idtr.numspaces ;i++) + { + os << ' '; + } + return os; + } +}; + +/* + * Private data + */ +namespace DFHack +{ + typedef pair nullableUint32; + typedef map ::iterator uint32_Iter; + typedef pair nullableInt32; + typedef map ::iterator int32_Iter; + typedef pair nullableString; + typedef map ::iterator strings_Iter; + typedef map ::iterator groups_Iter; + class OffsetGroupPrivate + { + public: + map addresses; + map hexvals; + map offsets; + map strings; + map groups; + std::string name; + OffsetGroup * parent; + }; +} + +void OffsetGroup::createOffset(const string & key) +{ + OGd->offsets[key] = nullableInt32(false, 0); +} + +void OffsetGroup::createAddress(const string & key) +{ + OGd->addresses[key] = nullableUint32(false, 0); +} + +void OffsetGroup::createHexValue(const string & key) +{ + OGd->hexvals[key] = nullableUint32(false, 0); +} + +void OffsetGroup::createString(const string & key) +{ + OGd->strings[key] = nullableString(false, std::string()); +} + +void OffsetGroup::setOffset (const string & key, const string & value) +{ + int32_Iter it = OGd->offsets.find(key); + if(it != OGd->offsets.end()) + { + int32_t offset = strtol(value.c_str(), NULL, 16); + (*it).second.second = offset; + (*it).second.first = true; + } + else throw Error::MissingMemoryDefinition("offset", getFullName() + key); +} + + +void OffsetGroup::setAddress (const string & key, const string & value) +{ + uint32_Iter it = OGd->addresses.find(key); + if(it != OGd->addresses.end()) + { + int32_t address = strtol(value.c_str(), NULL, 16); + (*it).second.second = address; + (*it).second.first = true; + } + else throw Error::MissingMemoryDefinition("address", getFullName() + key); +} + + +void OffsetGroup::setHexValue (const string & key, const string & value) +{ + uint32_Iter it = OGd->hexvals.find(key); + if(it != OGd->hexvals.end()) + { + (*it).second.second = strtol(value.c_str(), NULL, 16); + (*it).second.first = true; + } + else throw Error::MissingMemoryDefinition("hexvalue", getFullName() + key); +} + + +void OffsetGroup::setString (const string & key, const string & value) +{ + strings_Iter it = OGd->strings.find(key); + if(it != OGd->strings.end()) + { + (*it).second.second = value; + (*it).second.first = true; + } + else throw Error::MissingMemoryDefinition("string", getFullName() + key); +} + + +// Get named address +uint32_t OffsetGroup::getAddress (const string & key) +{ + uint32_Iter iter = OGd->addresses.find(key); + + if(iter != OGd->addresses.end()) + { + if((*iter).second.first) + return (*iter).second.second; + throw Error::UnsetMemoryDefinition("address", getFullName() + key); + } + throw Error::MissingMemoryDefinition("address", getFullName() + key); +} + + +// Get named offset +int32_t OffsetGroup::getOffset (const string & key) +{ + int32_Iter iter = OGd->offsets.find(key); + if(iter != OGd->offsets.end()) + { + if((*iter).second.first) + return (*iter).second.second; + throw Error::UnsetMemoryDefinition("offset", getFullName() + key); + } + throw Error::MissingMemoryDefinition("offset", getFullName() + key); +} + + +// Get named numerical value +uint32_t OffsetGroup::getHexValue (const string & key) +{ + uint32_Iter iter = OGd->hexvals.find(key); + if(iter != OGd->hexvals.end()) + { + if((*iter).second.first) + return (*iter).second.second; + throw Error::UnsetMemoryDefinition("hexvalue", getFullName() + key); + } + throw Error::MissingMemoryDefinition("hexvalue", getFullName() + key); +} + +// Get named string +std::string OffsetGroup::getString (const string &key) +{ + strings_Iter iter = OGd->strings.find(key); + if(iter != OGd->strings.end()) + { + if((*iter).second.first) + return (*iter).second.second; + throw Error::UnsetMemoryDefinition("string", getFullName() + key); + } + throw Error::MissingMemoryDefinition("string", getFullName() + key); +} + +OffsetGroup * OffsetGroup::getGroup(const std::string &name) +{ + groups_Iter iter = OGd->groups.find(name); + if(iter != OGd->groups.end()) + return ((*iter).second); + return 0; +} + +OffsetGroup * OffsetGroup::createGroup(const std::string &name) +{ + OffsetGroup * ret = getGroup(name); + if(ret) + return ret; + ret = new OffsetGroup(name, this); + OGd->groups[name] = ret; + return ret; +} + +void OffsetGroup::RebaseAddresses(int32_t offset) +{ + for(uint32_Iter iter = OGd->addresses.begin(); iter != OGd->addresses.end(); iter++) + { + if(iter->second.first) + OGd->addresses[iter->first].second = iter->second.second + offset; + } + for(groups_Iter iter = OGd->groups.begin(); iter != OGd->groups.end(); iter++) + { + (*iter).second->RebaseAddresses(offset); + } +} + +OffsetGroup::OffsetGroup() +{ + OGd = new OffsetGroupPrivate(); + OGd->name = ""; + OGd->parent = 0; +} + +OffsetGroup::OffsetGroup(const std::string & name, OffsetGroup * parent) +{ + OGd = new OffsetGroupPrivate(); + OGd->name = name; + OGd->parent = parent; +} + +OffsetGroup::~OffsetGroup() +{ + for(groups_Iter it = OGd->groups.begin();it != OGd->groups.end();it++) + { + delete (*it).second; + } + OGd->groups.clear(); + delete OGd; +} + +std::string OffsetGroup::getName() +{ + return OGd->name; +} + +OffsetGroup * OffsetGroup::getParent() +{ + return OGd->parent; +} + +std::string OffsetGroup::getFullName() +{ + string temp, accum; + OffsetGroup * curr = this; + while(curr) + { + temp = curr->getName() + string("/") + accum; + accum = temp; + curr = curr->getParent(); + } + return accum; +} + +std::string OffsetGroup::PrintOffsets(int indentation) +{ + uint32_Iter iter; + ostringstream ss; + indentr i(indentation); + for(iter = OGd->addresses.begin(); iter != OGd->addresses.end(); iter++) + { + ss << i << "
"; + if(!(*iter).second.first) + ss << " MISSING!"; + ss << endl; + } + int32_Iter iter2; + for(iter2 = OGd->offsets.begin(); iter2 != OGd->offsets.end(); iter2++) + { + ss << i << ""; + if(!(*iter2).second.first) + ss << " MISSING!"; + ss << endl; + } + for(iter = OGd->hexvals.begin(); iter != OGd->hexvals.end(); iter++) + { + ss << i << ""; + if(!(*iter).second.first) + ss << " MISSING!"; + ss << endl; + } + strings_Iter iter3; + for(iter3 = OGd->strings.begin(); iter3 != OGd->strings.end(); iter3++) + { + ss << i << ""; + if(!(*iter3).second.first) + ss << " MISSING!"; + ss << endl; + } + groups_Iter iter4; + for(iter4 = OGd->groups.begin(); iter4 != OGd->groups.end(); iter4++) + { + ss << i << "" << endl; + i.indent(); + ss <<(*iter4).second->PrintOffsets(i.get()); + i.unindent(); + ss << i << "" << endl; + } + return ss.str(); +} + +/* + * Private data + */ +namespace DFHack +{ + class VersionInfoPrivate + { + public: + vector professions; + vector jobs; + vector skills; + vector levels; + vector< vector > traits; + vector moods; + map labors; + + // storage for class and multiclass + vector classes; + + // cache for faster name lookup, indexed by classID + vector classnames; + // map between vptr and class id, needs further type id lookup for multi-classes, not inherited + map classIDs; + + // index for the next added class + uint32_t classindex; + + int32_t base; + Process * p; // the process this belongs to + + string version; + VersionInfo::OSType OS; + std::string md5; + uint32_t PE_timestamp; + }; +} + + +// normal constructor +VersionInfo::VersionInfo() +:d(new VersionInfoPrivate) +{ + d->base = 0; + d->p = 0; + d->classindex = 0; + d->levels.reserve(NUM_RESERVE_LVLS); + d->moods.reserve(NUM_RESERVE_MOODS); + d->md5 = "invalid"; + d->PE_timestamp = 0; + OffsetGroup(); +} + + +// copy constructor +VersionInfo::VersionInfo(const VersionInfo &old) +:d(new VersionInfoPrivate) +{ + copy(&old); +} + +void OffsetGroup::copy(const OffsetGroup * old) +{ + OGd->addresses = old->OGd->addresses; + OGd->offsets = old->OGd->offsets; + OGd->hexvals = old->OGd->hexvals; + OGd->strings = old->OGd->strings; + for(groups_Iter it = old->OGd->groups.begin(); it != old->OGd->groups.end(); it++) + { + OffsetGroup * ogn = new OffsetGroup((*it).first, this); + ogn->copy((*it).second); + OGd->groups[(*it).first] = ogn; + } +} + +void VersionInfo::copy(const VersionInfo * old) +{ + d->version = old->d->version; + d->OS = old->d->OS; + d->md5 = old->d->md5; + d->PE_timestamp = old->d->PE_timestamp; + d->base = old->d->base; + //d->classes = old.d->classes; + for(uint32_t i = 0; i < old->d->classes.size(); i++) + { + t_class * copy = new t_class(*old->d->classes[i]); + d->classes.push_back(copy); + } + d->classnames = old->d->classnames; + d->classindex = old->d->classindex; + d->professions = old->d->professions; + d->jobs = old->d->jobs; + 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; + OffsetGroup::copy(reinterpret_cast(old)); +} + +void VersionInfo::setParentProcess(Process * _p) +{ + d->p = _p; +} + + +// destructor +VersionInfo::~VersionInfo() +{ + // delete the vtables + for(uint32_t i = 0; i < d->classes.size();i++) + { + delete d->classes[i]; + } + // delete our data + delete d; +} + + +void VersionInfo::setVersion(const char * v) +{ + d->version = v; +} + + +void VersionInfo::setVersion(const string &v) +{ + d->version = v; +} + + +string VersionInfo::getVersion() +{ + return d->version; +} + +void VersionInfo::setMD5(const string &v) +{ + d->md5 = v; +} + +string VersionInfo::getMD5() +{ + return d->md5; +} + +void VersionInfo::setPE(uint32_t v) +{ + d->PE_timestamp = v; +} + +uint32_t VersionInfo::getPE() +{ + return d->PE_timestamp; +} + +void VersionInfo::setOS(const char *os) +{ + string oss = os; + if(oss == "windows") + d->OS = OS_WINDOWS; + else if(oss == "linux") + d->OS = OS_LINUX; + else if(oss == "apple") + d->OS = OS_APPLE; + else + d->OS = OS_BAD; +} + + +void VersionInfo::setOS(const string &os) +{ + if(os == "windows") + d->OS = OS_WINDOWS; + else if(os == "linux") + d->OS = OS_LINUX; + else if(os == "apple") + d->OS = OS_APPLE; + else + d->OS = OS_BAD; +} + + +void VersionInfo::setOS(OSType os) +{ + if(os >= OS_WINDOWS && os < OS_BAD) + { + d->OS = os; + return; + } + d->OS = OS_BAD; +} + + +VersionInfo::OSType VersionInfo::getOS() const +{ + return d->OS; +} + +uint32_t VersionInfo::getBase () const +{ + return d->base; +} + + +void VersionInfo::setBase (const string &s) +{ + d->base = strtol(s.c_str(), NULL, 16); +} + + +void VersionInfo::setBase (const uint32_t b) +{ + d->base = b; +} + + +void VersionInfo::setLabor(const string & key, const string & value) +{ + uint32_t keyInt = strtol(key.c_str(), NULL, 10); + d->labors[keyInt] = value; +} + + +void VersionInfo::setProfession (const string & key, const string & value) +{ + uint32_t keyInt = strtol(key.c_str(), NULL, 10); + if(d->professions.size() <= keyInt) + { + d->professions.resize(keyInt+1,""); + } + d->professions[keyInt] = value; +} + + +void VersionInfo::setJob (const string & key, const string & value) +{ + uint32_t keyInt = strtol(key.c_str(), NULL, 10); + if(d->jobs.size() <= keyInt) + { + d->jobs.resize(keyInt+1); + } + d->jobs[keyInt] = value; +} + + +void VersionInfo::setSkill (const string & key, const string & value) +{ + uint32_t keyInt = strtol(key.c_str(), NULL, 10); + if(d->skills.size() <= keyInt){ + d->skills.resize(keyInt+1); + } + d->skills[keyInt] = value; +} + + +void VersionInfo::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 VersionInfo::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 VersionInfo::setTrait(const string & key, + const string & value, + const string & zero, + const string & one, + const string & two, + const string & three, + const string & four, + const string & five) +{ + uint32_t keyInt = strtol(key.c_str(), NULL, 10); + if(d->traits.size() <= keyInt) + { + d->traits.resize(keyInt+1); + } + d->traits[keyInt].push_back(zero); + d->traits[keyInt].push_back(one); + d->traits[keyInt].push_back(two); + d->traits[keyInt].push_back(three); + d->traits[keyInt].push_back(four); + d->traits[keyInt].push_back(five); + d->traits[keyInt].push_back(value); +} + + +// FIXME: next three methods should use some kind of custom container so it doesn't have to search so much. +t_class * VersionInfo::setClass (const char * name, uint32_t vtable, uint32_t typeoffset) +{ + if(name == 0) + return 0; + for (uint32_t i=0; iclasses.size(); i++) + { + if(d->classes[i]->classname == name) + { + if(vtable != 0) + d->classes[i]->vtable = vtable; + if(typeoffset != 0) + d->classes[i]->type_offset = typeoffset; + return d->classes[i]; + } + } + + t_class *cls = new t_class(); + // get an unique ID and add ourselves to the index + cls->assign = d->classindex; + cls->classname = name; + d->classnames.push_back(name); + + // vtables no longer a requirement + cls->vtable = vtable; + + // multi class yes/no + cls->type_offset = typeoffset; + + d->classes.push_back(cls); + d->classindex++; + return cls; + +} + + +void VersionInfo::setClassChild (t_class * parent, const char * name, const char * type) +{ + vector & vec = parent->subs; + for (uint32_t i=0; iclassname == name) + { + vec[i]->type = strtol(type, NULL, 16); + return; + } + } + // new multiclass child + t_type *mcc = new t_type(d->classindex,strtol(type, NULL, 16),name); + d->classnames.push_back(name); + vec.push_back(mcc); + d->classindex++; + + //cout << " classtype " << name << ", assign " << mcc->assign << ", vtable " << mcc->type << endl; +} + + +// FIXME: stupid. we need a better container +bool VersionInfo::resolveObjectToClassID(const uint32_t address, int32_t & classid) +{ + uint32_t vtable = d->p->readDWord(address); + // try to find the vtable in our cache + map::iterator it; + it = d->classIDs.find(vtable); + t_class * cl; + + // class found in cache? + if(it != d->classIDs.end()) + { + cl = (*it).second; + } + else// couldn't find? + { + // we set up the class for the first time + string classname = d->p->readClassName(vtable); + d->classIDs[vtable] = cl = setClass(classname.c_str(),vtable); + } + // and isn't a multi-class + if(!cl->type_offset) + { + // return + classid = cl->assign; + return true; + } + // and is a multiclass + else + { + // find the type + vector & vec = cl->subs; + uint32_t type = d->p->readWord(address + cl->type_offset); + // return typed building if successful + //FIXME: the vector should map directly to the type IDs here, so we don't have to mess with O(n) search + for (uint32_t k = 0; k < vec.size();k++) + { + if(vec[k]->type == type) + { + //cout << " multi " << address + classes[i].type_offset << " " << vec[k].classname << endl; + classid = vec[k]->assign; + return true; + } + } + // couldn't find the type... now what do we do here? throw? + // this is a case where it might be a good idea, because it uncovers some deeper problems + // we return the parent class instead, it doesn't change the API semantics and sort-of makes sense + classid = cl->assign; + return true; + } +} + + +//ALERT: doesn't care about multiclasses +bool VersionInfo::resolveClassnameToVPtr(const string classname, uint32_t & vptr) +{ + // FIXME: another stupid search. + for(uint32_t i = 0;i< d->classes.size();i++) + { + //if(classes[i].) + if(d->classes[i]->classname == classname) // got class + { + vptr = d->classes[i]->vtable; + return true; + } + } + // we failed to find anything that would match + return false; +} + + +bool VersionInfo::resolveClassnameToClassID (const string classname, int32_t & classID) +{ + // FIXME: another stupid search. + classID = -1; + for(uint32_t i = 0;i< d->classnames.size();i++) + { + if(d->classnames[i] == classname) + { + classID = i; + return true; + } + } + // we failed to find anything that would match + return false; +} + + +bool VersionInfo::resolveClassIDToClassname (const int32_t classID, string & classname) +{ + if (classID >=0 && (uint32_t)classID < d->classnames.size()) + { + classname = d->classnames[classID]; + return true; + } + return false; +} + + +// return pointer to our internal classID -> className mapping +const vector * VersionInfo::getClassIDMapping() +{ + return &d->classnames; +} + + +// change base of all addresses +void VersionInfo::RebaseAddresses(const int32_t new_base) +{ + OffsetGroup::RebaseAddresses(- (int32_t)d->base + new_base); +} + + +// change base of all addresses *and* vtable entries +void VersionInfo::RebaseAll(int32_t new_base) +{ + RebaseAddresses(new_base); + int32_t rebase = - (int32_t)d->base + new_base; + RebaseVTable(rebase); +} + + +// change all vtable entries by offset +void VersionInfo::RebaseVTable(int32_t offset) +{ + vector::iterator iter; + for(iter = d->classes.begin(); iter != d->classes.end(); iter++) + { + (*iter)->vtable += offset; + } +} + + +// Get Profession +string VersionInfo::getProfession (const uint32_t key) const +{ + if(d->professions.size() > key) + { + return d->professions[key]; + } + throw Error::MissingMemoryDefinition("profession", key); +} + + +// Get Job +string VersionInfo::getJob (const uint32_t key) const +{ + if(d->jobs.size() > key) + + { + return d->jobs[key]; + } + throw Error::MissingMemoryDefinition("job", key); +} + + +string VersionInfo::getSkill (const uint32_t key) const +{ + if(d->skills.size() > key) + { + return d->skills[key]; + } + throw Error::MissingMemoryDefinition("skill", key); +} + + +DFHack::t_level VersionInfo::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) +{ + if (number < 0) + return -number; + return number; +} + + +string VersionInfo::getTrait (const uint32_t traitIdx, const uint32_t traitValue) const +{ + if(d->traits.size() > traitIdx) + { + int diff = absolute(traitValue-50); + if(diff < 10) + { + return string(""); + } + if (traitValue >= 91) + return d->traits[traitIdx][5]; + else if (traitValue >= 76) + return d->traits[traitIdx][4]; + else if (traitValue >= 61) + return d->traits[traitIdx][3]; + else if (traitValue >= 25) + return d->traits[traitIdx][2]; + else if (traitValue >= 10) + return d->traits[traitIdx][1]; + else + return d->traits[traitIdx][0]; + } + throw Error::MissingMemoryDefinition("trait", traitIdx); +} + + +string VersionInfo::getTraitName(const uint32_t traitIdx) const +{ + if(d->traits.size() > traitIdx) + { + return d->traits[traitIdx][d->traits[traitIdx].size()-1]; + } + throw Error::MissingMemoryDefinition("traitname", traitIdx); +} + + +std::vector< std::vector > const& VersionInfo::getAllTraits() +{ + return d->traits; +} + +std:: map const& VersionInfo::getAllLabours() +{ + return d->labors; +} + +string VersionInfo::getLabor (const uint32_t laborIdx) +{ + if(d->labors.count(laborIdx)) + { + return d->labors[laborIdx]; + } + throw Error::MissingMemoryDefinition("labor", laborIdx); +} + + +std::string VersionInfo::getMood(const uint32_t moodID) +{ + if(d->moods.size() > moodID) + { + return d->moods[moodID]; + } + throw Error::MissingMemoryDefinition("Mood", moodID); +} + +std::string VersionInfo::PrintOffsets() +{ + ostringstream ss; + indentr i; + ss << i << "" << endl; + i.indent(); + switch (getOS()) + { + case OS_LINUX: + ss << i << "" << endl; + break; + case OS_WINDOWS: + ss << i << "" << endl; + ss << i << "" << endl; + break; + default: + ss << i << " UNKNOWN" << endl; + } + ss << i << "" << endl; + i.indent(); + ss << OffsetGroup::PrintOffsets(i.get()); + i.unindent(); + ss << i << "" << endl; + i.unindent(); + ss << i << "" << endl; + ss << endl; + return ss.str(); +} \ No newline at end of file diff --git a/library/VersionInfoFactory.cpp b/library/VersionInfoFactory.cpp new file mode 100644 index 000000000..83102648e --- /dev/null +++ b/library/VersionInfoFactory.cpp @@ -0,0 +1,630 @@ +/* +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/VersionInfoFactory.h" +#include "dfhack/VersionInfo.h" +#include "dfhack/DFError.h" +#include + +using namespace DFHack; + +VersionInfoFactory::~VersionInfoFactory() +{ + // for each stored version, delete + for(uint32_t i = 0; i < versions.size();i++) + { + delete versions[i]; + } + versions.clear(); +} + +void VersionInfoFactory::ParseVTable(TiXmlElement* vtable, VersionInfo* mem) +{ + TiXmlElement* pClassEntry; + TiXmlElement* pClassSubEntry; + /* + // check for rebase, do rebase if check positive + const char * rebase = vtable->Attribute("rebase"); + if(rebase) + { + int32_t rebase_offset = strtol(rebase, NULL, 16); + mem->RebaseVTable(rebase_offset); + } + */ + // parse vtable entries + pClassEntry = vtable->FirstChildElement(); + for(;pClassEntry;pClassEntry=pClassEntry->NextSiblingElement()) + { + string type = pClassEntry->Value(); + const char *cstr_name = pClassEntry->Attribute("name"); + const char *cstr_vtable = pClassEntry->Attribute("vtable"); + uint32_t vtable = 0; + if(cstr_vtable) + vtable = strtol(cstr_vtable, NULL, 16); + // it's a simple class + if(type== "class") + { + mem->setClass(cstr_name, vtable); + } + // it's a multi-type class + else if (type == "multiclass") + { + // get offset of the type variable + const char *cstr_typeoffset = pClassEntry->Attribute("typeoffset"); + uint32_t typeoffset = 0; + if(cstr_typeoffset) + typeoffset = strtol(cstr_typeoffset, NULL, 16); + t_class * mclass = mem->setClass(cstr_name, vtable, typeoffset); + // parse class sub-entries + pClassSubEntry = pClassEntry->FirstChildElement(); + for(;pClassSubEntry;pClassSubEntry=pClassSubEntry->NextSiblingElement()) + { + type = pClassSubEntry->Value(); + if(type== "class") + { + // type is a value loaded from type offset + cstr_name = pClassSubEntry->Attribute("name"); + const char *cstr_value = pClassSubEntry->Attribute("type"); + mem->setClassChild(mclass,cstr_name,cstr_value); + } + } + } + } +} + +// FIXME: this is ripe for replacement with a more generic approach +void VersionInfoFactory::ParseOffsets(TiXmlElement * parent, VersionInfo* target, bool initial) +{ + // we parse the groups iteratively instead of recursively + // breadcrubs acts like a makeshift stack + // first pair entry stores the current element of that level + // second pair entry the group object from OffsetGroup + typedef pair < TiXmlElement *, OffsetGroup * > groupPair; + vector< groupPair > breadcrumbs; + { + TiXmlElement* pEntry; + // we get the , look at the children + pEntry = parent->FirstChildElement(); + if(!pEntry) + return; + + OffsetGroup * currentGroup = reinterpret_cast (target); + breadcrumbs.push_back(groupPair(pEntry,currentGroup)); + } + + // work variables + OffsetGroup * currentGroup = 0; + TiXmlElement * currentElem = 0; + //cerr << ""<< endl; + while(1) + { + // get current work variables + currentElem = breadcrumbs.back().first; + currentGroup = breadcrumbs.back().second; + + // we reached the end of the current group? + if(!currentElem) + { + // go one level up + breadcrumbs.pop_back(); + // exit if no more work + if(breadcrumbs.empty()) + { + break; + } + else + { + //cerr << "" << endl; + continue; + } + } + + if(!currentGroup) + { + groupPair & gp = breadcrumbs.back(); + gp.first = gp.first->NextSiblingElement(); + continue; + } + + // skip non-elements + if (currentElem->Type() != TiXmlNode::ELEMENT) + { + groupPair & gp = breadcrumbs.back(); + gp.first = gp.first->NextSiblingElement(); + continue; + } + + // we have a valid current element and current group + // get properties + string type = currentElem->Value(); + std::transform(type.begin(), type.end(), type.begin(), ::tolower); + const char *cstr_name = currentElem->Attribute("name"); + if(!cstr_name) + { + // ERROR, missing attribute + } + + // evaluate elements + const char *cstr_value = currentElem->Attribute("value"); + if(type == "group") + { + // FIXME: possibly use setGroup always, with the initial flag as parameter? + // create or get group + OffsetGroup * og; + if(initial) + og = currentGroup->createGroup(cstr_name); + else + og = currentGroup->getGroup(cstr_name); + //cerr << "" << endl; + // advance this level to the next element + groupPair & gp = breadcrumbs.back(); + gp.first = currentElem->NextSiblingElement(); + + if(!og) + { + string fullname = currentGroup->getFullName() + cstr_name; + throw Error::MissingMemoryDefinition("group", fullname); + } + + // add a new level that will be processed next + breadcrumbs.push_back(groupPair(currentElem->FirstChildElement(), og)); + continue; + } + else if(type == "address") + { + if(initial) + { + currentGroup->createAddress(cstr_name); + } + else if(cstr_value) + { + currentGroup->setAddress(cstr_name, cstr_value); + } + else + { + // ERROR, missing attribute + } + } + else if(type == "offset") + { + if(initial) + { + currentGroup->createOffset(cstr_name); + } + else if(cstr_value) + { + currentGroup->setOffset(cstr_name, cstr_value); + } + else + { + // ERROR, missing attribute + } + } + else if(type == "string") + { + if(initial) + { + currentGroup->createString(cstr_name); + } + else if(cstr_value) + { + currentGroup->setString(cstr_name, cstr_value); + } + else + { + // ERROR, missing attribute + } + } + else if(type == "hexvalue") + { + if(initial) + { + currentGroup->createHexValue(cstr_name); + } + else if(cstr_value) + { + currentGroup->setHexValue(cstr_name, cstr_value); + } + else + { + // ERROR, missing attribute + } + } + + // advance to next element + groupPair & gp = breadcrumbs.back(); + gp.first = currentElem->NextSiblingElement(); + continue; + } + //cerr << ""<< endl; +} + +void VersionInfoFactory::ParseBase (TiXmlElement* entry, VersionInfo* mem) +{ + TiXmlElement* pElement; + TiXmlElement* pElement2nd; + const char *cstr_version = entry->Attribute("name"); + + if (!cstr_version) + throw Error::MemoryXmlBadAttribute("name"); + + mem->setVersion(cstr_version); + mem->setOS(VersionInfo::OS_BAD); + + // process additional entries + pElement = entry->FirstChildElement()->ToElement(); + for(;pElement;pElement=pElement->NextSiblingElement()) + { + // only elements get processed + const char *cstr_type = pElement->Value(); + std::string type = cstr_type; + if(type == "VTable") + { + ParseVTable(pElement, mem); + continue; + } + else if(type == "Offsets") + { + // we don't care about the descriptions here, do nothing + ParseOffsets(pElement, mem, true); + continue; + } + else if (type == "Professions") + { + pElement2nd = pElement->FirstChildElement("Profession"); + for(;pElement2nd;pElement2nd=pElement2nd->NextSiblingElement("Profession")) + { + const char * id = pElement2nd->Attribute("id"); + const char * name = pElement2nd->Attribute("name"); + // FIXME: missing some attributes here + if(id && name) + { + mem->setProfession(id,name); + } + else + { + // FIXME: this is crap, doesn't tell anything about the error + throw Error::MemoryXmlUnderspecifiedEntry(name); + } + } + } + else if (type == "Jobs") + { + pElement2nd = pElement->FirstChildElement("Job"); + for(;pElement2nd;pElement2nd=pElement2nd->NextSiblingElement("Job")) + { + const char * id = pElement2nd->Attribute("id"); + const char * name = pElement2nd->Attribute("name"); + if(id && name) + { + mem->setJob(id,name); + } + else + { + // FIXME: this is crap, doesn't tell anything about the error + throw Error::MemoryXmlUnderspecifiedEntry(name); + } + } + } + else if (type == "Skills") + { + pElement2nd = pElement->FirstChildElement("Skill"); + for(;pElement2nd;pElement2nd=pElement2nd->NextSiblingElement("Skill")) + { + const char * id = pElement2nd->Attribute("id"); + const char * name = pElement2nd->Attribute("name"); + if(id && name) + { + mem->setSkill(id,name); + } + else + { + // FIXME: this is crap, doesn't tell anything about the error + throw Error::MemoryXmlUnderspecifiedEntry(name); + } + } + } + else if (type == "Traits") + { + pElement2nd = pElement->FirstChildElement("Trait"); + for(;pElement2nd;pElement2nd=pElement2nd->NextSiblingElement("Trait")) + { + const char * id = pElement2nd->Attribute("id"); + const char * name = pElement2nd->Attribute("name"); + const char * lvl0 = pElement2nd->Attribute("level_0"); + const char * lvl1 = pElement2nd->Attribute("level_1"); + const char * lvl2 = pElement2nd->Attribute("level_2"); + const char * lvl3 = pElement2nd->Attribute("level_3"); + const char * lvl4 = pElement2nd->Attribute("level_4"); + const char * lvl5 = pElement2nd->Attribute("level_5"); + if(id && name && lvl0 && lvl1 && lvl2 && lvl3 && lvl4 && lvl5) + { + mem->setTrait(id, name, lvl0, lvl1, lvl2, lvl3, lvl4, lvl5); + } + else + { + // FIXME: this is crap, doesn't tell anything about the error + throw Error::MemoryXmlUnderspecifiedEntry(name); + } + } + } + else if (type == "Labors") + { + pElement2nd = pElement->FirstChildElement("Labor"); + for(;pElement2nd;pElement2nd=pElement2nd->NextSiblingElement("Labor")) + { + const char * id = pElement2nd->Attribute("id"); + const char * name = pElement2nd->Attribute("name"); + if(id && name) + { + mem->setLabor(id,name); + } + else + { + // FIXME: this is crap, doesn't tell anything about the error + throw Error::MemoryXmlUnderspecifiedEntry(name); + } + } + } + else if (type == "Levels") + { + pElement2nd = pElement->FirstChildElement("Level"); + for(;pElement2nd;pElement2nd=pElement2nd->NextSiblingElement("Level")) + { + const char * id = pElement2nd->Attribute("id"); + const char * name = pElement2nd->Attribute("name"); + const char * nextlvl = pElement2nd->Attribute("xpNxtLvl"); + if(id && name && nextlvl) + { + mem->setLevel(id, name, nextlvl); + } + else + { + // FIXME: this is crap, doesn't tell anything about the error + throw Error::MemoryXmlUnderspecifiedEntry(name); + } + } + } + else if (type == "Moods") + { + pElement2nd = pElement->FirstChildElement("Mood"); + for(;pElement2nd;pElement2nd=pElement2nd->NextSiblingElement("Mood")) + { + const char * id = pElement2nd->Attribute("id"); + const char * name = pElement2nd->Attribute("name"); + if(id && name) + { + mem->setMood(id, name); + } + else + { + // FIXME: this is crap, doesn't tell anything about the error + throw Error::MemoryXmlUnderspecifiedEntry(name); + } + } + } + else + { + //FIXME: only log, not hard error + //throw Error::MemoryXmlUnknownType(type.c_str()); + } + } // for +} // method + +void VersionInfoFactory::EvalVersion(string base, VersionInfo * mem) +{ + if(knownVersions.find(base) != knownVersions.end()) + { + v_descr & desc = knownVersions[base]; + if (!desc.second) + { + VersionInfo * newmem = new VersionInfo(); + ParseVersion(desc.first, newmem); + desc.second = newmem; + } + mem->copy(desc.second); + } +} + +void VersionInfoFactory::ParseVersion (TiXmlElement* entry, VersionInfo* mem) +{ + TiXmlElement* pMemEntry; + const char *cstr_name = entry->Attribute("name"); + const char *cstr_os = entry->Attribute("os"); + const char *cstr_base = entry->Attribute("base"); + const char *cstr_rebase = entry->Attribute("rebase"); + if(cstr_base) + { + string base = cstr_base; + EvalVersion(base, mem); + } + + if (!cstr_name) + throw Error::MemoryXmlBadAttribute("name"); + if (!cstr_os) + throw Error::MemoryXmlBadAttribute("os"); + + string os = cstr_os; + mem->setVersion(cstr_name); + mem->setOS(cstr_os); + + // offset inherited addresses by 'rebase'. + int32_t rebase = 0; + if(cstr_rebase) + { + rebase = mem->getBase() + strtol(cstr_rebase, NULL, 16); + mem->RebaseAddresses(rebase); + } + + //set base to default, we're overwriting this because the previous rebase could cause havoc on Vista/7 + if(os == "windows") + { + // set default image base. this is fixed for base relocation later + mem->setBase(0x400000); + } + else if(os == "linux") + { + // this is wrong... I'm not going to do base image relocation on linux though. + // users are free to use a sane kernel that doesn't do this kind of **** by default + mem->setBase(0x0); + } + else + { + throw Error::MemoryXmlBadAttribute("os"); + } + + // process additional entries + //cout << "Entry " << cstr_version << " " << cstr_os << endl; + pMemEntry = entry->FirstChildElement()->ToElement(); + for(;pMemEntry;pMemEntry=pMemEntry->NextSiblingElement()) + { + string type, name, value; + const char *cstr_type = pMemEntry->Value(); + type = cstr_type; + // check for missing parts + if(type == "VTable") + { + ParseVTable(pMemEntry, mem); + continue; + } + else if(type == "Offsets") + { + ParseOffsets(pMemEntry, mem); + continue; + } + else if (type == "MD5") + { + const char *cstr_value = pMemEntry->Attribute("value"); + if(!cstr_value) + throw Error::MemoryXmlUnderspecifiedEntry(cstr_name); + mem->setMD5(cstr_value); + } + else if (type == "PETimeStamp") + { + const char *cstr_value = pMemEntry->Attribute("value"); + if(!cstr_value) + throw Error::MemoryXmlUnderspecifiedEntry(cstr_name); + mem->setPE(strtol(cstr_value, 0, 16)); + } + } // for +} // method + +VersionInfoFactory::VersionInfoFactory(string path_to_xml) +{ + error = false; + loadFile(path_to_xml); +} + +// load the XML file with offsets +bool VersionInfoFactory::loadFile(string path_to_xml) +{ + TiXmlDocument doc( path_to_xml.c_str() ); + //bool loadOkay = doc.LoadFile(); + if (!doc.LoadFile()) + { + error = true; + throw Error::MemoryXmlParse(doc.ErrorDesc(), doc.ErrorId(), doc.ErrorRow(), doc.ErrorCol()); + } + TiXmlHandle hDoc(&doc); + TiXmlElement* pElem; + TiXmlHandle hRoot(0); + VersionInfo *mem; + + // block: name + { + pElem=hDoc.FirstChildElement().Element(); + // should always have a valid root but handle gracefully if it does + if (!pElem) + { + error = true; + throw Error::MemoryXmlNoRoot(); + } + string m_name=pElem->Value(); + if(m_name != "DFHack") + { + error = true; + throw Error::MemoryXmlNoRoot(); + } + // save this for later + hRoot=TiXmlHandle(pElem); + } + // transform elements + { + // trash existing list + for(uint32_t i = 0; i < versions.size(); i++) + { + delete versions[i]; + } + versions.clear(); + + // For each base version + TiXmlElement* pMemInfo=hRoot.FirstChild( "Base" ).Element(); + map map_pNamedEntries; + vector v_sEntries; + for( ; pMemInfo; pMemInfo=pMemInfo->NextSiblingElement("Base")) + { + const char *name = pMemInfo->Attribute("name"); + if(name) + { + string str_name = name; + VersionInfo *base = new VersionInfo(); + mem = new VersionInfo(); + ParseBase( pMemInfo , mem ); + knownVersions[str_name] = v_descr (pMemInfo, mem); + } + } + + // For each derivative version + pMemInfo=hRoot.FirstChild( "Version" ).Element(); + for( ; pMemInfo; pMemInfo=pMemInfo->NextSiblingElement("Version")) + { + const char *name = pMemInfo->Attribute("name"); + if(name) + { + string str_name = name; + knownVersions[str_name] = v_descr (pMemInfo, NULL); + v_sEntries.push_back(str_name); + } + } + // Parse the versions + for(uint32_t i = 0; i< v_sEntries.size();i++) + { + //FIXME: add a set of entries processed in a step of this cycle, use it to check for infinite loops + string & name = v_sEntries[i]; + v_descr & desc = knownVersions[name]; + if(!desc.second) + { + VersionInfo *version = new VersionInfo(); + ParseVersion( desc.first , version ); + versions.push_back(version); + } + } + + // process found things here + } + error = false; + return true; +} diff --git a/library/include/DFHack.h b/library/include/DFHack.h index 3ccaf0b83..95f39729a 100644 --- a/library/include/DFHack.h +++ b/library/include/DFHack.h @@ -17,7 +17,7 @@ #include "dfhack/DFError.h" #include "dfhack/DFContextManager.h" #include "dfhack/DFContext.h" -#include "dfhack/DFMemInfo.h" +#include "dfhack/VersionInfo.h" #include "dfhack/DFProcess.h" #include "dfhack/DFTypes.h" @@ -32,6 +32,7 @@ #include "dfhack/modules/Items.h" #include "dfhack/modules/Vegetation.h" #include "dfhack/modules/Maps.h" +#include "dfhack/modules/Gui.h" /* * This is a header full of ugly, volatile things. diff --git a/library/include/dfhack-c/DFTypes_C.h b/library/include/dfhack-c/DFTypes_C.h index 112e195d4..49bd54dc9 100644 --- a/library/include/dfhack-c/DFTypes_C.h +++ b/library/include/dfhack-c/DFTypes_C.h @@ -29,6 +29,7 @@ distribution. #include "dfhack/DFTypes.h" #include "dfhack/modules/Maps.h" #include "dfhack/modules/Materials.h" +#include "dfhack/modules/Position.h" #include "dfhack/DFTileTypes.h" #ifdef __cplusplus @@ -49,6 +50,10 @@ 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); +DFHACK_EXPORT extern int (*alloc_t_feature_buffer_callback)(t_feature*, uint32_t); +DFHACK_EXPORT extern int (*alloc_t_hotkey_buffer_callback)(t_hotkey*, uint32_t); +DFHACK_EXPORT extern int (*alloc_t_screen_buffer_callback)(t_screen*, uint32_t); + struct t_customWorkshop { uint32_t index; diff --git a/library/include/dfhack-c/README_C.txt b/library/include/dfhack-c/README_C.rst similarity index 73% rename from library/include/dfhack-c/README_C.txt rename to library/include/dfhack-c/README_C.rst index 3b785cf54..7a5b69a54 100644 --- a/library/include/dfhack-c/README_C.txt +++ b/library/include/dfhack-c/README_C.rst @@ -54,17 +54,36 @@ Buffer Callback List - alloc_ubyte_buffer_callback(uint8_t*, uint32_t) - alloc_ushort_buffer_callback(uint16_t*, uint32_t) - alloc_uint_buffer_callback(uint32_t*, uint32_t) +- alloc_char_buffer_callback(char* uint32_t) - alloc_matgloss_buffer_callback(t_matgloss*, uint32_t) - alloc_descriptor_buffer_callback(t_descriptor_color*, uint32_t) - alloc_matgloss_other_buffer_callback(t_matglossOther*, uint32_t) - alloc_vein_buffer_callback(t_vein*, uint32_t) +- alloc_t_feature_buffer_callback(t_feature*, uint32_t) +- alloc_t_hotkey_buffer_callback(t_hotkey*, uint32_t) +- alloc_t_screen_buffer_callback(t_screen*, uint32_t) - alloc_frozenliquidvein_buffer_callback(t_frozenliquidvein*, uint32_t) - alloc_spattervein_buffer_callback(t_spattervein*, uint32_t) Templates Make My Life Harder ------------------------------- -Three dfhack structures (t_colormodifier, t_creaturecaste, and t_creaturetype) contain vectors, which (obviously) don't work in C. Therefore, these structures have C versions that replace the vector with a buffer and length, but are otherwise identical to their C++ counterparts. For each structure, there are three associated callbacks. One initializes an empty instance of the structure, one initializes an instance with values passed in, and one allocates a buffer in the same manner as the other allocators. - +Several dfhack structures contain vectors, which (obviously) don't work in C. Therefore, these structures have C versions that replace the vector with a buffer and length, but are otherwise identical to their C++ counterparts. For each structure, there are three associated callbacks. One initializes an empty instance of the structure (*alloc_empty_colormodifier_callback*, for instance), one initializes an instance with values passed in (*alloc_colormodifier_callback*), and one allocates a buffer in the same manner as the other allocators (*alloc_colormodifier_buffer_callback*). + +The replaced structures and their callbacks are as follows. + +- c_colormodifier + * alloc_empty_colormodifier_callback(c_colormodifier*) + * alloc_colormodifier_callback(c_colormodifier*, const char*, uint32_t) + * alloc_colormodifier_buffer_callback(c_colormodifier*, uint32_t) +- c_creaturecaste + * alloc_empty_creaturecaste_callback(c_creaturecaste*) + * alloc_creaturecaste_callback(c_creaturecaste*, const char*, const char*, const char*, const char*, uint32_t, uint32_t) + * alloc_creaturecaste_buffer_callback(c_creaturecaste*, uint32_t) +- c_creaturetype + * alloc_empty_creaturetype_callback(c_creaturetype*) + * alloc_creaturetype_callback(c_creaturetype*, const char*, uint32_t, uint32_t, uint8_t, uint16_t, uint16_t, uint16_t) + * alloc_creaturetype_buffer_callback(c_creaturetype*, uint32_t) + A Small Callback Example In Python ------------------------------------- The Python bindings for dfhack implement the unsigned integer allocator callback like this: diff --git a/library/include/dfhack-c/modules/Gui_C.h b/library/include/dfhack-c/modules/Gui_C.h index 2373d458d..8cc737f78 100644 --- a/library/include/dfhack-c/modules/Gui_C.h +++ b/library/include/dfhack-c/modules/Gui_C.h @@ -38,6 +38,7 @@ DFHACK_EXPORT int Gui_Finish(DFHackObject* gui); DFHACK_EXPORT int Gui_ReadPauseState(DFHackObject* gui); DFHACK_EXPORT int Gui_ReadViewScreen(DFHackObject* gui, t_viewscreen* viewscreen); +DFHACK_EXPORT int Gui_ReadMenuState(DFHackObject* gui, uint32_t* menuState); #ifdef __cplusplus } diff --git a/library/include/dfhack-c/modules/Maps_C.h b/library/include/dfhack-c/modules/Maps_C.h index d1bad823e..fdbfdf1be 100644 --- a/library/include/dfhack-c/modules/Maps_C.h +++ b/library/include/dfhack-c/modules/Maps_C.h @@ -36,6 +36,8 @@ extern "C" { DFHACK_EXPORT int Maps_Start(DFHackObject* maps); DFHACK_EXPORT int Maps_Finish(DFHackObject* maps); +DFHACK_EXPORT t_feature* Maps_ReadGlobalFeatures(DFHackObject* maps); + DFHACK_EXPORT void Maps_getSize(DFHackObject* maps, uint32_t* x, uint32_t* y, uint32_t* z); DFHACK_EXPORT int Maps_isValidBlock(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z); diff --git a/library/include/dfhack-c/modules/Materials_C.h b/library/include/dfhack-c/modules/Materials_C.h index 888978a50..82f426ca7 100644 --- a/library/include/dfhack-c/modules/Materials_C.h +++ b/library/include/dfhack-c/modules/Materials_C.h @@ -44,6 +44,7 @@ DFHACK_EXPORT int Materials_ReadOthers(DFHackObject* mat); DFHACK_EXPORT void Materials_ReadAllMaterials(DFHackObject* mat); +DFHACK_EXPORT const char* Materials_getType(DFHackObject* mat, t_material* material); DFHACK_EXPORT const char* Materials_getDescription(DFHackObject* mat, t_material* material); DFHACK_EXPORT int Materials_getInorganicSize(DFHackObject* mat); diff --git a/library/include/dfhack-c/modules/Position_C.h b/library/include/dfhack-c/modules/Position_C.h index 665e400bf..2b60fa2e2 100644 --- a/library/include/dfhack-c/modules/Position_C.h +++ b/library/include/dfhack-c/modules/Position_C.h @@ -38,8 +38,12 @@ DFHACK_EXPORT int Position_setViewCoords(DFHackObject* pos, const int32_t x, con DFHACK_EXPORT int Position_getCursorCoords(DFHackObject* pos, int32_t* x, int32_t* y, int32_t* z); DFHACK_EXPORT int Position_setCursorCoords(DFHackObject* pos, const int32_t x, const int32_t y, const int32_t z); +DFHACK_EXPORT t_hotkey* Position_ReadHotkeys(DFHackObject* pos); + DFHACK_EXPORT int Position_getWindowSize(DFHackObject* pos, int32_t* width, int32_t* height); +DFHACK_EXPORT t_screen* Position_getScreenTiles(DFHackObject* pos, int32_t width, int32_t height); + #ifdef __cplusplus } #endif diff --git a/library/include/dfhack-c/modules/World_C.h b/library/include/dfhack-c/modules/World_C.h index f6261a738..c4348b5e9 100644 --- a/library/include/dfhack-c/modules/World_C.h +++ b/library/include/dfhack-c/modules/World_C.h @@ -40,6 +40,9 @@ 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); +DFHACK_EXPORT int World_ReadCurrentWeather(DFHackObject* world, uint8_t* weather); +DFHACK_EXPORT int World_WriteCurrentWeather(DFHackObject* world, uint8_t weather); + #ifdef __cplusplus } #endif diff --git a/library/include/dfhack/DFContext.h b/library/include/dfhack/DFContext.h index 9c092cc38..3d8a0c150 100644 --- a/library/include/dfhack/DFContext.h +++ b/library/include/dfhack/DFContext.h @@ -40,7 +40,7 @@ namespace DFHack class Vegetation; class Buildings; class Constructions; - class memory_info; + class VersionInfo; class DFContextShared; class WindowIO; class Process; @@ -71,7 +71,7 @@ namespace DFHack /// forces resume on Windows. This can be a bad thing with multiple tools running! bool ForceResume(); - memory_info *getMemoryInfo(); + VersionInfo *getMemoryInfo(); Process* getProcess(); void ReadRaw (const uint32_t offset, const uint32_t size, uint8_t *target); diff --git a/library/include/dfhack/DFError.h b/library/include/dfhack/DFError.h index 79823a9fa..fcb80f724 100644 --- a/library/include/dfhack/DFError.h +++ b/library/include/dfhack/DFError.h @@ -34,7 +34,12 @@ namespace DFHack { namespace Error { - class DFHACK_EXPORT NoProcess : public std::exception + /* + * our wrapper for the C++ exception. used to differentiate + * the whole array of DFHack exceptions from the rest + */ + class DFHACK_EXPORT All : public std::exception{}; + class DFHACK_EXPORT NoProcess : public All { public: virtual const char* what() const throw() @@ -43,7 +48,7 @@ namespace DFHack } }; - class DFHACK_EXPORT CantAttach : public std::exception + class DFHACK_EXPORT CantAttach : public All { public: virtual const char* what() const throw() @@ -52,7 +57,7 @@ namespace DFHack } }; - class DFHACK_EXPORT NoMapLoaded : public std::exception + class DFHACK_EXPORT NoMapLoaded : public All { public: virtual const char* what() const throw() @@ -61,7 +66,7 @@ namespace DFHack } }; - class DFHACK_EXPORT BadMapDimensions : public std::exception + class DFHACK_EXPORT BadMapDimensions : public All { public: BadMapDimensions(uint32_t& _x, uint32_t& _y) : x(_x), y(_y) {} @@ -75,13 +80,13 @@ namespace DFHack }; // a call to DFHack::mem_info::get* failed - class DFHACK_EXPORT MissingMemoryDefinition : public std::exception + class DFHACK_EXPORT MissingMemoryDefinition : public All { public: - MissingMemoryDefinition(const char* _type, const char* _key) : type(_type), key(_key) + MissingMemoryDefinition(const char* _type, const std::string _key) : type(_type), key(_key) { std::stringstream s; - s << "memory definition missing: type " << type << " key " << key; + s << "memory object not declared: type=" << type << " key=" << key; full = s.str(); } // Used by functios using integer keys, such as getTrait @@ -92,24 +97,44 @@ namespace DFHack key = s1.str(); std::stringstream s; - s << "memory definition missing: type " << type << " key " << key; + s << "memory object not declared: type=" << type << " key=" << key; full = s.str(); } virtual ~MissingMemoryDefinition() throw(){}; - // (perhaps it should be an enum, but this is intended for easy printing/logging) - // type can be any of the following: - // - // address - // offset - // hexvalue - // string - // profession - // job - // skill - // trait - // traitname - // labor + std::string full; + const std::string type; + std::string key; + + virtual const char* what() const throw() + { + return full.c_str(); + } + }; + + // a call to DFHack::mem_info::get* failed + class DFHACK_EXPORT UnsetMemoryDefinition : public All + { + public: + UnsetMemoryDefinition(const char* _type, const std::string _key) : type(_type), key(_key) + { + std::stringstream s; + s << "memory object not set: type " << type << " key " << key; + full = s.str(); + } + // Used by functios using integer keys, such as getTrait + UnsetMemoryDefinition(const char* _type, uint32_t _key) : type(_type) + { + std::stringstream s1; + s1 << _key; + key = s1.str(); + + std::stringstream s; + s << "memory object not set: type " << type << " key " << key; + full = s.str(); + } + virtual ~UnsetMemoryDefinition() throw(){}; + std::string full; const std::string type; std::string key; @@ -121,7 +146,7 @@ namespace DFHack }; // Syntax errors and whatnot, the xml cant be read - class DFHACK_EXPORT MemoryXmlParse : public std::exception + class DFHACK_EXPORT MemoryXmlParse : public All { public: MemoryXmlParse(const char* _desc, int _id, int _row, int _col) @@ -147,7 +172,7 @@ namespace DFHack } }; - class DFHACK_EXPORT MemoryXmlBadAttribute : public std::exception + class DFHACK_EXPORT MemoryXmlBadAttribute : public All { public: MemoryXmlBadAttribute(const char* _attr) : attr(_attr) @@ -167,7 +192,7 @@ namespace DFHack } }; - class DFHACK_EXPORT MemoryXmlNoRoot : public std::exception + class DFHACK_EXPORT MemoryXmlNoRoot : public All { public: MemoryXmlNoRoot() {} @@ -180,7 +205,7 @@ namespace DFHack } }; - class DFHACK_EXPORT MemoryXmlNoDFExtractor : public std::exception + class DFHACK_EXPORT MemoryXmlNoDFExtractor : public All { public: MemoryXmlNoDFExtractor(const char* _name) : name(_name) @@ -200,7 +225,7 @@ namespace DFHack } }; - class DFHACK_EXPORT MemoryXmlUnderspecifiedEntry : public std::exception + class DFHACK_EXPORT MemoryXmlUnderspecifiedEntry : public All { public: MemoryXmlUnderspecifiedEntry(const char * _where) : where(_where) @@ -218,7 +243,7 @@ namespace DFHack } }; - class DFHACK_EXPORT MemoryXmlUnknownType : public std::exception + class DFHACK_EXPORT MemoryXmlUnknownType : public All { public: MemoryXmlUnknownType(const char* _type) : type(_type) @@ -238,7 +263,7 @@ namespace DFHack } }; - class DFHACK_EXPORT SHMServerDisappeared : public std::exception + class DFHACK_EXPORT SHMServerDisappeared : public All { public: SHMServerDisappeared(){} @@ -248,7 +273,7 @@ namespace DFHack return "The server process has disappeared"; } }; - class DFHACK_EXPORT SHMLockingError : public std::exception + class DFHACK_EXPORT SHMLockingError : public All { public: SHMLockingError(const char* _type) : type(_type) @@ -267,7 +292,7 @@ namespace DFHack return full.c_str(); } }; - class DFHACK_EXPORT MemoryAccessDenied : public std::exception + class DFHACK_EXPORT MemoryAccessDenied : public All { public: MemoryAccessDenied() {} @@ -277,7 +302,7 @@ namespace DFHack return "SHM ACCESS DENIED"; } }; - class DFHACK_EXPORT SHMVersionMismatch : public std::exception + class DFHACK_EXPORT SHMVersionMismatch : public All { public: SHMVersionMismatch() {} @@ -287,7 +312,7 @@ namespace DFHack return "SHM VERSION MISMATCH"; } }; - class DFHACK_EXPORT SHMAttachFailure : public std::exception + class DFHACK_EXPORT SHMAttachFailure : public All { public: SHMAttachFailure() {} @@ -297,7 +322,7 @@ namespace DFHack return "SHM ATTACH FAILURE"; } }; - class DFHACK_EXPORT ModuleNotInitialized : public std::exception + class DFHACK_EXPORT ModuleNotInitialized : public All { public: ModuleNotInitialized() {} diff --git a/library/include/dfhack/DFMiscUtils.h b/library/include/dfhack/DFMiscUtils.h index 04676a769..7082bbdd4 100644 --- a/library/include/dfhack/DFMiscUtils.h +++ b/library/include/dfhack/DFMiscUtils.h @@ -12,7 +12,7 @@ using namespace std; #include -#include +#include #include void DumpObjStr0Vector (const char * name, DFHack::Process *p, uint32_t addr) @@ -81,7 +81,7 @@ void hexdump (DFHack::Context *DF, uint32_t address, uint32_t length) void interleave_hex (DFHack::Context* DF, vector < uint32_t > & addresses, uint32_t length) { vector bufs; - + for(uint32_t counter = 0; counter < addresses.size(); counter ++) { char * buf = new char[length * 16]; @@ -97,7 +97,7 @@ void interleave_hex (DFHack::Context* DF, vector < uint32_t > & addresses, uint3 cout << "0x" << hex << setw(9) << addresses[obj] << " "; } cout << endl; - + for(uint32_t offs = 0 ; offs < length * 16; offs += 4) { if((!(offs % 16)) && offs != 0) @@ -130,7 +130,7 @@ template void print_bits ( T val, std::ostream& out ) { T n_bits = sizeof ( val ) * CHAR_BIT; - + for ( unsigned i = 0; i < n_bits; ++i ) { out<< !!( val & 1 ) << " "; val >>= 1; diff --git a/library/include/dfhack/DFProcess.h b/library/include/dfhack/DFProcess.h index 25ac51997..282e1b95f 100644 --- a/library/include/dfhack/DFProcess.h +++ b/library/include/dfhack/DFProcess.h @@ -31,7 +31,7 @@ distribution. namespace DFHack { - class memory_info; + class VersionInfo; class Process; class Window; @@ -160,7 +160,7 @@ namespace DFHack virtual void getMemRanges(std::vector & ranges ) = 0; /// get the flattened Memory.xml entry of this process - virtual memory_info *getDescriptor() = 0; + virtual VersionInfo *getDescriptor() = 0; /// get the DF Process ID virtual int getPID() = 0; /// get module index by name and version. bool 1 = error @@ -182,7 +182,7 @@ namespace DFHack private: Private * const d; public: - NormalProcess(uint32_t pid, std::vector & known_versions); + NormalProcess(uint32_t pid, std::vector & known_versions); ~NormalProcess(); bool attach(); bool detach(); @@ -228,7 +228,7 @@ namespace DFHack bool getThreadIDs(std::vector & threads ); void getMemRanges(std::vector & ranges ); - memory_info *getDescriptor(); + VersionInfo *getDescriptor(); int getPID(); // get module index by name and version. bool 1 = error bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) { OUTPUT=0; return false;}; @@ -246,7 +246,7 @@ namespace DFHack Private * const d; public: - SHMProcess(uint32_t PID, std::vector & known_versions); + SHMProcess(uint32_t PID, std::vector & known_versions); ~SHMProcess(); // Set up stuff so we can read memory bool attach(); @@ -293,7 +293,7 @@ namespace DFHack bool getThreadIDs(std::vector & threads ); void getMemRanges(std::vector & ranges ); - memory_info *getDescriptor(); + VersionInfo *getDescriptor(); int getPID(); // get module index by name and version. bool 1 = error bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT); @@ -311,7 +311,7 @@ namespace DFHack Private * const d; public: - WineProcess(uint32_t pid, std::vector & known_versions); + WineProcess(uint32_t pid, std::vector & known_versions); ~WineProcess(); bool attach(); bool detach(); @@ -357,7 +357,7 @@ namespace DFHack bool getThreadIDs(std::vector & threads ); void getMemRanges(std::vector & ranges ); - memory_info *getDescriptor(); + VersionInfo *getDescriptor(); int getPID(); // get module index by name and version. bool 1 = error bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) {OUTPUT=0; return false;}; diff --git a/library/include/dfhack/DFProcessEnumerator.h b/library/include/dfhack/DFProcessEnumerator.h index 0422367d5..4b1eca7b0 100644 --- a/library/include/dfhack/DFProcessEnumerator.h +++ b/library/include/dfhack/DFProcessEnumerator.h @@ -30,7 +30,7 @@ distribution. namespace DFHack { - class memory_info; + class VersionInfo; class Process; class BadProcesses; /** diff --git a/library/include/dfhack/DFVector.h b/library/include/dfhack/DFVector.h index c46c80492..2eca3f2d8 100644 --- a/library/include/dfhack/DFVector.h +++ b/library/include/dfhack/DFVector.h @@ -29,6 +29,7 @@ distribution. #include "DFExport.h" namespace DFHack { + class VersionInfo; class Process; template class DFHACK_EXPORT DfVector @@ -41,9 +42,9 @@ namespace DFHack DfVector(Process * p, uint32_t address) { uint32_t triplet[3]; - memory_info * mem = p->getDescriptor(); - uint32_t offs = mem->getOffset("vector_triplet"); - + VersionInfo * mem = p->getDescriptor(); + uint32_t offs = mem->getGroup("vector")->getOffset("start"); + p->read(address + offs, sizeof(triplet), (uint8_t *) &triplet); _start = triplet[0]; uint32_t byte_size = triplet[1] - triplet[0]; @@ -74,12 +75,12 @@ namespace DFHack return data[index]; }; // get vector size - inline uint32_t size () + inline uint32_t size () { return _size; }; // get vector start - inline uint32_t start () + inline uint32_t start () { return _start; }; diff --git a/library/include/dfhack/DFMemInfo.h b/library/include/dfhack/VersionInfo.h similarity index 69% rename from library/include/dfhack/DFMemInfo.h rename to library/include/dfhack/VersionInfo.h index e40ecbf11..84a7087da 100644 --- a/library/include/dfhack/DFMemInfo.h +++ b/library/include/dfhack/VersionInfo.h @@ -28,6 +28,7 @@ distribution. #include "DFPragma.h" #include "DFExport.h" #include "dfhack/DFTypes.h" +#include namespace DFHack { @@ -35,23 +36,67 @@ namespace DFHack * Stubs */ class Process; + class XMLPP; struct t_class; + class VersionInfoPrivate; + class OffsetGroupPrivate; - class DFHACK_EXPORT memory_info + /* + * Offset Group + */ + class DFHACK_EXPORT OffsetGroup + { + protected: + OffsetGroupPrivate * OGd; + public: + OffsetGroup(); + OffsetGroup(const std::string & _name, OffsetGroup * parent = 0); + ~OffsetGroup(); + + void copy(const OffsetGroup * old); // recursive + void RebaseAddresses( int32_t offset ); // recursive + + void createOffset (const std::string & key); + void createAddress (const std::string & key); + void createHexValue (const std::string & key); + void createString (const std::string & key); + OffsetGroup * createGroup ( const std::string & name ); + + int32_t getOffset (const std::string & key); + uint32_t getAddress (const std::string & key); + uint32_t getHexValue (const std::string & key); + std::string getString (const std::string & key); + OffsetGroup * getGroup ( const std::string & name ); + + void setOffset (const std::string & key, const std::string & value); + void setAddress (const std::string & key, const std::string & value); + void setHexValue (const std::string & key, const std::string & value); + void setString (const std::string & key, const std::string & value); + std::string PrintOffsets(int indentation); + std::string getName(); + std::string getFullName(); + OffsetGroup * getParent(); + }; + + /* + * Version Info + */ + class DFHACK_EXPORT VersionInfo : public OffsetGroup { private: - class Private; - Private * d; + VersionInfoPrivate * d; public: enum OSType { OS_WINDOWS, OS_LINUX, + OS_APPLE, OS_BAD }; - memory_info(); - memory_info(const memory_info&); - ~memory_info(); + VersionInfo(); + VersionInfo(const VersionInfo&); + void copy(const DFHack::VersionInfo* old); + ~VersionInfo(); void RebaseAddresses(const int32_t new_base); void RebaseAll(const int32_t new_base); @@ -59,12 +104,11 @@ namespace DFHack void setBase (const std::string&); void setBase (const uint32_t); - int32_t getOffset (const std::string&); - uint32_t getAddress (const std::string&); - uint32_t getHexValue (const std::string&); - int32_t getOffset (const char *); - uint32_t getAddress (const char *); - uint32_t getHexValue (const char *); + void setMD5 (const std::string & _md5); + std::string getMD5(); + + void setPE (uint32_t PE_); + uint32_t getPE(); std::string getMood(const uint32_t moodID); std::string getString (const std::string&); @@ -75,6 +119,7 @@ namespace DFHack std::string getTraitName(const uint32_t) const; std::string getLabor (const uint32_t); std::vector< std::vector > const& getAllTraits(); + std::map const& getAllLabours(); DFHack::t_level getLevelInfo(const uint32_t level) const; @@ -87,21 +132,7 @@ namespace DFHack void setOS(const OSType); OSType getOS() const; - void setOffset (const std::string &, const int32_t); - void setAddress (const std::string &, const uint32_t); - void setHexValue (const std::string &, const uint32_t); - - void setOffset (const std::string &, const char *); - void setAddress (const std::string &, const char *); - void setHexValue (const std::string &, const char *); - void setString (const std::string &, const char *); - - void setOffset (const std::string &, const std::string &); - void setAddress (const std::string &, const std::string &); - void setHexValue (const std::string &, const std::string &); - void setString (const std::string &, const std::string &); - - void setProfession(const std::string &, const std::string &); + void setProfession(const std::string & id, const std::string & name); 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 &, @@ -145,7 +176,7 @@ namespace DFHack * Get the internal classID->classname mapping (for speed). DO NOT MANIPULATE THE VECTOR! */ const std::vector * getClassIDMapping(); - + /** * Get a string with all addresses and offsets */ diff --git a/library/private/DFMemInfoManager.h b/library/include/dfhack/VersionInfoFactory.h similarity index 60% rename from library/private/DFMemInfoManager.h rename to library/include/dfhack/VersionInfoFactory.h index 60563d228..7f811f588 100644 --- a/library/private/DFMemInfoManager.h +++ b/library/include/dfhack/VersionInfoFactory.h @@ -26,25 +26,33 @@ distribution. #define MEMINFO_MANAGER_H_INCLUDED #include "dfhack/DFPragma.h" +#include "dfhack/DFExport.h" class TiXmlElement; namespace DFHack { - class memory_info; - class MemInfoManager + class VersionInfo; + class DFHACK_EXPORT VersionInfoFactory { friend class ProcessEnumerator; public: - MemInfoManager(string path_to_xml); - ~MemInfoManager(); + VersionInfoFactory(std::string path_to_xml); + ~VersionInfoFactory(); // memory info entries loaded from a file - bool loadFile( string path_to_xml); + bool loadFile( std::string path_to_xml); bool isInErrorState() const {return error;}; - std::vector meminfo; + std::vector versions; private: - void ParseVTable(TiXmlElement* vtable, memory_info* mem); - void ParseEntry (TiXmlElement* entry, memory_info* mem, map & knownEntries); + void ParseVTable(TiXmlElement* vtable, VersionInfo* mem); + void ParseBase (TiXmlElement* base, VersionInfo* mem); + void ParseVersion (TiXmlElement* version, VersionInfo* mem); + // copy version 'base' to 'target' or throw + void EvalVersion(std::string base, VersionInfo* target); + void ParseOffsets(TiXmlElement* elem, VersionInfo* target, bool initial = false); + bool error; + typedef std::pair < TiXmlElement *, VersionInfo *> v_descr; + std::map knownVersions; }; } diff --git a/library/include/dfhack/modules/Creatures.h b/library/include/dfhack/modules/Creatures.h index 1686be281..67418d08a 100644 --- a/library/include/dfhack/modules/Creatures.h +++ b/library/include/dfhack/modules/Creatures.h @@ -5,6 +5,7 @@ */ #include "dfhack/DFExport.h" #include "dfhack/DFModule.h" +#include "dfhack/modules/Items.h" namespace DFHack { /* @@ -374,6 +375,8 @@ namespace DFHack const uint16_t x2, const uint16_t y2,const uint16_t z2); bool ReadCreature(const int32_t index, t_creature & furball); bool ReadJob(const t_creature * furball, std::vector & mat); + bool ReadInventoryIdx(const uint32_t index, std::vector & item); + bool ReadInventoryPtr(const uint32_t index, std::vector & item); /* Getters */ uint32_t GetDwarfRaceIndex ( void ); diff --git a/library/include/dfhack/modules/Gui.h b/library/include/dfhack/modules/Gui.h index 0ef170d3f..6ac91f35c 100644 --- a/library/include/dfhack/modules/Gui.h +++ b/library/include/dfhack/modules/Gui.h @@ -21,7 +21,9 @@ namespace DFHack bool Finish(); ///true if paused, false if not - bool ReadPauseState(); + bool ReadPauseState(); + ///true if paused, false if not + void SetPauseState(bool paused); /// read the DF menu view state (stock screen, unit screen, other screens bool ReadViewScreen(t_viewscreen &); /// read the DF menu state (designation menu ect) diff --git a/library/include/dfhack/modules/Items.h b/library/include/dfhack/modules/Items.h index 9b2dba8fe..3810e6037 100644 --- a/library/include/dfhack/modules/Items.h +++ b/library/include/dfhack/modules/Items.h @@ -1,5 +1,10 @@ #ifndef CL_MOD_ITEMS #define CL_MOD_ITEMS + +/* + * DEPRECATED, DO NOT USE UNTIL FURTHER NOTICE! + **/ + /* * Creatures */ diff --git a/library/include/dfhack/modules/World.h b/library/include/dfhack/modules/World.h index fdb08baf7..7834d4719 100644 --- a/library/include/dfhack/modules/World.h +++ b/library/include/dfhack/modules/World.h @@ -9,21 +9,29 @@ namespace DFHack { + enum WeatherType + { + CLEAR, + RAINING, + SNOWING + }; class DFContextShared; class DFHACK_EXPORT World : public Module { public: - + World(DFHack::DFContextShared * d); ~World(); bool Start(); bool Finish(); - + uint32_t ReadCurrentTick(); uint32_t ReadCurrentYear(); uint32_t ReadCurrentMonth(); uint32_t ReadCurrentDay(); - + uint8_t ReadCurrentWeather(); + void SetCurrentWeather(uint8_t weather); + private: struct Private; Private *d; diff --git a/library/modules/Buildings.cpp b/library/modules/Buildings.cpp index 5d55163b3..92fca41d3 100644 --- a/library/modules/Buildings.cpp +++ b/library/modules/Buildings.cpp @@ -25,7 +25,7 @@ distribution. #include "Internal.h" #include "ContextShared.h" -#include "dfhack/DFMemInfo.h" +#include "dfhack/VersionInfo.h" #include "dfhack/DFProcess.h" #include "dfhack/DFVector.h" #include "dfhack/DFTypes.h" @@ -71,12 +71,13 @@ Buildings::Buildings(DFContextShared * d_) d->d = d_; d->owner = d_->p; d->Inited = d->Started = false; - memory_info * mem = d->d->offset_descriptor; - d->custom_workshop_vector = mem->getAddress("custom_workshop_vector"); - d->building_custom_workshop_type = mem->getOffset("building_custom_workshop_type"); - d->custom_workshop_type = mem->getOffset("custom_workshop_type"); - d->custom_workshop_name = mem->getOffset("custom_workshop_name"); - d->buildings_vector = mem->getAddress ("buildings_vector"); + VersionInfo * mem = d->d->offset_descriptor; + OffsetGroup * OG_build = mem->getGroup("Buildings"); + d->custom_workshop_vector = OG_build->getAddress("custom_workshop_vector"); + d->building_custom_workshop_type = OG_build->getOffset("building_custom_workshop_type"); + d->custom_workshop_type = OG_build->getOffset("custom_workshop_type"); + d->custom_workshop_name = OG_build->getOffset("custom_workshop_name"); + d->buildings_vector = OG_build->getAddress ("buildings_vector"); mem->resolveClassnameToClassID("building_custom_workshop", d->custom_workshop_id); d->Inited = true; } @@ -139,12 +140,12 @@ bool Buildings::ReadCustomWorkshopTypes(map & btypes) { if(!d->Started) return false; - + Process * p = d->owner; DfVector p_matgloss (p, d->custom_workshop_vector); uint32_t size = p_matgloss.size(); btypes.clear(); - + for (uint32_t i = 0; i < size;i++) { string out = p->readSTLString (p_matgloss[i] + d->custom_workshop_name); diff --git a/library/modules/Constructions.cpp b/library/modules/Constructions.cpp index 535098fc5..ba6370ffd 100644 --- a/library/modules/Constructions.cpp +++ b/library/modules/Constructions.cpp @@ -25,7 +25,7 @@ distribution. #include "Internal.h" #include "ContextShared.h" -#include "dfhack/DFMemInfo.h" +#include "dfhack/VersionInfo.h" #include "dfhack/DFProcess.h" #include "dfhack/DFVector.h" #include "dfhack/DFTypes.h" @@ -38,7 +38,7 @@ struct Constructions::Private uint32_t construction_vector; // translation DfVector * p_cons; - + DFContextShared *d; Process * owner; bool Inited; @@ -52,8 +52,8 @@ Constructions::Constructions(DFContextShared * d_) d->owner = d_->p; d->p_cons = 0; d->Inited = d->Started = false; - memory_info * mem = d->d->offset_descriptor; - d->construction_vector = mem->getAddress ("construction_vector"); + VersionInfo * mem = d->d->offset_descriptor; + d->construction_vector = mem->getGroup("Constructions")->getAddress ("vector"); d->Inited = true; } diff --git a/library/modules/Creatures.cpp b/library/modules/Creatures.cpp index 2e9e319cd..0d26f336b 100644 --- a/library/modules/Creatures.cpp +++ b/library/modules/Creatures.cpp @@ -25,7 +25,7 @@ distribution. #include "Internal.h" #include "ContextShared.h" -#include "dfhack/DFMemInfo.h" +#include "dfhack/VersionInfo.h" #include "dfhack/DFProcess.h" #include "dfhack/DFVector.h" #include "dfhack/DFError.h" @@ -50,10 +50,16 @@ struct Creatures::Private { bool Inited; bool Started; + bool Ft_basic; + bool Ft_advanced; + bool Ft_jobs; + bool Ft_soul; Creatures2010::creature_offsets creatures; uint32_t creature_module; uint32_t dwarf_race_index_addr; uint32_t dwarf_civ_id_addr; + OffsetGroup * OG_jobs; + OffsetGroup * OG_job_mats; DfVector *p_cre; DFContextShared *d; Process *owner; @@ -67,67 +73,72 @@ Creatures::Creatures(DFContextShared* _d) d->Inited = false; d->Started = false; d->d->InitReadNames(); // throws on error + VersionInfo * minfo = d->d->offset_descriptor; + OffsetGroup *OG_Creatures = minfo->getGroup("Creatures"); + OffsetGroup *OG_creature = OG_Creatures->getGroup("creature"); + OffsetGroup *OG_creature_ex = OG_creature->getGroup("advanced"); + OffsetGroup *OG_soul = OG_Creatures->getGroup("soul"); + OffsetGroup * OG_name = minfo->getGroup("name"); + d->OG_jobs = OG_Creatures->getGroup("job"); + d->OG_job_mats = d->OG_jobs->getGroup("material"); + d->Ft_basic = d->Ft_advanced = d->Ft_jobs = d->Ft_soul = false; + + Creatures2010::creature_offsets &creatures = d->creatures; try { - memory_info * minfo = d->d->offset_descriptor; - Creatures2010::creature_offsets &creatures = d->creatures; - creatures.vector = minfo->getAddress ("creature_vector"); - creatures.pos_offset = minfo->getOffset ("creature_position"); - creatures.profession_offset = minfo->getOffset ("creature_profession"); - creatures.custom_profession_offset = minfo->getOffset ("creature_custom_profession"); - creatures.race_offset = minfo->getOffset ("creature_race"); - creatures.civ_offset = minfo->getOffset ("creature_civ"); - creatures.flags1_offset = minfo->getOffset ("creature_flags1"); - creatures.flags2_offset = minfo->getOffset ("creature_flags2"); - creatures.name_offset = minfo->getOffset ("creature_name"); - creatures.sex_offset = minfo->getOffset ("creature_sex"); - creatures.caste_offset = minfo->getOffset ("creature_caste"); - creatures.id_offset = minfo->getOffset ("creature_id"); - creatures.labors_offset = minfo->getOffset ("creature_labors"); - creatures.happiness_offset = minfo->getOffset ("creature_happiness"); - creatures.artifact_name_offset = minfo->getOffset("creature_artifact_name"); - creatures.soul_vector_offset = minfo->getOffset("creature_soul_vector"); - creatures.default_soul_offset = minfo->getOffset("creature_default_soul"); - creatures.physical_offset = minfo->getOffset("creature_physical"); - 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"); - // 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"); - creatures.name_words_offset = minfo->getOffset("name_words"); - d->dwarf_race_index_addr = minfo->getAddress("dwarf_race_index"); - d->dwarf_civ_id_addr = minfo->getAddress("dwarf_civ_id"); - /* - // upload offsets to the SHM - if(p->getModuleIndex("Creatures2010",1,d->creature_module)) + // Creatures + creatures.vector = OG_Creatures->getAddress ("vector"); + d->dwarf_race_index_addr = OG_Creatures->getAddress("current_race"); + d->dwarf_civ_id_addr = OG_Creatures->getAddress("current_civ"); + // Creatures/creature + creatures.name_offset = OG_creature->getOffset ("name"); + creatures.custom_profession_offset = OG_creature->getOffset ("custom_profession"); + creatures.profession_offset = OG_creature->getOffset ("profession"); + creatures.race_offset = OG_creature->getOffset ("race"); + creatures.pos_offset = OG_creature->getOffset ("position"); + creatures.flags1_offset = OG_creature->getOffset ("flags1"); + creatures.flags2_offset = OG_creature->getOffset ("flags2"); + creatures.sex_offset = OG_creature->getOffset ("sex"); + creatures.caste_offset = OG_creature->getOffset ("caste"); + creatures.id_offset = OG_creature->getOffset ("id"); + creatures.civ_offset = OG_creature->getOffset ("civ"); + // name struct + creatures.name_firstname_offset = OG_name->getOffset("first"); + creatures.name_nickname_offset = OG_name->getOffset("nick"); + creatures.name_words_offset = OG_name->getOffset("second_words"); + d->Ft_basic = true; + try { - // supply the module with offsets so it can work with them - memcpy(SHMDATA(Creatures2010::creature_offsets),&creatures,sizeof(Creatures2010::creature_offsets)); - const uint32_t cmd = Creatures2010::CREATURE_INIT + (d->creature_module << 16); - p->SetAndWait(cmd); + creatures.inventory_offset = OG_creature_ex->getOffset("inventory_vector"); + creatures.pickup_equipment_bit = OG_creature_ex->getOffset("pickup_equipment_bit"); + creatures.mood_offset = OG_creature_ex->getOffset("mood"); + // pregnancy + // pregnancy_ptr + creatures.birth_year_offset = OG_creature_ex->getOffset("birth_year"); + creatures.birth_time_offset = OG_creature_ex->getOffset("birth_time"); + creatures.current_job_offset = OG_creature_ex->getOffset("current_job"); + creatures.mood_skill_offset = OG_creature_ex->getOffset("current_job_skill"); + creatures.physical_offset = OG_creature_ex->getOffset("physical"); + creatures.appearance_vector_offset = OG_creature_ex->getOffset("appearance_vector"); + creatures.artifact_name_offset = OG_creature_ex->getOffset("artifact_name"); + creatures.labors_offset = OG_creature_ex->getOffset ("labors"); + creatures.happiness_offset = OG_creature_ex->getOffset ("happiness"); + d->Ft_advanced = true; } - */ - d->Inited = true; - } - catch (Error::MissingMemoryDefinition&) - { - d->Inited = false; - throw; + catch(Error::All&){}; + try + { + creatures.soul_vector_offset = OG_creature_ex->getOffset("soul_vector"); + creatures.default_soul_offset = OG_creature_ex->getOffset("current_soul"); + creatures.soul_mental_offset = OG_soul->getOffset("mental"); + creatures.soul_skills_vector_offset = OG_soul->getOffset("skills_vector"); + creatures.soul_traits_offset = OG_soul->getOffset("traits"); + d->Ft_soul = true; + } + catch(Error::All&){}; } + catch(Error::All&){}; + d->Inited = true; } Creatures::~Creatures() @@ -158,6 +169,7 @@ bool Creatures::Finish() bool Creatures::ReadCreature (const int32_t index, t_creature & furball) { if(!d->Started) return false; + memset(&furball, 0, sizeof(t_creature)); // SHM fast path Process * p = d->owner; /* @@ -171,7 +183,7 @@ bool Creatures::ReadCreature (const int32_t index, t_creature & furball) } */ // non-SHM slow path - memory_info * minfo = d->d->offset_descriptor; + VersionInfo * minfo = d->d->offset_descriptor; // read pointer from vector at position uint32_t temp = d->p_cre->at (index); @@ -179,129 +191,120 @@ bool Creatures::ReadCreature (const int32_t index, t_creature & furball) 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); - p->read (temp + offs.pos_offset, 3 * sizeof (uint16_t), (uint8_t *) & (furball.x)); // xyz really - p->readDWord (temp + offs.race_offset, furball.race); - furball.civ = p->readDWord (temp + offs.civ_offset); - p->readByte (temp + offs.sex_offset, furball.sex); - 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) * 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); - - // 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); - - furball.current_job.occupationPtr = p->readDWord (temp + offs.current_job_offset); - if(furball.current_job.occupationPtr) + if(d->Ft_basic) { - furball.current_job.active = true; - furball.current_job.jobType = p->readByte (furball.current_job.occupationPtr + minfo->getOffset("job_type") ); - furball.current_job.jobId = p->readDWord (furball.current_job.occupationPtr + minfo->getOffset("job_id") ); + // name + d->d->readName(furball.name,temp + offs.name_offset); + + // basic stuff + p->readDWord (temp + offs.id_offset, furball.id); + p->read (temp + offs.pos_offset, 3 * sizeof (uint16_t), (uint8_t *) & (furball.x)); // xyz really + p->readDWord (temp + offs.race_offset, furball.race); + furball.civ = p->readDWord (temp + offs.civ_offset); + p->readByte (temp + offs.sex_offset, furball.sex); + 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); + // custom profession + p->readSTLString(temp + offs.custom_profession_offset, furball.custom_profession, sizeof(furball.custom_profession)); + // profession + furball.profession = p->readByte (temp + offs.profession_offset); } - else + if(d->Ft_advanced) { - furball.current_job.active = false;; - } - - furball.birth_year = p->readDWord (temp + offs.birth_year_offset ); - furball.birth_time = p->readDWord (temp + offs.birth_time_offset ); + // happiness + p->readDWord (temp + offs.happiness_offset, furball.happiness); + + // physical attributes + 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); + + // labors + p->read (temp + offs.labors_offset, NUM_CREATURE_LABORS, furball.labors); + furball.birth_year = p->readDWord (temp + offs.birth_year_offset ); + furball.birth_time = p->readDWord (temp + offs.birth_time_offset ); + /* + * p->readDWord(temp + offs.creature_pregnancy_offset, furball.pregnancy_timer); + */ - // current job HACK: the job object isn't cleanly represented here - /* - uint32_t jobIdAddr = p->readDWord (temp + offs.creature_current_job_offset); + // appearance + DfVector app(p, temp + offs.appearance_vector_offset); + furball.nbcolors = app.size(); + if(furball.nbcolors>MAX_COLORS) + furball.nbcolors = MAX_COLORS; + for(uint32_t i = 0; i < furball.nbcolors; i++) + { + furball.color[i] = app[i]; + } - if (jobIdAddr) - { - furball.current_job.active = true; - furball.current_job.jobId = p->readByte (jobIdAddr + offs.creature_current_job_id_offset); + //likes + /* + DfVector likes(d->p, temp + offs.creature_likes_offset); + furball.numLikes = likes.getSize(); + for(uint32_t i = 0;iread(temp2,sizeof(t_like),(uint8_t *) &furball.likes[i]); + }*/ } - else + if(d->Ft_soul) { - furball.current_job.active = false; - } - */ + /* + // enum soul pointer vector + DfVector souls(p,temp + offs.creature_soul_vector_offset); + */ + uint32_t soul = p->readDWord(temp + offs.default_soul_offset); + furball.has_default_soul = false; - /* - p->readDWord(temp + offs.creature_pregnancy_offset, furball.pregnancy_timer); - */ + 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(); - /* - // enum soul pointer vector - DfVector souls(p,temp + offs.creature_soul_vector_offset); - */ - uint32_t soul = p->readDWord(temp + offs.default_soul_offset); - furball.has_default_soul = false; + 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 + offsetof(t_skill, rating)); + furball.defaultSoul.skills[i].experience = + p->readWord (temp2 + offsetof(t_skill, experience)); + } - 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(); + // mental attributes are part of the soul + p->read(soul + offs.soul_mental_offset, + sizeof(t_attrib) * NUM_CREATURE_MENTAL_ATTRIBUTES, + (uint8_t *)&furball.defaultSoul.analytical_ability); - 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 + offsetof(t_skill, rating)); - furball.defaultSoul.skills[i].experience = - p->readWord (temp2 + offsetof(t_skill, experience)); + // traits as well + p->read(soul + offs.soul_traits_offset, + sizeof (uint16_t) * NUM_CREATURE_TRAITS, + (uint8_t *) &furball.defaultSoul.traits); } - - // mental attributes are part of the soul - 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); } - - DfVector app(p, temp + offs.appearance_vector_offset); - furball.nbcolors = app.size(); - if(furball.nbcolors>MAX_COLORS) - furball.nbcolors = MAX_COLORS; - for(uint32_t i = 0; i < furball.nbcolors; i++) + if(d->Ft_jobs) { - furball.color[i] = app[i]; + furball.current_job.occupationPtr = p->readDWord (temp + offs.current_job_offset); + if(furball.current_job.occupationPtr) + { + furball.current_job.active = true; + furball.current_job.jobType = p->readByte (furball.current_job.occupationPtr + d->OG_jobs->getOffset("type") ); + furball.current_job.jobId = p->readDWord (furball.current_job.occupationPtr + d->OG_jobs->getOffset("id") ); + } + else + { + furball.current_job.active = false;; + } } - //likes - /* - DfVector likes(d->p, temp + offs.creature_likes_offset); - furball.numLikes = likes.getSize(); - for(uint32_t i = 0;iread(temp2,sizeof(t_like),(uint8_t *) &furball.likes[i]); - }*/ - return true; } @@ -521,21 +524,19 @@ bool Creatures::WriteMoodSkill(const uint32_t index, const uint16_t moodSkill) bool Creatures::WriteJob(const t_creature * furball, std::vector const& mat) { - unsigned int i; + 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")); + DfVector cmats(p, furball->current_job.occupationPtr + d->OG_jobs->getOffset("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); + p->writeWord(cmats[i] + d->OG_job_mats->getOffset("maintype"), mat[i].itemType); + p->writeWord(cmats[i] + d->OG_job_mats->getOffset("sectype1"), mat[i].subType); + p->writeWord(cmats[i] + d->OG_job_mats->getOffset("sectype2"), mat[i].subIndex); + p->writeDWord(cmats[i] + d->OG_job_mats->getOffset("sectype3"), mat[i].index); + p->writeDWord(cmats[i] + d->OG_job_mats->getOffset("flags"), mat[i].flags); } return true; } @@ -595,17 +596,40 @@ bool Creatures::ReadJob(const t_creature * furball, vector & mat) if(!d->Inited) return false; if(!furball->current_job.active) return false; Process * p = d->owner; - memory_info * minfo = d->d->offset_descriptor; + VersionInfo * minfo = d->d->offset_descriptor; - DfVector cmats(p, furball->current_job.occupationPtr + minfo->getOffset("job_materials_vector")); + DfVector cmats(p, furball->current_job.occupationPtr + d->OG_jobs->getOffset("materials_vector")); mat.resize(cmats.size()); for(i=0;ireadWord(cmats[i] + minfo->getOffset("job_material_maintype")); - mat[i].subType = p->readWord(cmats[i] + minfo->getOffset("job_material_sectype1")); - mat[i].subIndex = p->readWord(cmats[i] + minfo->getOffset("job_material_sectype2")); - mat[i].index = p->readDWord(cmats[i] + minfo->getOffset("job_material_sectype3")); - mat[i].flags = p->readDWord(cmats[i] + minfo->getOffset("job_material_flags")); + mat[i].itemType = p->readWord(cmats[i] + d->OG_job_mats->getOffset("maintype")); + mat[i].subType = p->readWord(cmats[i] + d->OG_job_mats->getOffset("sectype1")); + mat[i].subIndex = p->readWord(cmats[i] + d->OG_job_mats->getOffset("sectype2")); + mat[i].index = p->readDWord(cmats[i] + d->OG_job_mats->getOffset("sectype3")); + mat[i].flags = p->readDWord(cmats[i] + d->OG_job_mats->getOffset("flags")); } return true; } + +bool Creatures::ReadInventoryIdx(const uint32_t index, std::vector & item) +{ + if(!d->Started) return false; + Process * p = d->owner; + uint32_t temp = d->p_cre->at (index); + return this->ReadInventoryPtr(temp, item); +} + +bool Creatures::ReadInventoryPtr(const uint32_t temp, std::vector & item) +{ + unsigned int i; + if(!d->Started) return false; + Process * p = d->owner; + + DfVector citem(p, temp + d->creatures.inventory_offset); + if(citem.size() == 0) + return false; + item.resize(citem.size()); + for(i=0;ireadDWord(citem[i]); + return true; +} diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index f017a04f3..177a00467 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -26,36 +26,54 @@ distribution. #include "ContextShared.h" #include "dfhack/modules/Gui.h" #include "dfhack/DFProcess.h" -#include "dfhack/DFMemInfo.h" +#include "dfhack/VersionInfo.h" #include "dfhack/DFTypes.h" using namespace DFHack; struct Gui::Private { - bool Inited; + Private() + { + Started = PauseInited = ViewScreeInited = MenuStateInited = false; + } bool Started; uint32_t pause_state_offset; + bool PauseInited; uint32_t view_screen_offset; - uint32_t current_cursor_creature_offset; + bool ViewScreeInited; uint32_t current_menu_state_offset; + bool MenuStateInited; DFContextShared *d; Process * owner; }; Gui::Gui(DFContextShared * _d) { - + d = new Private; d->d = _d; d->owner = _d->p; - d->Inited = d->Started = true; - - memory_info * mem = d->d->offset_descriptor; - d->current_menu_state_offset = mem->getAddress("current_menu_state"); - d->pause_state_offset = mem->getAddress ("pause_state"); - d->view_screen_offset = mem->getAddress ("view_screen"); - d->Inited = d->Started = true; + OffsetGroup * OG_Gui = d->d->offset_descriptor->getGroup("GUI"); + try + { + d->current_menu_state_offset = OG_Gui->getAddress("current_menu_state"); + d->MenuStateInited = true; + } + catch(exception &){}; + try + { + d->pause_state_offset = OG_Gui->getAddress ("pause_state"); + d->PauseInited = true; + } + catch(exception &){}; + try + { + d->view_screen_offset = OG_Gui->getAddress ("view_screen"); + d->ViewScreeInited = true; + } + catch(exception &){}; + d->Started = true; } Gui::~Gui() @@ -75,25 +93,31 @@ bool Gui::Finish() bool Gui::ReadPauseState() { - // replace with an exception - if(!d->Inited) return false; + if(!d->PauseInited) return false; uint32_t pauseState = d->owner->readDWord (d->pause_state_offset); return pauseState & 1; } +void Gui::SetPauseState(bool paused) +{ + if(!d->PauseInited) return; + cout << "pause set" << endl; + d->owner->writeDWord (d->pause_state_offset, paused); +} + uint32_t Gui::ReadMenuState() { - if(d->Inited) + if(d->MenuStateInited) return(d->owner->readDWord(d->current_menu_state_offset)); return false; } bool Gui::ReadViewScreen (t_viewscreen &screen) { - if (!d->Inited) return false; + if (!d->ViewScreeInited) return false; Process * p = d->owner; - + uint32_t last = p->readDWord (d->view_screen_offset); uint32_t screenAddr = p->readDWord (last); uint32_t nextScreenPtr = p->readDWord (last + 4); diff --git a/library/modules/Gui_C.cpp b/library/modules/Gui_C.cpp index da17d2a18..8870b4e87 100644 --- a/library/modules/Gui_C.cpp +++ b/library/modules/Gui_C.cpp @@ -60,8 +60,6 @@ int Gui_ReadPauseState(DFHackObject* gui) int Gui_ReadViewScreen(DFHackObject* gui, t_viewscreen* viewscreen) { - //int result; - if(gui != NULL) { return ((DFHack::Gui*)gui)->ReadViewScreen(*viewscreen); @@ -70,6 +68,18 @@ int Gui_ReadViewScreen(DFHackObject* gui, t_viewscreen* viewscreen) return -1; } +int Gui_ReadMenuState(DFHackObject* gui, uint32_t* menuState) +{ + if(gui != NULL) + { + *menuState = ((DFHack::Gui*)gui)->ReadMenuState(); + + return 1; + } + + return -1; +} + #ifdef __cplusplus } #endif diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp index 2419bbf40..6ae558dcd 100644 --- a/library/modules/Items.cpp +++ b/library/modules/Items.cpp @@ -25,7 +25,7 @@ distribution. #include "Internal.h" #include "ContextShared.h" #include "dfhack/DFTypes.h" -#include "dfhack/DFMemInfo.h" +#include "dfhack/VersionInfo.h" #include "dfhack/DFProcess.h" #include "dfhack/DFVector.h" #include "dfhack/modules/Materials.h" @@ -189,11 +189,12 @@ int32_t Accessor::getValue(uint32_t objectPtr) 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"); + OffsetGroup * Items = p->getDescriptor()->getGroup("Items"); + uint32_t funcOffsetA = Items->getOffset("item_type_accessor"); + uint32_t funcOffsetB = Items->getOffset("item_subtype_accessor"); + uint32_t funcOffsetC = Items->getOffset("item_subindex_accessor"); + uint32_t funcOffsetD = Items->getOffset("item_index_accessor"); + uint32_t funcOffsetQuality = Items->getOffset("item_quality_accessor"); this->vtable = VTable; this->p = p; this->className = p->readClassName(VTable).substr(5); diff --git a/library/modules/Maps.cpp b/library/modules/Maps.cpp index 0cf3588a1..124e9bea9 100644 --- a/library/modules/Maps.cpp +++ b/library/modules/Maps.cpp @@ -29,7 +29,7 @@ distribution. #include "ContextShared.h" #include "dfhack/modules/Maps.h" #include "dfhack/DFError.h" -#include "dfhack/DFMemInfo.h" +#include "dfhack/VersionInfo.h" #include "dfhack/DFProcess.h" #include "dfhack/DFVector.h" @@ -52,6 +52,9 @@ struct Maps::Private DFContextShared *d; Process * owner; + OffsetGroup *OG_local_features; + OffsetGroup *OG_global_features; + OffsetGroup *OG_vector; bool Inited; bool Started; @@ -67,40 +70,52 @@ Maps::Maps(DFContextShared* _d) d->d = _d; Process *p = d->owner = _d->p; d->Inited = d->Started = false; + d->block = NULL; - DFHack::memory_info * mem = p->getDescriptor(); + DFHack::VersionInfo * 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"); - off.y_count_offset = mem->getAddress ("y_count_block"); - off.z_count_offset = mem->getAddress ("z_count_block"); - off.tile_type_offset = mem->getOffset ("map_data_type"); - off.designation_offset = mem->getOffset ("map_data_designation"); - off.occupancy_offset = mem->getOffset("map_data_occupancy"); - off.biome_stuffs = mem->getOffset ("map_data_biome_stuffs"); - 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 + OffsetGroup *OG_Maps = mem->getGroup("Maps"); + { + off.map_offset = OG_Maps->getAddress ("map_data"); + off.x_count_offset = OG_Maps->getAddress ("x_count_block"); + off.y_count_offset = OG_Maps->getAddress ("y_count_block"); + off.z_count_offset = OG_Maps->getAddress ("z_count_block"); + off.region_x_offset = OG_Maps->getAddress ("region_x"); + off.region_y_offset = OG_Maps->getAddress ("region_y"); + off.region_z_offset = OG_Maps->getAddress ("region_z"); + off.world_size_x = OG_Maps->getAddress ("world_size_x"); + off.world_size_y = OG_Maps->getAddress ("world_size_y"); + + OffsetGroup *OG_MapBlock = OG_Maps->getGroup("block"); + { + off.tile_type_offset = OG_MapBlock->getOffset ("type"); + off.designation_offset = OG_MapBlock->getOffset ("designation"); + off.occupancy_offset = OG_MapBlock->getOffset("occupancy"); + off.biome_stuffs = OG_MapBlock->getOffset ("biome_stuffs"); + off.veinvector = OG_MapBlock->getOffset ("vein_vector"); + off.local_feature_offset = OG_MapBlock->getOffset ("feature_local"); + off.global_feature_offset = OG_MapBlock->getOffset ("feature_global"); + off.temperature1_offset = OG_MapBlock->getOffset ("temperature1"); + off.temperature2_offset = OG_MapBlock->getOffset ("temperature2"); + } + + OffsetGroup *OG_Geology = OG_Maps->getGroup("geology"); + { + off.world_regions = OG_Geology->getAddress ("ptr2_region_array"); + off.region_size = OG_Geology->getHexValue ("region_size"); + off.region_geo_index_offset = OG_Geology->getOffset ("region_geo_index_off"); + off.geolayer_geoblock_offset = OG_Geology->getOffset ("geolayer_geoblock_offset"); + off.world_geoblocks_vector = OG_Geology->getAddress ("geoblock_vector"); + off.type_inside_geolayer = OG_Geology->getOffset ("type_inside_geolayer"); + } + d->OG_global_features = OG_Maps->getGroup("features")->getGroup("global"); + d->OG_local_features = OG_Maps->getGroup("features")->getGroup("local"); + } + d->OG_vector = mem->getGroup("vector"); + + // these can (will) fail and will be found when looking at the actual veins later // basically a cache off.vein_ice_vptr = 0; mem->resolveClassnameToVPtr("block_square_event_frozen_liquid", off.vein_ice_vptr); @@ -446,7 +461,7 @@ bool Maps::WriteTemperatures (uint32_t x, uint32_t y, uint32_t z, t_temperatures /* * Region Offsets - used for layer geology - */ + */ bool Maps::ReadRegionOffsets (uint32_t x, uint32_t y, uint32_t z, biome_indices40d *buffer) { MAPS_GUARD @@ -501,7 +516,7 @@ bool Maps::WriteGlobalFeature(uint32_t x, uint32_t y, uint32_t z, int16_t global /* * Block events - */ + */ bool Maps::ReadVeins(uint32_t x, uint32_t y, uint32_t z, vector * veins, vector * ices, vector *splatter) { MAPS_GUARD @@ -509,12 +524,12 @@ bool Maps::ReadVeins(uint32_t x, uint32_t y, uint32_t z, vector * veins, t_frozenliquidvein fv; t_spattervein sv; Process* p = d->owner; - + uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if(veins) veins->clear(); if(ices) ices->clear(); if(splatter) splatter->clear(); - + Server::Maps::maps_offsets &off = d->offsets; if (addr) { @@ -646,7 +661,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; + VersionInfo * minfo = d->d->offset_descriptor; Process *p = d->owner; // get needed addresses and offsets. Now this is what I call crazy. uint16_t worldSizeX, worldSizeY; @@ -721,16 +736,16 @@ bool Maps::ReadLocalFeatures( std::map > & return false; Process * p = d->owner; - memory_info * mem = p->getDescriptor(); + VersionInfo * mem = p->getDescriptor(); // deref pointer to the humongo-structure - uint32_t base = p->readDWord(mem->getAddress("local_feature_start_ptr")); + uint32_t base = p->readDWord(d->OG_local_features->getAddress("start_ptr")); if(!base) return false; - uint32_t sizeof_vec = mem->getHexValue("sizeof_vector"); + const uint32_t sizeof_vec = d->OG_vector->getHexValue("sizeof"); const uint32_t sizeof_elem = 16; 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 + const uint32_t main_mat_offset = d->OG_local_features->getOffset("material"); // 0x30 + const uint32_t sub_mat_offset = d->OG_local_features->getOffset("submaterial"); // 0x34 local_features.clear(); @@ -746,7 +761,7 @@ bool Maps::ReadLocalFeatures( std::map > & 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); + uint32_t wtf = p->readDWord(array_elem + ( sizeof_elem * ( (uint32_t)region_y_local/16)) + offset_elem); if(wtf) { // wtf + sizeof(vector) * crap; @@ -814,12 +829,11 @@ bool Maps::ReadGlobalFeatures( std::vector & features) 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 + const uint32_t global_feature_vector = d->OG_global_features->getAddress("vector"); + const uint32_t global_feature_funcptr = d->OG_global_features->getOffset("funcptr"); + const uint32_t main_mat_offset = d->OG_global_features->getOffset("material"); // 0x34 + const uint32_t sub_mat_offset = d->OG_global_features->getOffset("submaterial"); // 0x38 DfVector p_features (p,global_feature_vector); features.clear(); diff --git a/library/modules/Maps_C.cpp b/library/modules/Maps_C.cpp index 09a7dc065..911f4e0f9 100644 --- a/library/modules/Maps_C.cpp +++ b/library/modules/Maps_C.cpp @@ -54,6 +54,37 @@ int Maps_Finish(DFHackObject* maps) return -1; } +t_feature* Maps_ReadGlobalFeatures(DFHackObject* maps) +{ + if(maps != NULL) + { + std::vector featureVec; + + if(((DFHack::Maps*)maps)->ReadGlobalFeatures(featureVec)) + { + if(featureVec.size() <= 0) + return NULL; + + t_feature* buf; + + (*alloc_t_feature_buffer_callback)(buf, featureVec.size()); + + if(buf != NULL) + { + copy(featureVec.begin(), featureVec.end(), buf); + + return buf; + } + else + return NULL; + } + else + return NULL; + } + + return NULL; +} + void Maps_getSize(DFHackObject* maps, uint32_t* x, uint32_t* y, uint32_t* z) { if(maps != NULL) diff --git a/library/modules/Materials.cpp b/library/modules/Materials.cpp index fe8e3f339..2ad78361e 100644 --- a/library/modules/Materials.cpp +++ b/library/modules/Materials.cpp @@ -26,9 +26,10 @@ distribution. #include "ContextShared.h" #include "dfhack/DFTypes.h" #include "dfhack/modules/Materials.h" -#include "dfhack/DFMemInfo.h" +#include "dfhack/VersionInfo.h" #include "dfhack/DFProcess.h" #include "dfhack/DFVector.h" +#include using namespace DFHack; @@ -37,6 +38,13 @@ class Materials::Private public: DFContextShared *d; Process * owner; + OffsetGroup * OG_Materials; + uint32_t vector_inorganic; + uint32_t vector_organic_all; + uint32_t vector_organic_plants; + uint32_t vector_organic_trees; + uint32_t vector_races; + uint32_t vector_other; /* bool Inited; bool Started; @@ -48,6 +56,14 @@ Materials::Materials(DFContextShared * d_) d = new Private; d->d = d_; d->owner = d_->p; + OffsetGroup *OG_Materials = d->OG_Materials = d->owner->getDescriptor()->getGroup("Materials"); + { + d->vector_inorganic = OG_Materials->getAddress("inorganics"); + d->vector_organic_all = OG_Materials->getAddress ("organics_all"); + d->vector_organic_plants = OG_Materials->getAddress ("organics_plants"); + d->vector_organic_trees = OG_Materials->getAddress ("organics_trees"); + d->vector_races = OG_Materials->getAddress("creature_type_vector"); + } } Materials::~Materials() { @@ -56,6 +72,7 @@ Materials::~Materials() bool Materials::Finish() { + /* inorganic.clear(); organic.clear(); tree.clear(); @@ -65,6 +82,7 @@ bool Materials::Finish() color.clear(); other.clear(); alldesc.clear(); + */ return true; } @@ -183,12 +201,12 @@ bool API::ReadInorganicMaterials (vector & inorganic) //cout << temp << endl; //fill_char_buf(mat.id, d->p->readSTLString(temp)); // reads a C string given an address p->readSTLString (temp, mat.id, 128); - + p->readSTLString (temp+matgloss_stone_name_offset, mat.name, 128); mat.fore = (uint8_t) p->readWord (temp + matgloss_colors); mat.back = (uint8_t) p->readWord (temp + matgloss_colors + 2); mat.bright = (uint8_t) p->readWord (temp + matgloss_colors + 4); - + inorganic.push_back (mat); } return true; @@ -216,14 +234,14 @@ inline bool ReadNamesOnly(Process* p, uint32_t address, vector & nam bool Materials::ReadInorganicMaterials (void) { Process * p = d->owner; - DfVector p_matgloss (p, d->owner->getDescriptor()->getAddress ("mat_inorganics")); + DfVector p_matgloss (p, d->vector_inorganic); uint32_t size = p_matgloss.size(); inorganic.clear(); inorganic.reserve (size); for (uint32_t i = 0; i < size;i++) { t_matgloss mat; - + p->readSTLString (p_matgloss[i], mat.id, 128); //p->readSTLString (p_matgloss[i] + mat_name, mat.name, 128); mat.name[0] = 0; @@ -237,29 +255,29 @@ bool Materials::ReadInorganicMaterials (void) bool Materials::ReadOrganicMaterials (void) { - return ReadNamesOnly(d->owner, d->owner->getDescriptor()->getAddress ("mat_organics_all"), organic ); + return ReadNamesOnly(d->owner, d->vector_organic_all, organic ); } bool Materials::ReadWoodMaterials (void) { - return ReadNamesOnly(d->owner, d->owner->getDescriptor()->getAddress ("mat_organics_trees"), tree ); + return ReadNamesOnly(d->owner, d->vector_organic_trees, tree ); } bool Materials::ReadPlantMaterials (void) { - return ReadNamesOnly(d->owner, d->owner->getDescriptor()->getAddress ("mat_organics_plants"), plant ); + return ReadNamesOnly(d->owner, d->vector_organic_plants, plant ); } bool Materials::ReadCreatureTypes (void) { - return ReadNamesOnly(d->owner, d->owner->getDescriptor()->getAddress ("creature_type_vector"), race ); + return ReadNamesOnly(d->owner, d->vector_races, race ); return true; } bool Materials::ReadOthers(void) { Process * p = d->owner; - uint32_t matBase = p->getDescriptor()->getAddress ("mat_other"); + uint32_t matBase = d->OG_Materials->getAddress ("other"); uint32_t i = 0; uint32_t ptr; @@ -281,7 +299,8 @@ bool Materials::ReadOthers(void) bool Materials::ReadDescriptorColors (void) { Process * p = d->owner; - DfVector p_colors (p, p->getDescriptor()->getAddress ("descriptor_colors_vector")); + OffsetGroup * OG_Descriptors = p->getDescriptor()->getGroup("Materials")->getGroup("descriptors"); + DfVector p_colors (p, OG_Descriptors->getAddress ("colors_vector")); uint32_t size = p_colors.size(); color.clear(); @@ -291,43 +310,70 @@ bool Materials::ReadDescriptorColors (void) for (uint32_t i = 0; i < size;i++) { t_descriptor_color col; - p->readSTLString (p_colors[i] + p->getDescriptor()->getOffset ("descriptor_rawname"), col.id, 128); - p->readSTLString (p_colors[i] + p->getDescriptor()->getOffset ("descriptor_name"), col.name, 128); - col.r = p->readFloat( p_colors[i] + p->getDescriptor()->getOffset ("descriptor_color_r") ); - col.v = p->readFloat( p_colors[i] + p->getDescriptor()->getOffset ("descriptor_color_v") ); - col.b = p->readFloat( p_colors[i] + p->getDescriptor()->getOffset ("descriptor_color_b") ); + p->readSTLString (p_colors[i] + OG_Descriptors->getOffset ("rawname"), col.id, 128); + p->readSTLString (p_colors[i] + OG_Descriptors->getOffset ("name"), col.name, 128); + col.r = p->readFloat( p_colors[i] + OG_Descriptors->getOffset ("color_r") ); + col.v = p->readFloat( p_colors[i] + OG_Descriptors->getOffset ("color_v") ); + col.b = p->readFloat( p_colors[i] + OG_Descriptors->getOffset ("color_b") ); color.push_back(col); } - return ReadNamesOnly(d->owner, d->owner->getDescriptor()->getAddress ("descriptor_all_colors"), alldesc ); + return ReadNamesOnly(d->owner, OG_Descriptors->getAddress ("all_colors_vector"), alldesc ); return true; } bool Materials::ReadCreatureTypesEx (void) { Process *p = d->owner; - memory_info *mem = d->owner->getDescriptor(); - DfVector p_races (p, mem->getAddress ("creature_type_vector")); - uint32_t castes_vector_offset = mem->getOffset ("creature_type_caste_vector"); - uint32_t extract_vector_offset = mem->getOffset ("creature_type_extract_vector"); - uint32_t sizeof_string = mem->getHexValue ("sizeof_string"); - uint32_t caste_colormod_offset = mem->getOffset ("caste_color_modifiers"); - uint32_t caste_bodypart_offset = mem->getOffset ("caste_bodypart_vector"); - uint32_t caste_attributes_offset = mem->getOffset ("caste_attributes"); - 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"); // 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"); + VersionInfo *mem = p->getDescriptor(); + OffsetGroup * OG_string = mem->getGroup("string"); + uint32_t sizeof_string = OG_string->getHexValue ("sizeof"); + + OffsetGroup * OG_Mats = mem->getGroup("Materials"); + DfVector p_races (p, OG_Mats->getAddress ("creature_type_vector")); + + OffsetGroup * OG_Creature = OG_Mats->getGroup("creature"); + uint32_t castes_vector_offset = OG_Creature->getOffset ("caste_vector"); + uint32_t extract_vector_offset = OG_Creature->getOffset ("extract_vector"); + uint32_t tile_offset = OG_Creature->getOffset ("tile"); + uint32_t tile_color_offset = OG_Creature->getOffset ("tile_color"); + + bool have_advanced = false; + uint32_t caste_colormod_offset; + uint32_t caste_attributes_offset; + uint32_t caste_bodypart_offset; + uint32_t bodypart_id_offset; + uint32_t bodypart_category_offset; + uint32_t bodypart_layers_offset; + uint32_t bodypart_singular_offset; + uint32_t bodypart_plural_offset; + uint32_t color_modifier_part_offset; + uint32_t color_modifier_startdate_offset; + uint32_t color_modifier_enddate_offset; + try + { + OffsetGroup * OG_Caste = OG_Creature->getGroup("caste"); + caste_colormod_offset = OG_Caste->getOffset ("color_modifiers"); + caste_attributes_offset = OG_Caste->getOffset ("attributes"); + caste_bodypart_offset = OG_Caste->getOffset ("bodypart_vector"); + OffsetGroup * OG_CasteBodyparts = OG_Creature->getGroup("caste_bodyparts"); + bodypart_id_offset = OG_CasteBodyparts->getOffset ("id"); + bodypart_category_offset = OG_CasteBodyparts->getOffset ("category"); + bodypart_layers_offset = OG_CasteBodyparts->getOffset ("layers_vector"); // unused + bodypart_singular_offset = OG_CasteBodyparts->getOffset ("singular_vector"); // unused + bodypart_plural_offset = OG_CasteBodyparts->getOffset ("plural_vector"); // unused + OffsetGroup * OG_CasteColorMods = OG_Creature->getGroup("caste_color_mods"); + color_modifier_part_offset = OG_CasteColorMods->getOffset ("part"); + color_modifier_startdate_offset = OG_CasteColorMods->getOffset ("startdate"); + color_modifier_enddate_offset = OG_CasteColorMods->getOffset ("enddate"); + have_advanced = true; + } + catch (Error::All &){}; + uint32_t size = p_races.size(); uint32_t sizecas = 0; uint32_t sizecolormod; uint32_t sizecolorlist; uint32_t sizebp; - uint32_t tile_offset = mem->getOffset ("creature_tile"); - uint32_t tile_color_offset = mem->getOffset ("creature_tile_color"); raceEx.clear(); raceEx.reserve (size); for (uint32_t i = 0; i < size;i++) @@ -338,13 +384,13 @@ bool Materials::ReadCreatureTypesEx (void) // 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 + // 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++) @@ -356,38 +402,36 @@ bool Materials::ReadCreatureTypesEx (void) p->readSTLString (caste_start + sizeof_string, caste.singular, sizeof(caste.singular)); p->readSTLString (caste_start + 2 * sizeof_string, caste.plural, sizeof(caste.plural)); p->readSTLString (caste_start + 3 * sizeof_string, caste.adjective, sizeof(caste.adjective)); - - /* color mod reading */ - DfVector p_colormod(p, caste_start + caste_colormod_offset); - sizecolormod = p_colormod.size(); - caste.ColorModifier.resize(sizecolormod); - for(uint32_t k = 0; k < sizecolormod;k++) - { - DfVector p_colorlist(p, p_colormod[k]); - sizecolorlist = p_colorlist.size(); - caste.ColorModifier[k].colorlist.resize(sizecolorlist); - for(uint32_t l = 0; l < sizecolorlist; l++) - caste.ColorModifier[k].colorlist[l] = p_colorlist[l]; - p->readSTLString( p_colormod[k] + color_modifier_part_offset, caste.ColorModifier[k].part, sizeof(caste.ColorModifier[k].part)); - caste.ColorModifier[k].startdate = p->readDWord( p_colormod[k] + color_modifier_startdate_offset ); - caste.ColorModifier[k].enddate = p->readDWord( p_colormod[k] + color_modifier_enddate_offset ); - } - - /* body parts */ - DfVector p_bodypart(p, caste_start + caste_bodypart_offset); - caste.bodypart.empty(); - sizebp = p_bodypart.size(); - for(uint32_t k = 0; k < sizebp; k++) + if(have_advanced) { - t_bodypart part; - p->readSTLString (p_bodypart[k] + bodypart_id_offset, part.id, sizeof(part.id)); - p->readSTLString (p_bodypart[k] + bodypart_category_offset, part.category, sizeof(part.category)); - caste.bodypart.push_back(part); + /* color mod reading */ + DfVector p_colormod(p, caste_start + caste_colormod_offset); + sizecolormod = p_colormod.size(); + caste.ColorModifier.resize(sizecolormod); + for(uint32_t k = 0; k < sizecolormod;k++) + { + DfVector p_colorlist(p, p_colormod[k]); + sizecolorlist = p_colorlist.size(); + caste.ColorModifier[k].colorlist.resize(sizecolorlist); + for(uint32_t l = 0; l < sizecolorlist; l++) + caste.ColorModifier[k].colorlist[l] = p_colorlist[l]; + p->readSTLString( p_colormod[k] + color_modifier_part_offset, caste.ColorModifier[k].part, sizeof(caste.ColorModifier[k].part)); + caste.ColorModifier[k].startdate = p->readDWord( p_colormod[k] + color_modifier_startdate_offset ); + caste.ColorModifier[k].enddate = p->readDWord( p_colormod[k] + color_modifier_enddate_offset ); + } + /* body parts */ + DfVector p_bodypart(p, caste_start + caste_bodypart_offset); + caste.bodypart.empty(); + sizebp = p_bodypart.size(); + for(uint32_t k = 0; k < sizebp; k++) + { + t_bodypart part; + p->readSTLString (p_bodypart[k] + bodypart_id_offset, part.id, sizeof(part.id)); + p->readSTLString (p_bodypart[k] + bodypart_category_offset, part.category, sizeof(part.category)); + caste.bodypart.push_back(part); + } + p->read(caste_start + caste_attributes_offset, sizeof(t_attrib) * (6+11), (uint8_t *)&caste.strength); } - - - p->read(caste_start + caste_attributes_offset, sizeof(t_attrib) * (6+11), (uint8_t *)&caste.strength); - mat.castes.push_back(caste); } DfVector p_extract(p, p_races[i] + extract_vector_offset); @@ -411,7 +455,7 @@ void Materials::ReadAllMaterials(void) this->ReadCreatureTypes(); this->ReadCreatureTypesEx(); this->ReadDescriptorColors(); - this->ReadOthers(); + //this->ReadOthers(); } std::string Materials::getDescription(t_material & mat) @@ -504,7 +548,7 @@ std::string Materials::getType(t_material & mat) } } } - else + else return "inorganic"; } else diff --git a/library/modules/Materials_C.cpp b/library/modules/Materials_C.cpp index f95c4e76c..4fa8b7705 100644 --- a/library/modules/Materials_C.cpp +++ b/library/modules/Materials_C.cpp @@ -116,6 +116,18 @@ void Materials_ReadAllMaterials(DFHackObject* mat) } } +const char* Materials_getType(DFHackObject* mat, t_material* material) +{ + if(mat != NULL) + { + std::string type = ((DFHack::Materials*)mat)->getType(*material); + + return type.c_str(); + } + + return "\0"; +} + const char* Materials_getDescription(DFHackObject* mat, t_material* material) { if(mat != NULL) diff --git a/library/modules/Position.cpp b/library/modules/Position.cpp index ab3fccba3..7442d9ddb 100644 --- a/library/modules/Position.cpp +++ b/library/modules/Position.cpp @@ -25,8 +25,9 @@ distribution. #include "Internal.h" #include "ContextShared.h" #include "dfhack/modules/Position.h" -#include "dfhack/DFMemInfo.h" +#include "dfhack/VersionInfo.h" #include "dfhack/DFProcess.h" +#include "dfhack/DFError.h" using namespace DFHack; struct Position::Private @@ -41,7 +42,7 @@ 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; @@ -59,33 +60,36 @@ Position::Position(DFContextShared * d_) d->owner = d_->p; d->Inited = true; d->StartedHotkeys = d->Started = d->StartedScreen = false; - memory_info * mem; + OffsetGroup * OG_Position; + VersionInfo * mem = d->d->offset_descriptor; + // this is how to do feature detection properly try { - mem = d->d->offset_descriptor; - d->window_x_offset = mem->getAddress ("window_x"); - d->window_y_offset = mem->getAddress ("window_y"); - d->window_z_offset = mem->getAddress ("window_z"); - d->cursor_xyz_offset = mem->getAddress ("cursor_xyz"); - d->window_dims_offset = mem->getAddress ("window_dims"); + OG_Position = mem->getGroup("Position"); + d->window_x_offset = OG_Position->getAddress ("window_x"); + d->window_y_offset = OG_Position->getAddress ("window_y"); + d->window_z_offset = OG_Position->getAddress ("window_z"); + d->cursor_xyz_offset = OG_Position->getAddress ("cursor_xyz"); + d->window_dims_offset = OG_Position->getAddress ("window_dims"); d->Started = true; } - catch(exception &){}; + catch(Error::All &){}; try { - d->hotkey_start = mem->getAddress("hotkey_start"); - d->hotkey_mode_offset = mem->getOffset ("hotkey_mode"); - d->hotkey_xyz_offset = mem->getOffset("hotkey_xyz"); - d->hotkey_size = mem->getHexValue("hotkey_size"); + OffsetGroup * OG_Hotkeys = mem->getGroup("Hotkeys"); + d->hotkey_start = OG_Hotkeys->getAddress("start"); + d->hotkey_mode_offset = OG_Hotkeys->getOffset ("mode"); + d->hotkey_xyz_offset = OG_Hotkeys->getOffset("coords"); + d->hotkey_size = OG_Hotkeys->getHexValue("size"); d->StartedHotkeys = true; } - catch(exception &){}; + catch(Error::All &){}; try { - d->screen_tiles_ptr_offset = mem->getAddress ("screen_tiles_pointer"); + d->screen_tiles_ptr_offset = OG_Position->getAddress ("screen_tiles_pointer"); d->StartedScreen = true; } - catch(exception &){}; + catch(Error::All &){}; } Position::~Position() @@ -176,9 +180,7 @@ 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); - + uint32_t screen_addr = d->owner->readDWord(d->screen_tiles_ptr_offset); 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); @@ -187,10 +189,10 @@ bool Position::getScreenTiles (int32_t width, int32_t height, t_screen screen[]) { for(int32_t ix=0; ixReadHotkeys(buf)) + return buf; + else + return NULL; + } + else + return NULL; + } + + return NULL; +} + int Position_getWindowSize(DFHackObject* pos, int32_t* width, int32_t* height) { if(pos != NULL) @@ -117,6 +140,26 @@ int Position_getWindowSize(DFHackObject* pos, int32_t* width, int32_t* height) return -1; } +t_screen* Position_getScreenTiles(DFHackObject* pos, int32_t width, int32_t height) +{ + if(pos != NULL) + { + t_screen* buf; + + (*alloc_t_screen_buffer_callback)(buf, width * height); + + if(buf == NULL) + return NULL; + + if(((DFHack::Position*)pos)->getScreenTiles(width, height, buf)) + return buf; + else + return NULL; + } + + return NULL; +} + #ifdef __cplusplus } #endif diff --git a/library/modules/Translation.cpp b/library/modules/Translation.cpp index ae0c8b7ed..ba6018d55 100644 --- a/library/modules/Translation.cpp +++ b/library/modules/Translation.cpp @@ -25,7 +25,7 @@ distribution. #include "Internal.h" #include "ContextShared.h" #include "dfhack/modules/Translation.h" -#include "dfhack/DFMemInfo.h" +#include "dfhack/VersionInfo.h" #include "dfhack/DFProcess.h" #include "dfhack/DFVector.h" #include "dfhack/DFTypes.h" @@ -38,10 +38,10 @@ struct Translation::Private uint32_t transAddress; uint32_t word_table_offset; uint32_t sizeof_string; - + // translation Dicts dicts; - + DFContextShared *d; bool Inited; bool Started; @@ -52,11 +52,12 @@ Translation::Translation(DFContextShared * d_) d = new Private; d->d = d_; d->Inited = d->Started = false; - memory_info * mem = d->d->offset_descriptor; - d->genericAddress = mem->getAddress ("language_vector"); - d->transAddress = mem->getAddress ("translation_vector"); - d->word_table_offset = mem->getOffset ("word_table"); - d->sizeof_string = mem->getHexValue ("sizeof_string"); + OffsetGroup * OG_Translation = d->d->offset_descriptor->getGroup("Translations"); + OffsetGroup * OG_String = d->d->offset_descriptor->getGroup("string"); + d->genericAddress = OG_Translation->getAddress ("language_vector"); + d->transAddress = OG_Translation->getAddress ("translation_vector"); + d->word_table_offset = OG_Translation->getOffset ("word_table"); + d->sizeof_string = OG_String->getHexValue ("sizeof"); d->Inited = true; } @@ -116,7 +117,7 @@ bool Translation::Finish() Dicts * Translation::getDicts() { assert(d->Started); - + if(d->Started) return &d->dicts; return 0; @@ -126,10 +127,10 @@ string Translation::TranslateName(const t_name &name, bool inEnglish) { string out; assert (d->Started); - + map >::const_iterator it; - if(!inEnglish) + if(!inEnglish) { if(name.words[0] >=0 || name.words[1] >=0) { @@ -137,7 +138,7 @@ string Translation::TranslateName(const t_name &name, bool inEnglish) if(name.words[1]>=0) out.append(d->dicts.foreign_languages[name.language][name.words[1]]); out[0] = toupper(out[0]); } - if(name.words[5] >=0) + if(name.words[5] >=0) { string word; for(int i=2;i<=5;i++) @@ -146,7 +147,7 @@ string Translation::TranslateName(const t_name &name, bool inEnglish) if(out.length() > 0) out.append(" "); out.append(word); } - if(name.words[6] >=0) + if(name.words[6] >=0) { string word; word.append(d->dicts.foreign_languages[name.language][name.words[6]]); @@ -154,7 +155,7 @@ string Translation::TranslateName(const t_name &name, bool inEnglish) if(out.length() > 0) out.append(" "); out.append(word); } - } + } else { if(name.words[0] >=0 || name.words[1] >=0) @@ -163,7 +164,7 @@ string Translation::TranslateName(const t_name &name, bool inEnglish) if(name.words[1]>=0) out.append(d->dicts.translations[name.parts_of_speech[1]+1][name.words[1]]); out[0] = toupper(out[0]); } - if(name.words[5] >=0) + if(name.words[5] >=0) { if(out.length() > 0) out.append(" the"); @@ -180,7 +181,7 @@ string Translation::TranslateName(const t_name &name, bool inEnglish) } } } - if(name.words[6] >=0) + if(name.words[6] >=0) { if(out.length() > 0) out.append(" of"); diff --git a/library/modules/Vegetation.cpp b/library/modules/Vegetation.cpp index 6038e4d53..cceff66ef 100644 --- a/library/modules/Vegetation.cpp +++ b/library/modules/Vegetation.cpp @@ -25,7 +25,7 @@ distribution. #include "Internal.h" #include "ContextShared.h" -#include "dfhack/DFMemInfo.h" +#include "dfhack/VersionInfo.h" #include "dfhack/DFProcess.h" #include "dfhack/DFVector.h" #include "dfhack/DFTypes.h" @@ -40,7 +40,7 @@ struct Vegetation::Private uint32_t tree_desc_offset; // translation DfVector * p_veg; - + DFContextShared *d; Process * owner; bool Inited; @@ -53,9 +53,9 @@ Vegetation::Vegetation(DFContextShared * d_) d->owner = d_->p; d->d = d_; d->Inited = d->Started = false; - memory_info * mem = d->d->offset_descriptor; - d->vegetation_vector = mem->getAddress ("vegetation_vector"); - d->tree_desc_offset = mem->getOffset ("tree_desc_offset"); + OffsetGroup * OG_Veg = d->d->offset_descriptor->getGroup("Vegetation"); + d->vegetation_vector = OG_Veg->getAddress ("vector"); + d->tree_desc_offset = OG_Veg->getOffset ("tree_desc_offset"); d->Inited = true; } @@ -68,6 +68,8 @@ Vegetation::~Vegetation() bool Vegetation::Start(uint32_t & numplants) { + if(!d->Inited) + return false; d->p_veg = new DfVector (d->owner, d->vegetation_vector); numplants = d->p_veg->size(); d->Started = true; diff --git a/library/modules/World.cpp b/library/modules/World.cpp index 92c8606d4..3e1a670de 100644 --- a/library/modules/World.cpp +++ b/library/modules/World.cpp @@ -38,32 +38,47 @@ FIXME: Japa said that he had to do this with the time stuff he got from here #include "ContextShared.h" #include "dfhack/modules/World.h" #include "dfhack/DFProcess.h" -#include "dfhack/DFMemInfo.h" +#include "dfhack/VersionInfo.h" #include "dfhack/DFTypes.h" +#include "dfhack/DFError.h" using namespace DFHack; struct World::Private { bool Inited; - bool Started; + bool StartedTime; + bool StartedWeather; uint32_t year_offset; uint32_t tick_offset; + uint32_t weather_offset; DFContextShared *d; Process * owner; }; World::World(DFContextShared * _d) { - + d = new Private; d->d = _d; d->owner = _d->p; - - memory_info * mem = d->d->offset_descriptor; - d->year_offset = mem->getAddress( "current_year" ); - d->tick_offset = mem->getAddress( "current_tick" ); - d->Inited = d->Started = true; + d->Inited = d->StartedTime = d->StartedWeather = false; + + OffsetGroup * OG_World = d->d->offset_descriptor->getGroup("World"); + try + { + d->year_offset = OG_World->getAddress( "current_year" ); + d->tick_offset = OG_World->getAddress( "current_tick" ); + d->StartedTime = true; + } + catch(Error::All &){}; + try + { + d->weather_offset = OG_World->getAddress( "current_weather" ); + d->StartedWeather = true; + } + catch(Error::All &){}; + d->Inited = true; } World::~World() @@ -83,19 +98,19 @@ bool World::Finish() uint32_t World::ReadCurrentYear() { - if(d->Inited) + if(d->Inited && d->StartedTime) return(d->owner->readDWord(d->year_offset)); return 0; } uint32_t World::ReadCurrentTick() { - if(d->Inited) + if(d->Inited && d->StartedTime) return(d->owner->readDWord(d->tick_offset)); return 0; } -// FIX'D according to this: +// FIX'D according to this: /* World::ReadCurrentMonth and World::ReadCurrentDay « Sent to: peterix on: June 04, 2010, 04:44:30 » @@ -114,3 +129,26 @@ uint32_t World::ReadCurrentDay() { return ((this->ReadCurrentTick() / 1200) % 28) + 1; } + +uint8_t World::ReadCurrentWeather() +{ + if (d->Inited && d->StartedWeather) + return(d->owner->readByte(d->weather_offset + 12)); + return 0; +} +/* +void World::SetCurrentWeather(uint8_t weather) +{ + if (d->Inited && d->StartedWeather) + d->owner->writeByte(d->weather_offset,weather); +} +*/ +void World::SetCurrentWeather(uint8_t weather) +{ + if (d->Inited && d->StartedWeather) + { + uint8_t buf[25]; + memset(&buf,weather, sizeof(buf)); + d->owner->write(d->weather_offset,sizeof(buf),buf); + } +} diff --git a/library/modules/World_C.cpp b/library/modules/World_C.cpp index a5be3bcd0..6aa0b320f 100644 --- a/library/modules/World_C.cpp +++ b/library/modules/World_C.cpp @@ -39,7 +39,7 @@ int World_Start(DFHackObject* world) else return 0; } - + return -1; } @@ -52,7 +52,7 @@ int World_Finish(DFHackObject* world) else return 0; } - + return -1; } @@ -63,7 +63,7 @@ int World_ReadCurrentTick(DFHackObject* world, uint32_t* tick) *tick = ((DFHack::World*)world)->ReadCurrentTick(); return 1; } - + return -1; } @@ -74,7 +74,7 @@ int World_ReadCurrentYear(DFHackObject* world, uint32_t* year) *year = ((DFHack::World*)world)->ReadCurrentYear(); return 1; } - + return -1; } @@ -85,7 +85,7 @@ int World_ReadCurrentMonth(DFHackObject* world, uint32_t* month) *month = ((DFHack::World*)world)->ReadCurrentMonth(); return 1; } - + return -1; } @@ -96,10 +96,32 @@ int World_ReadCurrentDay(DFHackObject* world, uint32_t* day) *day = ((DFHack::World*)world)->ReadCurrentDay(); return 1; } - + return -1; } +int World_ReadCurrentWeather(DFHackObject* world, uint8_t* weather) +{ + if(world != NULL) + { + *weather = ((DFHack::World*)world)->ReadCurrentWeather(); + return 1; + } + + return -1; +} + +int World_WriteCurrentWeather(DFHackObject* world, uint8_t weather) +{ + if (world != NULL) + { + ((DFHack::World*)world)->SetCurrentWeather(weather); + return 1; + } + + return -1; +} + #ifdef __cplusplus } #endif diff --git a/library/private/ContextShared.h b/library/private/ContextShared.h index 361ccc45d..89403836c 100644 --- a/library/private/ContextShared.h +++ b/library/private/ContextShared.h @@ -48,7 +48,7 @@ namespace DFHack class ProcessEnumerator; class Process; - class memory_info; + class VersionInfo; struct t_name; class DFContextShared { @@ -68,7 +68,7 @@ namespace DFHack ProcessEnumerator* pm; Process* p; char * shm_start; - memory_info* offset_descriptor; + VersionInfo* offset_descriptor; string xml; // Modules diff --git a/library/shm/mod-creature2010.h b/library/shm/mod-creature2010.h index f52122127..64a9936a6 100644 --- a/library/shm/mod-creature2010.h +++ b/library/shm/mod-creature2010.h @@ -67,6 +67,7 @@ typedef struct uint32_t appearance_vector_offset; uint32_t birth_year_offset; uint32_t birth_time_offset; + uint32_t inventory_offset; } creature_offsets; typedef struct diff --git a/tools/examples/CMakeLists.txt b/tools/examples/CMakeLists.txt index 05d03e3d8..251efe49c 100644 --- a/tools/examples/CMakeLists.txt +++ b/tools/examples/CMakeLists.txt @@ -1,8 +1,5 @@ # 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) @@ -61,5 +58,4 @@ dftreedump dfspatterdump dfprocessenum RUNTIME DESTINATION bin -) -ENDIF (BUILD_DFHACK_EXAMPLES) \ No newline at end of file +) \ No newline at end of file diff --git a/tools/examples/buildingsdump.cpp b/tools/examples/buildingsdump.cpp index bfb747685..1d7e20709 100644 --- a/tools/examples/buildingsdump.cpp +++ b/tools/examples/buildingsdump.cpp @@ -54,7 +54,7 @@ int main (int argc,const char* argv[]) return 1; } - DFHack::memory_info * mem = DF->getMemoryInfo(); + DFHack::VersionInfo * mem = DF->getMemoryInfo(); DFHack::Buildings * Bld = DF->getBuildings(); DFHack::Position * Pos = DF->getPosition(); diff --git a/tools/examples/creaturedump.cpp b/tools/examples/creaturedump.cpp index 81fc3da8d..dddd6e018 100644 --- a/tools/examples/creaturedump.cpp +++ b/tools/examples/creaturedump.cpp @@ -19,7 +19,7 @@ enum likeType }; DFHack::Materials * Materials; -DFHack::memory_info *mem; +DFHack::VersionInfo *mem; vector< vector > englishWords; vector< vector > foreignWords; DFHack::Creatures * Creatures = NULL; @@ -134,7 +134,7 @@ likeType printLike40d(DFHack::t_like like, const matGlosses & mat,const vector< void printCreature(DFHack::Context * DF, const DFHack::t_creature & creature) { uint32_t dayoflife; - cout << "address: " << hex << creature.origin << dec << " creature type: " << Materials->raceEx[creature.race].rawname + cout << "address: " << hex << creature.origin << dec << ", creature race: " << creature.race << "/" << Materials->raceEx[creature.race].rawname << "[" << Materials->raceEx[creature.race].tile_character << "," << Materials->raceEx[creature.race].tilecolor.fore << "," << Materials->raceEx[creature.race].tilecolor.back @@ -154,7 +154,7 @@ void printCreature(DFHack::Context * DF, const DFHack::t_creature & creature) } DFHack::Translation *Tran = DF->getTranslation(); - DFHack::memory_info *mem = DF->getMemoryInfo(); + DFHack::VersionInfo *mem = DF->getMemoryInfo(); string transName = Tran->TranslateName(creature.name,false); if(!transName.empty()) @@ -172,7 +172,7 @@ void printCreature(DFHack::Context * DF, const DFHack::t_creature & creature) if(creature.civ) { - cout << "civilization: " << creature.civ; + cout << ", civilization: " << creature.civ; addendl = true; } @@ -191,7 +191,7 @@ void printCreature(DFHack::Context * DF, const DFHack::t_creature & creature) cout << endl; addendl = false; } - cout << "profession: " << mem->getProfession(creature.profession) << "(" << (int) creature.profession << ")"; + cout << ", profession: " << mem->getProfession(creature.profession) << "(" << (int) creature.profession << ")"; if(creature.custom_profession[0]) { @@ -271,6 +271,20 @@ void printCreature(DFHack::Context * DF, const DFHack::t_creature & creature) } } + //std::vector inventory; + // FIXME: TOO BAD... + /* + if( Creatures->ReadInventoryPtr(creature.origin, inventory) ) + { + DFHack::Items * Items = DF->getItems(); + printf("\tInventory:\n"); + for(unsigned int i = 0; i < inventory.size(); i++) + { + printf("\t\t%s\n", Items->getItemDescription(inventory[i], Materials).c_str()); + } + } + */ + /* if(creature.pregnancy_timer > 0) cout << "gives birth in " << creature.pregnancy_timer/1200 << " days. "; @@ -439,8 +453,14 @@ int main (int numargs, char ** args) } mem = DF->getMemoryInfo(); - Materials->ReadAllMaterials(); - + Materials->ReadInorganicMaterials(); + Materials->ReadOrganicMaterials(); + Materials->ReadWoodMaterials(); + Materials->ReadPlantMaterials(); + Materials->ReadCreatureTypes(); + Materials->ReadCreatureTypesEx(); + Materials->ReadDescriptorColors(); + if(!Tran->Start()) { cerr << "Can't get name tables" << endl; @@ -450,6 +470,7 @@ int main (int numargs, char ** args) //DF.InitViewAndCursor(); for(uint32_t i = 0; i < numCreatures; i++) { + printf("%d/%d\n", i, numCreatures); DFHack::t_creature temp; Creatures->ReadCreature(i,temp); if(check.empty() || string(Materials->raceEx[temp.race].rawname) == check) @@ -459,6 +480,7 @@ int main (int numargs, char ** args) printCreature(DF,temp); addrs.push_back(temp.origin); } + printf("!\n"); } if(addrs.size() <= 10) { @@ -473,6 +495,7 @@ int main (int numargs, char ** args) DF.ReadCreature(currentIdx, currentCreature); printCreature(DF,currentCreature); */ + Creatures->Finish(); DF->Detach(); #ifndef LINUX_BUILD diff --git a/tools/examples/dfitemdump.cpp b/tools/examples/dfitemdump.cpp index cf1778326..f3a3dd39e 100644 --- a/tools/examples/dfitemdump.cpp +++ b/tools/examples/dfitemdump.cpp @@ -37,7 +37,7 @@ int main () return 1; } - DFHack::memory_info * mem = DF->getMemoryInfo(); + DFHack::VersionInfo * mem = DF->getMemoryInfo(); Materials = DF->getMaterials(); Materials->ReadAllMaterials(); p = DF->getProcess(); diff --git a/tools/examples/hotkeynotedump.cpp b/tools/examples/hotkeynotedump.cpp index 2e35f2796..405498a4d 100644 --- a/tools/examples/hotkeynotedump.cpp +++ b/tools/examples/hotkeynotedump.cpp @@ -25,7 +25,7 @@ int main (void) return 1; } - DFHack::memory_info * mem = DF->getMemoryInfo(); + DFHack::VersionInfo * mem = DF->getMemoryInfo(); DFHack::Position * Pos = DF->getPosition(); // get stone matgloss mapping /* diff --git a/tools/examples/materialtest.cpp b/tools/examples/materialtest.cpp index 65426e4ba..c1b02063b 100644 --- a/tools/examples/materialtest.cpp +++ b/tools/examples/materialtest.cpp @@ -35,7 +35,7 @@ int main (int numargs, const char ** args) } DFHack::Process* p = DF->getProcess(); - DFHack::memory_info* mem = DF->getMemoryInfo(); + DFHack::VersionInfo* mem = DF->getMemoryInfo(); DFHack::Materials *Materials = DF->getMaterials(); cout << "----==== Inorganic ====----" << endl; diff --git a/tools/examples/processenum.cpp b/tools/examples/processenum.cpp index 745e94371..425b247e4 100644 --- a/tools/examples/processenum.cpp +++ b/tools/examples/processenum.cpp @@ -56,7 +56,7 @@ int main (void) { cout << "Testing ProcessEnumerator" << endl; ProcessEnumerator Penum("Memory.xml"); - memory_info * mem; + VersionInfo * mem; do { // make the ProcessEnumerator update its list of Processes @@ -90,7 +90,7 @@ int main (void) { cout << "Testing ContextManager" << endl; ContextManager Cman("Memory.xml"); - memory_info * mem; + VersionInfo * mem; do { // make the ContextManager update its list of Contexts diff --git a/tools/examples/treedump.cpp b/tools/examples/treedump.cpp index 71b386220..410587173 100644 --- a/tools/examples/treedump.cpp +++ b/tools/examples/treedump.cpp @@ -37,7 +37,7 @@ int main (int numargs, const char ** args) } DFHack::Process* p = DF->getProcess(); - DFHack::memory_info* mem = DF->getMemoryInfo(); + DFHack::VersionInfo* mem = DF->getMemoryInfo(); DFHack::Position * pos = DF->getPosition(); DFHack::Vegetation * v = DF->getVegetation(); DFHack::Materials * mat = DF->getMaterials(); diff --git a/tools/playground/CMakeLists.txt b/tools/playground/CMakeLists.txt index a28597475..ab21e3c2d 100644 --- a/tools/playground/CMakeLists.txt +++ b/tools/playground/CMakeLists.txt @@ -1,8 +1,5 @@ # 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) @@ -56,8 +53,15 @@ TARGET_LINK_LIBRARIES(dfcatsplosion dfhack) #ADD_EXECUTABLE(dfrenamer renamer.cpp) #TARGET_LINK_LIBRARIES(dfrenamer dfhack) +# copypaste +# Author: belal +# copies the current buildings in a df map, and then designates the area to be dug +# mainly a proof of concept for my gui application dfCopyPaste +ADD_EXECUTABLE(dfcopypaste copypaste.cpp) +TARGET_LINK_LIBRARIES(dfcopypaste dfhack) + # this needs the C bindings -IF(BUILD_DFHACK_C_BINDIGS) +IF(BUILD_DFHACK_C_BINDINGS) # for trying out some 'stuff' ADD_EXECUTABLE(dftest test.cpp) TARGET_LINK_LIBRARIES(dftest dfhack) @@ -65,7 +69,7 @@ IF(BUILD_DFHACK_C_BINDIGS) dftest RUNTIME DESTINATION bin ) -ENDIF(BUILD_DFHACK_C_BINDIGS) +ENDIF(BUILD_DFHACK_C_BINDINGS) install(TARGETS dfmoodump @@ -80,4 +84,3 @@ IF(UNIX) 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 index c50cc4c6f..98de87711 100644 --- a/tools/playground/SegmentedFinder.h +++ b/tools/playground/SegmentedFinder.h @@ -311,4 +311,11 @@ bool findString (SegmentedFinder* s, uint32_t *addr, const char * compare ) return false; } +bool findStrBuffer (SegmentedFinder* s, uint32_t *addr, const char * compare ) +{ + if(strcmp((const char *)addr, compare) == 0) + return true; + return false; +} + #endif // SEGMENTED_FINDER_H \ No newline at end of file diff --git a/tools/playground/catsplosion.cpp b/tools/playground/catsplosion.cpp index 08d5c8961..c3c0126d2 100644 --- a/tools/playground/catsplosion.cpp +++ b/tools/playground/catsplosion.cpp @@ -21,7 +21,7 @@ using namespace DFHack; int main ( int argc, char** argv ) { - DFHack::memory_info *mem; + DFHack::VersionInfo *mem; DFHack::Process *proc; uint32_t creature_pregnancy_offset; diff --git a/tools/playground/copypaste.cpp b/tools/playground/copypaste.cpp new file mode 100644 index 000000000..dd304d5e9 --- /dev/null +++ b/tools/playground/copypaste.cpp @@ -0,0 +1,449 @@ +// Console version of DF copy paste, proof of concept +// By belal + +#include +#include +#include +#include +#include +#include +#include +#include + +#define DFHACK_WANT_MISCUTILS +#define DFHACK_WANT_TILETYPES +#include +#include "dfhack/modules/WindowIO.h" + +using namespace DFHack; +//bool waitTillCursorState(DFHack::Context *DF, bool On); +//bool waitTillCursorPositionState(DFHack::Context *DF, int32_t x,int32_t y, int32_t z); + +//change this if you are having problems getting correct results, lower if you would like to go faster +//const int WAIT_AMT = 25; + +void sort(uint32_t &a,uint32_t &b) +{ + if(a > b){ + uint32_t c = b; + b = a; + a = c; + } +} +void sort(int32_t &a,int32_t &b) +{ + if(a > b){ + int16_t c = b; + b = a; + a = c; + } +} +void printVecOfVec(ostream &out, vector > >vec,char sep){ + for(int k=0;k buildCommands; + buildCommands["building_stockpilest"]=""; + buildCommands["building_zonest"]=""; + buildCommands["building_construction_blueprintst"]=""; + buildCommands["building_wagonst"]=""; + buildCommands["building_armor_standst"]="a"; + buildCommands["building_bedst"]="b"; + buildCommands["building_seatst"]="c"; + buildCommands["building_burial_receptaclest"]="n"; + buildCommands["building_doorst"]="d"; + buildCommands["building_floodgatest"]="x"; + buildCommands["building_floor_hatchst"]="H"; + buildCommands["building_wall_gratest"]="W"; + buildCommands["building_floor_gratest"]="G"; + buildCommands["building_vertical_barsst"]="B"; + buildCommands["building_floor_barsst"]="alt-b"; + buildCommands["building_cabinetst"]="f"; + buildCommands["building_containerst"]="h"; + buildCommands["building_shopst"]=""; + buildCommands["building_workshopst"]=""; + buildCommands["building_alchemists_laboratoryst"]="wa"; + buildCommands["building_carpenters_workshopst"]="wc"; + buildCommands["building_farmers_workshopst"]="ww"; + buildCommands["building_masons_workshopst"]="wm"; + buildCommands["building_craftdwarfs_workshopst"]="wr"; + buildCommands["building_jewelers_workshopst"]="wj"; + buildCommands["building_metalsmiths_workshopst"]="wf"; + buildCommands["building_magma_forgest"]=""; + buildCommands["building_bowyers_workshopst"]="wb"; + buildCommands["building_mechanics_workshopst"]="wt"; + buildCommands["building_siege_workshopst"]="ws"; + buildCommands["building_butchers_shopst"]="wU"; + buildCommands["building_leather_worksst"]="we"; + buildCommands["building_tanners_shopst"]="wn"; + buildCommands["building_clothiers_shopst"]="wk"; + buildCommands["building_fisheryst"]="wh"; + buildCommands["building_stillst"]="wl"; + buildCommands["building_loomst"]="wo"; + buildCommands["building_quernst"]="wq"; + buildCommands["building_kennelsst"]="k"; + buildCommands["building_kitchenst"]="wz"; + buildCommands["building_asheryst"]="wy"; + buildCommands["building_dyers_shopst"]="wd"; + buildCommands["building_millstonest"]="wM"; + buildCommands["building_farm_plotst"]="p"; + buildCommands["building_weapon_rackst"]="r"; + buildCommands["building_statuest"]="s"; + buildCommands["building_tablest"]="t"; + buildCommands["building_paved_roadst"]="o"; + buildCommands["building_bridgest"]="g"; + buildCommands["building_wellst"]="l"; + buildCommands["building_siege enginest"]="i"; + buildCommands["building_catapultst"]="ic"; + buildCommands["building_ballistast"]="ib"; + buildCommands["building_furnacest"]=""; + buildCommands["building_wood_furnacest"]="ew"; + buildCommands["building_smelterst"]="es"; + buildCommands["building_glass_furnacest"]="ek"; + buildCommands["building_kilnst"]="ek"; + buildCommands["building_magma_smelterst"]="es"; + buildCommands["building_magma_glass_furnacest"]="ek"; + buildCommands["building_magma_kilnst"]="ek"; + buildCommands["building_glass_windowst"]="y"; + buildCommands["building_gem_windowst"]="Y"; + buildCommands["building_tradedepotst"]="D"; + buildCommands["building_mechanismst"]=""; + buildCommands["building_leverst"]="Tl"; + buildCommands["building_pressure_platest"]="Tp"; + buildCommands["building_cage_trapst"]="Tc"; + buildCommands["building_stonefall_trapst"]="Ts"; + buildCommands["building_weapon_trapst"]="Tw"; + buildCommands["building_spikest"]=""; + buildCommands["building_animal_trapst"]="m"; + buildCommands["building_screw_pumpst"]="Ms"; + buildCommands["building_water_wheelst"]="Mw"; + buildCommands["building_windmillst"]="Mm"; + buildCommands["building_gear_assemblyst"]="Mg"; + buildCommands["building_horizontal_axlest"]="Mh"; + buildCommands["building_vertical_axlest"]="Mv"; + buildCommands["building_supportst"]="S"; + buildCommands["building_cagest"]="j"; + buildCommands["building_archery_targetst"]="A"; + buildCommands["building_restraintst"]="v"; + + DFHack::ContextManager DFMgr("Memory.xml"); + DFHack::Context *DF = DFMgr.getSingleContext(); + + try + { + DF->Attach(); + } + catch (std::exception& e) + { + std::cerr << e.what() << std::endl; + #ifndef LINUX_BUILD + cin.ignore(); + #endif + return 1; + } + + DFHack::Position *Pos = DF->getPosition(); + DFHack::VersionInfo* mem = DF->getMemoryInfo(); + DFHack::Process * p = DF->getProcess(); + OffsetGroup * OG_Maps = mem->getGroup("Maps"); + OffsetGroup * OG_MapBlock = OG_Maps->getGroup("block"); + OffsetGroup * OG_LocalFt = OG_Maps->getGroup("features")->getGroup("local"); + uint32_t designations = OG_MapBlock->getOffset("designation"); + uint32_t block_feature1 = OG_MapBlock->getOffset("feature_local"); + uint32_t block_feature2 = OG_MapBlock->getOffset("feature_global"); + uint32_t region_x_offset = OG_Maps->getAddress("region_x"); + uint32_t region_y_offset = OG_Maps->getAddress("region_y"); + uint32_t region_z_offset = OG_Maps->getAddress("region_z"); + uint32_t feature1_start_ptr = OG_LocalFt->getAddress("start_ptr"); + int32_t regionX, regionY, regionZ; + + // read position of the region inside DF world + p->readDWord (region_x_offset, (uint32_t &)regionX); + p->readDWord (region_y_offset, (uint32_t &)regionY); + p->readDWord (region_z_offset, (uint32_t &)regionZ); + while(1){ + int32_t cx1,cy1,cz1; + cx1 = -30000; + while(cx1 == -30000){ + DF->ForceResume(); + cout << "Set cursor at first position, then press any key"; + cin.ignore(); + DF->Suspend(); + Pos->getCursorCoords(cx1,cy1,cz1); + } + + uint32_t tx1,ty1,tz1; + tx1 = cx1/16; + ty1 = cy1/16; + tz1 = cz1; + + int32_t cx2,cy2,cz2; + cx2 = -30000; + while(cx2 == -30000){ + DF->Resume(); + cout << "Set cursor at second position, then press any key"; + cin.ignore(); + DF->Suspend(); + Pos->getCursorCoords(cx2,cy2,cz2); + } + uint32_t tx2,ty2,tz2; + tx2 = cx2/16; + ty2 = cy2/16; + tz2 = cz2; + sort(tx1,tx2); + sort(ty1,ty2); + sort(tz1,tz2); + sort(cx1,cx2); + sort(cy1,cy2); + sort(cz1,cz2); + + vector > >dig(cz2-cz1+1,vector >(cy2-cy1+1,vector(cx2-cx1+1))); + vector > >build(cz2-cz1+1,vector >(cy2-cy1+1,vector(cx2-cx1+1))); + mapblock40d block; + DFHack::Maps *Maps = DF->getMaps(); + Maps->Start(); + for(uint32_t y = ty1;y<=ty2;y++) + { + for(uint32_t x = tx1;x<=tx2;x++) + { + for(uint32_t z = tz1;z<=tz2;z++) + { + if(Maps->isValidBlock(x,y,z)) + { + if(Maps->ReadBlock40d(x,y,z,&block)) + { + int ystart,yend,xstart,xend; + ystart=xstart=0; + yend=xend=15; + if(y == ty2) + { + yend = cy2 % 16; + } + if(y == ty1) + { + ystart = cy1 % 16; + } + if(x == tx2) + { + xend = cx2 % 16; + } + if(x == tx1) + { + xstart = cx1 % 16; + } + int zidx = z-tz1; + for(int yy = ystart; yy <= yend;yy++) + { + int yidx = yy+(16*(y-ty1)-(cy1%16)); + for(int xx = xstart; xx <= xend;xx++) + { + int xidx = xx+(16*(x-tx1)-(cx1%16)); + if(DFHack::isOpenTerrain(block.tiletypes[xx][yy]) || DFHack::isFloorTerrain(block.tiletypes[xx][yy])) {dig[zidx][yidx][xidx] = "d";} + else if(DFHack::STAIR_DOWN == DFHack::tileTypeTable[block.tiletypes[xx][yy]].c){ dig [zidx][yidx][xidx] = "j"; build [zidx][yidx][xidx] = "Cd";} + else if(DFHack::STAIR_UP == DFHack::tileTypeTable[block.tiletypes[xx][yy]].c){ dig [zidx][yidx][xidx] = "u"; build [zidx][yidx][xidx] = "Cu";} + else if(DFHack::STAIR_UPDOWN == DFHack::tileTypeTable[block.tiletypes[xx][yy]].c){ dig [zidx][yidx][xidx] = "i"; build [zidx][yidx][xidx] = "Cx";} + else if(DFHack::isRampTerrain(block.tiletypes[xx][yy])){dig [zidx][yidx][xidx] = "r";build [zidx][yidx][xidx] = "Cr";} + else if(DFHack::isWallTerrain(block.tiletypes[xx][yy])){build [zidx][yidx][xidx] = "Cw";} + } + yidx++; + } + } + } + } + } + } + DFHack::Buildings * Bld = DF->getBuildings(); + std::map custom_workshop_types; + uint32_t numBuildings; + if(Bld->Start(numBuildings)) + { + Bld->ReadCustomWorkshopTypes(custom_workshop_types); + 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 + { + std::string typestr; + mem->resolveClassIDToClassname(temp.type, typestr); + if(temp.z == cz1 && cx1 <= temp.x1 && cx2 >= temp.x2 && cy1 <= temp.y1 && cy2 >= temp.y2) + { + string currStr = build[temp.z-cz1][temp.y1-cy1][temp.x1-cx1]; + stringstream stream; + string newStr = buildCommands[typestr]; + if(temp.x1 != temp.x2) + { + stream << "(" << temp.x2-temp.x1+1 << "x" << temp.y2-temp.y1+1 << ")"; + newStr += stream.str(); + } + build[temp.z-cz1][temp.y1-cy1][temp.x1-cx1] = newStr + currStr; + } + } + } + } +// for testing purposes + //ofstream outfile("test.txt"); +// printVecOfVec(outfile, dig,'\t'); +// outfile << endl; +// printVecOfVec(outfile, build,'\t'); +// outfile << endl; +// outfile.close(); + + int32_t cx3,cy3,cz3,cx4,cy4,cz4; + uint32_t tx3,ty3,tz3,tx4,ty4,tz4; + char result; + while(1){ + cx3 = -30000; + while(cx3 == -30000){ + DF->Resume(); + cout << "Set cursor at new position, then press any key:"; + result = cin.get(); + DF->Suspend(); + Pos->getCursorCoords(cx3,cy3,cz3); + } + if(result == 'q'){ + break; + } + cx4 = cx3+cx2-cx1; + cy4 = cy3+cy2-cy1; + cz4 = cz3+cz2-cz1; + tx3=cx3/16; + ty3=cy3/16; + tz3=cz3; + tx4=cx4/16; + ty4=cy4/16; + tz4=cz4; + DFHack::WindowIO * Win = DF->getWindowIO(); + designations40d designationBlock; + for(uint32_t y = ty3;y<=ty4;y++) + { + for(uint32_t x = tx3;x<=tx4;x++) + { + for(uint32_t z = tz3;z<=tz4;z++) + { + Maps->Start(); + Maps->ReadBlock40d(x,y,z,&block); + Maps->ReadDesignations(x,y,z,&designationBlock); + int ystart,yend,xstart,xend; + ystart=xstart=0; + yend=xend=15; + if(y == ty4){ + yend = cy4 % 16; + } + if(y == ty3){ + ystart = cy3 % 16; + } + if(x == tx4){ + xend = cx4 % 16; + } + if(x == tx3){ + xstart = cx3 % 16; + } + int zidx = z-tz3; + for(int yy = ystart; yy <= yend;yy++){ + int yidx = yy+(16*(y-ty3)-(cy3%16)); + for(int xx = xstart; xx <= xend;xx++){ + int xidx = xx+(16*(x-tx3)-(cx3%16)); + if(dig[zidx][yidx][xidx] != ""){ + char test = dig[zidx][yidx][xidx].c_str()[0]; + switch (test){ + case 'd': + designationBlock[xx][yy].bits.dig = DFHack::designation_default; + break; + case 'i': + designationBlock[xx][yy].bits.dig = DFHack::designation_ud_stair; + break; + case 'u': + designationBlock[xx][yy].bits.dig = DFHack::designation_u_stair; + break; + case 'j': + designationBlock[xx][yy].bits.dig = DFHack::designation_d_stair; + break; + case 'r': + designationBlock[xx][yy].bits.dig = DFHack::designation_ramp; + break; + } + + } + } + yidx++; + } + Maps->Start(); + Maps->WriteDesignations(x,y,z,&designationBlock); + } + } + } + } + } + DF->Detach(); + #ifndef LINUX_BUILD + std::cout << "Done. Press any key to continue" << std::endl; + cin.ignore(); + #endif + return 0; +} +/* +bool waitTillCursorState(DFHack::Context *DF, bool On) +{ + DFHack::WindowIO * w = DF->getWindowIO(); + DFHack::Position * p = DF->getPosition(); + int32_t x,y,z; + int tryCount = 0; + DF->Suspend(); + bool cursorResult = p->getCursorCoords(x,y,z); + while(tryCount < 50 && On && !cursorResult || !On && cursorResult) + { + DF->Resume(); + w->TypeSpecial(DFHack::WAIT,1,WAIT_AMT); + tryCount++; + DF->Suspend(); + cursorResult = p->getCursorCoords(x,y,z); + } + if(tryCount >= 50) + { + cerr << "Something went wrong, cursor at x: " << x << " y: " << y << " z: " << z << endl; + return false; + } + DF->Resume(); + return true; +} +bool waitTillCursorPositionState(DFHack::Context *DF, int32_t x,int32_t y, int32_t z) +{ + DFHack::WindowIO * w = DF->getWindowIO(); + DFHack::Position * p = DF->getPosition(); + int32_t x2,y2,z2; + int tryCount = 0; + DF->Suspend(); + bool cursorResult = p->getCursorCoords(x2,y2,z2); + while(tryCount < 50 && (x != x2 || y != y2 || z != z2)) + { + DF->Resume(); + w->TypeSpecial(DFHack::WAIT,1,WAIT_AMT); + tryCount++; + DF->Suspend(); + cursorResult = p->getCursorCoords(x2,y2,z2); + } + if(tryCount >= 50) + { + cerr << "Something went wrong, cursor at x: " << x2 << " y: " << y2 << " z: " << z2 << endl; + return false; + } + DF->Resume(); + return true; +}*/ \ No newline at end of file diff --git a/tools/playground/incrementalsearch.cpp b/tools/playground/incrementalsearch.cpp index 0e9529cf1..918577944 100644 --- a/tools/playground/incrementalsearch.cpp +++ b/tools/playground/incrementalsearch.cpp @@ -181,12 +181,12 @@ bool getRanges(DFHack::Process * p, vector & selected_ranges { // 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) + if(p->getDescriptor()->getOS() == DFHack::VersionInfo::OS_WINDOWS) { start = min(11, (int)ranges.size()); end = min(14, (int)ranges.size()); } - else if(p->getDescriptor()->getOS() == DFHack::memory_info::OS_LINUX) + else if(p->getDescriptor()->getOS() == DFHack::VersionInfo::OS_LINUX) { start = min(2, (int)ranges.size()); end = min(4, (int)ranges.size()); @@ -482,6 +482,22 @@ void FindPtrVectorsByObjectAddress(DFHack::ContextManager & DFMgr, vector & ranges) +{ + vector found; + string select; + while (Incremental(found,"buffer",select,"buffer","buffers")) + { + DFMgr.Refresh(); + DFHack::Context * DF = DFMgr.getSingleContext(); + DF->Attach(); + SegmentedFinder sf(ranges,DF); + sf.Find< const char * ,uint32_t>(select.c_str(),1,found, findStrBuffer); + DF->Detach(); + } +} + + void FindStrings(DFHack::ContextManager & DFMgr, vector & ranges) { @@ -793,18 +809,19 @@ int main (void) vector selected_ranges; getRanges(p,selected_ranges); - DFHack::memory_info *minfo = DF->getMemoryInfo(); - DFHack::memory_info::OSType os = minfo->getOS(); + DFHack::VersionInfo *minfo = DF->getMemoryInfo(); + DFHack::VersionInfo::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"; + " 7=pointer vector by address of an object, 8=vector>first object>string\n" + " 9=string buffers\n"; int mode; do { getNumber(prompt,mode, 1, false); - } while (mode < 1 || mode > 8 ); + } while (mode < 1 || mode > 9 ); switch (mode) { case 1: @@ -838,6 +855,10 @@ int main (void) DF->Detach(); FindVectorByFirstObjectRawname(DFMgr, selected_ranges); break; + case 9: + DF->Detach(); + FindStrBufs(DFMgr, selected_ranges); + break; default: cout << "not implemented :(" << endl; } diff --git a/tools/playground/moodump.cpp b/tools/playground/moodump.cpp index a6cffd854..37c52a3d9 100644 --- a/tools/playground/moodump.cpp +++ b/tools/playground/moodump.cpp @@ -6,7 +6,7 @@ using namespace std; #include DFHack::Materials * Materials; -DFHack::memory_info *mem; +DFHack::VersionInfo *mem; vector< vector > englishWords; vector< vector > foreignWords; diff --git a/tools/supported/CMakeLists.txt b/tools/supported/CMakeLists.txt index f7006aeb2..22482f5ea 100644 --- a/tools/supported/CMakeLists.txt +++ b/tools/supported/CMakeLists.txt @@ -64,7 +64,13 @@ TARGET_LINK_LIBRARIES(dfposition dfhack) ADD_EXECUTABLE(dfdoffsets dumpoffsets.cpp) TARGET_LINK_LIBRARIES(dfdoffsets dfhack) +# change the weather +ADD_EXECUTABLE(dfweather weather.cpp) +TARGET_LINK_LIBRARIES(dfweather dfhack) + + IF(UNIX) + SET(VEINLOOK_BUILT "NO") SET(CURSES_NEED_WIDE "YES") SET(CURSES_NEED_NCURSES "NO") find_package(Curses QUIET) @@ -114,11 +120,6 @@ dfexpbench dfsuspend dfflows dfliquids +dfweather 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 index 267a686ff..08f86f781 100644 --- a/tools/supported/cleartask.cpp +++ b/tools/supported/cleartask.cpp @@ -32,7 +32,7 @@ int main () return 1; } - DFHack::memory_info * mem = DF->getMemoryInfo(); + DFHack::VersionInfo * mem = DF->getMemoryInfo(); p = DF->getProcess(); uint32_t item_vec_offset = 0; try diff --git a/tools/supported/dumpoffsets.cpp b/tools/supported/dumpoffsets.cpp index 2257ca1de..be5861bf1 100644 --- a/tools/supported/dumpoffsets.cpp +++ b/tools/supported/dumpoffsets.cpp @@ -8,15 +8,22 @@ using namespace std; #include +#include using namespace DFHack; int main (int numargs, const char ** args) { + /* + DFHack::VersionInfoFactory * VIF = new DFHack::VersionInfoFactory("Memory.xml"); + for(int i = 0; i < VIF->versions.size(); i++) + { + cout << VIF->versions[i]->PrintOffsets(); + } + */ DFHack::ContextManager DFMgr("Memory.xml"); - DFHack::Context * DF; + DFHack::Context *DF = DFMgr.getSingleContext(); try { - DF = DFMgr.getSingleContext(); DF->Attach(); } catch (exception& e) @@ -27,12 +34,11 @@ int main (int numargs, const char ** args) #endif return 1; } - memory_info * minfo = DF->getMemoryInfo(); - if(minfo) - cout << minfo->PrintOffsets(); + cout << DF->getMemoryInfo()->PrintOffsets(); #ifndef LINUX_BUILD cout << "Done. Press any key to continue" << endl; cin.ignore(); #endif + //delete VIF; return 0; } diff --git a/tools/supported/liquids.cpp b/tools/supported/liquids.cpp index b93c6cc29..ceff8c3fd 100644 --- a/tools/supported/liquids.cpp +++ b/tools/supported/liquids.cpp @@ -43,12 +43,13 @@ int main (void) string mode="magma"; string brush="point"; string flowmode="f+"; + string setmode ="s."; int amount = 7; while(!end) { DF->Resume(); string command = ""; - cout <<"[" << mode << ":" << amount << ":" << flowmode << "]# "; + cout <<"[" << mode << ":" << amount << ":" << flowmode << ":" << setmode << "]# "; getline(cin, command); if(command=="help") { @@ -57,6 +58,10 @@ int main (void) << "w - switch to water" << endl << "o - make obsidian wall instead" << endl << "f - flow bits only" << endl + << "Set-Modes:" << endl + << "s+ - only add" << endl + << "s. - set" << endl + << "s- - only remove" << endl << "Properties:" << endl << "f+ - make the spawned liquid flow" << endl << "f. - don't change flow state (read state in flow mode)" << endl @@ -125,6 +130,18 @@ int main (void) { flowmode = "f."; } + else if(command == "s+") + { + setmode = "s+"; + } + else if(command == "s-") + { + setmode = "s-"; + } + else if(command == "s.") + { + setmode = "s."; + } // blah blah, bad code, bite me. else if(command == "0") amount = 0; @@ -185,7 +202,7 @@ int main (void) } } // quick hack, do not use for serious stuff - + /* else if(mode == "starruby") { if(Maps->isValidBlock((x/16),(y/16),z)) @@ -236,6 +253,7 @@ int main (void) zzz --; } } + */ else { // place the magma @@ -248,7 +266,21 @@ int main (void) // fix temperatures so we don't produce lethal heat traps if(amount == 0 || designations[x%16][y%16].bits.liquid_type == DFHack::liquid_magma && mode == "water") temp1[x%16][y%16] = temp2[x%16][y%16] = 10015; - designations[x%16][y%16].bits.flow_size = amount; + DFHack::naked_designation & flow = designations[x%16][y%16].bits; + if(setmode == "s.") + { + flow.flow_size = amount; + } + else if(setmode == "s+") + { + if(flow.flow_size < amount) + flow.flow_size = amount; + } + else if(setmode == "s-") + { + if (flow.flow_size > amount) + flow.flow_size = amount; + } } if(mode == "magma") designations[x%16][y%16].bits.liquid_type = DFHack::liquid_magma; @@ -264,7 +296,21 @@ int main (void) // fix temperatures so we don't produce lethal heat traps if(amount == 0 || designations[xx][yy].bits.liquid_type == DFHack::liquid_magma && mode == "water") temp1[xx%16][yy%16] = temp2[xx%16][yy%16] = 10015; - designations[xx][yy].bits.flow_size = amount; + DFHack::naked_designation & flow= designations[xx][yy].bits; + if(setmode == "s.") + { + flow.flow_size = amount; + } + else if(setmode == "s+") + { + if(flow.flow_size < amount) + flow.flow_size = amount; + } + else if(setmode == "s-") + { + if (flow.flow_size > amount) + flow.flow_size = amount; + } } if(mode == "magma") designations[xx][yy].bits.liquid_type = DFHack::liquid_magma; diff --git a/tools/supported/probe.cpp b/tools/supported/probe.cpp index 832562dc5..57992f470 100644 --- a/tools/supported/probe.cpp +++ b/tools/supported/probe.cpp @@ -30,27 +30,33 @@ int main (int numargs, const char ** args) #endif return 1; } - + DFHack::Position *Pos = DF->getPosition(); - DFHack::memory_info* mem = DF->getMemoryInfo(); + DFHack::VersionInfo* mem = DF->getMemoryInfo(); DFHack::Maps *Maps = DF->getMaps(); DFHack::Process * p = DF->getProcess(); - uint32_t designatus = mem->getOffset("map_data_designation"); - uint32_t block_feature1 = mem->getOffset("map_data_feature_local"); - uint32_t block_feature2 = mem->getOffset("map_data_feature_global"); - uint32_t region_x_offset = mem->getAddress("region_x"); - uint32_t region_y_offset = mem->getAddress("region_y"); - uint32_t region_z_offset = mem->getAddress("region_z"); - uint32_t feature1_start_ptr = mem->getAddress("local_feature_start_ptr"); + OffsetGroup *mapsg = mem->getGroup("Maps"); + OffsetGroup *mapblockg = mapsg->getGroup("block"); + OffsetGroup *localfeatg = mapsg->getGroup("features")->getGroup("local"); + + uint32_t region_x_offset = mapsg->getAddress("region_x"); + uint32_t region_y_offset = mapsg->getAddress("region_y"); + uint32_t region_z_offset = mapsg->getAddress("region_z"); + + uint32_t designatus = mapblockg->getOffset("designation"); + uint32_t block_feature1 = mapblockg->getOffset("feature_local"); + uint32_t block_feature2 = mapblockg->getOffset("feature_global"); + + uint32_t feature1_start_ptr = localfeatg->getAddress("start_ptr"); int32_t regionX, regionY, regionZ; - + // read position of the region inside DF world p->readDWord (region_x_offset, (uint32_t &)regionX); p->readDWord (region_y_offset, (uint32_t &)regionY); p->readDWord (region_z_offset, (uint32_t &)regionZ); - + Maps->Start(); - + int32_t cursorX, cursorY, cursorZ; Pos->getCursorCoords(cursorX,cursorY,cursorZ); if(cursorX != -30000) @@ -72,20 +78,19 @@ int main (int numargs, const char ** args) std::cout << endl; print_bits(block.occupancy[tileX][tileY].whole,std::cout); std::cout << endl; - + // tiletype std::cout <<"tiletype: " << tiletype; if(tileTypeTable[tiletype].name) std::cout << " = " << tileTypeTable[tiletype].name; std::cout << std::endl; - - std::cout <<"temperature1: " << tmpb1[tileX][tileY] << " U" << std::endl; std::cout <<"temperature2: " << tmpb2[tileX][tileY] << " U" << std::endl; - + // biome, geolayer std::cout << "biome: " << des.biome << std::endl; std::cout << "geolayer: " << des.geolayer_index << std::endl; + // liquids if(des.flow_size) { diff --git a/tools/supported/prospector.cpp b/tools/supported/prospector.cpp index e7e0e9237..77ba6afcb 100644 --- a/tools/supported/prospector.cpp +++ b/tools/supported/prospector.cpp @@ -313,6 +313,11 @@ int main (int argc, const char* argv[]) std::sort(matss.begin(), matss.end(), compare_pair_second<>()); for(int i = 0; i < matss.size();i++) { + if(matss[i].first >= Mats->inorganic.size()) + { + cerr << "Error, material out of bounds: " << matss[i].first << endl; + continue; + } cout << Mats->inorganic[matss[i].first].id << " : " << matss[i].second << endl; } DF->Detach(); diff --git a/tools/supported/reveal.cpp b/tools/supported/reveal.cpp index 66ec3d92f..2c82075f7 100644 --- a/tools/supported/reveal.cpp +++ b/tools/supported/reveal.cpp @@ -6,6 +6,7 @@ using namespace std; #include +#include struct hideblock { @@ -37,6 +38,19 @@ int main (void) } DFHack::Maps *Maps =DF->getMaps(); + DFHack::Gui *Gui =DF->getGui(); + // walk the map, save the hide bits, reveal. + cout << "Pausing..." << endl; + + // horrible hack to make sure the pause is really set + // preblem here is that we could be 'arriving' at the wrong time and DF could be in the middle of a frame. + // that could mean that revealing, even with suspending DF's thread, would mean unleashing hell *in the same frame* + // this here hack sets the pause state, resumes DF, waits a second for it to enter the pause (I know, BS value.) and suspends. + Gui->SetPauseState(true); + DF->Resume(); + sleep(1); + DF->Suspend(); + // init the map if(!Maps->Start()) { @@ -46,11 +60,12 @@ int main (void) #endif return 1; } - + + cout << "Revealing, please wait..." << endl; + Maps->getSize(x_max,y_max,z_max); vector hidesaved; - // walk the map, save the hide bits, reveal. - cout << "Revealing... please wait." << endl; + for(uint32_t x = 0; x< x_max;x++) { for(uint32_t y = 0; y< y_max;y++) @@ -80,8 +95,10 @@ int main (void) } // FIXME: force game pause here! DF->Detach(); - cout << "Map revealed. Close window/force exit to keep it that way." << endl; - cout << "Press any key to unreveal. Don't close DF or unpause in that case!" << endl; + cout << "Map revealed. The game has been paused for you." << endl; + cout << "Unpausing can unleash the forces of hell!" << endl << endl; + cout << "Press any key to unreveal." << endl; + cout << "Close to keep the map revealed." << endl; cin.ignore(); cout << "Unrevealing... please wait." << endl; // FIXME: do some consistency checks here! diff --git a/tools/supported/veinlook.cpp b/tools/supported/veinlook.cpp index 1f489b355..7eaa2419f 100644 --- a/tools/supported/veinlook.cpp +++ b/tools/supported/veinlook.cpp @@ -723,6 +723,7 @@ main(int argc, char *argv[]) Maps->Start(); Mats->Start(); Mats->ReadInorganicMaterials(); + Mats->ReadCreatureTypes(); uint32_t effectnum; /* if(DF.InitReadEffects(effectnum)) diff --git a/tools/supported/weather.cpp b/tools/supported/weather.cpp new file mode 100644 index 000000000..6d441b00b --- /dev/null +++ b/tools/supported/weather.cpp @@ -0,0 +1,98 @@ +// Just show some position data + +#include +#include +#include +#include +#include +#include +#include + +#define DFHACK_WANT_MISCUTILS +#define DFHACK_WANT_TILETYPES +#include + +using namespace DFHack; + +void printWeather(DFHack::WeatherType current) +{ + switch (current) + { + case CLEAR: + cout << "The sky is clear." << endl; + cout << "Options:" << endl; + cout << "'r' to make it rain." << endl; + cout << "'s' to make it snow." << endl; + break; + case RAINING: + cout << "It is raining." << endl; + cout << "Options:" << endl; + cout << "'c' to clear the sky." << endl; + cout << "'s' to make it snow." << endl; + break; + case SNOWING: + cout << "It is snowing." << endl; + cout << "Options:" << endl; + cout << "'c' to clear the sky." << endl; + cout << "'r' to make it rain." << endl; + break; + } + cout << "'q' to quit." << endl; + cout << "anything else to refresh" << endl; + cout << ">"; +} + +using namespace DFHack; +int main (int numargs, const char ** args) +{ + DFHack::ContextManager DFMgr("Memory.xml"); + DFHack::Context *DF = DFMgr.getSingleContext(); + + try + { + DF->Attach(); + } + catch (std::exception& e) + { + std::cerr << e.what() << std::endl; + #ifndef LINUX_BUILD + cin.ignore(); + #endif + return 1; + } + + World *W = DF->getWorld(); + W->Start(); + bool end = false; + while(!end) + { + WeatherType current = (WeatherType) W->ReadCurrentWeather(); + DF->Resume(); + string command = ""; + printWeather(current); + getline(cin, command); + DF->Suspend(); + if(command == "c") + { + W->SetCurrentWeather(CLEAR); + } + else if(command == "r") + { + W->SetCurrentWeather(RAINING); + } + else if(command == "s") + { + W->SetCurrentWeather(SNOWING); + } + else if(command == "q") + { + end = true; + } + } + #ifndef LINUX_BUILD + std::cout << "Done. Press any key to continue" << std::endl; + cin.ignore(); + #endif + DF->Detach(); + return 0; +}