From a4e844ec96a24636f1d3efcb686512564180d2be Mon Sep 17 00:00:00 2001 From: doomchild Date: Mon, 30 Aug 2010 12:48:58 -0500 Subject: [PATCH 01/94] fixed misspelling of BUILD_DFHACK_C_BINDINGS --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b794b7143..ceffb938e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,7 +29,7 @@ SET( DATA_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/output CACHE PATH "Output directory fo OPTION(BUILD_DFHACK_DOCUMENTATION "Create doxygen documentation for developers" OFF) OPTION(BUILD_DFHACK_EXAMPLES "Build example tools" OFF) OPTION(BUILD_DFHACK_PLAYGROUND "Build tools from the playground folder" OFF) -OPTION(BUILD_DFHACK_C_BINDIGS "Build the C portion of the library" ON) +OPTION(BUILD_DFHACK_C_BINDINGS "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) From 315aab0d57e32110e78998c2c402a474ee34f604 Mon Sep 17 00:00:00 2001 From: doomchild Date: Fri, 3 Sep 2010 10:31:06 -0500 Subject: [PATCH 02/94] added registration functions for callbacks, since some languages can't directly access DLL data exports (*cough*P/Invoke*cough*) --- library/DFTypes_C.cpp | 59 ++++++++++++++++++++++++++++ library/include/dfhack-c/DFTypes_C.h | 52 ++++++++++++++++++++---- 2 files changed, 103 insertions(+), 8 deletions(-) diff --git a/library/DFTypes_C.cpp b/library/DFTypes_C.cpp index 9677ae9f1..2f996863e 100644 --- a/library/DFTypes_C.cpp +++ b/library/DFTypes_C.cpp @@ -39,6 +39,9 @@ using namespace std; using namespace DFHack; +#define BUILD(a) a ## BufferCallback +#define REG_MACRO(type_name, type, callback) void BUILD(Register ## type_name) (int (*fptr)(type, uint32_t)) { callback = fptr; } + #ifdef __cplusplus extern "C" { #endif @@ -80,6 +83,62 @@ int (*alloc_vein_buffer_callback)(t_vein*, uint32_t) = NULL; int (*alloc_frozenliquidvein_buffer_callback)(t_frozenliquidvein*, uint32_t) = NULL; int (*alloc_spattervein_buffer_callback)(t_spattervein*, uint32_t) = NULL; +REG_MACRO(Byte, int8_t*, alloc_byte_buffer_callback) +REG_MACRO(Short, int16_t*, alloc_short_buffer_callback) +REG_MACRO(Int, int32_t*, alloc_int_buffer_callback) +REG_MACRO(UByte, uint8_t*, alloc_ubyte_buffer_callback) +REG_MACRO(UShort, uint16_t*, alloc_ushort_buffer_callback) +REG_MACRO(UInt, uint32_t*, alloc_uint_buffer_callback) +REG_MACRO(Char, char*, alloc_char_buffer_callback) +REG_MACRO(Matgloss, t_matgloss*, alloc_matgloss_buffer_callback) +REG_MACRO(DescriptorColor, t_descriptor_color*, alloc_descriptor_buffer_callback) +REG_MACRO(MatglossOther, t_matglossOther*, alloc_matgloss_other_buffer_callback) +REG_MACRO(Feature, t_feature*, alloc_t_feature_buffer_callback) +REG_MACRO(Hotkey, t_hotkey*, alloc_t_hotkey_buffer_callback) +REG_MACRO(Screen, t_screen*, alloc_t_screen_buffer_callback) +REG_MACRO(CustomWorkshop, t_customWorkshop*, alloc_t_customWorkshop_buffer_callback) +REG_MACRO(Material, t_material*, alloc_t_material_buffer_callback) + +void RegisterEmptyColorModifierCallback(int (*funcptr)(c_colormodifier*)) +{ + alloc_empty_colormodifier_callback = funcptr; +} + +void RegisterNewColorModifierCallback(int (*funcptr)(c_colormodifier*, const char*, uint32_t)) +{ + alloc_colormodifier_callback = funcptr; +} + +REG_MACRO(ColorModifier, c_colormodifier*, alloc_colormodifier_buffer_callback) + +void RegisterEmptyCreatureCasteCallback(int (*funcptr)(c_creaturecaste*)) +{ + alloc_empty_creaturecaste_callback = funcptr; +} + +void RegisterNewCreatureCasteCallback(int (*funcptr)(c_creaturecaste*, const char*, const char*, const char*, const char*, uint32_t, uint32_t)) +{ + alloc_creaturecaste_callback = funcptr; +} + +REG_MACRO(CreatureCaste, c_creaturecaste*, alloc_creaturecaste_buffer_callback) + +void RegisterEmptyCreatureTypeCallback(int (*funcptr)(c_creaturetype*)) +{ + alloc_empty_creaturetype_callback = funcptr; +} + +void RegisterNewCreatureTypeCallback(int (*funcptr)(c_creaturetype*, const char*, uint32_t, uint32_t, uint8_t, uint16_t, uint16_t, uint16_t)) +{ + alloc_creaturetype_callback = funcptr; +} + +REG_MACRO(CreatureType, c_creaturetype*, alloc_creaturetype_buffer_callback) + +REG_MACRO(Vein, t_vein*, alloc_vein_buffer_callback) +REG_MACRO(FrozenLiquidVein, t_frozenliquidvein*, alloc_frozenliquidvein_buffer_callback) +REG_MACRO(SpatterVein, t_spattervein*, alloc_spattervein_buffer_callback) + int DFHack_isWallTerrain(int in) { return DFHack::isWallTerrain(in); diff --git a/library/include/dfhack-c/DFTypes_C.h b/library/include/dfhack-c/DFTypes_C.h index 49bd54dc9..39efbd46f 100644 --- a/library/include/dfhack-c/DFTypes_C.h +++ b/library/include/dfhack-c/DFTypes_C.h @@ -54,6 +54,24 @@ 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); +DFHACK_EXPORT void RegisterByteBufferCallback(int (*funcptr)(int8_t*, uint32_t)); +DFHACK_EXPORT void RegisterShortBufferCallback(int (*funcptr)(int16_t*, uint32_t)); +DFHACK_EXPORT void RegisterIntBufferCallback(int (*funcptr)(int32_t*, uint32_t)); + +DFHACK_EXPORT void RegisterUByteBufferCallback(int (*funcptr)(uint8_t*, uint32_t)); +DFHACK_EXPORT void RegisterUShortBufferCallback(int (*funcptr)(uint16_t*, uint32_t)); +DFHACK_EXPORT void RegisterUIntBufferCallback(int (*funcptr)(uint32_t*, uint32_t)); + +DFHACK_EXPORT void RegisterCharBufferCallback(int (*funcptr)(char*, uint32_t)); + +DFHACK_EXPORT void RegisterMatglossBufferCallback(int (*funcptr)(t_matgloss*, uint32_t)); +DFHACK_EXPORT void RegisterDescriptorColorBufferCallback(int (*funcptr)(t_descriptor_color*, uint32_t)); +DFHACK_EXPORT void RegisterMatglossOtherBufferCallback(int (*funcptr)(t_matglossOther*, uint32_t)); + +DFHACK_EXPORT void RegisterFeatureBufferCallback(int (*funcptr)(t_feature*, uint32_t)); +DFHACK_EXPORT void RegisterHotkeyBufferCallback(int (*funcptr)(t_hotkey*, uint32_t)); +DFHACK_EXPORT void RegisterScreenBufferCallback(int (*funcptr)(t_screen*, uint32_t)); + struct t_customWorkshop { uint32_t index; @@ -61,9 +79,11 @@ struct t_customWorkshop }; DFHACK_EXPORT extern int (*alloc_t_customWorkshop_buffer_callback)(t_customWorkshop*, uint32_t); - DFHACK_EXPORT extern int (*alloc_t_material_buffer_callback)(t_material*, uint32_t); +DFHACK_EXPORT void RegisterCustomWorkshopBufferCallback(int (*funcptr)(t_customWorkshop*, uint32_t)); +DFHACK_EXPORT void RegisterMaterialBufferCallback(int (*funcptr)(t_material*, uint32_t)); + struct c_colormodifier { char part[128]; @@ -75,6 +95,10 @@ DFHACK_EXPORT extern int (*alloc_empty_colormodifier_callback)(c_colormodifier*) DFHACK_EXPORT extern int (*alloc_colormodifier_callback)(c_colormodifier*, const char*, uint32_t); DFHACK_EXPORT extern int (*alloc_colormodifier_buffer_callback)(c_colormodifier*, uint32_t); +DFHACK_EXPORT void RegisterEmptyColorModifierCallback(int (*funcptr)(c_colormodifier*)); +DFHACK_EXPORT void RegisterNewColorModifierCallback(int (*funcptr)(c_colormodifier*, const char*, uint32_t)); +DFHACK_EXPORT void RegisterColorModifierBufferCallback(int (*funcptr)(c_colormodifier*, uint32_t)); + struct c_creaturecaste { char rawname[128]; @@ -93,6 +117,10 @@ DFHACK_EXPORT extern int (*alloc_empty_creaturecaste_callback)(c_creaturecaste*) DFHACK_EXPORT extern int (*alloc_creaturecaste_callback)(c_creaturecaste*, const char*, const char*, const char*, const char*, uint32_t, uint32_t); DFHACK_EXPORT extern int (*alloc_creaturecaste_buffer_callback)(c_creaturecaste*, uint32_t); +DFHACK_EXPORT void RegisterEmptyCreatureCasteCallback(int (*funcptr)(c_creaturecaste*)); +DFHACK_EXPORT void RegisterNewCreatureCasteCallback(int (*funcptr)(c_creaturecaste*, const char*, const char*, const char*, const char*, uint32_t, uint32_t)); +DFHACK_EXPORT void RegisterCreatureCasteBufferCallback(int (*funcptr)(c_creaturecaste*, uint32_t)); + struct c_creaturetype { char rawname[128]; @@ -121,14 +149,22 @@ DFHACK_EXPORT extern int (*alloc_vein_buffer_callback)(t_vein*, uint32_t); DFHACK_EXPORT extern int (*alloc_frozenliquidvein_buffer_callback)(t_frozenliquidvein*, uint32_t); DFHACK_EXPORT extern int (*alloc_spattervein_buffer_callback)(t_spattervein*, uint32_t); -DFHACK_EXPORT extern int DFHack_isWallTerrain(int in); -DFHACK_EXPORT extern int DFHack_isFloorTerrain(int in); -DFHACK_EXPORT extern int DFHack_isRampTerrain(int in); -DFHACK_EXPORT extern int DFHack_isStairTerrain(int in); -DFHACK_EXPORT extern int DFHack_isOpenTerrain(int in); -DFHACK_EXPORT extern int DFHack_getVegetationType(int in); +DFHACK_EXPORT void RegisterEmptyCreatureTypeCallback(int (*funcptr)(c_creaturetype*)); +DFHACK_EXPORT void RegisterNewCreatureTypeCallback(int (*funcptr)(c_creaturetype*, const char*, uint32_t, uint32_t, uint8_t, uint16_t, uint16_t, uint16_t)); +DFHACK_EXPORT void RegisterCreatureTypeBufferCallback(int (*funcptr)(c_creaturetype*, uint32_t)); + +DFHACK_EXPORT void RegisterVeinBufferCallback(int (*funcptr)(t_vein*, uint32_t)); +DFHACK_EXPORT void RegisterFrozenLiquidVeinBufferCallback(int (*funcptr)(t_frozenliquidvein*, uint32_t)); +DFHACK_EXPORT void RegisterSpatterVeinBufferCallback(int (*funcptr)(t_spattervein*, uint32_t)); + +DFHACK_EXPORT int DFHack_isWallTerrain(int in); +DFHACK_EXPORT int DFHack_isFloorTerrain(int in); +DFHACK_EXPORT int DFHack_isRampTerrain(int in); +DFHACK_EXPORT int DFHack_isStairTerrain(int in); +DFHACK_EXPORT int DFHack_isOpenTerrain(int in); +DFHACK_EXPORT int DFHack_getVegetationType(int in); -DFHACK_EXPORT extern int DFHack_getTileType(int index, TileRow* tPtr); +DFHACK_EXPORT int DFHack_getTileType(int index, TileRow* tPtr); #ifdef __cplusplus } From 040f8f7b7a3251ed263e6f60cdb5713313a4f378 Mon Sep 17 00:00:00 2001 From: belal Date: Sun, 12 Sep 2010 21:36:31 -0400 Subject: [PATCH 03/94] Add function to get the current working directory of the DF process, as well as offsets for the relative paths of the current tileset and color file, also created a simple program to dump those three things out --- data/Memory-ng.xml | 6 ++++++ library/DFProcess-linux-wine.cpp | 2 +- library/DFProcess-windows-SHM.cpp | 10 +++++++++ library/DFProcess-windows.cpp | 9 ++++++++ library/include/dfhack/DFProcess.h | 5 +++++ library/include/dfhack/modules/Gui.h | 4 ++++ library/modules/Gui.cpp | 28 ++++++++++++++++++++++++ tools/playground/CMakeLists.txt | 7 ++++++ tools/playground/paths.cpp | 32 ++++++++++++++++++++++++++++ 9 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 tools/playground/paths.cpp diff --git a/data/Memory-ng.xml b/data/Memory-ng.xml index f331c10d2..127266adb 100644 --- a/data/Memory-ng.xml +++ b/data/Memory-ng.xml @@ -694,6 +694,8 @@
+
+
@@ -1452,6 +1454,10 @@
+ +
+
+ diff --git a/library/DFProcess-linux-wine.cpp b/library/DFProcess-linux-wine.cpp index 8e8e3c1f5..20b33a9db 100644 --- a/library/DFProcess-linux-wine.cpp +++ b/library/DFProcess-linux-wine.cpp @@ -637,4 +637,4 @@ string WineProcess::readClassName (uint32_t vptr) string raw = readCString(typeinfo + 0xC); // skips the .?AV raw.resize(raw.length() - 2);// trim @@ from end return raw; -} +} \ No newline at end of file diff --git a/library/DFProcess-windows-SHM.cpp b/library/DFProcess-windows-SHM.cpp index 9742ceeca..7941f8c73 100644 --- a/library/DFProcess-windows-SHM.cpp +++ b/library/DFProcess-windows-SHM.cpp @@ -929,6 +929,16 @@ string SHMProcess::readClassName (uint32_t vptr) return raw; } +string SHMProcess::getPath() +{ + HMODULE hmod; + DWORD junk; + char String[255]; + HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, d->process_ID ); //get the handle from the process ID + EnumProcessModules(hProcess, &hmod, 1 * sizeof(HMODULE), &junk); //get the module from the handle + GetModuleFileNameEx(hProcess,hmod,String,sizeof(String)); //get the filename from the module + return(string(String)); +} // get module index by name and version. bool 0 = error bool SHMProcess::getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) { diff --git a/library/DFProcess-windows.cpp b/library/DFProcess-windows.cpp index a658b49a7..697558c5b 100644 --- a/library/DFProcess-windows.cpp +++ b/library/DFProcess-windows.cpp @@ -505,3 +505,12 @@ string NormalProcess::readClassName (uint32_t vptr) raw.resize(raw.length() - 2);// trim @@ from end return raw; } +string NormalProcess::getPath() +{ + HMODULE hmod; + DWORD junk; + char String[255]; + EnumProcessModules(d->my_handle, &hmod, 1 * sizeof(HMODULE), &junk); //get the module from the handle + GetModuleFileNameEx(d->my_handle,hmod,String,sizeof(String)); //get the filename from the module + return(string(String)); +} \ No newline at end of file diff --git a/library/include/dfhack/DFProcess.h b/library/include/dfhack/DFProcess.h index 282e1b95f..8918c1584 100644 --- a/library/include/dfhack/DFProcess.h +++ b/library/include/dfhack/DFProcess.h @@ -163,6 +163,8 @@ namespace DFHack virtual VersionInfo *getDescriptor() = 0; /// get the DF Process ID virtual int getPID() = 0; + /// get the DF Process FilePath + virtual std::string getPath() = 0; /// get module index by name and version. bool 1 = error virtual bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) = 0; /// get the SHM start if available @@ -230,6 +232,7 @@ namespace DFHack void getMemRanges(std::vector & ranges ); VersionInfo *getDescriptor(); int getPID(); + std::string getPath(); // 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;}; // get the SHM start if available @@ -295,6 +298,7 @@ namespace DFHack void getMemRanges(std::vector & ranges ); VersionInfo *getDescriptor(); int getPID(); + std::string getPath(); // get module index by name and version. bool 1 = error bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT); // get the SHM start if available @@ -364,6 +368,7 @@ namespace DFHack // get the SHM start if available char * getSHMStart (void){return 0;}; bool SetAndWait (uint32_t state){return false;}; + std::string getPath() {return std::string()}; //FIXME should be pretty trival }; #endif } diff --git a/library/include/dfhack/modules/Gui.h b/library/include/dfhack/modules/Gui.h index 6ac91f35c..64cf06d97 100644 --- a/library/include/dfhack/modules/Gui.h +++ b/library/include/dfhack/modules/Gui.h @@ -28,6 +28,10 @@ namespace DFHack bool ReadViewScreen(t_viewscreen &); /// read the DF menu state (designation menu ect) uint32_t ReadMenuState(); + /// read the current tileset file used in DF + string ReadCurrentTileSetFilename(); + /// read the current color file used in DF + string ReadCurrentColorsFilename(); private: struct Private; diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index 177a00467..15b5a0959 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -44,6 +44,10 @@ struct Gui::Private bool ViewScreeInited; uint32_t current_menu_state_offset; bool MenuStateInited; + uint32_t tileset_filename_offset; + bool TilesetFilenameInited; + uint32_t colors_filename_offset; + bool ColorsFilenameInited; DFContextShared *d; Process * owner; }; @@ -73,6 +77,18 @@ Gui::Gui(DFContextShared * _d) d->ViewScreeInited = true; } catch(exception &){}; + try + { + d->tileset_filename_offset = OG_Gui->getAddress ("tileset_filename"); + d->TilesetFilenameInited = true; + } + catch(exception &){}; + try + { + d->colors_filename_offset = OG_Gui->getAddress ("colors_filename"); + d->ColorsFilenameInited = true; + } + catch(exception &){}; d->Started = true; } @@ -129,3 +145,15 @@ bool Gui::ReadViewScreen (t_viewscreen &screen) } return d->d->offset_descriptor->resolveObjectToClassID (last, screen.type); } +string Gui::ReadCurrentTileSetFilename() +{ + if(d->TilesetFilenameInited) + return(d->owner->readCString(d->tileset_filename_offset)); + return ""; +} +string Gui::ReadCurrentColorsFilename() +{ + if(d->ColorsFilenameInited) + return(d->owner->readCString(d->colors_filename_offset)); + return ""; +} \ No newline at end of file diff --git a/tools/playground/CMakeLists.txt b/tools/playground/CMakeLists.txt index ab21e3c2d..f21d9170c 100644 --- a/tools/playground/CMakeLists.txt +++ b/tools/playground/CMakeLists.txt @@ -60,6 +60,13 @@ TARGET_LINK_LIBRARIES(dfcatsplosion dfhack) ADD_EXECUTABLE(dfcopypaste copypaste.cpp) TARGET_LINK_LIBRARIES(dfcopypaste dfhack) +# paths +# Author: belal +# dumps the current path to the DF exe, as well as the relative paths to the +# current tileset and color files +ADD_EXECUTABLE(dfpaths paths.cpp) +TARGET_LINK_LIBRARIES(dfpaths dfhack) + # this needs the C bindings IF(BUILD_DFHACK_C_BINDINGS) # for trying out some 'stuff' diff --git a/tools/playground/paths.cpp b/tools/playground/paths.cpp new file mode 100644 index 000000000..5ae3cd37a --- /dev/null +++ b/tools/playground/paths.cpp @@ -0,0 +1,32 @@ +#include +using namespace std; + +#include +using namespace DFHack; + +int main () +{ + DFHack::ContextManager DFMgr("Memory.xml"); + DFHack::Context *DF = DFMgr.getSingleContext(); + try + { + DF->Attach(); + } + catch (exception& e) + { + cerr << e.what() << endl; + #ifndef LINUX_BUILD + cin.ignore(); + #endif + return 1; + } + DFHack::Process * Process = DF->getProcess(); + DFHack::Gui * gui = DF->getGui(); + cout << Process->getPath() << endl; + cout << gui->ReadCurrentTileSetFilename() << "\n" << gui->ReadCurrentColorsFilename() << endl; + #ifndef LINUX_BUILD + cout << "Done. Press any key to continue" << endl; + cin.ignore(); + #endif + return 0; +} \ No newline at end of file From d2db7524a1a6744854f0fec94a8f42d65f664600 Mon Sep 17 00:00:00 2001 From: belal Date: Mon, 13 Sep 2010 09:45:53 -0400 Subject: [PATCH 04/94] Keeping the current working directory addition, but reverting the current tileset and color stuff, as the tileset was just an initializer, not the actual current one, just going to have to read the init.txt file myself Revert "Add function to get the current working directory of the DF process, as well as offsets for the relative paths of the current tileset and color file, also created a simple program to dump those three things out" This reverts commit 040f8f7b7a3251ed263e6f60cdb5713313a4f378. --- data/Memory-ng.xml | 6 ------ library/include/dfhack/modules/Gui.h | 4 ---- library/modules/Gui.cpp | 28 ---------------------------- tools/playground/paths.cpp | 1 - 4 files changed, 39 deletions(-) diff --git a/data/Memory-ng.xml b/data/Memory-ng.xml index 127266adb..f331c10d2 100644 --- a/data/Memory-ng.xml +++ b/data/Memory-ng.xml @@ -694,8 +694,6 @@
-
-
@@ -1454,10 +1452,6 @@
- -
-
- diff --git a/library/include/dfhack/modules/Gui.h b/library/include/dfhack/modules/Gui.h index 64cf06d97..6ac91f35c 100644 --- a/library/include/dfhack/modules/Gui.h +++ b/library/include/dfhack/modules/Gui.h @@ -28,10 +28,6 @@ namespace DFHack bool ReadViewScreen(t_viewscreen &); /// read the DF menu state (designation menu ect) uint32_t ReadMenuState(); - /// read the current tileset file used in DF - string ReadCurrentTileSetFilename(); - /// read the current color file used in DF - string ReadCurrentColorsFilename(); private: struct Private; diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index 15b5a0959..177a00467 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -44,10 +44,6 @@ struct Gui::Private bool ViewScreeInited; uint32_t current_menu_state_offset; bool MenuStateInited; - uint32_t tileset_filename_offset; - bool TilesetFilenameInited; - uint32_t colors_filename_offset; - bool ColorsFilenameInited; DFContextShared *d; Process * owner; }; @@ -77,18 +73,6 @@ Gui::Gui(DFContextShared * _d) d->ViewScreeInited = true; } catch(exception &){}; - try - { - d->tileset_filename_offset = OG_Gui->getAddress ("tileset_filename"); - d->TilesetFilenameInited = true; - } - catch(exception &){}; - try - { - d->colors_filename_offset = OG_Gui->getAddress ("colors_filename"); - d->ColorsFilenameInited = true; - } - catch(exception &){}; d->Started = true; } @@ -145,15 +129,3 @@ bool Gui::ReadViewScreen (t_viewscreen &screen) } return d->d->offset_descriptor->resolveObjectToClassID (last, screen.type); } -string Gui::ReadCurrentTileSetFilename() -{ - if(d->TilesetFilenameInited) - return(d->owner->readCString(d->tileset_filename_offset)); - return ""; -} -string Gui::ReadCurrentColorsFilename() -{ - if(d->ColorsFilenameInited) - return(d->owner->readCString(d->colors_filename_offset)); - return ""; -} \ No newline at end of file diff --git a/tools/playground/paths.cpp b/tools/playground/paths.cpp index 5ae3cd37a..cc00f79a3 100644 --- a/tools/playground/paths.cpp +++ b/tools/playground/paths.cpp @@ -23,7 +23,6 @@ int main () DFHack::Process * Process = DF->getProcess(); DFHack::Gui * gui = DF->getGui(); cout << Process->getPath() << endl; - cout << gui->ReadCurrentTileSetFilename() << "\n" << gui->ReadCurrentColorsFilename() << endl; #ifndef LINUX_BUILD cout << "Done. Press any key to continue" << endl; cin.ignore(); From 78a12876d5686a80e8547774de5504fe6eacd809 Mon Sep 17 00:00:00 2001 From: doomchild Date: Thu, 16 Sep 2010 13:04:09 -0500 Subject: [PATCH 05/94] added ReadInventoryIdx and ReadInventoryPtr wrappers --- .../include/dfhack-c/modules/Creatures_C.h | 3 + library/modules/Creatures_C.cpp | 58 +++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/library/include/dfhack-c/modules/Creatures_C.h b/library/include/dfhack-c/modules/Creatures_C.h index 16c357e58..34d145bde 100644 --- a/library/include/dfhack-c/modules/Creatures_C.h +++ b/library/include/dfhack-c/modules/Creatures_C.h @@ -45,6 +45,9 @@ DFHACK_EXPORT int32_t Creatures_ReadCreatureInBox(DFHackObject* cPtr, const int3 DFHACK_EXPORT int Creatures_ReadCreature(DFHackObject* cPtr, const int32_t index, t_creature* furball); DFHACK_EXPORT t_material* Creatures_ReadJob(DFHackObject* cPtr, const t_creature* furball); +DFHACK_EXPORT uint32_t* Creatures_ReadInventoryIdx(DFHackObject* cPtr, const uint32_t index); +DFHACK_EXPORT uint32_t* Creatures_ReadInventoryPtr(DFHackObject* cPtr, const uint32_t index); + DFHACK_EXPORT uint32_t Creatures_GetDwarfRaceIndex(DFHackObject* cPtr); DFHACK_EXPORT int32_t Creatures_GetDwarfCivId(DFHackObject* cPtr); diff --git a/library/modules/Creatures_C.cpp b/library/modules/Creatures_C.cpp index 1370258b2..a9b3f9191 100644 --- a/library/modules/Creatures_C.cpp +++ b/library/modules/Creatures_C.cpp @@ -104,6 +104,64 @@ t_material* Creatures_ReadJob(DFHackObject* cPtr, const t_creature* furball) return NULL; } +uint32_t* Creatures_ReadInventoryIdx(DFHackObject* cPtr, const uint32_t index) +{ + if(cPtr != NULL) + { + std::vector item; + + if(((DFHack::Creatures*)cPtr)->ReadInventoryIdx(index, item)) + { + if(item.size() <= 0) + return NULL; + + uint32_t* buf; + + (*alloc_uint_buffer_callback)(buf, item.size()); + + if(buf != NULL) + { + copy(item.begin(), item.end(), buf); + + return buf; + } + else + return NULL; + } + } + + return NULL; +} + +uint32_t* Creatures_ReadInventoryPtr(DFHackObject* cPtr, const uint32_t index) +{ + if(cPtr != NULL) + { + std::vector item; + + if(((DFHack::Creatures*)cPtr)->ReadInventoryPtr(index, item)) + { + if(item.size() <= 0) + return NULL; + + uint32_t* buf; + + (*alloc_uint_buffer_callback)(buf, item.size()); + + if(buf != NULL) + { + copy(item.begin(), item.end(), buf); + + return buf; + } + else + return NULL; + } + } + + return NULL; +} + uint32_t Creatures_GetDwarfRaceIndex(DFHackObject* cPtr) { if(cPtr != NULL) From 70b1a48cea444be8f36bc82087a21fda38b64b79 Mon Sep 17 00:00:00 2001 From: doomchild Date: Thu, 16 Sep 2010 13:04:52 -0500 Subject: [PATCH 06/94] added unregistration functions for callbacks --- library/DFTypes_C.cpp | 74 ++++++++++++++++++++++++++++ library/include/dfhack-c/DFTypes_C.h | 41 +++++++++++++++ 2 files changed, 115 insertions(+) diff --git a/library/DFTypes_C.cpp b/library/DFTypes_C.cpp index 2f996863e..0c885e8e4 100644 --- a/library/DFTypes_C.cpp +++ b/library/DFTypes_C.cpp @@ -39,9 +39,31 @@ using namespace std; using namespace DFHack; +/* +I believe this is what they call "the bad kind of clever", but writing out registration functions for each callback just feels *so* wrong... + +The output of this macro is something like this... + +void RegisterByteBufferCallback(int(*fptr)(int8_t*, uint32_t)) +{ + alloc_byte_buffer_callback = fptr; +} + +*/ #define BUILD(a) a ## BufferCallback #define REG_MACRO(type_name, type, callback) void BUILD(Register ## type_name) (int (*fptr)(type, uint32_t)) { callback = fptr; } +/* +The output of this macro is something like this... + +void UnregisterByteBufferCallback() +{ + alloc_byte_buffer_callback = NULL; +} + +*/ +#define UNREG_MACRO(type_name, callback) void BUILD(Unregister ## type_name) () { callback = NULL; } + #ifdef __cplusplus extern "C" { #endif @@ -99,6 +121,22 @@ REG_MACRO(Screen, t_screen*, alloc_t_screen_buffer_callback) REG_MACRO(CustomWorkshop, t_customWorkshop*, alloc_t_customWorkshop_buffer_callback) REG_MACRO(Material, t_material*, alloc_t_material_buffer_callback) +UNREG_MACRO(Byte, alloc_byte_buffer_callback) +UNREG_MACRO(Short, alloc_short_buffer_callback) +UNREG_MACRO(Int, alloc_int_buffer_callback) +UNREG_MACRO(UByte, alloc_ubyte_buffer_callback) +UNREG_MACRO(UShort, alloc_ushort_buffer_callback) +UNREG_MACRO(UInt, alloc_uint_buffer_callback) +UNREG_MACRO(Char, alloc_char_buffer_callback) +UNREG_MACRO(Matgloss, alloc_matgloss_buffer_callback) +UNREG_MACRO(DescriptorColor, alloc_descriptor_buffer_callback) +UNREG_MACRO(MatglossOther, alloc_matgloss_other_buffer_callback) +UNREG_MACRO(Feature, alloc_t_feature_buffer_callback) +UNREG_MACRO(Hotkey, alloc_t_hotkey_buffer_callback) +UNREG_MACRO(Screen, alloc_t_screen_buffer_callback) +UNREG_MACRO(CustomWorkshop, alloc_t_customWorkshop_buffer_callback) +UNREG_MACRO(Material, alloc_t_material_buffer_callback) + void RegisterEmptyColorModifierCallback(int (*funcptr)(c_colormodifier*)) { alloc_empty_colormodifier_callback = funcptr; @@ -116,12 +154,33 @@ void RegisterEmptyCreatureCasteCallback(int (*funcptr)(c_creaturecaste*)) alloc_empty_creaturecaste_callback = funcptr; } +void UnregisterEmptyColorModifierCallback() +{ + alloc_empty_colormodifier_callback = NULL; +} + +void UnregisterNewColorModifierCallback() +{ + alloc_colormodifier_callback = NULL; +} + void RegisterNewCreatureCasteCallback(int (*funcptr)(c_creaturecaste*, const char*, const char*, const char*, const char*, uint32_t, uint32_t)) { alloc_creaturecaste_callback = funcptr; } REG_MACRO(CreatureCaste, c_creaturecaste*, alloc_creaturecaste_buffer_callback) +UNREG_MACRO(CreatureCaste, alloc_creaturecaste_buffer_callback) + +void UnregisterEmptyCreatureCasteCallback() +{ + alloc_empty_creaturecaste_callback = NULL; +} + +void UnregisterNewCreatureCasteCallback() +{ + alloc_creaturecaste_callback = NULL; +} void RegisterEmptyCreatureTypeCallback(int (*funcptr)(c_creaturetype*)) { @@ -134,11 +193,26 @@ void RegisterNewCreatureTypeCallback(int (*funcptr)(c_creaturetype*, const char* } REG_MACRO(CreatureType, c_creaturetype*, alloc_creaturetype_buffer_callback) +UNREG_MACRO(CreatureType, alloc_creaturetype_buffer_callback) + +void UnregisterEmptyCreatureTypeCallback() +{ + alloc_empty_creaturetype_callback = NULL; +} + +void UnregisterNewCreatureTypeCallback() +{ + alloc_creaturetype_callback = NULL; +} REG_MACRO(Vein, t_vein*, alloc_vein_buffer_callback) REG_MACRO(FrozenLiquidVein, t_frozenliquidvein*, alloc_frozenliquidvein_buffer_callback) REG_MACRO(SpatterVein, t_spattervein*, alloc_spattervein_buffer_callback) +UNREG_MACRO(Vein, alloc_vein_buffer_callback) +UNREG_MACRO(FrozenLiquidVein, alloc_frozenliquidvein_buffer_callback) +UNREG_MACRO(SpatterVein, alloc_spattervein_buffer_callback) + int DFHack_isWallTerrain(int in) { return DFHack::isWallTerrain(in); diff --git a/library/include/dfhack-c/DFTypes_C.h b/library/include/dfhack-c/DFTypes_C.h index 39efbd46f..772a0be04 100644 --- a/library/include/dfhack-c/DFTypes_C.h +++ b/library/include/dfhack-c/DFTypes_C.h @@ -32,6 +32,11 @@ distribution. #include "dfhack/modules/Position.h" #include "dfhack/DFTileTypes.h" +#define HBUILD(a) a ## BufferCallback +#define HREG_MACRO(type_name, type) DFHACK_EXPORT void HBUILD(Register ## type_name) (int (*funcptr)(type, uint32_t)); + +#define HUNREG_MACRO(type_name) DFHACK_EXPORT void HBUILD(Unregister ## type_name) (); + #ifdef __cplusplus extern "C" { #endif @@ -72,6 +77,23 @@ DFHACK_EXPORT void RegisterFeatureBufferCallback(int (*funcptr)(t_feature*, uint DFHACK_EXPORT void RegisterHotkeyBufferCallback(int (*funcptr)(t_hotkey*, uint32_t)); DFHACK_EXPORT void RegisterScreenBufferCallback(int (*funcptr)(t_screen*, uint32_t)); +HUNREG_MACRO(Byte) +HUNREG_MACRO(Short) +HUNREG_MACRO(Int) +HUNREG_MACRO(UByte) +HUNREG_MACRO(UShort) +HUNREG_MACRO(UInt) + +HUNREG_MACRO(Char) + +HUNREG_MACRO(Matgloss) +HUNREG_MACRO(DescriptorColor) +HUNREG_MACRO(MatglossOther) + +HUNREG_MACRO(Feature) +HUNREG_MACRO(Hotkey) +HUNREG_MACRO(Screen) + struct t_customWorkshop { uint32_t index; @@ -84,6 +106,9 @@ DFHACK_EXPORT extern int (*alloc_t_material_buffer_callback)(t_material*, uint32 DFHACK_EXPORT void RegisterCustomWorkshopBufferCallback(int (*funcptr)(t_customWorkshop*, uint32_t)); DFHACK_EXPORT void RegisterMaterialBufferCallback(int (*funcptr)(t_material*, uint32_t)); +HUNREG_MACRO(CustomWorkshop) +HUNREG_MACRO(Material) + struct c_colormodifier { char part[128]; @@ -99,6 +124,10 @@ DFHACK_EXPORT void RegisterEmptyColorModifierCallback(int (*funcptr)(c_colormodi DFHACK_EXPORT void RegisterNewColorModifierCallback(int (*funcptr)(c_colormodifier*, const char*, uint32_t)); DFHACK_EXPORT void RegisterColorModifierBufferCallback(int (*funcptr)(c_colormodifier*, uint32_t)); +DFHACK_EXPORT void UnregisterEmptyColorModifierCallback(); +DFHACK_EXPORT void UnregisterNewColorModifierCallback(); +HUNREG_MACRO(ColorModifier) + struct c_creaturecaste { char rawname[128]; @@ -121,6 +150,10 @@ DFHACK_EXPORT void RegisterEmptyCreatureCasteCallback(int (*funcptr)(c_creaturec DFHACK_EXPORT void RegisterNewCreatureCasteCallback(int (*funcptr)(c_creaturecaste*, const char*, const char*, const char*, const char*, uint32_t, uint32_t)); DFHACK_EXPORT void RegisterCreatureCasteBufferCallback(int (*funcptr)(c_creaturecaste*, uint32_t)); +DFHACK_EXPORT void UnregisterEmptyCreatureCasteCallback(); +DFHACK_EXPORT void UnregisterNewCreatureCasteCallback(); +HUNREG_MACRO(CreatureCaste) + struct c_creaturetype { char rawname[128]; @@ -157,6 +190,14 @@ DFHACK_EXPORT void RegisterVeinBufferCallback(int (*funcptr)(t_vein*, uint32_t)) DFHACK_EXPORT void RegisterFrozenLiquidVeinBufferCallback(int (*funcptr)(t_frozenliquidvein*, uint32_t)); DFHACK_EXPORT void RegisterSpatterVeinBufferCallback(int (*funcptr)(t_spattervein*, uint32_t)); +DFHACK_EXPORT void UnregisterEmptyCreatureTypeCallback(); +DFHACK_EXPORT void UnregisterNewCreatureTypeCallback(); +HUNREG_MACRO(CreatureType) + +HUNREG_MACRO(Vein) +HUNREG_MACRO(FrozenLiquidVein) +HUNREG_MACRO(SpatterVein) + DFHACK_EXPORT int DFHack_isWallTerrain(int in); DFHACK_EXPORT int DFHack_isFloorTerrain(int in); DFHACK_EXPORT int DFHack_isRampTerrain(int in); From 9844a8f8b3843d6c3ed4ff2f317605b2c95d3b65 Mon Sep 17 00:00:00 2001 From: doomchild Date: Thu, 16 Sep 2010 13:10:04 -0500 Subject: [PATCH 07/94] added SetPauseState wrapper --- library/include/dfhack-c/modules/Gui_C.h | 1 + library/modules/Gui_C.cpp | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/library/include/dfhack-c/modules/Gui_C.h b/library/include/dfhack-c/modules/Gui_C.h index 8cc737f78..d57a874da 100644 --- a/library/include/dfhack-c/modules/Gui_C.h +++ b/library/include/dfhack-c/modules/Gui_C.h @@ -37,6 +37,7 @@ DFHACK_EXPORT int Gui_Start(DFHackObject* gui); DFHACK_EXPORT int Gui_Finish(DFHackObject* gui); DFHACK_EXPORT int Gui_ReadPauseState(DFHackObject* gui); +DFHACK_EXPORT int Gui_SetPauseState(DFHackObject* gui, int8_t paused); DFHACK_EXPORT int Gui_ReadViewScreen(DFHackObject* gui, t_viewscreen* viewscreen); DFHACK_EXPORT int Gui_ReadMenuState(DFHackObject* gui, uint32_t* menuState); diff --git a/library/modules/Gui_C.cpp b/library/modules/Gui_C.cpp index 8870b4e87..d2696370b 100644 --- a/library/modules/Gui_C.cpp +++ b/library/modules/Gui_C.cpp @@ -58,6 +58,23 @@ int Gui_ReadPauseState(DFHackObject* gui) return -1; } +int Gui_SetPauseState(DFHackObject* gui, int8_t paused) +{ + if(gui != NULL) + { + bool pauseState = false; + + if(paused > 0) + pauseState = true; + + ((DFHack::Gui*)gui)->SetPauseState(pauseState); + + return 1; + } + + return -1; +} + int Gui_ReadViewScreen(DFHackObject* gui, t_viewscreen* viewscreen) { if(gui != NULL) From 6661d7e1f766e169a94dc21d29718e70bbf3659e Mon Sep 17 00:00:00 2001 From: belal Date: Thu, 16 Sep 2010 18:21:41 -0700 Subject: [PATCH 08/94] added getPath() for all linux versions as well, should work fine --- library/DFProcess-linux-SHM.cpp | 11 +++++++++++ library/DFProcess-linux-wine.cpp | 13 ++++++++++++- library/DFProcess-linux.cpp | 11 +++++++++++ library/include/dfhack/DFProcess.h | 2 +- 4 files changed, 35 insertions(+), 2 deletions(-) diff --git a/library/DFProcess-linux-SHM.cpp b/library/DFProcess-linux-SHM.cpp index ace2dacf8..1432dc2c1 100644 --- a/library/DFProcess-linux-SHM.cpp +++ b/library/DFProcess-linux-SHM.cpp @@ -920,3 +920,14 @@ bool SHMProcess::Private::Aux_Core_Attach(bool & versionOK, pid_t & PID) #endif return true; } +string SHMProcess::getPath() +{ + char cwd_name[256]; + char target_name[1024]; + int target_result; + + sprintf(cwd_name,"/proc/%d/cwd", getPID()); + // resolve /proc/PID/exe link + target_result = readlink(cwd_name, target_name, sizeof(target_name)); + return(string(target_name)); +} diff --git a/library/DFProcess-linux-wine.cpp b/library/DFProcess-linux-wine.cpp index 20b33a9db..489118d5b 100644 --- a/library/DFProcess-linux-wine.cpp +++ b/library/DFProcess-linux-wine.cpp @@ -637,4 +637,15 @@ string WineProcess::readClassName (uint32_t vptr) string raw = readCString(typeinfo + 0xC); // skips the .?AV raw.resize(raw.length() - 2);// trim @@ from end return raw; -} \ No newline at end of file +} +string WineProcess::getPath() +{ + char cwd_name[256]; + char target_name[1024]; + int target_result; + + sprintf(cwd_name,"/proc/%d/cwd", getPID()); + // resolve /proc/PID/exe link + target_result = readlink(cwd_name, target_name, sizeof(target_name)); + return(string(target_name)); +} diff --git a/library/DFProcess-linux.cpp b/library/DFProcess-linux.cpp index 164834543..932847f2e 100644 --- a/library/DFProcess-linux.cpp +++ b/library/DFProcess-linux.cpp @@ -586,3 +586,14 @@ string NormalProcess::readClassName (uint32_t vptr) size_t end = raw.length(); return raw.substr(start,end-start); } +string NormalProcess::getPath() +{ + char cwd_name[256]; + char target_name[1024]; + int target_result; + + sprintf(cwd_name,"/proc/%d/cwd", getPID()); + // resolve /proc/PID/exe link + target_result = readlink(cwd_name, target_name, sizeof(target_name)); + return(string(target_name)); +} diff --git a/library/include/dfhack/DFProcess.h b/library/include/dfhack/DFProcess.h index 8918c1584..3743cf4b7 100644 --- a/library/include/dfhack/DFProcess.h +++ b/library/include/dfhack/DFProcess.h @@ -368,7 +368,7 @@ namespace DFHack // get the SHM start if available char * getSHMStart (void){return 0;}; bool SetAndWait (uint32_t state){return false;}; - std::string getPath() {return std::string()}; //FIXME should be pretty trival + std::string getPath(); }; #endif } From 3dfbc5fb211507df69043b01dd20286231ad1a5d Mon Sep 17 00:00:00 2001 From: belal Date: Thu, 16 Sep 2010 21:44:38 -0400 Subject: [PATCH 09/94] update widows getPath to only output the path, not the path and exe filename, to correspond with the linux versions --- library/DFProcess-windows-SHM.cpp | 3 ++- library/DFProcess-windows.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/library/DFProcess-windows-SHM.cpp b/library/DFProcess-windows-SHM.cpp index 7941f8c73..aa9d50dfe 100644 --- a/library/DFProcess-windows-SHM.cpp +++ b/library/DFProcess-windows-SHM.cpp @@ -937,7 +937,8 @@ string SHMProcess::getPath() HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, d->process_ID ); //get the handle from the process ID EnumProcessModules(hProcess, &hmod, 1 * sizeof(HMODULE), &junk); //get the module from the handle GetModuleFileNameEx(hProcess,hmod,String,sizeof(String)); //get the filename from the module - return(string(String)); + string out(String); + return(out.substr(0,out.find_last_of("\\"))); } // get module index by name and version. bool 0 = error bool SHMProcess::getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) diff --git a/library/DFProcess-windows.cpp b/library/DFProcess-windows.cpp index 697558c5b..9471116aa 100644 --- a/library/DFProcess-windows.cpp +++ b/library/DFProcess-windows.cpp @@ -512,5 +512,6 @@ string NormalProcess::getPath() char String[255]; EnumProcessModules(d->my_handle, &hmod, 1 * sizeof(HMODULE), &junk); //get the module from the handle GetModuleFileNameEx(d->my_handle,hmod,String,sizeof(String)); //get the filename from the module - return(string(String)); + string out(String); + return(out.substr(0,out.find_last_of("\\"))); } \ No newline at end of file From 918de0271ba1167b86257a56094b5d371ee07740 Mon Sep 17 00:00:00 2001 From: belal Date: Fri, 17 Sep 2010 09:20:15 -0400 Subject: [PATCH 10/94] fix to get the windowIO.h to compile from a submodule --- library/include/dfhack/modules/WindowIO.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/include/dfhack/modules/WindowIO.h b/library/include/dfhack/modules/WindowIO.h index 6e1af9fcb..5244d2a1c 100644 --- a/library/include/dfhack/modules/WindowIO.h +++ b/library/include/dfhack/modules/WindowIO.h @@ -25,9 +25,9 @@ distribution. #ifndef KEYS_H_INCLUDED #define KEYS_H_INCLUDED -#include "dfhack/DFPragma.h" -#include "dfhack/DFExport.h" -#include "dfhack/DFModule.h" +#include "../DFPragma.h" +#include "../DFExport.h" +#include "../DFModule.h" namespace DFHack { From 0f7a27d611db33c5f0208a177cb8002014c9b2a5 Mon Sep 17 00:00:00 2001 From: belal Date: Sun, 19 Sep 2010 19:49:45 -0400 Subject: [PATCH 11/94] fix the WindowIO-windows.cpp module to work correctly with the new DF, also made it a little simpler. --- library/modules/WindowIO-windows.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/library/modules/WindowIO-windows.cpp b/library/modules/WindowIO-windows.cpp index 37c5eb08c..1a432ade4 100644 --- a/library/modules/WindowIO-windows.cpp +++ b/library/modules/WindowIO-windows.cpp @@ -130,20 +130,19 @@ WindowIO::~WindowIO () void WindowIO::TypeStr (const char *input, int delay, bool useShift) { //sendmessage needs a window handle HWND, so have to get that from the process HANDLE - HWND currentWindow = GetForegroundWindow(); window myWindow; myWindow.pid = d->p->getPID(); EnumWindows (EnumWindowsProc, (LPARAM) &myWindow); - char cChar; - DWORD dfProccess = GetWindowThreadProcessId(myWindow.windowHandle,NULL); - DWORD currentProccess = GetWindowThreadProcessId(currentWindow,NULL); - AttachThreadInput(currentProccess,dfProccess,TRUE); //The two threads have to have attached input in order to change the keyboard state, which is needed to set the shift state + DWORD dfProcess = GetWindowThreadProcessId(myWindow.windowHandle,NULL); + DWORD currentProcess = GetCurrentThreadId(); + AttachThreadInput(currentProcess,dfProcess,TRUE); //The two threads have to have attached input in order to change the keyboard state, which is needed to set the shift state while ( (cChar = *input++)) // loops through chars { short vk = VkKeyScan (cChar); // keycode of char if (useShift || (vk >> 8) &1) // char is capital, so need to hold down shift { + vk = vk & 0xFF; // remove the shift state from the virtual key code BYTE keybstate[256] = {0}; BYTE keybstateOrig[256] = {0}; GetKeyboardState((LPBYTE)&keybstateOrig); @@ -160,7 +159,7 @@ void WindowIO::TypeStr (const char *input, int delay, bool useShift) SendMessage(myWindow.windowHandle,WM_KEYUP,vk,0); } } - AttachThreadInput(currentProccess,dfProccess,FALSE); //detach the threads + AttachThreadInput(currentProcess,dfProcess,FALSE); //detach the threads Sleep (delay); } From 1a5bce53a7e339aa96017a193c160f48a759cab0 Mon Sep 17 00:00:00 2001 From: doomchild Date: Mon, 20 Sep 2010 12:39:50 -0500 Subject: [PATCH 12/94] added ReadGeology --- library/include/dfhack-c/modules/Maps_C.h | 2 ++ library/modules/Maps_C.cpp | 42 +++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/library/include/dfhack-c/modules/Maps_C.h b/library/include/dfhack-c/modules/Maps_C.h index fdbfdf1be..3199fc3af 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 uint16_t* Maps_ReadGeology(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); diff --git a/library/modules/Maps_C.cpp b/library/modules/Maps_C.cpp index 911f4e0f9..9aacf8a0b 100644 --- a/library/modules/Maps_C.cpp +++ b/library/modules/Maps_C.cpp @@ -54,6 +54,48 @@ int Maps_Finish(DFHackObject* maps) return -1; } +uint16_t* Maps_ReadGeology(DFHackObject* maps) +{ + if(maps != NULL) + { + std::vector < std::vector > geology; + + if(((DFHack::Maps*)maps)->ReadGeology(geology)) + { + uint16_t* buf; + uint32_t geoLength = 0; + + for(int i = 0; i < geology.size(); i++) + { + for(int j = 0; j < geology[i].size(); j++) + { + geoLength += geology[i].size(); + } + } + + (*alloc_ushort_buffer_callback)(buf, geoLength); + + if(buf != NULL) + { + uint16_t* bufCopyPtr = buf; + + for(int i = 0; i < geology.size(); i++) + { + copy(geology[i].begin(), geology[i].end(), bufCopyPtr); + + bufCopyPtr += geology[i].size(); + } + + return buf; + } + else + return NULL; + } + } + + return NULL; +} + t_feature* Maps_ReadGlobalFeatures(DFHackObject* maps) { if(maps != NULL) From 583f997e2fe0c3935e7ffa7e282c848d6663e3df Mon Sep 17 00:00:00 2001 From: belal Date: Thu, 23 Sep 2010 08:33:45 -0400 Subject: [PATCH 13/94] fix linux getPaths to append a null terminator on the strings --- library/DFProcess-linux-SHM.cpp | 1 + library/DFProcess-linux-wine.cpp | 1 + library/DFProcess-linux.cpp | 1 + 3 files changed, 3 insertions(+) diff --git a/library/DFProcess-linux-SHM.cpp b/library/DFProcess-linux-SHM.cpp index 1432dc2c1..6f6bedb34 100644 --- a/library/DFProcess-linux-SHM.cpp +++ b/library/DFProcess-linux-SHM.cpp @@ -929,5 +929,6 @@ string SHMProcess::getPath() sprintf(cwd_name,"/proc/%d/cwd", getPID()); // resolve /proc/PID/exe link target_result = readlink(cwd_name, target_name, sizeof(target_name)); + target_name[target_result] = '\0'; return(string(target_name)); } diff --git a/library/DFProcess-linux-wine.cpp b/library/DFProcess-linux-wine.cpp index f92d4b5cd..8ab9bc689 100644 --- a/library/DFProcess-linux-wine.cpp +++ b/library/DFProcess-linux-wine.cpp @@ -633,5 +633,6 @@ string WineProcess::getPath() sprintf(cwd_name,"/proc/%d/cwd", getPID()); // resolve /proc/PID/exe link target_result = readlink(cwd_name, target_name, sizeof(target_name)); + target_name[target_result] = '\0'; return(string(target_name)); } diff --git a/library/DFProcess-linux.cpp b/library/DFProcess-linux.cpp index 932847f2e..24bff365a 100644 --- a/library/DFProcess-linux.cpp +++ b/library/DFProcess-linux.cpp @@ -595,5 +595,6 @@ string NormalProcess::getPath() sprintf(cwd_name,"/proc/%d/cwd", getPID()); // resolve /proc/PID/exe link target_result = readlink(cwd_name, target_name, sizeof(target_name)); + target_name[target_result] = '\0'; return(string(target_name)); } From eb7a6cdb652d3b30349d16c6082e2733296227f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Sun, 26 Sep 2010 00:41:03 +0200 Subject: [PATCH 14/94] 31.14 Windows - Maps, Materials --- data/Memory-ng.xml | 47 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/data/Memory-ng.xml b/data/Memory-ng.xml index 7f7e4c48c..6d9cbaaf3 100644 --- a/data/Memory-ng.xml +++ b/data/Memory-ng.xml @@ -1635,7 +1635,52 @@ - + + + + + + + + +
+ + +
+ + + +
+
+ + + YES +
+
+
+
+
+ + +
+
+ + + + .-"""-. ' \ |,. ,-. | _________________________ From 2081819a35b5c2b4e36942a4fabd24d6d3842f3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Sun, 26 Sep 2010 03:58:54 +0200 Subject: [PATCH 15/94] Base Creatures support, missing many advanced features... --- data/Memory-ng.xml | 69 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 2 deletions(-) diff --git a/data/Memory-ng.xml b/data/Memory-ng.xml index 6d9cbaaf3..ef289c783 100644 --- a/data/Memory-ng.xml +++ b/data/Memory-ng.xml @@ -1500,7 +1500,11 @@ - 0x01482874 - current race + + + + +
@@ -1618,7 +1622,68 @@
- + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + is it a vector? + + + + + + +
From 4fc05ee45ca70590ff1e38c83f5e970d141bc4e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Sun, 26 Sep 2010 05:14:06 +0200 Subject: [PATCH 16/94] Creature addresses 31.14 SDL Windows --- data/Memory-ng.xml | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/data/Memory-ng.xml b/data/Memory-ng.xml index ef289c783..31d3b2838 100644 --- a/data/Memory-ng.xml +++ b/data/Memory-ng.xml @@ -1705,20 +1705,6 @@ -
@@ -1732,6 +1718,17 @@
+ +
+
+ + YES
From 1ef138cf5f2beac532ad25088ff70eea64143111 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Mon, 27 Sep 2010 06:59:24 +0200 Subject: [PATCH 17/94] Custom workshop support for DF 31.13 and 31.14 on Windows. --- data/Memory-ng.xml | 90 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 75 insertions(+), 15 deletions(-) diff --git a/data/Memory-ng.xml b/data/Memory-ng.xml index 31d3b2838..38e4d89e2 100644 --- a/data/Memory-ng.xml +++ b/data/Memory-ng.xml @@ -1477,6 +1477,12 @@ + + + 0x164 was custom workshop type... extrapolate? + 0x44 + BOGUS + +
@@ -1690,13 +1696,10 @@
- Second possible: 0x16568a0 (can't decide) - + + + +
Second possible: 0x0169fb7C @@ -1722,14 +1725,7 @@
- - YES +
@@ -1741,6 +1737,9 @@
+ +
Second possible: 0x016a0b88 + .-"""-. @@ -2117,6 +2116,67 @@ + + + + +
+ + +
+ + +
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+ + +
+ + +
+ + + +
+
+ + + +
+
+
+
+
+
+ + +
+ + +
+ + +
+
+
+ + + From c51b9b22730317e6bea7b626be26b707948c5c86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Tue, 28 Sep 2010 05:37:57 +0200 Subject: [PATCH 18/94] Fix furnaces. --- data/Memory-ng.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/Memory-ng.xml b/data/Memory-ng.xml index 38e4d89e2..b47bcad73 100644 --- a/data/Memory-ng.xml +++ b/data/Memory-ng.xml @@ -1479,8 +1479,8 @@ - 0x164 was custom workshop type... extrapolate? + 0x44 - BOGUS + + From 65a24b7148f124d3f3772e28ba34542100e8f656 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Tue, 28 Sep 2010 06:04:15 +0200 Subject: [PATCH 19/94] Disable bad weather offset for 31.12-win-sdl. --- data/Memory-ng.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/data/Memory-ng.xml b/data/Memory-ng.xml index b47bcad73..ea69d1bd3 100644 --- a/data/Memory-ng.xml +++ b/data/Memory-ng.xml @@ -1469,9 +1469,11 @@
+ From 30bacaf2cdc5b8c077fbd113416e84806b723f33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Wed, 29 Sep 2010 08:45:34 +0200 Subject: [PATCH 20/94] Proper advanced creature offsets - windows - 31.13,13.14 - SDL --- data/Memory-ng.xml | 65 +++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 33 deletions(-) diff --git a/data/Memory-ng.xml b/data/Memory-ng.xml index ea69d1bd3..b0c0c9257 100644 --- a/data/Memory-ng.xml +++ b/data/Memory-ng.xml @@ -1480,10 +1480,10 @@ - - - - + + + +
@@ -1548,15 +1548,15 @@
- - - - - - - - - + + + + + + + + + @@ -1646,35 +1646,34 @@ - + Anything here is automatically suspect... - - - + + + + + + - - - - - + + BAD! + + + + + + + - - + + JUST PLAIN WRONG! - is it a vector? + is it a vector? From b541a855e514725bfd0f236ad00ceaf74623edd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Sat, 2 Oct 2010 07:23:48 +0200 Subject: [PATCH 21/94] 31.14 linux Maps --- data/Memory-ng.xml | 57 ++++++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/data/Memory-ng.xml b/data/Memory-ng.xml index b0c0c9257..4f3ec784a 100644 --- a/data/Memory-ng.xml +++ b/data/Memory-ng.xml @@ -2117,9 +2117,37 @@ - + + +
+
+
+
+
+
+
+
+
+
+
+
+ + +
0x933c0fc + + +
+ + + +
+
+ + + + From daf7c0a2ee8d9d9b96367911c93d109217172c82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Mon, 4 Oct 2010 21:54:58 +0200 Subject: [PATCH 22/94] More offsets... --- data/Memory-ng.xml | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/data/Memory-ng.xml b/data/Memory-ng.xml index 4f3ec784a..917e0a8ef 100644 --- a/data/Memory-ng.xml +++ b/data/Memory-ng.xml @@ -1742,6 +1742,10 @@
Second possible: 0x016a0b88 + + + + .-"""-. ' \ @@ -2146,30 +2150,32 @@
- - -
-
-
-
-
+
+
+
+
+
+ AS BOGUS AS IT GETS +
+
+
+
+ + +
+ + +
+ + .-"""-. ' \ diff --git a/library/include/dfhack/modules/Maps.h b/library/include/dfhack/modules/Maps.h index d1957c6b8..fcadecc92 100644 --- a/library/include/dfhack/modules/Maps.h +++ b/library/include/dfhack/modules/Maps.h @@ -149,6 +149,14 @@ namespace DFHack liquid_magma }; + enum e_liquidcharacter + { + liquid_fresh, + liquid_unk1, + liquid_salt, + liquid_unk2, + }; + struct naked_designation { unsigned int flow_size : 3; // how much liquid is here? @@ -188,8 +196,14 @@ namespace DFHack unsigned int feature_local : 1; /// this tile is a part of a global feature. can be combined with 'featstone' tiles unsigned int feature_global : 1; - /// those ripples on streams? - unsigned int liquid_character : 2; + /** + * water characteristics + * fresh=0 + * ?=1 + * salt=2 + * ?=3 + */ + e_liquidcharacter liquid_character : 2; }; union t_designation diff --git a/library/modules/Materials.cpp b/library/modules/Materials.cpp index 608e7b663..343fa99c0 100644 --- a/library/modules/Materials.cpp +++ b/library/modules/Materials.cpp @@ -402,7 +402,7 @@ 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)); - cout << "Caste " << caste.rawname << " " << caste.singular << ": 0x" << hex << caste_start << endl; + //cout << "Caste " << caste.rawname << " " << caste.singular << ": 0x" << hex << caste_start << endl; if(have_advanced) { /* color mod reading */ diff --git a/tools/examples/creaturedump.cpp b/tools/examples/creaturedump.cpp index dddd6e018..ac691316b 100644 --- a/tools/examples/creaturedump.cpp +++ b/tools/examples/creaturedump.cpp @@ -302,7 +302,15 @@ void printCreature(DFHack::Context * DF, const DFHack::t_creature & creature) { cout << ", "; } - cout << mem->getSkill(creature.defaultSoul.skills[i].id) << ": " << creature.defaultSoul.skills[i].rating; + try + { + cout << mem->getSkill(creature.defaultSoul.skills[i].id) << ": " << creature.defaultSoul.skills[i].rating; + } + catch(DFHack::Error::MissingMemoryDefinition &e) + { + cout << "Unknown skill! : " << creature.defaultSoul.skills[i].id <<", rating: " << creature.defaultSoul.skills[i].rating << endl; + cout << e.what() << endl; + } } cout << endl; cout << "Traits" << endl; From fd6ea7a15947cbbefc8f507be4b80ead67264a1b Mon Sep 17 00:00:00 2001 From: comestible Date: Wed, 6 Oct 2010 17:27:02 -0700 Subject: [PATCH 24/94] Added 'range' brush mode to dfliquids, user specifies width and height from the cursor. --- tools/supported/liquids.cpp | 290 +++++++++++++++++++++++++----------- 1 file changed, 202 insertions(+), 88 deletions(-) diff --git a/tools/supported/liquids.cpp b/tools/supported/liquids.cpp index ceff8c3fd..62cb34a34 100644 --- a/tools/supported/liquids.cpp +++ b/tools/supported/liquids.cpp @@ -4,6 +4,7 @@ #include #include #include +#include using namespace std; #include @@ -45,6 +46,8 @@ int main (void) string flowmode="f+"; string setmode ="s."; int amount = 7; + int width = 1; + int height = 1; while(!end) { DF->Resume(); @@ -69,6 +72,7 @@ int main (void) << "0-7 - set liquid amount" << endl << "Brush:" << endl << "point - single tile" << endl + << "range - rectangle with cursor at top left" << endl << "block - block with cursor in it" << endl << "Other:" << endl << "q - quit" << endl @@ -110,6 +114,18 @@ int main (void) { brush = "point"; } + else if(command == "range") + { + cout << " :set range width<" << width << "># "; + getline(cin, command); + width = atoi (command.c_str()); + if(width < 1) width = 1; + cout << " :set range height<" << height << "># "; + getline(cin, command); + height = atoi (command.c_str()); + if(height < 1) height = 1; + brush = "range"; + } else if(command == "block") { brush = "block"; @@ -257,94 +273,192 @@ int main (void) else { // place the magma - Maps->ReadDesignations((x/16),(y/16),z, &designations); - Maps->ReadTemperatures((x/16),(y/16),z, &temp1, &temp2); - if(brush == "point") - { - if(mode != "flowbits") - { - // 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; - 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; - else if(mode == "water") - designations[x%16][y%16].bits.liquid_type = DFHack::liquid_water; - } - else - { - for(uint32_t xx = 0; xx < 16; xx++) for(uint32_t yy = 0; yy < 16; yy++) - { - if(mode != "flowbits") - { - // 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; - 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; - else if(mode == "water") - designations[xx][yy].bits.liquid_type = DFHack::liquid_water; - } - } - Maps->WriteTemperatures((x/16),(y/16),z, &temp1, &temp2); - Maps->WriteDesignations(x/16,y/16,z, &designations); - } - - // make the magma flow :) - DFHack::t_blockflags bflags; - Maps->ReadBlockFlags((x/16),(y/16),z,bflags); - // 0x00000001 = job-designated - // 0x0000000C = run flows? - both bit 3 and 4 required for making magma placed on a glacier flow - if(flowmode == "f+") - { - bflags.bits.liquid_1 = true; - bflags.bits.liquid_2 = true; - } - else if(flowmode == "f-") - { - bflags.bits.liquid_1 = false; - bflags.bits.liquid_2 = false; - } - else - { - cout << "flow bit 1 = " << bflags.bits.liquid_1 << endl; - cout << "flow bit 2 = " << bflags.bits.liquid_2 << endl; - } - Maps->WriteBlockFlags((x/16),(y/16),z,bflags); - cout << "OK" << endl; - Maps->Finish(); + if(brush != "range") + { + Maps->ReadDesignations((x/16),(y/16),z, &designations); + Maps->ReadTemperatures((x/16),(y/16),z, &temp1, &temp2); + if(brush == "point") + { + if(mode != "flowbits") + { + // 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; + 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; + else if(mode == "water") + designations[x%16][y%16].bits.liquid_type = DFHack::liquid_water; + } + else + { + for(uint32_t xx = 0; xx < 16; xx++) for(uint32_t yy = 0; yy < 16; yy++) + { + if(mode != "flowbits") + { + // 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; + 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; + else if(mode == "water") + designations[xx][yy].bits.liquid_type = DFHack::liquid_water; + } + } + Maps->WriteTemperatures((x/16),(y/16),z, &temp1, &temp2); + Maps->WriteDesignations(x/16,y/16,z, &designations); + + // make the magma flow :) + DFHack::t_blockflags bflags; + Maps->ReadBlockFlags((x/16),(y/16),z,bflags); + // 0x00000001 = job-designated + // 0x0000000C = run flows? - both bit 3 and 4 required for making magma placed on a glacier flow + if(flowmode == "f+") + { + bflags.bits.liquid_1 = true; + bflags.bits.liquid_2 = true; + } + else if(flowmode == "f-") + { + bflags.bits.liquid_1 = false; + bflags.bits.liquid_2 = false; + } + else + { + cout << "flow bit 1 = " << bflags.bits.liquid_1 << endl; + cout << "flow bit 2 = " << bflags.bits.liquid_2 << endl; + } + Maps->WriteBlockFlags((x/16),(y/16),z,bflags); + } + else // (brush == "range") + { + // Crop the range into each block if necessary + int beginxblock = x/16; + int endxblock = (x+width)/16; + int beginyblock = y/16; + int endyblock = (y+height)/16; + for(uint32_t bx = beginxblock; bx < endxblock+1; bx++) for(uint32_t by = beginyblock; by < endyblock+1; by++) + { + if(Maps->isValidBlock(bx,by,z)) + { + Maps->ReadDesignations(bx,by,z, &designations); + Maps->ReadTemperatures(bx,by,z, &temp1, &temp2); + // Take original range and crop it into current block + int nx = x; + int ny = y; + int nwidth = width; + int nheight = height; + if(x/16 < bx) //Start point is left of block + { + nx = bx*16; + nwidth -= nx - x; + } + if (nx/16 < (nx+nwidth-1)/16)// End point is right of block + { + nwidth = (bx*16)+16-nx; + } + if(y/16 < by) //Start point is above block + { + ny = by*16; + nheight -= ny - y; + } + if (ny/16 < (ny+nheight-1)/16) // End point is below block + { + nheight = (by*16)+16-ny; + } + cout << " Block:" << bx << "," << by << ":" << endl; + cout << " Start:" << nx << "," << ny << ":" << endl; + cout << " Area: " << nwidth << "," << nheight << ":" << endl; + for(uint32_t xx = nx; xx < nx+nwidth; xx++) for(uint32_t yy = ny; yy < ny+nheight; yy++) + { + if(mode != "flowbits") + { + // fix temperatures so we don't produce lethal heat traps + if(amount == 0 || designations[xx%16][yy%16].bits.liquid_type == DFHack::liquid_magma && mode == "water") + temp1[xx%16][yy%16] = temp2[xx%16][yy%16] = 10015; + DFHack::naked_designation & flow= designations[xx%16][yy%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[xx%16][yy%16].bits.liquid_type = DFHack::liquid_magma; + else if(mode == "water") + designations[xx%16][yy%16].bits.liquid_type = DFHack::liquid_water; + } + Maps->WriteTemperatures(bx,by,z, &temp1, &temp2); + Maps->WriteDesignations(bx,by,z, &designations); + + // make the magma flow :) + DFHack::t_blockflags bflags; + Maps->ReadBlockFlags(bx,by,z,bflags); + // 0x00000001 = job-designated + // 0x0000000C = run flows? - both bit 3 and 4 required for making magma placed on a glacier flow + if(flowmode == "f+") + { + bflags.bits.liquid_1 = true; + bflags.bits.liquid_2 = true; + } + else if(flowmode == "f-") + { + bflags.bits.liquid_1 = false; + bflags.bits.liquid_2 = false; + } + else + { + cout << "flow bit 1 = " << bflags.bits.liquid_1 << endl; + cout << "flow bit 2 = " << bflags.bits.liquid_2 << endl; + } + Maps->WriteBlockFlags(bx,by,z,bflags); + } + } + } + + } + cout << "OK" << endl; + Maps->Finish(); } while (0); } } From 4bc83a1463f06188d5387bae57ce38881920513f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Thu, 7 Oct 2010 03:17:39 +0200 Subject: [PATCH 25/94] Time offsets, maybe wrong. Definitely wrong for most versions! --- data/Memory-ng.xml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/data/Memory-ng.xml b/data/Memory-ng.xml index 473d70989..47245030d 100644 --- a/data/Memory-ng.xml +++ b/data/Memory-ng.xml @@ -1469,11 +1469,11 @@
- - --> @@ -1525,7 +1525,7 @@
-
+
@@ -1751,6 +1751,10 @@ + +
+
+
AS BOGUS AS IT GETS @@ -1763,6 +1767,8 @@
+
MAYBE +
From 1460066a69e82443e8892cd8cb620225f1c7b253 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Fri, 8 Oct 2010 04:28:26 +0200 Subject: [PATCH 26/94] Fix formatting. --- tools/supported/liquids.cpp | 405 ++++++++++++++++++------------------ 1 file changed, 202 insertions(+), 203 deletions(-) diff --git a/tools/supported/liquids.cpp b/tools/supported/liquids.cpp index 62cb34a34..2316200bd 100644 --- a/tools/supported/liquids.cpp +++ b/tools/supported/liquids.cpp @@ -1,6 +1,8 @@ // This will create 7 deep magama on the square the cursor is on. It does not // enable magma buildings at this time. +// TO BE DEPRECATED SOON. + #include #include #include @@ -46,8 +48,8 @@ int main (void) string flowmode="f+"; string setmode ="s."; int amount = 7; - int width = 1; - int height = 1; + int width = 1; + int height = 1; while(!end) { DF->Resume(); @@ -72,7 +74,7 @@ int main (void) << "0-7 - set liquid amount" << endl << "Brush:" << endl << "point - single tile" << endl - << "range - rectangle with cursor at top left" << endl + << "range - rectangle with cursor at top left" << endl << "block - block with cursor in it" << endl << "Other:" << endl << "q - quit" << endl @@ -114,18 +116,18 @@ int main (void) { brush = "point"; } - else if(command == "range") - { - cout << " :set range width<" << width << "># "; - getline(cin, command); - width = atoi (command.c_str()); - if(width < 1) width = 1; - cout << " :set range height<" << height << "># "; - getline(cin, command); - height = atoi (command.c_str()); - if(height < 1) height = 1; - brush = "range"; - } + else if(command == "range") + { + cout << " :set range width<" << width << "># "; + getline(cin, command); + width = atoi (command.c_str()); + if(width < 1) width = 1; + cout << " :set range height<" << height << "># "; + getline(cin, command); + height = atoi (command.c_str()); + if(height < 1) height = 1; + brush = "range"; + } else if(command == "block") { brush = "block"; @@ -230,7 +232,6 @@ int main (void) cout << "sizeof(tiletypes) = " << sizeof(tiles) << endl; for(uint32_t xx = 0; xx < 16; xx++) for(uint32_t yy = 0; yy < 16; yy++) { - cout<< xx << " " << yy <<": " << tiles[xx][yy] << endl; tiles[xx][yy] = 335;// 45 DFHack::naked_designation & des = designations[xx][yy].bits; @@ -240,10 +241,8 @@ int main (void) des.skyview = 0; des.light = 0; des.subterranean = 1; - temp1[xx][yy] = 10015; temp2[xx][yy] = 10015; - } Maps->WriteTemperatures((x/16),(y/16),z, &temp1, &temp2); Maps->WriteDesignations((x/16),(y/16),z, &designations); @@ -273,192 +272,192 @@ int main (void) else { // place the magma - if(brush != "range") - { - Maps->ReadDesignations((x/16),(y/16),z, &designations); - Maps->ReadTemperatures((x/16),(y/16),z, &temp1, &temp2); - if(brush == "point") - { - if(mode != "flowbits") - { - // 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; - 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; - else if(mode == "water") - designations[x%16][y%16].bits.liquid_type = DFHack::liquid_water; - } - else - { - for(uint32_t xx = 0; xx < 16; xx++) for(uint32_t yy = 0; yy < 16; yy++) - { - if(mode != "flowbits") - { - // 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; - 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; - else if(mode == "water") - designations[xx][yy].bits.liquid_type = DFHack::liquid_water; - } - } - Maps->WriteTemperatures((x/16),(y/16),z, &temp1, &temp2); - Maps->WriteDesignations(x/16,y/16,z, &designations); - - // make the magma flow :) - DFHack::t_blockflags bflags; - Maps->ReadBlockFlags((x/16),(y/16),z,bflags); - // 0x00000001 = job-designated - // 0x0000000C = run flows? - both bit 3 and 4 required for making magma placed on a glacier flow - if(flowmode == "f+") - { - bflags.bits.liquid_1 = true; - bflags.bits.liquid_2 = true; - } - else if(flowmode == "f-") - { - bflags.bits.liquid_1 = false; - bflags.bits.liquid_2 = false; - } - else - { - cout << "flow bit 1 = " << bflags.bits.liquid_1 << endl; - cout << "flow bit 2 = " << bflags.bits.liquid_2 << endl; - } - Maps->WriteBlockFlags((x/16),(y/16),z,bflags); - } - else // (brush == "range") - { - // Crop the range into each block if necessary - int beginxblock = x/16; - int endxblock = (x+width)/16; - int beginyblock = y/16; - int endyblock = (y+height)/16; - for(uint32_t bx = beginxblock; bx < endxblock+1; bx++) for(uint32_t by = beginyblock; by < endyblock+1; by++) - { - if(Maps->isValidBlock(bx,by,z)) - { - Maps->ReadDesignations(bx,by,z, &designations); - Maps->ReadTemperatures(bx,by,z, &temp1, &temp2); - // Take original range and crop it into current block - int nx = x; - int ny = y; - int nwidth = width; - int nheight = height; - if(x/16 < bx) //Start point is left of block - { - nx = bx*16; - nwidth -= nx - x; - } - if (nx/16 < (nx+nwidth-1)/16)// End point is right of block - { - nwidth = (bx*16)+16-nx; - } - if(y/16 < by) //Start point is above block - { - ny = by*16; - nheight -= ny - y; - } - if (ny/16 < (ny+nheight-1)/16) // End point is below block - { - nheight = (by*16)+16-ny; - } - cout << " Block:" << bx << "," << by << ":" << endl; - cout << " Start:" << nx << "," << ny << ":" << endl; - cout << " Area: " << nwidth << "," << nheight << ":" << endl; - for(uint32_t xx = nx; xx < nx+nwidth; xx++) for(uint32_t yy = ny; yy < ny+nheight; yy++) - { - if(mode != "flowbits") - { - // fix temperatures so we don't produce lethal heat traps - if(amount == 0 || designations[xx%16][yy%16].bits.liquid_type == DFHack::liquid_magma && mode == "water") - temp1[xx%16][yy%16] = temp2[xx%16][yy%16] = 10015; - DFHack::naked_designation & flow= designations[xx%16][yy%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[xx%16][yy%16].bits.liquid_type = DFHack::liquid_magma; - else if(mode == "water") - designations[xx%16][yy%16].bits.liquid_type = DFHack::liquid_water; - } - Maps->WriteTemperatures(bx,by,z, &temp1, &temp2); - Maps->WriteDesignations(bx,by,z, &designations); - - // make the magma flow :) - DFHack::t_blockflags bflags; - Maps->ReadBlockFlags(bx,by,z,bflags); - // 0x00000001 = job-designated - // 0x0000000C = run flows? - both bit 3 and 4 required for making magma placed on a glacier flow - if(flowmode == "f+") - { - bflags.bits.liquid_1 = true; - bflags.bits.liquid_2 = true; - } - else if(flowmode == "f-") - { - bflags.bits.liquid_1 = false; - bflags.bits.liquid_2 = false; - } - else - { - cout << "flow bit 1 = " << bflags.bits.liquid_1 << endl; - cout << "flow bit 2 = " << bflags.bits.liquid_2 << endl; - } - Maps->WriteBlockFlags(bx,by,z,bflags); - } - } - } + if(brush != "range") + { + Maps->ReadDesignations((x/16),(y/16),z, &designations); + Maps->ReadTemperatures((x/16),(y/16),z, &temp1, &temp2); + if(brush == "point") + { + if(mode != "flowbits") + { + // 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; + 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; + else if(mode == "water") + designations[x%16][y%16].bits.liquid_type = DFHack::liquid_water; + } + else + { + for(uint32_t xx = 0; xx < 16; xx++) for(uint32_t yy = 0; yy < 16; yy++) + { + if(mode != "flowbits") + { + // 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; + 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; + else if(mode == "water") + designations[xx][yy].bits.liquid_type = DFHack::liquid_water; + } + } + Maps->WriteTemperatures((x/16),(y/16),z, &temp1, &temp2); + Maps->WriteDesignations(x/16,y/16,z, &designations); - } - cout << "OK" << endl; - Maps->Finish(); + // make the magma flow :) + DFHack::t_blockflags bflags; + Maps->ReadBlockFlags((x/16),(y/16),z,bflags); + // 0x00000001 = job-designated + // 0x0000000C = run flows? - both bit 3 and 4 required for making magma placed on a glacier flow + if(flowmode == "f+") + { + bflags.bits.liquid_1 = true; + bflags.bits.liquid_2 = true; + } + else if(flowmode == "f-") + { + bflags.bits.liquid_1 = false; + bflags.bits.liquid_2 = false; + } + else + { + cout << "flow bit 1 = " << bflags.bits.liquid_1 << endl; + cout << "flow bit 2 = " << bflags.bits.liquid_2 << endl; + } + Maps->WriteBlockFlags((x/16),(y/16),z,bflags); + } + else if (brush == "range") + { + // Crop the range into each block if necessary + int beginxblock = x/16; + int endxblock = (x+width)/16; + int beginyblock = y/16; + int endyblock = (y+height)/16; + for(uint32_t bx = beginxblock; bx < endxblock+1; bx++) for(uint32_t by = beginyblock; by < endyblock+1; by++) + { + if(Maps->isValidBlock(bx,by,z)) + { + Maps->ReadDesignations(bx,by,z, &designations); + Maps->ReadTemperatures(bx,by,z, &temp1, &temp2); + // Take original range and crop it into current block + int nx = x; + int ny = y; + int nwidth = width; + int nheight = height; + if(x/16 < bx) //Start point is left of block + { + nx = bx*16; + nwidth -= nx - x; + } + if (nx/16 < (nx+nwidth-1)/16)// End point is right of block + { + nwidth = (bx*16)+16-nx; + } + if(y/16 < by) //Start point is above block + { + ny = by*16; + nheight -= ny - y; + } + if (ny/16 < (ny+nheight-1)/16) // End point is below block + { + nheight = (by*16)+16-ny; + } + cout << " Block:" << bx << "," << by << ":" << endl; + cout << " Start:" << nx << "," << ny << ":" << endl; + cout << " Area: " << nwidth << "," << nheight << ":" << endl; + for(uint32_t xx = nx; xx < nx+nwidth; xx++) for(uint32_t yy = ny; yy < ny+nheight; yy++) + { + if(mode != "flowbits") + { + // fix temperatures so we don't produce lethal heat traps + if(amount == 0 || designations[xx%16][yy%16].bits.liquid_type == DFHack::liquid_magma && mode == "water") + temp1[xx%16][yy%16] = temp2[xx%16][yy%16] = 10015; + DFHack::naked_designation & flow= designations[xx%16][yy%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[xx%16][yy%16].bits.liquid_type = DFHack::liquid_magma; + else if(mode == "water") + designations[xx%16][yy%16].bits.liquid_type = DFHack::liquid_water; + } + Maps->WriteTemperatures(bx,by,z, &temp1, &temp2); + Maps->WriteDesignations(bx,by,z, &designations); + + // make the magma flow :) + DFHack::t_blockflags bflags; + Maps->ReadBlockFlags(bx,by,z,bflags); + // 0x00000001 = job-designated + // 0x0000000C = run flows? - both bit 3 and 4 required for making magma placed on a glacier flow + if(flowmode == "f+") + { + bflags.bits.liquid_1 = true; + bflags.bits.liquid_2 = true; + } + else if(flowmode == "f-") + { + bflags.bits.liquid_1 = false; + bflags.bits.liquid_2 = false; + } + else + { + cout << "flow bit 1 = " << bflags.bits.liquid_1 << endl; + cout << "flow bit 2 = " << bflags.bits.liquid_2 << endl; + } + Maps->WriteBlockFlags(bx,by,z,bflags); + } + } + } + + } + cout << "OK" << endl; + Maps->Finish(); } while (0); } } From 404c079ad71901c89023f0cfb23e0c15a70a7f01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Fri, 8 Oct 2010 04:41:54 +0200 Subject: [PATCH 27/94] comment fix --- tools/supported/liquids.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/tools/supported/liquids.cpp b/tools/supported/liquids.cpp index 2316200bd..2224bd4a3 100644 --- a/tools/supported/liquids.cpp +++ b/tools/supported/liquids.cpp @@ -1,6 +1,3 @@ -// This will create 7 deep magama on the square the cursor is on. It does not -// enable magma buildings at this time. - // TO BE DEPRECATED SOON. #include From d4b8b8df64d9bad82799ff4cbb2cdbe7a5da9dc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Fri, 8 Oct 2010 05:06:13 +0200 Subject: [PATCH 28/94] Don't remove snow covering with cleanmap. --- tools/supported/cleanmap.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/supported/cleanmap.cpp b/tools/supported/cleanmap.cpp index 78081f7fd..900aa3f72 100644 --- a/tools/supported/cleanmap.cpp +++ b/tools/supported/cleanmap.cpp @@ -58,7 +58,8 @@ int main (void) for(uint32_t i = 0; i < splatter.size(); i++) { DFHack::t_spattervein & vein = splatter[i]; - if(vein.mat1 != 0xC) + // filter away snow and mud + if(vein.mat1 != 0xC && vein.mat1 != 0x6) { uint32_t addr = vein.address_of; uint32_t offset = offsetof(DFHack::t_spattervein, intensity); From 247b7537fdfa56bd3da78456ec898028c6ea52be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Fri, 15 Oct 2010 05:43:54 +0200 Subject: [PATCH 29/94] Segmented finder gets backwards pointer scan and arbitrary data search. --- data/Memory-ng.xml | 4 + tools/playground/SegmentedFinder.h | 201 ++++++++++++++++++++++++- tools/playground/incrementalsearch.cpp | 200 ++++++++++++++++++++++-- 3 files changed, 385 insertions(+), 20 deletions(-) diff --git a/data/Memory-ng.xml b/data/Memory-ng.xml index 47245030d..d1c25a296 100644 --- a/data/Memory-ng.xml +++ b/data/Memory-ng.xml @@ -2212,6 +2212,10 @@ --> + + + + diff --git a/tools/playground/SegmentedFinder.h b/tools/playground/SegmentedFinder.h index 98de87711..eae2d1bf3 100644 --- a/tools/playground/SegmentedFinder.h +++ b/tools/playground/SegmentedFinder.h @@ -1,5 +1,8 @@ #ifndef SEGMENTED_FINDER_H #define SEGMENTED_FINDER_H +#include +#include +#include class SegmentedFinder; class SegmentFinder @@ -286,15 +289,205 @@ bool vectorAll (SegmentedFinder* s, vecTriplet *x, int ) return false; } -struct Bytestream +class Bytestreamdata { - uint32_t length; - void * object; + public: + void * object; + uint32_t length; + uint32_t allocated; + uint32_t n_used; }; +class Bytestream +{ +public: + Bytestream(void * obj, uint32_t len, bool alloc = false) + { + d = new Bytestreamdata(); + d->allocated = alloc; + d->object = obj; + d->length = len; + d->n_used = 1; + constant = false; + } + Bytestream() + { + d = new Bytestreamdata(); + d->allocated = false; + d->object = 0; + d->length = 0; + d->n_used = 1; + constant = false; + } + Bytestream( Bytestream & bs) + { + d =bs.d; + d->n_used++; + constant = false; + } + Bytestream( const Bytestream & bs) + { + d =bs.d; + d->n_used++; + constant = true; + } + ~Bytestream() + { + d->n_used --; + if(d->allocated && d->object && d->n_used == 0) + { + free (d->object); + free (d); + } + } + bool Allocate(size_t bytes) + { + if(constant) + return false; + if(d->allocated) + { + d->object = realloc(d->object, bytes); + } + else + { + d->object = malloc( bytes ); + } + + if(d->object) + { + d->allocated = bytes; + return true; + } + else + { + d->allocated = 0; + return false; + } + } + bool insert( char what ) + { + if(constant) + return false; + if(d->length+1 == d->allocated) + Allocate(d->allocated * 2); + ((char *) d->object)[d->length] = what; + d->length ++; + } + Bytestreamdata * d; + bool constant; +}; +std::ostream& operator<< ( std::ostream& out, Bytestream& bs ) +{ + if(bs.d->object) + { + out << "bytestream " << dec << bs.d->length << "/" << bs.d->allocated << " bytes" << endl; + for(int i = 0; i < bs.d->length; i++) + { + out << hex << (int) ((uint8_t *) bs.d->object)[i] << " "; + } + out << endl; + } + else + { + out << "empty bytestresm" << endl; + } + return out; +} + +std::istream& operator>> ( std::istream& out, Bytestream& bs ) +{ + string read; + while(!out.eof()) + { + string tmp; + out >> tmp; + read.append(tmp); + } + cout << read << endl; + bs.d->length = 0; + size_t first = read.find_first_of("\""); + size_t last = read.find_last_of("\""); + size_t start = first + 1; + if(first == read.npos) + { + std::transform(read.begin(), read.end(), read.begin(), (int(*)(int)) tolower); + bs.Allocate(read.size()); // overkill. size / 2 should be good, but this is safe + int state = 0; + char big = 0; + char small = 0; + string::iterator it = read.begin(); + // iterate through string, construct a bytestream out of 00-FF bytes + while(it != read.end()) + { + char reads = *it; + if((reads >='0' && reads <= '9')) + { + if(state == 0) + { + big = reads - '0'; + state = 1; + } + else if(state == 1) + { + small = reads - '0'; + state = 0; + bs.insert(big*16 + small); + } + } + if((reads >= 'a' && reads <= 'f')) + { + if(state == 0) + { + big = reads - 'a' + 10; + state = 1; + } + else if(state == 1) + { + small = reads - 'a' + 10; + state = 0; + bs.insert(big*16 + small); + } + } + it++; + } + // we end in state= 1. should we add or should we trim... or throw errors? + // I decided on adding + if (state == 1) + { + small = 0; + bs.insert(big*16 + small); + } + } + else + { + if(last == first) + { + // only one " + last = read.size(); + } + size_t length = last - start; + // construct bytestream out of stuff between "" + bs.d->length = length; + if(length) + { + // todo: Bytestream should be able to handle this without external code + bs.Allocate(length); + bs.d->length = length; + const char* strstart = read.c_str(); + memcpy(bs.d->object, strstart + start, length); + } + else + { + bs.d->object = 0; + } + } + cout << bs; + return out; +} + bool findBytestream (SegmentedFinder* s, void *addr, Bytestream compare ) { - if(memcmp(addr, compare.object, compare.length) == 0) + if(memcmp(addr, compare.d->object, compare.d->length) == 0) return true; return false; } diff --git a/tools/playground/incrementalsearch.cpp b/tools/playground/incrementalsearch.cpp index 918577944..f5ce91ffd 100644 --- a/tools/playground/incrementalsearch.cpp +++ b/tools/playground/incrementalsearch.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -273,7 +274,7 @@ bool getString (string prompt, string & output) template bool Incremental ( vector &found, const char * what, T& output, - const char *singular = "address", const char *plural = "addresses" ) + const char *singular = "address", const char *plural = "addresses", bool numberz = false ) { string select; if(found.empty()) @@ -317,20 +318,23 @@ bool Incremental ( vector &found, const char * what, T& output, } else { - if( sscanf(select.c_str(),"0x%x", &output) == 1 ) + if(numberz) { - //cout << dec << output << endl; - return true; - } - if( sscanf(select.c_str(),"%d", &output) == 1 ) - { - //cout << dec << output << endl; - return true; + if( sscanf(select.c_str(),"0x%x", &output) == 1 ) + { + //cout << dec << output << endl; + return true; + } + if( sscanf(select.c_str(),"%d", &output) == 1 ) + { + //cout << dec << output << endl; + return true; + } } - stringstream ss (stringstream::in | stringstream::out); ss << select; ss >> output; + cout << output; if(!ss.fail()) { return true; @@ -358,7 +362,7 @@ void FindIntegers(DFHack::ContextManager & DFMgr, vector & r uint32_t test1; vector found; found.reserve(100); - while(Incremental(found, "integer",test1)) + while(Incremental(found, "integer",test1,"address", "addresses",true)) { DFMgr.Refresh(); DFHack::Context * DF = DFMgr.getSingleContext(); @@ -514,6 +518,156 @@ void FindStrings(DFHack::ContextManager & DFMgr, vector & ra } } +void FindData(DFHack::ContextManager & DFMgr, vector & ranges) +{ + vector found; + Bytestream select; + while (Incremental(found,"byte stream",select,"byte stream","byte streams")) + { + DFMgr.Refresh(); + DFHack::Context * DF = DFMgr.getSingleContext(); + DF->Attach(); + SegmentedFinder sf(ranges,DF); + sf.Incremental< Bytestream ,uint32_t>(select,1,found, findBytestream); + DF->Detach(); + } +} +/* + while(Incremental(found, "integer",test1)) + { + DFMgr.Refresh(); + DFHack::Context * DF = DFMgr.getSingleContext(); + DF->Attach(); + SegmentedFinder sf(ranges,DF); + switch(size) + { + case 1: + sf.Incremental(test1,alignment,found, equalityP); + break; + case 2: + sf.Incremental(test1,alignment,found, equalityP); + break; + case 4: + sf.Incremental(test1,alignment,found, equalityP); + break; + } + DF->Detach(); + } +} +*/ +void PtrTrace(DFHack::ContextManager & DFMgr, vector & ranges) +{ + int element_size; + do + { + getNumber("Set search granularity",element_size, 4); + } while (element_size < 1); + + vector found; + set check; // to detect circles + uint32_t select; + while (Incremental(found,"address",select,"addresses","addresses",true)) + { + DFMgr.Refresh(); + found.clear(); + DFHack::Context * DF = DFMgr.getSingleContext(); + DF->Attach(); + SegmentedFinder sf(ranges,DF); + cout <<"Starting: 0x" << hex << select << endl; + while(sf.getSegmentForAddress(select)) + { + sf.Incremental(select,element_size,found, equalityP); + if(found.empty()) + { + cout << "."; + cout.flush(); + select -=element_size; + continue; + } + cout << endl; + cout <<"Object start: 0x" << hex << select << endl; + cout <<"Pointer: 0x" << hex << found[0] << endl; + // make sure we don't go in circles' + if(check.count(select)) + { + break; + } + check.insert(select); + // ascend + select = found[0]; + } + DF->Detach(); + } +} +/* +{ + vector found; + Bytestream select; + while (Incremental(found,"byte stream",select,"byte stream","byte streams")) + { + DFMgr.Refresh(); + DFHack::Context * DF = DFMgr.getSingleContext(); + DF->Attach(); + SegmentedFinder sf(ranges,DF); + sf.Incremental< Bytestream ,uint32_t>(select,1,found, findBytestream); + DF->Detach(); + } +} +*/ +void DataPtrTrace(DFHack::ContextManager & DFMgr, vector & ranges) +{ + int element_size; + do + { + getNumber("Set search granularity",element_size, 4); + } while (element_size < 1); + + vector found; + set check; // to detect circles + uint32_t select; + Bytestream bs_select; + DFHack::Context * DF = DFMgr.getSingleContext(); + DF->Attach(); + DFMgr.Refresh(); + found.clear(); + SegmentedFinder sf(ranges,DF); + while(found.empty()) + { + Incremental(found,"byte stream",bs_select,"byte stream","byte streams"); + + sf.Incremental< Bytestream ,uint32_t>(bs_select,1,found, findBytestream); + } + select = found[0]; + + + + + cout <<"Starting: 0x" << hex << select << endl; + while(sf.getSegmentForAddress(select)) + { + sf.Incremental(select,element_size,found, equalityP); + if(found.empty()) + { + cout << "."; + cout.flush(); + select -=element_size; + continue; + } + cout << endl; + cout <<"Object start: 0x" << hex << select << endl; + cout <<"Pointer: 0x" << hex << found[0] << endl; + // make sure we don't go in circles' + if(check.count(select)) + { + break; + } + check.insert(select); + // ascend + select = found[0]; + } + DF->Detach(); +} + void printFound(vector &found, const char * what) { cout << what << ":" << endl; @@ -726,7 +880,8 @@ void automatedLangtables(DFHack::Context * DF, vector & rang uint64_t Eoffset; cout << "Elephant: 0x" << hex << elephant << endl; cout << "Elephant: rawname = 0x0" << endl; - Eoffset = sf.FindInRange ('E',equalityP, elephant, 0x300 ); + uint8_t letter_E = 'E'; + Eoffset = sf.FindInRange (letter_E,equalityP, elephant, 0x300 ); if(Eoffset) { cout << "Elephant: big E = 0x" << hex << Eoffset - elephant << endl; @@ -742,7 +897,8 @@ void automatedLangtables(DFHack::Context * DF, vector & rang cout << "Elephant: extract? vector = 0x" << hex << Eoffset - elephant << endl; } tilecolors eletc = {7,0,0}; - Bytestream bs_eletc = {sizeof(tilecolors), &eletc}; + Bytestream bs_eletc(&eletc, sizeof(tilecolors)); + cout << bs_eletc; Eoffset = sf.FindInRange (bs_eletc, findBytestream, elephant, 0x300 ); if(Eoffset) { @@ -775,7 +931,7 @@ void automatedLangtables(DFHack::Context * DF, vector & rang cout << "Toad: extract? vector = 0x" << hex << Eoffset - toad << endl; } tilecolors toadtc = {2,0,0}; - Bytestream bs_toadc = {sizeof(tilecolors), &toadtc}; + Bytestream bs_toadc(&toadtc, sizeof(tilecolors)); Eoffset = sf.FindInRange (bs_toadc, findBytestream, toad, 0x300 ); if(Eoffset) { @@ -816,12 +972,12 @@ int main (void) "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" - " 9=string buffers\n"; + " 9=string buffers, 10=known data, 11=backpointers, 12=data+backpointers\n"; int mode; do { getNumber(prompt,mode, 1, false); - } while (mode < 1 || mode > 9 ); + } while (mode < 1 || mode > 12 ); switch (mode) { case 1: @@ -859,6 +1015,18 @@ int main (void) DF->Detach(); FindStrBufs(DFMgr, selected_ranges); break; + case 10: + DF->Detach(); + FindData(DFMgr, selected_ranges); + break; + case 11: + DF->Detach(); + PtrTrace(DFMgr, selected_ranges); + break; + case 12: + DF->Detach(); + DataPtrTrace(DFMgr, selected_ranges); + break; default: cout << "not implemented :(" << endl; } From 6da86ef1deb2b1e7749afa61d797e6779815befa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Fri, 15 Oct 2010 17:47:30 +0200 Subject: [PATCH 30/94] Creature attributes for 31.16 --- data/Memory-ng.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/data/Memory-ng.xml b/data/Memory-ng.xml index d1c25a296..eeb6b2c7a 100644 --- a/data/Memory-ng.xml +++ b/data/Memory-ng.xml @@ -1646,7 +1646,7 @@ - Anything here is automatically suspect... + @@ -1656,7 +1656,7 @@ - BAD! + @@ -1671,7 +1671,7 @@ - JUST PLAIN WRONG! + is it a vector? From 3acc4108574332fab7978b0f11b5357e0a158f99 Mon Sep 17 00:00:00 2001 From: zilpin Date: Sun, 17 Oct 2010 00:21:18 -0400 Subject: [PATCH 31/94] Tile Types update, and new hellhole n deramp tools in playground --- .gitignore | 2 + library/include/dfhack/DFTileTypes.h | 1798 +++++++++++++++----------- tools/playground/CMakeLists.txt | 28 + tools/playground/deramp.cpp | 128 ++ tools/playground/hellhole.cpp | 426 ++++++ tools/playground/printtiletypes.cpp | 93 ++ 6 files changed, 1704 insertions(+), 771 deletions(-) create mode 100644 tools/playground/deramp.cpp create mode 100644 tools/playground/hellhole.cpp create mode 100644 tools/playground/printtiletypes.cpp diff --git a/.gitignore b/.gitignore index 356bf6399..3d1c650da 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,5 @@ dfhack/python/pydfhack/_pydfhack.so dfhack/python/PyDFHack.egg-info dfhack/python/build dfhack/python/dist + +/cmakeall.bat \ No newline at end of file diff --git a/library/include/dfhack/DFTileTypes.h b/library/include/dfhack/DFTileTypes.h index e3b660711..52c3fb4de 100644 --- a/library/include/dfhack/DFTileTypes.h +++ b/library/include/dfhack/DFTileTypes.h @@ -1,771 +1,1027 @@ -/* -www.sourceforge.net/projects/dfhack -Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must -not claim that you wrote the original software. If you use this -software in a product, an acknowledgment in the product documentation -would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. -*/ - -#ifndef TILETYPES_H_INCLUDED -#define TILETYPES_H_INCLUDED - -#include "DFPragma.h" - -namespace DFHack -{ - // tile class -- determines the general shape of the tile - enum TileClass - { - EMPTY,// empty - - WALL, - PILLAR, - FORTIFICATION, - - STAIR_UP, - STAIR_DOWN, - STAIR_UPDOWN, - - RAMP,// ramps have no direction - RAMP_TOP,// the top of a ramp. I assume it's used for path finding. - - FLOOR,// generic floor - TREE_DEAD, - TREE_OK, - SAPLING_DEAD, - SAPLING_OK, - SHRUB_DEAD, - SHRUB_OK, - BOULDER, - PEBBLES - }; - // material -- what material the tile is made of - enum TileMaterial - { - AIR,// empty - SOIL,// ordinary soil. material depends on geology - STONE,// ordinary layer stone. material depends on geology - FEATSTONE,// map feature stone. used for things like hell, the hell temple or adamantine tubes. material depends on local/global feature - OBSIDIAN,// cast obsidian - - VEIN,// vein stone. material depends on mineral veins present - ICE,// frozen water... not much to say. you can determine what was on the tile before it froze by looking into the 'ice vein' objects - GRASS,// grass (has 4 variants) - GRASS2,// grass (has 4 variants) - GRASS_DEAD,// dead grass (has 4 variants) - GRASS_DRY,// dry grass (has 4 variants) - DRIFTWOOD,// non-specified wood - normally on top of the local layer stone/soil. - HFS,// the stuff demon pits are made of - this makes them different from ordinary pits. - MAGMA,// material for semi-molten rock and 'magma flow' tiles - CAMPFIRE,// human armies make them when they siege. The original tile may be lost? - FIRE,// burning grass - ASHES,// what remains from a FIRE - CONSTRUCTED,// tile material depends on the construction present - CYAN_GLOW// the glowy stuff that disappears from the demon temple when you take the sword. - }; - // variants are used for tiles, where there are multiple variants of the same - like grass floors - enum TileVariant - { - VAR_1, - VAR_2, - VAR_3, - VAR_4 - }; - - struct TileRow - { - const char * name; - TileClass c; - TileMaterial m; - TileVariant v; - }; - - #define TILE_TYPE_ARRAY_LENGTH 520 - - const TileRow tileTypeTable[TILE_TYPE_ARRAY_LENGTH] = - { - // 0 - {"void",EMPTY, AIR, VAR_1}, - {"ramp top",RAMP_TOP, AIR, VAR_1}, - {"pool",FLOOR, SOIL, VAR_1}, - {0, EMPTY, AIR, VAR_1}, - {0, EMPTY, AIR, VAR_1}, - {0, EMPTY, AIR, VAR_1}, - {0, EMPTY, AIR, VAR_1}, - {0, EMPTY, AIR, VAR_1}, - {0, EMPTY, AIR, VAR_1}, - {0, EMPTY, AIR, VAR_1}, - - // 10 - {0, EMPTY, AIR, VAR_1}, - {0, EMPTY, AIR, VAR_1}, - {0, EMPTY, AIR, VAR_1}, - {0, EMPTY, AIR, VAR_1}, - {0, EMPTY, AIR, VAR_1}, - {0, EMPTY, AIR, VAR_1}, - {0, EMPTY, AIR, VAR_1}, - {0, EMPTY, AIR, VAR_1}, - {0, EMPTY, AIR, VAR_1}, - {"driftwood stack",FLOOR, DRIFTWOOD, VAR_1}, - - // 20 - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {"tree",TREE_OK, SOIL, VAR_1}, - {"ice stair up/down",STAIR_UPDOWN, ICE, VAR_1}, - {"ice stair down",STAIR_DOWN, ICE, VAR_1}, - {"ice stair up",STAIR_UP, ICE, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - - // 30 - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {"empty space",EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {"shrub",SHRUB_OK, SOIL, VAR_1}, - {"chasm",FLOOR, AIR, VAR_1}, - {"obsidian stair up/down",STAIR_UPDOWN, OBSIDIAN, VAR_1}, - {"obsidian stair down",STAIR_DOWN, OBSIDIAN, VAR_1}, - {"obsidian stair up",STAIR_UP, OBSIDIAN, VAR_1}, - {"soil stair up/down",STAIR_UPDOWN, SOIL, VAR_1}, - - // 40 - {"soil stair down",STAIR_DOWN, SOIL, VAR_1}, - {"soil stair up",STAIR_UP, SOIL, VAR_1}, - {"eerie pit",FLOOR, HFS, VAR_1}, - {"smooth stone floor",FLOOR, STONE, VAR_1}, - {"smooth obsidian floor",FLOOR, OBSIDIAN, VAR_1}, - {"smooth featstone? floor",FLOOR, FEATSTONE, VAR_1}, - {"smooth vein floor",FLOOR, VEIN, VAR_1}, - {"smooth ice floor",FLOOR, ICE, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {"grass stair up/down",STAIR_UPDOWN, GRASS, VAR_1}, - - // 50 - {"grass stair down",STAIR_DOWN, GRASS, VAR_1}, - {"grass stair up",STAIR_UP, GRASS, VAR_1}, - {"grass2 stair up/down",STAIR_UPDOWN, GRASS2, VAR_1}, - {"grass2 stair down",STAIR_DOWN, GRASS2, VAR_1}, - {"grass2 stair up",STAIR_UP, GRASS2, VAR_1}, - {"stone stair up/down",STAIR_UPDOWN, STONE, VAR_1}, - {"stone stair down",STAIR_DOWN, STONE, VAR_1}, - {"stone stair up",STAIR_UP, STONE, VAR_1}, - {"vein stair up/down",STAIR_UPDOWN, VEIN, VAR_1}, - {"vein stair down",STAIR_DOWN, VEIN, VAR_1}, - - // 60 - {"vein stair up",STAIR_UP, VEIN, VAR_1}, - {"featstone? stair up/down",STAIR_UPDOWN, FEATSTONE, VAR_1}, - {"featstone? stair down",STAIR_DOWN, FEATSTONE, VAR_1}, - {"featstone? stair up",STAIR_UP, FEATSTONE, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {"stone fortification",FORTIFICATION, STONE, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {"campfire",FLOOR, CAMPFIRE, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - - // 70 - {"fire",FLOOR, FIRE, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {"stone pillar",PILLAR, STONE, VAR_1}, - - //80 - {"obsidian pillar",PILLAR, OBSIDIAN, VAR_1}, - {"featstone? pillar",PILLAR, FEATSTONE, VAR_1}, - {"vein pillar",PILLAR, VEIN, VAR_1}, - {"ice pillar",PILLAR, ICE, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {"waterfall landing",FLOOR, SOIL, VAR_1}, // verify material - - // 90 - {"river source",FLOOR, SOIL, VAR_1}, // verify material - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - - // 100 - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - - // 110 - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - - // 120 - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - - // 130 - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - - // 140 - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - - // 150 - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - - // 160 - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - - // 170 - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {"cracked stone wall" ,WALL, STONE, VAR_1}, - {"damaged stone wall" ,WALL, STONE, VAR_1}, - {"worn stone wall" ,WALL, STONE, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - - // 180 - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - - // 190 - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - - // 200 - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - - // 210 - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {"stone wall" ,WALL, STONE, VAR_1}, - - // 220 - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - - // 230 - {0 ,EMPTY, AIR, VAR_1}, - {"sapling" ,SAPLING_OK, SOIL, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {"dry grass ramp" ,RAMP, GRASS_DRY, VAR_1}, - {"dead grass ramp" ,RAMP, GRASS_DEAD, VAR_1}, - {"grass ramp" ,RAMP, GRASS, VAR_1}, - {"grass ramp" ,RAMP, GRASS2, VAR_1}, - {"stone ramp" ,RAMP, STONE, VAR_1}, - {"obsidian ramp" ,RAMP, OBSIDIAN, VAR_1}, - {"featstone? ramp" ,RAMP, FEATSTONE, VAR_1}, - - // 240 - {"vein ramp" ,RAMP, VEIN, VAR_1}, - {"soil ramp" ,RAMP, SOIL, VAR_1}, - {"ashes" ,FLOOR, ASHES, VAR_1}, - {"ashes" ,FLOOR, ASHES, VAR_2}, - {"ashes" ,FLOOR, ASHES, VAR_3}, - {"ice ramp" ,RAMP, ICE, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - - // 250 - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {"ice floor" ,FLOOR, ICE, VAR_2}, - {"ice floor" ,FLOOR, ICE, VAR_3}, - - // 260 - {"ice floor" ,FLOOR, ICE, VAR_4}, - {"furrowed soil" ,FLOOR, SOIL, VAR_1}, - {"ice floor" ,FLOOR, ICE, VAR_1}, - {"semi-molten rock" ,WALL, MAGMA, VAR_1},// unminable magma wall - {"magma" ,FLOOR, MAGMA, VAR_1}, - {"soil wall" ,WALL, SOIL, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {"glowing floor" ,FLOOR, CYAN_GLOW, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {"smooth obsidian wall RD2",WALL,OBSIDIAN,VAR_1}, - - // 270 - {"smooth obsidian wall R2D",WALL,OBSIDIAN,VAR_1}, - {"smooth obsidian wall R2U",WALL,OBSIDIAN,VAR_1}, - {"smooth obsidian wall RU2",WALL,OBSIDIAN,VAR_1}, - {"smooth obsidian wall L2U",WALL,OBSIDIAN,VAR_1}, - {"smooth obsidian wall LU2",WALL,OBSIDIAN,VAR_1}, - {"smooth obsidian wall L2D",WALL,OBSIDIAN,VAR_1}, - {"smooth obsidian wall LD2",WALL,OBSIDIAN,VAR_1}, - {"smooth obsidian wall LRUD",WALL,OBSIDIAN,VAR_1}, - {"smooth obsidian wall RUD",WALL,OBSIDIAN,VAR_1}, - {"smooth obsidian wall LRD",WALL,OBSIDIAN,VAR_1}, - - // 280 - {"smooth obsidian wall LRU",WALL,OBSIDIAN,VAR_1}, - {"smooth obsidian wall LUD",WALL,OBSIDIAN,VAR_1}, - {"smooth obsidian wall RD",WALL,OBSIDIAN,VAR_1}, - {"smooth obsidian wall RU",WALL,OBSIDIAN,VAR_1}, - {"smooth obsidian wall LU",WALL,OBSIDIAN,VAR_1}, - {"smooth obsidian wall LD",WALL,OBSIDIAN,VAR_1}, - {"smooth obsidian wall UD",WALL,OBSIDIAN,VAR_1}, - {"smooth obsidian wall LR",WALL,OBSIDIAN,VAR_1}, - {"smooth featstone wall RD2",WALL,FEATSTONE,VAR_1}, - {"smooth featstone wall R2D",WALL,FEATSTONE,VAR_1}, - - // 290 - {"smooth featstone wall R2U",WALL,FEATSTONE,VAR_1}, - {"smooth featstone wall RU2",WALL,FEATSTONE,VAR_1}, - {"smooth featstone wall L2U",WALL,FEATSTONE,VAR_1}, - {"smooth featstone wall LU2",WALL,FEATSTONE,VAR_1}, - {"smooth featstone wall L2D",WALL,FEATSTONE,VAR_1}, - {"smooth featstone wall LD2",WALL,FEATSTONE,VAR_1}, - {"smooth featstone wall LRUD",WALL,FEATSTONE,VAR_1}, - {"smooth featstone wall RUD",WALL,FEATSTONE,VAR_1}, - {"smooth featstone wall LRD",WALL,FEATSTONE,VAR_1}, - {"smooth featstone wall LRU",WALL,FEATSTONE,VAR_1}, - - //300 - {"smooth featstone wall LUD",WALL,FEATSTONE,VAR_1}, - {"smooth featstone wall RD",WALL,FEATSTONE,VAR_1}, - {"smooth featstone wall RU",WALL,FEATSTONE,VAR_1}, - {"smooth featstone wall LU",WALL,FEATSTONE,VAR_1}, - {"smooth featstone wall LD",WALL,FEATSTONE,VAR_1}, - {"smooth featstone wall UD",WALL,FEATSTONE,VAR_1}, - {"smooth featstone wall LR",WALL,FEATSTONE,VAR_1}, - {"smooth stone wall RD2",WALL,STONE,VAR_1}, - {"smooth stone wall R2D",WALL,STONE,VAR_1}, - {"smooth stone wall R2U",WALL,STONE,VAR_1}, - - //310 - {"smooth stone wall RU2",WALL,STONE,VAR_1}, - {"smooth stone wall L2U",WALL,STONE,VAR_1}, - {"smooth stone wall LU2",WALL,STONE,VAR_1}, - {"smooth stone wall L2D",WALL,STONE,VAR_1}, - {"smooth stone wall LD2",WALL,STONE,VAR_1}, - {"smooth stone wall LRUD",WALL,STONE,VAR_1}, - {"smooth stone wall RUD",WALL,STONE,VAR_1}, - {"smooth stone wall LRD",WALL,STONE,VAR_1}, - {"smooth stone wall LRU",WALL,STONE,VAR_1}, - {"smooth stone wall LUD",WALL,STONE,VAR_1}, - - //320 - {"smooth stone wall RD",WALL,STONE,VAR_1}, - {"smooth stone wall RU",WALL,STONE,VAR_1}, - {"smooth stone wall LU",WALL,STONE,VAR_1}, - {"smooth stone wall LD",WALL,STONE,VAR_1}, - {"smooth stone wall UD",WALL,STONE,VAR_1}, - {"smooth stone wall LR",WALL,STONE,VAR_1}, - {"obsidian fortification",FORTIFICATION,OBSIDIAN,VAR_1}, - {"featstone? fortification",FORTIFICATION,FEATSTONE,VAR_1}, - {"cracked obsidian wall",WALL,OBSIDIAN,VAR_1}, - {"damaged obsidian wall",WALL,OBSIDIAN,VAR_1}, - - // 330 - {"worn obsidian wall",WALL,OBSIDIAN,VAR_1}, - {"obsidian wall",WALL,OBSIDIAN,VAR_1}, - /*MAPTILE_FEATSTONE_WALL_WORN1, - MAPTILE_FEATSTONE_WALL_WORN2, - MAPTILE_FEATSTONE_WALL_WORN3, - MAPTILE_FEATSTONE_WALL,*/ - {"cracked featstone wall",WALL,STONE,VAR_1}, - {"damaged featstone wall",WALL,STONE,VAR_1}, - {"worn featstone wall",WALL,STONE,VAR_1}, - {"featstone wall",WALL,STONE,VAR_1}, - {"stone floor",FLOOR,STONE,VAR_1}, - {"stone floor",FLOOR,STONE,VAR_2}, - {"stone floor",FLOOR,STONE,VAR_3}, - {"stone floor",FLOOR,STONE,VAR_4}, - - // 340 - {"obsidian floor",FLOOR,OBSIDIAN,VAR_1}, - {"obsidian floor",FLOOR,OBSIDIAN,VAR_2}, - {"obsidian floor",FLOOR,OBSIDIAN,VAR_3}, - {"obsidian floor",FLOOR,OBSIDIAN,VAR_4}, - {"featstone floor 1",FLOOR,FEATSTONE,VAR_1}, - {"featstone floor 2",FLOOR,FEATSTONE,VAR_2}, - {"featstone floor 3",FLOOR,FEATSTONE,VAR_3}, - {"featstone floor 4",FLOOR,FEATSTONE,VAR_4}, - {"grass 1",FLOOR,GRASS,VAR_1}, - {"grass 2",FLOOR,GRASS,VAR_2}, - - // 350 - {"grass 3",FLOOR,GRASS,VAR_3}, - {"grass 4",FLOOR,GRASS,VAR_4}, - {"soil floor",FLOOR,SOIL,VAR_1}, - {"soil floor",FLOOR,SOIL,VAR_2}, - {"soil floor",FLOOR,SOIL,VAR_3}, - {"soil floor",FLOOR,SOIL,VAR_4}, - {"wet soil floor",FLOOR,SOIL,VAR_1}, - {"wet soil floor",FLOOR,SOIL,VAR_2}, - {"wet soil floor",FLOOR,SOIL,VAR_3}, - {"wet soil floor",FLOOR,SOIL,VAR_4}, - - // 360 - {"ice fortification",FORTIFICATION,ICE,VAR_1}, - {"cracked ice wall",WALL,ICE,VAR_1}, - {"damaged ice wall",WALL,ICE,VAR_1}, - {"worn ice wall",WALL,ICE,VAR_1}, - {"ice wall",WALL,ICE,VAR_1}, - {"river N",FLOOR,SOIL,VAR_1}, - {"river S",FLOOR,SOIL,VAR_1}, - {"river E",FLOOR,SOIL,VAR_1}, - {"river W",FLOOR,SOIL,VAR_1}, - {"river NW",FLOOR,SOIL,VAR_1}, - - //370 - {"river NE",FLOOR,SOIL,VAR_1}, - {"river SW",FLOOR,SOIL,VAR_1}, - {"river SE",FLOOR,SOIL,VAR_1}, - {"stream bed N",FLOOR,SOIL,VAR_1}, - {"stream bed S",FLOOR,SOIL,VAR_1}, - {"stream bed E",FLOOR,SOIL,VAR_1}, - {"stream bed W",FLOOR,SOIL,VAR_1}, - {"stream bed NW",FLOOR,SOIL,VAR_1}, - {"stream bed NE",FLOOR,SOIL,VAR_1}, - {"stream bed SW",FLOOR,SOIL,VAR_1}, - - // 380 - {"stream bed SE",FLOOR,SOIL,VAR_1}, - {"stream top",FLOOR,SOIL,VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {"dry grass 1",FLOOR,GRASS_DRY,VAR_1}, - {"dry grass 2",FLOOR,GRASS_DRY,VAR_2}, - {"dry grass 3",FLOOR,GRASS_DRY,VAR_3}, - - // 390 - {"dry grass 4",FLOOR,GRASS_DRY,VAR_4}, - {"dead tree",TREE_DEAD,SOIL,VAR_1}, - {"dead sapling",SAPLING_DEAD,SOIL,VAR_1}, - {"dead shrub",SHRUB_DEAD,SOIL,VAR_1}, - {"dead grass 1",FLOOR,GRASS_DEAD,VAR_1}, - {"dead grass 2",FLOOR,GRASS_DEAD,VAR_2}, - {"dead grass 3",FLOOR,GRASS_DEAD,VAR_3}, - {"dead grass 4",FLOOR,GRASS_DEAD,VAR_4}, - {"grass B1",FLOOR,GRASS2,VAR_1}, - {"grass B2",FLOOR,GRASS2,VAR_2}, - - // 400 - {"grass B3",FLOOR,GRASS2,VAR_3}, - {"grass B4",FLOOR,GRASS2,VAR_4}, - {"boulder",BOULDER,STONE,VAR_1}, - {"obsidian boulder",BOULDER,OBSIDIAN,VAR_1}, - {"featstone? boulder",BOULDER,FEATSTONE,VAR_1}, - {"pebbles 1",PEBBLES,STONE,VAR_1}, - {"pebbles 2",PEBBLES,STONE,VAR_2}, - {"pebbles 3",PEBBLES,STONE,VAR_3}, - {"pebbles 4",PEBBLES,STONE,VAR_4}, - {"obsidian shards",PEBBLES,OBSIDIAN,VAR_1}, - - // 410 - {"obsidian shards",PEBBLES,OBSIDIAN,VAR_2}, - {"obsidian shards",PEBBLES,OBSIDIAN,VAR_3}, - {"obsidian shards",PEBBLES,OBSIDIAN,VAR_4}, - {"featstone? pebbles",PEBBLES,FEATSTONE,VAR_1}, - {"featstone? pebbles",PEBBLES,FEATSTONE,VAR_2}, - {"featstone? pebbles",PEBBLES,FEATSTONE,VAR_3}, - {"featstone? pebbles",PEBBLES,FEATSTONE,VAR_4}, - {"smooth vein wall",WALL,VEIN,VAR_1}, - {"smooth vein wall",WALL,VEIN,VAR_1}, - {"smooth vein wall",WALL,VEIN,VAR_1}, - - // 420 - {"smooth vein wall",WALL,VEIN,VAR_1}, - {"smooth vein wall",WALL,VEIN,VAR_1}, - {"smooth vein wall",WALL,VEIN,VAR_1}, - {"smooth vein wall",WALL,VEIN,VAR_1}, - {"smooth vein wall",WALL,VEIN,VAR_1}, - {"smooth vein wall",WALL,VEIN,VAR_1}, - {"smooth vein wall",WALL,VEIN,VAR_1}, - {"smooth vein wall",WALL,VEIN,VAR_1}, - {"smooth vein wall",WALL,VEIN,VAR_1}, - {"smooth vein wall",WALL,VEIN,VAR_1}, - - // 430 - {"smooth vein wall",WALL,VEIN,VAR_1}, - {"smooth vein wall",WALL,VEIN,VAR_1}, - {"smooth vein wall",WALL,VEIN,VAR_1}, - {"smooth vein wall",WALL,VEIN,VAR_1}, - {"smooth vein wall",WALL,VEIN,VAR_1}, - {"smooth vein wall",WALL,VEIN,VAR_1}, - {"vein fortification",FORTIFICATION,VEIN,VAR_1}, - {"cracked vein wall",WALL,VEIN,VAR_1}, - {"damaged vein wall",WALL,VEIN,VAR_1}, - {"worn vein wall",WALL,VEIN,VAR_1}, - - // 440 - {"vein wall",WALL,VEIN,VAR_1}, - {"vein floor",FLOOR,VEIN,VAR_1}, - {"vein floor",FLOOR,VEIN,VAR_2}, - {"vein floor",FLOOR,VEIN,VAR_3}, - {"vein floor",FLOOR,VEIN,VAR_4}, - {"vein boulder",BOULDER,VEIN,VAR_1}, - {"vein pebbles",PEBBLES,VEIN,VAR_1}, - {"vein pebbles",PEBBLES,VEIN,VAR_2}, - {"vein pebbles",PEBBLES,VEIN,VAR_3}, - {"vein pebbles",PEBBLES,VEIN,VAR_4}, - - // 450 - {"smooth ice wall",WALL,ICE,VAR_1}, - {"smooth ice wall",WALL,ICE,VAR_1}, - {"smooth ice wall",WALL,ICE,VAR_1}, - {"smooth ice wall",WALL,ICE,VAR_1}, - {"smooth ice wall",WALL,ICE,VAR_1}, - {"smooth ice wall",WALL,ICE,VAR_1}, - {"smooth ice wall",WALL,ICE,VAR_1}, - {"smooth ice wall",WALL,ICE,VAR_1}, - {"smooth ice wall",WALL,ICE,VAR_1}, - {"smooth ice wall",WALL,ICE,VAR_1}, - - // 460 - {"smooth ice wall",WALL,ICE,VAR_1}, - {"smooth ice wall",WALL,ICE,VAR_1}, - {"smooth ice wall",WALL,ICE,VAR_1}, - {"smooth ice wall",WALL,ICE,VAR_1}, - {"smooth ice wall",WALL,ICE,VAR_1}, - {"smooth ice wall",WALL,ICE,VAR_1}, - {"smooth ice wall",WALL,ICE,VAR_1}, - {"smooth ice wall",WALL,ICE,VAR_1}, - {"smooth ice wall",WALL,ICE,VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - - // 470 - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - - // 480 - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - - // 490 - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {"constructed floor",FLOOR,CONSTRUCTED, VAR_1}, - {"constructed fortification",FORTIFICATION,CONSTRUCTED, VAR_1}, - {"constructed pillar",PILLAR,CONSTRUCTED, VAR_1}, - {"constructed wall",WALL,CONSTRUCTED, VAR_1}, - {"constructed wall",WALL,CONSTRUCTED, VAR_1}, - {"constructed wall",WALL,CONSTRUCTED, VAR_1}, - {"constructed wall",WALL,CONSTRUCTED, VAR_1}, - - // 500 - {"constructed wall",WALL,CONSTRUCTED, VAR_1}, - {"constructed wall",WALL,CONSTRUCTED, VAR_1}, - {"constructed wall",WALL,CONSTRUCTED, VAR_1}, - {"constructed wall",WALL,CONSTRUCTED, VAR_1}, - {"constructed wall",WALL,CONSTRUCTED, VAR_1}, - {"constructed wall",WALL,CONSTRUCTED, VAR_1}, - {"constructed wall",WALL,CONSTRUCTED, VAR_1}, - {"constructed wall",WALL,CONSTRUCTED, VAR_1}, - {"constructed wall",WALL,CONSTRUCTED, VAR_1}, - {"constructed wall",WALL,CONSTRUCTED, VAR_1}, - - // 510 - {"constructed wall",WALL,CONSTRUCTED, VAR_1}, - {"constructed wall",WALL,CONSTRUCTED, VAR_1}, - {"constructed wall",WALL,CONSTRUCTED, VAR_1}, - {"constructed wall",WALL,CONSTRUCTED, VAR_1}, - {"constructed wall",WALL,CONSTRUCTED, VAR_1}, - {"constructed stair up/down",STAIR_UPDOWN,CONSTRUCTED, VAR_1}, - {"constructed stair down",STAIR_DOWN,CONSTRUCTED, VAR_1}, - {"constructed stair up",STAIR_UP,CONSTRUCTED, VAR_1}, - {"constructed ramp",RAMP,CONSTRUCTED, VAR_1}, - {0 ,EMPTY, AIR, VAR_1} // end - }; - - inline - bool isWallTerrain(int in) - { - return tileTypeTable[in].c >= WALL && tileTypeTable[in].c <= FORTIFICATION ; - } - - inline - bool isFloorTerrain(int in) - { - return tileTypeTable[in].c >= FLOOR && tileTypeTable[in].c <= PEBBLES; - } - - inline - bool isRampTerrain(int in) - { - return tileTypeTable[in].c == RAMP; - } - - inline - bool isStairTerrain(int in) - { - return tileTypeTable[in].c >= STAIR_UP && tileTypeTable[in].c <= STAIR_UPDOWN; - } - - inline - bool isOpenTerrain(int in) - { - return tileTypeTable[in].c == EMPTY; - } - - inline - int getVegetationType(int in) - { - return tileTypeTable[in].c; - } -} - - - -#endif // TILETYPES_H_INCLUDED +/* +www.sourceforge.net/projects/dfhack +Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#ifndef TILETYPES_H_INCLUDED +#define TILETYPES_H_INCLUDED + +#include "DFPragma.h" + +namespace DFHack +{ + + // tile class -- determines the general shape of the tile + // enum and lookup table for string names created using X macros +#define TILECLASS_MACRO \ + X(EMPTY, "") \ + X(WALL, "") \ + X(PILLAR, "") \ + X(FORTIFICATION, "") \ + X(STAIR_UP, "") \ + X(STAIR_DOWN, "") \ + X(STAIR_UPDOWN, "") \ + X(RAMP, "ramps have no direction" ) \ + X(RAMP_TOP, "used for pathing?" ) \ + X(FLOOR, "") \ + X(TREE_DEAD, "") \ + X(TREE_OK, "") \ + X(SAPLING_DEAD, "") \ + X(SAPLING_OK, "") \ + X(SHRUB_DEAD, "") \ + X(SHRUB_OK, "") \ + X(BOULDER, "") \ + X(PEBBLES, "") +//end TILECLASS_MACRO + + //define tile class enum + #define X(name,comment) name, + enum TileClass { + tileclass_invalid=-1, + TILECLASS_MACRO + tileclass_count, + }; + #undef X + + //Visual Studio screams if you don't do this for the const char* arrays + #ifndef char_p + typedef char * char_p; + #endif + + //set tile class string lookup table (e.g. for printing to user) + #define X(name,comment) #name, + const char_p TileClassString[tileclass_count+1] = { + TILECLASS_MACRO + NULL + }; + #undef X + + +#define TILEMATERIAL_MACRO \ + X(AIR, "empty" ) \ + X(SOIL, "ordinary soil. material depends on geology" ) \ + X(STONE, "ordinary layer stone. material depends on geology" ) \ + X(FEATSTONE, "map special stone. used for things like hell, the hell temple or adamantine tubes. material depends on local/global special" ) \ + X(OBSIDIAN, "cast obsidian" ) \ + X(VEIN, "vein stone. material depends on mineral veins present" ) \ + X(ICE, "frozen water... not much to say. you can determine what was on the tile before it froze by looking into the 'ice vein' objects" ) \ + X(GRASS, "grass (has 4 variants)" ) \ + X(GRASS2, "grass (has 4 variants)" ) \ + X(GRASS_DEAD, "dead grass (has 4 variants)" ) \ + X(GRASS_DRY, "dry grass (has 4 variants)" ) \ + X(DRIFTWOOD, "non-specified wood - normally on top of the local layer stone/soil." ) \ + X(HFS, "the stuff demon pits are made of - this makes them different from ordinary pits." ) \ + X(MAGMA, "material for semi-molten rock and 'magma flow' tiles" ) \ + X(CAMPFIRE, "human armies make them when they siege. The original tile may be lost?" ) \ + X(FIRE, "burning grass" ) \ + X(ASHES, "what remains from a FIRE" ) \ + X(CONSTRUCTED,"tile material depends on the construction present" ) \ + X(CYAN_GLOW, "the glowy stuff that disappears from the demon temple when you take the sword." ) +//end TILEMATERIAL_MACRO + + // material enum + #define X(name,comment) name, + enum TileMaterial { + tilematerial_invalid=-1, + TILEMATERIAL_MACRO + tilematerial_count, + }; + #undef X + + //string lookup table (e.g. for printing to user) + #define X(name,comment) #name, + const char_p TileMaterialString[tilematerial_count+1] = { + TILEMATERIAL_MACRO + NULL + }; + #undef X + + + // Special specials of the tile. + // Not the best way to do this, but compatible with existing code. + // When the TileType class gets created, everything should be re-thought. +#define TILESPECIAL_MACRO \ + X(NORMAL, "Default for all type, nothing present" ) \ + X(SPECIAL, "General purpose, for any unique tile which can not otherwise be differenciated" ) \ + X(POOL, "Murky Pool, will gather water from rain" ) \ + X(STREAM, "Streams (and brooks too? maybe?)" ) \ + X(STREAM_TOP, "The walkable surface of a stream/brook" ) \ + X(RIVER_SOURCE, "Rivers Source, when it exists on a map" ) \ + X(RIVER, "Rivers, and their entering and exiting tiles" ) \ + X(WATERFALL, "Special case for Waterfall Landing. How's this used?" ) \ + X(ENDLESS, "Eerie Pit and Old Chasm/Endless Pit" ) \ + X(CRACKED, "Walls being dug" ) \ + X(DAMAGED, "Walls being dug" ) \ + X(WORN, "Walls being dug ??" ) \ + X(SMOOTH, "Walls and floors." ) +//end TILESPECIAL_MACRO + + //special enum + #define X(name,comment) TILE_##name, + enum TileSpecial { + tilespecial_invalid=-1, + TILESPECIAL_MACRO + tilespecial_count, + }; + #undef X + + //string lookup table (e.g. for printing to user) + #define X(name,comment) #name, + const char_p TileSpecialString[tilespecial_count+1] = { + TILESPECIAL_MACRO + NULL + }; + #undef X + + + // variants are used for tiles, where there are multiple variants of the same - like grass floors + enum TileVariant + { + tilevariant_invalid=-1, + VAR_1, //Yes, the value of VAR_1 is 0. It's legacy. Deal with it. + VAR_2, + VAR_3, + VAR_4, + }; + + + //Mainly walls and rivers + //Byte values are used because walls can have either 1 or 2 in any given direction. + const int TileDirectionCount = 4; + union TileDirection + { + uint32_t whole; + unsigned char b[TileDirectionCount]; + struct { + //Maybe should add 'up' and 'down' for Z-levels? + unsigned char north,south,west,east; + }; + + inline TileDirection() + { + whole = 0; + } + TileDirection( uint32_t whole_bits) + { + whole = whole_bits; + } + TileDirection( unsigned char North, unsigned char South, unsigned char West, unsigned char East ) + { + north=North; south=South; east=East; west=West; + } + TileDirection( const char *dir ) + { + //This one just made for fun. + //Supports N S E W + const char *p = dir; + unsigned char *l=NULL; + north=south=east=west=0; + if(!dir) return; + + for( ;*p;++p){ + switch(*p){ + case 'N': //North / Up + case 'n': + ++north; l=&north; break; + case 'S': //South / Down + case 's': + ++south; l=&south; break; + case 'E': //East / Right + case 'e': + ++east; l=&east; break; + case 'W': //West / Left + case 'w': + ++west; l=&west; break; + case '-': + case ' ': + //Explicitly ensure dash and space are ignored. + //Other characters/symbols may be assigned in the future. + break; + default: + if( l && '0' <= *p && '9' >= *p ) + *l += *p - '0'; + break; + } + } + } + + //may be useful for some situations + inline uint32_t sum() const { + return 0L + north + south + east + west; + } + + //Gives a string that represents the direction. + //This is a static string, overwritten with every call! + //Support values > 2 even though they should never happen. + //Copy string if it will be used. + inline char * getStr() const { + static char str[16]; + //type punning trick + *( (uint64_t *)str ) = *( (uint64_t *)"--------" ); + str[8]=0; +#define DIRECTION(x,i,c) \ + if(x){ \ + str[i]=c; \ + if(1==x) ; \ + else if(2==x) str[i+1]=c; \ + else str[i+1]='0'+x; \ + } + + DIRECTION(north,0,'N') + DIRECTION(south,2,'S') + DIRECTION(west,4,'W') + DIRECTION(east,6,'E') +#undef DIRECTION + return str; + } + + + }; + + struct TileRow + { + const char * name; + TileClass c; + TileMaterial m; + TileVariant v; + TileSpecial s; + TileDirection d; + }; + + #define TILE_TYPE_ARRAY_LENGTH 520 + + const TileRow tileTypeTable[TILE_TYPE_ARRAY_LENGTH] = + { + // 0 + {"void",EMPTY, AIR, VAR_1}, + {"ramp top",RAMP_TOP, AIR, VAR_1}, + {"pool",FLOOR, SOIL, VAR_1, TILE_POOL}, + {0, EMPTY, AIR, VAR_1}, + {0, EMPTY, AIR, VAR_1}, + {0, EMPTY, AIR, VAR_1}, + {0, EMPTY, AIR, VAR_1}, + {0, EMPTY, AIR, VAR_1}, + {0, EMPTY, AIR, VAR_1}, + {0, EMPTY, AIR, VAR_1}, + + // 10 + {0, EMPTY, AIR, VAR_1}, + {0, EMPTY, AIR, VAR_1}, + {0, EMPTY, AIR, VAR_1}, + {0, EMPTY, AIR, VAR_1}, + {0, EMPTY, AIR, VAR_1}, + {0, EMPTY, AIR, VAR_1}, + {0, EMPTY, AIR, VAR_1}, + {0, EMPTY, AIR, VAR_1}, + {0, EMPTY, AIR, VAR_1}, + {"driftwood stack",FLOOR, DRIFTWOOD, VAR_1}, + + // 20 + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {"tree",TREE_OK, SOIL, VAR_1}, + {"ice stair up/down",STAIR_UPDOWN, ICE, VAR_1}, + {"ice stair down",STAIR_DOWN, ICE, VAR_1}, + {"ice stair up",STAIR_UP, ICE, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + + // 30 + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {"empty space",EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {"shrub",SHRUB_OK, SOIL, VAR_1}, + {"chasm",FLOOR, AIR, VAR_1, TILE_ENDLESS }, + {"obsidian stair up/down",STAIR_UPDOWN, OBSIDIAN, VAR_1}, + {"obsidian stair down",STAIR_DOWN, OBSIDIAN, VAR_1}, + {"obsidian stair up",STAIR_UP, OBSIDIAN, VAR_1}, + {"soil stair up/down",STAIR_UPDOWN, SOIL, VAR_1}, + + // 40 + {"soil stair down",STAIR_DOWN, SOIL, VAR_1}, + {"soil stair up",STAIR_UP, SOIL, VAR_1}, + {"eerie pit",FLOOR, HFS, VAR_1, TILE_ENDLESS}, + {"smooth stone floor",FLOOR, STONE, VAR_1 , TILE_SMOOTH }, + {"smooth obsidian floor",FLOOR, OBSIDIAN, VAR_1 , TILE_SMOOTH }, + {"smooth featstone? floor",FLOOR, FEATSTONE, VAR_1 , TILE_SMOOTH }, + {"smooth vein floor",FLOOR, VEIN, VAR_1 , TILE_SMOOTH }, + {"smooth ice floor",FLOOR, ICE, VAR_1 , TILE_SMOOTH }, + {0 ,EMPTY, AIR, VAR_1}, + {"grass stair up/down",STAIR_UPDOWN, GRASS, VAR_1}, + + // 50 + {"grass stair down",STAIR_DOWN, GRASS, VAR_1}, + {"grass stair up",STAIR_UP, GRASS, VAR_1}, + {"grass2 stair up/down",STAIR_UPDOWN, GRASS2, VAR_1}, + {"grass2 stair down",STAIR_DOWN, GRASS2, VAR_1}, + {"grass2 stair up",STAIR_UP, GRASS2, VAR_1}, + {"stone stair up/down",STAIR_UPDOWN, STONE, VAR_1}, + {"stone stair down",STAIR_DOWN, STONE, VAR_1}, + {"stone stair up",STAIR_UP, STONE, VAR_1}, + {"vein stair up/down",STAIR_UPDOWN, VEIN, VAR_1}, + {"vein stair down",STAIR_DOWN, VEIN, VAR_1}, + + // 60 + {"vein stair up",STAIR_UP, VEIN, VAR_1}, + {"featstone? stair up/down",STAIR_UPDOWN, FEATSTONE, VAR_1}, + {"featstone? stair down",STAIR_DOWN, FEATSTONE, VAR_1}, + {"featstone? stair up",STAIR_UP, FEATSTONE, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {"stone fortification",FORTIFICATION, STONE, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {"campfire",FLOOR, CAMPFIRE, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + + // 70 + {"fire",FLOOR, FIRE, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {"stone pillar",PILLAR, STONE, VAR_1}, + + //80 + {"obsidian pillar",PILLAR, OBSIDIAN, VAR_1}, + {"featstone? pillar",PILLAR, FEATSTONE, VAR_1}, + {"vein pillar",PILLAR, VEIN, VAR_1}, + {"ice pillar",PILLAR, ICE, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {"waterfall landing",FLOOR, SOIL, VAR_1, TILE_WATERFALL }, // verify material + + // 90 + {"river source",FLOOR, SOIL, VAR_1, TILE_RIVER_SOURCE }, // verify material + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + + // 100 + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + + // 110 + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + + // 120 + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + + // 130 + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + + // 140 + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + + // 150 + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + + // 160 + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + + // 170 + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {"cracked stone wall" ,WALL, STONE, VAR_1, TILE_CRACKED }, + {"damaged stone wall" ,WALL, STONE, VAR_1, TILE_DAMAGED }, + {"worn stone wall" ,WALL, STONE, VAR_1, TILE_WORN }, + {0 ,EMPTY, AIR, VAR_1}, + + // 180 + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + + // 190 + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + + // 200 + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + + // 210 + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {"stone wall" ,WALL, STONE, VAR_1}, + + // 220 + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + + // 230 + {0 ,EMPTY, AIR, VAR_1}, + {"sapling" ,SAPLING_OK, SOIL, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {"dry grass ramp" ,RAMP, GRASS_DRY, VAR_1}, + {"dead grass ramp" ,RAMP, GRASS_DEAD, VAR_1}, + {"grass ramp" ,RAMP, GRASS, VAR_1}, + {"grass ramp" ,RAMP, GRASS2, VAR_1}, + {"stone ramp" ,RAMP, STONE, VAR_1}, + {"obsidian ramp" ,RAMP, OBSIDIAN, VAR_1}, + {"featstone? ramp" ,RAMP, FEATSTONE, VAR_1}, + + // 240 + {"vein ramp" ,RAMP, VEIN, VAR_1}, + {"soil ramp" ,RAMP, SOIL, VAR_1}, + {"ashes" ,FLOOR, ASHES, VAR_1}, + {"ashes" ,FLOOR, ASHES, VAR_2}, + {"ashes" ,FLOOR, ASHES, VAR_3}, + {"ice ramp" ,RAMP, ICE, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + + // 250 + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {"ice floor" ,FLOOR, ICE, VAR_2}, + {"ice floor" ,FLOOR, ICE, VAR_3}, + + // 260 + {"ice floor" ,FLOOR, ICE, VAR_4}, + {"furrowed soil" ,FLOOR, SOIL, VAR_1}, + {"ice floor" ,FLOOR, ICE, VAR_1}, + {"semi-molten rock" ,WALL, MAGMA, VAR_1},// unminable magma wall + {"magma" ,FLOOR, MAGMA, VAR_1}, + {"soil wall" ,WALL, SOIL, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {"glowing floor" ,FLOOR, CYAN_GLOW, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {"smooth obsidian wall RD2",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "--SS--E-" }, + + // 270 + {"smooth obsidian wall R2D",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "--S---EE" }, + {"smooth obsidian wall R2U",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "N-----EE" }, + {"smooth obsidian wall RU2",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "NN----E-" }, + {"smooth obsidian wall L2U",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "N---WW--" }, + {"smooth obsidian wall LU2",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "NN--W---" }, + {"smooth obsidian wall L2D",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "--S-WW--" }, + {"smooth obsidian wall LD2",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "--SSW---" }, + {"smooth obsidian wall LRUD",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH ,"N-S-W-E-" }, + {"smooth obsidian wall RUD",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "N-S---E-" }, + {"smooth obsidian wall LRD",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "--S-W-E-" }, + + // 280 + {"smooth obsidian wall LRU",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "N---W-E-" }, + {"smooth obsidian wall LUD",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "N-S-W---" }, + {"smooth obsidian wall RD",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "--S---E-" }, + {"smooth obsidian wall RU",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "N-----E-" }, + {"smooth obsidian wall LU",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "N---W---" }, + {"smooth obsidian wall LD",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "--S-W---" }, + {"smooth obsidian wall UD",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "N-S-----" }, + {"smooth obsidian wall LR",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "----W-E-" }, + {"smooth featstone wall RD2",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "--SS--E-" }, + {"smooth featstone wall R2D",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "--S---EE" }, + + // 290 + {"smooth featstone wall R2U",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "N-----EE" }, + {"smooth featstone wall RU2",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "NN----E-" }, + {"smooth featstone wall L2U",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "N---WW--" }, + {"smooth featstone wall LU2",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "NN--W---" }, + {"smooth featstone wall L2D",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "--S-WW--" }, + {"smooth featstone wall LD2",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "--SSW---" }, + {"smooth featstone wall LRUD",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH ,"N-S-W-E-" }, + {"smooth featstone wall RUD",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "N-S---E-" }, + {"smooth featstone wall LRD",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "--S-W-E-" }, + {"smooth featstone wall LRU",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "N---W-E-" }, + + //300 + {"smooth featstone wall LUD",WALL,FEATSTONE,VAR_1, TILE_SMOOTH , "N-S-W---" }, + {"smooth featstone wall RD",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "--S---E-" }, + {"smooth featstone wall RU",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "N-----E-" }, + {"smooth featstone wall LU",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "N---W---" }, + {"smooth featstone wall LD",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "--S-W---" }, + {"smooth featstone wall UD",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "N-S-----" }, + {"smooth featstone wall LR",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "----W-E-" }, + {"smooth stone wall RD2",WALL,STONE,VAR_1 , TILE_SMOOTH , "--SS--E-" }, + {"smooth stone wall R2D",WALL,STONE,VAR_1 , TILE_SMOOTH , "--S---EE" }, + {"smooth stone wall R2U",WALL,STONE,VAR_1 , TILE_SMOOTH , "N-----EE" }, + + //310 + {"smooth stone wall RU2",WALL,STONE,VAR_1 , TILE_SMOOTH , "NN----E-" }, + {"smooth stone wall L2U",WALL,STONE,VAR_1 , TILE_SMOOTH , "N---WW--" }, + {"smooth stone wall LU2",WALL,STONE,VAR_1 , TILE_SMOOTH , "NN--W---" }, + {"smooth stone wall L2D",WALL,STONE,VAR_1 , TILE_SMOOTH , "--S-WW--" }, + {"smooth stone wall LD2",WALL,STONE,VAR_1 , TILE_SMOOTH , "--SSW---" }, + {"smooth stone wall LRUD",WALL,STONE,VAR_1 , TILE_SMOOTH , "N-S-W-E-" }, + {"smooth stone wall RUD",WALL,STONE,VAR_1 , TILE_SMOOTH , "N-S---E-" }, + {"smooth stone wall LRD",WALL,STONE,VAR_1 , TILE_SMOOTH , "--S-W-E-" }, + {"smooth stone wall LRU",WALL,STONE,VAR_1 , TILE_SMOOTH , "N---W-E-" }, + {"smooth stone wall LUD",WALL,STONE,VAR_1 , TILE_SMOOTH , "N-S-W---" }, + + //320 + {"smooth stone wall RD",WALL,STONE,VAR_1 , TILE_SMOOTH , "--S---E-" }, + {"smooth stone wall RU",WALL,STONE,VAR_1 , TILE_SMOOTH , "N-----E-" }, + {"smooth stone wall LU",WALL,STONE,VAR_1 , TILE_SMOOTH , "N---W---" }, + {"smooth stone wall LD",WALL,STONE,VAR_1 , TILE_SMOOTH , "--S-W---" }, + {"smooth stone wall UD",WALL,STONE,VAR_1 , TILE_SMOOTH , "N-S-----" }, + {"smooth stone wall LR",WALL,STONE,VAR_1 , TILE_SMOOTH , "----W-E-" }, + {"obsidian fortification",FORTIFICATION,OBSIDIAN,VAR_1}, + {"featstone? fortification",FORTIFICATION,FEATSTONE,VAR_1}, + {"cracked obsidian wall",WALL,OBSIDIAN,VAR_1, TILE_CRACKED }, + {"damaged obsidian wall",WALL,OBSIDIAN,VAR_1, TILE_DAMAGED }, + + // 330 + {"worn obsidian wall",WALL,OBSIDIAN,VAR_1}, + {"obsidian wall",WALL,OBSIDIAN,VAR_1}, + /*MAPTILE_FEATSTONE_WALL_WORN1, + MAPTILE_FEATSTONE_WALL_WORN2, + MAPTILE_FEATSTONE_WALL_WORN3, + MAPTILE_FEATSTONE_WALL,*/ + {"cracked featstone wall",WALL,STONE,VAR_1, TILE_CRACKED }, + {"damaged featstone wall",WALL,STONE,VAR_1, TILE_DAMAGED }, + {"worn featstone wall",WALL,STONE,VAR_1, TILE_WORN }, + {"featstone wall",WALL,STONE,VAR_1}, + {"stone floor",FLOOR,STONE,VAR_1}, + {"stone floor",FLOOR,STONE,VAR_2}, + {"stone floor",FLOOR,STONE,VAR_3}, + {"stone floor",FLOOR,STONE,VAR_4}, + + // 340 + {"obsidian floor",FLOOR,OBSIDIAN,VAR_1}, + {"obsidian floor",FLOOR,OBSIDIAN,VAR_2}, + {"obsidian floor",FLOOR,OBSIDIAN,VAR_3}, + {"obsidian floor",FLOOR,OBSIDIAN,VAR_4}, + {"featstone floor 1",FLOOR,FEATSTONE,VAR_1}, + {"featstone floor 2",FLOOR,FEATSTONE,VAR_2}, + {"featstone floor 3",FLOOR,FEATSTONE,VAR_3}, + {"featstone floor 4",FLOOR,FEATSTONE,VAR_4}, + {"grass 1",FLOOR,GRASS,VAR_1}, + {"grass 2",FLOOR,GRASS,VAR_2}, + + // 350 + {"grass 3",FLOOR,GRASS,VAR_3}, + {"grass 4",FLOOR,GRASS,VAR_4}, + {"soil floor",FLOOR,SOIL,VAR_1}, + {"soil floor",FLOOR,SOIL,VAR_2}, + {"soil floor",FLOOR,SOIL,VAR_3}, + {"soil floor",FLOOR,SOIL,VAR_4}, + {"wet soil floor",FLOOR,SOIL,VAR_1}, + {"wet soil floor",FLOOR,SOIL,VAR_2}, + {"wet soil floor",FLOOR,SOIL,VAR_3}, + {"wet soil floor",FLOOR,SOIL,VAR_4}, + + // 360 + {"ice fortification",FORTIFICATION,ICE,VAR_1}, + {"cracked ice wall",WALL,ICE,VAR_1, TILE_CRACKED}, + {"damaged ice wall",WALL,ICE,VAR_1, TILE_DAMAGED}, + {"worn ice wall",WALL,ICE,VAR_1, TILE_WORN }, + {"ice wall",WALL,ICE,VAR_1}, + {"river N",FLOOR,SOIL,VAR_1, TILE_RIVER , "N" }, + {"river S",FLOOR,SOIL,VAR_1, TILE_RIVER , "S" }, + {"river E",FLOOR,SOIL,VAR_1, TILE_RIVER , "E" }, + {"river W",FLOOR,SOIL,VAR_1, TILE_RIVER , "W" }, + {"river NW",FLOOR,SOIL,VAR_1, TILE_RIVER, "NW"}, + + //370 + {"river NE",FLOOR,SOIL,VAR_1, TILE_RIVER , "NE" }, + {"river SW",FLOOR,SOIL,VAR_1, TILE_RIVER , "SW" }, + {"river SE",FLOOR,SOIL,VAR_1, TILE_RIVER , "SE" }, + {"stream bed N",FLOOR,SOIL,VAR_1, TILE_STREAM , "N" }, + {"stream bed S",FLOOR,SOIL,VAR_1, TILE_STREAM , "S" }, + {"stream bed E",FLOOR,SOIL,VAR_1, TILE_STREAM , "E" }, + {"stream bed W",FLOOR,SOIL,VAR_1, TILE_STREAM , "W" }, + {"stream bed NW",FLOOR,SOIL,VAR_1, TILE_STREAM, "NW" }, + {"stream bed NE",FLOOR,SOIL,VAR_1, TILE_STREAM, "NE" }, + {"stream bed SW",FLOOR,SOIL,VAR_1, TILE_STREAM, "SW" }, + + // 380 + {"stream bed SE",FLOOR,SOIL,VAR_1, TILE_STREAM, "SE" }, + {"stream top",FLOOR,SOIL,VAR_1, TILE_STREAM_TOP }, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {"dry grass 1",FLOOR,GRASS_DRY,VAR_1}, + {"dry grass 2",FLOOR,GRASS_DRY,VAR_2}, + {"dry grass 3",FLOOR,GRASS_DRY,VAR_3}, + + // 390 + {"dry grass 4",FLOOR,GRASS_DRY,VAR_4}, + {"dead tree",TREE_DEAD,SOIL,VAR_1}, + {"dead sapling",SAPLING_DEAD,SOIL,VAR_1}, + {"dead shrub",SHRUB_DEAD,SOIL,VAR_1}, + {"dead grass 1",FLOOR,GRASS_DEAD,VAR_1}, + {"dead grass 2",FLOOR,GRASS_DEAD,VAR_2}, + {"dead grass 3",FLOOR,GRASS_DEAD,VAR_3}, + {"dead grass 4",FLOOR,GRASS_DEAD,VAR_4}, + {"grass B1",FLOOR,GRASS2,VAR_1}, + {"grass B2",FLOOR,GRASS2,VAR_2}, + + // 400 + {"grass B3",FLOOR,GRASS2,VAR_3}, + {"grass B4",FLOOR,GRASS2,VAR_4}, + {"boulder",BOULDER,STONE,VAR_1}, + {"obsidian boulder",BOULDER,OBSIDIAN,VAR_1}, + {"featstone? boulder",BOULDER,FEATSTONE,VAR_1}, + {"pebbles 1",PEBBLES,STONE,VAR_1}, + {"pebbles 2",PEBBLES,STONE,VAR_2}, + {"pebbles 3",PEBBLES,STONE,VAR_3}, + {"pebbles 4",PEBBLES,STONE,VAR_4}, + {"obsidian shards",PEBBLES,OBSIDIAN,VAR_1}, + + // 410 + {"obsidian shards",PEBBLES,OBSIDIAN,VAR_2}, + {"obsidian shards",PEBBLES,OBSIDIAN,VAR_3}, + {"obsidian shards",PEBBLES,OBSIDIAN,VAR_4}, + {"featstone? pebbles",PEBBLES,FEATSTONE,VAR_1}, + {"featstone? pebbles",PEBBLES,FEATSTONE,VAR_2}, + {"featstone? pebbles",PEBBLES,FEATSTONE,VAR_3}, + {"featstone? pebbles",PEBBLES,FEATSTONE,VAR_4}, + {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "--SS--E-"}, + {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "--S---EE"}, + {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N-----EE" }, + + // 420 + {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "NN----E-"}, + {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N---WW--"}, + {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "NN--W---"}, + {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "--S-WW--" }, + {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "--SSW---"}, + {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N-S-W-E-"}, + {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N-S---E-"}, + {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "--S-W-E-"}, + {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N---W-E-"}, + {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N-S-W---"}, + + // 430 + {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "--S---E-"}, + {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N-----E-"}, + {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N---W---"}, + {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "--S-W---"}, + {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N-S-----"}, + {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "----W-E-"}, + {"vein fortification",FORTIFICATION,VEIN,VAR_1}, + {"cracked vein wall",WALL,VEIN,VAR_1, TILE_CRACKED }, + {"damaged vein wall",WALL,VEIN,VAR_1, TILE_DAMAGED }, + {"worn vein wall",WALL,VEIN,VAR_1 , TILE_WORN }, + + // 440 + {"vein wall",WALL,VEIN,VAR_1}, + {"vein floor",FLOOR,VEIN,VAR_1}, + {"vein floor",FLOOR,VEIN,VAR_2}, + {"vein floor",FLOOR,VEIN,VAR_3}, + {"vein floor",FLOOR,VEIN,VAR_4}, + {"vein boulder",BOULDER,VEIN,VAR_1}, + {"vein pebbles",PEBBLES,VEIN,VAR_1}, + {"vein pebbles",PEBBLES,VEIN,VAR_2}, + {"vein pebbles",PEBBLES,VEIN,VAR_3}, + {"vein pebbles",PEBBLES,VEIN,VAR_4}, + + // 450 + {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "--SS--E-"}, + {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "--S---EE" }, + {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N-----EE" }, + {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "NN----E-"}, + {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N---WW--" }, + {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "NN--W---" }, + {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "--S-WW--" }, + {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "--SSW---" }, + {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N-S-W-E-"}, + {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N-S---E-" }, + + // 460 + {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "--S-W-E-" }, + {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N---W-E-" }, + {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N-S-W---"}, + {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "--S---E-"}, + {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N-----E-" }, + {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N---W---" }, + {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "--S-W---" }, + {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N-S-----" }, + {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "----W-E-"}, + {0 ,EMPTY, AIR, VAR_1}, + + // 470 + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + + // 480 + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + + // 490 + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {"constructed floor",FLOOR,CONSTRUCTED, VAR_1}, + {"constructed fortification",FORTIFICATION,CONSTRUCTED, VAR_1}, + {"constructed pillar",PILLAR,CONSTRUCTED, VAR_1}, + {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "--SS--E-" }, + {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "--S---EE" }, + {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N-----EE" }, + {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "NN----E-" }, + + // 500 + {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N---WW--" }, + {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "NN--W---" }, + {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "--S-WW--" }, + {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "--SSW---" }, + {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N-S-W-E-" }, + {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N-S---E-" }, + {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "--S-W-E-" }, + {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N---W-E-" }, + {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N-S-W---" }, + {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "--S---E-" }, + + // 510 + {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N-----E-" }, + {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N---W---" }, + {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "--S-W---" }, + {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N-S-----" }, + {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "----W-E-" }, + {"constructed stair up/down",STAIR_UPDOWN,CONSTRUCTED, VAR_1}, + {"constructed stair down",STAIR_DOWN,CONSTRUCTED, VAR_1}, + {"constructed stair up",STAIR_UP,CONSTRUCTED, VAR_1}, + {"constructed ramp",RAMP,CONSTRUCTED, VAR_1}, + {0 ,EMPTY, AIR, VAR_1} // end + }; + + inline + bool isWallTerrain(int in) + { + return tileTypeTable[in].c >= WALL && tileTypeTable[in].c <= FORTIFICATION ; + } + + inline + bool isFloorTerrain(int in) + { + return tileTypeTable[in].c >= FLOOR && tileTypeTable[in].c <= PEBBLES; + } + + inline + bool isRampTerrain(int in) + { + return tileTypeTable[in].c == RAMP; + } + + inline + bool isStairTerrain(int in) + { + return tileTypeTable[in].c >= STAIR_UP && tileTypeTable[in].c <= STAIR_UPDOWN; + } + + inline + bool isOpenTerrain(int in) + { + return tileTypeTable[in].c == EMPTY; + } + + inline + int getVegetationType(int in) + { + return tileTypeTable[in].c; + } + + //zilpin: for convenience, when you'll be using the tile information a lot. + inline const + TileRow * getTileTypeP(int in) + { + if( in<0 || in>=TILE_TYPE_ARRAY_LENGTH ) return NULL; + return ( const TileRow * ) &tileTypeTable[in]; + } + + //zilpin: Find the first tile entry which matches the given search criteria. + //All parameters are optional. + //To omit, use the 'invalid' enum for that type (e.g. tileclass_invalid, tilematerial_invalid, etc) + //For tile directions, pass NULL to omit. + //Returns matching index in tileTypeTable, or -1 if none found. + inline + int32_t findTileType( const TileClass tclass, const TileMaterial tmat, const TileVariant tvar, const TileSpecial tspecial, const TileDirection tdir ) + { + int32_t tt; + for(tt=0;tt-1 ) if( tclass != tileTypeTable[tt].c ) continue; + if( tmat>-1 ) if( tmat != tileTypeTable[tt].m ) continue; + if( tvar>-1 ) if( tvar != tileTypeTable[tt].v ) continue; + if( tspecial>-1 ) if( tspecial != tileTypeTable[tt].s ) continue; + if( tdir.whole ) if( tdir.whole != tileTypeTable[tt].d.whole ) continue; + //Match! + return tt; + } + return -1; + } + //Convenience version of the above, to pass strings as the direction + inline + int32_t findTileType( const TileClass tclass, const TileMaterial tmat, const TileVariant tvar, const TileSpecial tspecial, const char *tdirStr ) + { + if(tdirStr){ + TileDirection tdir(tdirStr); + return findTileType(tclass,tmat,tvar,tspecial, tdir ); + }else{ + return findTileType(tclass,tmat,tvar,tspecial, NULL ); + } + } + + + //zilpin: Find a tile type similar to the one given, but with a different class. + //Useful for tile-editing operations. + //If no match found, returns the sourceType + //Definitely needs improvement for wall directions, etc. + inline + int32_t findSimilarTileType( const int32_t sourceTileType, const TileClass tclass ){ + int32_t tt, maybe=0, match=0; + int value=0, matchv=0; + const TileRow *source = &tileTypeTable[sourceTileType]; + const char * sourcename = source->name; + const uint32_t sourcenameint = *((const uint32_t *)sourcename); + +#ifdef assert + assert( sourceTileType >=0 && sourceTileType < TILE_TYPE_ARRAY_LENGTH ); +#endif + + for(tt=0;tts != tileTypeTable[tt].s ) continue; + + maybe=tt; value=0; + //Material is high-value match + if( tileTypeTable[tt].m == source->m ) value|=8; + //Direction is medium value match + if( tileTypeTable[tt].d.whole == source->d.whole ) value|=4; + //Variant is low-value match + if( tileTypeTable[tt].v == source->v ) value|=1; + + //Check value against last match + if( value>matchv ){ + match=tt; + matchv=value; + } + } + } + if( match ) return match; + return sourceTileType; + } + + +} + + + +#endif // TILETYPES_H_INCLUDED diff --git a/tools/playground/CMakeLists.txt b/tools/playground/CMakeLists.txt index f21d9170c..291845660 100644 --- a/tools/playground/CMakeLists.txt +++ b/tools/playground/CMakeLists.txt @@ -67,6 +67,31 @@ TARGET_LINK_LIBRARIES(dfcopypaste dfhack) ADD_EXECUTABLE(dfpaths paths.cpp) TARGET_LINK_LIBRARIES(dfpaths dfhack) +# deramp +# Author: zilpin +# seeks entire map for 'remove ramp' designation, makes a floor, removes designation. +# intended use is to simulate old 'channel' functionality. +ADD_EXECUTABLE(dfderamp deramp.cpp) +TARGET_LINK_LIBRARIES(dfderamp dfhack) + + +# printtiletypes +# Author: zilpin +# Prints CSV dump of all tile type information. +# No DF process needed. Intended only for debugging and information purposes. +ADD_EXECUTABLE(dfprinttiletypes printtiletypes.cpp) +TARGET_LINK_LIBRARIES(dfprinttiletypes dfhack) + +# hellhole +# Author: zilpin +# Creates a bottomless hole to hell. +# Experimental version hard-codes values. +# Will have many options in the future. +ADD_EXECUTABLE(dfhellhole hellhole.cpp) +TARGET_LINK_LIBRARIES(dfhellhole dfhack) + + + # this needs the C bindings IF(BUILD_DFHACK_C_BINDINGS) # for trying out some 'stuff' @@ -83,6 +108,9 @@ dfmoodump dfdigger dfdigger2 dfcatsplosion +dfderamp +dfprinttiletypes +dfhellhole RUNTIME DESTINATION bin ) IF(UNIX) diff --git a/tools/playground/deramp.cpp b/tools/playground/deramp.cpp new file mode 100644 index 000000000..3cfbf5170 --- /dev/null +++ b/tools/playground/deramp.cpp @@ -0,0 +1,128 @@ +// De-ramp. All ramps marked for removal are replaced with given tile (presently, normal floor). + +#include +#include +#include +#include +#include +using namespace std; + +#include +#include + + +int main (void) +{ + uint32_t x_max,y_max,z_max; + uint32_t num_blocks = 0; + uint32_t bytes_read = 0; + DFHack::designations40d designations; + DFHack::tiletypes40d tiles; + DFHack::tiletypes40d tilesAbove; + + //DFHack::TileRow *ptile; + int32_t oldT, newT; + int16_t t; + + int dirty=0, count=0; + + DFHack::ContextManager DFMgr("Memory.xml"); + DFHack::Context *DF = DFMgr.getSingleContext(); + + //sanity check + assert( sizeof(designations) == (16*16*sizeof(DFHack::t_designation)) ); + + //Init + try + { + DF->Attach(); + } + catch (exception& e) + { + cerr << e.what() << endl; + #ifndef LINUX_BUILD + cin.ignore(); + #endif + return 1; + } + DFHack::Maps *Mapz = DF->getMaps(); + + // init the map + if(!Mapz->Start()) + { + cerr << "Can't init map." << endl; + #ifndef LINUX_BUILD + cin.ignore(); + #endif + return 1; + } + + Mapz->getSize(x_max,y_max,z_max); + + uint8_t zeroes [16][16] = {0}; + + // walk the map + for(uint32_t x = 0; x< x_max;x++) + { + for(uint32_t y = 0; y< y_max;y++) + { + for(uint32_t z = 0; z< z_max;z++) + { + if(Mapz->isValidBlock(x,y,z)) + { + dirty=0; + Mapz->ReadDesignations(x,y,z, &designations); + Mapz->ReadTileTypes(x,y,z, &tiles); + if(Mapz->isValidBlock(x,y,z+1)){ + Mapz->ReadTileTypes(x,y,z+1, &tilesAbove); + }else{ + memset(&tilesAbove,0,sizeof(tilesAbove)); + } + + for(uint32_t ty=0;ty<16;++ty){ + for(uint32_t tx=0;tx<16;++tx){ + //Only the remove ramp designation (ignore channel designation, etc) + oldT = tiles[tx][ty]; + if( DFHack::designation_default == designations[tx][ty].bits.dig + && DFHack::RAMP==DFHack::tileTypeTable[oldT].c + ){ + //Current tile is a ramp. + //Set current tile, as accurately as can be expected + newT = DFHack::findSimilarTileType(oldT,DFHack::FLOOR); + + //If no change, skip it (couldn't find a good tile type) + if( oldT == newT) continue; + //Set new tile type, clear designation + tiles[tx][ty] = newT; + designations[tx][ty].bits.dig = DFHack::designation_no; + + //Check the tile above this one, in case a downward slope needs to be removed. + if( DFHack::RAMP_TOP == DFHack::tileTypeTable[tilesAbove[tx][ty]].c ){ + tilesAbove[tx][ty] = 32; + } + + dirty=-1; + ++count; + } + } + } + //If anything was changed, write it all. + if(dirty){ + Mapz->WriteDesignations(x,y,z, &designations); + Mapz->WriteTileTypes(x,y,z, &tiles); + if(Mapz->isValidBlock(x,y,z+1)){ + Mapz->WriteTileTypes(x,y,z+1, &tilesAbove); + } + } + } + } + } + } + DF->Detach(); + cout << "Found and changed " << count << " tiles." << endl; + #ifndef LINUX_BUILD + cout << "Done. Press any key to continue" << endl; + cin.ignore(); + #endif + return 0; +} diff --git a/tools/playground/hellhole.cpp b/tools/playground/hellhole.cpp new file mode 100644 index 000000000..06d1847d3 --- /dev/null +++ b/tools/playground/hellhole.cpp @@ -0,0 +1,426 @@ +// Burn a hole straight to hell! + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +using namespace std; + +#include +#include +#include +using namespace DFHack; + + +#ifdef LINUX_BUILD +#include +void waitmsec (int delay) +{ + usleep(delay); +} +#else +#include +void waitmsec (int delay) +{ + Sleep(delay); +} +#endif + + + +int main (void) +{ + srand ( time(NULL) ); + + int64_t n; + uint32_t x_max,y_max,z_max; + + //The Tile Type to use for the walls lining the hole + //263 is semi-molten rock, 331 is obsidian + uint32_t whell=263, wmolten=263, wmagma=331, wcave=331; + //The Tile Type to use for the hole's floor at bottom of the map + //35 is chasm, 42 is eerie pit , 340 is obsidian floor + uint32_t floor=35, cap=340; + //Should tiles be revealed? + int reveal=0; + + + //Pattern to dig + unsigned char pattern[16][16] = {0,}; + + { + //Calculate a randomized circle. + //These values found through experimentation. + int radius=6; + int x=0, y=0; + + for(y=-radius; y<=radius; ++y){ + for(x=-radius; x<=radius; ++x){ + if(x*x+y*y <= radius*radius + (rand()&31) ){ + pattern[7+x][7+y]=1; + } + } + } + //Post-process to figure out where to put walls. + for(y=0;y<16;++y){ + for(x=0;x<16;++x){ + if( 1==pattern[x][y] ){ + //No hole at edges. + if( x<1 || x>14 || y<1 || y>14 ){ + pattern[x][y]=2; + } + }else if( 0==pattern[x][y] ){ + //check neighbors + if( x>0 && y>0 && 1==pattern[x-1][y-1] ){ pattern[x][y]=2; continue; } + if( x>0 && 1==pattern[x-1][y ] ){ pattern[x][y]=2; continue; } + if( y>0 && 1==pattern[x ][y-1] ){ pattern[x][y]=2; continue; } + if( x<15 && 1==pattern[x+1][y ] ){ pattern[x][y]=2; continue; } + if( x<15&& y>0 && 1==pattern[x+1][y-1] ){ pattern[x][y]=2; continue; } + if( x<15&& y<15&& 1==pattern[x+1][y+1] ){ pattern[x][y]=2; continue; } + if( y<15&& 1==pattern[x ][y+1] ){ pattern[x][y]=2; continue; } + if( x>0 && y<15&& 1==pattern[x-1][y+1] ){ pattern[x][y]=2; continue; } + } + } + } + //Final pass, makes sure that somewhere random gets a vertical pillar of rock which is safe + //to dig stairs down, to permit access to anywhere within the pit from the top. + for(x=0, y=0; 1!=pattern[x][y]; x=rand()&15, y=rand()&15 ){} + pattern[x][y]=3; + +#if 0 + cout << endl; + //Print the pattern (debugging) + for(y=0;y<16;++y){ + for(x=0;x<16;++x){ + printf("%d",pattern[x][y]); + } + cout << endl; + } + cout << endl; + cin.ignore(); + return 0; +#endif + + } + + + + DFHack::ContextManager DFMgr("Memory.xml"); + DFHack::Context *DF = DFMgr.getSingleContext(); + + + //Message of intent + cout << + "DF Hell Hole" << endl << + "This program will instantly dig a hole through hell, wherever your cursor is." << endl << + "This can not be undone! End program now if you don't want hellish fun." << endl + ; + cin.ignore(); + + //Init + try + { + DF->Attach(); + } + catch (exception& e) + { + cerr << e.what() << endl; + #ifndef LINUX_BUILD + cin.ignore(); + #endif + return 1; + } + + // init the map + DFHack::Maps *Mapz = DF->getMaps(); + if(!Mapz->Start()) + { + cerr << "Can't init map. Exiting." << endl; + #ifndef LINUX_BUILD + cin.ignore(); + #endif + return 1; + } + + Mapz->getSize(x_max,y_max,z_max); + + + //Get cursor + int32_t cursorX, cursorY, cursorZ; + DFHack::Position *Pos = DF->getPosition(); + Pos->getCursorCoords(cursorX,cursorY,cursorZ); + if(-30000==cursorX){ + cout << "No cursor position found. Exiting." << endl; + #ifndef LINUX_BUILD + cin.ignore(); + #endif + return 1; + } + + //Block coordinates + int32_t bx=cursorX/16, by=cursorY/16, bz=cursorZ; + //Tile coordinates within block + int32_t tx=cursorX%16, ty=cursorY%16, tz=cursorZ; + + + /* + //Access the DF interface to pause the game. + //Copied from the reveal tool. + DFHack::Gui *Gui =DF->getGui(); + cout << "Pausing..." << endl; + Gui->SetPauseState(true); + DF->Resume(); + waitmsec(1000); + DF->Suspend(); + */ + + + //Verify that every z-level at this location exists. + for(uint32_t z = 0; z<= bz ;z++){ + if( ! Mapz->isValidBlock(bx,by,z) ){ + cout << "This block does't exist yet!" << endl << "Designate the lowest level for digging to make DF allocate the block, then try again." << endl; + #ifndef LINUX_BUILD + cin.ignore(); + #endif + return 1; + } + } + + //Get all the map features. + vector global_features; + if(!Mapz->ReadGlobalFeatures(global_features)){ + cout << "Couldn't load global features! Probably a version problem." << endl; + #ifndef LINUX_BUILD + cin.ignore(); + #endif + return 1; + } + std::map > local_features; + if(!Mapz->ReadLocalFeatures(local_features)){ + cout << "Couldn't load local features! Probably a version problem." << endl; + #ifndef LINUX_BUILD + cin.ignore(); + #endif + return 1; + } + + //Get info on current tile, to determine how to generate the pit + mapblock40d topblock; + Mapz->ReadBlock40d( bx, by, bz , &topblock ); + //Related block info + planecoord pc; + pc.dim.x=bx; pc.dim.y=by; + mapblock40d block; + const TileRow * tp; + t_designation * d; + + //From top to bottom, dig this dude. + + //Top level, cap. + Mapz->ReadBlock40d( bx, by, bz , &block ); + for(uint32_t x=0;x<16;++x){ + for(uint32_t y=0;y<16;++y){ + if(pattern[x][y]){ + tp = getTileTypeP(block.tiletypes[x][y]); + d = &block.designation[x][y]; + //Only modify this level if it's 'empty' + if( EMPTY != tp->c && RAMP_TOP != tp->c && STAIR_DOWN != tp->c && DFHack::TILE_STREAM_TOP != tp->s) continue; + + //Need a floor for empty space. + if(reveal) d->bits.hidden = 0; //topblock.designation[x][y].bits.hidden; + //Always clear the dig designation. + d->bits.dig=designation_no; + //unlock fluids, so they fall down the pit. + d->bits.flow_forbid = d->bits.liquid_static=0; + block.blockflags.bits.liquid_1 = block.blockflags.bits.liquid_2 = 1; + //Remove aquifer, to prevent bugginess + d->bits.water_table=0; + //Set the tile. + block.tiletypes[x][y] = cap + rand()%4; + } + } + } + //Write the block. + Mapz->WriteBlockFlags(bx,by,bz, block.blockflags ); + Mapz->WriteDesignations(bx,by,bz, &block.designation ); + Mapz->WriteTileTypes(bx,by,bz, &block.tiletypes ); + Mapz->WriteDirtyBit(bx,by,bz,1); + + //All levels in between. + uint32_t t; + for(uint32_t z = bz-1; z>0 ; --z){ + cout << z << endl; + assert( Mapz->isValidBlock(bx,by,z) ); + if(!Mapz->ReadBlock40d( bx, by, z , &block )){ + cout << "Bad block! " << bx << "," << by << "," << z; + } + for(uint32_t x=0;x<16;++x){ + for(uint32_t y=0;y<16;++y){ + t=0; + tp = getTileTypeP(block.tiletypes[x][y]); + d = &block.designation[x][y]; + //Border or space? + switch(pattern[x][y]){ + case 0: + continue; + break; + case 1: + //Empty Space + t=32; + //d->bits.light = topblock.designation[x][y].bits.light; + //d->bits.skyview = topblock.designation[x][y].bits.skyview; + //d->bits.subterranean = topblock.designation[x][y].bits.subterranean; + + //Erase special markers + d->bits.feature_global = d->bits.feature_local = 0; + + break; + case 2: + //Border. + //First guess based on current material + switch( tp->m ){ + case OBSIDIAN: + t=wmagma; + break; + case MAGMA: + t=wmolten; + break; + case HFS: + t=whell; + break; + case VEIN: + t=440; //Solid vein block + break; + case FEATSTONE: + t=335; //Solid feature stone block + break; + default: + t=wcave; + } + + //If the tile already is a feature, or if it is a vein, we're done. + //Otherwise, adopt block features. + if( VEIN!=tp->m && !d->bits.feature_global && !d->bits.feature_local ){ + //Local Feature? + if( block.local_feature > -1 ){ + switch( n=local_features[pc][block.local_feature]->type ){ + case feature_Adamantine_Tube: + case feature_Underworld: + case feature_Hell_Temple: + //Whatever the feature is made of. "featstone wall" + d->bits.feature_local = 1; + t=335; + break; + default: + //something here. for debugging, it may be interesting to know. + if(n) cout << '(' << n << ')'; + } + } + //Global Feature? + else if(block.global_feature > -1 ){ + switch( n=global_features[block.global_feature].type ){ + case feature_Adamantine_Tube: + case feature_Underworld: + case feature_Hell_Temple: + //Whatever the feature is made of. "featstone wall" + d->bits.feature_global = 1; + t=335; + break; + default: + //something here. for debugging, it may be interesting to know. + if(n) cout << '[' << n << ']'; + } + } + } + + //Erase any liquids, as they cause problems. + d->bits.flow_size=0; + d->bits.liquid_character = liquid_fresh; + d->bits.liquid_type=liquid_water; + + break; + + case 3: + //Special wall, always sets to obsidian, to give a stairway + t=331; + + //Erase special markers + d->bits.feature_global = d->bits.feature_local = 0; + + //Erase any liquids, as they cause problems. + d->bits.flow_size=0; + d->bits.liquid_character = liquid_fresh; + d->bits.liquid_type=liquid_water; + break; + default: + cout << ".err,bad pattern."; + } + + //For all tiles. + if(reveal) d->bits.hidden = 0; //topblock.designation[x][y].bits.hidden; + //Always clear the dig designation. + d->bits.dig=designation_no; + //unlock fluids, so they fall down the pit. + d->bits.flow_forbid = d->bits.liquid_static=0; + block.blockflags.bits.liquid_1 = block.blockflags.bits.liquid_2 = 1; + //Remove aquifer, to prevent bugginess + d->bits.water_table=0; + //Set the tile. + block.tiletypes[x][y] = t; + } + } + + //Write the block. + Mapz->WriteBlockFlags(bx,by,z, block.blockflags ); + Mapz->WriteDesignations(bx,by,z, &block.designation ); + Mapz->WriteTileTypes(bx,by,z, &block.tiletypes ); + Mapz->WriteDirtyBit(bx,by,z,1); + } + + + //The bottom level is special. + Mapz->ReadBlock40d( bx, by, 0 , &block ); + for(uint32_t x=0;x<16;++x){ + for(uint32_t y=0;y<16;++y){ + //Only the portion below the empty space is handled. + if(pattern[x][y]){ + if( 1==pattern[x][y] ) t=floor; + else if( 3==pattern[x][y] ) t=331; + else continue; + + tp = getTileTypeP(block.tiletypes[x][y]); + d = &block.designation[x][y]; + + //For all tiles. + if(reveal) d->bits.hidden = 0; //topblock.designation[x][y].bits.hidden; + //Always clear the dig designation. + d->bits.dig=designation_no; + //unlock fluids, so they fall down the pit. + d->bits.flow_forbid = d->bits.liquid_static=0; + block.blockflags.bits.liquid_1 = block.blockflags.bits.liquid_2 = 1; + //Set the tile. + block.tiletypes[x][y] = floor; + } + } + } + //Write the block. + Mapz->WriteBlockFlags(bx,by,0, block.blockflags ); + Mapz->WriteDesignations(bx,by,0, &block.designation ); + Mapz->WriteTileTypes(bx,by,0, &block.tiletypes ); + Mapz->WriteDirtyBit(bx,by,0,1); + + + + DF->Detach(); + #ifndef LINUX_BUILD + cout << "Done. Press any key to continue" << endl; + cin.ignore(); + #endif + return 0; +} diff --git a/tools/playground/printtiletypes.cpp b/tools/playground/printtiletypes.cpp new file mode 100644 index 000000000..1016694c9 --- /dev/null +++ b/tools/playground/printtiletypes.cpp @@ -0,0 +1,93 @@ +// Prints all the Tile Types known by DFHack. +// File is both fixed-field and CSV parsable. + +#include +#include +#include +#include +#include +#include +#include +using namespace std; + +#include +#include + +using namespace DFHack; + +int main (int argc, char **argv) +{ + FILE *f=stdout; + const int Columns = 7; + const char * Headings[Columns] = {"TileTypeID","Class","Material","V","Special","Direction","Description"}; + size_t Size[ Columns ] = {}; + int i; + + //First, figure out column widths. + for(i=0;i(Size[1],strlen(TileClassString[i])); + fprintf(f,"%4i ; %s\n", i, TileClassString[i] ,0 ); + } + + //Materials + fprintf(f,"\nTile Type Materials:\n"); + for(i=0;i(Size[2],strlen(TileMaterialString[i])); + fprintf(f,"%4i ; %s\n", i, TileMaterialString[i] ,0 ); + } + + //Specials + fprintf(f,"\nTile Type Specials:\n"); + for(i=0;i(Size[4],strlen(TileSpecialString[i])); + fprintf(f,"%4i ; %s\n", i, TileSpecialString[i] ,0 ); + } + + /* - Not needed for now - + //Direction is tricky + for(i=0;i Date: Mon, 18 Oct 2010 15:38:12 -0400 Subject: [PATCH 32/94] better randomized holes and walls. better placement of walls and pillars. --- tools/playground/hellhole.cpp | 476 ++++++++++++++++++++++++++++------ 1 file changed, 397 insertions(+), 79 deletions(-) diff --git a/tools/playground/hellhole.cpp b/tools/playground/hellhole.cpp index 06d1847d3..16905a83a 100644 --- a/tools/playground/hellhole.cpp +++ b/tools/playground/hellhole.cpp @@ -32,11 +32,237 @@ void waitmsec (int delay) } #endif +#define minmax(MinV,V,MaxV) (max((MinV),min((MaxV),(V)))) + +//User interaction enums. +//Pit Type (these only have meaning within hellhole, btw) +#define PITTYPEMACRO \ + X(pitTypeChasm,"Bottomless Chasm" ) \ + X(pitTypeEerie,"Bottomless Eerie Pit" ) \ + X(pitTypeMagma,"Magma Pit (similar to volcanoe, no hell access)" ) +//end PITTYPEMACRO + +#define X(name,desc) name, +enum e_pitType { + pitTypeInvalid=-1, + PITTYPEMACRO + pitTypeCount, +}; +#undef X + + +#define X(name,desc) desc, +const char * pitTypeDesc[pitTypeCount+1] = +{ + PITTYPEMACRO + "" +}; +#undef X + + + + +int getyesno( const char * msg , int default_value ){ + const int bufferlen=4; + static char buf[bufferlen]; + memset(buf,0,bufferlen); + while(-1){ + if(msg) printf("\n%s (default=%s)\n:" , msg , (default_value?"yes":"no") ); + fflush(stdin); + fgets(buf,bufferlen,stdin); + switch(buf[0]){ + case 0: case 0x0d: case 0x0a: + return default_value; + case 'y': case 'Y': case 'T': case 't': case '1': + return -1; + case 'n': case 'N': case 'F': case 'f': case '0': + return 0; + } + } + return 0; +} + +int getint( const char * msg , int min, int max, int default_value ){ + const int bufferlen=16; + static char buf[bufferlen]; + int n=0; + memset(buf,0,bufferlen); + while(-1){ + if(msg) printf("\n%s (default=%d)\n:" , msg , default_value); + fflush(stdin); + fgets(buf,bufferlen,stdin); + if( !buf[0] || 0x0a==buf[0] || 0x0d==buf[0] ) return default_value; + if( sscanf(buf,"%d", &n) ){ + if(n>=min && n<=max ) return n; + } + } +} + + + +//Interactive, get pit type from user +#define X( e , desc ) printf("%2d) %s\n", (e), (desc) ); +e_pitType selectPitType(e_pitType default_value ){ + e_pitType r=pitTypeInvalid; + int c=-1; + while( -1 ){ + printf("Enter the type of hole to dig (if no entry, default everything):\n" ); + PITTYPEMACRO + printf(":"); + return (e_pitType)getint(NULL, 0, pitTypeCount-1, default_value ); + } +} +#undef X + + +void drawcircle(const int radius, unsigned char pattern[16][16], unsigned char v ){ + //Small circles get better randomness if handled manually + if( 1==radius ){ + pattern[7][7]=v; + if( (rand()&1) ) pattern[6][7]=v; + if( (rand()&1) ) pattern[8][7]=v; + if( (rand()&1) ) pattern[7][6]=v; + if( (rand()&1) ) pattern[7][8]=v; + + }else if( 2==radius ){ + pattern[7][7]=v; + pattern[7][5]=v; + pattern[7][6]=v; + pattern[7][8]=v; + pattern[7][9]=v; + pattern[6][7]=v; + pattern[8][7]=v; + pattern[9][7]=v; + pattern[6][6]=v; + pattern[6][8]=v; + pattern[8][6]=v; + pattern[8][8]=v; + pattern[5][7]=v; + + if( (rand()&1) ) pattern[6][5]=v; + if( (rand()&1) ) pattern[5][6]=v; + if( (rand()&1) ) pattern[8][5]=v; + if( (rand()&1) ) pattern[9][6]=v; + if( (rand()&1) ) pattern[6][9]=v; + if( (rand()&1) ) pattern[5][8]=v; + if( (rand()&1) ) pattern[8][9]=v; + if( (rand()&1) ) pattern[9][8]=v; + }else{ + //radius 3 or larger, simple circle calculation. + int x,y; + for(y=0-radius; y<=radius; ++y){ + for(x=0-radius; x<=radius; ++x){ + if(x*x+y*y <= radius*radius + (rand()&31-8) ){ + pattern[ minmax(0,7+x,15) ][ minmax(0,7+y,15) ]=v; + } + } + } + //Prevent boxy patterns with a quick modification on edges + if(rand()&1) pattern[ 7 ][ minmax(0,7+radius+1,15) ] = v; + if(rand()&1) pattern[ 7 ][ minmax(0,7-radius-1,15) ] = v; + if(rand()&1) pattern[ minmax(0,7+radius+1,15) ][ 7 ] = v; + if(rand()&1) pattern[ minmax(0,7-radius-1,15) ][ 7 ] = v; + } +} + +void settileat(unsigned char pattern[16][16], const unsigned char needle, const unsigned char v, const int index ) +{ + int ok=0; + int safety=256*256; + int y,x,i=0; + //Scan for sequential index + while( !ok && --safety ){ + for(y=0 ; !ok && y<16 ; ++y ){ + for(x=0 ; !ok && x<16 ; ++x ){ + if( needle==pattern[x][y] ){ + ++i; + if( index==i ){ + //Got it! + pattern[x][y]=v; + ok=-1; + } + } + } + } + } +} int main (void) { - srand ( time(NULL) ); + srand ( (unsigned int)time(NULL) ); + + //Message of intent + cout << + "DF Hell Hole" << endl << + "This program will instantly dig a bottomless hole through hell, wherever your cursor is." << endl << + "This can not be undone! End program now if you don't want hellish fun." << endl + ; + + //User selection of settings should have it own routine, a structure for settings, I know + //sloppy mess, but this is just a demo utility. + + //Pit Types. + e_pitType pittype = selectPitType(pitTypeInvalid); + + + //Hole Diameter + int holeradius=6; + if( pitTypeInvalid != pittype && pitTypeMagma != pittype ){ + holeradius = getint( "Enter hole radius, 0 to 8", 0, 8, holeradius ); + } + + //Wall thickness + int wallthickness=1; + if( pitTypeInvalid != pittype && pitTypeMagma != pittype ){ + wallthickness = getint( "Enter wall thickness, 0 to 8", 0, 8, wallthickness ); + } + + //Obsidian Pillars + int pillarwall=1; + if( pitTypeInvalid != pittype ){ + pillarwall = getint( "Number of Obsidian Pillars in wall, 0 to 255", 0, 255, pillarwall ); + } + int pillarchasm=1; + if( pitTypeInvalid != pittype ){ + pillarchasm = getint( "Number of Obsidian Pillars in hole, 0 to 255", 0, 255, pillarchasm ); + } + + //Open Hell? + int exposehell = 0; + if( pitTypeInvalid != pittype && pitTypeMagma != pittype && wallthickness ){ + exposehell=getyesno("Expose the pit to hell (no walls in hell)?",0); + } + + //Fill? + int fillmagma=0; + if( pitTypeInvalid != pittype ){ + fillmagma=getyesno("Fill with magma?",0); + } + int fillwater=0; + if( pitTypeInvalid != pittype && !fillmagma){ + fillwater=getyesno("Fill with water?",0); + } + + + //If skipped all settings, fix the pit type + if( pitTypeInvalid == pittype ) pittype = pitTypeChasm; + + + /////////////////////////////////////////////////////////////////////////////////////////////// + //Print settings. + //If a settings struct existed, this could be in a routine + printf("Using Settings:\n"); + printf("Pit Type......: %d = %s\n", pittype, pitTypeDesc[pittype]); + printf("Hole Radius...: %d\n", holeradius); + printf("Wall Thickness: %d\n", wallthickness); + printf("Pillars, Wall.: %d\n", pillarwall); + printf("Pillars, Hole.: %d\n", pillarchasm); + printf("Expose Hell...: %c\n", (exposehell?'Y':'N') ); + printf("Magma Fill....: %c\n", (fillmagma?'Y':'N') ); + printf("Water Fill....: %c\n", (fillwater?'Y':'N') ); + + int64_t n; uint32_t x_max,y_max,z_max; @@ -47,81 +273,100 @@ int main (void) //The Tile Type to use for the hole's floor at bottom of the map //35 is chasm, 42 is eerie pit , 340 is obsidian floor uint32_t floor=35, cap=340; + if( pitTypeEerie == pittype ) floor=42; + //Should tiles be revealed? - int reveal=0; + int reveal=1; //Pattern to dig - unsigned char pattern[16][16] = {0,}; + unsigned char pattern[16][16]; + + + for(int regen=1;regen; ){ + regen=0; + + memset(pattern,0,sizeof(pattern)); - { //Calculate a randomized circle. //These values found through experimentation. - int radius=6; - int x=0, y=0; + int x=0, y=0, n=0; - for(y=-radius; y<=radius; ++y){ - for(x=-radius; x<=radius; ++x){ - if(x*x+y*y <= radius*radius + (rand()&31) ){ - pattern[7+x][7+y]=1; - } - } + //Two concentric irregular circles + //Outer circle, solid. + if( wallthickness ){ + drawcircle(holeradius+wallthickness, pattern, 2); } - //Post-process to figure out where to put walls. - for(y=0;y<16;++y){ - for(x=0;x<16;++x){ - if( 1==pattern[x][y] ){ - //No hole at edges. - if( x<1 || x>14 || y<1 || y>14 ){ - pattern[x][y]=2; + //Inner circle, hole. + if( holeradius ){ + drawcircle(holeradius, pattern, 1); + } + + + //Post-process to be certain the wall totally encloses hole. + if(wallthickness){ + for(y=0;y<16;++y){ + for(x=0;x<16;++x){ + if( 1==pattern[x][y] ){ + //No hole at edges. + if( x<1 || x>14 || y<1 || y>14 ){ + pattern[x][y]=2; + } + }else if( 0==pattern[x][y] ){ + //check neighbors + if( x>0 && y>0 && 1==pattern[x-1][y-1] ){ pattern[x][y]=2; continue; } + if( x>0 && 1==pattern[x-1][y ] ){ pattern[x][y]=2; continue; } + if( y>0 && 1==pattern[x ][y-1] ){ pattern[x][y]=2; continue; } + if( x<15 && 1==pattern[x+1][y ] ){ pattern[x][y]=2; continue; } + if( x<15&& y>0 && 1==pattern[x+1][y-1] ){ pattern[x][y]=2; continue; } + if( x<15&& y<15&& 1==pattern[x+1][y+1] ){ pattern[x][y]=2; continue; } + if( y<15&& 1==pattern[x ][y+1] ){ pattern[x][y]=2; continue; } + if( x>0 && y<15&& 1==pattern[x-1][y+1] ){ pattern[x][y]=2; continue; } } - }else if( 0==pattern[x][y] ){ - //check neighbors - if( x>0 && y>0 && 1==pattern[x-1][y-1] ){ pattern[x][y]=2; continue; } - if( x>0 && 1==pattern[x-1][y ] ){ pattern[x][y]=2; continue; } - if( y>0 && 1==pattern[x ][y-1] ){ pattern[x][y]=2; continue; } - if( x<15 && 1==pattern[x+1][y ] ){ pattern[x][y]=2; continue; } - if( x<15&& y>0 && 1==pattern[x+1][y-1] ){ pattern[x][y]=2; continue; } - if( x<15&& y<15&& 1==pattern[x+1][y+1] ){ pattern[x][y]=2; continue; } - if( y<15&& 1==pattern[x ][y+1] ){ pattern[x][y]=2; continue; } - if( x>0 && y<15&& 1==pattern[x-1][y+1] ){ pattern[x][y]=2; continue; } } } } + //Final pass, makes sure that somewhere random gets a vertical pillar of rock which is safe //to dig stairs down, to permit access to anywhere within the pit from the top. - for(x=0, y=0; 1!=pattern[x][y]; x=rand()&15, y=rand()&15 ){} - pattern[x][y]=3; + for(n=pillarchasm; n ; --n){ + settileat( pattern , 1 , 3 , rand()&255 ); + } + for(n=pillarwall; n ; --n){ + settileat( pattern , 2 , 3 , rand()&255 ); + } -#if 0 - cout << endl; - //Print the pattern (debugging) + + //Note: + //At this point, the pattern holds: + //0 for all tiles which will be ignored. + //1 for all tiles set to empty pit space. + //2 for all normal walls. + //3 for the straight obsidian top-to-bottom wall. + + printf("\nPattern:\n"); + const char patternkey[] = ".cW!4567890123"; + + //Print the pattern for(y=0;y<16;++y){ for(x=0;x<16;++x){ - printf("%d",pattern[x][y]); + cout << patternkey[ pattern[x][y] ]; } cout << endl; } cout << endl; - cin.ignore(); - return 0; -#endif + regen = !getyesno("Acceptable Pattern?",1); } - + /////////////////////////////////////////////////////////////////////////////////////////////// + + //Connect to DF! DFHack::ContextManager DFMgr("Memory.xml"); DFHack::Context *DF = DFMgr.getSingleContext(); - //Message of intent - cout << - "DF Hell Hole" << endl << - "This program will instantly dig a hole through hell, wherever your cursor is." << endl << - "This can not be undone! End program now if you don't want hellish fun." << endl - ; - cin.ignore(); //Init try @@ -136,7 +381,7 @@ int main (void) #endif return 1; } - + // init the map DFHack::Maps *Mapz = DF->getMaps(); if(!Mapz->Start()) @@ -182,7 +427,7 @@ int main (void) //Verify that every z-level at this location exists. - for(uint32_t z = 0; z<= bz ;z++){ + for(int32_t z = 0; z<= bz ;z++){ if( ! Mapz->isValidBlock(bx,by,z) ){ cout << "This block does't exist yet!" << endl << "Designate the lowest level for digging to make DF allocate the block, then try again." << endl; #ifndef LINUX_BUILD @@ -252,21 +497,74 @@ int main (void) Mapz->WriteTileTypes(bx,by,bz, &block.tiletypes ); Mapz->WriteDirtyBit(bx,by,bz,1); + //Various behaviour flags. + int moltencount=0; + int solidcount=0; + int emptycount=0; + int hellcount=0; + int tpat; + //All levels in between. uint32_t t; - for(uint32_t z = bz-1; z>0 ; --z){ + for(int32_t z = bz-1; z>0 ; --z){ + moltencount=0; + solidcount=0; + emptycount=0; + hellcount=0; cout << z << endl; assert( Mapz->isValidBlock(bx,by,z) ); if(!Mapz->ReadBlock40d( bx, by, z , &block )){ cout << "Bad block! " << bx << "," << by << "," << z; } - for(uint32_t x=0;x<16;++x){ - for(uint32_t y=0;y<16;++y){ + for(int32_t x=0;x<16;++x){ + for(int32_t y=0;y<16;++y){ t=0; tp = getTileTypeP(block.tiletypes[x][y]); d = &block.designation[x][y]; + tpat=pattern[x][y]; + + //Manipulate behaviour based on settings and location + switch( tp->m ){ + case MAGMA: + ++moltencount; + //Making a fake volcanoe/magma pipe? + if( pitTypeMagma == pittype ){ + //Leave tile unchanged. + tpat=0; + } + break; + case OBSIDIAN: + case FEATSTONE: + case HFS: + //ignore, even though it is technically solid + break; + case VEIN: + default: + if( EMPTY != tp->c ){ + ++emptycount; + }else{ + ++solidcount; + } + } + + //Check hell status + if( + (block.local_feature > -1 && feature_Underworld==local_features[pc][block.local_feature]->type ) + || + (block.global_feature > -1 && feature_Underworld==global_features[block.global_feature].type ) + ){ + ++hellcount; + + //Are we leaving hell open? + if( exposehell ){ + //Leave tile unchanged. + tpat=0; + } + } + + //Border or space? - switch(pattern[x][y]){ + switch(tpat){ case 0: continue; break; @@ -280,6 +578,17 @@ int main (void) //Erase special markers d->bits.feature_global = d->bits.feature_local = 0; + //Water? Magma? + if(fillmagma || fillwater){ + d->bits.flow_size=7; + d->bits.liquid_character = liquid_fresh; + if(fillmagma){ + d->bits.liquid_type=liquid_magma; + }else{ + d->bits.liquid_type=liquid_water; + } + } + break; case 2: //Border. @@ -373,6 +682,7 @@ int main (void) d->bits.water_table=0; //Set the tile. block.tiletypes[x][y] = t; + } } @@ -381,40 +691,48 @@ int main (void) Mapz->WriteDesignations(bx,by,z, &block.designation ); Mapz->WriteTileTypes(bx,by,z, &block.tiletypes ); Mapz->WriteDirtyBit(bx,by,z,1); - } + //Making a fake volcanoe/magma pipe? + if( pitTypeMagma == pittype && !solidcount){ + //Nothing «solid», we're making a magma pipe, we're done. + z=0; + } - //The bottom level is special. - Mapz->ReadBlock40d( bx, by, 0 , &block ); - for(uint32_t x=0;x<16;++x){ - for(uint32_t y=0;y<16;++y){ - //Only the portion below the empty space is handled. - if(pattern[x][y]){ - if( 1==pattern[x][y] ) t=floor; - else if( 3==pattern[x][y] ) t=331; - else continue; + } - tp = getTileTypeP(block.tiletypes[x][y]); - d = &block.designation[x][y]; - //For all tiles. - if(reveal) d->bits.hidden = 0; //topblock.designation[x][y].bits.hidden; - //Always clear the dig designation. - d->bits.dig=designation_no; - //unlock fluids, so they fall down the pit. - d->bits.flow_forbid = d->bits.liquid_static=0; - block.blockflags.bits.liquid_1 = block.blockflags.bits.liquid_2 = 1; - //Set the tile. - block.tiletypes[x][y] = floor; + //The bottom level is special. + if( pitTypeMagma != pittype ) { + Mapz->ReadBlock40d( bx, by, 0 , &block ); + for(uint32_t x=0;x<16;++x){ + for(uint32_t y=0;y<16;++y){ + //Only the portion below the empty space is handled. + if(pattern[x][y]){ + if( 1==pattern[x][y] ) t=floor; + else if( 3==pattern[x][y] ) t=331; + else continue; + + tp = getTileTypeP(block.tiletypes[x][y]); + d = &block.designation[x][y]; + + //For all tiles. + if(reveal) d->bits.hidden = 0; //topblock.designation[x][y].bits.hidden; + //Always clear the dig designation. + d->bits.dig=designation_no; + //unlock fluids, so they fall down the pit. + d->bits.flow_forbid = d->bits.liquid_static=0; + block.blockflags.bits.liquid_1 = block.blockflags.bits.liquid_2 = 1; + //Set the tile. + block.tiletypes[x][y] = floor; + } } } + //Write the block. + Mapz->WriteBlockFlags(bx,by,0, block.blockflags ); + Mapz->WriteDesignations(bx,by,0, &block.designation ); + Mapz->WriteTileTypes(bx,by,0, &block.tiletypes ); + Mapz->WriteDirtyBit(bx,by,0,1); } - //Write the block. - Mapz->WriteBlockFlags(bx,by,0, block.blockflags ); - Mapz->WriteDesignations(bx,by,0, &block.designation ); - Mapz->WriteTileTypes(bx,by,0, &block.tiletypes ); - Mapz->WriteDirtyBit(bx,by,0,1); - DF->Detach(); From ba88c866706a3e18106c260496bc445cb721acdb Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 19 Oct 2010 05:07:07 -0500 Subject: [PATCH 33/94] dfitemdump appears to work. Materials still buggy (Pig Iron Bar != Mule Bar). This has been bugged since .12 or earlier --- data/Memory-ng.xml | 9 +++++++ library/modules/Items.cpp | 22 ++++++++++++++++++ tools/examples/dfitemdump.cpp | 44 +++++++++++++++++++++++++++++++---- 3 files changed, 70 insertions(+), 5 deletions(-) diff --git a/data/Memory-ng.xml b/data/Memory-ng.xml index eeb6b2c7a..a157c0172 100644 --- a/data/Memory-ng.xml +++ b/data/Memory-ng.xml @@ -1771,6 +1771,15 @@
+ +
+ + + + + + + .-"""-. diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp index 6ae558dcd..e63b85875 100644 --- a/library/modules/Items.cpp +++ b/library/modules/Items.cpp @@ -116,6 +116,21 @@ Accessor::Accessor(uint32_t function, Process *p) this->offset1 = (funcText>>24) & 0xffff; return; } + if( (funcText&0x000000FF00FFFFFFLL) == 0x000000C300418B66LL ) + { + /* mov ax, [ecx+xx]; ret; (shorter instruction)*/ + this->type = ACCESSOR_INDIRECT; + this->offset1 = (funcText>>24) & 0xff; + return; + } + if( (funcText&0x00000000FF00FFFFLL) == 0x00000000C300418BLL ) + { + /* mov eax, [ecx+xx]; ret; */ + this->type = ACCESSOR_INDIRECT; + this->offset1 = (funcText>>16) & 0xff; + this->dataWidth = 4; + return; + } if( (funcText&0xFFFFFFFF0000FFFFLL) == 0x8B6600000000818BLL ) { uint64_t funcText2 = p->readQuad(function+8); @@ -134,6 +149,13 @@ Accessor::Accessor(uint32_t function, Process *p) this->offset1 = (funcText>>24) & 0xffff; return; } + if( (funcText&0x000000FF00FFFFFFLL) == 0x000000C30041BF0FLL ) + { + /* movsx eax, word ptr [ecx+xx]; ret (shorter opcode)*/ + this->type = ACCESSOR_INDIRECT; + this->offset1 = (funcText>>24) & 0xff; + return; + } if( (funcText&0xFFFFFFFF0000FFFFLL) == 0xCCC300000000818BLL ) { /* mov eax, [ecx+xx]; ret; */ diff --git a/tools/examples/dfitemdump.cpp b/tools/examples/dfitemdump.cpp index f3a3dd39e..eff18dcdb 100644 --- a/tools/examples/dfitemdump.cpp +++ b/tools/examples/dfitemdump.cpp @@ -41,7 +41,8 @@ int main () Materials = DF->getMaterials(); Materials->ReadAllMaterials(); p = DF->getProcess(); - DFHack::DfVector p_items (p, p->getDescriptor()->getAddress ("items_vector")); + DFHack::OffsetGroup* itemGroup = mem->getGroup("Items"); + DFHack::DfVector p_items (p, itemGroup->getAddress("items_vector")); uint32_t size = p_items.size(); Items = DF->getItems(); @@ -49,6 +50,7 @@ int main () printf("type\tvtable\tname\tquality\tdecorate\n"); for (i=0;ireadDWord(p_items[i]); uint32_t func0 = p->readDWord(vtable); uint64_t funct0 = p->readQuad(func0); @@ -84,6 +86,8 @@ int main () if (funct1 == 0xC300000092818B66LL) quality = p->readWord(p_items[i]+0x92); + if (funct1 == 0xC300000082818B66LL) + quality = p->readWord(p_items[i]+0x82); else if (funct1 == 0xCCCCCCCCCCC3C033LL) quality = 0; else @@ -115,6 +119,11 @@ int main () uint32_t off1 = (funcBt>>24) & 0xffff; typeB = p->readWord(p_items[i] + off1); } + else if ( (funcBt&0x000000FF00FFFFFFLL) == 0x000000C300418B66LL ) + { + uint32_t off1 = (funcBt>>24) & 0xff; + typeB = p->readWord(p_items[i] + off1); + } else printf("bad typeB func @%p\n", (void*) funcB); } @@ -126,6 +135,16 @@ int main () uint32_t off1 = (funcCt>>24)&0xffff; typeC = p->readWord(p_items[i] + off1); } + else if ( (funcCt&0x000000FF00FFFFFFLL) == 0x000000C300418B66LL ) + { + uint32_t off1 = (funcCt>>24) & 0xff; + typeC = p->readWord(p_items[i] + off1); + } + else if ( (funcCt&0x00000000FF00FFFFLL) == 0x00000000C300418BLL ) + { + uint32_t off1 = (funcCt>>16) & 0xff; + typeC = p->readWord(p_items[i] + off1); + } else printf("bad typeC func @%p\n", (void*) funcC); @@ -134,12 +153,27 @@ int main () else if ( (funcDt&0xFFFFFFFF0000FFFFLL) == 0xCCC300000000818BLL ) { uint32_t off1 = (funcDt>>16) & 0xffff; - typeD = p->readDWord(p_items[i] + off1); + typeD = p->readWord(p_items[i] + off1); } else if ( (funcDt&0xFFFFFF0000FFFFFFLL) == 0xC30000000081BF0FLL ) { uint32_t off1 = (funcDt>>24) & 0xffff; - typeD = (int16_t) p->readWord(p_items[i] + off1); + typeD = p->readWord(p_items[i] + off1); + } + else if ( (funcDt&0x000000FF00FFFFFFLL) == 0x000000C30041BF0FLL ) + { + uint32_t off1 = (funcDt>>24) & 0xff; + typeD = p->readWord(p_items[i] + off1); + } + else if ( (funcDt&0x000000FF00FFFFFFLL) == 0x000000C300418B66LL ) + { + uint32_t off1 = (funcDt>>24) & 0xff; + typeD = p->readWord(p_items[i] + off1); + } + else if ( (funcDt&0x00000000FF00FFFFLL) == 0x00000000C300418BLL ) + { + uint32_t off1 = (funcDt>>16) & 0xff; + typeD = p->readDWord(p_items[i] + off1); } else printf("bad typeD func @%p\n", (void*) funcD); @@ -155,8 +189,8 @@ int main () { bool sep = false; printf("\tdeco=["); - uint32_t decStart = p->readDWord(p_items[i] + 0xAC); - uint32_t decEnd = p->readDWord(p_items[i] + 0xB0); + uint32_t decStart = p->readDWord(p_items[i] + 0x90); // 0xAC pre .13 + uint32_t decEnd = p->readDWord(p_items[i] + 0x94); // 0xB0 pre .13 if (decStart != decEnd) { for (j=decStart;j Date: Wed, 20 Oct 2010 12:31:16 -0400 Subject: [PATCH 34/94] added more information to probe. added pit-with-floor option to hellhole. bug fixes for the fake magma pipe in hellhole. --- library/include/dfhack/DFTileTypes.h | 1 + tools/playground/hellhole.cpp | 155 ++++++++++++++++++--------- tools/supported/probe.cpp | 70 +++++++++--- 3 files changed, 157 insertions(+), 69 deletions(-) diff --git a/library/include/dfhack/DFTileTypes.h b/library/include/dfhack/DFTileTypes.h index 52c3fb4de..affff0c7a 100644 --- a/library/include/dfhack/DFTileTypes.h +++ b/library/include/dfhack/DFTileTypes.h @@ -997,6 +997,7 @@ namespace DFHack if( tclass == tileTypeTable[tt].c ){ //shortcut null entries if(!tileTypeTable[tt].name) continue; + //Special flag match is absolutely mandatory! if( source->s != tileTypeTable[tt].s ) continue; diff --git a/tools/playground/hellhole.cpp b/tools/playground/hellhole.cpp index 16905a83a..e8fc9da17 100644 --- a/tools/playground/hellhole.cpp +++ b/tools/playground/hellhole.cpp @@ -39,6 +39,7 @@ void waitmsec (int delay) #define PITTYPEMACRO \ X(pitTypeChasm,"Bottomless Chasm" ) \ X(pitTypeEerie,"Bottomless Eerie Pit" ) \ + X(pitTypeFloor,"Pit with a floor" ) \ X(pitTypeMagma,"Magma Pit (similar to volcanoe, no hell access)" ) //end PITTYPEMACRO @@ -208,13 +209,13 @@ int main (void) //Hole Diameter int holeradius=6; - if( pitTypeInvalid != pittype && pitTypeMagma != pittype ){ + if( pitTypeInvalid != pittype ){ holeradius = getint( "Enter hole radius, 0 to 8", 0, 8, holeradius ); } //Wall thickness int wallthickness=1; - if( pitTypeInvalid != pittype && pitTypeMagma != pittype ){ + if( pitTypeInvalid != pittype ){ wallthickness = getint( "Enter wall thickness, 0 to 8", 0, 8, wallthickness ); } @@ -271,12 +272,19 @@ int main (void) //263 is semi-molten rock, 331 is obsidian uint32_t whell=263, wmolten=263, wmagma=331, wcave=331; //The Tile Type to use for the hole's floor at bottom of the map - //35 is chasm, 42 is eerie pit , 340 is obsidian floor + //35 is chasm, 42 is eerie pit , 340 is obsidian floor, 344 is featstone floor, 264 is 'magma flow' floor uint32_t floor=35, cap=340; - if( pitTypeEerie == pittype ) floor=42; + switch( pittype ){ + case pitTypeEerie: floor=42; break; + case pitTypeFloor: floor=344; break; + case pitTypeMagma: floor=264; break; + default: + floor=35; + } + //Should tiles be revealed? - int reveal=1; + int reveal=0; //Pattern to dig @@ -314,14 +322,14 @@ int main (void) } }else if( 0==pattern[x][y] ){ //check neighbors - if( x>0 && y>0 && 1==pattern[x-1][y-1] ){ pattern[x][y]=2; continue; } - if( x>0 && 1==pattern[x-1][y ] ){ pattern[x][y]=2; continue; } - if( y>0 && 1==pattern[x ][y-1] ){ pattern[x][y]=2; continue; } - if( x<15 && 1==pattern[x+1][y ] ){ pattern[x][y]=2; continue; } - if( x<15&& y>0 && 1==pattern[x+1][y-1] ){ pattern[x][y]=2; continue; } - if( x<15&& y<15&& 1==pattern[x+1][y+1] ){ pattern[x][y]=2; continue; } - if( y<15&& 1==pattern[x ][y+1] ){ pattern[x][y]=2; continue; } - if( x>0 && y<15&& 1==pattern[x-1][y+1] ){ pattern[x][y]=2; continue; } + if( x>0 && y>0 && 1==pattern[x-1][y-1] ){ pattern[x][y]=2; continue; } + if( x>0 && 1==pattern[x-1][y ] ){ pattern[x][y]=2; continue; } + if( y>0 && 1==pattern[x ][y-1] ){ pattern[x][y]=2; continue; } + if( x<15 && 1==pattern[x+1][y ] ){ pattern[x][y]=2; continue; } + if( x<15 && y>0 && 1==pattern[x+1][y-1] ){ pattern[x][y]=2; continue; } + if( x<15 && y<15 && 1==pattern[x+1][y+1] ){ pattern[x][y]=2; continue; } + if( y<15 && 1==pattern[x ][y+1] ){ pattern[x][y]=2; continue; } + if( x>0 && y<15 && 1==pattern[x-1][y+1] ){ pattern[x][y]=2; continue; } } } } @@ -465,39 +473,46 @@ int main (void) const TileRow * tp; t_designation * d; + ////////////////////////////////////// //From top to bottom, dig this dude. + ////////////////////////////////////// //Top level, cap. - Mapz->ReadBlock40d( bx, by, bz , &block ); - for(uint32_t x=0;x<16;++x){ - for(uint32_t y=0;y<16;++y){ - if(pattern[x][y]){ - tp = getTileTypeP(block.tiletypes[x][y]); - d = &block.designation[x][y]; - //Only modify this level if it's 'empty' - if( EMPTY != tp->c && RAMP_TOP != tp->c && STAIR_DOWN != tp->c && DFHack::TILE_STREAM_TOP != tp->s) continue; + //Might make this an option in the future + if(-1){ + Mapz->ReadBlock40d( bx, by, bz , &block ); + for(uint32_t x=0;x<16;++x){ + for(uint32_t y=0;y<16;++y){ + if(pattern[x][y]){ + tp = getTileTypeP(block.tiletypes[x][y]); + d = &block.designation[x][y]; + //Only modify this level if it's 'empty' + if( EMPTY != tp->c && RAMP_TOP != tp->c && STAIR_DOWN != tp->c && DFHack::TILE_STREAM_TOP != tp->s) continue; - //Need a floor for empty space. - if(reveal) d->bits.hidden = 0; //topblock.designation[x][y].bits.hidden; - //Always clear the dig designation. - d->bits.dig=designation_no; - //unlock fluids, so they fall down the pit. - d->bits.flow_forbid = d->bits.liquid_static=0; - block.blockflags.bits.liquid_1 = block.blockflags.bits.liquid_2 = 1; - //Remove aquifer, to prevent bugginess - d->bits.water_table=0; - //Set the tile. - block.tiletypes[x][y] = cap + rand()%4; + //Need a floor for empty space. + if(reveal) d->bits.hidden = 0; //topblock.designation[x][y].bits.hidden; + //Always clear the dig designation. + d->bits.dig=designation_no; + //unlock fluids, so they fall down the pit. + d->bits.flow_forbid = d->bits.liquid_static=0; + block.blockflags.bits.liquid_1 = block.blockflags.bits.liquid_2 = 1; + //Remove aquifer, to prevent bugginess + d->bits.water_table=0; + //Set the tile. + block.tiletypes[x][y] = cap + rand()%4; + } } } + //Write the block. + Mapz->WriteBlockFlags(bx,by,bz, block.blockflags ); + Mapz->WriteDesignations(bx,by,bz, &block.designation ); + Mapz->WriteTileTypes(bx,by,bz, &block.tiletypes ); + Mapz->WriteDirtyBit(bx,by,bz,1); } - //Write the block. - Mapz->WriteBlockFlags(bx,by,bz, block.blockflags ); - Mapz->WriteDesignations(bx,by,bz, &block.designation ); - Mapz->WriteTileTypes(bx,by,bz, &block.tiletypes ); - Mapz->WriteDirtyBit(bx,by,bz,1); + /////////////////////////////////////////////////////////////////////////////////////////////// //Various behaviour flags. + int magmacount=0; int moltencount=0; int solidcount=0; int emptycount=0; @@ -508,6 +523,7 @@ int main (void) uint32_t t; for(int32_t z = bz-1; z>0 ; --z){ moltencount=0; + magmacount=0; solidcount=0; emptycount=0; hellcount=0; @@ -527,18 +543,16 @@ int main (void) switch( tp->m ){ case MAGMA: ++moltencount; + case FEATSTONE: + case HFS: //Making a fake volcanoe/magma pipe? if( pitTypeMagma == pittype ){ //Leave tile unchanged. tpat=0; } break; - case OBSIDIAN: - case FEATSTONE: - case HFS: - //ignore, even though it is technically solid - break; case VEIN: + case OBSIDIAN: default: if( EMPTY != tp->c ){ ++emptycount; @@ -547,6 +561,15 @@ int main (void) } } + //No walls if magma found anywhere for a magma pipe + if( d->bits.flow_size && liquid_magma==d->bits.liquid_type ){ + ++magmacount; + if(pitTypeMagma == pittype){ + tpat=0; + } + } + + //Check hell status if( (block.local_feature > -1 && feature_Underworld==local_features[pc][block.local_feature]->type ) @@ -560,6 +583,15 @@ int main (void) //Leave tile unchanged. tpat=0; } + + //Never should have gotten here + if(pitTypeMagma == pittype){ + x=y=255; + z=0; + tpat=0; + continue; + } + } @@ -587,6 +619,11 @@ int main (void) }else{ d->bits.liquid_type=liquid_water; } + }else{ + //Otherwise, remove all liquids. + d->bits.flow_size=0; + d->bits.liquid_character = liquid_fresh; + d->bits.liquid_type=liquid_water; } break; @@ -615,9 +652,10 @@ int main (void) //If the tile already is a feature, or if it is a vein, we're done. //Otherwise, adopt block features. - if( VEIN!=tp->m && !d->bits.feature_global && !d->bits.feature_local ){ + //Adamantine (a local feature) trumps veins. + { //Local Feature? - if( block.local_feature > -1 ){ + if( block.local_feature > -1 && !d->bits.feature_global ){ switch( n=local_features[pc][block.local_feature]->type ){ case feature_Adamantine_Tube: case feature_Underworld: @@ -632,7 +670,7 @@ int main (void) } } //Global Feature? - else if(block.global_feature > -1 ){ + else if(block.global_feature > -1 && !d->bits.feature_local ){ switch( n=global_features[block.global_feature].type ){ case feature_Adamantine_Tube: case feature_Underworld: @@ -668,13 +706,17 @@ int main (void) d->bits.liquid_type=liquid_water; break; default: - cout << ".err,bad pattern."; + cout << ".error,bad pattern."; } //For all tiles. if(reveal) d->bits.hidden = 0; //topblock.designation[x][y].bits.hidden; //Always clear the dig designation. d->bits.dig=designation_no; + //Make it underground, because it is capped + d->bits.subterranean=1; + d->bits.light=0; + d->bits.skyview=0; //unlock fluids, so they fall down the pit. d->bits.flow_forbid = d->bits.liquid_static=0; block.blockflags.bits.liquid_1 = block.blockflags.bits.liquid_2 = 1; @@ -693,7 +735,7 @@ int main (void) Mapz->WriteDirtyBit(bx,by,z,1); //Making a fake volcanoe/magma pipe? - if( pitTypeMagma == pittype && !solidcount){ + if( pitTypeMagma == pittype && !solidcount && (moltencount || magmacount) ){ //Nothing «solid», we're making a magma pipe, we're done. z=0; } @@ -702,24 +744,31 @@ int main (void) //The bottom level is special. - if( pitTypeMagma != pittype ) { + if(-1){ Mapz->ReadBlock40d( bx, by, 0 , &block ); for(uint32_t x=0;x<16;++x){ for(uint32_t y=0;y<16;++y){ //Only the portion below the empty space is handled. - if(pattern[x][y]){ - if( 1==pattern[x][y] ) t=floor; - else if( 3==pattern[x][y] ) t=331; - else continue; + if(1==pattern[x][y]){ + //if( 1==pattern[x][y] ) t=floor; + //else if( 3==pattern[x][y] ) t=331; + //else continue; tp = getTileTypeP(block.tiletypes[x][y]); d = &block.designation[x][y]; + //Special handling for magma pipe. + //Need to be sure that solid blocks have a floor above them. + //Only solid blocks will have a floor drawn; empty blocks will be ignored. + if( pitTypeMagma == pittype ) { + if( EMPTY == tp->c || RAMP_TOP == tp->c || STAIR_DOWN == tp->c ) continue; + } + //For all tiles. if(reveal) d->bits.hidden = 0; //topblock.designation[x][y].bits.hidden; //Always clear the dig designation. d->bits.dig=designation_no; - //unlock fluids, so they fall down the pit. + //unlock fluids d->bits.flow_forbid = d->bits.liquid_static=0; block.blockflags.bits.liquid_1 = block.blockflags.bits.liquid_2 = 1; //Set the tile. diff --git a/tools/supported/probe.cpp b/tools/supported/probe.cpp index 57992f470..81a34b693 100644 --- a/tools/supported/probe.cpp +++ b/tools/supported/probe.cpp @@ -8,8 +8,8 @@ #include #include -#define DFHACK_WANT_MISCUTILS -#define DFHACK_WANT_TILETYPES +#define DFHACK_WANT_MISCUTILS 1 +#define DFHACK_WANT_TILETYPES 1 #include using namespace DFHack; @@ -18,6 +18,7 @@ int main (int numargs, const char ** args) DFHack::ContextManager DFMgr("Memory.xml"); DFHack::Context *DF = DFMgr.getSingleContext(); +BEGIN_PROBE: try { DF->Attach(); @@ -31,6 +32,7 @@ int main (int numargs, const char ** args) return 1; } + DFHack::Position *Pos = DF->getPosition(); DFHack::VersionInfo* mem = DF->getMemoryInfo(); DFHack::Maps *Maps = DF->getMaps(); @@ -57,6 +59,11 @@ int main (int numargs, const char ** args) Maps->Start(); + vector global_features; + std::map > local_features; + Maps->ReadLocalFeatures(local_features); + Maps->ReadGlobalFeatures(global_features); + int32_t cursorX, cursorY, cursorZ; Pos->getCursorCoords(cursorX,cursorY,cursorZ); if(cursorX != -30000) @@ -82,7 +89,15 @@ int main (int numargs, const char ** args) // tiletype std::cout <<"tiletype: " << tiletype; if(tileTypeTable[tiletype].name) - std::cout << " = " << tileTypeTable[tiletype].name; + std::cout << " = " << tileTypeTable[tiletype].name << std::endl; + + printf("%-10s: %4d %s\n","Class",tileTypeTable[tiletype].c,TileClassString[ tileTypeTable[tiletype].c ] , 0); + printf("%-10s: %4d %s\n","Material",tileTypeTable[tiletype].c,TileMaterialString[ tileTypeTable[tiletype].m ] , 0); + printf("%-10s: %4d %s\n","Special",tileTypeTable[tiletype].c,TileSpecialString[ tileTypeTable[tiletype].s ] , 0); + printf("%-10s: %4d\n","Variant",tileTypeTable[tiletype].v , 0); + printf("%-10s: %s\n","Direction",tileTypeTable[tiletype].d.getStr() , 0); + + std::cout << std::endl; std::cout <<"temperature1: " << tmpb1[tileX][tileY] << " U" << std::endl; std::cout <<"temperature2: " << tmpb2[tileX][tileY] << " U" << std::endl; @@ -109,24 +124,47 @@ int main (int numargs, const char ** args) std::cout << "smooth?" << std::endl; uint32_t designato = block.origin + designatus + (tileX * 16 + tileY) * sizeof(t_designation); printf("designation offset: 0x%x\n", designato); - if(des.light) - std::cout << "Light "; - else - std::cout << " "; - if(des.skyview) - std::cout << "SkyView "; - else - std::cout << " "; - if(des.subterranean) - std::cout << "Underground "; - else - std::cout << " "; + +#define PRINT_FLAG( X ) printf("%-16s= %c\n", #X , ( des.X ? 'Y' : ' ' ) ) + PRINT_FLAG( hidden ); + PRINT_FLAG( light ); + PRINT_FLAG( skyview ); + PRINT_FLAG( subterranean ); + PRINT_FLAG( water_table ); + //PRINT_FLAG( rained ); + + planecoord pc; + pc.dim.x=blockX; pc.dim.y=blockY; + + PRINT_FLAG( feature_local ); + if( des.feature_local ){ + printf("%-16s %4d (%2d) %s\n", "", + block.local_feature, + local_features[pc][block.local_feature]->type, + sa_feature[local_features[pc][block.local_feature]->type] + ); + } + + PRINT_FLAG( feature_global ); + if( des.feature_global ){ + printf("%-16s %4d (%2d) %s\n", "", + block.global_feature, + global_features[block.global_feature].type, + sa_feature[global_features[block.global_feature].type] + ); + } + +#undef PRINT_FLAG + std::cout << std::endl; } } + DF->Detach(); #ifndef LINUX_BUILD - std::cout << "Done. Press any key to continue" << std::endl; + //std::cout << "Done. Press any key to continue" << std::endl; + std::cout << "Press any key to refresh..." << std::endl; cin.ignore(); + goto BEGIN_PROBE; #endif return 0; } From 30b94dac8787d1e135c018089968b1a4a37be48e Mon Sep 17 00:00:00 2001 From: zilpin Date: Thu, 21 Oct 2010 17:25:24 -0400 Subject: [PATCH 35/94] lots of new features. need debugging. --- tools/playground/hellhole.cpp | 605 ++++++++++++++++++++++++---------- 1 file changed, 438 insertions(+), 167 deletions(-) diff --git a/tools/playground/hellhole.cpp b/tools/playground/hellhole.cpp index e8fc9da17..4767d4700 100644 --- a/tools/playground/hellhole.cpp +++ b/tools/playground/hellhole.cpp @@ -39,8 +39,12 @@ void waitmsec (int delay) #define PITTYPEMACRO \ X(pitTypeChasm,"Bottomless Chasm" ) \ X(pitTypeEerie,"Bottomless Eerie Pit" ) \ - X(pitTypeFloor,"Pit with a floor" ) \ - X(pitTypeMagma,"Magma Pit (similar to volcanoe, no hell access)" ) + X(pitTypeFloor,"Pit with floor" ) \ + X(pitTypeSolid,"Solid Pillar" ) \ + X(pitTypeOasis,"Oasis, with partial aquifer (no hell access)" ) \ + X(pitTypeOPool,"Oasis Pool, with partial aquifer (default 5 deep)" ) \ + X(pitTypeMagma,"Magma Pit (similar to volcano, no hell access)" ) \ + X(pitTypeMPool,"Magma Pool (default 5 z-levels)" ) //end PITTYPEMACRO #define X(name,desc) name, @@ -99,21 +103,35 @@ int getint( const char * msg , int min, int max, int default_value ){ } } +int getint( const char * msg , int min, int max ){ + const int bufferlen=16; + static char buf[bufferlen]; + int n=0; + memset(buf,0,bufferlen); + while(-1){ + if(msg) printf("\n%s \n:" , msg ); + fflush(stdin); + fgets(buf,bufferlen,stdin); + if( !buf[0] || 0x0a==buf[0] || 0x0d==buf[0] ) continue; + if( sscanf(buf,"%d", &n) ){ + if(n>=min && n<=max ) return n; + } + } +} + //Interactive, get pit type from user -#define X( e , desc ) printf("%2d) %s\n", (e), (desc) ); -e_pitType selectPitType(e_pitType default_value ){ - e_pitType r=pitTypeInvalid; - int c=-1; +e_pitType selectPitType(){ while( -1 ){ - printf("Enter the type of hole to dig (if no entry, default everything):\n" ); - PITTYPEMACRO + printf("Enter the type of hole to dig:\n" ); + for(int n=0;n=0, replace with v. +//Returns number of neighbors found. +int checkneighbors(unsigned char pattern[16][16], int x, int y, unsigned char n , char v ) +{ + int r=0; + if( x>0 && y>0 && n==pattern[x-1][y-1] ){ ++r; if(v>-1) pattern[x][y]=v; } + if( x>0 && n==pattern[x-1][y ] ){ ++r; if(v>-1) pattern[x][y]=v; } + if( y>0 && n==pattern[x ][y-1] ){ ++r; if(v>-1) pattern[x][y]=v; } + if( x<15 && n==pattern[x+1][y ] ){ ++r; if(v>-1) pattern[x][y]=v; } + if( x<15 && y>0 && n==pattern[x+1][y-1] ){ ++r; if(v>-1) pattern[x][y]=v; } + if( x<15 && y<15 && n==pattern[x+1][y+1] ){ ++r; if(v>-1) pattern[x][y]=v; } + if( y<15 && n==pattern[x ][y+1] ){ ++r; if(v>-1) pattern[x][y]=v; } + if( x>0 && y<15 && n==pattern[x-1][y+1] ){ ++r; if(v>-1) pattern[x][y]=v; } + return r; +} +//convenience +int checkneighbors(unsigned char pattern[16][16], int x, int y, unsigned char n ) +{ + return checkneighbors(pattern,x,y,n,-1); +} + void settileat(unsigned char pattern[16][16], const unsigned char needle, const unsigned char v, const int index ) { int ok=0; @@ -189,14 +229,37 @@ void settileat(unsigned char pattern[16][16], const unsigned char needle, const } +//Is a given feature present at the given tile? +int isfeature( + vector global_features, + std::map > local_features, + const mapblock40d &block, const planecoord &pc, const int x, const int y, const e_feature Feat +) +{ + //const TileRow * tp; + //tp = getTileTypeP(block.tiletypes[x][y]); + const t_designation * d; + d = &block.designation[x][y]; + + if( block.local_feature > -1 && d->bits.feature_local ){ + if( Feat==local_features[pc][block.local_feature]->type ) return Feat; + } + if( block.global_feature > -1 && d->bits.feature_global ){ + if( Feat==global_features[block.global_feature].type ) return Feat; + } + + return 0; +} + + int main (void) { srand ( (unsigned int)time(NULL) ); //Message of intent cout << - "DF Hell Hole" << endl << - "This program will instantly dig a bottomless hole through hell, wherever your cursor is." << endl << + "DF Hole" << endl << + "This tool will instantly dig a chasm, pit, pipe, etc through hell, wherever your cursor is." << endl << "This can not be undone! End program now if you don't want hellish fun." << endl ; @@ -204,69 +267,22 @@ int main (void) //sloppy mess, but this is just a demo utility. //Pit Types. - e_pitType pittype = selectPitType(pitTypeInvalid); - + e_pitType pittype = selectPitType(); - //Hole Diameter + //Here are all the settings. + //Default values are set here. + int pitdepth=0; + int roof=-1; int holeradius=6; - if( pitTypeInvalid != pittype ){ - holeradius = getint( "Enter hole radius, 0 to 8", 0, 8, holeradius ); - } - - //Wall thickness int wallthickness=1; - if( pitTypeInvalid != pittype ){ - wallthickness = getint( "Enter wall thickness, 0 to 8", 0, 8, wallthickness ); - } - - //Obsidian Pillars - int pillarwall=1; - if( pitTypeInvalid != pittype ){ - pillarwall = getint( "Number of Obsidian Pillars in wall, 0 to 255", 0, 255, pillarwall ); - } - int pillarchasm=1; - if( pitTypeInvalid != pittype ){ - pillarchasm = getint( "Number of Obsidian Pillars in hole, 0 to 255", 0, 255, pillarchasm ); - } - - //Open Hell? + int wallpillar=1; + int holepillar=1; int exposehell = 0; - if( pitTypeInvalid != pittype && pitTypeMagma != pittype && wallthickness ){ - exposehell=getyesno("Expose the pit to hell (no walls in hell)?",0); - } - - //Fill? int fillmagma=0; - if( pitTypeInvalid != pittype ){ - fillmagma=getyesno("Fill with magma?",0); - } int fillwater=0; - if( pitTypeInvalid != pittype && !fillmagma){ - fillwater=getyesno("Fill with water?",0); - } - - - //If skipped all settings, fix the pit type - if( pitTypeInvalid == pittype ) pittype = pitTypeChasm; - - - /////////////////////////////////////////////////////////////////////////////////////////////// - //Print settings. - //If a settings struct existed, this could be in a routine - printf("Using Settings:\n"); - printf("Pit Type......: %d = %s\n", pittype, pitTypeDesc[pittype]); - printf("Hole Radius...: %d\n", holeradius); - printf("Wall Thickness: %d\n", wallthickness); - printf("Pillars, Wall.: %d\n", pillarwall); - printf("Pillars, Hole.: %d\n", pillarchasm); - printf("Expose Hell...: %c\n", (exposehell?'Y':'N') ); - printf("Magma Fill....: %c\n", (fillmagma?'Y':'N') ); - printf("Water Fill....: %c\n", (fillwater?'Y':'N') ); - - - - int64_t n; - uint32_t x_max,y_max,z_max; + int stopatmagma=0; + int exposemagma=0; + int aquify=0; //The Tile Type to use for the walls lining the hole //263 is semi-molten rock, 331 is obsidian @@ -274,10 +290,47 @@ int main (void) //The Tile Type to use for the hole's floor at bottom of the map //35 is chasm, 42 is eerie pit , 340 is obsidian floor, 344 is featstone floor, 264 is 'magma flow' floor uint32_t floor=35, cap=340; + int floorvar=0; + + + //Modify default settings based on pit type. switch( pittype ){ - case pitTypeEerie: floor=42; break; - case pitTypeFloor: floor=344; break; - case pitTypeMagma: floor=264; break; + case pitTypeChasm: + floor=35; + break; + case pitTypeEerie: + floor=42; + break; + case pitTypeFloor: + floor=344; + floorvar=3; + break; + case pitTypeOasis: + stopatmagma=-1; + //fillwater=-1; + wallthickness=2; + aquify=-1; + floor=340; + floorvar=3; + break; + case pitTypeOPool: + //fillwater=-1; + wallthickness=2; + aquify=-1; + floor=340; + floorvar=3; + break; + case pitTypeMagma: + stopatmagma=-1; + exposemagma=-1; + fillmagma=-1; + floor=264; + break; + case pitTypeMPool: + fillmagma=-1; + floor=340; + floorvar=3; + break; default: floor=35; } @@ -287,6 +340,59 @@ int main (void) int reveal=0; + int accept = getyesno("Use default settings?",1); + + while( !accept ){ + + //Pit Depth + pitdepth = getint( "Enter pit depth (0 for bottom of map)", 0, INT_MAX, pitdepth ); + + //Hole Size + holeradius = getint( "Enter hole radius, 0 to 16", 0, 8, holeradius ); + + //Wall thickness + wallthickness = getint( "Enter wall thickness, 0 to 16", 0, 8, wallthickness ); + + //Obsidian Pillars + holepillar = getint( "Number of Obsidian Pillars in hole, 0 to 255", 0, 255, holepillar ); + wallpillar = getint( "Number of Obsidian Pillars in wall, 0 to 255", 0, 255, wallpillar ); + + //Open Hell? + exposehell=getyesno("Expose the pit to hell (no walls in hell)?",exposehell); + + //Stop when magma sea is hit? + stopatmagma=getyesno("Stop at magma sea?",stopatmagma); + + //Fill? + fillmagma=getyesno("Fill with magma?",fillmagma); + if(fillmagma) aquify=fillwater=0; + fillwater=getyesno("Fill with water?",fillwater); + aquify=getyesno("Aquifer?",aquify); + + + /////////////////////////////////////////////////////////////////////////////////////////////// + //Print settings. + //If a settings struct existed, this could be in a routine + printf("Using Settings:\n"); + printf("Pit Type......: %d = %s\n", pittype, pitTypeDesc[pittype]); + printf("Hole Radius...: %d\n", holeradius); + printf("Wall Thickness: %d\n", wallthickness); + printf("Pillars, Hole.: %d\n", holepillar); + printf("Pillars, Wall.: %d\n", wallpillar); + printf("Expose Hell...: %c\n", (exposehell?'Y':'N') ); + printf("Stop at Magma.: %c\n", (stopatmagma?'Y':'N') ); + printf("Magma Fill....: %c\n", (fillmagma?'Y':'N') ); + printf("Water Fill....: %c\n", (fillwater?'Y':'N') ); + printf("Aquifer.......: %c\n", (aquify?'Y':'N') ); + + accept = getyesno("Accept these settings?",1); + } + + + int64_t n; + uint32_t x_max,y_max,z_max; + + //Pattern to dig unsigned char pattern[16][16]; @@ -322,38 +428,33 @@ int main (void) } }else if( 0==pattern[x][y] ){ //check neighbors - if( x>0 && y>0 && 1==pattern[x-1][y-1] ){ pattern[x][y]=2; continue; } - if( x>0 && 1==pattern[x-1][y ] ){ pattern[x][y]=2; continue; } - if( y>0 && 1==pattern[x ][y-1] ){ pattern[x][y]=2; continue; } - if( x<15 && 1==pattern[x+1][y ] ){ pattern[x][y]=2; continue; } - if( x<15 && y>0 && 1==pattern[x+1][y-1] ){ pattern[x][y]=2; continue; } - if( x<15 && y<15 && 1==pattern[x+1][y+1] ){ pattern[x][y]=2; continue; } - if( y<15 && 1==pattern[x ][y+1] ){ pattern[x][y]=2; continue; } - if( x>0 && y<15 && 1==pattern[x-1][y+1] ){ pattern[x][y]=2; continue; } + checkneighbors( pattern , x,y, 1, 2); } } } } - //Final pass, makes sure that somewhere random gets a vertical pillar of rock which is safe + //Makes sure that somewhere random gets a vertical pillar of rock which is safe //to dig stairs down, to permit access to anywhere within the pit from the top. - for(n=pillarchasm; n ; --n){ + for(n=holepillar; n ; --n){ settileat( pattern , 1 , 3 , rand()&255 ); } - for(n=pillarwall; n ; --n){ + for(n=wallpillar; n ; --n){ settileat( pattern , 2 , 3 , rand()&255 ); } + //Note: //At this point, the pattern holds: //0 for all tiles which will be ignored. //1 for all tiles set to empty pit space. //2 for all normal walls. //3 for the straight obsidian top-to-bottom wall. + //4 is randomized between wall or floor (!not implemented!) printf("\nPattern:\n"); - const char patternkey[] = ".cW!4567890123"; + const char patternkey[] = ".cW!?567890123"; //Print the pattern for(y=0;y<16;++y){ @@ -367,9 +468,15 @@ int main (void) regen = !getyesno("Acceptable Pattern?",1); } + //Post-process settings to fix problems here + if(pitdepth<1) pitdepth=INT_MAX; + /////////////////////////////////////////////////////////////////////////////////////////////// + + cerr << "Loading memory map..." << endl; + //Connect to DF! DFHack::ContextManager DFMgr("Memory.xml"); DFHack::Context *DF = DFMgr.getSingleContext(); @@ -377,6 +484,7 @@ int main (void) //Init + cerr << "Attaching to DF..." << endl; try { DF->Attach(); @@ -435,9 +543,9 @@ int main (void) //Verify that every z-level at this location exists. - for(int32_t z = 0; z<= bz ;z++){ - if( ! Mapz->isValidBlock(bx,by,z) ){ - cout << "This block does't exist yet!" << endl << "Designate the lowest level for digging to make DF allocate the block, then try again." << endl; + for(int32_t Z = 0; Z<= bz ;Z++){ + if( ! Mapz->isValidBlock(bx,by,Z) ){ + cout << "This block does't exist! Exiting." << endl; #ifndef LINUX_BUILD cin.ignore(); #endif @@ -479,11 +587,12 @@ int main (void) //Top level, cap. //Might make this an option in the future - if(-1){ + //For now, no wall means no cap. + if(wallthickness){ Mapz->ReadBlock40d( bx, by, bz , &block ); for(uint32_t x=0;x<16;++x){ for(uint32_t y=0;y<16;++y){ - if(pattern[x][y]){ + if( (pattern[x][y]>1) || (roof && pattern[x][y]) ){ tp = getTileTypeP(block.tiletypes[x][y]); d = &block.designation[x][y]; //Only modify this level if it's 'empty' @@ -511,27 +620,32 @@ int main (void) } /////////////////////////////////////////////////////////////////////////////////////////////// - //Various behaviour flags. - int magmacount=0; - int moltencount=0; - int solidcount=0; - int emptycount=0; - int hellcount=0; - int tpat; - //All levels in between. - uint32_t t; - for(int32_t z = bz-1; z>0 ; --z){ - moltencount=0; - magmacount=0; - solidcount=0; - emptycount=0; - hellcount=0; + int done=0; + uint32_t t,v; + int32_t z = bz-1; + int32_t bottom = max(0,bz-pitdepth-1); + assert( bottom>=0 && bottom<=bz ); + for( ; !done && z>=bottom ; --z){ + int watercount=0; + int magmacount=0; + int moltencount=0; + int solidcount=0; + int veincount=0; + int emptycount=0; + int hellcount=0; + int templecount=0; + int adamcount=0; + int featcount=0; + int tpat; + cout << z << endl; assert( Mapz->isValidBlock(bx,by,z) ); if(!Mapz->ReadBlock40d( bx, by, z , &block )){ - cout << "Bad block! " << bx << "," << by << "," << z; + cout << "Bad block! " << bx << "," << by << "," << z << endl; } + + //Pre-process this z-level, to get some tile statistics. for(int32_t x=0;x<16;++x){ for(int32_t y=0;y<16;++y){ t=0; @@ -539,59 +653,145 @@ int main (void) d = &block.designation[x][y]; tpat=pattern[x][y]; - //Manipulate behaviour based on settings and location + //Tile type material categories switch( tp->m ){ case MAGMA: ++moltencount; - case FEATSTONE: - case HFS: - //Making a fake volcanoe/magma pipe? - if( pitTypeMagma == pittype ){ - //Leave tile unchanged. - tpat=0; - } break; case VEIN: + ++veincount; + break; + case FEATSTONE: + case HFS: case OBSIDIAN: default: - if( EMPTY != tp->c ){ + if( EMPTY == tp->c || RAMP_TOP == tp->c || STAIR_DOWN == tp->c ){ ++emptycount; }else{ ++solidcount; } } - //No walls if magma found anywhere for a magma pipe - if( d->bits.flow_size && liquid_magma==d->bits.liquid_type ){ - ++magmacount; - if(pitTypeMagma == pittype){ - tpat=0; + //Magma and water + if( d->bits.flow_size ){ + if(d->bits.liquid_type){ + ++magmacount; + }else{ + ++watercount; } } - //Check hell status - if( - (block.local_feature > -1 && feature_Underworld==local_features[pc][block.local_feature]->type ) - || - (block.global_feature > -1 && feature_Underworld==global_features[block.global_feature].type ) - ){ - ++hellcount; + //Check for Features + if( block.local_feature > -1 || block.global_feature > -1 ){ + //Count tiles which actually are in the feature. + //It is possible for a block to have a feature, but no tiles to be feature. + if( d->bits.feature_global || d->bits.feature_local ){ + //All features + ++featcount; + + if( d->bits.feature_global && d->bits.feature_local ){ + cout << "warn:tile is global and local at same time!" << endl; + } - //Are we leaving hell open? + n=0; + if( block.global_feature > -1 && d->bits.feature_global ){ + n=global_features[block.global_feature].type; + switch( n ){ + case feature_Other: + //no count + break; + case feature_Adamantine_Tube: + ++adamcount; + break; + case feature_Underworld: + ++hellcount; + break; + case feature_Hell_Temple: + ++templecount; + break; + default: + //something here. for debugging, it may be interesting to know. + if(n) cout << '(' << n << ')'; + } + } + + n=0; + if( block.local_feature > -1 && d->bits.feature_local ){ + n=local_features[pc][block.local_feature]->type; + switch( n ){ + case feature_Other: + //no count + break; + case feature_Adamantine_Tube: + ++adamcount; + break; + case feature_Underworld: + ++hellcount; + break; + case feature_Hell_Temple: + ++templecount; + break; + default: + //something here. for debugging, it may be interesting to know. + if(n) cout << '[' << n << ']'; + } + } + } + } + } + } + + + ///////////////////////////////////////////////////////////////////////////////////////////////// + //Some checks, based on settings and stats collected + //First check, are we at illegal depth? + if( hellcount && stopatmagma ){ + //Panic! + done=-1; + tpat=0; + cout << "error: illegal breach of hell!"; + } + + + ///////////////////////////////////////////////////////////////////////////////////////////////// + //Actually process the current z-level. + //These loops do the work. + for(int32_t x=0;!done && x<16;++x){ + for(int32_t y=0;!done && y<16;++y){ + t=0; + tp = getTileTypeP(block.tiletypes[x][y]); + d = &block.designation[x][y]; + tpat=pattern[x][y]; + + //Change behaviour based on settings and stats from this z-level + + //In hell? + if( tpat && isfeature(global_features, local_features,block,pc,x,y,feature_Underworld ) ){ if( exposehell ){ - //Leave tile unchanged. tpat=0; } + } - //Never should have gotten here - if(pitTypeMagma == pittype){ - x=y=255; - z=0; + //Expose magma? + if( tpat && exposemagma ){ + //Leave certain tiles unchanged. + switch( tp->m ){ + case MAGMA: + case VEIN: + case FEATSTONE: + case HFS: + tpat=0; + } + //Leave magma sea unchanged. + if( d->bits.flow_size && d->bits.liquid_type){ tpat=0; - continue; } + } + //Stop at magma? + if( tpat && stopatmagma ){ + //Processed normally, but tricky at end. } @@ -623,12 +823,12 @@ int main (void) //Otherwise, remove all liquids. d->bits.flow_size=0; d->bits.liquid_character = liquid_fresh; - d->bits.liquid_type=liquid_water; + d->bits.liquid_type = liquid_water; } break; case 2: - //Border. + //Wall. //First guess based on current material switch( tp->m ){ case OBSIDIAN: @@ -664,9 +864,6 @@ int main (void) d->bits.feature_local = 1; t=335; break; - default: - //something here. for debugging, it may be interesting to know. - if(n) cout << '(' << n << ')'; } } //Global Feature? @@ -679,9 +876,6 @@ int main (void) d->bits.feature_global = 1; t=335; break; - default: - //something here. for debugging, it may be interesting to know. - if(n) cout << '[' << n << ']'; } } } @@ -691,9 +885,25 @@ int main (void) d->bits.liquid_character = liquid_fresh; d->bits.liquid_type=liquid_water; + //Placing an aquifer? + if( aquify ){ + //Only normal stone types can be aquified + if( tp->m!=MAGMA && tp->m!=FEATSTONE && tp->m!=HFS ){ + //Only place next to the hole. + //If no hole, place in middle. + if( checkneighbors(pattern,x,y,1) || (7==x && 7==y) ){ + d->bits.water_table = 1; + t=265; //soil wall + } + } + } + break; case 3: + //No obsidian walls on bottom of map! + if(z<1) continue; + //Special wall, always sets to obsidian, to give a stairway t=331; @@ -735,45 +945,106 @@ int main (void) Mapz->WriteDirtyBit(bx,by,z,1); //Making a fake volcanoe/magma pipe? - if( pitTypeMagma == pittype && !solidcount && (moltencount || magmacount) ){ - //Nothing «solid», we're making a magma pipe, we're done. - z=0; + if( stopatmagma && (moltencount || magmacount) && (!exposemagma || !solidcount) ){ + //If not exposing magma, quit at the first sign of magma. + //If exposing magma, quite once magma is exposed. + done=-1; } } + //Re-process the last z-level handled above. + z++; + assert( z>=0 ); + + /////////////////////////////////////////////////////////////////////////////////////////////// //The bottom level is special. if(-1){ - Mapz->ReadBlock40d( bx, by, 0 , &block ); + Mapz->ReadBlock40d( bx, by, z , &block ); for(uint32_t x=0;x<16;++x){ for(uint32_t y=0;y<16;++y){ - //Only the portion below the empty space is handled. - if(1==pattern[x][y]){ - //if( 1==pattern[x][y] ) t=floor; - //else if( 3==pattern[x][y] ) t=331; - //else continue; - - tp = getTileTypeP(block.tiletypes[x][y]); - d = &block.designation[x][y]; + t=floor; + v=floorvar; + tp = getTileTypeP(block.tiletypes[x][y]); + d = &block.designation[x][y]; - //Special handling for magma pipe. - //Need to be sure that solid blocks have a floor above them. - //Only solid blocks will have a floor drawn; empty blocks will be ignored. - if( pitTypeMagma == pittype ) { - if( EMPTY == tp->c || RAMP_TOP == tp->c || STAIR_DOWN == tp->c ) continue; + if( exposehell ){ + //Leave hell tiles unchanged when exposing hell. + if( isfeature(global_features,local_features,block,pc,x,y,feature_Underworld) ){ + continue; } + } - //For all tiles. - if(reveal) d->bits.hidden = 0; //topblock.designation[x][y].bits.hidden; - //Always clear the dig designation. - d->bits.dig=designation_no; - //unlock fluids - d->bits.flow_forbid = d->bits.liquid_static=0; - block.blockflags.bits.liquid_1 = block.blockflags.bits.liquid_2 = 1; - //Set the tile. - block.tiletypes[x][y] = floor; + switch(pattern[x][y]){ + case 0: + continue; + break; + case 1: + //Empty becomes floor. + + //Base floor type on the z-level first, features, then tile type. + if(!z){ + //Bottom of map, use the floor specified, always. + break; + } + + if(exposemagma){ + //Only place floor where ground is already solid when exposing + if( EMPTY == tp->c || RAMP_TOP == tp->c || STAIR_DOWN == tp->c ){ + continue; + } + } + + if( d->bits.feature_global || d->bits.feature_global ){ + //Feature Floor! + t=344; + break; + } + + //Tile material check. + switch( tp->m ){ + case OBSIDIAN: + t=340; + v=3; + break; + case MAGMA: + v=0; + t=264; //magma flow + break; + case HFS: + //should only happen at bottom of map + break; + case VEIN: + t=441; //vein floor + v=3; + break; + case FEATSTONE: + t=344; + v=3; + break; + } + + break; + case 2: + case 3: + //Walls already drawn. + //Ignore. + continue; + break; } + + //For all tiles. + if(reveal) d->bits.hidden = 0; //topblock.designation[x][y].bits.hidden; + //Always clear the dig designation. + d->bits.dig=designation_no; + //unlock fluids + d->bits.flow_forbid = d->bits.liquid_static=0; + block.blockflags.bits.liquid_1 = block.blockflags.bits.liquid_2 = 1; + + //Set the tile. + block.tiletypes[x][y] = t + ( v ? rand()&v : 0 ) ; + } } //Write the block. From e2d776d23fa33f110786defeaf983dcfd295d878 Mon Sep 17 00:00:00 2001 From: zilpin Date: Thu, 21 Oct 2010 19:00:12 -0400 Subject: [PATCH 36/94] tested, working. many extensions, hellhole should probably be renamed. --- tools/playground/hellhole.cpp | 71 +++++++++++++++++++++++------------ 1 file changed, 46 insertions(+), 25 deletions(-) diff --git a/tools/playground/hellhole.cpp b/tools/playground/hellhole.cpp index 4767d4700..e42fe992c 100644 --- a/tools/playground/hellhole.cpp +++ b/tools/playground/hellhole.cpp @@ -41,8 +41,8 @@ void waitmsec (int delay) X(pitTypeEerie,"Bottomless Eerie Pit" ) \ X(pitTypeFloor,"Pit with floor" ) \ X(pitTypeSolid,"Solid Pillar" ) \ - X(pitTypeOasis,"Oasis, with partial aquifer (no hell access)" ) \ - X(pitTypeOPool,"Oasis Pool, with partial aquifer (default 5 deep)" ) \ + X(pitTypeOasis,"Oasis Pit (ends at magma, no hell access)" ) \ + X(pitTypeOPool,"Oasis Pool, with partial aquifer (default 5 z-levels)" ) \ X(pitTypeMagma,"Magma Pit (similar to volcano, no hell access)" ) \ X(pitTypeMPool,"Magma Pool (default 5 z-levels)" ) //end PITTYPEMACRO @@ -305,34 +305,43 @@ int main (void) floor=344; floorvar=3; break; + case pitTypeSolid: + holeradius=0; + wallthickness=7; + wallpillar=4; + break; case pitTypeOasis: stopatmagma=-1; - //fillwater=-1; + fillwater=-1; + holeradius=5; wallthickness=2; - aquify=-1; + //aquify=-1; floor=340; floorvar=3; break; case pitTypeOPool: - //fillwater=-1; + pitdepth=5; + fillwater=-1; + holeradius=5; wallthickness=2; - aquify=-1; + //aquify=-1; floor=340; floorvar=3; break; case pitTypeMagma: stopatmagma=-1; exposemagma=-1; + wallthickness=2; fillmagma=-1; floor=264; break; case pitTypeMPool: + pitdepth=5; + wallthickness=2; fillmagma=-1; floor=340; floorvar=3; break; - default: - floor=35; } @@ -362,12 +371,13 @@ int main (void) //Stop when magma sea is hit? stopatmagma=getyesno("Stop at magma sea?",stopatmagma); + exposemagma=getyesno("Expose magma sea (no walls)?",exposemagma); //Fill? fillmagma=getyesno("Fill with magma?",fillmagma); if(fillmagma) aquify=fillwater=0; fillwater=getyesno("Fill with water?",fillwater); - aquify=getyesno("Aquifer?",aquify); + //aquify=getyesno("Aquifer?",aquify); /////////////////////////////////////////////////////////////////////////////////////////////// @@ -375,12 +385,14 @@ int main (void) //If a settings struct existed, this could be in a routine printf("Using Settings:\n"); printf("Pit Type......: %d = %s\n", pittype, pitTypeDesc[pittype]); + printf("Depth.........: %d\n", pitdepth); printf("Hole Radius...: %d\n", holeradius); printf("Wall Thickness: %d\n", wallthickness); printf("Pillars, Hole.: %d\n", holepillar); printf("Pillars, Wall.: %d\n", wallpillar); printf("Expose Hell...: %c\n", (exposehell?'Y':'N') ); printf("Stop at Magma.: %c\n", (stopatmagma?'Y':'N') ); + printf("Expose Magma..: %c\n", (exposemagma?'Y':'N') ); printf("Magma Fill....: %c\n", (fillmagma?'Y':'N') ); printf("Water Fill....: %c\n", (fillwater?'Y':'N') ); printf("Aquifer.......: %c\n", (aquify?'Y':'N') ); @@ -582,7 +594,7 @@ int main (void) t_designation * d; ////////////////////////////////////// - //From top to bottom, dig this dude. + //From top to bottom, dig this thing. ////////////////////////////////////// //Top level, cap. @@ -646,8 +658,10 @@ int main (void) } //Pre-process this z-level, to get some tile statistics. - for(int32_t x=0;x<16;++x){ - for(int32_t y=0;y<16;++y){ + for(int32_t x=0;x<16;++x) + { + for(int32_t y=0;y<16;++y) + { t=0; tp = getTileTypeP(block.tiletypes[x][y]); d = &block.designation[x][y]; @@ -753,7 +767,7 @@ int main (void) cout << "error: illegal breach of hell!"; } - + ///////////////////////////////////////////////////////////////////////////////////////////////// //Actually process the current z-level. //These loops do the work. @@ -764,6 +778,11 @@ int main (void) d = &block.designation[x][y]; tpat=pattern[x][y]; + //Up front, remove aquifer, to prevent bugginess + //It may be added back if aquify is set. + d->bits.water_table=0; + + //Change behaviour based on settings and stats from this z-level //In hell? @@ -778,7 +797,6 @@ int main (void) //Leave certain tiles unchanged. switch( tp->m ){ case MAGMA: - case VEIN: case FEATSTONE: case HFS: tpat=0; @@ -807,8 +825,8 @@ int main (void) //d->bits.skyview = topblock.designation[x][y].bits.skyview; //d->bits.subterranean = topblock.designation[x][y].bits.subterranean; - //Erase special markers - d->bits.feature_global = d->bits.feature_local = 0; + //Erase special markers? + //d->bits.feature_global = d->bits.feature_local = 0; //Water? Magma? if(fillmagma || fillwater){ @@ -838,7 +856,7 @@ int main (void) t=wmolten; break; case HFS: - t=whell; + //t=whell; break; case VEIN: t=440; //Solid vein block @@ -861,6 +879,7 @@ int main (void) case feature_Underworld: case feature_Hell_Temple: //Whatever the feature is made of. "featstone wall" + d->bits.feature_global = 0; d->bits.feature_local = 1; t=335; break; @@ -902,7 +921,9 @@ int main (void) case 3: //No obsidian walls on bottom of map! - if(z<1) continue; + if(z<1 && (d->bits.feature_global || d->bits.feature_local) ) { + t=335; + } //Special wall, always sets to obsidian, to give a stairway t=331; @@ -930,8 +951,6 @@ int main (void) //unlock fluids, so they fall down the pit. d->bits.flow_forbid = d->bits.liquid_static=0; block.blockflags.bits.liquid_1 = block.blockflags.bits.liquid_2 = 1; - //Remove aquifer, to prevent bugginess - d->bits.water_table=0; //Set the tile. block.tiletypes[x][y] = t; @@ -961,7 +980,9 @@ int main (void) /////////////////////////////////////////////////////////////////////////////////////////////// //The bottom level is special. if(-1){ - Mapz->ReadBlock40d( bx, by, z , &block ); + if(!Mapz->ReadBlock40d( bx, by, z , &block )){ + cout << "Bad block! " << bx << "," << by << "," << z << endl; + } for(uint32_t x=0;x<16;++x){ for(uint32_t y=0;y<16;++y){ t=floor; @@ -1048,10 +1069,10 @@ int main (void) } } //Write the block. - Mapz->WriteBlockFlags(bx,by,0, block.blockflags ); - Mapz->WriteDesignations(bx,by,0, &block.designation ); - Mapz->WriteTileTypes(bx,by,0, &block.tiletypes ); - Mapz->WriteDirtyBit(bx,by,0,1); + Mapz->WriteBlockFlags(bx,by,z, block.blockflags ); + Mapz->WriteDesignations(bx,by,z, &block.designation ); + Mapz->WriteTileTypes(bx,by,z, &block.tiletypes ); + Mapz->WriteDirtyBit(bx,by,z,1); } From 36fb3a2c6ac3aa6f7f8c9289fc6b32aade659799 Mon Sep 17 00:00:00 2001 From: zilpin Date: Fri, 22 Oct 2010 10:44:33 -0400 Subject: [PATCH 37/94] some bug fixes. magma pit still bugged when placed over adamantine tube, but no longer leaks. --- tools/playground/hellhole.cpp | 100 +++++++++++++++++++++------------- 1 file changed, 63 insertions(+), 37 deletions(-) diff --git a/tools/playground/hellhole.cpp b/tools/playground/hellhole.cpp index e42fe992c..32c6f9b46 100644 --- a/tools/playground/hellhole.cpp +++ b/tools/playground/hellhole.cpp @@ -354,13 +354,13 @@ int main (void) while( !accept ){ //Pit Depth - pitdepth = getint( "Enter pit depth (0 for bottom of map)", 0, INT_MAX, pitdepth ); + pitdepth = getint( "Enter max depth (0 for bottom of map)", 0, INT_MAX, pitdepth ); //Hole Size - holeradius = getint( "Enter hole radius, 0 to 16", 0, 8, holeradius ); + holeradius = getint( "Enter hole radius, 0 to 16", 0, 16, holeradius ); //Wall thickness - wallthickness = getint( "Enter wall thickness, 0 to 16", 0, 8, wallthickness ); + wallthickness = getint( "Enter wall thickness, 0 to 16", 0, 16, wallthickness ); //Obsidian Pillars holepillar = getint( "Number of Obsidian Pillars in hole, 0 to 255", 0, 255, holepillar ); @@ -371,7 +371,7 @@ int main (void) //Stop when magma sea is hit? stopatmagma=getyesno("Stop at magma sea?",stopatmagma); - exposemagma=getyesno("Expose magma sea (no walls)?",exposemagma); + exposemagma=getyesno("Expose magma sea (no walls in magma)?",exposemagma); //Fill? fillmagma=getyesno("Fill with magma?",fillmagma); @@ -642,7 +642,7 @@ int main (void) int watercount=0; int magmacount=0; int moltencount=0; - int solidcount=0; + int rockcount=0; int veincount=0; int emptycount=0; int hellcount=0; @@ -669,6 +669,9 @@ int main (void) //Tile type material categories switch( tp->m ){ + case AIR: + ++emptycount; + break; case MAGMA: ++moltencount; break; @@ -678,12 +681,15 @@ int main (void) case FEATSTONE: case HFS: case OBSIDIAN: + //basicly, ignored. + break; default: if( EMPTY == tp->c || RAMP_TOP == tp->c || STAIR_DOWN == tp->c ){ ++emptycount; }else{ - ++solidcount; + ++rockcount; } + break; } //Magma and water @@ -757,14 +763,23 @@ int main (void) } + //If stopping at magma, and no no non-feature stone in this layer, and magma found, then we're either at + //or below the magma sea / molten rock. + if( stopatmagma && (moltencount || magmacount) && (!exposemagma || !rockcount) ){ + //If not exposing magma, quit at the first sign of magma. + //If exposing magma, quite once magma is exposed. + done=-1; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////// //Some checks, based on settings and stats collected //First check, are we at illegal depth? - if( hellcount && stopatmagma ){ + if( !done && hellcount && stopatmagma ){ //Panic! done=-1; tpat=0; - cout << "error: illegal breach of hell!"; + cout << "error: illegal breach of hell!" << endl; } @@ -786,20 +801,26 @@ int main (void) //Change behaviour based on settings and stats from this z-level //In hell? - if( tpat && isfeature(global_features, local_features,block,pc,x,y,feature_Underworld ) ){ + if( tpat && tpat!=3 && isfeature(global_features, local_features,block,pc,x,y,feature_Underworld ) ){ if( exposehell ){ tpat=0; } } //Expose magma? - if( tpat && exposemagma ){ + if( tpat && tpat!=3 && exposemagma ){ //Leave certain tiles unchanged. switch( tp->m ){ - case MAGMA: - case FEATSTONE: case HFS: + case FEATSTONE: + case MAGMA: tpat=0; + default: + break; + } + //Adamantine may be left unchanged... + if( isfeature(global_features, local_features,block,pc,x,y,feature_Adamantine_Tube ) ){ + tpat=0; } //Leave magma sea unchanged. if( d->bits.flow_size && d->bits.liquid_type){ @@ -807,9 +828,13 @@ int main (void) } } - //Stop at magma? - if( tpat && stopatmagma ){ - //Processed normally, but tricky at end. + + //For all situations... + //Special modification for walls, always for adamantine. + if( isfeature(global_features, local_features,block,pc,x,y,feature_Adamantine_Tube ) ){ + if( 2==pattern[x][y] || 3==pattern[x][y] ){ + tpat=2; + } } @@ -868,16 +893,20 @@ int main (void) t=wcave; } - //If the tile already is a feature, or if it is a vein, we're done. - //Otherwise, adopt block features. + //Adamantine (a local feature) trumps veins. { //Local Feature? - if( block.local_feature > -1 && !d->bits.feature_global ){ + if( block.local_feature > -1 ){ switch( n=local_features[pc][block.local_feature]->type ){ - case feature_Adamantine_Tube: case feature_Underworld: case feature_Hell_Temple: + //Only adopt these if there is no global feature present + if( block.global_feature >-1 ){ + break; + } + case feature_Adamantine_Tube: + //Always for adamantine, sometimes for others //Whatever the feature is made of. "featstone wall" d->bits.feature_global = 0; d->bits.feature_local = 1; @@ -905,6 +934,7 @@ int main (void) d->bits.liquid_type=liquid_water; //Placing an aquifer? + //(bugged, these aquifers don't generate water!) if( aquify ){ //Only normal stone types can be aquified if( tp->m!=MAGMA && tp->m!=FEATSTONE && tp->m!=HFS ){ @@ -912,7 +942,7 @@ int main (void) //If no hole, place in middle. if( checkneighbors(pattern,x,y,1) || (7==x && 7==y) ){ d->bits.water_table = 1; - t=265; //soil wall + //t=265; //soil wall } } } @@ -920,10 +950,10 @@ int main (void) break; case 3: - //No obsidian walls on bottom of map! - if(z<1 && (d->bits.feature_global || d->bits.feature_local) ) { - t=335; - } + ////No obsidian walls on bottom of map! + //if(z<1 && (d->bits.feature_global || d->bits.feature_local) ) { + // t=335; + //} //Special wall, always sets to obsidian, to give a stairway t=331; @@ -963,13 +993,6 @@ int main (void) Mapz->WriteTileTypes(bx,by,z, &block.tiletypes ); Mapz->WriteDirtyBit(bx,by,z,1); - //Making a fake volcanoe/magma pipe? - if( stopatmagma && (moltencount || magmacount) && (!exposemagma || !solidcount) ){ - //If not exposing magma, quit at the first sign of magma. - //If exposing magma, quite once magma is exposed. - done=-1; - } - } //Re-process the last z-level handled above. @@ -997,6 +1020,11 @@ int main (void) } } + //Does expose magma need anything at this level? + if( exposemagma && stopatmagma ){ + continue; + } + switch(pattern[x][y]){ case 0: continue; @@ -1010,12 +1038,10 @@ int main (void) break; } - if(exposemagma){ - //Only place floor where ground is already solid when exposing - if( EMPTY == tp->c || RAMP_TOP == tp->c || STAIR_DOWN == tp->c ){ - continue; - } - } + ////Only place floor where ground is already solid when exposing + //if( EMPTY == tp->c || RAMP_TOP == tp->c || STAIR_DOWN == tp->c ){ + // continue; + //} if( d->bits.feature_global || d->bits.feature_global ){ //Feature Floor! From 70cb93d9f4c510d8a3718e4e1455c984f81943a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Mon, 25 Oct 2010 04:39:14 +0200 Subject: [PATCH 38/94] Fixed includes, unified formatting. --- library/include/dfhack/DFTileTypes.h | 607 ++++---- tools/playground/deramp.cpp | 133 +- tools/playground/hellhole.cpp | 2058 ++++++++++++++------------ tools/playground/printtiletypes.cpp | 127 +- tools/supported/probe.cpp | 334 +++-- 5 files changed, 1722 insertions(+), 1537 deletions(-) diff --git a/library/include/dfhack/DFTileTypes.h b/library/include/dfhack/DFTileTypes.h index affff0c7a..8ccb89827 100644 --- a/library/include/dfhack/DFTileTypes.h +++ b/library/include/dfhack/DFTileTypes.h @@ -30,9 +30,9 @@ distribution. namespace DFHack { - // tile class -- determines the general shape of the tile - // enum and lookup table for string names created using X macros -#define TILECLASS_MACRO \ + // tile class -- determines the general shape of the tile + // enum and lookup table for string names created using X macros + #define TILECLASS_MACRO \ X(EMPTY, "") \ X(WALL, "") \ X(PILLAR, "") \ @@ -51,32 +51,32 @@ namespace DFHack X(SHRUB_OK, "") \ X(BOULDER, "") \ X(PEBBLES, "") -//end TILECLASS_MACRO - - //define tile class enum - #define X(name,comment) name, - enum TileClass { - tileclass_invalid=-1, - TILECLASS_MACRO - tileclass_count, - }; - #undef X - - //Visual Studio screams if you don't do this for the const char* arrays - #ifndef char_p - typedef char * char_p; - #endif - - //set tile class string lookup table (e.g. for printing to user) - #define X(name,comment) #name, - const char_p TileClassString[tileclass_count+1] = { - TILECLASS_MACRO - NULL - }; - #undef X - - -#define TILEMATERIAL_MACRO \ + //end TILECLASS_MACRO + + //define tile class enum + #define X(name,comment) name, + enum TileClass { + tileclass_invalid=-1, + TILECLASS_MACRO + tileclass_count, + }; + #undef X + + //Visual Studio screams if you don't do this for the const char* arrays + #ifndef char_p + typedef char * char_p; + #endif + + //set tile class string lookup table (e.g. for printing to user) + #define X(name,comment) #name, + const char_p TileClassString[tileclass_count+1] = { + TILECLASS_MACRO + 0 + }; + #undef X + + + #define TILEMATERIAL_MACRO \ X(AIR, "empty" ) \ X(SOIL, "ordinary soil. material depends on geology" ) \ X(STONE, "ordinary layer stone. material depends on geology" ) \ @@ -96,30 +96,30 @@ namespace DFHack X(ASHES, "what remains from a FIRE" ) \ X(CONSTRUCTED,"tile material depends on the construction present" ) \ X(CYAN_GLOW, "the glowy stuff that disappears from the demon temple when you take the sword." ) -//end TILEMATERIAL_MACRO + //end TILEMATERIAL_MACRO // material enum - #define X(name,comment) name, - enum TileMaterial { - tilematerial_invalid=-1, - TILEMATERIAL_MACRO - tilematerial_count, - }; - #undef X - - //string lookup table (e.g. for printing to user) - #define X(name,comment) #name, - const char_p TileMaterialString[tilematerial_count+1] = { - TILEMATERIAL_MACRO - NULL - }; - #undef X - - - // Special specials of the tile. - // Not the best way to do this, but compatible with existing code. - // When the TileType class gets created, everything should be re-thought. -#define TILESPECIAL_MACRO \ + #define X(name,comment) name, + enum TileMaterial { + tilematerial_invalid=-1, + TILEMATERIAL_MACRO + tilematerial_count, + }; + #undef X + + //string lookup table (e.g. for printing to user) + #define X(name,comment) #name, + const char_p TileMaterialString[tilematerial_count+1] = { + TILEMATERIAL_MACRO + 0 + }; + #undef X + + + // Special specials of the tile. + // Not the best way to do this, but compatible with existing code. + // When the TileType class gets created, everything should be re-thought. + #define TILESPECIAL_MACRO \ X(NORMAL, "Default for all type, nothing present" ) \ X(SPECIAL, "General purpose, for any unique tile which can not otherwise be differenciated" ) \ X(POOL, "Murky Pool, will gather water from rain" ) \ @@ -133,141 +133,146 @@ namespace DFHack X(DAMAGED, "Walls being dug" ) \ X(WORN, "Walls being dug ??" ) \ X(SMOOTH, "Walls and floors." ) -//end TILESPECIAL_MACRO - - //special enum - #define X(name,comment) TILE_##name, - enum TileSpecial { - tilespecial_invalid=-1, - TILESPECIAL_MACRO - tilespecial_count, - }; - #undef X - - //string lookup table (e.g. for printing to user) - #define X(name,comment) #name, - const char_p TileSpecialString[tilespecial_count+1] = { - TILESPECIAL_MACRO - NULL - }; - #undef X + //end TILESPECIAL_MACRO + + //special enum + #define X(name,comment) TILE_##name, + enum TileSpecial { + tilespecial_invalid=-1, + TILESPECIAL_MACRO + tilespecial_count, + }; + #undef X + + //string lookup table (e.g. for printing to user) + #define X(name,comment) #name, + const char_p TileSpecialString[tilespecial_count+1] = { + TILESPECIAL_MACRO + 0 + }; + #undef X // variants are used for tiles, where there are multiple variants of the same - like grass floors enum TileVariant { - tilevariant_invalid=-1, - VAR_1, //Yes, the value of VAR_1 is 0. It's legacy. Deal with it. + tilevariant_invalid=-1, + VAR_1, //Yes, the value of VAR_1 is 0. It's legacy. Deal with it. VAR_2, VAR_3, VAR_4, }; - //Mainly walls and rivers - //Byte values are used because walls can have either 1 or 2 in any given direction. - const int TileDirectionCount = 4; - union TileDirection - { - uint32_t whole; - unsigned char b[TileDirectionCount]; - struct { - //Maybe should add 'up' and 'down' for Z-levels? - unsigned char north,south,west,east; - }; - - inline TileDirection() - { - whole = 0; - } - TileDirection( uint32_t whole_bits) - { - whole = whole_bits; - } - TileDirection( unsigned char North, unsigned char South, unsigned char West, unsigned char East ) - { - north=North; south=South; east=East; west=West; - } - TileDirection( const char *dir ) - { - //This one just made for fun. - //Supports N S E W - const char *p = dir; - unsigned char *l=NULL; - north=south=east=west=0; - if(!dir) return; - - for( ;*p;++p){ - switch(*p){ - case 'N': //North / Up - case 'n': - ++north; l=&north; break; - case 'S': //South / Down - case 's': - ++south; l=&south; break; - case 'E': //East / Right - case 'e': - ++east; l=&east; break; - case 'W': //West / Left - case 'w': - ++west; l=&west; break; - case '-': - case ' ': - //Explicitly ensure dash and space are ignored. - //Other characters/symbols may be assigned in the future. - break; - default: - if( l && '0' <= *p && '9' >= *p ) - *l += *p - '0'; - break; - } - } - } - - //may be useful for some situations - inline uint32_t sum() const { - return 0L + north + south + east + west; - } - - //Gives a string that represents the direction. - //This is a static string, overwritten with every call! - //Support values > 2 even though they should never happen. - //Copy string if it will be used. - inline char * getStr() const { - static char str[16]; - //type punning trick - *( (uint64_t *)str ) = *( (uint64_t *)"--------" ); - str[8]=0; -#define DIRECTION(x,i,c) \ - if(x){ \ - str[i]=c; \ - if(1==x) ; \ - else if(2==x) str[i+1]=c; \ - else str[i+1]='0'+x; \ - } - - DIRECTION(north,0,'N') - DIRECTION(south,2,'S') - DIRECTION(west,4,'W') - DIRECTION(east,6,'E') -#undef DIRECTION - return str; - } - - - }; - + //Mainly walls and rivers + //Byte values are used because walls can have either 1 or 2 in any given direction. + const int TileDirectionCount = 4; + union TileDirection + { + uint32_t whole; + unsigned char b[TileDirectionCount]; + struct + { + //Maybe should add 'up' and 'down' for Z-levels? + unsigned char north,south,west,east; + }; + + inline TileDirection() + { + whole = 0; + } + TileDirection( uint32_t whole_bits) + { + whole = whole_bits; + } + TileDirection( unsigned char North, unsigned char South, unsigned char West, unsigned char East ) + { + north=North; south=South; east=East; west=West; + } + TileDirection( const char *dir ) + { + //This one just made for fun. + //Supports N S E W + const char *p = dir; + unsigned char *l=0; + north=south=east=west=0; + if(!dir) return; + + for( ;*p;++p) + { + switch(*p) + { + case 'N': //North / Up + case 'n': + ++north; l=&north; break; + case 'S': //South / Down + case 's': + ++south; l=&south; break; + case 'E': //East / Right + case 'e': + ++east; l=&east; break; + case 'W': //West / Left + case 'w': + ++west; l=&west; break; + case '-': + case ' ': + //Explicitly ensure dash and space are ignored. + //Other characters/symbols may be assigned in the future. + break; + default: + if( l && '0' <= *p && '9' >= *p ) + *l += *p - '0'; + break; + } + } + } + + //may be useful for some situations + inline uint32_t sum() const + { + return 0L + north + south + east + west; + } + + //Gives a string that represents the direction. + //This is a static string, overwritten with every call! + //Support values > 2 even though they should never happen. + //Copy string if it will be used. + inline char * getStr() const + { + static char str[16]; + //type punning trick + *( (uint64_t *)str ) = *( (uint64_t *)"--------" ); + str[8]=0; + #define DIRECTION(x,i,c) \ + if(x){ \ + str[i]=c; \ + if(1==x) ; \ + else if(2==x) str[i+1]=c; \ + else str[i+1]='0'+x; \ + } + + DIRECTION(north,0,'N') + DIRECTION(south,2,'S') + DIRECTION(west,4,'W') + DIRECTION(east,6,'E') + #undef DIRECTION + return str; + } + + + }; + struct TileRow { const char * name; TileClass c; TileMaterial m; TileVariant v; - TileSpecial s; - TileDirection d; + TileSpecial s; + TileDirection d; }; - - #define TILE_TYPE_ARRAY_LENGTH 520 + + #define TILE_TYPE_ARRAY_LENGTH 520 const TileRow tileTypeTable[TILE_TYPE_ARRAY_LENGTH] = { @@ -282,7 +287,7 @@ namespace DFHack {0, EMPTY, AIR, VAR_1}, {0, EMPTY, AIR, VAR_1}, {0, EMPTY, AIR, VAR_1}, - + // 10 {0, EMPTY, AIR, VAR_1}, {0, EMPTY, AIR, VAR_1}, @@ -294,7 +299,7 @@ namespace DFHack {0, EMPTY, AIR, VAR_1}, {0, EMPTY, AIR, VAR_1}, {"driftwood stack",FLOOR, DRIFTWOOD, VAR_1}, - + // 20 {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, @@ -306,7 +311,7 @@ namespace DFHack {"ice stair up",STAIR_UP, ICE, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, - + // 30 {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, @@ -318,7 +323,7 @@ namespace DFHack {"obsidian stair down",STAIR_DOWN, OBSIDIAN, VAR_1}, {"obsidian stair up",STAIR_UP, OBSIDIAN, VAR_1}, {"soil stair up/down",STAIR_UPDOWN, SOIL, VAR_1}, - + // 40 {"soil stair down",STAIR_DOWN, SOIL, VAR_1}, {"soil stair up",STAIR_UP, SOIL, VAR_1}, @@ -330,7 +335,7 @@ namespace DFHack {"smooth ice floor",FLOOR, ICE, VAR_1 , TILE_SMOOTH }, {0 ,EMPTY, AIR, VAR_1}, {"grass stair up/down",STAIR_UPDOWN, GRASS, VAR_1}, - + // 50 {"grass stair down",STAIR_DOWN, GRASS, VAR_1}, {"grass stair up",STAIR_UP, GRASS, VAR_1}, @@ -342,7 +347,7 @@ namespace DFHack {"stone stair up",STAIR_UP, STONE, VAR_1}, {"vein stair up/down",STAIR_UPDOWN, VEIN, VAR_1}, {"vein stair down",STAIR_DOWN, VEIN, VAR_1}, - + // 60 {"vein stair up",STAIR_UP, VEIN, VAR_1}, {"featstone? stair up/down",STAIR_UPDOWN, FEATSTONE, VAR_1}, @@ -354,7 +359,7 @@ namespace DFHack {"campfire",FLOOR, CAMPFIRE, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, - + // 70 {"fire",FLOOR, FIRE, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, @@ -366,7 +371,7 @@ namespace DFHack {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, {"stone pillar",PILLAR, STONE, VAR_1}, - + //80 {"obsidian pillar",PILLAR, OBSIDIAN, VAR_1}, {"featstone? pillar",PILLAR, FEATSTONE, VAR_1}, @@ -378,7 +383,7 @@ namespace DFHack {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, {"waterfall landing",FLOOR, SOIL, VAR_1, TILE_WATERFALL }, // verify material - + // 90 {"river source",FLOOR, SOIL, VAR_1, TILE_RIVER_SOURCE }, // verify material {0 ,EMPTY, AIR, VAR_1}, @@ -390,7 +395,7 @@ namespace DFHack {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, - + // 100 {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, @@ -402,7 +407,7 @@ namespace DFHack {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, - + // 110 {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, @@ -414,7 +419,7 @@ namespace DFHack {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, - + // 120 {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, @@ -426,7 +431,7 @@ namespace DFHack {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, - + // 130 {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, @@ -438,7 +443,7 @@ namespace DFHack {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, - + // 140 {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, @@ -450,7 +455,7 @@ namespace DFHack {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, - + // 150 {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, @@ -462,7 +467,7 @@ namespace DFHack {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, - + // 160 {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, @@ -474,7 +479,7 @@ namespace DFHack {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, - + // 170 {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, @@ -486,7 +491,7 @@ namespace DFHack {"damaged stone wall" ,WALL, STONE, VAR_1, TILE_DAMAGED }, {"worn stone wall" ,WALL, STONE, VAR_1, TILE_WORN }, {0 ,EMPTY, AIR, VAR_1}, - + // 180 {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, @@ -498,7 +503,7 @@ namespace DFHack {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, - + // 190 {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, @@ -510,7 +515,7 @@ namespace DFHack {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, - + // 200 {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, @@ -522,7 +527,7 @@ namespace DFHack {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, - + // 210 {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, @@ -534,7 +539,7 @@ namespace DFHack {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, {"stone wall" ,WALL, STONE, VAR_1}, - + // 220 {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, @@ -546,7 +551,7 @@ namespace DFHack {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, - + // 230 {0 ,EMPTY, AIR, VAR_1}, {"sapling" ,SAPLING_OK, SOIL, VAR_1}, @@ -558,7 +563,7 @@ namespace DFHack {"stone ramp" ,RAMP, STONE, VAR_1}, {"obsidian ramp" ,RAMP, OBSIDIAN, VAR_1}, {"featstone? ramp" ,RAMP, FEATSTONE, VAR_1}, - + // 240 {"vein ramp" ,RAMP, VEIN, VAR_1}, {"soil ramp" ,RAMP, SOIL, VAR_1}, @@ -570,7 +575,7 @@ namespace DFHack {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, - + // 250 {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, @@ -582,7 +587,7 @@ namespace DFHack {0 ,EMPTY, AIR, VAR_1}, {"ice floor" ,FLOOR, ICE, VAR_2}, {"ice floor" ,FLOOR, ICE, VAR_3}, - + // 260 {"ice floor" ,FLOOR, ICE, VAR_4}, {"furrowed soil" ,FLOOR, SOIL, VAR_1}, @@ -594,7 +599,7 @@ namespace DFHack {"glowing floor" ,FLOOR, CYAN_GLOW, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, {"smooth obsidian wall RD2",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "--SS--E-" }, - + // 270 {"smooth obsidian wall R2D",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "--S---EE" }, {"smooth obsidian wall R2U",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "N-----EE" }, @@ -606,7 +611,7 @@ namespace DFHack {"smooth obsidian wall LRUD",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH ,"N-S-W-E-" }, {"smooth obsidian wall RUD",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "N-S---E-" }, {"smooth obsidian wall LRD",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "--S-W-E-" }, - + // 280 {"smooth obsidian wall LRU",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "N---W-E-" }, {"smooth obsidian wall LUD",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "N-S-W---" }, @@ -618,7 +623,7 @@ namespace DFHack {"smooth obsidian wall LR",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "----W-E-" }, {"smooth featstone wall RD2",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "--SS--E-" }, {"smooth featstone wall R2D",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "--S---EE" }, - + // 290 {"smooth featstone wall R2U",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "N-----EE" }, {"smooth featstone wall RU2",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "NN----E-" }, @@ -630,7 +635,7 @@ namespace DFHack {"smooth featstone wall RUD",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "N-S---E-" }, {"smooth featstone wall LRD",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "--S-W-E-" }, {"smooth featstone wall LRU",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "N---W-E-" }, - + //300 {"smooth featstone wall LUD",WALL,FEATSTONE,VAR_1, TILE_SMOOTH , "N-S-W---" }, {"smooth featstone wall RD",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "--S---E-" }, @@ -642,7 +647,7 @@ namespace DFHack {"smooth stone wall RD2",WALL,STONE,VAR_1 , TILE_SMOOTH , "--SS--E-" }, {"smooth stone wall R2D",WALL,STONE,VAR_1 , TILE_SMOOTH , "--S---EE" }, {"smooth stone wall R2U",WALL,STONE,VAR_1 , TILE_SMOOTH , "N-----EE" }, - + //310 {"smooth stone wall RU2",WALL,STONE,VAR_1 , TILE_SMOOTH , "NN----E-" }, {"smooth stone wall L2U",WALL,STONE,VAR_1 , TILE_SMOOTH , "N---WW--" }, @@ -654,7 +659,7 @@ namespace DFHack {"smooth stone wall LRD",WALL,STONE,VAR_1 , TILE_SMOOTH , "--S-W-E-" }, {"smooth stone wall LRU",WALL,STONE,VAR_1 , TILE_SMOOTH , "N---W-E-" }, {"smooth stone wall LUD",WALL,STONE,VAR_1 , TILE_SMOOTH , "N-S-W---" }, - + //320 {"smooth stone wall RD",WALL,STONE,VAR_1 , TILE_SMOOTH , "--S---E-" }, {"smooth stone wall RU",WALL,STONE,VAR_1 , TILE_SMOOTH , "N-----E-" }, @@ -666,7 +671,7 @@ namespace DFHack {"featstone? fortification",FORTIFICATION,FEATSTONE,VAR_1}, {"cracked obsidian wall",WALL,OBSIDIAN,VAR_1, TILE_CRACKED }, {"damaged obsidian wall",WALL,OBSIDIAN,VAR_1, TILE_DAMAGED }, - + // 330 {"worn obsidian wall",WALL,OBSIDIAN,VAR_1}, {"obsidian wall",WALL,OBSIDIAN,VAR_1}, @@ -682,7 +687,7 @@ namespace DFHack {"stone floor",FLOOR,STONE,VAR_2}, {"stone floor",FLOOR,STONE,VAR_3}, {"stone floor",FLOOR,STONE,VAR_4}, - + // 340 {"obsidian floor",FLOOR,OBSIDIAN,VAR_1}, {"obsidian floor",FLOOR,OBSIDIAN,VAR_2}, @@ -694,7 +699,7 @@ namespace DFHack {"featstone floor 4",FLOOR,FEATSTONE,VAR_4}, {"grass 1",FLOOR,GRASS,VAR_1}, {"grass 2",FLOOR,GRASS,VAR_2}, - + // 350 {"grass 3",FLOOR,GRASS,VAR_3}, {"grass 4",FLOOR,GRASS,VAR_4}, @@ -706,7 +711,7 @@ namespace DFHack {"wet soil floor",FLOOR,SOIL,VAR_2}, {"wet soil floor",FLOOR,SOIL,VAR_3}, {"wet soil floor",FLOOR,SOIL,VAR_4}, - + // 360 {"ice fortification",FORTIFICATION,ICE,VAR_1}, {"cracked ice wall",WALL,ICE,VAR_1, TILE_CRACKED}, @@ -718,7 +723,7 @@ namespace DFHack {"river E",FLOOR,SOIL,VAR_1, TILE_RIVER , "E" }, {"river W",FLOOR,SOIL,VAR_1, TILE_RIVER , "W" }, {"river NW",FLOOR,SOIL,VAR_1, TILE_RIVER, "NW"}, - + //370 {"river NE",FLOOR,SOIL,VAR_1, TILE_RIVER , "NE" }, {"river SW",FLOOR,SOIL,VAR_1, TILE_RIVER , "SW" }, @@ -730,7 +735,7 @@ namespace DFHack {"stream bed NW",FLOOR,SOIL,VAR_1, TILE_STREAM, "NW" }, {"stream bed NE",FLOOR,SOIL,VAR_1, TILE_STREAM, "NE" }, {"stream bed SW",FLOOR,SOIL,VAR_1, TILE_STREAM, "SW" }, - + // 380 {"stream bed SE",FLOOR,SOIL,VAR_1, TILE_STREAM, "SE" }, {"stream top",FLOOR,SOIL,VAR_1, TILE_STREAM_TOP }, @@ -742,7 +747,7 @@ namespace DFHack {"dry grass 1",FLOOR,GRASS_DRY,VAR_1}, {"dry grass 2",FLOOR,GRASS_DRY,VAR_2}, {"dry grass 3",FLOOR,GRASS_DRY,VAR_3}, - + // 390 {"dry grass 4",FLOOR,GRASS_DRY,VAR_4}, {"dead tree",TREE_DEAD,SOIL,VAR_1}, @@ -754,7 +759,7 @@ namespace DFHack {"dead grass 4",FLOOR,GRASS_DEAD,VAR_4}, {"grass B1",FLOOR,GRASS2,VAR_1}, {"grass B2",FLOOR,GRASS2,VAR_2}, - + // 400 {"grass B3",FLOOR,GRASS2,VAR_3}, {"grass B4",FLOOR,GRASS2,VAR_4}, @@ -766,7 +771,7 @@ namespace DFHack {"pebbles 3",PEBBLES,STONE,VAR_3}, {"pebbles 4",PEBBLES,STONE,VAR_4}, {"obsidian shards",PEBBLES,OBSIDIAN,VAR_1}, - + // 410 {"obsidian shards",PEBBLES,OBSIDIAN,VAR_2}, {"obsidian shards",PEBBLES,OBSIDIAN,VAR_3}, @@ -778,7 +783,7 @@ namespace DFHack {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "--SS--E-"}, {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "--S---EE"}, {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N-----EE" }, - + // 420 {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "NN----E-"}, {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N---WW--"}, @@ -790,7 +795,7 @@ namespace DFHack {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "--S-W-E-"}, {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N---W-E-"}, {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N-S-W---"}, - + // 430 {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "--S---E-"}, {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N-----E-"}, @@ -802,7 +807,7 @@ namespace DFHack {"cracked vein wall",WALL,VEIN,VAR_1, TILE_CRACKED }, {"damaged vein wall",WALL,VEIN,VAR_1, TILE_DAMAGED }, {"worn vein wall",WALL,VEIN,VAR_1 , TILE_WORN }, - + // 440 {"vein wall",WALL,VEIN,VAR_1}, {"vein floor",FLOOR,VEIN,VAR_1}, @@ -814,7 +819,7 @@ namespace DFHack {"vein pebbles",PEBBLES,VEIN,VAR_2}, {"vein pebbles",PEBBLES,VEIN,VAR_3}, {"vein pebbles",PEBBLES,VEIN,VAR_4}, - + // 450 {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "--SS--E-"}, {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "--S---EE" }, @@ -826,7 +831,7 @@ namespace DFHack {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "--SSW---" }, {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N-S-W-E-"}, {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N-S---E-" }, - + // 460 {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "--S-W-E-" }, {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N---W-E-" }, @@ -838,7 +843,7 @@ namespace DFHack {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N-S-----" }, {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "----W-E-"}, {0 ,EMPTY, AIR, VAR_1}, - + // 470 {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, @@ -850,7 +855,7 @@ namespace DFHack {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, - + // 480 {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, @@ -862,7 +867,7 @@ namespace DFHack {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, - + // 490 {0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1}, @@ -874,7 +879,7 @@ namespace DFHack {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "--S---EE" }, {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N-----EE" }, {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "NN----E-" }, - + // 500 {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N---WW--" }, {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "NN--W---" }, @@ -886,11 +891,11 @@ namespace DFHack {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N---W-E-" }, {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N-S-W---" }, {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "--S---E-" }, - + // 510 {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N-----E-" }, {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N---W---" }, - {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "--S-W---" }, + {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "--S-W---" }, {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N-S-----" }, {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "----W-E-" }, {"constructed stair up/down",STAIR_UPDOWN,CONSTRUCTED, VAR_1}, @@ -899,7 +904,7 @@ namespace DFHack {"constructed ramp",RAMP,CONSTRUCTED, VAR_1}, {0 ,EMPTY, AIR, VAR_1} // end }; - + inline bool isWallTerrain(int in) { @@ -911,116 +916,114 @@ namespace DFHack { return tileTypeTable[in].c >= FLOOR && tileTypeTable[in].c <= PEBBLES; } - + inline bool isRampTerrain(int in) { return tileTypeTable[in].c == RAMP; } - + inline bool isStairTerrain(int in) { return tileTypeTable[in].c >= STAIR_UP && tileTypeTable[in].c <= STAIR_UPDOWN; } - + inline bool isOpenTerrain(int in) { return tileTypeTable[in].c == EMPTY; } - + inline int getVegetationType(int in) { return tileTypeTable[in].c; } - //zilpin: for convenience, when you'll be using the tile information a lot. + //zilpin: for convenience, when you'll be using the tile information a lot. inline const TileRow * getTileTypeP(int in) { - if( in<0 || in>=TILE_TYPE_ARRAY_LENGTH ) return NULL; + if( in<0 || in>=TILE_TYPE_ARRAY_LENGTH ) return 0; return ( const TileRow * ) &tileTypeTable[in]; } - //zilpin: Find the first tile entry which matches the given search criteria. - //All parameters are optional. - //To omit, use the 'invalid' enum for that type (e.g. tileclass_invalid, tilematerial_invalid, etc) - //For tile directions, pass NULL to omit. - //Returns matching index in tileTypeTable, or -1 if none found. - inline - int32_t findTileType( const TileClass tclass, const TileMaterial tmat, const TileVariant tvar, const TileSpecial tspecial, const TileDirection tdir ) - { - int32_t tt; - for(tt=0;tt-1 ) if( tclass != tileTypeTable[tt].c ) continue; - if( tmat>-1 ) if( tmat != tileTypeTable[tt].m ) continue; - if( tvar>-1 ) if( tvar != tileTypeTable[tt].v ) continue; - if( tspecial>-1 ) if( tspecial != tileTypeTable[tt].s ) continue; - if( tdir.whole ) if( tdir.whole != tileTypeTable[tt].d.whole ) continue; - //Match! - return tt; - } - return -1; - } - //Convenience version of the above, to pass strings as the direction - inline - int32_t findTileType( const TileClass tclass, const TileMaterial tmat, const TileVariant tvar, const TileSpecial tspecial, const char *tdirStr ) - { - if(tdirStr){ - TileDirection tdir(tdirStr); - return findTileType(tclass,tmat,tvar,tspecial, tdir ); - }else{ - return findTileType(tclass,tmat,tvar,tspecial, NULL ); - } - } - - - //zilpin: Find a tile type similar to the one given, but with a different class. - //Useful for tile-editing operations. - //If no match found, returns the sourceType - //Definitely needs improvement for wall directions, etc. - inline - int32_t findSimilarTileType( const int32_t sourceTileType, const TileClass tclass ){ - int32_t tt, maybe=0, match=0; - int value=0, matchv=0; - const TileRow *source = &tileTypeTable[sourceTileType]; - const char * sourcename = source->name; - const uint32_t sourcenameint = *((const uint32_t *)sourcename); - -#ifdef assert - assert( sourceTileType >=0 && sourceTileType < TILE_TYPE_ARRAY_LENGTH ); -#endif - - for(tt=0;tts != tileTypeTable[tt].s ) continue; - - maybe=tt; value=0; - //Material is high-value match - if( tileTypeTable[tt].m == source->m ) value|=8; - //Direction is medium value match - if( tileTypeTable[tt].d.whole == source->d.whole ) value|=4; - //Variant is low-value match - if( tileTypeTable[tt].v == source->v ) value|=1; - - //Check value against last match - if( value>matchv ){ - match=tt; - matchv=value; - } - } - } - if( match ) return match; - return sourceTileType; - } + //zilpin: Find the first tile entry which matches the given search criteria. + //All parameters are optional. + //To omit, use the 'invalid' enum for that type (e.g. tileclass_invalid, tilematerial_invalid, etc) + //For tile directions, pass NULL to omit. + //Returns matching index in tileTypeTable, or -1 if none found. + inline + int32_t findTileType( const TileClass tclass, const TileMaterial tmat, const TileVariant tvar, const TileSpecial tspecial, const TileDirection tdir ) + { + int32_t tt; + for(tt=0;tt-1 ) if( tclass != tileTypeTable[tt].c ) continue; + if( tmat>-1 ) if( tmat != tileTypeTable[tt].m ) continue; + if( tvar>-1 ) if( tvar != tileTypeTable[tt].v ) continue; + if( tspecial>-1 ) if( tspecial != tileTypeTable[tt].s ) continue; + if( tdir.whole ) if( tdir.whole != tileTypeTable[tt].d.whole ) continue; + //Match! + return tt; + } + return -1; + } + //Convenience version of the above, to pass strings as the direction + inline + int32_t findTileType( const TileClass tclass, const TileMaterial tmat, const TileVariant tvar, const TileSpecial tspecial, const char *tdirStr ) + { + if(tdirStr){ + TileDirection tdir(tdirStr); + return findTileType(tclass,tmat,tvar,tspecial, tdir ); + }else{ + return findTileType(tclass,tmat,tvar,tspecial, 0 ); + } + } + + //zilpin: Find a tile type similar to the one given, but with a different class. + //Useful for tile-editing operations. + //If no match found, returns the sourceType + //Definitely needs improvement for wall directions, etc. + inline + int32_t findSimilarTileType( const int32_t sourceTileType, const TileClass tclass ){ + int32_t tt, maybe=0, match=0; + int value=0, matchv=0; + const TileRow *source = &tileTypeTable[sourceTileType]; + const char * sourcename = source->name; + const uint32_t sourcenameint = *((const uint32_t *)sourcename); + + #ifdef assert + assert( sourceTileType >=0 && sourceTileType < TILE_TYPE_ARRAY_LENGTH ); + #endif + + for(tt=0;tts != tileTypeTable[tt].s ) continue; + + maybe=tt; value=0; + //Material is high-value match + if( tileTypeTable[tt].m == source->m ) value|=8; + //Direction is medium value match + if( tileTypeTable[tt].d.whole == source->d.whole ) value|=4; + //Variant is low-value match + if( tileTypeTable[tt].v == source->v ) value|=1; + + //Check value against last match + if( value>matchv ){ + match=tt; + matchv=value; + } + } + } + if( match ) return match; + return sourceTileType; + } } diff --git a/tools/playground/deramp.cpp b/tools/playground/deramp.cpp index 3cfbf5170..894cc1082 100644 --- a/tools/playground/deramp.cpp +++ b/tools/playground/deramp.cpp @@ -5,6 +5,7 @@ #include #include #include +#include using namespace std; #include @@ -20,20 +21,20 @@ int main (void) DFHack::tiletypes40d tiles; DFHack::tiletypes40d tilesAbove; - //DFHack::TileRow *ptile; - int32_t oldT, newT; - int16_t t; + //DFHack::TileRow *ptile; + int32_t oldT, newT; + int16_t t; + + int dirty=0, count=0; - int dirty=0, count=0; - DFHack::ContextManager DFMgr("Memory.xml"); DFHack::Context *DF = DFMgr.getSingleContext(); - //sanity check - assert( sizeof(designations) == (16*16*sizeof(DFHack::t_designation)) ); + //sanity check + assert( sizeof(designations) == (16*16*sizeof(DFHack::t_designation)) ); - //Init - try + //Init + try { DF->Attach(); } @@ -46,9 +47,9 @@ int main (void) return 1; } DFHack::Maps *Mapz = DF->getMaps(); - + // init the map - if(!Mapz->Start()) + if (!Mapz->Start()) { cerr << "Can't init map." << endl; #ifndef LINUX_BUILD @@ -56,73 +57,81 @@ int main (void) #endif return 1; } - + Mapz->getSize(x_max,y_max,z_max); uint8_t zeroes [16][16] = {0}; // walk the map - for(uint32_t x = 0; x< x_max;x++) + for (uint32_t x = 0; x< x_max;x++) { - for(uint32_t y = 0; y< y_max;y++) + for (uint32_t y = 0; y< y_max;y++) { - for(uint32_t z = 0; z< z_max;z++) + for (uint32_t z = 0; z< z_max;z++) { - if(Mapz->isValidBlock(x,y,z)) + if (Mapz->isValidBlock(x,y,z)) { - dirty=0; + dirty=0; Mapz->ReadDesignations(x,y,z, &designations); - Mapz->ReadTileTypes(x,y,z, &tiles); - if(Mapz->isValidBlock(x,y,z+1)){ - Mapz->ReadTileTypes(x,y,z+1, &tilesAbove); - }else{ - memset(&tilesAbove,0,sizeof(tilesAbove)); - } - - for(uint32_t ty=0;ty<16;++ty){ - for(uint32_t tx=0;tx<16;++tx){ - //Only the remove ramp designation (ignore channel designation, etc) - oldT = tiles[tx][ty]; - if( DFHack::designation_default == designations[tx][ty].bits.dig - && DFHack::RAMP==DFHack::tileTypeTable[oldT].c - ){ - //Current tile is a ramp. - //Set current tile, as accurately as can be expected - newT = DFHack::findSimilarTileType(oldT,DFHack::FLOOR); - - //If no change, skip it (couldn't find a good tile type) - if( oldT == newT) continue; - //Set new tile type, clear designation - tiles[tx][ty] = newT; - designations[tx][ty].bits.dig = DFHack::designation_no; - - //Check the tile above this one, in case a downward slope needs to be removed. - if( DFHack::RAMP_TOP == DFHack::tileTypeTable[tilesAbove[tx][ty]].c ){ - tilesAbove[tx][ty] = 32; - } - - dirty=-1; - ++count; - } - } - } - //If anything was changed, write it all. - if(dirty){ - Mapz->WriteDesignations(x,y,z, &designations); - Mapz->WriteTileTypes(x,y,z, &tiles); - if(Mapz->isValidBlock(x,y,z+1)){ - Mapz->WriteTileTypes(x,y,z+1, &tilesAbove); - } - } + Mapz->ReadTileTypes(x,y,z, &tiles); + if (Mapz->isValidBlock(x,y,z+1)) + { + Mapz->ReadTileTypes(x,y,z+1, &tilesAbove); + } + else + { + memset(&tilesAbove,0,sizeof(tilesAbove)); + } + + for (uint32_t ty=0;ty<16;++ty) + { + for (uint32_t tx=0;tx<16;++tx) + { + //Only the remove ramp designation (ignore channel designation, etc) + oldT = tiles[tx][ty]; + if ( DFHack::designation_default == designations[tx][ty].bits.dig + && DFHack::RAMP==DFHack::tileTypeTable[oldT].c) + { + //Current tile is a ramp. + //Set current tile, as accurately as can be expected + newT = DFHack::findSimilarTileType(oldT,DFHack::FLOOR); + + //If no change, skip it (couldn't find a good tile type) + if ( oldT == newT) continue; + //Set new tile type, clear designation + tiles[tx][ty] = newT; + designations[tx][ty].bits.dig = DFHack::designation_no; + + //Check the tile above this one, in case a downward slope needs to be removed. + if ( DFHack::RAMP_TOP == DFHack::tileTypeTable[tilesAbove[tx][ty]].c ) + { + tilesAbove[tx][ty] = 32; + } + + dirty=-1; + ++count; + } + } + } + //If anything was changed, write it all. + if (dirty) + { + Mapz->WriteDesignations(x,y,z, &designations); + Mapz->WriteTileTypes(x,y,z, &tiles); + if (Mapz->isValidBlock(x,y,z+1)) + { + Mapz->WriteTileTypes(x,y,z+1, &tilesAbove); + } + } } } } } DF->Detach(); - cout << "Found and changed " << count << " tiles." << endl; - #ifndef LINUX_BUILD + cout << "Found and changed " << count << " tiles." << endl; +#ifndef LINUX_BUILD cout << "Done. Press any key to continue" << endl; cin.ignore(); - #endif +#endif return 0; } diff --git a/tools/playground/hellhole.cpp b/tools/playground/hellhole.cpp index 32c6f9b46..a57b815a1 100644 --- a/tools/playground/hellhole.cpp +++ b/tools/playground/hellhole.cpp @@ -10,6 +10,9 @@ #include #include #include +#include +#include +#include using namespace std; #include @@ -37,21 +40,22 @@ void waitmsec (int delay) //User interaction enums. //Pit Type (these only have meaning within hellhole, btw) #define PITTYPEMACRO \ - X(pitTypeChasm,"Bottomless Chasm" ) \ - X(pitTypeEerie,"Bottomless Eerie Pit" ) \ - X(pitTypeFloor,"Pit with floor" ) \ - X(pitTypeSolid,"Solid Pillar" ) \ - X(pitTypeOasis,"Oasis Pit (ends at magma, no hell access)" ) \ - X(pitTypeOPool,"Oasis Pool, with partial aquifer (default 5 z-levels)" ) \ - X(pitTypeMagma,"Magma Pit (similar to volcano, no hell access)" ) \ - X(pitTypeMPool,"Magma Pool (default 5 z-levels)" ) + X(pitTypeChasm,"Bottomless Chasm" ) \ + X(pitTypeEerie,"Bottomless Eerie Pit" ) \ + X(pitTypeFloor,"Pit with floor" ) \ + X(pitTypeSolid,"Solid Pillar" ) \ + X(pitTypeOasis,"Oasis Pit (ends at magma, no hell access)" ) \ + X(pitTypeOPool,"Oasis Pool, with partial aquifer (default 5 z-levels)" ) \ + X(pitTypeMagma,"Magma Pit (similar to volcano, no hell access)" ) \ + X(pitTypeMPool,"Magma Pool (default 5 z-levels)" ) //end PITTYPEMACRO #define X(name,desc) name, -enum e_pitType { - pitTypeInvalid=-1, - PITTYPEMACRO - pitTypeCount, +enum e_pitType +{ + pitTypeInvalid=-1, + PITTYPEMACRO + pitTypeCount, }; #undef X @@ -59,129 +63,175 @@ enum e_pitType { #define X(name,desc) desc, const char * pitTypeDesc[pitTypeCount+1] = { - PITTYPEMACRO - "" + PITTYPEMACRO + "" }; #undef X -int getyesno( const char * msg , int default_value ){ - const int bufferlen=4; - static char buf[bufferlen]; - memset(buf,0,bufferlen); - while(-1){ - if(msg) printf("\n%s (default=%s)\n:" , msg , (default_value?"yes":"no") ); - fflush(stdin); - fgets(buf,bufferlen,stdin); - switch(buf[0]){ - case 0: case 0x0d: case 0x0a: - return default_value; - case 'y': case 'Y': case 'T': case 't': case '1': - return -1; - case 'n': case 'N': case 'F': case 'f': case '0': - return 0; - } - } - return 0; +int getyesno( const char * msg , int default_value ) +{ + const int bufferlen=4; + static char buf[bufferlen]; + memset(buf,0,bufferlen); + while (-1) + { + if (msg) printf("\n%s (default=%s)\n:" , msg , (default_value?"yes":"no") ); + fflush(stdin); + fgets(buf,bufferlen,stdin); + switch (buf[0]) + { + case 0: + case 0x0d: + case 0x0a: + return default_value; + case 'y': + case 'Y': + case 'T': + case 't': + case '1': + return -1; + case 'n': + case 'N': + case 'F': + case 'f': + case '0': + return 0; + } + } + return 0; } -int getint( const char * msg , int min, int max, int default_value ){ - const int bufferlen=16; - static char buf[bufferlen]; - int n=0; - memset(buf,0,bufferlen); - while(-1){ - if(msg) printf("\n%s (default=%d)\n:" , msg , default_value); - fflush(stdin); - fgets(buf,bufferlen,stdin); - if( !buf[0] || 0x0a==buf[0] || 0x0d==buf[0] ) return default_value; - if( sscanf(buf,"%d", &n) ){ - if(n>=min && n<=max ) return n; - } - } +int getint( const char * msg , int min, int max, int default_value ) { + const int bufferlen=16; + static char buf[bufferlen]; + int n=0; + memset(buf,0,bufferlen); + while (-1) + { + if (msg) printf("\n%s (default=%d)\n:" , msg , default_value); + fflush(stdin); + fgets(buf,bufferlen,stdin); + if ( !buf[0] || 0x0a==buf[0] || 0x0d==buf[0] ) + { + return default_value; + } + if ( sscanf(buf,"%d", &n) ) + { + if (n>=min && n<=max ) + { + return n; + } + } + } } -int getint( const char * msg , int min, int max ){ - const int bufferlen=16; - static char buf[bufferlen]; - int n=0; - memset(buf,0,bufferlen); - while(-1){ - if(msg) printf("\n%s \n:" , msg ); - fflush(stdin); - fgets(buf,bufferlen,stdin); - if( !buf[0] || 0x0a==buf[0] || 0x0d==buf[0] ) continue; - if( sscanf(buf,"%d", &n) ){ - if(n>=min && n<=max ) return n; - } - } +int getint( const char * msg , int min, int max ) +{ + const int bufferlen=16; + static char buf[bufferlen]; + int n=0; + memset(buf,0,bufferlen); + while (-1) + { + if (msg) + { + printf("\n%s \n:" , msg ); + } + fflush(stdin); + fgets(buf,bufferlen,stdin); + + if ( !buf[0] || 0x0a==buf[0] || 0x0d==buf[0] ) + { + continue; + } + if ( sscanf(buf,"%d", &n) ) + { + if (n>=min && n<=max ) + { + return n; + } + } + } } //Interactive, get pit type from user -e_pitType selectPitType(){ - while( -1 ){ - printf("Enter the type of hole to dig:\n" ); - for(int n=0;n0 && y>0 && n==pattern[x-1][y-1] ){ ++r; if(v>-1) pattern[x][y]=v; } - if( x>0 && n==pattern[x-1][y ] ){ ++r; if(v>-1) pattern[x][y]=v; } - if( y>0 && n==pattern[x ][y-1] ){ ++r; if(v>-1) pattern[x][y]=v; } - if( x<15 && n==pattern[x+1][y ] ){ ++r; if(v>-1) pattern[x][y]=v; } - if( x<15 && y>0 && n==pattern[x+1][y-1] ){ ++r; if(v>-1) pattern[x][y]=v; } - if( x<15 && y<15 && n==pattern[x+1][y+1] ){ ++r; if(v>-1) pattern[x][y]=v; } - if( y<15 && n==pattern[x ][y+1] ){ ++r; if(v>-1) pattern[x][y]=v; } - if( x>0 && y<15 && n==pattern[x-1][y+1] ){ ++r; if(v>-1) pattern[x][y]=v; } - return r; + int r=0; + if ( x>0 && y>0 && n==pattern[x-1][y-1] ) + { + ++r; + if (v>-1) pattern[x][y]=v; + } + if ( x>0 && n==pattern[x-1][y ] ) + { + ++r; + if (v>-1) pattern[x][y]=v; + } + if ( y>0 && n==pattern[x ][y-1] ) + { + ++r; + if (v>-1) pattern[x][y]=v; + } + if ( x<15 && n==pattern[x+1][y ] ) + { + ++r; + if (v>-1) pattern[x][y]=v; + } + if ( x<15 && y>0 && n==pattern[x+1][y-1] ) + { + ++r; + if (v>-1) pattern[x][y]=v; + } + if ( x<15 && y<15 && n==pattern[x+1][y+1] ) + { + ++r; + if (v>-1) pattern[x][y]=v; + } + if ( y<15 && n==pattern[x ][y+1] ) + { + ++r; + if (v>-1) pattern[x][y]=v; + } + if ( x>0 && y<15 && n==pattern[x-1][y+1] ) + { + ++r; + if (v>-1) pattern[x][y]=v; + } + return r; } //convenience int checkneighbors(unsigned char pattern[16][16], int x, int y, unsigned char n ) { - return checkneighbors(pattern,x,y,n,-1); + return checkneighbors(pattern,x,y,n,-1); } void settileat(unsigned char pattern[16][16], const unsigned char needle, const unsigned char v, const int index ) { - int ok=0; - int safety=256*256; - int y,x,i=0; - //Scan for sequential index - while( !ok && --safety ){ - for(y=0 ; !ok && y<16 ; ++y ){ - for(x=0 ; !ok && x<16 ; ++x ){ - if( needle==pattern[x][y] ){ - ++i; - if( index==i ){ - //Got it! - pattern[x][y]=v; - ok=-1; - } - } - } - } - } + int ok=0; + int safety=256*256; + int y,x,i=0; + //Scan for sequential index + while ( !ok && --safety ) + { + for (y=0 ; !ok && y<16 ; ++y ) + { + for (x=0 ; !ok && x<16 ; ++x ) + { + if ( needle==pattern[x][y] ) + { + ++i; + if ( index==i ) + { + //Got it! + pattern[x][y]=v; + ok=-1; + } + } + } + } + } } +//FIXME: good candidate for adding to dfhack. Maybe the Maps should have those cached so they can be queried? //Is a given feature present at the given tile? int isfeature( - vector global_features, - std::map > local_features, - const mapblock40d &block, const planecoord &pc, const int x, const int y, const e_feature Feat + vector global_features, + std::map > local_features, + const mapblock40d &block, const planecoord &pc, const int x, const int y, const e_feature Feat ) { - //const TileRow * tp; - //tp = getTileTypeP(block.tiletypes[x][y]); - const t_designation * d; - d = &block.designation[x][y]; - - if( block.local_feature > -1 && d->bits.feature_local ){ - if( Feat==local_features[pc][block.local_feature]->type ) return Feat; - } - if( block.global_feature > -1 && d->bits.feature_global ){ - if( Feat==global_features[block.global_feature].type ) return Feat; - } - - return 0; -} + //const TileRow * tp; + //tp = getTileTypeP(block.tiletypes[x][y]); + const t_designation * d; + d = &block.designation[x][y]; + if ( block.local_feature > -1 && d->bits.feature_local ) { + if ( Feat==local_features[pc][block.local_feature]->type ) return Feat; + } + if ( block.global_feature > -1 && d->bits.feature_global ) { + if ( Feat==global_features[block.global_feature].type ) return Feat; + } + return 0; +} + +// FIXME: use block cache, break into manageable bits int main (void) { - srand ( (unsigned int)time(NULL) ); - - //Message of intent - cout << - "DF Hole" << endl << - "This tool will instantly dig a chasm, pit, pipe, etc through hell, wherever your cursor is." << endl << - "This can not be undone! End program now if you don't want hellish fun." << endl - ; - - //User selection of settings should have it own routine, a structure for settings, I know - //sloppy mess, but this is just a demo utility. - - //Pit Types. - e_pitType pittype = selectPitType(); - - //Here are all the settings. - //Default values are set here. - int pitdepth=0; - int roof=-1; - int holeradius=6; - int wallthickness=1; - int wallpillar=1; - int holepillar=1; - int exposehell = 0; - int fillmagma=0; - int fillwater=0; - int stopatmagma=0; - int exposemagma=0; - int aquify=0; - - //The Tile Type to use for the walls lining the hole - //263 is semi-molten rock, 331 is obsidian - uint32_t whell=263, wmolten=263, wmagma=331, wcave=331; - //The Tile Type to use for the hole's floor at bottom of the map - //35 is chasm, 42 is eerie pit , 340 is obsidian floor, 344 is featstone floor, 264 is 'magma flow' floor - uint32_t floor=35, cap=340; - int floorvar=0; - - - //Modify default settings based on pit type. - switch( pittype ){ - case pitTypeChasm: - floor=35; - break; - case pitTypeEerie: - floor=42; - break; - case pitTypeFloor: - floor=344; - floorvar=3; - break; - case pitTypeSolid: - holeradius=0; - wallthickness=7; - wallpillar=4; - break; - case pitTypeOasis: - stopatmagma=-1; - fillwater=-1; - holeradius=5; - wallthickness=2; - //aquify=-1; - floor=340; - floorvar=3; - break; - case pitTypeOPool: - pitdepth=5; - fillwater=-1; - holeradius=5; - wallthickness=2; - //aquify=-1; - floor=340; - floorvar=3; - break; - case pitTypeMagma: - stopatmagma=-1; - exposemagma=-1; - wallthickness=2; - fillmagma=-1; - floor=264; - break; - case pitTypeMPool: - pitdepth=5; - wallthickness=2; - fillmagma=-1; - floor=340; - floorvar=3; - break; - } - - - //Should tiles be revealed? - int reveal=0; - - - int accept = getyesno("Use default settings?",1); - - while( !accept ){ - - //Pit Depth - pitdepth = getint( "Enter max depth (0 for bottom of map)", 0, INT_MAX, pitdepth ); - - //Hole Size - holeradius = getint( "Enter hole radius, 0 to 16", 0, 16, holeradius ); - - //Wall thickness - wallthickness = getint( "Enter wall thickness, 0 to 16", 0, 16, wallthickness ); - - //Obsidian Pillars - holepillar = getint( "Number of Obsidian Pillars in hole, 0 to 255", 0, 255, holepillar ); - wallpillar = getint( "Number of Obsidian Pillars in wall, 0 to 255", 0, 255, wallpillar ); - - //Open Hell? - exposehell=getyesno("Expose the pit to hell (no walls in hell)?",exposehell); - - //Stop when magma sea is hit? - stopatmagma=getyesno("Stop at magma sea?",stopatmagma); - exposemagma=getyesno("Expose magma sea (no walls in magma)?",exposemagma); - - //Fill? - fillmagma=getyesno("Fill with magma?",fillmagma); - if(fillmagma) aquify=fillwater=0; - fillwater=getyesno("Fill with water?",fillwater); - //aquify=getyesno("Aquifer?",aquify); - - - /////////////////////////////////////////////////////////////////////////////////////////////// - //Print settings. - //If a settings struct existed, this could be in a routine - printf("Using Settings:\n"); - printf("Pit Type......: %d = %s\n", pittype, pitTypeDesc[pittype]); - printf("Depth.........: %d\n", pitdepth); - printf("Hole Radius...: %d\n", holeradius); - printf("Wall Thickness: %d\n", wallthickness); - printf("Pillars, Hole.: %d\n", holepillar); - printf("Pillars, Wall.: %d\n", wallpillar); - printf("Expose Hell...: %c\n", (exposehell?'Y':'N') ); - printf("Stop at Magma.: %c\n", (stopatmagma?'Y':'N') ); - printf("Expose Magma..: %c\n", (exposemagma?'Y':'N') ); - printf("Magma Fill....: %c\n", (fillmagma?'Y':'N') ); - printf("Water Fill....: %c\n", (fillwater?'Y':'N') ); - printf("Aquifer.......: %c\n", (aquify?'Y':'N') ); - - accept = getyesno("Accept these settings?",1); - } - - - int64_t n; - uint32_t x_max,y_max,z_max; - - - //Pattern to dig - unsigned char pattern[16][16]; - - - for(int regen=1;regen; ){ - regen=0; - - memset(pattern,0,sizeof(pattern)); + srand ( (unsigned int)time(NULL) ); + + //Message of intent + cout << + "DF Hole" << endl << + "This tool will instantly dig a chasm, pit, pipe, etc through hell, wherever your cursor is." << endl << + "This can not be undone! End program now if you don't want hellish fun." << endl + ; + + //User selection of settings should have it own routine, a structure for settings, I know + //sloppy mess, but this is just a demo utility. + + //Pit Types. + e_pitType pittype = selectPitType(); + + //Here are all the settings. + //Default values are set here. + int pitdepth=0; + int roof=-1; + int holeradius=6; + int wallthickness=1; + int wallpillar=1; + int holepillar=1; + int exposehell = 0; + int fillmagma=0; + int fillwater=0; + int stopatmagma=0; + int exposemagma=0; + int aquify=0; + + //The Tile Type to use for the walls lining the hole + //263 is semi-molten rock, 331 is obsidian + uint32_t whell=263, wmolten=263, wmagma=331, wcave=331; + //The Tile Type to use for the hole's floor at bottom of the map + //35 is chasm, 42 is eerie pit , 340 is obsidian floor, 344 is featstone floor, 264 is 'magma flow' floor + uint32_t floor=35, cap=340; + int floorvar=0; + + + //Modify default settings based on pit type. + switch ( pittype ) + { + case pitTypeChasm: + floor=35; + break; + case pitTypeEerie: + floor=42; + break; + case pitTypeFloor: + floor=344; + floorvar=3; + break; + case pitTypeSolid: + holeradius=0; + wallthickness=7; + wallpillar=4; + break; + case pitTypeOasis: + stopatmagma=-1; + fillwater=-1; + holeradius=5; + wallthickness=2; + //aquify=-1; + floor=340; + floorvar=3; + break; + case pitTypeOPool: + pitdepth=5; + fillwater=-1; + holeradius=5; + wallthickness=2; + //aquify=-1; + floor=340; + floorvar=3; + break; + case pitTypeMagma: + stopatmagma=-1; + exposemagma=-1; + wallthickness=2; + fillmagma=-1; + floor=264; + break; + case pitTypeMPool: + pitdepth=5; + wallthickness=2; + fillmagma=-1; + floor=340; + floorvar=3; + break; + } - //Calculate a randomized circle. - //These values found through experimentation. - int x=0, y=0, n=0; - //Two concentric irregular circles - //Outer circle, solid. - if( wallthickness ){ - drawcircle(holeradius+wallthickness, pattern, 2); - } - //Inner circle, hole. - if( holeradius ){ - drawcircle(holeradius, pattern, 1); - } + //Should tiles be revealed? + int reveal=0; - //Post-process to be certain the wall totally encloses hole. - if(wallthickness){ - for(y=0;y<16;++y){ - for(x=0;x<16;++x){ - if( 1==pattern[x][y] ){ - //No hole at edges. - if( x<1 || x>14 || y<1 || y>14 ){ - pattern[x][y]=2; - } - }else if( 0==pattern[x][y] ){ - //check neighbors - checkneighbors( pattern , x,y, 1, 2); - } - } - } - } + int accept = getyesno("Use default settings?",1); - //Makes sure that somewhere random gets a vertical pillar of rock which is safe - //to dig stairs down, to permit access to anywhere within the pit from the top. - for(n=holepillar; n ; --n){ - settileat( pattern , 1 , 3 , rand()&255 ); - } - for(n=wallpillar; n ; --n){ - settileat( pattern , 2 , 3 , rand()&255 ); - } + while ( !accept ) + { + //Pit Depth + pitdepth = getint( "Enter max depth (0 for bottom of map)", 0, INT_MAX, pitdepth ); + + //Hole Size + holeradius = getint( "Enter hole radius, 0 to 16", 0, 16, holeradius ); + + //Wall thickness + wallthickness = getint( "Enter wall thickness, 0 to 16", 0, 16, wallthickness ); + + //Obsidian Pillars + holepillar = getint( "Number of Obsidian Pillars in hole, 0 to 255", 0, 255, holepillar ); + wallpillar = getint( "Number of Obsidian Pillars in wall, 0 to 255", 0, 255, wallpillar ); + + //Open Hell? + exposehell=getyesno("Expose the pit to hell (no walls in hell)?",exposehell); + + //Stop when magma sea is hit? + stopatmagma=getyesno("Stop at magma sea?",stopatmagma); + exposemagma=getyesno("Expose magma sea (no walls in magma)?",exposemagma); + + //Fill? + fillmagma=getyesno("Fill with magma?",fillmagma); + if (fillmagma) aquify=fillwater=0; + fillwater=getyesno("Fill with water?",fillwater); + //aquify=getyesno("Aquifer?",aquify); + + + /////////////////////////////////////////////////////////////////////////////////////////////// + //Print settings. + //If a settings struct existed, this could be in a routine + printf("Using Settings:\n"); + printf("Pit Type......: %d = %s\n", pittype, pitTypeDesc[pittype]); + printf("Depth.........: %d\n", pitdepth); + printf("Hole Radius...: %d\n", holeradius); + printf("Wall Thickness: %d\n", wallthickness); + printf("Pillars, Hole.: %d\n", holepillar); + printf("Pillars, Wall.: %d\n", wallpillar); + printf("Expose Hell...: %c\n", (exposehell?'Y':'N') ); + printf("Stop at Magma.: %c\n", (stopatmagma?'Y':'N') ); + printf("Expose Magma..: %c\n", (exposemagma?'Y':'N') ); + printf("Magma Fill....: %c\n", (fillmagma?'Y':'N') ); + printf("Water Fill....: %c\n", (fillwater?'Y':'N') ); + printf("Aquifer.......: %c\n", (aquify?'Y':'N') ); + + accept = getyesno("Accept these settings?",1); + } + int64_t n; + uint32_t x_max,y_max,z_max; - //Note: - //At this point, the pattern holds: - //0 for all tiles which will be ignored. - //1 for all tiles set to empty pit space. - //2 for all normal walls. - //3 for the straight obsidian top-to-bottom wall. - //4 is randomized between wall or floor (!not implemented!) - printf("\nPattern:\n"); - const char patternkey[] = ".cW!?567890123"; + //Pattern to dig + unsigned char pattern[16][16]; - //Print the pattern - for(y=0;y<16;++y){ - for(x=0;x<16;++x){ - cout << patternkey[ pattern[x][y] ]; - } - cout << endl; - } - cout << endl; - regen = !getyesno("Acceptable Pattern?",1); - } + for (int regen=1;regen; ) + { + regen=0; + + memset(pattern,0,sizeof(pattern)); + + //Calculate a randomized circle. + //These values found through experimentation. + int x=0, y=0, n=0; + + //Two concentric irregular circles + //Outer circle, solid. + if ( wallthickness ) + { + drawcircle(holeradius+wallthickness, pattern, 2); + } + //Inner circle, hole. + if ( holeradius ) + { + drawcircle(holeradius, pattern, 1); + } + + + //Post-process to be certain the wall totally encloses hole. + if (wallthickness) + { + for (y=0;y<16;++y) + { + for (x=0;x<16;++x) + { + if ( 1==pattern[x][y] ) + { + //No hole at edges. + if ( x<1 || x>14 || y<1 || y>14 ) + { + pattern[x][y]=2; + } + } + else if ( 0==pattern[x][y] ) + { + //check neighbors + checkneighbors( pattern , x,y, 1, 2); + } + } + } + } + + //Makes sure that somewhere random gets a vertical pillar of rock which is safe + //to dig stairs down, to permit access to anywhere within the pit from the top. + for (n=holepillar; n ; --n) + { + settileat( pattern , 1 , 3 , rand()&255 ); + } + for (n=wallpillar; n ; --n) + { + settileat( pattern , 2 , 3 , rand()&255 ); + } + + //Note: + //At this point, the pattern holds: + //0 for all tiles which will be ignored. + //1 for all tiles set to empty pit space. + //2 for all normal walls. + //3 for the straight obsidian top-to-bottom wall. + //4 is randomized between wall or floor (!not implemented!) + + printf("\nPattern:\n"); + const char patternkey[] = ".cW!?567890123"; + + //Print the pattern + for (y=0;y<16;++y) + { + for (x=0;x<16;++x) + { + cout << patternkey[ pattern[x][y] ]; + } + cout << endl; + } + cout << endl; + + regen = !getyesno("Acceptable Pattern?",1); + } - //Post-process settings to fix problems here - if(pitdepth<1) pitdepth=INT_MAX; + //Post-process settings to fix problems here + if (pitdepth<1) + { + pitdepth=INT_MAX; + } - /////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////// cerr << "Loading memory map..." << endl; - //Connect to DF! + //Connect to DF! DFHack::ContextManager DFMgr("Memory.xml"); DFHack::Context *DF = DFMgr.getSingleContext(); - //Init + //Init cerr << "Attaching to DF..." << endl; - try + try { DF->Attach(); } @@ -508,11 +612,11 @@ int main (void) cin.ignore(); #endif return 1; - } - + } + // init the map - DFHack::Maps *Mapz = DF->getMaps(); - if(!Mapz->Start()) + DFHack::Maps *Mapz = DF->getMaps(); + if (!Mapz->Start()) { cerr << "Can't init map. Exiting." << endl; #ifndef LINUX_BUILD @@ -520,592 +624,656 @@ int main (void) #endif return 1; } - + Mapz->getSize(x_max,y_max,z_max); - //Get cursor + //Get cursor int32_t cursorX, cursorY, cursorZ; DFHack::Position *Pos = DF->getPosition(); Pos->getCursorCoords(cursorX,cursorY,cursorZ); - if(-30000==cursorX){ - cout << "No cursor position found. Exiting." << endl; + if (-30000==cursorX) + { + cout << "No cursor position found. Exiting." << endl; #ifndef LINUX_BUILD cin.ignore(); #endif return 1; - } + } - //Block coordinates + //Block coordinates int32_t bx=cursorX/16, by=cursorY/16, bz=cursorZ; - //Tile coordinates within block + //Tile coordinates within block int32_t tx=cursorX%16, ty=cursorY%16, tz=cursorZ; - - /* - //Access the DF interface to pause the game. - //Copied from the reveal tool. + /* + //Access the DF interface to pause the game. + //Copied from the reveal tool. DFHack::Gui *Gui =DF->getGui(); cout << "Pausing..." << endl; Gui->SetPauseState(true); DF->Resume(); waitmsec(1000); DF->Suspend(); - */ - + */ - //Verify that every z-level at this location exists. - for(int32_t Z = 0; Z<= bz ;Z++){ - if( ! Mapz->isValidBlock(bx,by,Z) ){ - cout << "This block does't exist! Exiting." << endl; - #ifndef LINUX_BUILD - cin.ignore(); - #endif - return 1; - } - } + //Verify that every z-level at this location exists. + for (int32_t Z = 0; Z<= bz ;Z++) + { + if ( ! Mapz->isValidBlock(bx,by,Z) ) + { + cout << "This block does't exist! Exiting." << endl; + #ifndef LINUX_BUILD + cin.ignore(); + #endif + return 1; + } + } - //Get all the map features. + //Get all the map features. vector global_features; - if(!Mapz->ReadGlobalFeatures(global_features)){ - cout << "Couldn't load global features! Probably a version problem." << endl; - #ifndef LINUX_BUILD - cin.ignore(); - #endif - return 1; - } + if (!Mapz->ReadGlobalFeatures(global_features)) + { + cout << "Couldn't load global features! Probably a version problem." << endl; + #ifndef LINUX_BUILD + cin.ignore(); + #endif + return 1; + } + std::map > local_features; - if(!Mapz->ReadLocalFeatures(local_features)){ - cout << "Couldn't load local features! Probably a version problem." << endl; - #ifndef LINUX_BUILD - cin.ignore(); - #endif - return 1; - } - - //Get info on current tile, to determine how to generate the pit - mapblock40d topblock; - Mapz->ReadBlock40d( bx, by, bz , &topblock ); - //Related block info - planecoord pc; - pc.dim.x=bx; pc.dim.y=by; - mapblock40d block; - const TileRow * tp; - t_designation * d; - - ////////////////////////////////////// - //From top to bottom, dig this thing. - ////////////////////////////////////// - - //Top level, cap. - //Might make this an option in the future - //For now, no wall means no cap. - if(wallthickness){ - Mapz->ReadBlock40d( bx, by, bz , &block ); - for(uint32_t x=0;x<16;++x){ - for(uint32_t y=0;y<16;++y){ - if( (pattern[x][y]>1) || (roof && pattern[x][y]) ){ - tp = getTileTypeP(block.tiletypes[x][y]); - d = &block.designation[x][y]; - //Only modify this level if it's 'empty' - if( EMPTY != tp->c && RAMP_TOP != tp->c && STAIR_DOWN != tp->c && DFHack::TILE_STREAM_TOP != tp->s) continue; - - //Need a floor for empty space. - if(reveal) d->bits.hidden = 0; //topblock.designation[x][y].bits.hidden; - //Always clear the dig designation. - d->bits.dig=designation_no; - //unlock fluids, so they fall down the pit. - d->bits.flow_forbid = d->bits.liquid_static=0; - block.blockflags.bits.liquid_1 = block.blockflags.bits.liquid_2 = 1; - //Remove aquifer, to prevent bugginess - d->bits.water_table=0; - //Set the tile. - block.tiletypes[x][y] = cap + rand()%4; - } - } - } - //Write the block. - Mapz->WriteBlockFlags(bx,by,bz, block.blockflags ); - Mapz->WriteDesignations(bx,by,bz, &block.designation ); - Mapz->WriteTileTypes(bx,by,bz, &block.tiletypes ); - Mapz->WriteDirtyBit(bx,by,bz,1); - } - - /////////////////////////////////////////////////////////////////////////////////////////////// - //All levels in between. - int done=0; - uint32_t t,v; - int32_t z = bz-1; - int32_t bottom = max(0,bz-pitdepth-1); - assert( bottom>=0 && bottom<=bz ); - for( ; !done && z>=bottom ; --z){ - int watercount=0; - int magmacount=0; - int moltencount=0; - int rockcount=0; - int veincount=0; - int emptycount=0; - int hellcount=0; - int templecount=0; - int adamcount=0; - int featcount=0; - int tpat; - - cout << z << endl; - assert( Mapz->isValidBlock(bx,by,z) ); - if(!Mapz->ReadBlock40d( bx, by, z , &block )){ - cout << "Bad block! " << bx << "," << by << "," << z << endl; - } - - //Pre-process this z-level, to get some tile statistics. - for(int32_t x=0;x<16;++x) - { - for(int32_t y=0;y<16;++y) - { - t=0; - tp = getTileTypeP(block.tiletypes[x][y]); - d = &block.designation[x][y]; - tpat=pattern[x][y]; - - //Tile type material categories - switch( tp->m ){ - case AIR: - ++emptycount; - break; - case MAGMA: - ++moltencount; - break; - case VEIN: - ++veincount; - break; - case FEATSTONE: - case HFS: - case OBSIDIAN: - //basicly, ignored. - break; - default: - if( EMPTY == tp->c || RAMP_TOP == tp->c || STAIR_DOWN == tp->c ){ - ++emptycount; - }else{ - ++rockcount; - } - break; - } - - //Magma and water - if( d->bits.flow_size ){ - if(d->bits.liquid_type){ - ++magmacount; - }else{ - ++watercount; - } - } - - - //Check for Features - if( block.local_feature > -1 || block.global_feature > -1 ){ - //Count tiles which actually are in the feature. - //It is possible for a block to have a feature, but no tiles to be feature. - if( d->bits.feature_global || d->bits.feature_local ){ - //All features - ++featcount; - - if( d->bits.feature_global && d->bits.feature_local ){ - cout << "warn:tile is global and local at same time!" << endl; - } - - n=0; - if( block.global_feature > -1 && d->bits.feature_global ){ - n=global_features[block.global_feature].type; - switch( n ){ - case feature_Other: - //no count - break; - case feature_Adamantine_Tube: - ++adamcount; - break; - case feature_Underworld: - ++hellcount; - break; - case feature_Hell_Temple: - ++templecount; - break; - default: - //something here. for debugging, it may be interesting to know. - if(n) cout << '(' << n << ')'; - } - } - - n=0; - if( block.local_feature > -1 && d->bits.feature_local ){ - n=local_features[pc][block.local_feature]->type; - switch( n ){ - case feature_Other: - //no count - break; - case feature_Adamantine_Tube: - ++adamcount; - break; - case feature_Underworld: - ++hellcount; - break; - case feature_Hell_Temple: - ++templecount; - break; - default: - //something here. for debugging, it may be interesting to know. - if(n) cout << '[' << n << ']'; - } - } - } - } - } - } - - - //If stopping at magma, and no no non-feature stone in this layer, and magma found, then we're either at - //or below the magma sea / molten rock. - if( stopatmagma && (moltencount || magmacount) && (!exposemagma || !rockcount) ){ - //If not exposing magma, quit at the first sign of magma. - //If exposing magma, quite once magma is exposed. - done=-1; - } - - - ///////////////////////////////////////////////////////////////////////////////////////////////// - //Some checks, based on settings and stats collected - //First check, are we at illegal depth? - if( !done && hellcount && stopatmagma ){ - //Panic! - done=-1; - tpat=0; - cout << "error: illegal breach of hell!" << endl; - } - - - ///////////////////////////////////////////////////////////////////////////////////////////////// - //Actually process the current z-level. - //These loops do the work. - for(int32_t x=0;!done && x<16;++x){ - for(int32_t y=0;!done && y<16;++y){ - t=0; - tp = getTileTypeP(block.tiletypes[x][y]); - d = &block.designation[x][y]; - tpat=pattern[x][y]; - - //Up front, remove aquifer, to prevent bugginess - //It may be added back if aquify is set. - d->bits.water_table=0; - - - //Change behaviour based on settings and stats from this z-level - - //In hell? - if( tpat && tpat!=3 && isfeature(global_features, local_features,block,pc,x,y,feature_Underworld ) ){ - if( exposehell ){ - tpat=0; - } - } - - //Expose magma? - if( tpat && tpat!=3 && exposemagma ){ - //Leave certain tiles unchanged. - switch( tp->m ){ - case HFS: - case FEATSTONE: - case MAGMA: - tpat=0; - default: - break; - } - //Adamantine may be left unchanged... - if( isfeature(global_features, local_features,block,pc,x,y,feature_Adamantine_Tube ) ){ - tpat=0; - } - //Leave magma sea unchanged. - if( d->bits.flow_size && d->bits.liquid_type){ - tpat=0; - } - } - - - //For all situations... - //Special modification for walls, always for adamantine. - if( isfeature(global_features, local_features,block,pc,x,y,feature_Adamantine_Tube ) ){ - if( 2==pattern[x][y] || 3==pattern[x][y] ){ - tpat=2; - } - } - - - //Border or space? - switch(tpat){ - case 0: - continue; - break; - case 1: - //Empty Space - t=32; - //d->bits.light = topblock.designation[x][y].bits.light; - //d->bits.skyview = topblock.designation[x][y].bits.skyview; - //d->bits.subterranean = topblock.designation[x][y].bits.subterranean; - - //Erase special markers? - //d->bits.feature_global = d->bits.feature_local = 0; - - //Water? Magma? - if(fillmagma || fillwater){ - d->bits.flow_size=7; - d->bits.liquid_character = liquid_fresh; - if(fillmagma){ - d->bits.liquid_type=liquid_magma; - }else{ - d->bits.liquid_type=liquid_water; - } - }else{ - //Otherwise, remove all liquids. - d->bits.flow_size=0; - d->bits.liquid_character = liquid_fresh; - d->bits.liquid_type = liquid_water; - } - - break; - case 2: - //Wall. - //First guess based on current material - switch( tp->m ){ - case OBSIDIAN: - t=wmagma; - break; - case MAGMA: - t=wmolten; - break; - case HFS: - //t=whell; - break; - case VEIN: - t=440; //Solid vein block - break; - case FEATSTONE: - t=335; //Solid feature stone block - break; - default: - t=wcave; - } - - - //Adamantine (a local feature) trumps veins. - { - //Local Feature? - if( block.local_feature > -1 ){ - switch( n=local_features[pc][block.local_feature]->type ){ - case feature_Underworld: - case feature_Hell_Temple: - //Only adopt these if there is no global feature present - if( block.global_feature >-1 ){ - break; - } - case feature_Adamantine_Tube: - //Always for adamantine, sometimes for others - //Whatever the feature is made of. "featstone wall" - d->bits.feature_global = 0; - d->bits.feature_local = 1; - t=335; - break; - } - } - //Global Feature? - else if(block.global_feature > -1 && !d->bits.feature_local ){ - switch( n=global_features[block.global_feature].type ){ - case feature_Adamantine_Tube: - case feature_Underworld: - case feature_Hell_Temple: - //Whatever the feature is made of. "featstone wall" - d->bits.feature_global = 1; - t=335; - break; - } - } - } - - //Erase any liquids, as they cause problems. - d->bits.flow_size=0; - d->bits.liquid_character = liquid_fresh; - d->bits.liquid_type=liquid_water; - - //Placing an aquifer? - //(bugged, these aquifers don't generate water!) - if( aquify ){ - //Only normal stone types can be aquified - if( tp->m!=MAGMA && tp->m!=FEATSTONE && tp->m!=HFS ){ - //Only place next to the hole. - //If no hole, place in middle. - if( checkneighbors(pattern,x,y,1) || (7==x && 7==y) ){ - d->bits.water_table = 1; - //t=265; //soil wall - } - } - } - - break; - - case 3: - ////No obsidian walls on bottom of map! - //if(z<1 && (d->bits.feature_global || d->bits.feature_local) ) { - // t=335; - //} - - //Special wall, always sets to obsidian, to give a stairway - t=331; - - //Erase special markers - d->bits.feature_global = d->bits.feature_local = 0; - - //Erase any liquids, as they cause problems. - d->bits.flow_size=0; - d->bits.liquid_character = liquid_fresh; - d->bits.liquid_type=liquid_water; - break; - default: - cout << ".error,bad pattern."; - } - - //For all tiles. - if(reveal) d->bits.hidden = 0; //topblock.designation[x][y].bits.hidden; - //Always clear the dig designation. - d->bits.dig=designation_no; - //Make it underground, because it is capped - d->bits.subterranean=1; - d->bits.light=0; - d->bits.skyview=0; - //unlock fluids, so they fall down the pit. - d->bits.flow_forbid = d->bits.liquid_static=0; - block.blockflags.bits.liquid_1 = block.blockflags.bits.liquid_2 = 1; - //Set the tile. - block.tiletypes[x][y] = t; - - } - } - - //Write the block. - Mapz->WriteBlockFlags(bx,by,z, block.blockflags ); - Mapz->WriteDesignations(bx,by,z, &block.designation ); - Mapz->WriteTileTypes(bx,by,z, &block.tiletypes ); - Mapz->WriteDirtyBit(bx,by,z,1); - - } - - //Re-process the last z-level handled above. - z++; - assert( z>=0 ); - - - /////////////////////////////////////////////////////////////////////////////////////////////// - //The bottom level is special. - if(-1){ - if(!Mapz->ReadBlock40d( bx, by, z , &block )){ - cout << "Bad block! " << bx << "," << by << "," << z << endl; - } - for(uint32_t x=0;x<16;++x){ - for(uint32_t y=0;y<16;++y){ - t=floor; - v=floorvar; - tp = getTileTypeP(block.tiletypes[x][y]); - d = &block.designation[x][y]; - - if( exposehell ){ - //Leave hell tiles unchanged when exposing hell. - if( isfeature(global_features,local_features,block,pc,x,y,feature_Underworld) ){ - continue; - } - } - - //Does expose magma need anything at this level? - if( exposemagma && stopatmagma ){ - continue; - } - - switch(pattern[x][y]){ - case 0: - continue; - break; - case 1: - //Empty becomes floor. - - //Base floor type on the z-level first, features, then tile type. - if(!z){ - //Bottom of map, use the floor specified, always. - break; - } - - ////Only place floor where ground is already solid when exposing - //if( EMPTY == tp->c || RAMP_TOP == tp->c || STAIR_DOWN == tp->c ){ - // continue; - //} - - if( d->bits.feature_global || d->bits.feature_global ){ - //Feature Floor! - t=344; - break; - } - - //Tile material check. - switch( tp->m ){ - case OBSIDIAN: - t=340; - v=3; - break; - case MAGMA: - v=0; - t=264; //magma flow - break; - case HFS: - //should only happen at bottom of map - break; - case VEIN: - t=441; //vein floor - v=3; - break; - case FEATSTONE: - t=344; - v=3; - break; - } - - break; - case 2: - case 3: - //Walls already drawn. - //Ignore. - continue; - break; - } - - //For all tiles. - if(reveal) d->bits.hidden = 0; //topblock.designation[x][y].bits.hidden; - //Always clear the dig designation. - d->bits.dig=designation_no; - //unlock fluids - d->bits.flow_forbid = d->bits.liquid_static=0; - block.blockflags.bits.liquid_1 = block.blockflags.bits.liquid_2 = 1; - - //Set the tile. - block.tiletypes[x][y] = t + ( v ? rand()&v : 0 ) ; - - } - } - //Write the block. - Mapz->WriteBlockFlags(bx,by,z, block.blockflags ); - Mapz->WriteDesignations(bx,by,z, &block.designation ); - Mapz->WriteTileTypes(bx,by,z, &block.tiletypes ); - Mapz->WriteDirtyBit(bx,by,z,1); - } + if (!Mapz->ReadLocalFeatures(local_features)) + { + cout << "Couldn't load local features! Probably a version problem." << endl; + #ifndef LINUX_BUILD + cin.ignore(); + #endif + return 1; + } + //Get info on current tile, to determine how to generate the pit + mapblock40d topblock; + Mapz->ReadBlock40d( bx, by, bz , &topblock ); + //Related block info + planecoord pc; + pc.dim.x=bx; + pc.dim.y=by; + mapblock40d block; + const TileRow * tp; + t_designation * d; + + ////////////////////////////////////// + //From top to bottom, dig this thing. + ////////////////////////////////////// + + //Top level, cap. + //Might make this an option in the future + //For now, no wall means no cap. + if (wallthickness) + { + Mapz->ReadBlock40d( bx, by, bz , &block ); + for (uint32_t x=0;x<16;++x) + { + for (uint32_t y=0;y<16;++y) + { + if ( (pattern[x][y]>1) || (roof && pattern[x][y]) ) + { + tp = getTileTypeP(block.tiletypes[x][y]); + d = &block.designation[x][y]; + //Only modify this level if it's 'empty' + if ( EMPTY != tp->c && RAMP_TOP != tp->c && STAIR_DOWN != tp->c && DFHack::TILE_STREAM_TOP != tp->s) + { + continue; + } + + //Need a floor for empty space. + if (reveal) + { + d->bits.hidden = 0; //topblock.designation[x][y].bits.hidden; + } + //Always clear the dig designation. + d->bits.dig = designation_no; + //unlock fluids, so they fall down the pit. + d->bits.flow_forbid = d->bits.liquid_static=0; + block.blockflags.bits.liquid_1 = block.blockflags.bits.liquid_2 = 1; + //Remove aquifer, to prevent bugginess + d->bits.water_table=0; + //Set the tile. + block.tiletypes[x][y] = cap + rand()%4; + } + } + } + //Write the block. + Mapz->WriteBlockFlags(bx,by,bz, block.blockflags ); + Mapz->WriteDesignations(bx,by,bz, &block.designation ); + Mapz->WriteTileTypes(bx,by,bz, &block.tiletypes ); + Mapz->WriteDirtyBit(bx,by,bz,1); + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + //All levels in between. + int done=0; + uint32_t t,v; + int32_t z = bz-1; + int32_t bottom = max(0,bz-pitdepth-1); + assert( bottom>=0 && bottom<=bz ); + for ( ; !done && z>=bottom ; --z) + { + int watercount=0; + int magmacount=0; + int moltencount=0; + int rockcount=0; + int veincount=0; + int emptycount=0; + int hellcount=0; + int templecount=0; + int adamcount=0; + int featcount=0; + int tpat; + + cout << z << endl; + assert( Mapz->isValidBlock(bx,by,z) ); + if (!Mapz->ReadBlock40d( bx, by, z , &block )) + { + cout << "Bad block! " << bx << "," << by << "," << z << endl; + } + + //Pre-process this z-level, to get some tile statistics. + for (int32_t x=0;x<16;++x) + { + for (int32_t y=0;y<16;++y) + { + t=0; + tp = getTileTypeP(block.tiletypes[x][y]); + d = &block.designation[x][y]; + tpat=pattern[x][y]; + + //Tile type material categories + switch ( tp->m ) + { + case AIR: + ++emptycount; + break; + case MAGMA: + ++moltencount; + break; + case VEIN: + ++veincount; + break; + case FEATSTONE: + case HFS: + case OBSIDIAN: + //basicly, ignored. + break; + default: + if ( EMPTY == tp->c || RAMP_TOP == tp->c || STAIR_DOWN == tp->c ) + { + ++emptycount; + } + else + { + ++rockcount; + } + break; + } + + //Magma and water + if ( d->bits.flow_size ) + { + if (d->bits.liquid_type) + { + ++magmacount; + } + else + { + ++watercount; + } + } + + + //Check for Features + if ( block.local_feature > -1 || block.global_feature > -1 ) + { + //Count tiles which actually are in the feature. + //It is possible for a block to have a feature, but no tiles to be feature. + if ( d->bits.feature_global || d->bits.feature_local ) + { + //All features + ++featcount; + + if ( d->bits.feature_global && d->bits.feature_local ) + { + cout << "warn:tile is global and local at same time!" << endl; + } + + n=0; + if ( block.global_feature > -1 && d->bits.feature_global ) + { + n=global_features[block.global_feature].type; + switch ( n ) + { + case feature_Other: + //no count + break; + case feature_Adamantine_Tube: + ++adamcount; + break; + case feature_Underworld: + ++hellcount; + break; + case feature_Hell_Temple: + ++templecount; + break; + default: + //something here. for debugging, it may be interesting to know. + if (n) cout << '(' << n << ')'; + } + } + + n=0; + if ( block.local_feature > -1 && d->bits.feature_local ) + { + n=local_features[pc][block.local_feature]->type; + switch ( n ) + { + case feature_Other: + //no count + break; + case feature_Adamantine_Tube: + ++adamcount; + break; + case feature_Underworld: + ++hellcount; + break; + case feature_Hell_Temple: + ++templecount; + break; + default: + //something here. for debugging, it may be interesting to know. + if (n) cout << '[' << n << ']'; + } + } + } + } + } + } + + + //If stopping at magma, and no no non-feature stone in this layer, and magma found, then we're either at + //or below the magma sea / molten rock. + if ( stopatmagma && (moltencount || magmacount) && (!exposemagma || !rockcount) ) + { + //If not exposing magma, quit at the first sign of magma. + //If exposing magma, quite once magma is exposed. + done=-1; + } + + + ///////////////////////////////////////////////////////////////////////////////////////////////// + //Some checks, based on settings and stats collected + //First check, are we at illegal depth? + if ( !done && hellcount && stopatmagma ) + { + //Panic! + done=-1; + tpat=0; + cout << "error: illegal breach of hell!" << endl; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////// + //Actually process the current z-level. + //These loops do the work. + for (int32_t x=0;!done && x<16;++x) + { + for (int32_t y=0;!done && y<16;++y) + { + t=0; + tp = getTileTypeP(block.tiletypes[x][y]); + d = &block.designation[x][y]; + tpat=pattern[x][y]; + + //Up front, remove aquifer, to prevent bugginess + //It may be added back if aquify is set. + d->bits.water_table=0; + + //Change behaviour based on settings and stats from this z-level + + //In hell? + if ( tpat && tpat!=3 && isfeature(global_features, local_features,block,pc,x,y,feature_Underworld ) ) + { + if ( exposehell ) + { + tpat=0; + } + } + + //Expose magma? + if ( tpat && tpat!=3 && exposemagma ) + { + //Leave certain tiles unchanged. + switch ( tp->m ) + { + case HFS: + case FEATSTONE: + case MAGMA: + tpat=0; + default: + break; + } + //Adamantine may be left unchanged... + if ( isfeature(global_features, local_features,block,pc,x,y,feature_Adamantine_Tube ) ) + { + tpat=0; + } + //Leave magma sea unchanged. + if ( d->bits.flow_size && d->bits.liquid_type) + { + tpat=0; + } + } + + + //For all situations... + //Special modification for walls, always for adamantine. + if ( isfeature(global_features, local_features,block,pc,x,y,feature_Adamantine_Tube ) ) + { + if ( 2==pattern[x][y] || 3==pattern[x][y] ) + { + tpat=2; + } + } + + + //Border or space? + switch (tpat) + { + case 0: + continue; + break; + case 1: + //Empty Space + t=32; + //d->bits.light = topblock.designation[x][y].bits.light; + //d->bits.skyview = topblock.designation[x][y].bits.skyview; + //d->bits.subterranean = topblock.designation[x][y].bits.subterranean; + + //Erase special markers? + //d->bits.feature_global = d->bits.feature_local = 0; + + //Water? Magma? + if (fillmagma || fillwater) + { + d->bits.flow_size=7; + d->bits.liquid_character = liquid_fresh; + if (fillmagma) + { + d->bits.liquid_type=liquid_magma; + } + else + { + d->bits.liquid_type=liquid_water; + } + } + else + { + //Otherwise, remove all liquids. + d->bits.flow_size=0; + d->bits.liquid_character = liquid_fresh; + d->bits.liquid_type = liquid_water; + } + + break; + case 2: + //Wall. + //First guess based on current material + switch ( tp->m ) + { + case OBSIDIAN: + t=wmagma; + break; + case MAGMA: + t=wmolten; + break; + case HFS: + //t=whell; + break; + case VEIN: + t=440; //Solid vein block + break; + case FEATSTONE: + t=335; //Solid feature stone block + break; + default: + t=wcave; + } + //Adamantine (a local feature) trumps veins. + { + //Local Feature? + if ( block.local_feature > -1 ) + { + switch ( n=local_features[pc][block.local_feature]->type ) + { + case feature_Underworld: + case feature_Hell_Temple: + //Only adopt these if there is no global feature present + if ( block.global_feature >-1 ) + { + break; + } + case feature_Adamantine_Tube: + //Always for adamantine, sometimes for others + //Whatever the feature is made of. "featstone wall" + d->bits.feature_global = 0; + d->bits.feature_local = 1; + t=335; + break; + } + } + //Global Feature? + else if (block.global_feature > -1 && !d->bits.feature_local ) + { + switch ( n=global_features[block.global_feature].type ) + { + case feature_Adamantine_Tube: + case feature_Underworld: + case feature_Hell_Temple: + //Whatever the feature is made of. "featstone wall" + d->bits.feature_global = 1; + t=335; + break; + } + } + } + + //Erase any liquids, as they cause problems. + d->bits.flow_size=0; + d->bits.liquid_character = liquid_fresh; + d->bits.liquid_type=liquid_water; + + //Placing an aquifer? + //(bugged, these aquifers don't generate water!) + if ( aquify ) + { + //Only normal stone types can be aquified + if ( tp->m!=MAGMA && tp->m!=FEATSTONE && tp->m!=HFS ) + { + //Only place next to the hole. + //If no hole, place in middle. + if ( checkneighbors(pattern,x,y,1) || (7==x && 7==y) ) + { + d->bits.water_table = 1; + //t=265; //soil wall + } + } + } + break; + case 3: + ////No obsidian walls on bottom of map! + //if(z<1 && (d->bits.feature_global || d->bits.feature_local) ) { + // t=335; + //} + + //Special wall, always sets to obsidian, to give a stairway + t=331; + + //Erase special markers + d->bits.feature_global = d->bits.feature_local = 0; + + //Erase any liquids, as they cause problems. + d->bits.flow_size=0; + d->bits.liquid_character = liquid_fresh; + d->bits.liquid_type=liquid_water; + break; + default: + cout << ".error,bad pattern."; + } + + //For all tiles. + if (reveal) + { + d->bits.hidden = 0; //topblock.designation[x][y].bits.hidden; + } + //Always clear the dig designation. + d->bits.dig=designation_no; + //Make it underground, because it is capped + d->bits.subterranean=1; + d->bits.light=0; + d->bits.skyview=0; + //unlock fluids, so they fall down the pit. + d->bits.flow_forbid = d->bits.liquid_static=0; + block.blockflags.bits.liquid_1 = block.blockflags.bits.liquid_2 = 1; + //Set the tile. + block.tiletypes[x][y] = t; + + } + } + + //Write the block. + Mapz->WriteBlockFlags(bx,by,z, block.blockflags ); + Mapz->WriteDesignations(bx,by,z, &block.designation ); + Mapz->WriteTileTypes(bx,by,z, &block.tiletypes ); + Mapz->WriteDirtyBit(bx,by,z,1); + + } + + //Re-process the last z-level handled above. + z++; + assert( z>=0 ); + + + /////////////////////////////////////////////////////////////////////////////////////////////// + //The bottom level is special. + if (-1) + { + if (!Mapz->ReadBlock40d( bx, by, z , &block )) + { + cout << "Bad block! " << bx << "," << by << "," << z << endl; + } + for (uint32_t x=0;x<16;++x) + { + for (uint32_t y=0;y<16;++y) + { + t=floor; + v=floorvar; + tp = getTileTypeP(block.tiletypes[x][y]); + d = &block.designation[x][y]; + + if ( exposehell ) + { + //Leave hell tiles unchanged when exposing hell. + if ( isfeature(global_features,local_features,block,pc,x,y,feature_Underworld) ) + { + continue; + } + } + + //Does expose magma need anything at this level? + if ( exposemagma && stopatmagma ) + { + continue; + } + + switch (pattern[x][y]) + { + case 0: + continue; + break; + case 1: + //Empty becomes floor. + + //Base floor type on the z-level first, features, then tile type. + if (!z) { + //Bottom of map, use the floor specified, always. + break; + } + + ////Only place floor where ground is already solid when exposing + //if( EMPTY == tp->c || RAMP_TOP == tp->c || STAIR_DOWN == tp->c ){ + // continue; + //} + + if ( d->bits.feature_global || d->bits.feature_global ) { + //Feature Floor! + t=344; + break; + } + + //Tile material check. + switch ( tp->m ) + { + case OBSIDIAN: + t=340; + v=3; + break; + case MAGMA: + v=0; + t=264; //magma flow + break; + case HFS: + //should only happen at bottom of map + break; + case VEIN: + t=441; //vein floor + v=3; + break; + case FEATSTONE: + t=344; + v=3; + break; + } + + break; + case 2: + case 3: + //Walls already drawn. + //Ignore. + continue; + break; + } + + //For all tiles. + if (reveal) d->bits.hidden = 0; //topblock.designation[x][y].bits.hidden; + //Always clear the dig designation. + d->bits.dig=designation_no; + //unlock fluids + d->bits.flow_forbid = d->bits.liquid_static=0; + block.blockflags.bits.liquid_1 = block.blockflags.bits.liquid_2 = 1; + + //Set the tile. + block.tiletypes[x][y] = t + ( v ? rand()&v : 0 ); + } + } + //Write the block. + Mapz->WriteBlockFlags(bx,by,z, block.blockflags ); + Mapz->WriteDesignations(bx,by,z, &block.designation ); + Mapz->WriteTileTypes(bx,by,z, &block.tiletypes ); + Mapz->WriteDirtyBit(bx,by,z,1); + } DF->Detach(); - #ifndef LINUX_BUILD +#ifndef LINUX_BUILD cout << "Done. Press any key to continue" << endl; cin.ignore(); - #endif +#endif return 0; } diff --git a/tools/playground/printtiletypes.cpp b/tools/playground/printtiletypes.cpp index 1016694c9..b9e9d75ce 100644 --- a/tools/playground/printtiletypes.cpp +++ b/tools/playground/printtiletypes.cpp @@ -17,77 +17,84 @@ using namespace DFHack; int main (int argc, char **argv) { - FILE *f=stdout; - const int Columns = 7; - const char * Headings[Columns] = {"TileTypeID","Class","Material","V","Special","Direction","Description"}; - size_t Size[ Columns ] = {}; - int i; + FILE *f=stdout; + const int Columns = 7; + const char * Headings[Columns] = {"TileTypeID","Class","Material","V","Special","Direction","Description"}; + size_t Size[ Columns ] = {}; + int i; - //First, figure out column widths. - for(i=0;i(Size[1],strlen(TileClassString[i])); - fprintf(f,"%4i ; %s\n", i, TileClassString[i] ,0 ); - } + //Classes + fprintf(f,"\nTile Type Classes:\n"); + for(i=0;i(Size[1],strlen(TileClassString[i])); + fprintf(f,"%4i ; %s\n", i, TileClassString[i] ,0 ); + } - //Materials - fprintf(f,"\nTile Type Materials:\n"); - for(i=0;i(Size[2],strlen(TileMaterialString[i])); - fprintf(f,"%4i ; %s\n", i, TileMaterialString[i] ,0 ); - } + //Materials + fprintf(f,"\nTile Type Materials:\n"); + for(i=0;i(Size[2],strlen(TileMaterialString[i])); + fprintf(f,"%4i ; %s\n", i, TileMaterialString[i] ,0 ); + } - //Specials - fprintf(f,"\nTile Type Specials:\n"); - for(i=0;i(Size[4],strlen(TileSpecialString[i])); - fprintf(f,"%4i ; %s\n", i, TileSpecialString[i] ,0 ); - } + //Specials + fprintf(f,"\nTile Type Specials:\n"); + for(i=0;i(Size[4],strlen(TileSpecialString[i])); + fprintf(f,"%4i ; %s\n", i, TileSpecialString[i] ,0 ); + } - /* - Not needed for now - - //Direction is tricky - for(i=0;i -#include -#include -#include -#include -#include -#include - -#define DFHACK_WANT_MISCUTILS 1 -#define DFHACK_WANT_TILETYPES 1 -#include - -using namespace DFHack; -int main (int numargs, const char ** args) -{ - DFHack::ContextManager DFMgr("Memory.xml"); - DFHack::Context *DF = DFMgr.getSingleContext(); - -BEGIN_PROBE: - 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::Maps *Maps = DF->getMaps(); - DFHack::Process * p = DF->getProcess(); - 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(); - +// Just show some position data + +#include +#include +#include +#include +#include +#include +#include + +#define DFHACK_WANT_MISCUTILS 1 +#define DFHACK_WANT_TILETYPES 1 +#include + +using namespace DFHack; +int main (int numargs, const char ** args) +{ + DFHack::ContextManager DFMgr("Memory.xml"); + DFHack::Context *DF = DFMgr.getSingleContext(); + + BEGIN_PROBE: + 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::Maps *Maps = DF->getMaps(); + DFHack::Process * p = DF->getProcess(); + 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(); + vector global_features; std::map > local_features; - Maps->ReadLocalFeatures(local_features); - Maps->ReadGlobalFeatures(global_features); - - int32_t cursorX, cursorY, cursorZ; - Pos->getCursorCoords(cursorX,cursorY,cursorZ); - if(cursorX != -30000) - { - uint32_t blockX = cursorX / 16; - uint32_t tileX = cursorX % 16; - uint32_t blockY = cursorY / 16; - uint32_t tileY = cursorY % 16; - t_temperatures tmpb1, tmpb2; - mapblock40d block; - if(Maps->ReadBlock40d(blockX,blockY,cursorZ,&block)) - { - Maps->ReadTemperatures(blockX,blockY,cursorZ,&tmpb1, &tmpb2); - printf("block addr: 0x%x\n", block.origin); - int16_t tiletype = block.tiletypes[tileX][tileY]; - naked_designation &des = block.designation[tileX][tileY].bits; - uint32_t &desw = block.designation[tileX][tileY].whole; - print_bits(block.designation[tileX][tileY].whole,std::cout); - 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::endl; - - printf("%-10s: %4d %s\n","Class",tileTypeTable[tiletype].c,TileClassString[ tileTypeTable[tiletype].c ] , 0); - printf("%-10s: %4d %s\n","Material",tileTypeTable[tiletype].c,TileMaterialString[ tileTypeTable[tiletype].m ] , 0); - printf("%-10s: %4d %s\n","Special",tileTypeTable[tiletype].c,TileSpecialString[ tileTypeTable[tiletype].s ] , 0); - printf("%-10s: %4d\n","Variant",tileTypeTable[tiletype].v , 0); - printf("%-10s: %s\n","Direction",tileTypeTable[tiletype].d.getStr() , 0); - - - 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) - { - if(des.liquid_type == DFHack::liquid_magma) - std::cout <<"magma: "; - else std::cout <<"water: "; - std::cout << des.flow_size << std::endl; - } - if(des.flow_forbid) - std::cout << "flow forbid" << std::endl; - if(des.pile) - std::cout << "stockpile?" << std::endl; - if(des.rained) - std::cout << "rained?" << std::endl; - if(des.smooth) - std::cout << "smooth?" << std::endl; - uint32_t designato = block.origin + designatus + (tileX * 16 + tileY) * sizeof(t_designation); - printf("designation offset: 0x%x\n", designato); - -#define PRINT_FLAG( X ) printf("%-16s= %c\n", #X , ( des.X ? 'Y' : ' ' ) ) - PRINT_FLAG( hidden ); - PRINT_FLAG( light ); - PRINT_FLAG( skyview ); - PRINT_FLAG( subterranean ); - PRINT_FLAG( water_table ); - //PRINT_FLAG( rained ); - - planecoord pc; - pc.dim.x=blockX; pc.dim.y=blockY; - - PRINT_FLAG( feature_local ); - if( des.feature_local ){ - printf("%-16s %4d (%2d) %s\n", "", - block.local_feature, - local_features[pc][block.local_feature]->type, - sa_feature[local_features[pc][block.local_feature]->type] - ); - } - - PRINT_FLAG( feature_global ); - if( des.feature_global ){ - printf("%-16s %4d (%2d) %s\n", "", - block.global_feature, - global_features[block.global_feature].type, - sa_feature[global_features[block.global_feature].type] - ); - } - -#undef PRINT_FLAG - - std::cout << std::endl; - } - } - DF->Detach(); - #ifndef LINUX_BUILD - //std::cout << "Done. Press any key to continue" << std::endl; - std::cout << "Press any key to refresh..." << std::endl; - cin.ignore(); - goto BEGIN_PROBE; - #endif - return 0; -} + Maps->ReadLocalFeatures(local_features); + Maps->ReadGlobalFeatures(global_features); + + int32_t cursorX, cursorY, cursorZ; + Pos->getCursorCoords(cursorX,cursorY,cursorZ); + if(cursorX != -30000) + { + uint32_t blockX = cursorX / 16; + uint32_t tileX = cursorX % 16; + uint32_t blockY = cursorY / 16; + uint32_t tileY = cursorY % 16; + t_temperatures tmpb1, tmpb2; + mapblock40d block; + if(Maps->ReadBlock40d(blockX,blockY,cursorZ,&block)) + { + Maps->ReadTemperatures(blockX,blockY,cursorZ,&tmpb1, &tmpb2); + printf("block addr: 0x%x\n", block.origin); + int16_t tiletype = block.tiletypes[tileX][tileY]; + naked_designation &des = block.designation[tileX][tileY].bits; + uint32_t &desw = block.designation[tileX][tileY].whole; + print_bits(block.designation[tileX][tileY].whole,std::cout); + 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::endl; + + printf("%-10s: %4d %s\n","Class",tileTypeTable[tiletype].c,TileClassString[ tileTypeTable[tiletype].c ] , 0); + printf("%-10s: %4d %s\n","Material",tileTypeTable[tiletype].c,TileMaterialString[ tileTypeTable[tiletype].m ] , 0); + printf("%-10s: %4d %s\n","Special",tileTypeTable[tiletype].c,TileSpecialString[ tileTypeTable[tiletype].s ] , 0); + printf("%-10s: %4d\n","Variant",tileTypeTable[tiletype].v , 0); + printf("%-10s: %s\n","Direction",tileTypeTable[tiletype].d.getStr() , 0); + + + 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) + { + if(des.liquid_type == DFHack::liquid_magma) + std::cout <<"magma: "; + else std::cout <<"water: "; + std::cout << des.flow_size << std::endl; + } + if(des.flow_forbid) + std::cout << "flow forbid" << std::endl; + if(des.pile) + std::cout << "stockpile?" << std::endl; + if(des.rained) + std::cout << "rained?" << std::endl; + if(des.smooth) + std::cout << "smooth?" << std::endl; + uint32_t designato = block.origin + designatus + (tileX * 16 + tileY) * sizeof(t_designation); + printf("designation offset: 0x%x\n", designato); + + #define PRINT_FLAG( X ) printf("%-16s= %c\n", #X , ( des.X ? 'Y' : ' ' ) ) + PRINT_FLAG( hidden ); + PRINT_FLAG( light ); + PRINT_FLAG( skyview ); + PRINT_FLAG( subterranean ); + PRINT_FLAG( water_table ); + //PRINT_FLAG( rained ); + + planecoord pc; + pc.dim.x=blockX; pc.dim.y=blockY; + + PRINT_FLAG( feature_local ); + if( des.feature_local ) + { + printf("%-16s %4d (%2d) %s\n", "", + block.local_feature, + local_features[pc][block.local_feature]->type, + sa_feature[local_features[pc][block.local_feature]->type] + ); + } + + PRINT_FLAG( feature_global ); + if( des.feature_global ){ + printf("%-16s %4d (%2d) %s\n", "", + block.global_feature, + global_features[block.global_feature].type, + sa_feature[global_features[block.global_feature].type] + ); + } + #undef PRINT_FLAG + std::cout << std::endl; + } + } + DF->Detach(); + #ifndef LINUX_BUILD + std::cout << "Press any key to refresh..." << std::endl; + cin.ignore(); + goto BEGIN_PROBE; + #endif + return 0; +} From df012b4bae5ae13092e46c0c00ccf6475276776e Mon Sep 17 00:00:00 2001 From: reverb Date: Mon, 25 Oct 2010 16:15:14 -0500 Subject: [PATCH 39/94] Fixes animal bars but may need to be reworked if other item types were messed up. Also, fix shouldn't break other types. --- library/modules/Materials.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/modules/Materials.cpp b/library/modules/Materials.cpp index 343fa99c0..b1a8afcb9 100644 --- a/library/modules/Materials.cpp +++ b/library/modules/Materials.cpp @@ -476,6 +476,12 @@ std::string Materials::getDescription(t_material & mat) return "?"; else { + if (mat.itemType == 0) { + if(mat.subIndex<0) + return "any inorganic"; + else + return this->inorganic[mat.subIndex].id; + } if (mat.subIndex>=this->other.size()) { if(mat.subIndex<0) From 5e507163b87ccb96cd76064b4f3f49554c7bdf66 Mon Sep 17 00:00:00 2001 From: reverb Date: Wed, 27 Oct 2010 22:30:58 -0500 Subject: [PATCH 40/94] Material fix, custom reaction items seem to work again with offset update and bars work --- data/Memory-ng.xml | 3 +++ library/modules/Materials.cpp | 14 +++++++------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/data/Memory-ng.xml b/data/Memory-ng.xml index a157c0172..a8576e88f 100644 --- a/data/Memory-ng.xml +++ b/data/Memory-ng.xml @@ -1751,6 +1751,9 @@ + +
0x16445F0 + 0x5DC0C see code at 0x9CFB01 +
diff --git a/library/modules/Materials.cpp b/library/modules/Materials.cpp index b1a8afcb9..7ab9f8218 100644 --- a/library/modules/Materials.cpp +++ b/library/modules/Materials.cpp @@ -459,7 +459,7 @@ void Materials::ReadAllMaterials(void) this->ReadCreatureTypes(); this->ReadCreatureTypesEx(); this->ReadDescriptorColors(); - //this->ReadOthers(); + this->ReadOthers(); } std::string Materials::getDescription(t_material & mat) @@ -476,14 +476,14 @@ std::string Materials::getDescription(t_material & mat) return "?"; else { - if (mat.itemType == 0) { - if(mat.subIndex<0) - return "any inorganic"; - else - return this->inorganic[mat.subIndex].id; - } if (mat.subIndex>=this->other.size()) { + if (mat.itemType == 0) { + if(mat.subIndex<0) + return "any inorganic"; + else + return this->inorganic[mat.subIndex].id; + } if(mat.subIndex<0) return "any"; if(mat.subIndex>=this->raceEx.size()) From 4edd33e13ad2bc9a3aeca9e56d94b117afb70c7e Mon Sep 17 00:00:00 2001 From: reverb Date: Thu, 28 Oct 2010 17:22:56 -0500 Subject: [PATCH 41/94] Fix crash when deallocating items module --- library/modules/Items.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp index e63b85875..265677c8d 100644 --- a/library/modules/Items.cpp +++ b/library/modules/Items.cpp @@ -272,6 +272,7 @@ Items::~Items() while (it != d->descVTable.end()) { delete (*it).second; + ++it; } d->descType.clear(); d->descVTable.clear(); From 603d11ea0a9c66b475293527911dc24cf16313c3 Mon Sep 17 00:00:00 2001 From: rofl0r Date: Fri, 29 Oct 2010 04:45:30 +0200 Subject: [PATCH 42/94] abbreviatons for range and point in dfliquids, reapply width and height when nothing is entered --- tools/supported/liquids.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/supported/liquids.cpp b/tools/supported/liquids.cpp index 2224bd4a3..702630162 100644 --- a/tools/supported/liquids.cpp +++ b/tools/supported/liquids.cpp @@ -70,8 +70,8 @@ int main (void) << "f- - make the spawned liquid static" << endl << "0-7 - set liquid amount" << endl << "Brush:" << endl - << "point - single tile" << endl - << "range - rectangle with cursor at top left" << endl + << "point - single tile [p]" << endl + << "range - rectangle with cursor at top left [r]" << endl << "block - block with cursor in it" << endl << "Other:" << endl << "q - quit" << endl @@ -109,19 +109,19 @@ int main (void) { mode = "flowbits"; } - else if(command == "point") + else if(command == "point" || command == "p") { brush = "point"; } - else if(command == "range") + else if(command == "range" || command == "r") { cout << " :set range width<" << width << "># "; getline(cin, command); - width = atoi (command.c_str()); + width = command == "" ? width : atoi (command.c_str()); if(width < 1) width = 1; cout << " :set range height<" << height << "># "; getline(cin, command); - height = atoi (command.c_str()); + height = command == "" ? height : atoi (command.c_str()); if(height < 1) height = 1; brush = "range"; } From ab1a3a8ceff44d056555175939238d0161a2fdda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Fri, 29 Oct 2010 07:36:06 +0200 Subject: [PATCH 43/94] Salt/Stagnant water finally understood. --- library/include/dfhack/modules/Maps.h | 15 ++++-------- tools/playground/hellhole.cpp | 12 ++++++---- tools/supported/veinlook.cpp | 34 ++++++++++++++++++++++++++- 3 files changed, 46 insertions(+), 15 deletions(-) diff --git a/library/include/dfhack/modules/Maps.h b/library/include/dfhack/modules/Maps.h index fcadecc92..a9ce94a06 100644 --- a/library/include/dfhack/modules/Maps.h +++ b/library/include/dfhack/modules/Maps.h @@ -148,7 +148,7 @@ namespace DFHack liquid_water, liquid_magma }; - + /* enum e_liquidcharacter { liquid_fresh, @@ -156,7 +156,7 @@ namespace DFHack liquid_salt, liquid_unk2, }; - + */ struct naked_designation { unsigned int flow_size : 3; // how much liquid is here? @@ -196,14 +196,9 @@ namespace DFHack unsigned int feature_local : 1; /// this tile is a part of a global feature. can be combined with 'featstone' tiles unsigned int feature_global : 1; - /** - * water characteristics - * fresh=0 - * ?=1 - * salt=2 - * ?=3 - */ - e_liquidcharacter liquid_character : 2; + unsigned int water_stagnant : 1; + unsigned int water_salt : 1; + // e_liquidcharacter liquid_character : 2; }; union t_designation diff --git a/tools/playground/hellhole.cpp b/tools/playground/hellhole.cpp index a57b815a1..cc12554be 100644 --- a/tools/playground/hellhole.cpp +++ b/tools/playground/hellhole.cpp @@ -1004,7 +1004,8 @@ int main (void) if (fillmagma || fillwater) { d->bits.flow_size=7; - d->bits.liquid_character = liquid_fresh; + d->bits.water_stagnant = false; + d->bits.water_salt = false; if (fillmagma) { d->bits.liquid_type=liquid_magma; @@ -1018,7 +1019,8 @@ int main (void) { //Otherwise, remove all liquids. d->bits.flow_size=0; - d->bits.liquid_character = liquid_fresh; + d->bits.water_stagnant = false; + d->bits.water_salt = false; d->bits.liquid_type = liquid_water; } @@ -1087,7 +1089,8 @@ int main (void) //Erase any liquids, as they cause problems. d->bits.flow_size=0; - d->bits.liquid_character = liquid_fresh; + d->bits.water_stagnant = false; + d->bits.water_salt = false; d->bits.liquid_type=liquid_water; //Placing an aquifer? @@ -1121,7 +1124,8 @@ int main (void) //Erase any liquids, as they cause problems. d->bits.flow_size=0; - d->bits.liquid_character = liquid_fresh; + d->bits.water_stagnant = false; + d->bits.water_salt = false; d->bits.liquid_type=liquid_water; break; default: diff --git a/tools/supported/veinlook.cpp b/tools/supported/veinlook.cpp index 7eaa2419f..90e2f9c29 100644 --- a/tools/supported/veinlook.cpp +++ b/tools/supported/veinlook.cpp @@ -620,7 +620,9 @@ main(int argc, char *argv[]) { TEMP_NO, TEMP_1, - TEMP_2 + TEMP_2, + WATER_SALT, + WATER_STAGNANT }; e_tempmode temperature = TEMP_NO; @@ -691,6 +693,12 @@ main(int argc, char *argv[]) case 'm': temperature = TEMP_2; break; + case 'c': + temperature = WATER_SALT; + break; + case 'v': + temperature = WATER_STAGNANT; + break; case 27: // escape key DF->Detach(); return 0; @@ -940,6 +948,30 @@ main(int argc, char *argv[]) } } } + else if(temperature == WATER_SALT) + { + for(int x = 0; x < 16; x++) for(int y = 0; y < 16; y++) + { + if(Block->designation[x][y].bits.water_salt) + { + putch(x + 16,y + 16,'@',COLOR_WHITE); + } + } + gotoxy (50,8); + cprintf ("Salt water"); + } + else if(temperature == WATER_STAGNANT) + { + for(int x = 0; x < 16; x++) for(int y = 0; y < 16; y++) + { + if(Block->designation[x][y].bits.water_stagnant) + { + putch(x + 16,y + 16,'@',COLOR_WHITE); + } + } + gotoxy (50,8); + cprintf ("Stagnant water"); + } else { if(temperature == TEMP_1) From 457b331be7ee68a67c47c7af966ac56a62ef20ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Wed, 3 Nov 2010 10:45:29 +0100 Subject: [PATCH 44/94] Small fixes --- library/include/dfhack/modules/Items.h | 4 ---- library/modules/Items.cpp | 21 +++++++++++++++------ tools/examples/dfitemdump.cpp | 6 ++++++ tools/supported/vdig.cpp | 7 +------ 4 files changed, 22 insertions(+), 16 deletions(-) diff --git a/library/include/dfhack/modules/Items.h b/library/include/dfhack/modules/Items.h index 3810e6037..8940b6c95 100644 --- a/library/include/dfhack/modules/Items.h +++ b/library/include/dfhack/modules/Items.h @@ -1,10 +1,6 @@ #ifndef CL_MOD_ITEMS #define CL_MOD_ITEMS -/* - * DEPRECATED, DO NOT USE UNTIL FURTHER NOTICE! - **/ - /* * Creatures */ diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp index 265677c8d..c381184d8 100644 --- a/library/modules/Items.cpp +++ b/library/modules/Items.cpp @@ -262,8 +262,17 @@ Items::Items(DFContextShared * d_) d->d = d_; d->owner = d_->p; } -bool Items::Start(){return true;} -bool Items::Finish(){return true;} + +bool Items::Start() +{ + return true; +} + +bool Items::Finish() +{ + return true; +} + Items::~Items() { Finish(); @@ -285,10 +294,10 @@ bool Items::getItemData(uint32_t itemptr, DFHack::t_item &item) Process * p = d->owner; ItemDesc * desc; - it = d->descVTable.find(itemptr); - if(it==d->descVTable.end()) + uint32_t vtable = p->readDWord(itemptr); + it = d->descVTable.find(vtable); + if(it == d->descVTable.end()) { - uint32_t vtable = p->readDWord(itemptr); desc = new ItemDesc(vtable, p); d->descVTable[vtable] = desc; d->descType[desc->mainType] = desc; @@ -305,7 +314,7 @@ std::string Items::getItemClass(int32_t index) std::string out; it = d->descType.find(index); - if(it==d->descType.end()) + if(it == d->descType.end()) { /* these are dummy values for mood decoding */ switch(index) diff --git a/tools/examples/dfitemdump.cpp b/tools/examples/dfitemdump.cpp index eff18dcdb..7633a243a 100644 --- a/tools/examples/dfitemdump.cpp +++ b/tools/examples/dfitemdump.cpp @@ -2,6 +2,12 @@ * dumps vtables, items types and class name for all items in game * best used this way : ./dfitemdump | sort -ug */ + +// THIS IS NOT A GOOD EXAMPLE! +// ... just look at all the magic numbers. +// I'm not fixing it though. +// ~px + #include #include #include diff --git a/tools/supported/vdig.cpp b/tools/supported/vdig.cpp index 80cab23e7..07e17cc3d 100644 --- a/tools/supported/vdig.cpp +++ b/tools/supported/vdig.cpp @@ -16,12 +16,7 @@ using namespace std; class Point { public: - Point(uint32_t x, uint32_t y, uint32_t z) - { - this->x = x; - this->y = y; - this->z = z; - } + Point(uint32_t _x, uint32_t _y, uint32_t _z):x(_x),y(_y),z(_z) {} Point() { x = y = z = 0; From 8a675364e5d545ce5d04ee16ae0a1ce7fcb4d3b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Sun, 7 Nov 2010 09:49:33 +0100 Subject: [PATCH 45/94] Added force pause tool, forum posted linux 31.16 offsets (not complete). --- data/Memory-ng.xml | 11 +++++++++- tools/supported/CMakeLists.txt | 5 +++++ tools/supported/forcepause.cpp | 39 ++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 tools/supported/forcepause.cpp diff --git a/data/Memory-ng.xml b/data/Memory-ng.xml index a8576e88f..3cf4be3e7 100644 --- a/data/Memory-ng.xml +++ b/data/Memory-ng.xml @@ -2226,8 +2226,17 @@ - + + + +
+
+ + +
+ + diff --git a/tools/supported/CMakeLists.txt b/tools/supported/CMakeLists.txt index 22482f5ea..bc080448a 100644 --- a/tools/supported/CMakeLists.txt +++ b/tools/supported/CMakeLists.txt @@ -9,6 +9,10 @@ ENDIF(UNIX) ADD_EXECUTABLE(dfreveal reveal.cpp) TARGET_LINK_LIBRARIES(dfreveal dfhack) +# force pause! +ADD_EXECUTABLE(dfpause forcepause.cpp) +TARGET_LINK_LIBRARIES(dfpause dfhack) + # prospector - produces a list of available materials and their quantities ADD_EXECUTABLE(dfprospector prospector.cpp) TARGET_LINK_LIBRARIES(dfprospector dfhack) @@ -113,6 +117,7 @@ dfvdig dfcleanmap dfunstuck dfprobe +dfpause dfdoffsets dfattachtest dfcleartask diff --git a/tools/supported/forcepause.cpp b/tools/supported/forcepause.cpp new file mode 100644 index 000000000..521859078 --- /dev/null +++ b/tools/supported/forcepause.cpp @@ -0,0 +1,39 @@ +// This forces the game to pause. + +#include +#include +#include +using namespace std; + +#include +#include + +int main (void) +{ + DFHack::ContextManager DFMgr("Memory.xml"); + DFHack::Context *DF; + try + { + DF = DFMgr.getSingleContext(); + DF->Attach(); + } + catch (exception& e) + { + cerr << e.what() << endl; + #ifndef LINUX_BUILD + cin.ignore(); + #endif + return 1; + } + + DFHack::Gui *Gui =DF->getGui(); + cout << "Pausing..." << endl; + + Gui->SetPauseState(true); + DF->Resume(); + #ifndef LINUX_BUILD + cout << "Done. The current game frame will have to finish first. This can take some time on bugged maps." << endl; + cin.ignore(); + #endif + return 0; +} From 9ac7c1a9f240433eb46fd3914541560e8584df0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Mon, 8 Nov 2010 00:10:59 +0100 Subject: [PATCH 46/94] memory.xml invalidation (untested) --- data/Memory-ng.xml | 12 +-- library/DFContext.cpp | 8 +- library/DFProcess-linux-SHM.cpp | 2 +- library/DFProcess-linux-wine.cpp | 2 +- library/DFProcess-linux.cpp | 2 +- library/DFProcess-windows-SHM.cpp | 2 +- library/DFProcess-windows.cpp | 2 +- library/VersionInfo.cpp | 94 ++++++++++++++++----- library/VersionInfoFactory.cpp | 119 +++++++++++++++++++++++---- library/include/dfhack/DFError.h | 45 ++++++++-- library/include/dfhack/VersionInfo.h | 16 +++- library/modules/Buildings.cpp | 4 +- tools/examples/creaturedump.cpp | 2 +- tools/playground/renamer.cpp | 4 +- tools/supported/cleartask.cpp | 2 +- 15 files changed, 249 insertions(+), 67 deletions(-) diff --git a/data/Memory-ng.xml b/data/Memory-ng.xml index 3cf4be3e7..48c9ce60b 100644 --- a/data/Memory-ng.xml +++ b/data/Memory-ng.xml @@ -1892,7 +1892,7 @@
- + @@ -2028,12 +2028,12 @@ - + - + CHMOD @@ -2144,7 +2144,7 @@
-
+
@@ -2208,7 +2208,7 @@
-
+
@@ -2231,7 +2231,7 @@
-
+
diff --git a/library/DFContext.cpp b/library/DFContext.cpp index 8b67f193f..72662490b 100644 --- a/library/DFContext.cpp +++ b/library/DFContext.cpp @@ -334,7 +334,7 @@ bool API::InitReadEffects ( uint32_t & numeffects ) { effects = d->offset_descriptor->getAddress ("effects_vector"); } - catch(Error::MissingMemoryDefinition) + catch(Error::AllMemdef) { return false; } @@ -400,7 +400,7 @@ bool API::InitReadNotes( uint32_t &numnotes ) numnotes = d->p_notes->getSize(); return true; } - catch (Error::MissingMemoryDefinition&) + catch (Error::AllMemdef&) { d->notesInited = false; numnotes = 0; @@ -438,7 +438,7 @@ bool API::InitReadSettlements( uint32_t & numsettlements ) numsettlements = d->p_settlements->getSize(); return true; } - catch (Error::MissingMemoryDefinition&) + catch (Error::AllMemdef&) { d->settlementsInited = false; numsettlements = 0; @@ -543,7 +543,7 @@ bool API::InitReadItems(uint32_t & numitems) numitems = d->p_itm->getSize(); return true; } - catch (Error::MissingMemoryDefinition&) + catch (Error::AllMemdef&) { d->itemsInited = false; numitems = 0; diff --git a/library/DFProcess-linux-SHM.cpp b/library/DFProcess-linux-SHM.cpp index 6f6bedb34..4eaf47b90 100644 --- a/library/DFProcess-linux-SHM.cpp +++ b/library/DFProcess-linux-SHM.cpp @@ -339,7 +339,7 @@ bool SHMProcess::Private::validate(vector & known_versions) return true; } } - catch (Error::MissingMemoryDefinition&) + catch (Error::AllMemdef&) { continue; } diff --git a/library/DFProcess-linux-wine.cpp b/library/DFProcess-linux-wine.cpp index 8ab9bc689..cd96b3e54 100644 --- a/library/DFProcess-linux-wine.cpp +++ b/library/DFProcess-linux-wine.cpp @@ -142,7 +142,7 @@ bool WineProcess::Private::validate(char* exe_file, uint32_t pid, char* mem_file { thishash = (*it)->getMD5(); } - catch (Error::MissingMemoryDefinition& e) + catch (Error::AllMemdef& e) { continue; } diff --git a/library/DFProcess-linux.cpp b/library/DFProcess-linux.cpp index 24bff365a..431dee508 100644 --- a/library/DFProcess-linux.cpp +++ b/library/DFProcess-linux.cpp @@ -142,7 +142,7 @@ bool NormalProcess::Private::validate(char * exe_file,uint32_t pid, char * memFi return true; } } - catch (Error::MissingMemoryDefinition&) + catch (Error::AllMemdef&) { continue; } diff --git a/library/DFProcess-windows-SHM.cpp b/library/DFProcess-windows-SHM.cpp index aa9d50dfe..5630d3146 100644 --- a/library/DFProcess-windows-SHM.cpp +++ b/library/DFProcess-windows-SHM.cpp @@ -353,7 +353,7 @@ bool SHMProcess::Private::validate(vector & known_versions) { pe_timestamp = (*it)->getPE(); } - catch(Error::MissingMemoryDefinition&) + catch(Error::AllMemdef&) { continue; } diff --git a/library/DFProcess-windows.cpp b/library/DFProcess-windows.cpp index 5bc7bbe23..b9f3fd86e 100644 --- a/library/DFProcess-windows.cpp +++ b/library/DFProcess-windows.cpp @@ -111,7 +111,7 @@ NormalProcess::NormalProcess(uint32_t pid, vector & known_versio { pe_timestamp = (*it)->getPE(); } - catch(Error::MissingMemoryDefinition&) + catch(Error::AllMemdef&) { continue; } diff --git a/library/VersionInfo.cpp b/library/VersionInfo.cpp index c0a3477af..f63dc0930 100644 --- a/library/VersionInfo.cpp +++ b/library/VersionInfo.cpp @@ -127,11 +127,11 @@ namespace DFHack */ namespace DFHack { - typedef pair nullableUint32; + typedef pair nullableUint32; typedef map ::iterator uint32_Iter; - typedef pair nullableInt32; + typedef pair nullableInt32; typedef map ::iterator int32_Iter; - typedef pair nullableString; + typedef pair nullableString; typedef map ::iterator strings_Iter; typedef map ::iterator groups_Iter; class OffsetGroupPrivate @@ -149,69 +149,73 @@ namespace DFHack void OffsetGroup::createOffset(const string & key) { - OGd->offsets[key] = nullableInt32(false, 0); + OGd->offsets[key] = nullableInt32(NOT_SET, 0); } void OffsetGroup::createAddress(const string & key) { - OGd->addresses[key] = nullableUint32(false, 0); + OGd->addresses[key] = nullableUint32(NOT_SET, 0); } void OffsetGroup::createHexValue(const string & key) { - OGd->hexvals[key] = nullableUint32(false, 0); + OGd->hexvals[key] = nullableUint32(NOT_SET, 0); } void OffsetGroup::createString(const string & key) { - OGd->strings[key] = nullableString(false, std::string()); + OGd->strings[key] = nullableString(NOT_SET, std::string()); } -void OffsetGroup::setOffset (const string & key, const string & value) +void OffsetGroup::setOffset (const string & key, const string & value, const INVAL_TYPE inval) { 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; + if(inval != NOT_SET) + (*it).second.first = inval; } else throw Error::MissingMemoryDefinition("offset", getFullName() + key); } -void OffsetGroup::setAddress (const string & key, const string & value) +void OffsetGroup::setAddress (const string & key, const string & value, const INVAL_TYPE inval) { 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; + if(inval != NOT_SET) + (*it).second.first = inval; } else throw Error::MissingMemoryDefinition("address", getFullName() + key); } -void OffsetGroup::setHexValue (const string & key, const string & value) +void OffsetGroup::setHexValue (const string & key, const string & value, const INVAL_TYPE inval) { 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; + if(inval != NOT_SET) + (*it).second.first = inval; } else throw Error::MissingMemoryDefinition("hexvalue", getFullName() + key); } -void OffsetGroup::setString (const string & key, const string & value) +void OffsetGroup::setString (const string & key, const string & value, const INVAL_TYPE inval) { strings_Iter it = OGd->strings.find(key); if(it != OGd->strings.end()) { (*it).second.second = value; - (*it).second.first = true; + if(inval != NOT_SET) + (*it).second.first = inval; } else throw Error::MissingMemoryDefinition("string", getFullName() + key); } @@ -224,8 +228,10 @@ uint32_t OffsetGroup::getAddress (const string & key) if(iter != OGd->addresses.end()) { - if((*iter).second.first) + if((*iter).second.first == IS_VALID) return (*iter).second.second; + if((*iter).second.first == IS_INVALID) + throw Error::InvalidMemoryDefinition("address", getFullName() + key); throw Error::UnsetMemoryDefinition("address", getFullName() + key); } throw Error::MissingMemoryDefinition("address", getFullName() + key); @@ -238,8 +244,10 @@ int32_t OffsetGroup::getOffset (const string & key) int32_Iter iter = OGd->offsets.find(key); if(iter != OGd->offsets.end()) { - if((*iter).second.first) + if((*iter).second.first == IS_VALID) return (*iter).second.second; + if((*iter).second.first == IS_INVALID) + throw Error::InvalidMemoryDefinition("offset", getFullName() + key); throw Error::UnsetMemoryDefinition("offset", getFullName() + key); } throw Error::MissingMemoryDefinition("offset", getFullName() + key); @@ -252,8 +260,10 @@ uint32_t OffsetGroup::getHexValue (const string & key) uint32_Iter iter = OGd->hexvals.find(key); if(iter != OGd->hexvals.end()) { - if((*iter).second.first) + if((*iter).second.first == IS_VALID) return (*iter).second.second; + if((*iter).second.first == IS_INVALID) + throw Error::InvalidMemoryDefinition("hexvalue", getFullName() + key); throw Error::UnsetMemoryDefinition("hexvalue", getFullName() + key); } throw Error::MissingMemoryDefinition("hexvalue", getFullName() + key); @@ -265,8 +275,10 @@ std::string OffsetGroup::getString (const string &key) strings_Iter iter = OGd->strings.find(key); if(iter != OGd->strings.end()) { - if((*iter).second.first) + if((*iter).second.first == IS_VALID) return (*iter).second.second; + if((*iter).second.first == IS_INVALID) + throw Error::InvalidMemoryDefinition("string", getFullName() + key); throw Error::UnsetMemoryDefinition("string", getFullName() + key); } throw Error::MissingMemoryDefinition("string", getFullName() + key); @@ -361,6 +373,8 @@ std::string OffsetGroup::PrintOffsets(int indentation) if((*iter).second.first) ss << " value=\"" << hex << "0x" << (*iter).second.second << "\""; ss << " />"; + if((*iter).second.first == IS_INVALID) + ss << " INVALID!"; if(!(*iter).second.first) ss << " MISSING!"; ss << endl; @@ -372,6 +386,8 @@ std::string OffsetGroup::PrintOffsets(int indentation) if((*iter2).second.first) ss << " value=\"" << hex << "0x" << (*iter2).second.second << "\""; ss << " />"; + if((*iter2).second.first == IS_INVALID) + ss << " INVALID!"; if(!(*iter2).second.first) ss << " MISSING!"; ss << endl; @@ -382,6 +398,8 @@ std::string OffsetGroup::PrintOffsets(int indentation) if((*iter).second.first) ss << " value=\"" << hex << "0x" << (*iter).second.second << "\""; ss << " />"; + if((*iter).second.first == IS_INVALID) + ss << " INVALID!"; if(!(*iter).second.first) ss << " MISSING!"; ss << endl; @@ -393,6 +411,8 @@ std::string OffsetGroup::PrintOffsets(int indentation) if((*iter3).second.first) ss << " value=\"" << (*iter3).second.second << "\""; ss << " />"; + if((*iter3).second.first == IS_INVALID) + ss << " INVALID!"; if(!(*iter3).second.first) ss << " MISSING!"; ss << endl; @@ -409,6 +429,42 @@ std::string OffsetGroup::PrintOffsets(int indentation) return ss.str(); } +// the big ugly method behind the curtain... +void OffsetGroup::setInvalid(INVAL_TYPE invalidity) +{ + if(invalidity == NOT_SET) + return; + + uint32_Iter iter; + for(iter = OGd->addresses.begin(); iter != OGd->addresses.end(); iter++) + { + if((*iter).second.first) + (*iter).second.first = invalidity; + } + int32_Iter iter2; + for(iter2 = OGd->offsets.begin(); iter2 != OGd->offsets.end(); iter2++) + { + if((*iter2).second.first) + (*iter2).second.first = invalidity; + } + for(iter = OGd->hexvals.begin(); iter != OGd->hexvals.end(); iter++) + { + if((*iter).second.first) + (*iter).second.first = invalidity; + } + strings_Iter iter3; + for(iter3 = OGd->strings.begin(); iter3 != OGd->strings.end(); iter3++) + { + if((*iter3).second.first) + (*iter3).second.first = invalidity; + } + groups_Iter iter4; + for(iter4 = OGd->groups.begin(); iter4 != OGd->groups.end(); iter4++) + { + (*iter4).second->setInvalid(invalidity); + } +} + /* * Private data */ diff --git a/library/VersionInfoFactory.cpp b/library/VersionInfoFactory.cpp index b9a640663..0f99713e4 100644 --- a/library/VersionInfoFactory.cpp +++ b/library/VersionInfoFactory.cpp @@ -31,6 +31,65 @@ distribution. using namespace DFHack; +template +struct triple +{ + typedef _T1 first_type; + typedef _T2 second_type; + typedef _T3 third_type; + + _T1 first; + _T2 second; + _T3 third; + + triple() : first(), second(), third() { } + + triple(const _T1& __a, const _T2& __b, const _T3& __c) : first(__a), second(__b), third(__c) { } + + template + triple(const triple<_U1, _U2, _U3>& __p) : first(__p.first), second(__p.second), third(__p.third) { } + +}; + +template +inline bool operator==(const triple<_T1, _T2, _T3>& __x, const triple<_T1, _T2, _T3>& __y) +{ + return __x.first == __y.first && __x.second == __y.second && __x.third == __y.third; +} + +template +inline bool operator<(const triple<_T1, _T2, _T3>& __x, const triple<_T1, _T2, _T3>& __y) +{ + return + __x.first < __y.first || + (!(__y.first < __x.first) && __x.second < __y.second) || + (!(__y.first < __x.first) && !(__x.second < __y.second) && (__x.third < __y.third)); +} + +template +inline bool operator!=(const triple<_T1, _T2, _T3>& __x, const triple<_T1, _T2, _T3>& __y) +{ + return !(__x == __y); +} + +template +inline bool operator>(const triple<_T1, _T2, _T3>& __x, const triple<_T1, _T2, _T3>& __y) +{ + return __y < __x; +} + +template +inline bool operator<=(const triple<_T1, _T2, _T3>& __x, const triple<_T1, _T2, _T3>& __y) +{ + return !(__y < __x); +} + +template +inline bool operator>=(const triple<_T1, _T2, _T3>& __x, const triple<_T1, _T2, _T3>& __y) +{ + return !(__x < __y); +} + VersionInfoFactory::~VersionInfoFactory() { // for each stored version, delete @@ -95,35 +154,51 @@ void VersionInfoFactory::ParseVTable(TiXmlElement* vtable, VersionInfo* mem) } } -// FIXME: this is ripe for replacement with a more generic approach +struct breadcrumb +{ + TiXmlElement * first; + OffsetGroup * second; +}; + 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; + typedef triple< TiXmlElement *, OffsetGroup *, INVAL_TYPE> groupTriple; + vector< groupTriple > breadcrumbs; { TiXmlElement* pEntry; // we get the , look at the children pEntry = parent->FirstChildElement(); if(!pEntry) return; - + const char *cstr_invalid = parent->Attribute("valid"); + INVAL_TYPE parent_inval = NOT_SET; + if(cstr_invalid) + { + if(strcmp(cstr_invalid,"false") == 0) + parent_inval = IS_INVALID; + else if(strcmp(cstr_invalid,"true") == 0) + parent_inval = IS_VALID; + } OffsetGroup * currentGroup = reinterpret_cast (target); - breadcrumbs.push_back(groupPair(pEntry,currentGroup)); + currentGroup->setInvalid(parent_inval); + breadcrumbs.push_back(groupTriple(pEntry,currentGroup, parent_inval)); } // work variables OffsetGroup * currentGroup = 0; TiXmlElement * currentElem = 0; + INVAL_TYPE parent_inval = NOT_SET; //cerr << ""<< endl; while(1) { // get current work variables currentElem = breadcrumbs.back().first; currentGroup = breadcrumbs.back().second; + parent_inval = breadcrumbs.back().third; // we reached the end of the current group? if(!currentElem) @@ -144,7 +219,7 @@ void VersionInfoFactory::ParseOffsets(TiXmlElement * parent, VersionInfo* target if(!currentGroup) { - groupPair & gp = breadcrumbs.back(); + groupTriple & gp = breadcrumbs.back(); gp.first = gp.first->NextSiblingElement(); continue; } @@ -152,7 +227,7 @@ void VersionInfoFactory::ParseOffsets(TiXmlElement * parent, VersionInfo* target // skip non-elements if (currentElem->Type() != TiXmlNode::ELEMENT) { - groupPair & gp = breadcrumbs.back(); + groupTriple & gp = breadcrumbs.back(); gp.first = gp.first->NextSiblingElement(); continue; } @@ -169,18 +244,27 @@ void VersionInfoFactory::ParseOffsets(TiXmlElement * parent, VersionInfo* target // evaluate elements const char *cstr_value = currentElem->Attribute("value"); + const char *cstr_invalid = currentElem->Attribute("valid"); + + INVAL_TYPE child_inval = parent_inval; + if(cstr_invalid) + { + if(strcmp(cstr_invalid,"false") == 0) + child_inval = IS_INVALID; + else if(strcmp(cstr_invalid,"true") == 0) + child_inval = IS_VALID; + } 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(); + groupTriple & gp = breadcrumbs.back(); gp.first = currentElem->NextSiblingElement(); if(!og) @@ -189,8 +273,9 @@ void VersionInfoFactory::ParseOffsets(TiXmlElement * parent, VersionInfo* target throw Error::MissingMemoryDefinition("group", fullname); } - // add a new level that will be processed next - breadcrumbs.push_back(groupPair(currentElem->FirstChildElement(), og)); + // add a new level that will be processed in the next step + breadcrumbs.push_back(groupTriple(currentElem->FirstChildElement(), og, child_inval)); + og->setInvalid(child_inval); continue; } else if(type == "address") @@ -201,7 +286,7 @@ void VersionInfoFactory::ParseOffsets(TiXmlElement * parent, VersionInfo* target } else if(cstr_value) { - currentGroup->setAddress(cstr_name, cstr_value); + currentGroup->setAddress(cstr_name, cstr_value, child_inval); } else { @@ -216,7 +301,7 @@ void VersionInfoFactory::ParseOffsets(TiXmlElement * parent, VersionInfo* target } else if(cstr_value) { - currentGroup->setOffset(cstr_name, cstr_value); + currentGroup->setOffset(cstr_name, cstr_value, child_inval); } else { @@ -231,7 +316,7 @@ void VersionInfoFactory::ParseOffsets(TiXmlElement * parent, VersionInfo* target } else if(cstr_value) { - currentGroup->setString(cstr_name, cstr_value); + currentGroup->setString(cstr_name, cstr_value, child_inval); } else { @@ -246,7 +331,7 @@ void VersionInfoFactory::ParseOffsets(TiXmlElement * parent, VersionInfo* target } else if(cstr_value) { - currentGroup->setHexValue(cstr_name, cstr_value); + currentGroup->setHexValue(cstr_name, cstr_value, child_inval); } else { @@ -255,7 +340,7 @@ void VersionInfoFactory::ParseOffsets(TiXmlElement * parent, VersionInfo* target } // advance to next element - groupPair & gp = breadcrumbs.back(); + groupTriple & gp = breadcrumbs.back(); gp.first = currentElem->NextSiblingElement(); continue; } diff --git a/library/include/dfhack/DFError.h b/library/include/dfhack/DFError.h index fcb80f724..28e11df33 100644 --- a/library/include/dfhack/DFError.h +++ b/library/include/dfhack/DFError.h @@ -39,6 +39,7 @@ namespace DFHack * the whole array of DFHack exceptions from the rest */ class DFHACK_EXPORT All : public std::exception{}; + class DFHACK_EXPORT AllMemdef : public All{}; class DFHACK_EXPORT NoProcess : public All { public: @@ -80,7 +81,7 @@ namespace DFHack }; // a call to DFHack::mem_info::get* failed - class DFHACK_EXPORT MissingMemoryDefinition : public All + class DFHACK_EXPORT MissingMemoryDefinition : public AllMemdef { public: MissingMemoryDefinition(const char* _type, const std::string _key) : type(_type), key(_key) @@ -113,7 +114,7 @@ namespace DFHack }; // a call to DFHack::mem_info::get* failed - class DFHACK_EXPORT UnsetMemoryDefinition : public All + class DFHACK_EXPORT UnsetMemoryDefinition : public AllMemdef { public: UnsetMemoryDefinition(const char* _type, const std::string _key) : type(_type), key(_key) @@ -145,7 +146,41 @@ namespace DFHack } }; - // Syntax errors and whatnot, the xml cant be read + // a call to DFHack::mem_info::get* failed + class DFHACK_EXPORT InvalidMemoryDefinition : public AllMemdef + { + public: + InvalidMemoryDefinition(const char* _type, const std::string _key) : type(_type), key(_key) + { + std::stringstream s; + s << "memory object is INVALID: type " << type << " key " << key; + full = s.str(); + } + // Used by functios using integer keys, such as getTrait + InvalidMemoryDefinition(const char* _type, uint32_t _key) : type(_type) + { + std::stringstream s1; + s1 << _key; + key = s1.str(); + + std::stringstream s; + s << "memory object is INVALID: type " << type << " key " << key; + full = s.str(); + } + virtual ~InvalidMemoryDefinition() throw(){}; + + std::string full; + const std::string type; + std::string key; + + virtual const char* what() const throw() + { + return full.c_str(); + } + }; + + + // Syntax errors and whatnot, the xml can't be read class DFHACK_EXPORT MemoryXmlParse : public All { public: @@ -156,14 +191,12 @@ namespace DFHack s << "error " << id << ": " << desc << ", at row " << row << " col " << col; full = s.str(); } - - + std::string full; const std::string desc; const int id; const int row; const int col; - virtual ~MemoryXmlParse() throw(){}; virtual const char* what() const throw() diff --git a/library/include/dfhack/VersionInfo.h b/library/include/dfhack/VersionInfo.h index 84a7087da..e01b8f115 100644 --- a/library/include/dfhack/VersionInfo.h +++ b/library/include/dfhack/VersionInfo.h @@ -41,6 +41,13 @@ namespace DFHack class VersionInfoPrivate; class OffsetGroupPrivate; + enum INVAL_TYPE + { + NOT_SET, + IS_INVALID, + IS_VALID + }; + /* * Offset Group */ @@ -68,14 +75,15 @@ namespace DFHack 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); + void setOffset (const std::string& key, const std::string& value, const DFHack::INVAL_TYPE inval = IS_VALID); + void setAddress (const std::string& key, const std::string& value, const DFHack::INVAL_TYPE inval = IS_VALID); + void setHexValue (const std::string& key, const std::string& value, const DFHack::INVAL_TYPE inval = IS_VALID); + void setString (const std::string& key, const std::string& value, const DFHack::INVAL_TYPE inval = IS_VALID); std::string PrintOffsets(int indentation); std::string getName(); std::string getFullName(); OffsetGroup * getParent(); + void setInvalid(INVAL_TYPE arg1); }; /* diff --git a/library/modules/Buildings.cpp b/library/modules/Buildings.cpp index 5e82be992..7541bb33e 100644 --- a/library/modules/Buildings.cpp +++ b/library/modules/Buildings.cpp @@ -85,9 +85,9 @@ Buildings::Buildings(DFContextShared * d_) mem->resolveClassnameToClassID("building_custom_workshop", d->custom_workshop_id); d->hasCustomWorkshops = true; } - catch(DFHack::Error::UnsetMemoryDefinition &e) + catch(DFHack::Error::AllMemdef &e) { - cerr << "Custom workshops not available. Unset Memory Definition: " << e.what() << endl; + cerr << "Custom workshops not available. Memory Definition: " << e.what() << endl; } d->Inited = true; } diff --git a/tools/examples/creaturedump.cpp b/tools/examples/creaturedump.cpp index ac691316b..ae221a1e6 100644 --- a/tools/examples/creaturedump.cpp +++ b/tools/examples/creaturedump.cpp @@ -306,7 +306,7 @@ void printCreature(DFHack::Context * DF, const DFHack::t_creature & creature) { cout << mem->getSkill(creature.defaultSoul.skills[i].id) << ": " << creature.defaultSoul.skills[i].rating; } - catch(DFHack::Error::MissingMemoryDefinition &e) + catch(DFHack::Error::AllMemdef &e) { cout << "Unknown skill! : " << creature.defaultSoul.skills[i].id <<", rating: " << creature.defaultSoul.skills[i].rating << endl; cout << e.what() << endl; diff --git a/tools/playground/renamer.cpp b/tools/playground/renamer.cpp index c08fb0bfc..389ba8068 100644 --- a/tools/playground/renamer.cpp +++ b/tools/playground/renamer.cpp @@ -449,7 +449,7 @@ start: uint32_t nickname = mem->getOffset("creature_name") + mem->getOffset("name_nickname"); p->writeSTLString(toChange.origin+nickname,changeString); } - catch (DFHack::Error::MissingMemoryDefinition&) + catch (DFHack::Error::AllMemdef&) { cerr << "Writing creature nicknames unsupported in this version!" << endl; } @@ -461,7 +461,7 @@ start: uint32_t custom_prof = mem->getOffset("creature_custom_profession"); p->writeSTLString(toChange.origin+custom_prof,changeString); } - catch (DFHack::Error::MissingMemoryDefinition&) + catch (DFHack::Error::AllMemdef&) { cerr << "Writing creature custom profession unsupported in this version!" << endl; } diff --git a/tools/supported/cleartask.cpp b/tools/supported/cleartask.cpp index 08f86f781..6ef34abac 100644 --- a/tools/supported/cleartask.cpp +++ b/tools/supported/cleartask.cpp @@ -39,7 +39,7 @@ int main () { item_vec_offset = p->getDescriptor()->getAddress ("items_vector"); } - catch(DFHack::Error::MissingMemoryDefinition & e) + catch(DFHack::Error::AllMemdef & e) { cerr << "missing offset for the item vector, exiting :(" << endl; #ifndef LINUX_BUILD From a5d21e612b2be797249bd8b1a1da90d1a8449665 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Mon, 8 Nov 2010 00:31:40 +0100 Subject: [PATCH 47/94] Fixes, some messing around with the invalidation code --- data/Memory-ng.xml | 10 +++++++--- library/VersionInfoFactory.cpp | 8 ++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/data/Memory-ng.xml b/data/Memory-ng.xml index 48c9ce60b..b2e9f11b7 100644 --- a/data/Memory-ng.xml +++ b/data/Memory-ng.xml @@ -2226,12 +2226,16 @@ - + + + + + + -
-
+
diff --git a/library/VersionInfoFactory.cpp b/library/VersionInfoFactory.cpp index 0f99713e4..686a426e4 100644 --- a/library/VersionInfoFactory.cpp +++ b/library/VersionInfoFactory.cpp @@ -280,6 +280,8 @@ void VersionInfoFactory::ParseOffsets(TiXmlElement * parent, VersionInfo* target } else if(type == "address") { + if(child_inval == NOT_SET) + child_inval = IS_VALID; if(initial) { currentGroup->createAddress(cstr_name); @@ -295,6 +297,8 @@ void VersionInfoFactory::ParseOffsets(TiXmlElement * parent, VersionInfo* target } else if(type == "offset") { + if(child_inval == NOT_SET) + child_inval = IS_VALID; if(initial) { currentGroup->createOffset(cstr_name); @@ -310,6 +314,8 @@ void VersionInfoFactory::ParseOffsets(TiXmlElement * parent, VersionInfo* target } else if(type == "string") { + if(child_inval == NOT_SET) + child_inval = IS_VALID; if(initial) { currentGroup->createString(cstr_name); @@ -325,6 +331,8 @@ void VersionInfoFactory::ParseOffsets(TiXmlElement * parent, VersionInfo* target } else if(type == "hexvalue") { + if(child_inval == NOT_SET) + child_inval = IS_VALID; if(initial) { currentGroup->createHexValue(cstr_name); From be11bdbe263715d18819cac6f07b655c6aedf128 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Mon, 8 Nov 2010 02:09:51 +0100 Subject: [PATCH 48/94] Removed some redundant xml attributes --- data/Memory-ng.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/data/Memory-ng.xml b/data/Memory-ng.xml index b2e9f11b7..b35de2f82 100644 --- a/data/Memory-ng.xml +++ b/data/Memory-ng.xml @@ -1811,7 +1811,7 @@
- + - + - + @@ -1852,7 +1852,7 @@
- + @@ -1892,7 +1892,7 @@
- + @@ -1950,7 +1950,7 @@
- + VERIFY @@ -2025,7 +2025,7 @@ - + VERIFY From 0df38244e4a7576cac4c0c1f3f2ea4c5bf3ce0f2 Mon Sep 17 00:00:00 2001 From: rofl0r Date: Thu, 11 Nov 2010 02:09:43 +0100 Subject: [PATCH 49/94] added -q (quiet) command line parameter to a couple of tools, to allow usage in scripts. --- tools/supported/cleanmap.cpp | 22 ++++++++++++++++++---- tools/supported/forcepause.cpp | 16 +++++++++++++--- tools/supported/liquids.cpp | 20 ++++++++++++++++---- tools/supported/position.cpp | 15 ++++++++++++++- tools/supported/prospector.cpp | 2 +- tools/supported/weather.cpp | 29 +++++++++++++++++++++++++---- 6 files changed, 87 insertions(+), 17 deletions(-) diff --git a/tools/supported/cleanmap.cpp b/tools/supported/cleanmap.cpp index 900aa3f72..7ff2e7255 100644 --- a/tools/supported/cleanmap.cpp +++ b/tools/supported/cleanmap.cpp @@ -8,9 +8,20 @@ using namespace std; #include -int main (void) +int main (int argc, char** argv) { - uint32_t x_max,y_max,z_max; + + bool quiet = false; + for(int i = 1; i < argc; i++) + { + string test = argv[i]; + if(test == "-q") + { + quiet = true; + } + } + + uint32_t x_max,y_max,z_max; uint32_t num_blocks = 0; uint32_t bytes_read = 0; vector splatter; @@ -72,8 +83,11 @@ int main (void) } DF->Detach(); #ifndef LINUX_BUILD - cout << "Done. Press any key to continue" << endl; - cin.ignore(); + if (!quiet) + { + cout << "Done. Press any key to continue" << endl; + cin.ignore(); + } #endif return 0; } diff --git a/tools/supported/forcepause.cpp b/tools/supported/forcepause.cpp index 521859078..c6115aa5a 100644 --- a/tools/supported/forcepause.cpp +++ b/tools/supported/forcepause.cpp @@ -8,8 +8,18 @@ using namespace std; #include #include -int main (void) +int main (int argc, char** argv) { + bool quiet = false; + for(int i = 1; i < argc; i++) + { + string test = argv[i]; + if(test == "-q") + { + quiet = true; + } + } + DFHack::ContextManager DFMgr("Memory.xml"); DFHack::Context *DF; try @@ -21,7 +31,7 @@ int main (void) { cerr << e.what() << endl; #ifndef LINUX_BUILD - cin.ignore(); + if(!quiet) cin.ignore(); #endif return 1; } @@ -33,7 +43,7 @@ int main (void) DF->Resume(); #ifndef LINUX_BUILD cout << "Done. The current game frame will have to finish first. This can take some time on bugged maps." << endl; - cin.ignore(); + if (!quiet) cin.ignore(); #endif return 0; } diff --git a/tools/supported/liquids.cpp b/tools/supported/liquids.cpp index 702630162..702610931 100644 --- a/tools/supported/liquids.cpp +++ b/tools/supported/liquids.cpp @@ -9,9 +9,18 @@ using namespace std; #include #include -int main (void) +int main (int argc, char** argv) { - int32_t x,y,z; + bool quiet = false; + for(int i = 1; i < argc; i++) + { + string test = argv[i]; + if(test == "-q") + { + quiet = true; + } + } + int32_t x,y,z; DFHack::designations40d designations; DFHack::tiletypes40d tiles; DFHack::t_temperatures temp1,temp2; @@ -460,8 +469,11 @@ int main (void) } DF->Detach(); #ifndef LINUX_BUILD - cout << "Done. Press any key to continue" << endl; - cin.ignore(); + if(!quiet) + { + cout << "Done. Press any key to continue" << endl; + cin.ignore(); + } #endif return 0; } diff --git a/tools/supported/position.cpp b/tools/supported/position.cpp index 5f666ec4e..e660c2a91 100644 --- a/tools/supported/position.cpp +++ b/tools/supported/position.cpp @@ -8,8 +8,18 @@ using namespace std; #include -int main (void) +int main (int argc, char** argv) { + bool quiet = false; + for(int i = 1; i < argc; i++) + { + string test = argv[i]; + if(test == "-q") + { + quiet = true; + } + } + DFHack::Position * Position = 0; DFHack::ContextManager DFMgr("Memory.xml"); DFHack::Context * DF; @@ -50,8 +60,11 @@ int main (void) } #ifndef LINUX_BUILD + if(!quiet) + { cout << "Done. Press any key to continue" << endl; cin.ignore(); + } #endif return 0; } diff --git a/tools/supported/prospector.cpp b/tools/supported/prospector.cpp index 77ba6afcb..096b1269a 100644 --- a/tools/supported/prospector.cpp +++ b/tools/supported/prospector.cpp @@ -44,7 +44,7 @@ int main (int argc, const char* argv[]) bool showhidden = false; bool showbaselayers = false; - for(int i = 0; i < argc; i++) + for(int i = 1; i < argc; i++) { string test = argv[i]; if(test == "-a") diff --git a/tools/supported/weather.cpp b/tools/supported/weather.cpp index 6d441b00b..4ca738842 100644 --- a/tools/supported/weather.cpp +++ b/tools/supported/weather.cpp @@ -43,9 +43,26 @@ void printWeather(DFHack::WeatherType current) } using namespace DFHack; -int main (int numargs, const char ** args) +int main (int argc, char** argv) { - DFHack::ContextManager DFMgr("Memory.xml"); + string command = ""; + bool quiet = false; + bool cmdarg = false; + for(int i = 1; i < argc; i++) + { + string test = argv[i]; + if(test == "-q") + { + quiet = true; + } + else + { + command = test; + cmdarg = true; + } + } + + DFHack::ContextManager DFMgr("Memory.xml"); DFHack::Context *DF = DFMgr.getSingleContext(); try @@ -68,9 +85,8 @@ int main (int numargs, const char ** args) { WeatherType current = (WeatherType) W->ReadCurrentWeather(); DF->Resume(); - string command = ""; printWeather(current); - getline(cin, command); + if (command == "") getline(cin, command); // only read from stdin if command hasn't been passed on the console DF->Suspend(); if(command == "c") { @@ -88,10 +104,15 @@ int main (int numargs, const char ** args) { end = true; } + command = ""; + if(cmdarg) end = true; // exit the loop when a cmd line arg has been passed. } #ifndef LINUX_BUILD + if (!quiet) + { std::cout << "Done. Press any key to continue" << std::endl; cin.ignore(); + } #endif DF->Detach(); return 0; From e41a5c6300f666e2847921dc7931493d568864f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Thu, 11 Nov 2010 02:32:33 +0100 Subject: [PATCH 50/94] Fixed URL in LICENSE, whitespace in tools. --- LICENSE | 2 +- tools/supported/cleanmap.cpp | 16 +++---- tools/supported/forcepause.cpp | 8 ++-- tools/supported/liquids.cpp | 16 +++---- tools/supported/position.cpp | 20 ++++---- tools/supported/prospector.cpp | 30 ++++++------ tools/supported/vdig.cpp | 88 +++++++++++++++++----------------- tools/supported/weather.cpp | 34 ++++++------- 8 files changed, 106 insertions(+), 108 deletions(-) diff --git a/LICENSE b/LICENSE index 5b904f714..9c8259200 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -www.sourceforge.net/projects/dfhack +github.com/peterix/dfhack Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf This software is provided 'as-is', without any express or implied diff --git a/tools/supported/cleanmap.cpp b/tools/supported/cleanmap.cpp index 7ff2e7255..e4b97b703 100644 --- a/tools/supported/cleanmap.cpp +++ b/tools/supported/cleanmap.cpp @@ -19,13 +19,13 @@ int main (int argc, char** argv) { quiet = true; } - } - - uint32_t x_max,y_max,z_max; + } + + uint32_t x_max,y_max,z_max; uint32_t num_blocks = 0; uint32_t bytes_read = 0; vector splatter; - + DFHack::ContextManager DFMgr("Memory.xml"); DFHack::Context *DF = DFMgr.getSingleContext(); try @@ -41,7 +41,7 @@ int main (int argc, char** argv) return 1; } DFHack::Maps *Mapz = DF->getMaps(); - + // init the map if(!Mapz->Start()) { @@ -51,11 +51,11 @@ int main (int argc, char** argv) #endif return 1; } - + Mapz->getSize(x_max,y_max,z_max); - + uint8_t zeroes [16][16] = {0}; - + // walk the map for(uint32_t x = 0; x< x_max;x++) { diff --git a/tools/supported/forcepause.cpp b/tools/supported/forcepause.cpp index c6115aa5a..4288ccefe 100644 --- a/tools/supported/forcepause.cpp +++ b/tools/supported/forcepause.cpp @@ -18,8 +18,8 @@ int main (int argc, char** argv) { quiet = true; } - } - + } + DFHack::ContextManager DFMgr("Memory.xml"); DFHack::Context *DF; try @@ -42,8 +42,8 @@ int main (int argc, char** argv) Gui->SetPauseState(true); DF->Resume(); #ifndef LINUX_BUILD - cout << "Done. The current game frame will have to finish first. This can take some time on bugged maps." << endl; - if (!quiet) cin.ignore(); + cout << "Done. The current game frame will have to finish first. This can take some time on bugged maps." << endl; + if (!quiet) cin.ignore(); #endif return 0; } diff --git a/tools/supported/liquids.cpp b/tools/supported/liquids.cpp index 702610931..46596f6d8 100644 --- a/tools/supported/liquids.cpp +++ b/tools/supported/liquids.cpp @@ -19,13 +19,13 @@ int main (int argc, char** argv) { quiet = true; } - } - int32_t x,y,z; + } + int32_t x,y,z; DFHack::designations40d designations; DFHack::tiletypes40d tiles; DFHack::t_temperatures temp1,temp2; uint32_t x_max,y_max,z_max; - + DFHack::ContextManager DFMgr("Memory.xml"); DFHack::Context *DF; DFHack::Maps * Maps; @@ -469,11 +469,11 @@ int main (int argc, char** argv) } DF->Detach(); #ifndef LINUX_BUILD - if(!quiet) - { - cout << "Done. Press any key to continue" << endl; - cin.ignore(); - } + if(!quiet) + { + cout << "Done. Press any key to continue" << endl; + cin.ignore(); + } #endif return 0; } diff --git a/tools/supported/position.cpp b/tools/supported/position.cpp index e660c2a91..a6383e0ef 100644 --- a/tools/supported/position.cpp +++ b/tools/supported/position.cpp @@ -18,8 +18,8 @@ int main (int argc, char** argv) { quiet = true; } - } - + } + DFHack::Position * Position = 0; DFHack::ContextManager DFMgr("Memory.xml"); DFHack::Context * DF; @@ -41,7 +41,7 @@ int main (int argc, char** argv) { int32_t x,y,z; int32_t width,height; - + if(Position->getViewCoords(x,y,z)) cout << "view coords: " << x << "/" << y << "/" << z << endl; if(Position->getCursorCoords(x,y,z)) @@ -53,18 +53,18 @@ int main (int argc, char** argv) { cerr << "cursor and window parameters are unsupported on your version of DF" << endl; } - + if(!DF->Detach()) { cerr << "Can't detach from DF" << endl; } - + #ifndef LINUX_BUILD - if(!quiet) - { - cout << "Done. Press any key to continue" << endl; - cin.ignore(); - } + if(!quiet) + { + cout << "Done. Press any key to continue" << endl; + cin.ignore(); + } #endif return 0; } diff --git a/tools/supported/prospector.cpp b/tools/supported/prospector.cpp index 096b1269a..4b036fb8d 100644 --- a/tools/supported/prospector.cpp +++ b/tools/supported/prospector.cpp @@ -41,7 +41,6 @@ struct compare_pair_second int main (int argc, const char* argv[]) { - bool showhidden = false; bool showbaselayers = false; for(int i = 1; i < argc; i++) @@ -76,9 +75,9 @@ int main (int argc, const char* argv[]) materials.clear(); vector global_features; std::map > local_features; - + vector< vector > layerassign; - + DFHack::ContextManager DFMgr("Memory.xml"); DFHack::Context *DF; try @@ -94,11 +93,10 @@ int main (int argc, const char* argv[]) #endif return 1; } - DFHack::Maps * Maps = DF->getMaps(); DFHack::Materials * Mats = DF->getMaterials(); - + // init the map if(!Maps->Start()) { @@ -109,7 +107,7 @@ int main (int argc, const char* argv[]) return 1; } Maps->getSize(x_max,y_max,z_max); - + if(!Maps->ReadGlobalFeatures(global_features)) { cerr << "Can't get global features." << endl; @@ -137,7 +135,7 @@ int main (int argc, const char* argv[]) #endif return 1; } - + // get region geology if(!Maps->ReadGeology( layerassign )) { @@ -147,7 +145,7 @@ int main (int argc, const char* argv[]) #endif return 1; } - + int16_t tempvein [16][16]; vector veins; uint32_t maximum_regionoffset = 0; @@ -161,16 +159,16 @@ int main (int argc, const char* argv[]) { if(!Maps->isValidBlock(x,y,z)) continue; - + // read data Maps->ReadBlock40d(x,y,z, &Block); //Maps->ReadTileTypes(x,y,z, &tiletypes); //Maps->ReadDesignations(x,y,z, &designations); - + memset(tempvein, -1, sizeof(tempvein)); veins.clear(); Maps->ReadVeins(x,y,z,&veins); - + if(showbaselayers) { //Maps->ReadRegionOffsets(x,y,z, ®ionoffsets); @@ -194,7 +192,7 @@ int main (int argc, const char* argv[]) } } } - + // for each vein for(int i = 0; i < (int)veins.size();i++) { @@ -214,7 +212,7 @@ int main (int argc, const char* argv[]) } } } - + // global feature overrides int16_t idx = Block.global_feature; if( idx != -1 && uint16_t(idx) < global_features.size() && global_features[idx].type == DFHack::feature_Underworld) @@ -234,7 +232,7 @@ int main (int argc, const char* argv[]) } } } - + idx = Block.local_feature; if( idx != -1 ) { @@ -263,7 +261,7 @@ int main (int argc, const char* argv[]) } } } - + // count the material types for(uint32_t xi = 0 ; xi< 16 ; xi++) { @@ -275,7 +273,7 @@ int main (int argc, const char* argv[]) continue; if(tempvein[xi][yi] < 0) continue; - + if(materials.count(tempvein[xi][yi])) { materials[tempvein[xi][yi]] += 1; diff --git a/tools/supported/vdig.cpp b/tools/supported/vdig.cpp index 07e17cc3d..17a7c2f2c 100644 --- a/tools/supported/vdig.cpp +++ b/tools/supported/vdig.cpp @@ -13,37 +13,37 @@ using namespace std; #include #define MAX_DIM 0x300 -class Point +class Vertex { public: - Point(uint32_t _x, uint32_t _y, uint32_t _z):x(_x),y(_y),z(_z) {} - Point() + Vertex(uint32_t _x, uint32_t _y, uint32_t _z):x(_x),y(_y),z(_z) {} + Vertex() { x = y = z = 0; } - bool operator==(const Point &other) const + bool operator==(const Vertex &other) const { return (other.x == x && other.y == y && other.z == z); } - bool operator<(const Point &other) const + bool operator<(const Vertex &other) const { return ( (z*MAX_DIM*MAX_DIM + y*MAX_DIM + x) < (other.z*MAX_DIM*MAX_DIM + other.y*MAX_DIM + other.x)); } - Point operator/(int number) const + Vertex operator/(int number) const { - return Point(x/number, y/number, z); + return Vertex(x/number, y/number, z); } - Point operator%(int number) const + Vertex operator%(int number) const { - return Point(x%number, y%number, z); + return Vertex(x%number, y%number, z); } - Point operator-(int number) const + Vertex operator-(int number) const { - return Point(x,y,z-number); + return Vertex(x,y,z-number); } - Point operator+(int number) const + Vertex operator+(int number) const { - return Point(x,y,z+number); + return Vertex(x,y,z+number); } uint32_t x; uint32_t y; @@ -53,7 +53,7 @@ class Point class Block { public: - Block(DFHack::Maps *_m, Point _bcoord) + Block(DFHack::Maps *_m, Vertex _bcoord) { vector veins; m = _m; @@ -92,23 +92,23 @@ class Block valid = true; } } - int16_t MaterialAt(Point p) + int16_t MaterialAt(Vertex p) { return materials[p.x][p.y]; } - void ClearMaterialAt(Point p) + void ClearMaterialAt(Vertex p) { materials[p.x][p.y] = -1; } - int16_t TileTypeAt(Point p) + int16_t TileTypeAt(Vertex p) { return raw.tiletypes[p.x][p.y]; } - DFHack::t_designation DesignationAt(Point p) + DFHack::t_designation DesignationAt(Vertex p) { return raw.designation[p.x][p.y]; } - bool setDesignationAt(Point p, DFHack::t_designation des) + bool setDesignationAt(Vertex p, DFHack::t_designation des) { if(!valid) return false; dirty = true; @@ -131,7 +131,7 @@ class Block volatile bool dirty; DFHack::Maps * m; DFHack::mapblock40d raw; - Point bcoord; + Vertex bcoord; int16_t materials[16][16]; int8_t bitmap[16][16]; }; @@ -148,7 +148,7 @@ class MapCache }; ~MapCache() { - map::iterator p; + map::iterator p; for(p = blocks.begin(); p != blocks.end(); p++) { delete p->second; @@ -160,11 +160,11 @@ class MapCache return valid; } - Block * BlockAt (Point blockcoord) + Block * BlockAt (Vertex blockcoord) { if(!valid) return 0; - map ::iterator iter = blocks.find(blockcoord); + map ::iterator iter = blocks.find(blockcoord); if(iter != blocks.end()) { return (*iter).second; @@ -181,7 +181,7 @@ class MapCache } } - uint16_t tiletypeAt (Point tilecoord) + uint16_t tiletypeAt (Vertex tilecoord) { Block * b= BlockAt(tilecoord / 16); if(b && b->valid) @@ -191,7 +191,7 @@ class MapCache return 0; } - int16_t materialAt (Point tilecoord) + int16_t materialAt (Vertex tilecoord) { Block * b= BlockAt(tilecoord / 16); if(b && b->valid) @@ -200,7 +200,7 @@ class MapCache } return 0; } - bool clearMaterialAt (Point tilecoord) + bool clearMaterialAt (Vertex tilecoord) { Block * b= BlockAt(tilecoord / 16); if(b && b->valid) @@ -211,7 +211,7 @@ class MapCache } - DFHack::t_designation designationAt (Point tilecoord) + DFHack::t_designation designationAt (Vertex tilecoord) { Block * b= BlockAt(tilecoord / 16); if(b && b->valid) @@ -222,7 +222,7 @@ class MapCache temp.whole = 0; return temp; } - bool setDesignationAt (Point tilecoord, DFHack::t_designation des) + bool setDesignationAt (Vertex tilecoord, DFHack::t_designation des) { Block * b= BlockAt(tilecoord / 16); if(b && b->valid) @@ -232,7 +232,7 @@ class MapCache } return false; } - bool testCoord (Point tilecoord) + bool testCoord (Vertex tilecoord) { Block * b= BlockAt(tilecoord / 16); if(b && b->valid) @@ -244,7 +244,7 @@ class MapCache bool WriteAll() { - map::iterator p; + map::iterator p; for(p = blocks.begin(); p != blocks.end(); p++) { p->second->WriteDesignations(); @@ -260,7 +260,7 @@ class MapCache uint32_t y_tmax; uint32_t z_max; DFHack::Maps * Maps; - map blocks; + map blocks; }; int main (int argc, char* argv[]) @@ -325,7 +325,7 @@ int main (int argc, char* argv[]) DF->Suspend(); Pos->getCursorCoords(cx,cy,cz); } - Point xy ((uint32_t)cx,(uint32_t)cy,cz); + Vertex xy ((uint32_t)cx,(uint32_t)cy,cz); if(xy.x == 0 || xy.x == tx_max - 1 || xy.y == 0 || xy.y == ty_max - 1) { cerr << "I won't dig the borders. That would be cheating!" << endl; @@ -353,13 +353,13 @@ int main (int argc, char* argv[]) return 1; } printf("%d/%d/%d tiletype: %d, veinmat: %d, designation: 0x%x ... DIGGING!\n", cx,cy,cz, tt, veinmat, des.whole); - stack flood; + stack flood; flood.push(xy); while( !flood.empty() ) { - Point current = flood.top(); + Vertex current = flood.top(); flood.pop(); int16_t vmat2 = MCache->materialAt(current); @@ -397,30 +397,30 @@ int main (int argc, char* argv[]) MCache->clearMaterialAt(current); if(current.x < tx_max - 2) { - flood.push(Point(current.x + 1, current.y, current.z)); + flood.push(Vertex(current.x + 1, current.y, current.z)); if(current.y < ty_max - 2) { - flood.push(Point(current.x + 1, current.y + 1,current.z)); - flood.push(Point(current.x, current.y + 1,current.z)); + flood.push(Vertex(current.x + 1, current.y + 1,current.z)); + flood.push(Vertex(current.x, current.y + 1,current.z)); } if(current.y > 1) { - flood.push(Point(current.x + 1, current.y - 1,current.z)); - flood.push(Point(current.x, current.y - 1,current.z)); + flood.push(Vertex(current.x + 1, current.y - 1,current.z)); + flood.push(Vertex(current.x, current.y - 1,current.z)); } } if(current.x > 1) { - flood.push(Point(current.x - 1, current.y,current.z)); + flood.push(Vertex(current.x - 1, current.y,current.z)); if(current.y < ty_max - 2) { - flood.push(Point(current.x - 1, current.y + 1,current.z)); - flood.push(Point(current.x, current.y + 1,current.z)); + flood.push(Vertex(current.x - 1, current.y + 1,current.z)); + flood.push(Vertex(current.x, current.y + 1,current.z)); } if(current.y > 1) { - flood.push(Point(current.x - 1, current.y - 1,current.z)); - flood.push(Point(current.x, current.y - 1,current.z)); + flood.push(Vertex(current.x - 1, current.y - 1,current.z)); + flood.push(Vertex(current.x, current.y - 1,current.z)); } } if(updown) diff --git a/tools/supported/weather.cpp b/tools/supported/weather.cpp index 4ca738842..5ded20649 100644 --- a/tools/supported/weather.cpp +++ b/tools/supported/weather.cpp @@ -45,9 +45,9 @@ void printWeather(DFHack::WeatherType current) using namespace DFHack; int main (int argc, char** argv) { - string command = ""; + string command = ""; bool quiet = false; - bool cmdarg = false; + bool cmdarg = false; for(int i = 1; i < argc; i++) { string test = argv[i]; @@ -55,14 +55,14 @@ int main (int argc, char** argv) { quiet = true; } - else - { - command = test; - cmdarg = true; - } - } - - DFHack::ContextManager DFMgr("Memory.xml"); + else + { + command = test; + cmdarg = true; + } + } + + DFHack::ContextManager DFMgr("Memory.xml"); DFHack::Context *DF = DFMgr.getSingleContext(); try @@ -104,15 +104,15 @@ int main (int argc, char** argv) { end = true; } - command = ""; - if(cmdarg) end = true; // exit the loop when a cmd line arg has been passed. + command = ""; + if(cmdarg) end = true; // exit the loop when a cmd line arg has been passed. } #ifndef LINUX_BUILD - if (!quiet) - { - std::cout << "Done. Press any key to continue" << std::endl; - cin.ignore(); - } + if (!quiet) + { + std::cout << "Done. Press any key to continue" << std::endl; + cin.ignore(); + } #endif DF->Detach(); return 0; From 1a93c737375a86b0cde6f06c22eff4d54b4a6fc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Wed, 17 Nov 2010 04:48:06 +0100 Subject: [PATCH 51/94] Big chunk of windows 31.18 offsets. --- data/Memory-ng.xml | 86 ++++++++++++++++++++++++++++ library/VersionInfo.cpp | 49 ++++++++++++++++ library/VersionInfoFactory.cpp | 8 +-- library/include/dfhack/VersionInfo.h | 4 ++ 4 files changed, 143 insertions(+), 4 deletions(-) diff --git a/data/Memory-ng.xml b/data/Memory-ng.xml index b35de2f82..702d1a273 100644 --- a/data/Memory-ng.xml +++ b/data/Memory-ng.xml @@ -1784,6 +1784,92 @@ + + + + + +
+ +
+
+ + + + +
+
+
+
+
+ + +
+ + + + +
+ + +
+ + + +
+
+ + + + 0x016a12c0 vector + + +
MAYBE... THE DETAILS WILL BE DIFFERENT +
+ WTF IS THIS, I DON'T EVEN... +
+
+
+ + +
+ + +
+
+ + + + +
+ List of offsets in the VTable : + + + + + + + + + + (in the vtable) + + +
+
+
+ + + .-"""-. ' \ diff --git a/library/VersionInfo.cpp b/library/VersionInfo.cpp index f63dc0930..7773b7470 100644 --- a/library/VersionInfo.cpp +++ b/library/VersionInfo.cpp @@ -180,6 +180,18 @@ void OffsetGroup::setOffset (const string & key, const string & value, const INV else throw Error::MissingMemoryDefinition("offset", getFullName() + key); } +void OffsetGroup::setOffsetValidity (const string & key, const INVAL_TYPE inval) +{ + if(inval != NOT_SET) + { + int32_Iter it = OGd->offsets.find(key); + if(it != OGd->offsets.end()) + { + (*it).second.first = inval; + } + else throw Error::MissingMemoryDefinition("offset", getFullName() + key); + } +} void OffsetGroup::setAddress (const string & key, const string & value, const INVAL_TYPE inval) { @@ -194,6 +206,19 @@ void OffsetGroup::setAddress (const string & key, const string & value, const IN else throw Error::MissingMemoryDefinition("address", getFullName() + key); } +void OffsetGroup::setAddressValidity (const string & key, const INVAL_TYPE inval) +{ + if(inval != NOT_SET) + { + uint32_Iter it = OGd->addresses.find(key); + if(it != OGd->addresses.end()) + { + (*it).second.first = inval; + } + else throw Error::MissingMemoryDefinition("address", getFullName() + key); + } +} + void OffsetGroup::setHexValue (const string & key, const string & value, const INVAL_TYPE inval) { @@ -207,6 +232,18 @@ void OffsetGroup::setHexValue (const string & key, const string & value, const I else throw Error::MissingMemoryDefinition("hexvalue", getFullName() + key); } +void OffsetGroup::setHexValueValidity (const string & key, const INVAL_TYPE inval) +{ + if(inval != NOT_SET) + { + uint32_Iter it = OGd->hexvals.find(key); + if(it != OGd->hexvals.end()) + { + (*it).second.first = inval; + } + else throw Error::MissingMemoryDefinition("hexvalue", getFullName() + key); + } +} void OffsetGroup::setString (const string & key, const string & value, const INVAL_TYPE inval) { @@ -220,6 +257,18 @@ void OffsetGroup::setString (const string & key, const string & value, const INV else throw Error::MissingMemoryDefinition("string", getFullName() + key); } +void OffsetGroup::setStringValidity (const string & key, const INVAL_TYPE inval) +{ + if(inval != NOT_SET) + { + strings_Iter it = OGd->strings.find(key); + if(it != OGd->strings.end()) + { + (*it).second.first = inval; + } + else throw Error::MissingMemoryDefinition("string", getFullName() + key); + } +} // Get named address uint32_t OffsetGroup::getAddress (const string & key) diff --git a/library/VersionInfoFactory.cpp b/library/VersionInfoFactory.cpp index 686a426e4..e74ca2b44 100644 --- a/library/VersionInfoFactory.cpp +++ b/library/VersionInfoFactory.cpp @@ -292,7 +292,7 @@ void VersionInfoFactory::ParseOffsets(TiXmlElement * parent, VersionInfo* target } else { - // ERROR, missing attribute + currentGroup->setAddressValidity(cstr_name, child_inval); } } else if(type == "offset") @@ -309,7 +309,7 @@ void VersionInfoFactory::ParseOffsets(TiXmlElement * parent, VersionInfo* target } else { - // ERROR, missing attribute + currentGroup->setOffsetValidity(cstr_name, child_inval); } } else if(type == "string") @@ -326,7 +326,7 @@ void VersionInfoFactory::ParseOffsets(TiXmlElement * parent, VersionInfo* target } else { - // ERROR, missing attribute + currentGroup->setStringValidity(cstr_name, child_inval); } } else if(type == "hexvalue") @@ -343,7 +343,7 @@ void VersionInfoFactory::ParseOffsets(TiXmlElement * parent, VersionInfo* target } else { - // ERROR, missing attribute + currentGroup->setHexValueValidity(cstr_name, child_inval); } } diff --git a/library/include/dfhack/VersionInfo.h b/library/include/dfhack/VersionInfo.h index e01b8f115..b5c7dac14 100644 --- a/library/include/dfhack/VersionInfo.h +++ b/library/include/dfhack/VersionInfo.h @@ -76,9 +76,13 @@ namespace DFHack OffsetGroup * getGroup ( const std::string & name ); void setOffset (const std::string& key, const std::string& value, const DFHack::INVAL_TYPE inval = IS_VALID); + void setOffsetValidity(const std::string& key, const DFHack::INVAL_TYPE inval = IS_VALID); void setAddress (const std::string& key, const std::string& value, const DFHack::INVAL_TYPE inval = IS_VALID); + void setAddressValidity(const std::string& key, const DFHack::INVAL_TYPE inval = IS_VALID); void setHexValue (const std::string& key, const std::string& value, const DFHack::INVAL_TYPE inval = IS_VALID); + void setHexValueValidity(const std::string& key, const DFHack::INVAL_TYPE inval = IS_VALID); void setString (const std::string& key, const std::string& value, const DFHack::INVAL_TYPE inval = IS_VALID); + void setStringValidity(const std::string& key, const DFHack::INVAL_TYPE inval = IS_VALID); std::string PrintOffsets(int indentation); std::string getName(); std::string getFullName(); From 88e076c50722f9d5de960881597078a43795ac40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Wed, 17 Nov 2010 05:03:25 +0100 Subject: [PATCH 52/94] Slab! --- data/Memory-ng.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/data/Memory-ng.xml b/data/Memory-ng.xml index 702d1a273..212c87b7d 100644 --- a/data/Memory-ng.xml +++ b/data/Memory-ng.xml @@ -664,6 +664,7 @@ +
= *p ) - *l += *p - '0'; - break; - } - } - } - - //may be useful for some situations - inline uint32_t sum() const - { - return 0L + north + south + east + west; - } - - //Gives a string that represents the direction. - //This is a static string, overwritten with every call! - //Support values > 2 even though they should never happen. - //Copy string if it will be used. - inline char * getStr() const - { - static char str[16]; - //type punning trick - *( (uint64_t *)str ) = *( (uint64_t *)"--------" ); - str[8]=0; - #define DIRECTION(x,i,c) \ - if(x){ \ - str[i]=c; \ - if(1==x) ; \ - else if(2==x) str[i+1]=c; \ - else str[i+1]='0'+x; \ - } - - DIRECTION(north,0,'N') - DIRECTION(south,2,'S') - DIRECTION(west,4,'W') - DIRECTION(east,6,'E') - #undef DIRECTION - return str; - } - - - }; - - struct TileRow - { - const char * name; - TileClass c; - TileMaterial m; - TileVariant v; - TileSpecial s; - TileDirection d; - }; - - #define TILE_TYPE_ARRAY_LENGTH 520 - - const TileRow tileTypeTable[TILE_TYPE_ARRAY_LENGTH] = - { - // 0 - {"void",EMPTY, AIR, VAR_1}, - {"ramp top",RAMP_TOP, AIR, VAR_1}, - {"pool",FLOOR, SOIL, VAR_1, TILE_POOL}, - {0, EMPTY, AIR, VAR_1}, - {0, EMPTY, AIR, VAR_1}, - {0, EMPTY, AIR, VAR_1}, - {0, EMPTY, AIR, VAR_1}, - {0, EMPTY, AIR, VAR_1}, - {0, EMPTY, AIR, VAR_1}, - {0, EMPTY, AIR, VAR_1}, - - // 10 - {0, EMPTY, AIR, VAR_1}, - {0, EMPTY, AIR, VAR_1}, - {0, EMPTY, AIR, VAR_1}, - {0, EMPTY, AIR, VAR_1}, - {0, EMPTY, AIR, VAR_1}, - {0, EMPTY, AIR, VAR_1}, - {0, EMPTY, AIR, VAR_1}, - {0, EMPTY, AIR, VAR_1}, - {0, EMPTY, AIR, VAR_1}, - {"driftwood stack",FLOOR, DRIFTWOOD, VAR_1}, - - // 20 - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {"tree",TREE_OK, SOIL, VAR_1}, - {"ice stair up/down",STAIR_UPDOWN, ICE, VAR_1}, - {"ice stair down",STAIR_DOWN, ICE, VAR_1}, - {"ice stair up",STAIR_UP, ICE, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - - // 30 - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {"empty space",EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {"shrub",SHRUB_OK, SOIL, VAR_1}, - {"chasm",FLOOR, AIR, VAR_1, TILE_ENDLESS }, - {"obsidian stair up/down",STAIR_UPDOWN, OBSIDIAN, VAR_1}, - {"obsidian stair down",STAIR_DOWN, OBSIDIAN, VAR_1}, - {"obsidian stair up",STAIR_UP, OBSIDIAN, VAR_1}, - {"soil stair up/down",STAIR_UPDOWN, SOIL, VAR_1}, - - // 40 - {"soil stair down",STAIR_DOWN, SOIL, VAR_1}, - {"soil stair up",STAIR_UP, SOIL, VAR_1}, - {"eerie pit",FLOOR, HFS, VAR_1, TILE_ENDLESS}, - {"smooth stone floor",FLOOR, STONE, VAR_1 , TILE_SMOOTH }, - {"smooth obsidian floor",FLOOR, OBSIDIAN, VAR_1 , TILE_SMOOTH }, - {"smooth featstone? floor",FLOOR, FEATSTONE, VAR_1 , TILE_SMOOTH }, - {"smooth vein floor",FLOOR, VEIN, VAR_1 , TILE_SMOOTH }, - {"smooth ice floor",FLOOR, ICE, VAR_1 , TILE_SMOOTH }, - {0 ,EMPTY, AIR, VAR_1}, - {"grass stair up/down",STAIR_UPDOWN, GRASS, VAR_1}, - - // 50 - {"grass stair down",STAIR_DOWN, GRASS, VAR_1}, - {"grass stair up",STAIR_UP, GRASS, VAR_1}, - {"grass2 stair up/down",STAIR_UPDOWN, GRASS2, VAR_1}, - {"grass2 stair down",STAIR_DOWN, GRASS2, VAR_1}, - {"grass2 stair up",STAIR_UP, GRASS2, VAR_1}, - {"stone stair up/down",STAIR_UPDOWN, STONE, VAR_1}, - {"stone stair down",STAIR_DOWN, STONE, VAR_1}, - {"stone stair up",STAIR_UP, STONE, VAR_1}, - {"vein stair up/down",STAIR_UPDOWN, VEIN, VAR_1}, - {"vein stair down",STAIR_DOWN, VEIN, VAR_1}, - - // 60 - {"vein stair up",STAIR_UP, VEIN, VAR_1}, - {"featstone? stair up/down",STAIR_UPDOWN, FEATSTONE, VAR_1}, - {"featstone? stair down",STAIR_DOWN, FEATSTONE, VAR_1}, - {"featstone? stair up",STAIR_UP, FEATSTONE, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {"stone fortification",FORTIFICATION, STONE, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {"campfire",FLOOR, CAMPFIRE, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - - // 70 - {"fire",FLOOR, FIRE, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {"stone pillar",PILLAR, STONE, VAR_1}, - - //80 - {"obsidian pillar",PILLAR, OBSIDIAN, VAR_1}, - {"featstone? pillar",PILLAR, FEATSTONE, VAR_1}, - {"vein pillar",PILLAR, VEIN, VAR_1}, - {"ice pillar",PILLAR, ICE, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {"waterfall landing",FLOOR, SOIL, VAR_1, TILE_WATERFALL }, // verify material - - // 90 - {"river source",FLOOR, SOIL, VAR_1, TILE_RIVER_SOURCE }, // verify material - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - - // 100 - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - - // 110 - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - - // 120 - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - - // 130 - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - - // 140 - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - - // 150 - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - - // 160 - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - - // 170 - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {"cracked stone wall" ,WALL, STONE, VAR_1, TILE_CRACKED }, - {"damaged stone wall" ,WALL, STONE, VAR_1, TILE_DAMAGED }, - {"worn stone wall" ,WALL, STONE, VAR_1, TILE_WORN }, - {0 ,EMPTY, AIR, VAR_1}, - - // 180 - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - - // 190 - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - - // 200 - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - - // 210 - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {"stone wall" ,WALL, STONE, VAR_1}, - - // 220 - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - - // 230 - {0 ,EMPTY, AIR, VAR_1}, - {"sapling" ,SAPLING_OK, SOIL, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {"dry grass ramp" ,RAMP, GRASS_DRY, VAR_1}, - {"dead grass ramp" ,RAMP, GRASS_DEAD, VAR_1}, - {"grass ramp" ,RAMP, GRASS, VAR_1}, - {"grass ramp" ,RAMP, GRASS2, VAR_1}, - {"stone ramp" ,RAMP, STONE, VAR_1}, - {"obsidian ramp" ,RAMP, OBSIDIAN, VAR_1}, - {"featstone? ramp" ,RAMP, FEATSTONE, VAR_1}, - - // 240 - {"vein ramp" ,RAMP, VEIN, VAR_1}, - {"soil ramp" ,RAMP, SOIL, VAR_1}, - {"ashes" ,FLOOR, ASHES, VAR_1}, - {"ashes" ,FLOOR, ASHES, VAR_2}, - {"ashes" ,FLOOR, ASHES, VAR_3}, - {"ice ramp" ,RAMP, ICE, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - - // 250 - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {"ice floor" ,FLOOR, ICE, VAR_2}, - {"ice floor" ,FLOOR, ICE, VAR_3}, - - // 260 - {"ice floor" ,FLOOR, ICE, VAR_4}, - {"furrowed soil" ,FLOOR, SOIL, VAR_1}, - {"ice floor" ,FLOOR, ICE, VAR_1}, - {"semi-molten rock" ,WALL, MAGMA, VAR_1},// unminable magma wall - {"magma" ,FLOOR, MAGMA, VAR_1}, - {"soil wall" ,WALL, SOIL, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {"glowing floor" ,FLOOR, CYAN_GLOW, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {"smooth obsidian wall RD2",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "--SS--E-" }, - - // 270 - {"smooth obsidian wall R2D",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "--S---EE" }, - {"smooth obsidian wall R2U",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "N-----EE" }, - {"smooth obsidian wall RU2",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "NN----E-" }, - {"smooth obsidian wall L2U",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "N---WW--" }, - {"smooth obsidian wall LU2",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "NN--W---" }, - {"smooth obsidian wall L2D",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "--S-WW--" }, - {"smooth obsidian wall LD2",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "--SSW---" }, - {"smooth obsidian wall LRUD",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH ,"N-S-W-E-" }, - {"smooth obsidian wall RUD",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "N-S---E-" }, - {"smooth obsidian wall LRD",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "--S-W-E-" }, - - // 280 - {"smooth obsidian wall LRU",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "N---W-E-" }, - {"smooth obsidian wall LUD",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "N-S-W---" }, - {"smooth obsidian wall RD",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "--S---E-" }, - {"smooth obsidian wall RU",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "N-----E-" }, - {"smooth obsidian wall LU",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "N---W---" }, - {"smooth obsidian wall LD",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "--S-W---" }, - {"smooth obsidian wall UD",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "N-S-----" }, - {"smooth obsidian wall LR",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "----W-E-" }, - {"smooth featstone wall RD2",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "--SS--E-" }, - {"smooth featstone wall R2D",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "--S---EE" }, - - // 290 - {"smooth featstone wall R2U",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "N-----EE" }, - {"smooth featstone wall RU2",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "NN----E-" }, - {"smooth featstone wall L2U",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "N---WW--" }, - {"smooth featstone wall LU2",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "NN--W---" }, - {"smooth featstone wall L2D",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "--S-WW--" }, - {"smooth featstone wall LD2",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "--SSW---" }, - {"smooth featstone wall LRUD",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH ,"N-S-W-E-" }, - {"smooth featstone wall RUD",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "N-S---E-" }, - {"smooth featstone wall LRD",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "--S-W-E-" }, - {"smooth featstone wall LRU",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "N---W-E-" }, - - //300 - {"smooth featstone wall LUD",WALL,FEATSTONE,VAR_1, TILE_SMOOTH , "N-S-W---" }, - {"smooth featstone wall RD",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "--S---E-" }, - {"smooth featstone wall RU",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "N-----E-" }, - {"smooth featstone wall LU",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "N---W---" }, - {"smooth featstone wall LD",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "--S-W---" }, - {"smooth featstone wall UD",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "N-S-----" }, - {"smooth featstone wall LR",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "----W-E-" }, - {"smooth stone wall RD2",WALL,STONE,VAR_1 , TILE_SMOOTH , "--SS--E-" }, - {"smooth stone wall R2D",WALL,STONE,VAR_1 , TILE_SMOOTH , "--S---EE" }, - {"smooth stone wall R2U",WALL,STONE,VAR_1 , TILE_SMOOTH , "N-----EE" }, - - //310 - {"smooth stone wall RU2",WALL,STONE,VAR_1 , TILE_SMOOTH , "NN----E-" }, - {"smooth stone wall L2U",WALL,STONE,VAR_1 , TILE_SMOOTH , "N---WW--" }, - {"smooth stone wall LU2",WALL,STONE,VAR_1 , TILE_SMOOTH , "NN--W---" }, - {"smooth stone wall L2D",WALL,STONE,VAR_1 , TILE_SMOOTH , "--S-WW--" }, - {"smooth stone wall LD2",WALL,STONE,VAR_1 , TILE_SMOOTH , "--SSW---" }, - {"smooth stone wall LRUD",WALL,STONE,VAR_1 , TILE_SMOOTH , "N-S-W-E-" }, - {"smooth stone wall RUD",WALL,STONE,VAR_1 , TILE_SMOOTH , "N-S---E-" }, - {"smooth stone wall LRD",WALL,STONE,VAR_1 , TILE_SMOOTH , "--S-W-E-" }, - {"smooth stone wall LRU",WALL,STONE,VAR_1 , TILE_SMOOTH , "N---W-E-" }, - {"smooth stone wall LUD",WALL,STONE,VAR_1 , TILE_SMOOTH , "N-S-W---" }, - - //320 - {"smooth stone wall RD",WALL,STONE,VAR_1 , TILE_SMOOTH , "--S---E-" }, - {"smooth stone wall RU",WALL,STONE,VAR_1 , TILE_SMOOTH , "N-----E-" }, - {"smooth stone wall LU",WALL,STONE,VAR_1 , TILE_SMOOTH , "N---W---" }, - {"smooth stone wall LD",WALL,STONE,VAR_1 , TILE_SMOOTH , "--S-W---" }, - {"smooth stone wall UD",WALL,STONE,VAR_1 , TILE_SMOOTH , "N-S-----" }, - {"smooth stone wall LR",WALL,STONE,VAR_1 , TILE_SMOOTH , "----W-E-" }, - {"obsidian fortification",FORTIFICATION,OBSIDIAN,VAR_1}, - {"featstone? fortification",FORTIFICATION,FEATSTONE,VAR_1}, - {"cracked obsidian wall",WALL,OBSIDIAN,VAR_1, TILE_CRACKED }, - {"damaged obsidian wall",WALL,OBSIDIAN,VAR_1, TILE_DAMAGED }, - - // 330 - {"worn obsidian wall",WALL,OBSIDIAN,VAR_1}, - {"obsidian wall",WALL,OBSIDIAN,VAR_1}, - /*MAPTILE_FEATSTONE_WALL_WORN1, - MAPTILE_FEATSTONE_WALL_WORN2, - MAPTILE_FEATSTONE_WALL_WORN3, - MAPTILE_FEATSTONE_WALL,*/ - {"cracked featstone wall",WALL,STONE,VAR_1, TILE_CRACKED }, - {"damaged featstone wall",WALL,STONE,VAR_1, TILE_DAMAGED }, - {"worn featstone wall",WALL,STONE,VAR_1, TILE_WORN }, - {"featstone wall",WALL,STONE,VAR_1}, - {"stone floor",FLOOR,STONE,VAR_1}, - {"stone floor",FLOOR,STONE,VAR_2}, - {"stone floor",FLOOR,STONE,VAR_3}, - {"stone floor",FLOOR,STONE,VAR_4}, - - // 340 - {"obsidian floor",FLOOR,OBSIDIAN,VAR_1}, - {"obsidian floor",FLOOR,OBSIDIAN,VAR_2}, - {"obsidian floor",FLOOR,OBSIDIAN,VAR_3}, - {"obsidian floor",FLOOR,OBSIDIAN,VAR_4}, - {"featstone floor 1",FLOOR,FEATSTONE,VAR_1}, - {"featstone floor 2",FLOOR,FEATSTONE,VAR_2}, - {"featstone floor 3",FLOOR,FEATSTONE,VAR_3}, - {"featstone floor 4",FLOOR,FEATSTONE,VAR_4}, - {"grass 1",FLOOR,GRASS,VAR_1}, - {"grass 2",FLOOR,GRASS,VAR_2}, - - // 350 - {"grass 3",FLOOR,GRASS,VAR_3}, - {"grass 4",FLOOR,GRASS,VAR_4}, - {"soil floor",FLOOR,SOIL,VAR_1}, - {"soil floor",FLOOR,SOIL,VAR_2}, - {"soil floor",FLOOR,SOIL,VAR_3}, - {"soil floor",FLOOR,SOIL,VAR_4}, - {"wet soil floor",FLOOR,SOIL,VAR_1}, - {"wet soil floor",FLOOR,SOIL,VAR_2}, - {"wet soil floor",FLOOR,SOIL,VAR_3}, - {"wet soil floor",FLOOR,SOIL,VAR_4}, - - // 360 - {"ice fortification",FORTIFICATION,ICE,VAR_1}, - {"cracked ice wall",WALL,ICE,VAR_1, TILE_CRACKED}, - {"damaged ice wall",WALL,ICE,VAR_1, TILE_DAMAGED}, - {"worn ice wall",WALL,ICE,VAR_1, TILE_WORN }, - {"ice wall",WALL,ICE,VAR_1}, - {"river N",FLOOR,SOIL,VAR_1, TILE_RIVER , "N" }, - {"river S",FLOOR,SOIL,VAR_1, TILE_RIVER , "S" }, - {"river E",FLOOR,SOIL,VAR_1, TILE_RIVER , "E" }, - {"river W",FLOOR,SOIL,VAR_1, TILE_RIVER , "W" }, - {"river NW",FLOOR,SOIL,VAR_1, TILE_RIVER, "NW"}, - - //370 - {"river NE",FLOOR,SOIL,VAR_1, TILE_RIVER , "NE" }, - {"river SW",FLOOR,SOIL,VAR_1, TILE_RIVER , "SW" }, - {"river SE",FLOOR,SOIL,VAR_1, TILE_RIVER , "SE" }, - {"stream bed N",FLOOR,SOIL,VAR_1, TILE_STREAM , "N" }, - {"stream bed S",FLOOR,SOIL,VAR_1, TILE_STREAM , "S" }, - {"stream bed E",FLOOR,SOIL,VAR_1, TILE_STREAM , "E" }, - {"stream bed W",FLOOR,SOIL,VAR_1, TILE_STREAM , "W" }, - {"stream bed NW",FLOOR,SOIL,VAR_1, TILE_STREAM, "NW" }, - {"stream bed NE",FLOOR,SOIL,VAR_1, TILE_STREAM, "NE" }, - {"stream bed SW",FLOOR,SOIL,VAR_1, TILE_STREAM, "SW" }, - - // 380 - {"stream bed SE",FLOOR,SOIL,VAR_1, TILE_STREAM, "SE" }, - {"stream top",FLOOR,SOIL,VAR_1, TILE_STREAM_TOP }, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {"dry grass 1",FLOOR,GRASS_DRY,VAR_1}, - {"dry grass 2",FLOOR,GRASS_DRY,VAR_2}, - {"dry grass 3",FLOOR,GRASS_DRY,VAR_3}, - - // 390 - {"dry grass 4",FLOOR,GRASS_DRY,VAR_4}, - {"dead tree",TREE_DEAD,SOIL,VAR_1}, - {"dead sapling",SAPLING_DEAD,SOIL,VAR_1}, - {"dead shrub",SHRUB_DEAD,SOIL,VAR_1}, - {"dead grass 1",FLOOR,GRASS_DEAD,VAR_1}, - {"dead grass 2",FLOOR,GRASS_DEAD,VAR_2}, - {"dead grass 3",FLOOR,GRASS_DEAD,VAR_3}, - {"dead grass 4",FLOOR,GRASS_DEAD,VAR_4}, - {"grass B1",FLOOR,GRASS2,VAR_1}, - {"grass B2",FLOOR,GRASS2,VAR_2}, - - // 400 - {"grass B3",FLOOR,GRASS2,VAR_3}, - {"grass B4",FLOOR,GRASS2,VAR_4}, - {"boulder",BOULDER,STONE,VAR_1}, - {"obsidian boulder",BOULDER,OBSIDIAN,VAR_1}, - {"featstone? boulder",BOULDER,FEATSTONE,VAR_1}, - {"pebbles 1",PEBBLES,STONE,VAR_1}, - {"pebbles 2",PEBBLES,STONE,VAR_2}, - {"pebbles 3",PEBBLES,STONE,VAR_3}, - {"pebbles 4",PEBBLES,STONE,VAR_4}, - {"obsidian shards",PEBBLES,OBSIDIAN,VAR_1}, - - // 410 - {"obsidian shards",PEBBLES,OBSIDIAN,VAR_2}, - {"obsidian shards",PEBBLES,OBSIDIAN,VAR_3}, - {"obsidian shards",PEBBLES,OBSIDIAN,VAR_4}, - {"featstone? pebbles",PEBBLES,FEATSTONE,VAR_1}, - {"featstone? pebbles",PEBBLES,FEATSTONE,VAR_2}, - {"featstone? pebbles",PEBBLES,FEATSTONE,VAR_3}, - {"featstone? pebbles",PEBBLES,FEATSTONE,VAR_4}, - {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "--SS--E-"}, - {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "--S---EE"}, - {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N-----EE" }, - - // 420 - {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "NN----E-"}, - {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N---WW--"}, - {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "NN--W---"}, - {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "--S-WW--" }, - {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "--SSW---"}, - {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N-S-W-E-"}, - {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N-S---E-"}, - {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "--S-W-E-"}, - {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N---W-E-"}, - {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N-S-W---"}, - - // 430 - {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "--S---E-"}, - {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N-----E-"}, - {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N---W---"}, - {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "--S-W---"}, - {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N-S-----"}, - {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "----W-E-"}, - {"vein fortification",FORTIFICATION,VEIN,VAR_1}, - {"cracked vein wall",WALL,VEIN,VAR_1, TILE_CRACKED }, - {"damaged vein wall",WALL,VEIN,VAR_1, TILE_DAMAGED }, - {"worn vein wall",WALL,VEIN,VAR_1 , TILE_WORN }, - - // 440 - {"vein wall",WALL,VEIN,VAR_1}, - {"vein floor",FLOOR,VEIN,VAR_1}, - {"vein floor",FLOOR,VEIN,VAR_2}, - {"vein floor",FLOOR,VEIN,VAR_3}, - {"vein floor",FLOOR,VEIN,VAR_4}, - {"vein boulder",BOULDER,VEIN,VAR_1}, - {"vein pebbles",PEBBLES,VEIN,VAR_1}, - {"vein pebbles",PEBBLES,VEIN,VAR_2}, - {"vein pebbles",PEBBLES,VEIN,VAR_3}, - {"vein pebbles",PEBBLES,VEIN,VAR_4}, - - // 450 - {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "--SS--E-"}, - {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "--S---EE" }, - {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N-----EE" }, - {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "NN----E-"}, - {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N---WW--" }, - {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "NN--W---" }, - {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "--S-WW--" }, - {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "--SSW---" }, - {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N-S-W-E-"}, - {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N-S---E-" }, - - // 460 - {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "--S-W-E-" }, - {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N---W-E-" }, - {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N-S-W---"}, - {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "--S---E-"}, - {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N-----E-" }, - {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N---W---" }, - {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "--S-W---" }, - {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N-S-----" }, - {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "----W-E-"}, - {0 ,EMPTY, AIR, VAR_1}, - - // 470 - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - - // 480 - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - - // 490 - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {0 ,EMPTY, AIR, VAR_1}, - {"constructed floor",FLOOR,CONSTRUCTED, VAR_1}, - {"constructed fortification",FORTIFICATION,CONSTRUCTED, VAR_1}, - {"constructed pillar",PILLAR,CONSTRUCTED, VAR_1}, - {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "--SS--E-" }, - {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "--S---EE" }, - {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N-----EE" }, - {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "NN----E-" }, - - // 500 - {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N---WW--" }, - {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "NN--W---" }, - {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "--S-WW--" }, - {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "--SSW---" }, - {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N-S-W-E-" }, - {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N-S---E-" }, - {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "--S-W-E-" }, - {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N---W-E-" }, - {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N-S-W---" }, - {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "--S---E-" }, - - // 510 - {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N-----E-" }, - {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N---W---" }, - {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "--S-W---" }, - {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N-S-----" }, - {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "----W-E-" }, - {"constructed stair up/down",STAIR_UPDOWN,CONSTRUCTED, VAR_1}, - {"constructed stair down",STAIR_DOWN,CONSTRUCTED, VAR_1}, - {"constructed stair up",STAIR_UP,CONSTRUCTED, VAR_1}, - {"constructed ramp",RAMP,CONSTRUCTED, VAR_1}, - {0 ,EMPTY, AIR, VAR_1} // end - }; - - inline - bool isWallTerrain(int in) - { - return tileTypeTable[in].c >= WALL && tileTypeTable[in].c <= FORTIFICATION ; - } - - inline - bool isFloorTerrain(int in) - { - return tileTypeTable[in].c >= FLOOR && tileTypeTable[in].c <= PEBBLES; - } - - inline - bool isRampTerrain(int in) - { - return tileTypeTable[in].c == RAMP; - } - - inline - bool isStairTerrain(int in) - { - return tileTypeTable[in].c >= STAIR_UP && tileTypeTable[in].c <= STAIR_UPDOWN; - } - - inline - bool isOpenTerrain(int in) - { - return tileTypeTable[in].c == EMPTY; - } - - inline - int getVegetationType(int in) - { - return tileTypeTable[in].c; - } - - //zilpin: for convenience, when you'll be using the tile information a lot. - inline const - TileRow * getTileTypeP(int in) - { - if( in<0 || in>=TILE_TYPE_ARRAY_LENGTH ) return 0; - return ( const TileRow * ) &tileTypeTable[in]; - } - - //zilpin: Find the first tile entry which matches the given search criteria. - //All parameters are optional. - //To omit, use the 'invalid' enum for that type (e.g. tileclass_invalid, tilematerial_invalid, etc) - //For tile directions, pass NULL to omit. - //Returns matching index in tileTypeTable, or -1 if none found. - inline - int32_t findTileType( const TileClass tclass, const TileMaterial tmat, const TileVariant tvar, const TileSpecial tspecial, const TileDirection tdir ) - { - int32_t tt; - for(tt=0;tt-1 ) if( tclass != tileTypeTable[tt].c ) continue; - if( tmat>-1 ) if( tmat != tileTypeTable[tt].m ) continue; - if( tvar>-1 ) if( tvar != tileTypeTable[tt].v ) continue; - if( tspecial>-1 ) if( tspecial != tileTypeTable[tt].s ) continue; - if( tdir.whole ) if( tdir.whole != tileTypeTable[tt].d.whole ) continue; - //Match! - return tt; - } - return -1; - } - //Convenience version of the above, to pass strings as the direction - inline - int32_t findTileType( const TileClass tclass, const TileMaterial tmat, const TileVariant tvar, const TileSpecial tspecial, const char *tdirStr ) - { - if(tdirStr){ - TileDirection tdir(tdirStr); - return findTileType(tclass,tmat,tvar,tspecial, tdir ); - }else{ - return findTileType(tclass,tmat,tvar,tspecial, 0 ); - } - } - - - //zilpin: Find a tile type similar to the one given, but with a different class. - //Useful for tile-editing operations. - //If no match found, returns the sourceType - //Definitely needs improvement for wall directions, etc. - inline - int32_t findSimilarTileType( const int32_t sourceTileType, const TileClass tclass ){ - int32_t tt, maybe=0, match=0; - int value=0, matchv=0; - const TileRow *source = &tileTypeTable[sourceTileType]; - const char * sourcename = source->name; - const uint32_t sourcenameint = *((const uint32_t *)sourcename); - - #ifdef assert - assert( sourceTileType >=0 && sourceTileType < TILE_TYPE_ARRAY_LENGTH ); - #endif - - for(tt=0;tts != tileTypeTable[tt].s ) continue; - - maybe=tt; value=0; - //Material is high-value match - if( tileTypeTable[tt].m == source->m ) value|=8; - //Direction is medium value match - if( tileTypeTable[tt].d.whole == source->d.whole ) value|=4; - //Variant is low-value match - if( tileTypeTable[tt].v == source->v ) value|=1; - - //Check value against last match - if( value>matchv ){ - match=tt; - matchv=value; - } - } - } - if( match ) return match; - return sourceTileType; - } -} - - - -#endif // TILETYPES_H_INCLUDED +/* +www.sourceforge.net/projects/dfhack +Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#ifndef TILETYPES_H_INCLUDED +#define TILETYPES_H_INCLUDED + +#include "DFPragma.h" + +namespace DFHack +{ + + // tile class -- determines the general shape of the tile + // enum and lookup table for string names created using X macros + #define TILECLASS_MACRO \ + X(EMPTY, "") \ + X(WALL, "") \ + X(PILLAR, "") \ + X(FORTIFICATION, "") \ + X(STAIR_UP, "") \ + X(STAIR_DOWN, "") \ + X(STAIR_UPDOWN, "") \ + X(RAMP, "ramps have no direction" ) \ + X(RAMP_TOP, "used for pathing?" ) \ + X(FLOOR, "") \ + X(TREE_DEAD, "") \ + X(TREE_OK, "") \ + X(SAPLING_DEAD, "") \ + X(SAPLING_OK, "") \ + X(SHRUB_DEAD, "") \ + X(SHRUB_OK, "") \ + X(BOULDER, "") \ + X(PEBBLES, "") + //end TILECLASS_MACRO + + //define tile class enum + #define X(name,comment) name, + enum TileClass { + tileclass_invalid=-1, + TILECLASS_MACRO + tileclass_count, + }; + #undef X + + extern const char *TileClassString[]; + + #define TILEMATERIAL_MACRO \ + X(AIR, "empty" ) \ + X(SOIL, "ordinary soil. material depends on geology" ) \ + X(STONE, "ordinary layer stone. material depends on geology" ) \ + X(FEATSTONE, "map special stone. used for things like hell, the hell temple or adamantine tubes. material depends on local/global special" ) \ + X(OBSIDIAN, "cast obsidian" ) \ + X(VEIN, "vein stone. material depends on mineral veins present" ) \ + X(ICE, "frozen water... not much to say. you can determine what was on the tile before it froze by looking into the 'ice vein' objects" ) \ + X(GRASS, "grass (has 4 variants)" ) \ + X(GRASS2, "grass (has 4 variants)" ) \ + X(GRASS_DEAD, "dead grass (has 4 variants)" ) \ + X(GRASS_DRY, "dry grass (has 4 variants)" ) \ + X(DRIFTWOOD, "non-specified wood - normally on top of the local layer stone/soil." ) \ + X(HFS, "the stuff demon pits are made of - this makes them different from ordinary pits." ) \ + X(MAGMA, "material for semi-molten rock and 'magma flow' tiles" ) \ + X(CAMPFIRE, "human armies make them when they siege. The original tile may be lost?" ) \ + X(FIRE, "burning grass" ) \ + X(ASHES, "what remains from a FIRE" ) \ + X(CONSTRUCTED,"tile material depends on the construction present" ) \ + X(CYAN_GLOW, "the glowy stuff that disappears from the demon temple when you take the sword." ) + //end TILEMATERIAL_MACRO + + // material enum + #define X(name,comment) name, + enum TileMaterial { + tilematerial_invalid=-1, + TILEMATERIAL_MACRO + tilematerial_count, + }; + #undef X + + + extern const char *TileMaterialString[]; + + // Special specials of the tile. + // Not the best way to do this, but compatible with existing code. + // When the TileType class gets created, everything should be re-thought. + #define TILESPECIAL_MACRO \ + X(NORMAL, "Default for all type, nothing present" ) \ + X(SPECIAL, "General purpose, for any unique tile which can not otherwise be differenciated" ) \ + X(POOL, "Murky Pool, will gather water from rain" ) \ + X(STREAM, "Streams (and brooks too? maybe?)" ) \ + X(STREAM_TOP, "The walkable surface of a stream/brook" ) \ + X(RIVER_SOURCE, "Rivers Source, when it exists on a map" ) \ + X(RIVER, "Rivers, and their entering and exiting tiles" ) \ + X(WATERFALL, "Special case for Waterfall Landing. How's this used?" ) \ + X(ENDLESS, "Eerie Pit and Old Chasm/Endless Pit" ) \ + X(CRACKED, "Walls being dug" ) \ + X(DAMAGED, "Walls being dug" ) \ + X(WORN, "Walls being dug ??" ) \ + X(SMOOTH, "Walls and floors." ) + //end TILESPECIAL_MACRO + + //special enum + #define X(name,comment) TILE_##name, + enum TileSpecial { + tilespecial_invalid=-1, + TILESPECIAL_MACRO + tilespecial_count, + }; + #undef X + + extern const char *TileSpecialString[]; + + // variants are used for tiles, where there are multiple variants of the same - like grass floors + enum TileVariant + { + tilevariant_invalid=-1, + VAR_1, //Yes, the value of VAR_1 is 0. It's legacy. Deal with it. + VAR_2, + VAR_3, + VAR_4, + }; + + + //Mainly walls and rivers + //Byte values are used because walls can have either 1 or 2 in any given direction. + const int TileDirectionCount = 4; + union TileDirection + { + uint32_t whole; + unsigned char b[TileDirectionCount]; + struct + { + //Maybe should add 'up' and 'down' for Z-levels? + unsigned char north,south,west,east; + }; + + inline TileDirection() + { + whole = 0; + } + TileDirection( uint32_t whole_bits) + { + whole = whole_bits; + } + TileDirection( unsigned char North, unsigned char South, unsigned char West, unsigned char East ) + { + north=North; south=South; east=East; west=West; + } + TileDirection( const char *dir ) + { + //This one just made for fun. + //Supports N S E W + const char *p = dir; + unsigned char *l=0; + north=south=east=west=0; + if(!dir) return; + + for( ;*p;++p) + { + switch(*p) + { + case 'N': //North / Up + case 'n': + ++north; l=&north; break; + case 'S': //South / Down + case 's': + ++south; l=&south; break; + case 'E': //East / Right + case 'e': + ++east; l=&east; break; + case 'W': //West / Left + case 'w': + ++west; l=&west; break; + case '-': + case ' ': + //Explicitly ensure dash and space are ignored. + //Other characters/symbols may be assigned in the future. + break; + default: + if( l && '0' <= *p && '9' >= *p ) + *l += *p - '0'; + break; + } + } + } + + //may be useful for some situations + inline uint32_t sum() const + { + return 0L + north + south + east + west; + } + + //Gives a string that represents the direction. + //This is a static string, overwritten with every call! + //Support values > 2 even though they should never happen. + //Copy string if it will be used. + inline char * getStr() const + { + static char str[16]; + //type punning trick + *( (uint64_t *)str ) = *( (uint64_t *)"--------" ); + str[8]=0; + #define DIRECTION(x,i,c) \ + if(x){ \ + str[i]=c; \ + if(1==x) ; \ + else if(2==x) str[i+1]=c; \ + else str[i+1]='0'+x; \ + } + + DIRECTION(north,0,'N') + DIRECTION(south,2,'S') + DIRECTION(west,4,'W') + DIRECTION(east,6,'E') + #undef DIRECTION + return str; + } + + + }; + + struct TileRow + { + const char * name; + TileClass c; + TileMaterial m; + TileVariant v; + TileSpecial s; + TileDirection d; + }; + + #define TILE_TYPE_ARRAY_LENGTH 520 + + const TileRow tileTypeTable[TILE_TYPE_ARRAY_LENGTH] = + { + // 0 + {"void",EMPTY, AIR, VAR_1}, + {"ramp top",RAMP_TOP, AIR, VAR_1}, + {"pool",FLOOR, SOIL, VAR_1, TILE_POOL}, + {0, EMPTY, AIR, VAR_1}, + {0, EMPTY, AIR, VAR_1}, + {0, EMPTY, AIR, VAR_1}, + {0, EMPTY, AIR, VAR_1}, + {0, EMPTY, AIR, VAR_1}, + {0, EMPTY, AIR, VAR_1}, + {0, EMPTY, AIR, VAR_1}, + + // 10 + {0, EMPTY, AIR, VAR_1}, + {0, EMPTY, AIR, VAR_1}, + {0, EMPTY, AIR, VAR_1}, + {0, EMPTY, AIR, VAR_1}, + {0, EMPTY, AIR, VAR_1}, + {0, EMPTY, AIR, VAR_1}, + {0, EMPTY, AIR, VAR_1}, + {0, EMPTY, AIR, VAR_1}, + {0, EMPTY, AIR, VAR_1}, + {"driftwood stack",FLOOR, DRIFTWOOD, VAR_1}, + + // 20 + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {"tree",TREE_OK, SOIL, VAR_1}, + {"ice stair up/down",STAIR_UPDOWN, ICE, VAR_1}, + {"ice stair down",STAIR_DOWN, ICE, VAR_1}, + {"ice stair up",STAIR_UP, ICE, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + + // 30 + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {"empty space",EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {"shrub",SHRUB_OK, SOIL, VAR_1}, + {"chasm",FLOOR, AIR, VAR_1, TILE_ENDLESS }, + {"obsidian stair up/down",STAIR_UPDOWN, OBSIDIAN, VAR_1}, + {"obsidian stair down",STAIR_DOWN, OBSIDIAN, VAR_1}, + {"obsidian stair up",STAIR_UP, OBSIDIAN, VAR_1}, + {"soil stair up/down",STAIR_UPDOWN, SOIL, VAR_1}, + + // 40 + {"soil stair down",STAIR_DOWN, SOIL, VAR_1}, + {"soil stair up",STAIR_UP, SOIL, VAR_1}, + {"eerie pit",FLOOR, HFS, VAR_1, TILE_ENDLESS}, + {"smooth stone floor",FLOOR, STONE, VAR_1 , TILE_SMOOTH }, + {"smooth obsidian floor",FLOOR, OBSIDIAN, VAR_1 , TILE_SMOOTH }, + {"smooth featstone? floor",FLOOR, FEATSTONE, VAR_1 , TILE_SMOOTH }, + {"smooth vein floor",FLOOR, VEIN, VAR_1 , TILE_SMOOTH }, + {"smooth ice floor",FLOOR, ICE, VAR_1 , TILE_SMOOTH }, + {0 ,EMPTY, AIR, VAR_1}, + {"grass stair up/down",STAIR_UPDOWN, GRASS, VAR_1}, + + // 50 + {"grass stair down",STAIR_DOWN, GRASS, VAR_1}, + {"grass stair up",STAIR_UP, GRASS, VAR_1}, + {"grass2 stair up/down",STAIR_UPDOWN, GRASS2, VAR_1}, + {"grass2 stair down",STAIR_DOWN, GRASS2, VAR_1}, + {"grass2 stair up",STAIR_UP, GRASS2, VAR_1}, + {"stone stair up/down",STAIR_UPDOWN, STONE, VAR_1}, + {"stone stair down",STAIR_DOWN, STONE, VAR_1}, + {"stone stair up",STAIR_UP, STONE, VAR_1}, + {"vein stair up/down",STAIR_UPDOWN, VEIN, VAR_1}, + {"vein stair down",STAIR_DOWN, VEIN, VAR_1}, + + // 60 + {"vein stair up",STAIR_UP, VEIN, VAR_1}, + {"featstone? stair up/down",STAIR_UPDOWN, FEATSTONE, VAR_1}, + {"featstone? stair down",STAIR_DOWN, FEATSTONE, VAR_1}, + {"featstone? stair up",STAIR_UP, FEATSTONE, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {"stone fortification",FORTIFICATION, STONE, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {"campfire",FLOOR, CAMPFIRE, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + + // 70 + {"fire",FLOOR, FIRE, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {"stone pillar",PILLAR, STONE, VAR_1}, + + //80 + {"obsidian pillar",PILLAR, OBSIDIAN, VAR_1}, + {"featstone? pillar",PILLAR, FEATSTONE, VAR_1}, + {"vein pillar",PILLAR, VEIN, VAR_1}, + {"ice pillar",PILLAR, ICE, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {"waterfall landing",FLOOR, SOIL, VAR_1, TILE_WATERFALL }, // verify material + + // 90 + {"river source",FLOOR, SOIL, VAR_1, TILE_RIVER_SOURCE }, // verify material + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + + // 100 + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + + // 110 + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + + // 120 + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + + // 130 + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + + // 140 + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + + // 150 + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + + // 160 + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + + // 170 + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {"cracked stone wall" ,WALL, STONE, VAR_1, TILE_CRACKED }, + {"damaged stone wall" ,WALL, STONE, VAR_1, TILE_DAMAGED }, + {"worn stone wall" ,WALL, STONE, VAR_1, TILE_WORN }, + {0 ,EMPTY, AIR, VAR_1}, + + // 180 + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + + // 190 + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + + // 200 + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + + // 210 + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {"stone wall" ,WALL, STONE, VAR_1}, + + // 220 + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + + // 230 + {0 ,EMPTY, AIR, VAR_1}, + {"sapling" ,SAPLING_OK, SOIL, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {"dry grass ramp" ,RAMP, GRASS_DRY, VAR_1}, + {"dead grass ramp" ,RAMP, GRASS_DEAD, VAR_1}, + {"grass ramp" ,RAMP, GRASS, VAR_1}, + {"grass ramp" ,RAMP, GRASS2, VAR_1}, + {"stone ramp" ,RAMP, STONE, VAR_1}, + {"obsidian ramp" ,RAMP, OBSIDIAN, VAR_1}, + {"featstone? ramp" ,RAMP, FEATSTONE, VAR_1}, + + // 240 + {"vein ramp" ,RAMP, VEIN, VAR_1}, + {"soil ramp" ,RAMP, SOIL, VAR_1}, + {"ashes" ,FLOOR, ASHES, VAR_1}, + {"ashes" ,FLOOR, ASHES, VAR_2}, + {"ashes" ,FLOOR, ASHES, VAR_3}, + {"ice ramp" ,RAMP, ICE, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + + // 250 + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {"ice floor" ,FLOOR, ICE, VAR_2}, + {"ice floor" ,FLOOR, ICE, VAR_3}, + + // 260 + {"ice floor" ,FLOOR, ICE, VAR_4}, + {"furrowed soil" ,FLOOR, SOIL, VAR_1}, + {"ice floor" ,FLOOR, ICE, VAR_1}, + {"semi-molten rock" ,WALL, MAGMA, VAR_1},// unminable magma wall + {"magma" ,FLOOR, MAGMA, VAR_1}, + {"soil wall" ,WALL, SOIL, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {"glowing floor" ,FLOOR, CYAN_GLOW, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {"smooth obsidian wall RD2",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "--SS--E-" }, + + // 270 + {"smooth obsidian wall R2D",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "--S---EE" }, + {"smooth obsidian wall R2U",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "N-----EE" }, + {"smooth obsidian wall RU2",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "NN----E-" }, + {"smooth obsidian wall L2U",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "N---WW--" }, + {"smooth obsidian wall LU2",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "NN--W---" }, + {"smooth obsidian wall L2D",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "--S-WW--" }, + {"smooth obsidian wall LD2",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "--SSW---" }, + {"smooth obsidian wall LRUD",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH ,"N-S-W-E-" }, + {"smooth obsidian wall RUD",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "N-S---E-" }, + {"smooth obsidian wall LRD",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "--S-W-E-" }, + + // 280 + {"smooth obsidian wall LRU",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "N---W-E-" }, + {"smooth obsidian wall LUD",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "N-S-W---" }, + {"smooth obsidian wall RD",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "--S---E-" }, + {"smooth obsidian wall RU",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "N-----E-" }, + {"smooth obsidian wall LU",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "N---W---" }, + {"smooth obsidian wall LD",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "--S-W---" }, + {"smooth obsidian wall UD",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "N-S-----" }, + {"smooth obsidian wall LR",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "----W-E-" }, + {"smooth featstone wall RD2",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "--SS--E-" }, + {"smooth featstone wall R2D",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "--S---EE" }, + + // 290 + {"smooth featstone wall R2U",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "N-----EE" }, + {"smooth featstone wall RU2",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "NN----E-" }, + {"smooth featstone wall L2U",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "N---WW--" }, + {"smooth featstone wall LU2",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "NN--W---" }, + {"smooth featstone wall L2D",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "--S-WW--" }, + {"smooth featstone wall LD2",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "--SSW---" }, + {"smooth featstone wall LRUD",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH ,"N-S-W-E-" }, + {"smooth featstone wall RUD",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "N-S---E-" }, + {"smooth featstone wall LRD",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "--S-W-E-" }, + {"smooth featstone wall LRU",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "N---W-E-" }, + + //300 + {"smooth featstone wall LUD",WALL,FEATSTONE,VAR_1, TILE_SMOOTH , "N-S-W---" }, + {"smooth featstone wall RD",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "--S---E-" }, + {"smooth featstone wall RU",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "N-----E-" }, + {"smooth featstone wall LU",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "N---W---" }, + {"smooth featstone wall LD",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "--S-W---" }, + {"smooth featstone wall UD",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "N-S-----" }, + {"smooth featstone wall LR",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "----W-E-" }, + {"smooth stone wall RD2",WALL,STONE,VAR_1 , TILE_SMOOTH , "--SS--E-" }, + {"smooth stone wall R2D",WALL,STONE,VAR_1 , TILE_SMOOTH , "--S---EE" }, + {"smooth stone wall R2U",WALL,STONE,VAR_1 , TILE_SMOOTH , "N-----EE" }, + + //310 + {"smooth stone wall RU2",WALL,STONE,VAR_1 , TILE_SMOOTH , "NN----E-" }, + {"smooth stone wall L2U",WALL,STONE,VAR_1 , TILE_SMOOTH , "N---WW--" }, + {"smooth stone wall LU2",WALL,STONE,VAR_1 , TILE_SMOOTH , "NN--W---" }, + {"smooth stone wall L2D",WALL,STONE,VAR_1 , TILE_SMOOTH , "--S-WW--" }, + {"smooth stone wall LD2",WALL,STONE,VAR_1 , TILE_SMOOTH , "--SSW---" }, + {"smooth stone wall LRUD",WALL,STONE,VAR_1 , TILE_SMOOTH , "N-S-W-E-" }, + {"smooth stone wall RUD",WALL,STONE,VAR_1 , TILE_SMOOTH , "N-S---E-" }, + {"smooth stone wall LRD",WALL,STONE,VAR_1 , TILE_SMOOTH , "--S-W-E-" }, + {"smooth stone wall LRU",WALL,STONE,VAR_1 , TILE_SMOOTH , "N---W-E-" }, + {"smooth stone wall LUD",WALL,STONE,VAR_1 , TILE_SMOOTH , "N-S-W---" }, + + //320 + {"smooth stone wall RD",WALL,STONE,VAR_1 , TILE_SMOOTH , "--S---E-" }, + {"smooth stone wall RU",WALL,STONE,VAR_1 , TILE_SMOOTH , "N-----E-" }, + {"smooth stone wall LU",WALL,STONE,VAR_1 , TILE_SMOOTH , "N---W---" }, + {"smooth stone wall LD",WALL,STONE,VAR_1 , TILE_SMOOTH , "--S-W---" }, + {"smooth stone wall UD",WALL,STONE,VAR_1 , TILE_SMOOTH , "N-S-----" }, + {"smooth stone wall LR",WALL,STONE,VAR_1 , TILE_SMOOTH , "----W-E-" }, + {"obsidian fortification",FORTIFICATION,OBSIDIAN,VAR_1}, + {"featstone? fortification",FORTIFICATION,FEATSTONE,VAR_1}, + {"cracked obsidian wall",WALL,OBSIDIAN,VAR_1, TILE_CRACKED }, + {"damaged obsidian wall",WALL,OBSIDIAN,VAR_1, TILE_DAMAGED }, + + // 330 + {"worn obsidian wall",WALL,OBSIDIAN,VAR_1}, + {"obsidian wall",WALL,OBSIDIAN,VAR_1}, + /*MAPTILE_FEATSTONE_WALL_WORN1, + MAPTILE_FEATSTONE_WALL_WORN2, + MAPTILE_FEATSTONE_WALL_WORN3, + MAPTILE_FEATSTONE_WALL,*/ + {"cracked featstone wall",WALL,STONE,VAR_1, TILE_CRACKED }, + {"damaged featstone wall",WALL,STONE,VAR_1, TILE_DAMAGED }, + {"worn featstone wall",WALL,STONE,VAR_1, TILE_WORN }, + {"featstone wall",WALL,STONE,VAR_1}, + {"stone floor",FLOOR,STONE,VAR_1}, + {"stone floor",FLOOR,STONE,VAR_2}, + {"stone floor",FLOOR,STONE,VAR_3}, + {"stone floor",FLOOR,STONE,VAR_4}, + + // 340 + {"obsidian floor",FLOOR,OBSIDIAN,VAR_1}, + {"obsidian floor",FLOOR,OBSIDIAN,VAR_2}, + {"obsidian floor",FLOOR,OBSIDIAN,VAR_3}, + {"obsidian floor",FLOOR,OBSIDIAN,VAR_4}, + {"featstone floor 1",FLOOR,FEATSTONE,VAR_1}, + {"featstone floor 2",FLOOR,FEATSTONE,VAR_2}, + {"featstone floor 3",FLOOR,FEATSTONE,VAR_3}, + {"featstone floor 4",FLOOR,FEATSTONE,VAR_4}, + {"grass 1",FLOOR,GRASS,VAR_1}, + {"grass 2",FLOOR,GRASS,VAR_2}, + + // 350 + {"grass 3",FLOOR,GRASS,VAR_3}, + {"grass 4",FLOOR,GRASS,VAR_4}, + {"soil floor",FLOOR,SOIL,VAR_1}, + {"soil floor",FLOOR,SOIL,VAR_2}, + {"soil floor",FLOOR,SOIL,VAR_3}, + {"soil floor",FLOOR,SOIL,VAR_4}, + {"wet soil floor",FLOOR,SOIL,VAR_1}, + {"wet soil floor",FLOOR,SOIL,VAR_2}, + {"wet soil floor",FLOOR,SOIL,VAR_3}, + {"wet soil floor",FLOOR,SOIL,VAR_4}, + + // 360 + {"ice fortification",FORTIFICATION,ICE,VAR_1}, + {"cracked ice wall",WALL,ICE,VAR_1, TILE_CRACKED}, + {"damaged ice wall",WALL,ICE,VAR_1, TILE_DAMAGED}, + {"worn ice wall",WALL,ICE,VAR_1, TILE_WORN }, + {"ice wall",WALL,ICE,VAR_1}, + {"river N",FLOOR,SOIL,VAR_1, TILE_RIVER , "N" }, + {"river S",FLOOR,SOIL,VAR_1, TILE_RIVER , "S" }, + {"river E",FLOOR,SOIL,VAR_1, TILE_RIVER , "E" }, + {"river W",FLOOR,SOIL,VAR_1, TILE_RIVER , "W" }, + {"river NW",FLOOR,SOIL,VAR_1, TILE_RIVER, "NW"}, + + //370 + {"river NE",FLOOR,SOIL,VAR_1, TILE_RIVER , "NE" }, + {"river SW",FLOOR,SOIL,VAR_1, TILE_RIVER , "SW" }, + {"river SE",FLOOR,SOIL,VAR_1, TILE_RIVER , "SE" }, + {"stream bed N",FLOOR,SOIL,VAR_1, TILE_STREAM , "N" }, + {"stream bed S",FLOOR,SOIL,VAR_1, TILE_STREAM , "S" }, + {"stream bed E",FLOOR,SOIL,VAR_1, TILE_STREAM , "E" }, + {"stream bed W",FLOOR,SOIL,VAR_1, TILE_STREAM , "W" }, + {"stream bed NW",FLOOR,SOIL,VAR_1, TILE_STREAM, "NW" }, + {"stream bed NE",FLOOR,SOIL,VAR_1, TILE_STREAM, "NE" }, + {"stream bed SW",FLOOR,SOIL,VAR_1, TILE_STREAM, "SW" }, + + // 380 + {"stream bed SE",FLOOR,SOIL,VAR_1, TILE_STREAM, "SE" }, + {"stream top",FLOOR,SOIL,VAR_1, TILE_STREAM_TOP }, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {"dry grass 1",FLOOR,GRASS_DRY,VAR_1}, + {"dry grass 2",FLOOR,GRASS_DRY,VAR_2}, + {"dry grass 3",FLOOR,GRASS_DRY,VAR_3}, + + // 390 + {"dry grass 4",FLOOR,GRASS_DRY,VAR_4}, + {"dead tree",TREE_DEAD,SOIL,VAR_1}, + {"dead sapling",SAPLING_DEAD,SOIL,VAR_1}, + {"dead shrub",SHRUB_DEAD,SOIL,VAR_1}, + {"dead grass 1",FLOOR,GRASS_DEAD,VAR_1}, + {"dead grass 2",FLOOR,GRASS_DEAD,VAR_2}, + {"dead grass 3",FLOOR,GRASS_DEAD,VAR_3}, + {"dead grass 4",FLOOR,GRASS_DEAD,VAR_4}, + {"grass B1",FLOOR,GRASS2,VAR_1}, + {"grass B2",FLOOR,GRASS2,VAR_2}, + + // 400 + {"grass B3",FLOOR,GRASS2,VAR_3}, + {"grass B4",FLOOR,GRASS2,VAR_4}, + {"boulder",BOULDER,STONE,VAR_1}, + {"obsidian boulder",BOULDER,OBSIDIAN,VAR_1}, + {"featstone? boulder",BOULDER,FEATSTONE,VAR_1}, + {"pebbles 1",PEBBLES,STONE,VAR_1}, + {"pebbles 2",PEBBLES,STONE,VAR_2}, + {"pebbles 3",PEBBLES,STONE,VAR_3}, + {"pebbles 4",PEBBLES,STONE,VAR_4}, + {"obsidian shards",PEBBLES,OBSIDIAN,VAR_1}, + + // 410 + {"obsidian shards",PEBBLES,OBSIDIAN,VAR_2}, + {"obsidian shards",PEBBLES,OBSIDIAN,VAR_3}, + {"obsidian shards",PEBBLES,OBSIDIAN,VAR_4}, + {"featstone? pebbles",PEBBLES,FEATSTONE,VAR_1}, + {"featstone? pebbles",PEBBLES,FEATSTONE,VAR_2}, + {"featstone? pebbles",PEBBLES,FEATSTONE,VAR_3}, + {"featstone? pebbles",PEBBLES,FEATSTONE,VAR_4}, + {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "--SS--E-"}, + {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "--S---EE"}, + {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N-----EE" }, + + // 420 + {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "NN----E-"}, + {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N---WW--"}, + {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "NN--W---"}, + {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "--S-WW--" }, + {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "--SSW---"}, + {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N-S-W-E-"}, + {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N-S---E-"}, + {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "--S-W-E-"}, + {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N---W-E-"}, + {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N-S-W---"}, + + // 430 + {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "--S---E-"}, + {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N-----E-"}, + {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N---W---"}, + {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "--S-W---"}, + {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N-S-----"}, + {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "----W-E-"}, + {"vein fortification",FORTIFICATION,VEIN,VAR_1}, + {"cracked vein wall",WALL,VEIN,VAR_1, TILE_CRACKED }, + {"damaged vein wall",WALL,VEIN,VAR_1, TILE_DAMAGED }, + {"worn vein wall",WALL,VEIN,VAR_1 , TILE_WORN }, + + // 440 + {"vein wall",WALL,VEIN,VAR_1}, + {"vein floor",FLOOR,VEIN,VAR_1}, + {"vein floor",FLOOR,VEIN,VAR_2}, + {"vein floor",FLOOR,VEIN,VAR_3}, + {"vein floor",FLOOR,VEIN,VAR_4}, + {"vein boulder",BOULDER,VEIN,VAR_1}, + {"vein pebbles",PEBBLES,VEIN,VAR_1}, + {"vein pebbles",PEBBLES,VEIN,VAR_2}, + {"vein pebbles",PEBBLES,VEIN,VAR_3}, + {"vein pebbles",PEBBLES,VEIN,VAR_4}, + + // 450 + {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "--SS--E-"}, + {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "--S---EE" }, + {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N-----EE" }, + {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "NN----E-"}, + {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N---WW--" }, + {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "NN--W---" }, + {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "--S-WW--" }, + {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "--SSW---" }, + {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N-S-W-E-"}, + {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N-S---E-" }, + + // 460 + {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "--S-W-E-" }, + {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N---W-E-" }, + {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N-S-W---"}, + {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "--S---E-"}, + {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N-----E-" }, + {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N---W---" }, + {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "--S-W---" }, + {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N-S-----" }, + {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "----W-E-"}, + {0 ,EMPTY, AIR, VAR_1}, + + // 470 + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + + // 480 + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + + // 490 + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {0 ,EMPTY, AIR, VAR_1}, + {"constructed floor",FLOOR,CONSTRUCTED, VAR_1}, + {"constructed fortification",FORTIFICATION,CONSTRUCTED, VAR_1}, + {"constructed pillar",PILLAR,CONSTRUCTED, VAR_1}, + {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "--SS--E-" }, + {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "--S---EE" }, + {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N-----EE" }, + {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "NN----E-" }, + + // 500 + {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N---WW--" }, + {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "NN--W---" }, + {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "--S-WW--" }, + {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "--SSW---" }, + {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N-S-W-E-" }, + {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N-S---E-" }, + {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "--S-W-E-" }, + {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N---W-E-" }, + {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N-S-W---" }, + {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "--S---E-" }, + + // 510 + {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N-----E-" }, + {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N---W---" }, + {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "--S-W---" }, + {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N-S-----" }, + {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "----W-E-" }, + {"constructed stair up/down",STAIR_UPDOWN,CONSTRUCTED, VAR_1}, + {"constructed stair down",STAIR_DOWN,CONSTRUCTED, VAR_1}, + {"constructed stair up",STAIR_UP,CONSTRUCTED, VAR_1}, + {"constructed ramp",RAMP,CONSTRUCTED, VAR_1}, + {0 ,EMPTY, AIR, VAR_1} // end + }; + + inline + bool isWallTerrain(int in) + { + return tileTypeTable[in].c >= WALL && tileTypeTable[in].c <= FORTIFICATION ; + } + + inline + bool isFloorTerrain(int in) + { + return tileTypeTable[in].c >= FLOOR && tileTypeTable[in].c <= PEBBLES; + } + + inline + bool isRampTerrain(int in) + { + return tileTypeTable[in].c == RAMP; + } + + inline + bool isStairTerrain(int in) + { + return tileTypeTable[in].c >= STAIR_UP && tileTypeTable[in].c <= STAIR_UPDOWN; + } + + inline + bool isOpenTerrain(int in) + { + return tileTypeTable[in].c == EMPTY; + } + + inline + int getVegetationType(int in) + { + return tileTypeTable[in].c; + } + + //zilpin: for convenience, when you'll be using the tile information a lot. + inline const + TileRow * getTileTypeP(int in) + { + if( in<0 || in>=TILE_TYPE_ARRAY_LENGTH ) return 0; + return ( const TileRow * ) &tileTypeTable[in]; + } + + //zilpin: Find the first tile entry which matches the given search criteria. + //All parameters are optional. + //To omit, use the 'invalid' enum for that type (e.g. tileclass_invalid, tilematerial_invalid, etc) + //For tile directions, pass NULL to omit. + //Returns matching index in tileTypeTable, or -1 if none found. + inline + int32_t findTileType( const TileClass tclass, const TileMaterial tmat, const TileVariant tvar, const TileSpecial tspecial, const TileDirection tdir ) + { + int32_t tt; + for(tt=0;tt-1 ) if( tclass != tileTypeTable[tt].c ) continue; + if( tmat>-1 ) if( tmat != tileTypeTable[tt].m ) continue; + if( tvar>-1 ) if( tvar != tileTypeTable[tt].v ) continue; + if( tspecial>-1 ) if( tspecial != tileTypeTable[tt].s ) continue; + if( tdir.whole ) if( tdir.whole != tileTypeTable[tt].d.whole ) continue; + //Match! + return tt; + } + return -1; + } + //Convenience version of the above, to pass strings as the direction + inline + int32_t findTileType( const TileClass tclass, const TileMaterial tmat, const TileVariant tvar, const TileSpecial tspecial, const char *tdirStr ) + { + if(tdirStr){ + TileDirection tdir(tdirStr); + return findTileType(tclass,tmat,tvar,tspecial, tdir ); + }else{ + return findTileType(tclass,tmat,tvar,tspecial, 0 ); + } + } + + + //zilpin: Find a tile type similar to the one given, but with a different class. + //Useful for tile-editing operations. + //If no match found, returns the sourceType + //Definitely needs improvement for wall directions, etc. + inline + int32_t findSimilarTileType( const int32_t sourceTileType, const TileClass tclass ){ + int32_t tt, maybe=0, match=0; + int value=0, matchv=0; + const TileRow *source = &tileTypeTable[sourceTileType]; + + #ifdef assert + assert( sourceTileType >=0 && sourceTileType < TILE_TYPE_ARRAY_LENGTH ); + #endif + + for(tt=0;tts != tileTypeTable[tt].s ) continue; + + maybe=tt; value=0; + //Material is high-value match + if( tileTypeTable[tt].m == source->m ) value|=8; + //Direction is medium value match + if( tileTypeTable[tt].d.whole == source->d.whole ) value|=4; + //Variant is low-value match + if( tileTypeTable[tt].v == source->v ) value|=1; + + //Check value against last match + if( value>matchv ){ + match=tt; + matchv=value; + } + } + } + if( match ) return match; + return sourceTileType; + } +} + + + +#endif // TILETYPES_H_INCLUDED diff --git a/library/modules/Buildings_C.cpp b/library/modules/Buildings_C.cpp index 6017a75e5..ed3e3e74e 100644 --- a/library/modules/Buildings_C.cpp +++ b/library/modules/Buildings_C.cpp @@ -74,7 +74,7 @@ t_customWorkshop* Buildings_ReadCustomWorkshopTypes(DFHackObject* b_Ptr) if(b_Ptr != NULL) { int i; - t_customWorkshop* cw_Ptr; + t_customWorkshop* cw_Ptr = NULL; std::map bTypes; map::iterator bIter; diff --git a/library/modules/Creatures.cpp b/library/modules/Creatures.cpp index 0d26f336b..39e734355 100644 --- a/library/modules/Creatures.cpp +++ b/library/modules/Creatures.cpp @@ -69,7 +69,7 @@ Creatures::Creatures(DFContextShared* _d) { d = new Private; d->d = _d; - Process * p = d->owner = _d->p; + d->owner = _d->p; d->Inited = false; d->Started = false; d->d->InitReadNames(); // throws on error @@ -183,7 +183,6 @@ bool Creatures::ReadCreature (const int32_t index, t_creature & furball) } */ // non-SHM slow path - VersionInfo * minfo = d->d->offset_descriptor; // read pointer from vector at position uint32_t temp = d->p_cre->at (index); @@ -471,6 +470,8 @@ bool Creatures::WriteSex(const uint32_t index, const uint8_t sex) uint32_t temp = d->p_cre->at (index); Process * p = d->owner; p->writeByte (temp + d->creatures.sex_offset, sex); + + return true; } bool Creatures::WriteTraits(const uint32_t index, const t_soul &soul) @@ -596,7 +597,6 @@ 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; - VersionInfo * minfo = d->d->offset_descriptor; DfVector cmats(p, furball->current_job.occupationPtr + d->OG_jobs->getOffset("materials_vector")); mat.resize(cmats.size()); @@ -614,7 +614,6 @@ bool Creatures::ReadJob(const t_creature * furball, vector & mat) 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); } diff --git a/library/modules/Creatures_C.cpp b/library/modules/Creatures_C.cpp index a9b3f9191..297a15460 100644 --- a/library/modules/Creatures_C.cpp +++ b/library/modules/Creatures_C.cpp @@ -84,7 +84,7 @@ t_material* Creatures_ReadJob(DFHackObject* cPtr, const t_creature* furball) if(mat.size() <= 0) return NULL; - t_material* buf; + t_material* buf = NULL; (*alloc_t_material_buffer_callback)(buf, mat.size()); @@ -115,7 +115,7 @@ uint32_t* Creatures_ReadInventoryIdx(DFHackObject* cPtr, const uint32_t index) if(item.size() <= 0) return NULL; - uint32_t* buf; + uint32_t* buf = NULL; (*alloc_uint_buffer_callback)(buf, item.size()); @@ -144,7 +144,7 @@ uint32_t* Creatures_ReadInventoryPtr(DFHackObject* cPtr, const uint32_t index) if(item.size() <= 0) return NULL; - uint32_t* buf; + uint32_t* buf = NULL; (*alloc_uint_buffer_callback)(buf, item.size()); diff --git a/library/modules/Items_C.cpp b/library/modules/Items_C.cpp index f0231617f..bfc31f2f4 100644 --- a/library/modules/Items_C.cpp +++ b/library/modules/Items_C.cpp @@ -58,7 +58,7 @@ char* Items_getItemDescription(DFHackObject* items, uint32_t itemptr, DFHackObje if(desc.size() > 0) { - char* buf; + char* buf = NULL; (*alloc_char_buffer_callback)(buf,desc.size()); if(buf != NULL) @@ -86,7 +86,7 @@ char* Items_getItemClass(DFHackObject* items, int32_t index) if(iclass.size() > 0) { - char* buf; + char* buf = NULL; (*alloc_char_buffer_callback)(buf, iclass.size()); if(buf != NULL) { diff --git a/library/modules/Maps.cpp b/library/modules/Maps.cpp index 124e9bea9..4df9c38a0 100644 --- a/library/modules/Maps.cpp +++ b/library/modules/Maps.cpp @@ -661,7 +661,6 @@ __int16 __userpurge GetGeologicalRegion(__int16 block_X, int X, __i bool Maps::ReadGeology (vector < vector >& assign) { MAPS_GUARD - 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; @@ -736,7 +735,6 @@ bool Maps::ReadLocalFeatures( std::map > & return false; Process * p = d->owner; - VersionInfo * mem = p->getDescriptor(); // deref pointer to the humongo-structure uint32_t base = p->readDWord(d->OG_local_features->getAddress("start_ptr")); if(!base) diff --git a/library/modules/Maps_C.cpp b/library/modules/Maps_C.cpp index 9aacf8a0b..0c5647b16 100644 --- a/library/modules/Maps_C.cpp +++ b/library/modules/Maps_C.cpp @@ -62,12 +62,12 @@ uint16_t* Maps_ReadGeology(DFHackObject* maps) if(((DFHack::Maps*)maps)->ReadGeology(geology)) { - uint16_t* buf; + uint16_t* buf = NULL; uint32_t geoLength = 0; - for(int i = 0; i < geology.size(); i++) + for(unsigned int i = 0; i < geology.size(); i++) { - for(int j = 0; j < geology[i].size(); j++) + for(unsigned int j = 0; j < geology[i].size(); j++) { geoLength += geology[i].size(); } @@ -79,7 +79,7 @@ uint16_t* Maps_ReadGeology(DFHackObject* maps) { uint16_t* bufCopyPtr = buf; - for(int i = 0; i < geology.size(); i++) + for(unsigned int i = 0; i < geology.size(); i++) { copy(geology[i].begin(), geology[i].end(), bufCopyPtr); @@ -107,7 +107,7 @@ t_feature* Maps_ReadGlobalFeatures(DFHackObject* maps) if(featureVec.size() <= 0) return NULL; - t_feature* buf; + t_feature* buf = NULL; (*alloc_t_feature_buffer_callback)(buf, featureVec.size()); @@ -297,6 +297,8 @@ int Maps_WriteEmptyLocalFeature(DFHackObject* maps, uint32_t x, uint32_t y, uint { return ((DFHack::Maps*)maps)->WriteLocalFeature(x, y, z, -1); } + + return -1; } int Maps_WriteGlobalFeature(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, int16_t local) @@ -315,6 +317,8 @@ int Maps_WriteEmptyGlobalFeature(DFHackObject* maps, uint32_t x, uint32_t y, uin { return ((DFHack::Maps*)maps)->WriteGlobalFeature(x, y, z, -1); } + + return -1; } int Maps_ReadBlockFlags(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, t_blockflags* blockflags) diff --git a/library/modules/Materials_C.cpp b/library/modules/Materials_C.cpp index 4fa8b7705..90b16adf9 100644 --- a/library/modules/Materials_C.cpp +++ b/library/modules/Materials_C.cpp @@ -232,7 +232,7 @@ t_matgloss* Materials_getInorganic(DFHackObject* mat) if(materials->inorganic.size() > 0) { - t_matgloss* buf; + t_matgloss* buf = NULL; ((*alloc_matgloss_buffer_callback)(buf, materials->inorganic.size())); @@ -256,7 +256,7 @@ t_matgloss* Materials_getOrganic(DFHackObject* mat) if(materials->organic.size() > 0) { - t_matgloss* buf; + t_matgloss* buf = NULL; ((*alloc_matgloss_buffer_callback)(buf, materials->organic.size())); @@ -280,7 +280,7 @@ t_matgloss* Materials_getTree(DFHackObject* mat) if(materials->tree.size() > 0) { - t_matgloss* buf; + t_matgloss* buf = NULL; ((*alloc_matgloss_buffer_callback)(buf, materials->tree.size())); @@ -304,7 +304,7 @@ t_matgloss* Materials_getPlant(DFHackObject* mat) if(materials->plant.size() > 0) { - t_matgloss* buf; + t_matgloss* buf = NULL; ((*alloc_matgloss_buffer_callback)(buf, materials->plant.size())); @@ -328,7 +328,7 @@ t_matgloss* Materials_getRace(DFHackObject* mat) if(materials->race.size() > 0) { - t_matgloss* buf; + t_matgloss* buf = NULL; ((*alloc_matgloss_buffer_callback)(buf, materials->race.size())); @@ -354,7 +354,7 @@ c_creaturetype* Materials_getRaceEx(DFHackObject* mat) if(matSize > 0) { - c_creaturetype* buf; + c_creaturetype* buf = NULL; ((*alloc_creaturetype_buffer_callback)(buf, matSize)); @@ -379,7 +379,7 @@ t_descriptor_color* Materials_getColor(DFHackObject* mat) if(materials->color.size() > 0) { - t_descriptor_color* buf; + t_descriptor_color* buf = NULL; ((*alloc_descriptor_buffer_callback)(buf, materials->color.size())); @@ -403,7 +403,7 @@ t_matglossOther* Materials_getOther(DFHackObject* mat) if(materials->other.size() > 0) { - t_matglossOther* buf; + t_matglossOther* buf = NULL; ((*alloc_matgloss_other_buffer_callback)(buf, materials->other.size())); @@ -427,7 +427,7 @@ t_matgloss* Materials_getAllDesc(DFHackObject* mat) if(materials->alldesc.size() > 0) { - t_matgloss* buf; + t_matgloss* buf = NULL; ((*alloc_matgloss_buffer_callback)(buf, materials->alldesc.size())); diff --git a/library/modules/Position_C.cpp b/library/modules/Position_C.cpp index a97a52a56..386bd1c5b 100644 --- a/library/modules/Position_C.cpp +++ b/library/modules/Position_C.cpp @@ -102,7 +102,7 @@ t_hotkey* Position_ReadHotkeys(DFHackObject* pos) { if(pos != NULL) { - t_hotkey* buf; + t_hotkey* buf = NULL; (*alloc_t_hotkey_buffer_callback)(buf, NUM_HOTKEYS); @@ -144,7 +144,7 @@ t_screen* Position_getScreenTiles(DFHackObject* pos, int32_t width, int32_t heig { if(pos != NULL) { - t_screen* buf; + t_screen* buf = NULL; (*alloc_t_screen_buffer_callback)(buf, width * height); diff --git a/library/modules/Translation_C.cpp b/library/modules/Translation_C.cpp index 2589e9640..7032f26c5 100644 --- a/library/modules/Translation_C.cpp +++ b/library/modules/Translation_C.cpp @@ -124,7 +124,7 @@ char* Translation_TranslateNameEnglish(DFHackObject* trans, const DFHack::t_name if(nameTrans.size() > 0) { - char* buf; + char* buf = NULL; (*alloc_char_buffer_callback)(buf, nameTrans.size()); @@ -155,7 +155,7 @@ char* Translation_TranslateNameNonEnglish(DFHackObject* trans, const DFHack::t_n if(nameTrans.size() > 0) { - char* buf; + char* buf = NULL; (*alloc_char_buffer_callback)(buf, nameTrans.size()); From c13b7c035f50a293a0f764c574961c2aad8d0078 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Fri, 19 Nov 2010 01:14:41 +0100 Subject: [PATCH 54/94] Fix weather tool/offsets for 31.18. Added a file I missed. --- data/Memory-ng.xml | 2 +- library/DFTileTypes.cpp | 31 +++++++++++++++++++++++++++++++ tools/supported/weather.cpp | 1 + 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 library/DFTileTypes.cpp diff --git a/data/Memory-ng.xml b/data/Memory-ng.xml index 212c87b7d..537e2a2da 100644 --- a/data/Memory-ng.xml +++ b/data/Memory-ng.xml @@ -1867,7 +1867,7 @@
-
+
diff --git a/library/DFTileTypes.cpp b/library/DFTileTypes.cpp new file mode 100644 index 000000000..3064aa007 --- /dev/null +++ b/library/DFTileTypes.cpp @@ -0,0 +1,31 @@ +// vim: sts=4 sta et shiftwidth=4: +#include "dfhack/DFIntegers.h" +#include "dfhack/DFTileTypes.h" +#include "dfhack/DFExport.h" + +namespace DFHack { + //set tile class string lookup table (e.g. for printing to user) +#define X(name,comment) #name, + DFHACK_EXPORT const char * TileClassString[tileclass_count+1] = { + TILECLASS_MACRO + 0 + }; +#undef X + + //string lookup table (e.g. for printing to user) +#define X(name,comment) #name, + DFHACK_EXPORT const char * TileMaterialString[tilematerial_count+1] = { + TILEMATERIAL_MACRO + 0 + }; +#undef X + + //string lookup table (e.g. for printing to user) +#define X(name,comment) #name, + DFHACK_EXPORT const char * TileSpecialString[tilespecial_count+1] = { + TILESPECIAL_MACRO + 0 + }; +#undef X + +} diff --git a/tools/supported/weather.cpp b/tools/supported/weather.cpp index 5ded20649..8e8a936bc 100644 --- a/tools/supported/weather.cpp +++ b/tools/supported/weather.cpp @@ -114,6 +114,7 @@ int main (int argc, char** argv) cin.ignore(); } #endif + DF->Resume(); DF->Detach(); return 0; } From 8439b3fa7d48b1f48bc2e5128484613e9d14cd55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Fri, 19 Nov 2010 02:40:38 +0100 Subject: [PATCH 55/94] Required fixes for properly exporting the new symbols. --- library/DFTileTypes.cpp | 6 +++--- library/include/dfhack/DFTileTypes.h | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/library/DFTileTypes.cpp b/library/DFTileTypes.cpp index 3064aa007..964233e50 100644 --- a/library/DFTileTypes.cpp +++ b/library/DFTileTypes.cpp @@ -6,7 +6,7 @@ namespace DFHack { //set tile class string lookup table (e.g. for printing to user) #define X(name,comment) #name, - DFHACK_EXPORT const char * TileClassString[tileclass_count+1] = { + const char * TileClassString[tileclass_count+1] = { TILECLASS_MACRO 0 }; @@ -14,7 +14,7 @@ namespace DFHack { //string lookup table (e.g. for printing to user) #define X(name,comment) #name, - DFHACK_EXPORT const char * TileMaterialString[tilematerial_count+1] = { + const char * TileMaterialString[tilematerial_count+1] = { TILEMATERIAL_MACRO 0 }; @@ -22,7 +22,7 @@ namespace DFHack { //string lookup table (e.g. for printing to user) #define X(name,comment) #name, - DFHACK_EXPORT const char * TileSpecialString[tilespecial_count+1] = { + const char * TileSpecialString[tilespecial_count+1] = { TILESPECIAL_MACRO 0 }; diff --git a/library/include/dfhack/DFTileTypes.h b/library/include/dfhack/DFTileTypes.h index fe30e83ff..5637dc2ab 100644 --- a/library/include/dfhack/DFTileTypes.h +++ b/library/include/dfhack/DFTileTypes.h @@ -26,6 +26,7 @@ distribution. #define TILETYPES_H_INCLUDED #include "DFPragma.h" +#include "DFExport.h" namespace DFHack { @@ -62,7 +63,7 @@ namespace DFHack }; #undef X - extern const char *TileClassString[]; + DFHACK_EXPORT extern const char *TileClassString[]; #define TILEMATERIAL_MACRO \ X(AIR, "empty" ) \ @@ -96,7 +97,7 @@ namespace DFHack #undef X - extern const char *TileMaterialString[]; + DFHACK_EXPORT extern const char *TileMaterialString[]; // Special specials of the tile. // Not the best way to do this, but compatible with existing code. @@ -126,7 +127,7 @@ namespace DFHack }; #undef X - extern const char *TileSpecialString[]; + DFHACK_EXPORT extern const char *TileSpecialString[]; // variants are used for tiles, where there are multiple variants of the same - like grass floors enum TileVariant From 30d806d9889697a9347327319e86e34af17bd507 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Fri, 19 Nov 2010 06:37:36 +0100 Subject: [PATCH 56/94] Fix backpointer scan in search tool. --- tools/playground/incrementalsearch.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/playground/incrementalsearch.cpp b/tools/playground/incrementalsearch.cpp index f5ce91ffd..8c347d0c7 100644 --- a/tools/playground/incrementalsearch.cpp +++ b/tools/playground/incrementalsearch.cpp @@ -595,6 +595,7 @@ void PtrTrace(DFHack::ContextManager & DFMgr, vector & range check.insert(select); // ascend select = found[0]; + found.clear(); } DF->Detach(); } @@ -664,6 +665,7 @@ void DataPtrTrace(DFHack::ContextManager & DFMgr, vector & r check.insert(select); // ascend select = found[0]; + found.clear(); } DF->Detach(); } From a436db541da200eab85598b5cfff6adfa0e0ac3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Tue, 8 Feb 2011 14:33:58 +0100 Subject: [PATCH 57/94] CRLF hell --- .gitignore | 2 +- build/build-MinGW32-debug.bat | 8 +- build/build-MinGW32-release-trace.bat | 10 +- build/build-MinGW32-release.bat | 8 +- build/generate-MSVC-2005.bat | 6 +- build/generate-MSVC-2008.bat | 6 +- build/generate-MSVC-2010.bat | 6 +- tools/playground/hellhole.cpp | 2566 ++++++++++++------------- tools/supported/probe.cpp | 336 ++-- 9 files changed, 1474 insertions(+), 1474 deletions(-) diff --git a/.gitignore b/.gitignore index 3d1c650da..1a06c65bc 100644 --- a/.gitignore +++ b/.gitignore @@ -29,5 +29,5 @@ dfhack/python/pydfhack/_pydfhack.so dfhack/python/PyDFHack.egg-info dfhack/python/build dfhack/python/dist - + /cmakeall.bat \ No newline at end of file diff --git a/build/build-MinGW32-debug.bat b/build/build-MinGW32-debug.bat index e60ca7211..ee622d5ff 100644 --- a/build/build-MinGW32-debug.bat +++ b/build/build-MinGW32-debug.bat @@ -1,5 +1,5 @@ -mkdir build-real -cd build-real -cmake ..\.. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE:string=Debug -mingw32-make +mkdir build-real +cd build-real +cmake ..\.. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE:string=Debug +mingw32-make pause \ No newline at end of file diff --git a/build/build-MinGW32-release-trace.bat b/build/build-MinGW32-release-trace.bat index ca7df86d3..f75da5ff8 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/build-MinGW32-release.bat b/build/build-MinGW32-release.bat index 18e5bcab4..dd0dc6b88 100644 --- a/build/build-MinGW32-release.bat +++ b/build/build-MinGW32-release.bat @@ -1,5 +1,5 @@ -mkdir build-real -cd build-real -cmake ..\.. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE:string=Release -mingw32-make 2> log.txt +mkdir build-real +cd build-real +cmake ..\.. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE:string=Release +mingw32-make 2> log.txt pause \ No newline at end of file diff --git a/build/generate-MSVC-2005.bat b/build/generate-MSVC-2005.bat index a187b4663..35451e362 100644 --- a/build/generate-MSVC-2005.bat +++ b/build/generate-MSVC-2005.bat @@ -1,4 +1,4 @@ -mkdir build-real -cd build-real -cmake ..\.. -G"Visual Studio 8 2005" +mkdir build-real +cd build-real +cmake ..\.. -G"Visual Studio 8 2005" pause \ No newline at end of file diff --git a/build/generate-MSVC-2008.bat b/build/generate-MSVC-2008.bat index 79e95a8c5..8d39368b5 100644 --- a/build/generate-MSVC-2008.bat +++ b/build/generate-MSVC-2008.bat @@ -1,4 +1,4 @@ -mkdir build-real -cd build-real -cmake ..\.. -G"Visual Studio 9 2008" +mkdir build-real +cd build-real +cmake ..\.. -G"Visual Studio 9 2008" pause \ No newline at end of file diff --git a/build/generate-MSVC-2010.bat b/build/generate-MSVC-2010.bat index 50828f7ea..588051bc6 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/tools/playground/hellhole.cpp b/tools/playground/hellhole.cpp index cc12554be..340d5169e 100644 --- a/tools/playground/hellhole.cpp +++ b/tools/playground/hellhole.cpp @@ -1,1283 +1,1283 @@ -// Burn a hole straight to hell! - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -using namespace std; - -#include -#include -#include -using namespace DFHack; - - -#ifdef LINUX_BUILD -#include -void waitmsec (int delay) -{ - usleep(delay); -} -#else -#include -void waitmsec (int delay) -{ - Sleep(delay); -} -#endif - -#define minmax(MinV,V,MaxV) (max((MinV),min((MaxV),(V)))) - -//User interaction enums. -//Pit Type (these only have meaning within hellhole, btw) -#define PITTYPEMACRO \ - X(pitTypeChasm,"Bottomless Chasm" ) \ - X(pitTypeEerie,"Bottomless Eerie Pit" ) \ - X(pitTypeFloor,"Pit with floor" ) \ - X(pitTypeSolid,"Solid Pillar" ) \ - X(pitTypeOasis,"Oasis Pit (ends at magma, no hell access)" ) \ - X(pitTypeOPool,"Oasis Pool, with partial aquifer (default 5 z-levels)" ) \ - X(pitTypeMagma,"Magma Pit (similar to volcano, no hell access)" ) \ - X(pitTypeMPool,"Magma Pool (default 5 z-levels)" ) -//end PITTYPEMACRO - -#define X(name,desc) name, -enum e_pitType -{ - pitTypeInvalid=-1, - PITTYPEMACRO - pitTypeCount, -}; -#undef X - - -#define X(name,desc) desc, -const char * pitTypeDesc[pitTypeCount+1] = -{ - PITTYPEMACRO - "" -}; -#undef X - - - - -int getyesno( const char * msg , int default_value ) -{ - const int bufferlen=4; - static char buf[bufferlen]; - memset(buf,0,bufferlen); - while (-1) - { - if (msg) printf("\n%s (default=%s)\n:" , msg , (default_value?"yes":"no") ); - fflush(stdin); - fgets(buf,bufferlen,stdin); - switch (buf[0]) - { - case 0: - case 0x0d: - case 0x0a: - return default_value; - case 'y': - case 'Y': - case 'T': - case 't': - case '1': - return -1; - case 'n': - case 'N': - case 'F': - case 'f': - case '0': - return 0; - } - } - return 0; -} - -int getint( const char * msg , int min, int max, int default_value ) { - const int bufferlen=16; - static char buf[bufferlen]; - int n=0; - memset(buf,0,bufferlen); - while (-1) - { - if (msg) printf("\n%s (default=%d)\n:" , msg , default_value); - fflush(stdin); - fgets(buf,bufferlen,stdin); - if ( !buf[0] || 0x0a==buf[0] || 0x0d==buf[0] ) - { - return default_value; - } - if ( sscanf(buf,"%d", &n) ) - { - if (n>=min && n<=max ) - { - return n; - } - } - } -} - -int getint( const char * msg , int min, int max ) -{ - const int bufferlen=16; - static char buf[bufferlen]; - int n=0; - memset(buf,0,bufferlen); - while (-1) - { - if (msg) - { - printf("\n%s \n:" , msg ); - } - fflush(stdin); - fgets(buf,bufferlen,stdin); - - if ( !buf[0] || 0x0a==buf[0] || 0x0d==buf[0] ) - { - continue; - } - if ( sscanf(buf,"%d", &n) ) - { - if (n>=min && n<=max ) - { - return n; - } - } - } -} - - - -//Interactive, get pit type from user -e_pitType selectPitType() -{ - while ( -1 ) - { - printf("Enter the type of hole to dig:\n" ); - for (int n=0;n=0, replace with v. -//Returns number of neighbors found. -int checkneighbors(unsigned char pattern[16][16], int x, int y, unsigned char n , char v ) -{ - int r=0; - if ( x>0 && y>0 && n==pattern[x-1][y-1] ) - { - ++r; - if (v>-1) pattern[x][y]=v; - } - if ( x>0 && n==pattern[x-1][y ] ) - { - ++r; - if (v>-1) pattern[x][y]=v; - } - if ( y>0 && n==pattern[x ][y-1] ) - { - ++r; - if (v>-1) pattern[x][y]=v; - } - if ( x<15 && n==pattern[x+1][y ] ) - { - ++r; - if (v>-1) pattern[x][y]=v; - } - if ( x<15 && y>0 && n==pattern[x+1][y-1] ) - { - ++r; - if (v>-1) pattern[x][y]=v; - } - if ( x<15 && y<15 && n==pattern[x+1][y+1] ) - { - ++r; - if (v>-1) pattern[x][y]=v; - } - if ( y<15 && n==pattern[x ][y+1] ) - { - ++r; - if (v>-1) pattern[x][y]=v; - } - if ( x>0 && y<15 && n==pattern[x-1][y+1] ) - { - ++r; - if (v>-1) pattern[x][y]=v; - } - return r; -} -//convenience -int checkneighbors(unsigned char pattern[16][16], int x, int y, unsigned char n ) -{ - return checkneighbors(pattern,x,y,n,-1); -} - -void settileat(unsigned char pattern[16][16], const unsigned char needle, const unsigned char v, const int index ) -{ - int ok=0; - int safety=256*256; - int y,x,i=0; - //Scan for sequential index - while ( !ok && --safety ) - { - for (y=0 ; !ok && y<16 ; ++y ) - { - for (x=0 ; !ok && x<16 ; ++x ) - { - if ( needle==pattern[x][y] ) - { - ++i; - if ( index==i ) - { - //Got it! - pattern[x][y]=v; - ok=-1; - } - } - } - } - } -} - - -//FIXME: good candidate for adding to dfhack. Maybe the Maps should have those cached so they can be queried? -//Is a given feature present at the given tile? -int isfeature( - vector global_features, - std::map > local_features, - const mapblock40d &block, const planecoord &pc, const int x, const int y, const e_feature Feat -) -{ - //const TileRow * tp; - //tp = getTileTypeP(block.tiletypes[x][y]); - const t_designation * d; - d = &block.designation[x][y]; - - if ( block.local_feature > -1 && d->bits.feature_local ) { - if ( Feat==local_features[pc][block.local_feature]->type ) return Feat; - } - if ( block.global_feature > -1 && d->bits.feature_global ) { - if ( Feat==global_features[block.global_feature].type ) return Feat; - } - - return 0; -} - -// FIXME: use block cache, break into manageable bits -int main (void) -{ - srand ( (unsigned int)time(NULL) ); - - //Message of intent - cout << - "DF Hole" << endl << - "This tool will instantly dig a chasm, pit, pipe, etc through hell, wherever your cursor is." << endl << - "This can not be undone! End program now if you don't want hellish fun." << endl - ; - - //User selection of settings should have it own routine, a structure for settings, I know - //sloppy mess, but this is just a demo utility. - - //Pit Types. - e_pitType pittype = selectPitType(); - - //Here are all the settings. - //Default values are set here. - int pitdepth=0; - int roof=-1; - int holeradius=6; - int wallthickness=1; - int wallpillar=1; - int holepillar=1; - int exposehell = 0; - int fillmagma=0; - int fillwater=0; - int stopatmagma=0; - int exposemagma=0; - int aquify=0; - - //The Tile Type to use for the walls lining the hole - //263 is semi-molten rock, 331 is obsidian - uint32_t whell=263, wmolten=263, wmagma=331, wcave=331; - //The Tile Type to use for the hole's floor at bottom of the map - //35 is chasm, 42 is eerie pit , 340 is obsidian floor, 344 is featstone floor, 264 is 'magma flow' floor - uint32_t floor=35, cap=340; - int floorvar=0; - - - //Modify default settings based on pit type. - switch ( pittype ) - { - case pitTypeChasm: - floor=35; - break; - case pitTypeEerie: - floor=42; - break; - case pitTypeFloor: - floor=344; - floorvar=3; - break; - case pitTypeSolid: - holeradius=0; - wallthickness=7; - wallpillar=4; - break; - case pitTypeOasis: - stopatmagma=-1; - fillwater=-1; - holeradius=5; - wallthickness=2; - //aquify=-1; - floor=340; - floorvar=3; - break; - case pitTypeOPool: - pitdepth=5; - fillwater=-1; - holeradius=5; - wallthickness=2; - //aquify=-1; - floor=340; - floorvar=3; - break; - case pitTypeMagma: - stopatmagma=-1; - exposemagma=-1; - wallthickness=2; - fillmagma=-1; - floor=264; - break; - case pitTypeMPool: - pitdepth=5; - wallthickness=2; - fillmagma=-1; - floor=340; - floorvar=3; - break; - } - - - //Should tiles be revealed? - int reveal=0; - - - int accept = getyesno("Use default settings?",1); - - while ( !accept ) - { - //Pit Depth - pitdepth = getint( "Enter max depth (0 for bottom of map)", 0, INT_MAX, pitdepth ); - - //Hole Size - holeradius = getint( "Enter hole radius, 0 to 16", 0, 16, holeradius ); - - //Wall thickness - wallthickness = getint( "Enter wall thickness, 0 to 16", 0, 16, wallthickness ); - - //Obsidian Pillars - holepillar = getint( "Number of Obsidian Pillars in hole, 0 to 255", 0, 255, holepillar ); - wallpillar = getint( "Number of Obsidian Pillars in wall, 0 to 255", 0, 255, wallpillar ); - - //Open Hell? - exposehell=getyesno("Expose the pit to hell (no walls in hell)?",exposehell); - - //Stop when magma sea is hit? - stopatmagma=getyesno("Stop at magma sea?",stopatmagma); - exposemagma=getyesno("Expose magma sea (no walls in magma)?",exposemagma); - - //Fill? - fillmagma=getyesno("Fill with magma?",fillmagma); - if (fillmagma) aquify=fillwater=0; - fillwater=getyesno("Fill with water?",fillwater); - //aquify=getyesno("Aquifer?",aquify); - - - /////////////////////////////////////////////////////////////////////////////////////////////// - //Print settings. - //If a settings struct existed, this could be in a routine - printf("Using Settings:\n"); - printf("Pit Type......: %d = %s\n", pittype, pitTypeDesc[pittype]); - printf("Depth.........: %d\n", pitdepth); - printf("Hole Radius...: %d\n", holeradius); - printf("Wall Thickness: %d\n", wallthickness); - printf("Pillars, Hole.: %d\n", holepillar); - printf("Pillars, Wall.: %d\n", wallpillar); - printf("Expose Hell...: %c\n", (exposehell?'Y':'N') ); - printf("Stop at Magma.: %c\n", (stopatmagma?'Y':'N') ); - printf("Expose Magma..: %c\n", (exposemagma?'Y':'N') ); - printf("Magma Fill....: %c\n", (fillmagma?'Y':'N') ); - printf("Water Fill....: %c\n", (fillwater?'Y':'N') ); - printf("Aquifer.......: %c\n", (aquify?'Y':'N') ); - - accept = getyesno("Accept these settings?",1); - } - - - int64_t n; - uint32_t x_max,y_max,z_max; - - - //Pattern to dig - unsigned char pattern[16][16]; - - - for (int regen=1;regen; ) - { - regen=0; - - memset(pattern,0,sizeof(pattern)); - - //Calculate a randomized circle. - //These values found through experimentation. - int x=0, y=0, n=0; - - //Two concentric irregular circles - //Outer circle, solid. - if ( wallthickness ) - { - drawcircle(holeradius+wallthickness, pattern, 2); - } - //Inner circle, hole. - if ( holeradius ) - { - drawcircle(holeradius, pattern, 1); - } - - - //Post-process to be certain the wall totally encloses hole. - if (wallthickness) - { - for (y=0;y<16;++y) - { - for (x=0;x<16;++x) - { - if ( 1==pattern[x][y] ) - { - //No hole at edges. - if ( x<1 || x>14 || y<1 || y>14 ) - { - pattern[x][y]=2; - } - } - else if ( 0==pattern[x][y] ) - { - //check neighbors - checkneighbors( pattern , x,y, 1, 2); - } - } - } - } - - //Makes sure that somewhere random gets a vertical pillar of rock which is safe - //to dig stairs down, to permit access to anywhere within the pit from the top. - for (n=holepillar; n ; --n) - { - settileat( pattern , 1 , 3 , rand()&255 ); - } - for (n=wallpillar; n ; --n) - { - settileat( pattern , 2 , 3 , rand()&255 ); - } - - //Note: - //At this point, the pattern holds: - //0 for all tiles which will be ignored. - //1 for all tiles set to empty pit space. - //2 for all normal walls. - //3 for the straight obsidian top-to-bottom wall. - //4 is randomized between wall or floor (!not implemented!) - - printf("\nPattern:\n"); - const char patternkey[] = ".cW!?567890123"; - - //Print the pattern - for (y=0;y<16;++y) - { - for (x=0;x<16;++x) - { - cout << patternkey[ pattern[x][y] ]; - } - cout << endl; - } - cout << endl; - - regen = !getyesno("Acceptable Pattern?",1); - } - - //Post-process settings to fix problems here - if (pitdepth<1) - { - pitdepth=INT_MAX; - } - - - /////////////////////////////////////////////////////////////////////////////////////////////// - - - cerr << "Loading memory map..." << endl; - - //Connect to DF! - DFHack::ContextManager DFMgr("Memory.xml"); - DFHack::Context *DF = DFMgr.getSingleContext(); - - - - //Init - cerr << "Attaching to DF..." << endl; - try - { - DF->Attach(); - } - catch (exception& e) - { - cerr << e.what() << endl; - #ifndef LINUX_BUILD - cin.ignore(); - #endif - return 1; - } - - // init the map - DFHack::Maps *Mapz = DF->getMaps(); - if (!Mapz->Start()) - { - cerr << "Can't init map. Exiting." << endl; - #ifndef LINUX_BUILD - cin.ignore(); - #endif - return 1; - } - - Mapz->getSize(x_max,y_max,z_max); - - - //Get cursor - int32_t cursorX, cursorY, cursorZ; - DFHack::Position *Pos = DF->getPosition(); - Pos->getCursorCoords(cursorX,cursorY,cursorZ); - if (-30000==cursorX) - { - cout << "No cursor position found. Exiting." << endl; - #ifndef LINUX_BUILD - cin.ignore(); - #endif - return 1; - } - - //Block coordinates - int32_t bx=cursorX/16, by=cursorY/16, bz=cursorZ; - //Tile coordinates within block - int32_t tx=cursorX%16, ty=cursorY%16, tz=cursorZ; - - /* - //Access the DF interface to pause the game. - //Copied from the reveal tool. - DFHack::Gui *Gui =DF->getGui(); - cout << "Pausing..." << endl; - Gui->SetPauseState(true); - DF->Resume(); - waitmsec(1000); - DF->Suspend(); - */ - - //Verify that every z-level at this location exists. - for (int32_t Z = 0; Z<= bz ;Z++) - { - if ( ! Mapz->isValidBlock(bx,by,Z) ) - { - cout << "This block does't exist! Exiting." << endl; - #ifndef LINUX_BUILD - cin.ignore(); - #endif - return 1; - } - } - - //Get all the map features. - vector global_features; - if (!Mapz->ReadGlobalFeatures(global_features)) - { - cout << "Couldn't load global features! Probably a version problem." << endl; - #ifndef LINUX_BUILD - cin.ignore(); - #endif - return 1; - } - - std::map > local_features; - if (!Mapz->ReadLocalFeatures(local_features)) - { - cout << "Couldn't load local features! Probably a version problem." << endl; - #ifndef LINUX_BUILD - cin.ignore(); - #endif - return 1; - } - - //Get info on current tile, to determine how to generate the pit - mapblock40d topblock; - Mapz->ReadBlock40d( bx, by, bz , &topblock ); - //Related block info - planecoord pc; - pc.dim.x=bx; - pc.dim.y=by; - mapblock40d block; - const TileRow * tp; - t_designation * d; - - ////////////////////////////////////// - //From top to bottom, dig this thing. - ////////////////////////////////////// - - //Top level, cap. - //Might make this an option in the future - //For now, no wall means no cap. - if (wallthickness) - { - Mapz->ReadBlock40d( bx, by, bz , &block ); - for (uint32_t x=0;x<16;++x) - { - for (uint32_t y=0;y<16;++y) - { - if ( (pattern[x][y]>1) || (roof && pattern[x][y]) ) - { - tp = getTileTypeP(block.tiletypes[x][y]); - d = &block.designation[x][y]; - //Only modify this level if it's 'empty' - if ( EMPTY != tp->c && RAMP_TOP != tp->c && STAIR_DOWN != tp->c && DFHack::TILE_STREAM_TOP != tp->s) - { - continue; - } - - //Need a floor for empty space. - if (reveal) - { - d->bits.hidden = 0; //topblock.designation[x][y].bits.hidden; - } - //Always clear the dig designation. - d->bits.dig = designation_no; - //unlock fluids, so they fall down the pit. - d->bits.flow_forbid = d->bits.liquid_static=0; - block.blockflags.bits.liquid_1 = block.blockflags.bits.liquid_2 = 1; - //Remove aquifer, to prevent bugginess - d->bits.water_table=0; - //Set the tile. - block.tiletypes[x][y] = cap + rand()%4; - } - } - } - //Write the block. - Mapz->WriteBlockFlags(bx,by,bz, block.blockflags ); - Mapz->WriteDesignations(bx,by,bz, &block.designation ); - Mapz->WriteTileTypes(bx,by,bz, &block.tiletypes ); - Mapz->WriteDirtyBit(bx,by,bz,1); - } - - /////////////////////////////////////////////////////////////////////////////////////////////// - //All levels in between. - int done=0; - uint32_t t,v; - int32_t z = bz-1; - int32_t bottom = max(0,bz-pitdepth-1); - assert( bottom>=0 && bottom<=bz ); - for ( ; !done && z>=bottom ; --z) - { - int watercount=0; - int magmacount=0; - int moltencount=0; - int rockcount=0; - int veincount=0; - int emptycount=0; - int hellcount=0; - int templecount=0; - int adamcount=0; - int featcount=0; - int tpat; - - cout << z << endl; - assert( Mapz->isValidBlock(bx,by,z) ); - if (!Mapz->ReadBlock40d( bx, by, z , &block )) - { - cout << "Bad block! " << bx << "," << by << "," << z << endl; - } - - //Pre-process this z-level, to get some tile statistics. - for (int32_t x=0;x<16;++x) - { - for (int32_t y=0;y<16;++y) - { - t=0; - tp = getTileTypeP(block.tiletypes[x][y]); - d = &block.designation[x][y]; - tpat=pattern[x][y]; - - //Tile type material categories - switch ( tp->m ) - { - case AIR: - ++emptycount; - break; - case MAGMA: - ++moltencount; - break; - case VEIN: - ++veincount; - break; - case FEATSTONE: - case HFS: - case OBSIDIAN: - //basicly, ignored. - break; - default: - if ( EMPTY == tp->c || RAMP_TOP == tp->c || STAIR_DOWN == tp->c ) - { - ++emptycount; - } - else - { - ++rockcount; - } - break; - } - - //Magma and water - if ( d->bits.flow_size ) - { - if (d->bits.liquid_type) - { - ++magmacount; - } - else - { - ++watercount; - } - } - - - //Check for Features - if ( block.local_feature > -1 || block.global_feature > -1 ) - { - //Count tiles which actually are in the feature. - //It is possible for a block to have a feature, but no tiles to be feature. - if ( d->bits.feature_global || d->bits.feature_local ) - { - //All features - ++featcount; - - if ( d->bits.feature_global && d->bits.feature_local ) - { - cout << "warn:tile is global and local at same time!" << endl; - } - - n=0; - if ( block.global_feature > -1 && d->bits.feature_global ) - { - n=global_features[block.global_feature].type; - switch ( n ) - { - case feature_Other: - //no count - break; - case feature_Adamantine_Tube: - ++adamcount; - break; - case feature_Underworld: - ++hellcount; - break; - case feature_Hell_Temple: - ++templecount; - break; - default: - //something here. for debugging, it may be interesting to know. - if (n) cout << '(' << n << ')'; - } - } - - n=0; - if ( block.local_feature > -1 && d->bits.feature_local ) - { - n=local_features[pc][block.local_feature]->type; - switch ( n ) - { - case feature_Other: - //no count - break; - case feature_Adamantine_Tube: - ++adamcount; - break; - case feature_Underworld: - ++hellcount; - break; - case feature_Hell_Temple: - ++templecount; - break; - default: - //something here. for debugging, it may be interesting to know. - if (n) cout << '[' << n << ']'; - } - } - } - } - } - } - - - //If stopping at magma, and no no non-feature stone in this layer, and magma found, then we're either at - //or below the magma sea / molten rock. - if ( stopatmagma && (moltencount || magmacount) && (!exposemagma || !rockcount) ) - { - //If not exposing magma, quit at the first sign of magma. - //If exposing magma, quite once magma is exposed. - done=-1; - } - - - ///////////////////////////////////////////////////////////////////////////////////////////////// - //Some checks, based on settings and stats collected - //First check, are we at illegal depth? - if ( !done && hellcount && stopatmagma ) - { - //Panic! - done=-1; - tpat=0; - cout << "error: illegal breach of hell!" << endl; - } - - ///////////////////////////////////////////////////////////////////////////////////////////////// - //Actually process the current z-level. - //These loops do the work. - for (int32_t x=0;!done && x<16;++x) - { - for (int32_t y=0;!done && y<16;++y) - { - t=0; - tp = getTileTypeP(block.tiletypes[x][y]); - d = &block.designation[x][y]; - tpat=pattern[x][y]; - - //Up front, remove aquifer, to prevent bugginess - //It may be added back if aquify is set. - d->bits.water_table=0; - - //Change behaviour based on settings and stats from this z-level - - //In hell? - if ( tpat && tpat!=3 && isfeature(global_features, local_features,block,pc,x,y,feature_Underworld ) ) - { - if ( exposehell ) - { - tpat=0; - } - } - - //Expose magma? - if ( tpat && tpat!=3 && exposemagma ) - { - //Leave certain tiles unchanged. - switch ( tp->m ) - { - case HFS: - case FEATSTONE: - case MAGMA: - tpat=0; - default: - break; - } - //Adamantine may be left unchanged... - if ( isfeature(global_features, local_features,block,pc,x,y,feature_Adamantine_Tube ) ) - { - tpat=0; - } - //Leave magma sea unchanged. - if ( d->bits.flow_size && d->bits.liquid_type) - { - tpat=0; - } - } - - - //For all situations... - //Special modification for walls, always for adamantine. - if ( isfeature(global_features, local_features,block,pc,x,y,feature_Adamantine_Tube ) ) - { - if ( 2==pattern[x][y] || 3==pattern[x][y] ) - { - tpat=2; - } - } - - - //Border or space? - switch (tpat) - { - case 0: - continue; - break; - case 1: - //Empty Space - t=32; - //d->bits.light = topblock.designation[x][y].bits.light; - //d->bits.skyview = topblock.designation[x][y].bits.skyview; - //d->bits.subterranean = topblock.designation[x][y].bits.subterranean; - - //Erase special markers? - //d->bits.feature_global = d->bits.feature_local = 0; - - //Water? Magma? - if (fillmagma || fillwater) - { - d->bits.flow_size=7; - d->bits.water_stagnant = false; - d->bits.water_salt = false; - if (fillmagma) - { - d->bits.liquid_type=liquid_magma; - } - else - { - d->bits.liquid_type=liquid_water; - } - } - else - { - //Otherwise, remove all liquids. - d->bits.flow_size=0; - d->bits.water_stagnant = false; - d->bits.water_salt = false; - d->bits.liquid_type = liquid_water; - } - - break; - case 2: - //Wall. - //First guess based on current material - switch ( tp->m ) - { - case OBSIDIAN: - t=wmagma; - break; - case MAGMA: - t=wmolten; - break; - case HFS: - //t=whell; - break; - case VEIN: - t=440; //Solid vein block - break; - case FEATSTONE: - t=335; //Solid feature stone block - break; - default: - t=wcave; - } - //Adamantine (a local feature) trumps veins. - { - //Local Feature? - if ( block.local_feature > -1 ) - { - switch ( n=local_features[pc][block.local_feature]->type ) - { - case feature_Underworld: - case feature_Hell_Temple: - //Only adopt these if there is no global feature present - if ( block.global_feature >-1 ) - { - break; - } - case feature_Adamantine_Tube: - //Always for adamantine, sometimes for others - //Whatever the feature is made of. "featstone wall" - d->bits.feature_global = 0; - d->bits.feature_local = 1; - t=335; - break; - } - } - //Global Feature? - else if (block.global_feature > -1 && !d->bits.feature_local ) - { - switch ( n=global_features[block.global_feature].type ) - { - case feature_Adamantine_Tube: - case feature_Underworld: - case feature_Hell_Temple: - //Whatever the feature is made of. "featstone wall" - d->bits.feature_global = 1; - t=335; - break; - } - } - } - - //Erase any liquids, as they cause problems. - d->bits.flow_size=0; - d->bits.water_stagnant = false; - d->bits.water_salt = false; - d->bits.liquid_type=liquid_water; - - //Placing an aquifer? - //(bugged, these aquifers don't generate water!) - if ( aquify ) - { - //Only normal stone types can be aquified - if ( tp->m!=MAGMA && tp->m!=FEATSTONE && tp->m!=HFS ) - { - //Only place next to the hole. - //If no hole, place in middle. - if ( checkneighbors(pattern,x,y,1) || (7==x && 7==y) ) - { - d->bits.water_table = 1; - //t=265; //soil wall - } - } - } - break; - case 3: - ////No obsidian walls on bottom of map! - //if(z<1 && (d->bits.feature_global || d->bits.feature_local) ) { - // t=335; - //} - - //Special wall, always sets to obsidian, to give a stairway - t=331; - - //Erase special markers - d->bits.feature_global = d->bits.feature_local = 0; - - //Erase any liquids, as they cause problems. - d->bits.flow_size=0; - d->bits.water_stagnant = false; - d->bits.water_salt = false; - d->bits.liquid_type=liquid_water; - break; - default: - cout << ".error,bad pattern."; - } - - //For all tiles. - if (reveal) - { - d->bits.hidden = 0; //topblock.designation[x][y].bits.hidden; - } - //Always clear the dig designation. - d->bits.dig=designation_no; - //Make it underground, because it is capped - d->bits.subterranean=1; - d->bits.light=0; - d->bits.skyview=0; - //unlock fluids, so they fall down the pit. - d->bits.flow_forbid = d->bits.liquid_static=0; - block.blockflags.bits.liquid_1 = block.blockflags.bits.liquid_2 = 1; - //Set the tile. - block.tiletypes[x][y] = t; - - } - } - - //Write the block. - Mapz->WriteBlockFlags(bx,by,z, block.blockflags ); - Mapz->WriteDesignations(bx,by,z, &block.designation ); - Mapz->WriteTileTypes(bx,by,z, &block.tiletypes ); - Mapz->WriteDirtyBit(bx,by,z,1); - - } - - //Re-process the last z-level handled above. - z++; - assert( z>=0 ); - - - /////////////////////////////////////////////////////////////////////////////////////////////// - //The bottom level is special. - if (-1) - { - if (!Mapz->ReadBlock40d( bx, by, z , &block )) - { - cout << "Bad block! " << bx << "," << by << "," << z << endl; - } - for (uint32_t x=0;x<16;++x) - { - for (uint32_t y=0;y<16;++y) - { - t=floor; - v=floorvar; - tp = getTileTypeP(block.tiletypes[x][y]); - d = &block.designation[x][y]; - - if ( exposehell ) - { - //Leave hell tiles unchanged when exposing hell. - if ( isfeature(global_features,local_features,block,pc,x,y,feature_Underworld) ) - { - continue; - } - } - - //Does expose magma need anything at this level? - if ( exposemagma && stopatmagma ) - { - continue; - } - - switch (pattern[x][y]) - { - case 0: - continue; - break; - case 1: - //Empty becomes floor. - - //Base floor type on the z-level first, features, then tile type. - if (!z) { - //Bottom of map, use the floor specified, always. - break; - } - - ////Only place floor where ground is already solid when exposing - //if( EMPTY == tp->c || RAMP_TOP == tp->c || STAIR_DOWN == tp->c ){ - // continue; - //} - - if ( d->bits.feature_global || d->bits.feature_global ) { - //Feature Floor! - t=344; - break; - } - - //Tile material check. - switch ( tp->m ) - { - case OBSIDIAN: - t=340; - v=3; - break; - case MAGMA: - v=0; - t=264; //magma flow - break; - case HFS: - //should only happen at bottom of map - break; - case VEIN: - t=441; //vein floor - v=3; - break; - case FEATSTONE: - t=344; - v=3; - break; - } - - break; - case 2: - case 3: - //Walls already drawn. - //Ignore. - continue; - break; - } - - //For all tiles. - if (reveal) d->bits.hidden = 0; //topblock.designation[x][y].bits.hidden; - //Always clear the dig designation. - d->bits.dig=designation_no; - //unlock fluids - d->bits.flow_forbid = d->bits.liquid_static=0; - block.blockflags.bits.liquid_1 = block.blockflags.bits.liquid_2 = 1; - - //Set the tile. - block.tiletypes[x][y] = t + ( v ? rand()&v : 0 ); - } - } - //Write the block. - Mapz->WriteBlockFlags(bx,by,z, block.blockflags ); - Mapz->WriteDesignations(bx,by,z, &block.designation ); - Mapz->WriteTileTypes(bx,by,z, &block.tiletypes ); - Mapz->WriteDirtyBit(bx,by,z,1); - } - - DF->Detach(); -#ifndef LINUX_BUILD - cout << "Done. Press any key to continue" << endl; - cin.ignore(); -#endif - return 0; -} +// Burn a hole straight to hell! + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace std; + +#include +#include +#include +using namespace DFHack; + + +#ifdef LINUX_BUILD +#include +void waitmsec (int delay) +{ + usleep(delay); +} +#else +#include +void waitmsec (int delay) +{ + Sleep(delay); +} +#endif + +#define minmax(MinV,V,MaxV) (max((MinV),min((MaxV),(V)))) + +//User interaction enums. +//Pit Type (these only have meaning within hellhole, btw) +#define PITTYPEMACRO \ + X(pitTypeChasm,"Bottomless Chasm" ) \ + X(pitTypeEerie,"Bottomless Eerie Pit" ) \ + X(pitTypeFloor,"Pit with floor" ) \ + X(pitTypeSolid,"Solid Pillar" ) \ + X(pitTypeOasis,"Oasis Pit (ends at magma, no hell access)" ) \ + X(pitTypeOPool,"Oasis Pool, with partial aquifer (default 5 z-levels)" ) \ + X(pitTypeMagma,"Magma Pit (similar to volcano, no hell access)" ) \ + X(pitTypeMPool,"Magma Pool (default 5 z-levels)" ) +//end PITTYPEMACRO + +#define X(name,desc) name, +enum e_pitType +{ + pitTypeInvalid=-1, + PITTYPEMACRO + pitTypeCount, +}; +#undef X + + +#define X(name,desc) desc, +const char * pitTypeDesc[pitTypeCount+1] = +{ + PITTYPEMACRO + "" +}; +#undef X + + + + +int getyesno( const char * msg , int default_value ) +{ + const int bufferlen=4; + static char buf[bufferlen]; + memset(buf,0,bufferlen); + while (-1) + { + if (msg) printf("\n%s (default=%s)\n:" , msg , (default_value?"yes":"no") ); + fflush(stdin); + fgets(buf,bufferlen,stdin); + switch (buf[0]) + { + case 0: + case 0x0d: + case 0x0a: + return default_value; + case 'y': + case 'Y': + case 'T': + case 't': + case '1': + return -1; + case 'n': + case 'N': + case 'F': + case 'f': + case '0': + return 0; + } + } + return 0; +} + +int getint( const char * msg , int min, int max, int default_value ) { + const int bufferlen=16; + static char buf[bufferlen]; + int n=0; + memset(buf,0,bufferlen); + while (-1) + { + if (msg) printf("\n%s (default=%d)\n:" , msg , default_value); + fflush(stdin); + fgets(buf,bufferlen,stdin); + if ( !buf[0] || 0x0a==buf[0] || 0x0d==buf[0] ) + { + return default_value; + } + if ( sscanf(buf,"%d", &n) ) + { + if (n>=min && n<=max ) + { + return n; + } + } + } +} + +int getint( const char * msg , int min, int max ) +{ + const int bufferlen=16; + static char buf[bufferlen]; + int n=0; + memset(buf,0,bufferlen); + while (-1) + { + if (msg) + { + printf("\n%s \n:" , msg ); + } + fflush(stdin); + fgets(buf,bufferlen,stdin); + + if ( !buf[0] || 0x0a==buf[0] || 0x0d==buf[0] ) + { + continue; + } + if ( sscanf(buf,"%d", &n) ) + { + if (n>=min && n<=max ) + { + return n; + } + } + } +} + + + +//Interactive, get pit type from user +e_pitType selectPitType() +{ + while ( -1 ) + { + printf("Enter the type of hole to dig:\n" ); + for (int n=0;n=0, replace with v. +//Returns number of neighbors found. +int checkneighbors(unsigned char pattern[16][16], int x, int y, unsigned char n , char v ) +{ + int r=0; + if ( x>0 && y>0 && n==pattern[x-1][y-1] ) + { + ++r; + if (v>-1) pattern[x][y]=v; + } + if ( x>0 && n==pattern[x-1][y ] ) + { + ++r; + if (v>-1) pattern[x][y]=v; + } + if ( y>0 && n==pattern[x ][y-1] ) + { + ++r; + if (v>-1) pattern[x][y]=v; + } + if ( x<15 && n==pattern[x+1][y ] ) + { + ++r; + if (v>-1) pattern[x][y]=v; + } + if ( x<15 && y>0 && n==pattern[x+1][y-1] ) + { + ++r; + if (v>-1) pattern[x][y]=v; + } + if ( x<15 && y<15 && n==pattern[x+1][y+1] ) + { + ++r; + if (v>-1) pattern[x][y]=v; + } + if ( y<15 && n==pattern[x ][y+1] ) + { + ++r; + if (v>-1) pattern[x][y]=v; + } + if ( x>0 && y<15 && n==pattern[x-1][y+1] ) + { + ++r; + if (v>-1) pattern[x][y]=v; + } + return r; +} +//convenience +int checkneighbors(unsigned char pattern[16][16], int x, int y, unsigned char n ) +{ + return checkneighbors(pattern,x,y,n,-1); +} + +void settileat(unsigned char pattern[16][16], const unsigned char needle, const unsigned char v, const int index ) +{ + int ok=0; + int safety=256*256; + int y,x,i=0; + //Scan for sequential index + while ( !ok && --safety ) + { + for (y=0 ; !ok && y<16 ; ++y ) + { + for (x=0 ; !ok && x<16 ; ++x ) + { + if ( needle==pattern[x][y] ) + { + ++i; + if ( index==i ) + { + //Got it! + pattern[x][y]=v; + ok=-1; + } + } + } + } + } +} + + +//FIXME: good candidate for adding to dfhack. Maybe the Maps should have those cached so they can be queried? +//Is a given feature present at the given tile? +int isfeature( + vector global_features, + std::map > local_features, + const mapblock40d &block, const planecoord &pc, const int x, const int y, const e_feature Feat +) +{ + //const TileRow * tp; + //tp = getTileTypeP(block.tiletypes[x][y]); + const t_designation * d; + d = &block.designation[x][y]; + + if ( block.local_feature > -1 && d->bits.feature_local ) { + if ( Feat==local_features[pc][block.local_feature]->type ) return Feat; + } + if ( block.global_feature > -1 && d->bits.feature_global ) { + if ( Feat==global_features[block.global_feature].type ) return Feat; + } + + return 0; +} + +// FIXME: use block cache, break into manageable bits +int main (void) +{ + srand ( (unsigned int)time(NULL) ); + + //Message of intent + cout << + "DF Hole" << endl << + "This tool will instantly dig a chasm, pit, pipe, etc through hell, wherever your cursor is." << endl << + "This can not be undone! End program now if you don't want hellish fun." << endl + ; + + //User selection of settings should have it own routine, a structure for settings, I know + //sloppy mess, but this is just a demo utility. + + //Pit Types. + e_pitType pittype = selectPitType(); + + //Here are all the settings. + //Default values are set here. + int pitdepth=0; + int roof=-1; + int holeradius=6; + int wallthickness=1; + int wallpillar=1; + int holepillar=1; + int exposehell = 0; + int fillmagma=0; + int fillwater=0; + int stopatmagma=0; + int exposemagma=0; + int aquify=0; + + //The Tile Type to use for the walls lining the hole + //263 is semi-molten rock, 331 is obsidian + uint32_t whell=263, wmolten=263, wmagma=331, wcave=331; + //The Tile Type to use for the hole's floor at bottom of the map + //35 is chasm, 42 is eerie pit , 340 is obsidian floor, 344 is featstone floor, 264 is 'magma flow' floor + uint32_t floor=35, cap=340; + int floorvar=0; + + + //Modify default settings based on pit type. + switch ( pittype ) + { + case pitTypeChasm: + floor=35; + break; + case pitTypeEerie: + floor=42; + break; + case pitTypeFloor: + floor=344; + floorvar=3; + break; + case pitTypeSolid: + holeradius=0; + wallthickness=7; + wallpillar=4; + break; + case pitTypeOasis: + stopatmagma=-1; + fillwater=-1; + holeradius=5; + wallthickness=2; + //aquify=-1; + floor=340; + floorvar=3; + break; + case pitTypeOPool: + pitdepth=5; + fillwater=-1; + holeradius=5; + wallthickness=2; + //aquify=-1; + floor=340; + floorvar=3; + break; + case pitTypeMagma: + stopatmagma=-1; + exposemagma=-1; + wallthickness=2; + fillmagma=-1; + floor=264; + break; + case pitTypeMPool: + pitdepth=5; + wallthickness=2; + fillmagma=-1; + floor=340; + floorvar=3; + break; + } + + + //Should tiles be revealed? + int reveal=0; + + + int accept = getyesno("Use default settings?",1); + + while ( !accept ) + { + //Pit Depth + pitdepth = getint( "Enter max depth (0 for bottom of map)", 0, INT_MAX, pitdepth ); + + //Hole Size + holeradius = getint( "Enter hole radius, 0 to 16", 0, 16, holeradius ); + + //Wall thickness + wallthickness = getint( "Enter wall thickness, 0 to 16", 0, 16, wallthickness ); + + //Obsidian Pillars + holepillar = getint( "Number of Obsidian Pillars in hole, 0 to 255", 0, 255, holepillar ); + wallpillar = getint( "Number of Obsidian Pillars in wall, 0 to 255", 0, 255, wallpillar ); + + //Open Hell? + exposehell=getyesno("Expose the pit to hell (no walls in hell)?",exposehell); + + //Stop when magma sea is hit? + stopatmagma=getyesno("Stop at magma sea?",stopatmagma); + exposemagma=getyesno("Expose magma sea (no walls in magma)?",exposemagma); + + //Fill? + fillmagma=getyesno("Fill with magma?",fillmagma); + if (fillmagma) aquify=fillwater=0; + fillwater=getyesno("Fill with water?",fillwater); + //aquify=getyesno("Aquifer?",aquify); + + + /////////////////////////////////////////////////////////////////////////////////////////////// + //Print settings. + //If a settings struct existed, this could be in a routine + printf("Using Settings:\n"); + printf("Pit Type......: %d = %s\n", pittype, pitTypeDesc[pittype]); + printf("Depth.........: %d\n", pitdepth); + printf("Hole Radius...: %d\n", holeradius); + printf("Wall Thickness: %d\n", wallthickness); + printf("Pillars, Hole.: %d\n", holepillar); + printf("Pillars, Wall.: %d\n", wallpillar); + printf("Expose Hell...: %c\n", (exposehell?'Y':'N') ); + printf("Stop at Magma.: %c\n", (stopatmagma?'Y':'N') ); + printf("Expose Magma..: %c\n", (exposemagma?'Y':'N') ); + printf("Magma Fill....: %c\n", (fillmagma?'Y':'N') ); + printf("Water Fill....: %c\n", (fillwater?'Y':'N') ); + printf("Aquifer.......: %c\n", (aquify?'Y':'N') ); + + accept = getyesno("Accept these settings?",1); + } + + + int64_t n; + uint32_t x_max,y_max,z_max; + + + //Pattern to dig + unsigned char pattern[16][16]; + + + for (int regen=1;regen; ) + { + regen=0; + + memset(pattern,0,sizeof(pattern)); + + //Calculate a randomized circle. + //These values found through experimentation. + int x=0, y=0, n=0; + + //Two concentric irregular circles + //Outer circle, solid. + if ( wallthickness ) + { + drawcircle(holeradius+wallthickness, pattern, 2); + } + //Inner circle, hole. + if ( holeradius ) + { + drawcircle(holeradius, pattern, 1); + } + + + //Post-process to be certain the wall totally encloses hole. + if (wallthickness) + { + for (y=0;y<16;++y) + { + for (x=0;x<16;++x) + { + if ( 1==pattern[x][y] ) + { + //No hole at edges. + if ( x<1 || x>14 || y<1 || y>14 ) + { + pattern[x][y]=2; + } + } + else if ( 0==pattern[x][y] ) + { + //check neighbors + checkneighbors( pattern , x,y, 1, 2); + } + } + } + } + + //Makes sure that somewhere random gets a vertical pillar of rock which is safe + //to dig stairs down, to permit access to anywhere within the pit from the top. + for (n=holepillar; n ; --n) + { + settileat( pattern , 1 , 3 , rand()&255 ); + } + for (n=wallpillar; n ; --n) + { + settileat( pattern , 2 , 3 , rand()&255 ); + } + + //Note: + //At this point, the pattern holds: + //0 for all tiles which will be ignored. + //1 for all tiles set to empty pit space. + //2 for all normal walls. + //3 for the straight obsidian top-to-bottom wall. + //4 is randomized between wall or floor (!not implemented!) + + printf("\nPattern:\n"); + const char patternkey[] = ".cW!?567890123"; + + //Print the pattern + for (y=0;y<16;++y) + { + for (x=0;x<16;++x) + { + cout << patternkey[ pattern[x][y] ]; + } + cout << endl; + } + cout << endl; + + regen = !getyesno("Acceptable Pattern?",1); + } + + //Post-process settings to fix problems here + if (pitdepth<1) + { + pitdepth=INT_MAX; + } + + + /////////////////////////////////////////////////////////////////////////////////////////////// + + + cerr << "Loading memory map..." << endl; + + //Connect to DF! + DFHack::ContextManager DFMgr("Memory.xml"); + DFHack::Context *DF = DFMgr.getSingleContext(); + + + + //Init + cerr << "Attaching to DF..." << endl; + try + { + DF->Attach(); + } + catch (exception& e) + { + cerr << e.what() << endl; + #ifndef LINUX_BUILD + cin.ignore(); + #endif + return 1; + } + + // init the map + DFHack::Maps *Mapz = DF->getMaps(); + if (!Mapz->Start()) + { + cerr << "Can't init map. Exiting." << endl; + #ifndef LINUX_BUILD + cin.ignore(); + #endif + return 1; + } + + Mapz->getSize(x_max,y_max,z_max); + + + //Get cursor + int32_t cursorX, cursorY, cursorZ; + DFHack::Position *Pos = DF->getPosition(); + Pos->getCursorCoords(cursorX,cursorY,cursorZ); + if (-30000==cursorX) + { + cout << "No cursor position found. Exiting." << endl; + #ifndef LINUX_BUILD + cin.ignore(); + #endif + return 1; + } + + //Block coordinates + int32_t bx=cursorX/16, by=cursorY/16, bz=cursorZ; + //Tile coordinates within block + int32_t tx=cursorX%16, ty=cursorY%16, tz=cursorZ; + + /* + //Access the DF interface to pause the game. + //Copied from the reveal tool. + DFHack::Gui *Gui =DF->getGui(); + cout << "Pausing..." << endl; + Gui->SetPauseState(true); + DF->Resume(); + waitmsec(1000); + DF->Suspend(); + */ + + //Verify that every z-level at this location exists. + for (int32_t Z = 0; Z<= bz ;Z++) + { + if ( ! Mapz->isValidBlock(bx,by,Z) ) + { + cout << "This block does't exist! Exiting." << endl; + #ifndef LINUX_BUILD + cin.ignore(); + #endif + return 1; + } + } + + //Get all the map features. + vector global_features; + if (!Mapz->ReadGlobalFeatures(global_features)) + { + cout << "Couldn't load global features! Probably a version problem." << endl; + #ifndef LINUX_BUILD + cin.ignore(); + #endif + return 1; + } + + std::map > local_features; + if (!Mapz->ReadLocalFeatures(local_features)) + { + cout << "Couldn't load local features! Probably a version problem." << endl; + #ifndef LINUX_BUILD + cin.ignore(); + #endif + return 1; + } + + //Get info on current tile, to determine how to generate the pit + mapblock40d topblock; + Mapz->ReadBlock40d( bx, by, bz , &topblock ); + //Related block info + planecoord pc; + pc.dim.x=bx; + pc.dim.y=by; + mapblock40d block; + const TileRow * tp; + t_designation * d; + + ////////////////////////////////////// + //From top to bottom, dig this thing. + ////////////////////////////////////// + + //Top level, cap. + //Might make this an option in the future + //For now, no wall means no cap. + if (wallthickness) + { + Mapz->ReadBlock40d( bx, by, bz , &block ); + for (uint32_t x=0;x<16;++x) + { + for (uint32_t y=0;y<16;++y) + { + if ( (pattern[x][y]>1) || (roof && pattern[x][y]) ) + { + tp = getTileTypeP(block.tiletypes[x][y]); + d = &block.designation[x][y]; + //Only modify this level if it's 'empty' + if ( EMPTY != tp->c && RAMP_TOP != tp->c && STAIR_DOWN != tp->c && DFHack::TILE_STREAM_TOP != tp->s) + { + continue; + } + + //Need a floor for empty space. + if (reveal) + { + d->bits.hidden = 0; //topblock.designation[x][y].bits.hidden; + } + //Always clear the dig designation. + d->bits.dig = designation_no; + //unlock fluids, so they fall down the pit. + d->bits.flow_forbid = d->bits.liquid_static=0; + block.blockflags.bits.liquid_1 = block.blockflags.bits.liquid_2 = 1; + //Remove aquifer, to prevent bugginess + d->bits.water_table=0; + //Set the tile. + block.tiletypes[x][y] = cap + rand()%4; + } + } + } + //Write the block. + Mapz->WriteBlockFlags(bx,by,bz, block.blockflags ); + Mapz->WriteDesignations(bx,by,bz, &block.designation ); + Mapz->WriteTileTypes(bx,by,bz, &block.tiletypes ); + Mapz->WriteDirtyBit(bx,by,bz,1); + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + //All levels in between. + int done=0; + uint32_t t,v; + int32_t z = bz-1; + int32_t bottom = max(0,bz-pitdepth-1); + assert( bottom>=0 && bottom<=bz ); + for ( ; !done && z>=bottom ; --z) + { + int watercount=0; + int magmacount=0; + int moltencount=0; + int rockcount=0; + int veincount=0; + int emptycount=0; + int hellcount=0; + int templecount=0; + int adamcount=0; + int featcount=0; + int tpat; + + cout << z << endl; + assert( Mapz->isValidBlock(bx,by,z) ); + if (!Mapz->ReadBlock40d( bx, by, z , &block )) + { + cout << "Bad block! " << bx << "," << by << "," << z << endl; + } + + //Pre-process this z-level, to get some tile statistics. + for (int32_t x=0;x<16;++x) + { + for (int32_t y=0;y<16;++y) + { + t=0; + tp = getTileTypeP(block.tiletypes[x][y]); + d = &block.designation[x][y]; + tpat=pattern[x][y]; + + //Tile type material categories + switch ( tp->m ) + { + case AIR: + ++emptycount; + break; + case MAGMA: + ++moltencount; + break; + case VEIN: + ++veincount; + break; + case FEATSTONE: + case HFS: + case OBSIDIAN: + //basicly, ignored. + break; + default: + if ( EMPTY == tp->c || RAMP_TOP == tp->c || STAIR_DOWN == tp->c ) + { + ++emptycount; + } + else + { + ++rockcount; + } + break; + } + + //Magma and water + if ( d->bits.flow_size ) + { + if (d->bits.liquid_type) + { + ++magmacount; + } + else + { + ++watercount; + } + } + + + //Check for Features + if ( block.local_feature > -1 || block.global_feature > -1 ) + { + //Count tiles which actually are in the feature. + //It is possible for a block to have a feature, but no tiles to be feature. + if ( d->bits.feature_global || d->bits.feature_local ) + { + //All features + ++featcount; + + if ( d->bits.feature_global && d->bits.feature_local ) + { + cout << "warn:tile is global and local at same time!" << endl; + } + + n=0; + if ( block.global_feature > -1 && d->bits.feature_global ) + { + n=global_features[block.global_feature].type; + switch ( n ) + { + case feature_Other: + //no count + break; + case feature_Adamantine_Tube: + ++adamcount; + break; + case feature_Underworld: + ++hellcount; + break; + case feature_Hell_Temple: + ++templecount; + break; + default: + //something here. for debugging, it may be interesting to know. + if (n) cout << '(' << n << ')'; + } + } + + n=0; + if ( block.local_feature > -1 && d->bits.feature_local ) + { + n=local_features[pc][block.local_feature]->type; + switch ( n ) + { + case feature_Other: + //no count + break; + case feature_Adamantine_Tube: + ++adamcount; + break; + case feature_Underworld: + ++hellcount; + break; + case feature_Hell_Temple: + ++templecount; + break; + default: + //something here. for debugging, it may be interesting to know. + if (n) cout << '[' << n << ']'; + } + } + } + } + } + } + + + //If stopping at magma, and no no non-feature stone in this layer, and magma found, then we're either at + //or below the magma sea / molten rock. + if ( stopatmagma && (moltencount || magmacount) && (!exposemagma || !rockcount) ) + { + //If not exposing magma, quit at the first sign of magma. + //If exposing magma, quite once magma is exposed. + done=-1; + } + + + ///////////////////////////////////////////////////////////////////////////////////////////////// + //Some checks, based on settings and stats collected + //First check, are we at illegal depth? + if ( !done && hellcount && stopatmagma ) + { + //Panic! + done=-1; + tpat=0; + cout << "error: illegal breach of hell!" << endl; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////// + //Actually process the current z-level. + //These loops do the work. + for (int32_t x=0;!done && x<16;++x) + { + for (int32_t y=0;!done && y<16;++y) + { + t=0; + tp = getTileTypeP(block.tiletypes[x][y]); + d = &block.designation[x][y]; + tpat=pattern[x][y]; + + //Up front, remove aquifer, to prevent bugginess + //It may be added back if aquify is set. + d->bits.water_table=0; + + //Change behaviour based on settings and stats from this z-level + + //In hell? + if ( tpat && tpat!=3 && isfeature(global_features, local_features,block,pc,x,y,feature_Underworld ) ) + { + if ( exposehell ) + { + tpat=0; + } + } + + //Expose magma? + if ( tpat && tpat!=3 && exposemagma ) + { + //Leave certain tiles unchanged. + switch ( tp->m ) + { + case HFS: + case FEATSTONE: + case MAGMA: + tpat=0; + default: + break; + } + //Adamantine may be left unchanged... + if ( isfeature(global_features, local_features,block,pc,x,y,feature_Adamantine_Tube ) ) + { + tpat=0; + } + //Leave magma sea unchanged. + if ( d->bits.flow_size && d->bits.liquid_type) + { + tpat=0; + } + } + + + //For all situations... + //Special modification for walls, always for adamantine. + if ( isfeature(global_features, local_features,block,pc,x,y,feature_Adamantine_Tube ) ) + { + if ( 2==pattern[x][y] || 3==pattern[x][y] ) + { + tpat=2; + } + } + + + //Border or space? + switch (tpat) + { + case 0: + continue; + break; + case 1: + //Empty Space + t=32; + //d->bits.light = topblock.designation[x][y].bits.light; + //d->bits.skyview = topblock.designation[x][y].bits.skyview; + //d->bits.subterranean = topblock.designation[x][y].bits.subterranean; + + //Erase special markers? + //d->bits.feature_global = d->bits.feature_local = 0; + + //Water? Magma? + if (fillmagma || fillwater) + { + d->bits.flow_size=7; + d->bits.water_stagnant = false; + d->bits.water_salt = false; + if (fillmagma) + { + d->bits.liquid_type=liquid_magma; + } + else + { + d->bits.liquid_type=liquid_water; + } + } + else + { + //Otherwise, remove all liquids. + d->bits.flow_size=0; + d->bits.water_stagnant = false; + d->bits.water_salt = false; + d->bits.liquid_type = liquid_water; + } + + break; + case 2: + //Wall. + //First guess based on current material + switch ( tp->m ) + { + case OBSIDIAN: + t=wmagma; + break; + case MAGMA: + t=wmolten; + break; + case HFS: + //t=whell; + break; + case VEIN: + t=440; //Solid vein block + break; + case FEATSTONE: + t=335; //Solid feature stone block + break; + default: + t=wcave; + } + //Adamantine (a local feature) trumps veins. + { + //Local Feature? + if ( block.local_feature > -1 ) + { + switch ( n=local_features[pc][block.local_feature]->type ) + { + case feature_Underworld: + case feature_Hell_Temple: + //Only adopt these if there is no global feature present + if ( block.global_feature >-1 ) + { + break; + } + case feature_Adamantine_Tube: + //Always for adamantine, sometimes for others + //Whatever the feature is made of. "featstone wall" + d->bits.feature_global = 0; + d->bits.feature_local = 1; + t=335; + break; + } + } + //Global Feature? + else if (block.global_feature > -1 && !d->bits.feature_local ) + { + switch ( n=global_features[block.global_feature].type ) + { + case feature_Adamantine_Tube: + case feature_Underworld: + case feature_Hell_Temple: + //Whatever the feature is made of. "featstone wall" + d->bits.feature_global = 1; + t=335; + break; + } + } + } + + //Erase any liquids, as they cause problems. + d->bits.flow_size=0; + d->bits.water_stagnant = false; + d->bits.water_salt = false; + d->bits.liquid_type=liquid_water; + + //Placing an aquifer? + //(bugged, these aquifers don't generate water!) + if ( aquify ) + { + //Only normal stone types can be aquified + if ( tp->m!=MAGMA && tp->m!=FEATSTONE && tp->m!=HFS ) + { + //Only place next to the hole. + //If no hole, place in middle. + if ( checkneighbors(pattern,x,y,1) || (7==x && 7==y) ) + { + d->bits.water_table = 1; + //t=265; //soil wall + } + } + } + break; + case 3: + ////No obsidian walls on bottom of map! + //if(z<1 && (d->bits.feature_global || d->bits.feature_local) ) { + // t=335; + //} + + //Special wall, always sets to obsidian, to give a stairway + t=331; + + //Erase special markers + d->bits.feature_global = d->bits.feature_local = 0; + + //Erase any liquids, as they cause problems. + d->bits.flow_size=0; + d->bits.water_stagnant = false; + d->bits.water_salt = false; + d->bits.liquid_type=liquid_water; + break; + default: + cout << ".error,bad pattern."; + } + + //For all tiles. + if (reveal) + { + d->bits.hidden = 0; //topblock.designation[x][y].bits.hidden; + } + //Always clear the dig designation. + d->bits.dig=designation_no; + //Make it underground, because it is capped + d->bits.subterranean=1; + d->bits.light=0; + d->bits.skyview=0; + //unlock fluids, so they fall down the pit. + d->bits.flow_forbid = d->bits.liquid_static=0; + block.blockflags.bits.liquid_1 = block.blockflags.bits.liquid_2 = 1; + //Set the tile. + block.tiletypes[x][y] = t; + + } + } + + //Write the block. + Mapz->WriteBlockFlags(bx,by,z, block.blockflags ); + Mapz->WriteDesignations(bx,by,z, &block.designation ); + Mapz->WriteTileTypes(bx,by,z, &block.tiletypes ); + Mapz->WriteDirtyBit(bx,by,z,1); + + } + + //Re-process the last z-level handled above. + z++; + assert( z>=0 ); + + + /////////////////////////////////////////////////////////////////////////////////////////////// + //The bottom level is special. + if (-1) + { + if (!Mapz->ReadBlock40d( bx, by, z , &block )) + { + cout << "Bad block! " << bx << "," << by << "," << z << endl; + } + for (uint32_t x=0;x<16;++x) + { + for (uint32_t y=0;y<16;++y) + { + t=floor; + v=floorvar; + tp = getTileTypeP(block.tiletypes[x][y]); + d = &block.designation[x][y]; + + if ( exposehell ) + { + //Leave hell tiles unchanged when exposing hell. + if ( isfeature(global_features,local_features,block,pc,x,y,feature_Underworld) ) + { + continue; + } + } + + //Does expose magma need anything at this level? + if ( exposemagma && stopatmagma ) + { + continue; + } + + switch (pattern[x][y]) + { + case 0: + continue; + break; + case 1: + //Empty becomes floor. + + //Base floor type on the z-level first, features, then tile type. + if (!z) { + //Bottom of map, use the floor specified, always. + break; + } + + ////Only place floor where ground is already solid when exposing + //if( EMPTY == tp->c || RAMP_TOP == tp->c || STAIR_DOWN == tp->c ){ + // continue; + //} + + if ( d->bits.feature_global || d->bits.feature_global ) { + //Feature Floor! + t=344; + break; + } + + //Tile material check. + switch ( tp->m ) + { + case OBSIDIAN: + t=340; + v=3; + break; + case MAGMA: + v=0; + t=264; //magma flow + break; + case HFS: + //should only happen at bottom of map + break; + case VEIN: + t=441; //vein floor + v=3; + break; + case FEATSTONE: + t=344; + v=3; + break; + } + + break; + case 2: + case 3: + //Walls already drawn. + //Ignore. + continue; + break; + } + + //For all tiles. + if (reveal) d->bits.hidden = 0; //topblock.designation[x][y].bits.hidden; + //Always clear the dig designation. + d->bits.dig=designation_no; + //unlock fluids + d->bits.flow_forbid = d->bits.liquid_static=0; + block.blockflags.bits.liquid_1 = block.blockflags.bits.liquid_2 = 1; + + //Set the tile. + block.tiletypes[x][y] = t + ( v ? rand()&v : 0 ); + } + } + //Write the block. + Mapz->WriteBlockFlags(bx,by,z, block.blockflags ); + Mapz->WriteDesignations(bx,by,z, &block.designation ); + Mapz->WriteTileTypes(bx,by,z, &block.tiletypes ); + Mapz->WriteDirtyBit(bx,by,z,1); + } + + DF->Detach(); +#ifndef LINUX_BUILD + cout << "Done. Press any key to continue" << endl; + cin.ignore(); +#endif + return 0; +} diff --git a/tools/supported/probe.cpp b/tools/supported/probe.cpp index 9d8549e5b..eb4ec284c 100644 --- a/tools/supported/probe.cpp +++ b/tools/supported/probe.cpp @@ -1,168 +1,168 @@ -// Just show some position data - -#include -#include -#include -#include -#include -#include -#include - -#define DFHACK_WANT_MISCUTILS 1 -#define DFHACK_WANT_TILETYPES 1 -#include - -using namespace DFHack; -int main (int numargs, const char ** args) -{ - DFHack::ContextManager DFMgr("Memory.xml"); - DFHack::Context *DF = DFMgr.getSingleContext(); - - BEGIN_PROBE: - 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::Maps *Maps = DF->getMaps(); - DFHack::Process * p = DF->getProcess(); - 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(); - - vector global_features; - std::map > local_features; - Maps->ReadLocalFeatures(local_features); - Maps->ReadGlobalFeatures(global_features); - - int32_t cursorX, cursorY, cursorZ; - Pos->getCursorCoords(cursorX,cursorY,cursorZ); - if(cursorX != -30000) - { - uint32_t blockX = cursorX / 16; - uint32_t tileX = cursorX % 16; - uint32_t blockY = cursorY / 16; - uint32_t tileY = cursorY % 16; - t_temperatures tmpb1, tmpb2; - mapblock40d block; - if(Maps->ReadBlock40d(blockX,blockY,cursorZ,&block)) - { - Maps->ReadTemperatures(blockX,blockY,cursorZ,&tmpb1, &tmpb2); - printf("block addr: 0x%x\n", block.origin); - int16_t tiletype = block.tiletypes[tileX][tileY]; - naked_designation &des = block.designation[tileX][tileY].bits; - uint32_t &desw = block.designation[tileX][tileY].whole; - print_bits(block.designation[tileX][tileY].whole,std::cout); - 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::endl; - - printf("%-10s: %4d %s\n","Class",tileTypeTable[tiletype].c,TileClassString[ tileTypeTable[tiletype].c ] , 0); - printf("%-10s: %4d %s\n","Material",tileTypeTable[tiletype].c,TileMaterialString[ tileTypeTable[tiletype].m ] , 0); - printf("%-10s: %4d %s\n","Special",tileTypeTable[tiletype].c,TileSpecialString[ tileTypeTable[tiletype].s ] , 0); - printf("%-10s: %4d\n","Variant",tileTypeTable[tiletype].v , 0); - printf("%-10s: %s\n","Direction",tileTypeTable[tiletype].d.getStr() , 0); - - - 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) - { - if(des.liquid_type == DFHack::liquid_magma) - std::cout <<"magma: "; - else std::cout <<"water: "; - std::cout << des.flow_size << std::endl; - } - if(des.flow_forbid) - std::cout << "flow forbid" << std::endl; - if(des.pile) - std::cout << "stockpile?" << std::endl; - if(des.rained) - std::cout << "rained?" << std::endl; - if(des.smooth) - std::cout << "smooth?" << std::endl; - uint32_t designato = block.origin + designatus + (tileX * 16 + tileY) * sizeof(t_designation); - printf("designation offset: 0x%x\n", designato); - - #define PRINT_FLAG( X ) printf("%-16s= %c\n", #X , ( des.X ? 'Y' : ' ' ) ) - PRINT_FLAG( hidden ); - PRINT_FLAG( light ); - PRINT_FLAG( skyview ); - PRINT_FLAG( subterranean ); - PRINT_FLAG( water_table ); - //PRINT_FLAG( rained ); - - planecoord pc; - pc.dim.x=blockX; pc.dim.y=blockY; - - PRINT_FLAG( feature_local ); - if( des.feature_local ) - { - printf("%-16s %4d (%2d) %s\n", "", - block.local_feature, - local_features[pc][block.local_feature]->type, - sa_feature[local_features[pc][block.local_feature]->type] - ); - } - - PRINT_FLAG( feature_global ); - if( des.feature_global ){ - printf("%-16s %4d (%2d) %s\n", "", - block.global_feature, - global_features[block.global_feature].type, - sa_feature[global_features[block.global_feature].type] - ); - } - #undef PRINT_FLAG - std::cout << std::endl; - } - } - DF->Detach(); - #ifndef LINUX_BUILD - std::cout << "Press any key to refresh..." << std::endl; - cin.ignore(); - goto BEGIN_PROBE; - #endif - return 0; -} +// Just show some position data + +#include +#include +#include +#include +#include +#include +#include + +#define DFHACK_WANT_MISCUTILS 1 +#define DFHACK_WANT_TILETYPES 1 +#include + +using namespace DFHack; +int main (int numargs, const char ** args) +{ + DFHack::ContextManager DFMgr("Memory.xml"); + DFHack::Context *DF = DFMgr.getSingleContext(); + + BEGIN_PROBE: + 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::Maps *Maps = DF->getMaps(); + DFHack::Process * p = DF->getProcess(); + 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(); + + vector global_features; + std::map > local_features; + Maps->ReadLocalFeatures(local_features); + Maps->ReadGlobalFeatures(global_features); + + int32_t cursorX, cursorY, cursorZ; + Pos->getCursorCoords(cursorX,cursorY,cursorZ); + if(cursorX != -30000) + { + uint32_t blockX = cursorX / 16; + uint32_t tileX = cursorX % 16; + uint32_t blockY = cursorY / 16; + uint32_t tileY = cursorY % 16; + t_temperatures tmpb1, tmpb2; + mapblock40d block; + if(Maps->ReadBlock40d(blockX,blockY,cursorZ,&block)) + { + Maps->ReadTemperatures(blockX,blockY,cursorZ,&tmpb1, &tmpb2); + printf("block addr: 0x%x\n", block.origin); + int16_t tiletype = block.tiletypes[tileX][tileY]; + naked_designation &des = block.designation[tileX][tileY].bits; + uint32_t &desw = block.designation[tileX][tileY].whole; + print_bits(block.designation[tileX][tileY].whole,std::cout); + 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::endl; + + printf("%-10s: %4d %s\n","Class",tileTypeTable[tiletype].c,TileClassString[ tileTypeTable[tiletype].c ] , 0); + printf("%-10s: %4d %s\n","Material",tileTypeTable[tiletype].c,TileMaterialString[ tileTypeTable[tiletype].m ] , 0); + printf("%-10s: %4d %s\n","Special",tileTypeTable[tiletype].c,TileSpecialString[ tileTypeTable[tiletype].s ] , 0); + printf("%-10s: %4d\n","Variant",tileTypeTable[tiletype].v , 0); + printf("%-10s: %s\n","Direction",tileTypeTable[tiletype].d.getStr() , 0); + + + 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) + { + if(des.liquid_type == DFHack::liquid_magma) + std::cout <<"magma: "; + else std::cout <<"water: "; + std::cout << des.flow_size << std::endl; + } + if(des.flow_forbid) + std::cout << "flow forbid" << std::endl; + if(des.pile) + std::cout << "stockpile?" << std::endl; + if(des.rained) + std::cout << "rained?" << std::endl; + if(des.smooth) + std::cout << "smooth?" << std::endl; + uint32_t designato = block.origin + designatus + (tileX * 16 + tileY) * sizeof(t_designation); + printf("designation offset: 0x%x\n", designato); + + #define PRINT_FLAG( X ) printf("%-16s= %c\n", #X , ( des.X ? 'Y' : ' ' ) ) + PRINT_FLAG( hidden ); + PRINT_FLAG( light ); + PRINT_FLAG( skyview ); + PRINT_FLAG( subterranean ); + PRINT_FLAG( water_table ); + //PRINT_FLAG( rained ); + + planecoord pc; + pc.dim.x=blockX; pc.dim.y=blockY; + + PRINT_FLAG( feature_local ); + if( des.feature_local ) + { + printf("%-16s %4d (%2d) %s\n", "", + block.local_feature, + local_features[pc][block.local_feature]->type, + sa_feature[local_features[pc][block.local_feature]->type] + ); + } + + PRINT_FLAG( feature_global ); + if( des.feature_global ){ + printf("%-16s %4d (%2d) %s\n", "", + block.global_feature, + global_features[block.global_feature].type, + sa_feature[global_features[block.global_feature].type] + ); + } + #undef PRINT_FLAG + std::cout << std::endl; + } + } + DF->Detach(); + #ifndef LINUX_BUILD + std::cout << "Press any key to refresh..." << std::endl; + cin.ignore(); + goto BEGIN_PROBE; + #endif + return 0; +} From 130d96549490b7efc297d8576bf23811af6434e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Tue, 8 Feb 2011 14:34:43 +0100 Subject: [PATCH 58/94] TODO use VirtualQuery --- library/DFProcess-windows.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/library/DFProcess-windows.cpp b/library/DFProcess-windows.cpp index b9f3fd86e..2ba868d22 100644 --- a/library/DFProcess-windows.cpp +++ b/library/DFProcess-windows.cpp @@ -297,8 +297,12 @@ 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 - + //FIXME: USE THIS! + /* + while VirtualQuery(process, info, sizeOf(info)) == sizeOf(info) + { + } + */ t_memrange temp; uint32_t base = d->my_descriptor->getBase(); temp.start = base + 0x1000; // more fakery. From 7676120dc89ae90adca558024d1ea0a520b6b8cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Tue, 8 Feb 2011 15:34:34 +0100 Subject: [PATCH 59/94] Windows VM ranges (not tested) --- library/DFProcess-windows.cpp | 49 +++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/library/DFProcess-windows.cpp b/library/DFProcess-windows.cpp index 2ba868d22..c3e1a0cbe 100644 --- a/library/DFProcess-windows.cpp +++ b/library/DFProcess-windows.cpp @@ -291,27 +291,42 @@ bool NormalProcess::getThreadIDs(vector & threads ) return true; } -//FIXME: use VirtualQuery to probe for memory ranges, cross-reference with base-corrected PE segment entries -void NormalProcess::getMemRanges( vector & ranges ) +typedef struct _MEMORY_BASIC_INFORMATION { - // 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 + void * BaseAddress; + void * AllocationBase; + uint32_t AllocationProtect; + size_t RegionSize; + uint32_t State; + uint32_t Protect; + uint32_t Type; +} MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION; + - //FIXME: USE THIS! - /* - while VirtualQuery(process, info, sizeOf(info)) == sizeOf(info) +// FIXME: NEEDS TESTING! +void NormalProcess::getMemRanges( vector & ranges ) +{ + MEMORY_BASIC_INFORMATION MBI; + const uint64_t PageSize = 4096; + uint64_t page = 0; + while (VirtualQuery(this->d->my_handle, page * PageSize, sizeof(MBI)) == sizeof(MBI)) { + page = MBI.RegionSize / PageSize; + if(MBI.RegionSize - MBI.RegionSize / PageSize != 0) + page ++; // skip over non-whole page + if( !(MBI.Protect & MEM_COMMIT) ) // skip empty regions + continue; + + t_memrange temp; + temp.start = MBI.BaseAddress; + temp.end = MBI.BaseAddress + MBI.RegionSize; + temp.read = MBI.Protect & PAGE_EXECUTE_READ | MBI.Protect & PAGE_EXECUTE_READWRITE | MBI.Protect & PAGE_READONLY | MBI.Protect & PAGE_READWRITE; + temp.write = MBI.Protect & PAGE_EXECUTE_READWRITE | MBI.Protect & PAGE_READWRITE; + temp.execute = MBI.Protect & PAGE_EXECUTE_READ | MBI.Protect & PAGE_EXECUTE_READWRITE | MBI.Protect & PAGE_EXECUTE; + temp.name = "N/A"; // FIXME: pull some relevant names from somewhere... + ranges.push_back(temp); } - */ - t_memrange temp; - uint32_t base = d->my_descriptor->getBase(); - temp.start = base + 0x1000; // more fakery. - temp.end = base + readDWord(base+readDWord(base+0x3C)+0x50)-1; // yay for magic. - temp.read = 1; - temp.write = 1; - temp.execute = 0; // fake - strcpy(temp.name,"pants");// that's right. I'm calling it pants. Windows can go to HELL - ranges.push_back(temp); + } uint8_t NormalProcess::readByte (const uint32_t offset) From 5bed6c594931f6cc4e77ce68a0933ba75c14315a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Tue, 8 Feb 2011 22:55:40 +0100 Subject: [PATCH 60/94] Sync, autosearch skeleton. --- library/DFProcess-linux-wine.cpp | 2 +- library/DFProcess-linux.cpp | 2 +- library/DFProcess-windows.cpp | 2 +- library/VersionInfo.cpp | 4 +- library/VersionInfoFactory.cpp | 2 +- library/include/dfhack/VersionInfo.h | 14 +- tools/playground/CMakeLists.txt | 5 + tools/playground/autosearch.cpp | 780 +++++++++++++++++++++++++ tools/playground/incrementalsearch.cpp | 144 +---- tools/playground/primitives.cpp | 27 + 10 files changed, 830 insertions(+), 152 deletions(-) create mode 100644 tools/playground/autosearch.cpp create mode 100644 tools/playground/primitives.cpp diff --git a/library/DFProcess-linux-wine.cpp b/library/DFProcess-linux-wine.cpp index cd96b3e54..ce1916e54 100644 --- a/library/DFProcess-linux-wine.cpp +++ b/library/DFProcess-linux-wine.cpp @@ -147,7 +147,7 @@ bool WineProcess::Private::validate(char* exe_file, uint32_t pid, char* mem_file continue; } // are the md5 hashes the same? - if(VersionInfo::OS_WINDOWS == (*it)->getOS() && hash == thishash) + if(OS_WINDOWS == (*it)->getOS() && hash == thishash) { // keep track of created memory_info object so we can destroy it later diff --git a/library/DFProcess-linux.cpp b/library/DFProcess-linux.cpp index 431dee508..7d82aa851 100644 --- a/library/DFProcess-linux.cpp +++ b/library/DFProcess-linux.cpp @@ -124,7 +124,7 @@ bool NormalProcess::Private::validate(char * exe_file,uint32_t pid, char * memFi if(hash == (*it)->getMD5()) // are the md5 hashes the same? { VersionInfo * m = *it; - if (VersionInfo::OS_LINUX == m->getOS()) + if (OS_LINUX == m->getOS()) { VersionInfo *m2 = new VersionInfo(*m); my_descriptor = m2; diff --git a/library/DFProcess-windows.cpp b/library/DFProcess-windows.cpp index b9f3fd86e..6625669d5 100644 --- a/library/DFProcess-windows.cpp +++ b/library/DFProcess-windows.cpp @@ -103,7 +103,7 @@ NormalProcess::NormalProcess(uint32_t pid, vector & known_versio for ( it=known_versions.begin() ; it < known_versions.end(); it++ ) { // filter by OS - if(VersionInfo::OS_WINDOWS != (*it)->getOS()) + if(OS_WINDOWS != (*it)->getOS()) continue; uint32_t pe_timestamp; // filter by timestamp, skip entries without a timestamp diff --git a/library/VersionInfo.cpp b/library/VersionInfo.cpp index 7773b7470..0569b90f8 100644 --- a/library/VersionInfo.cpp +++ b/library/VersionInfo.cpp @@ -545,7 +545,7 @@ namespace DFHack Process * p; // the process this belongs to string version; - VersionInfo::OSType OS; + OSType OS; std::string md5; uint32_t PE_timestamp; }; @@ -707,7 +707,7 @@ void VersionInfo::setOS(OSType os) } -VersionInfo::OSType VersionInfo::getOS() const +OSType VersionInfo::getOS() const { return d->OS; } diff --git a/library/VersionInfoFactory.cpp b/library/VersionInfoFactory.cpp index d25af91c1..3aa3d924c 100644 --- a/library/VersionInfoFactory.cpp +++ b/library/VersionInfoFactory.cpp @@ -365,7 +365,7 @@ void VersionInfoFactory::ParseBase (TiXmlElement* entry, VersionInfo* mem) throw Error::MemoryXmlBadAttribute("name"); mem->setVersion(cstr_version); - mem->setOS(VersionInfo::OS_BAD); + mem->setOS(OS_BAD); // process additional entries pElement = entry->FirstChildElement()->ToElement(); diff --git a/library/include/dfhack/VersionInfo.h b/library/include/dfhack/VersionInfo.h index b5c7dac14..39e838234 100644 --- a/library/include/dfhack/VersionInfo.h +++ b/library/include/dfhack/VersionInfo.h @@ -93,18 +93,18 @@ namespace DFHack /* * Version Info */ + enum OSType + { + OS_WINDOWS, + OS_LINUX, + OS_APPLE, + OS_BAD + }; class DFHACK_EXPORT VersionInfo : public OffsetGroup { private: VersionInfoPrivate * d; public: - enum OSType - { - OS_WINDOWS, - OS_LINUX, - OS_APPLE, - OS_BAD - }; VersionInfo(); VersionInfo(const VersionInfo&); void copy(const DFHack::VersionInfo* old); diff --git a/tools/playground/CMakeLists.txt b/tools/playground/CMakeLists.txt index 291845660..ab1b70165 100644 --- a/tools/playground/CMakeLists.txt +++ b/tools/playground/CMakeLists.txt @@ -24,6 +24,8 @@ TARGET_LINK_LIBRARIES(dfdigger dfhack) ADD_EXECUTABLE(dfdigger2 digger2.cpp) TARGET_LINK_LIBRARIES(dfdigger2 dfhack) +ADD_EXECUTABLE(primitives primitives.cpp) + # itemdesignator - change some item designations (dump, forbid, on-fire) for all # items of a given type and material # Author: belal @@ -33,6 +35,8 @@ TARGET_LINK_LIBRARIES(dfdigger2 dfhack) # incrementalsearch - a bit like cheat engine, only DF-specific, very basic # and Linux-only IF(UNIX) + ADD_EXECUTABLE(dfautosearch autosearch.cpp) + TARGET_LINK_LIBRARIES(dfautosearch dfhack) ADD_EXECUTABLE(dfincremental incrementalsearch.cpp) TARGET_LINK_LIBRARIES(dfincremental dfhack) ENDIF(UNIX) @@ -115,6 +119,7 @@ RUNTIME DESTINATION bin ) IF(UNIX) install(TARGETS + dfautosearch dfincremental RUNTIME DESTINATION bin ) diff --git a/tools/playground/autosearch.cpp b/tools/playground/autosearch.cpp new file mode 100644 index 000000000..1edab9797 --- /dev/null +++ b/tools/playground/autosearch.cpp @@ -0,0 +1,780 @@ +// this is an incremental search tool. It only works on Linux. +// here be dragons... and ugly code :P +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace std; + +#ifndef LINUX_BUILD + #define WINVER 0x0500 + // this one prevents windows from infecting the global namespace with filth + #define NOMINMAX + #define WIN32_LEAN_AND_MEAN + #include +#endif + +#include +#include "SegmentedFinder.h" +class Token +{ +public: + Token(uint64_t _offset) + { + offset = _offset; + offset_valid = 1; + value_valid = 0; + parent = 0; + } + Token(const std::string & offsetn) + { + full_offset_name = offsetn; + offset_valid = 0; + value_valid = 0; + parent = 0; + } + Token() + { + offset_valid = 0; + value_valid = 0; + parent = 0; + } + virtual ~Token(){}; + virtual bool LoadData(SegmentedFinder * s) = 0; + virtual void EmptyData() + { + value_valid = false; + }; + virtual bool Match(SegmentedFinder * s, uint64_t offset) = 0; + virtual void EmptyOffset() + { + offset_valid = false; + }; + virtual bool AcquireOffset(DFHack::VersionInfo * vinfo) + { + vinfo->getOffset(full_offset_name); + } + virtual uint32_t Length() = 0; + virtual uint64_t getAbsolute(){if(parent) return parent->getAbsolute() + offset; else return offset;}; + void setParent( Token *par ) + { + par = parent; + } +protected: + uint64_t offset;// offset from the start of the parent token + std::string full_offset_name; + Token * parent; + bool offset_valid :1; + bool value_valid :1; +}; + +class Byte: virtual public Token +{ +public: + Byte(uint64_t _offset):Token(_offset){}; + Byte():Token(){}; + ~Byte(); + virtual bool LoadData(SegmentedFinder * s) + { + if(offset_valid) + { + char * ptr = s->Translate(getAbsolute()); + if(ptr) + { + value = *ptr; + value_valid = true; + return true; + } + } + return false; + }; + // is the loaded data same as data at offset? yes -> set our offset to that. + virtual bool Match(SegmentedFinder * s, uint64_t offs) + { + if(value_valid && (*s->Translate(parent->getAbsolute() + offset)) == value ) + { + if(parent) + offset = offs - parent->getAbsolute(); + else + offset = offs; + return true; + } + return false; + }; + virtual uint32_t Length() + { + return 1; + }; +private: + char value; +}; + +class Short: virtual public Token +{ +public: + Short(uint64_t _offset):Token(_offset){}; + Short():Token(){}; + ~Short(); + virtual bool LoadData(SegmentedFinder * s) + { + if(offset_valid) + { + uint16_t * ptr = s->Translate(getAbsolute()); + if(ptr) + { + value = *ptr; + value_valid = true; + return true; + } + } + return false; + }; + // is the loaded data same as data at offset? yes -> set our offset to that. + virtual bool Match(SegmentedFinder * s, uint64_t offs) + { + if(value_valid && (*s->Translate(parent->getAbsolute() + offset)) == value ) + { + if(parent) + offset = offs - parent->getAbsolute(); + else + offset = offs; + return true; + } + return false; + }; + virtual uint32_t Length() + { + return 2; + }; +private: + uint16_t value; +}; + +class Long: virtual public Token +{ +public: + Long(uint64_t _offset):Token(_offset){}; + Long():Token(){}; + ~Long(); + virtual bool LoadData(SegmentedFinder * s) + { + if(offset_valid) + { + uint32_t * ptr = s->Translate(getAbsolute()); + if(ptr) + { + value = *ptr; + value_valid = true; + return true; + } + } + return false; + }; + // is the loaded data same as data at offset? yes -> set our offset to that. + virtual bool Match(SegmentedFinder * s, uint64_t offs) + { + if(value_valid && (*s->Translate(offs)) == value ) + { + if(parent) + offset = offs - parent->getAbsolute(); + else + offset = offs; + return true; + } + return false; + + }; + virtual uint32_t Length(){return 4;}; +private: + uint32_t value; +}; + +class PtrVector : virtual public Token +{ +public: + PtrVector(uint64_t _offset):Token(_offset){}; + PtrVector():Token(){}; + ~PtrVector(); + virtual uint32_t Length(){return 12;}; +private: + vector value; +}; + +class Pointer: virtual public Token +{ +public: + Pointer(uint64_t _offset):Token(_offset){}; + Pointer():Token(){}; + ~Pointer(); + virtual uint32_t Length(){return 4;}; +private: + uint64_t value; +}; + +class String: virtual public Token +{ +protected: + string value; +}; + +class Struct: virtual public Token +{ +public: + Struct(uint64_t _offset):Token(_offset){}; + Struct():Token(){}; + ~Struct(){}; + void Add( Token * t ){members.push_back(t);}; + virtual uint32_t Length(){return 0;}; // FIXME: temporary solution, should be the minimal length of all the contents combined + virtual bool LoadData(SegmentedFinder* s) + { + bool OK = true; + for(int i = 0; i < members.size() && OK; i++) + OK &= members[i]->LoadData(s); + return OK; + }; + // TODO: IMPLEMENT! + virtual bool Match(SegmentedFinder* s, uint64_t offset) + { + return false; + } +private: + vector members; +}; + +class LinuxString: virtual public String +{ +public: + LinuxString(uint64_t _offset):Token(_offset){}; + LinuxString():Token(){}; + ~LinuxString(){}; + virtual uint32_t Length(){return 4;}; + virtual bool LoadData(SegmentedFinder* s) + { + return false; + } + virtual bool Match(SegmentedFinder* s, uint64_t offset) + { + return false; + } + /* + // read string pointer, translate to local scheme + char *str = sf->Translate(*offset); + // verify + if(!str) + return false; + uint32_t length = *(uint32_t *)(offset - 12); + uint32_t capacity = *(uint32_t *)(offset - 8); + if(length > capacity) + return false; + //char * temp = new char[length+1]; + // read data from inside the string structure + //memcpy(temp, str,length + 1); + output = str; + return true; + */ +}; + +class WindowsString: virtual public String +{ +public: + WindowsString(uint64_t _offset):Token(_offset){}; + WindowsString():Token(){}; + ~WindowsString(){}; + virtual uint32_t Length(){return 0x1C;}; // FIXME: pouzivat Memory.xml? + virtual bool LoadData(SegmentedFinder* s) + { + return false; + } + virtual bool Match(SegmentedFinder* s, uint64_t offset) + { + return false; + } + string rdWinString( char * offset, SegmentedFinder & sf ) + { + char * start_offset = offset + 4; // FIXME: pouzivat Memory.xml? + uint32_t length = *(uint32_t *)(offset + 20); // FIXME: pouzivat Memory.xml? + uint32_t capacity = *(uint32_t *)(offset + 24); // FIXME: pouzivat Memory.xml? + char * temp = new char[capacity+1]; + + // read data from inside the string structure + if(capacity < 16) + { + memcpy(temp, start_offset,capacity); + //read(start_offset, capacity, (uint8_t *)temp); + } + else // read data from what the offset + 4 dword points to + { + start_offset = sf.Translate(*(uint32_t*)start_offset); + memcpy(temp, start_offset,capacity); + } + + temp[length] = 0; + string ret = temp; + delete temp; + return ret; + } +}; + +inline void printRange(DFHack::t_memrange * tpr) +{ + std::cout << std::hex << tpr->start << " - " << tpr->end << "|" << (tpr->read ? "r" : "-") << (tpr->write ? "w" : "-") << (tpr->execute ? "x" : "-") << "|" << tpr->name << std::endl; +} + +bool getRanges(DFHack::Process * p, vector & selected_ranges) +{ + vector ranges; + selected_ranges.clear(); + p->getMemRanges(ranges); + cout << "Which range to search? (default is 1-4)" << endl; + for(int i = 0; i< ranges.size();i++) + { + cout << dec << "(" << i << ") "; + printRange(&(ranges[i])); + } + int start, end; + while(1) + { + string select; + cout << ">>"; + std::getline(cin, select); + if(select.empty()) + { + // 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::OS_WINDOWS) + { + start = min(11, (int)ranges.size()); + end = min(14, (int)ranges.size()); + } + else if(p->getDescriptor()->getOS() == DFHack::OS_LINUX) + { + start = min(2, (int)ranges.size()); + end = min(4, (int)ranges.size()); + } + else + { + start = 1; + end = 1; + } + break; + } + // I like the C variants here. much less object clutter + else if(sscanf(select.c_str(), "%d-%d", &start, &end) == 2) + { + start = min(start, (int)ranges.size()); + end = min(end, (int)ranges.size()); + break; + } + else + { + continue; + } + break; + } + end++; + cout << "selected ranges:" <::iterator it; + it = ranges.begin() + start; + while (it != ranges.begin() + end) + { + // check if readable + if((*it).read) + { + selected_ranges.push_back(*it); + printRange(&*it); + } + it++; + } +} + +bool getNumber (string prompt, int & output, int def, bool pdef = true) +{ + cout << prompt; + if(pdef) + cout << " default=" << def << endl; + while (1) + { + string select; + cout << ">>"; + std::getline(cin, select); + if(select.empty()) + { + output = def; + break; + } + else if( sscanf(select.c_str(), "%d", &output) == 1 ) + { + break; + } + else + { + continue; + } + } + return true; +} + +bool getString (string prompt, string & output) +{ + cout << prompt; + cout << ">>"; + string select; + std::getline(cin, select); + if(select.empty()) + { + return false; + } + else + { + output = select; + return true; + } +} + +// meh +#pragma pack(1) +struct tilecolors +{ + uint16_t fore; + uint16_t back; + uint16_t bright; +}; +#pragma pack() + +void printFound(vector &found, const char * what) +{ + cout << what << ":" << endl; + for(int i = 0; i < found.size();i++) + { + cout << hex << "0x" << found[i] << endl; + } +} + +void printFoundStrVec(vector &found, const char * what, SegmentedFinder & s) +{ + cout << what << ":" << endl; + for(int i = 0; i < found.size();i++) + { + cout << hex << "0x" << found[i] << endl; + cout << "--------------------------" << endl; + vecTriplet * vt = s.Translate(found[i]); + if(vt) + { + int j = 0; + for(uint32_t idx = vt->start; idx < vt->finish; idx += sizeof(uint32_t)) + { + uint32_t object_ptr; + // deref ptr idx, get ptr to object + if(!s.Read(idx,object_ptr)) + { + cout << "BAD!" << endl; + break; + } + // deref ptr to first object, get ptr to string + uint32_t string_ptr; + if(!s.Read(object_ptr,string_ptr)) + { + cout << "BAD!" << endl; + break; + } + // get string location in our local cache + char * str = s.Translate(string_ptr); + if(!str) + { + cout << "BAD!" << endl; + break; + } + cout << dec << j << ":" << hex << "0x" << object_ptr << " : " << str << endl; + j++; + } + } + else + { + cout << "BAD!" << endl; + break; + } + cout << "--------------------------" << endl; + } +} + +class TokenFactory +{ + DFHack::OSType platform; +public: + TokenFactory(DFHack::OSType platform_in) + { + platform = platform_in; + } + template + T * Build() + { + return new T; + } + template + T * Build(uint64_t offset) + { + return new T(offset); + } +}; +template <> +String * TokenFactory::Build() +{ + switch(platform) + { + case DFHack::OS_WINDOWS: + return new WindowsString(); + case DFHack::OS_LINUX: + case DFHack::OS_APPLE: + return new LinuxString(); + } + return 0; +}; +template <> +String * TokenFactory::Build(uint64_t offset) +{ + switch(platform) + { + case DFHack::OS_WINDOWS: + return new WindowsString(offset); + case DFHack::OS_LINUX: + case DFHack::OS_APPLE: + return new LinuxString(offset); + } + return 0; +}; + +void autoSearch(DFHack::Context * DF, vector & ranges, DFHack::OSType platform) +{ + cout << "stealing memory..." << endl; + SegmentedFinder sf(ranges, DF); + TokenFactory tf(platform); + cout << "done!" << endl; + Struct maps; + maps.Add(tf.Build()); + maps.Add(tf.Build()); + /* + vector allVectors; + vector filtVectors; + vector to_filter; + + cout << "stealing memory..." << endl; + SegmentedFinder sf(ranges, DF); + cout << "looking for vectors..." << endl; + sf.Find(0,4,allVectors, vectorAll); + + filtVectors = allVectors; + cout << "-------------------" << endl; + cout << "!!LANGUAGE TABLES!!" << endl; + cout << "-------------------" << endl; + + uint64_t kulet_vector; + uint64_t word_table_offset; + uint64_t DWARF_vector; + uint64_t DWARF_object; + + // find lang vector (neutral word table) + to_filter = filtVectors; + sf.Filter("ABBEY",to_filter, vectorStringFirst); + uint64_t lang_addr = to_filter[0]; + + // find dwarven language word table + to_filter = filtVectors; + sf.Filter("kulet",to_filter, vectorStringFirst); + kulet_vector = to_filter[0]; + + // find vector of languages + to_filter = filtVectors; + sf.Filter("DWARF",to_filter, vectorStringFirst); + + // verify + for(int i = 0; i < to_filter.size(); i++) + { + vecTriplet * vec = sf.Translate(to_filter[i]); + if(((vec->finish - vec->start) / 4) == 4) // verified + { + DWARF_vector = to_filter[i]; + DWARF_object = sf.Read(vec->start); + // compute word table offset from dwarf word table and dwarf language object addresses + word_table_offset = kulet_vector - DWARF_object; + break; + } + } + cout << "translation vector: " << hex << "0x" << DWARF_vector << endl; + cout << "lang vector: " << hex << "0x" << lang_addr << endl; + cout << "word table offset: " << hex << "0x" << word_table_offset << endl; + + cout << "-------------" << endl; + cout << "!!MATERIALS!!" << endl; + cout << "-------------" << endl; + // inorganics vector + to_filter = filtVectors; + //sf.Find(257 * 4,4,to_filter,vectorLength); + sf.Filter("IRON",to_filter, vectorString); + sf.Filter("ONYX",to_filter, vectorString); + sf.Filter("RAW_ADAMANTINE",to_filter, vectorString); + sf.Filter("BLOODSTONE",to_filter, vectorString); + printFound(to_filter,"inorganics"); + + // organics vector + to_filter = filtVectors; + sf.Filter(52 * 4,to_filter,vectorLength); + sf.Filter("MUSHROOM_HELMET_PLUMP",to_filter, vectorStringFirst); + printFound(to_filter,"organics"); + + // tree vector + to_filter = filtVectors; + sf.Filter(31 * 4,to_filter,vectorLength); + sf.Filter("MANGROVE",to_filter, vectorStringFirst); + printFound(to_filter,"trees"); + + // plant vector + to_filter = filtVectors; + sf.Filter(21 * 4,to_filter,vectorLength); + sf.Filter("MUSHROOM_HELMET_PLUMP",to_filter, vectorStringFirst); + printFound(to_filter,"plants"); + + // color descriptors + //AMBER, 112 + to_filter = filtVectors; + sf.Filter(112 * 4,to_filter,vectorLength); + sf.Filter("AMBER",to_filter, vectorStringFirst); + printFound(to_filter,"color descriptors"); + if(!to_filter.empty()) + { + uint64_t vec = to_filter[0]; + vecTriplet *vtColors = sf.Translate(vec); + uint32_t colorObj = sf.Read(vtColors->start); + cout << "Amber color:" << hex << "0x" << colorObj << endl; + // TODO: find string 'amber', the floats + } + + // all descriptors + //AMBER, 338 + to_filter = filtVectors; + sf.Filter(338 * 4,to_filter,vectorLength); + sf.Filter("AMBER",to_filter, vectorStringFirst); + printFound(to_filter,"all descriptors"); + + // creature type + //ELEPHANT, ?? (demons abound) + to_filter = filtVectors; + //sf.Find(338 * 4,4,to_filter,vectorLength); + sf.Filter("ELEPHANT",to_filter, vectorString); + sf.Filter("CAT",to_filter, vectorString); + sf.Filter("DWARF",to_filter, vectorString); + sf.Filter("WAMBLER_FLUFFY",to_filter, vectorString); + sf.Filter("TOAD",to_filter, vectorString); + sf.Filter("DEMON_1",to_filter, vectorString); + + vector toad_first = to_filter; + vector elephant_first = to_filter; + sf.Filter("TOAD",toad_first, vectorStringFirst); + sf.Filter("ELEPHANT",elephant_first, vectorStringFirst); + printFoundStrVec(toad_first,"toad-first creature types",sf); + printFound(elephant_first,"elephant-first creature types"); + printFound(to_filter,"all creature types"); + + uint64_t to_use = 0; + if(!elephant_first.empty()) + { + to_use = elephant_first[0]; + vecTriplet *vtCretypes = sf.Translate(to_use); + uint32_t elephant = sf.Read(vtCretypes->start); + uint64_t Eoffset; + cout << "Elephant: 0x" << hex << elephant << endl; + cout << "Elephant: rawname = 0x0" << endl; + uint8_t letter_E = 'E'; + Eoffset = sf.FindInRange (letter_E,equalityP, elephant, 0x300 ); + if(Eoffset) + { + cout << "Elephant: big E = 0x" << hex << Eoffset - elephant << endl; + } + Eoffset = sf.FindInRange ("FEMALE",vectorStringFirst, elephant, 0x300 ); + if(Eoffset) + { + cout << "Elephant: caste vector = 0x" << hex << Eoffset - elephant << endl; + } + Eoffset = sf.FindInRange ("SKIN",vectorStringFirst, elephant, 0x2000 ); + if(Eoffset) + { + cout << "Elephant: extract? vector = 0x" << hex << Eoffset - elephant << endl; + } + tilecolors eletc = {7,0,0}; + Bytestream bs_eletc(&eletc, sizeof(tilecolors)); + cout << bs_eletc; + Eoffset = sf.FindInRange (bs_eletc, findBytestream, elephant, 0x300 ); + if(Eoffset) + { + cout << "Elephant: colors = 0x" << hex << Eoffset - elephant << endl; + } + //cout << "Amber color:" << hex << "0x" << colorObj << endl; + // TODO: find string 'amber', the floats + } + if(!toad_first.empty()) + { + to_use = toad_first[0]; + vecTriplet *vtCretypes = sf.Translate(to_use); + uint32_t toad = sf.Read(vtCretypes->start); + uint64_t Eoffset; + cout << "Toad: 0x" << hex << toad << endl; + cout << "Toad: rawname = 0x0" << endl; + Eoffset = sf.FindInRange (0xF9,equalityP, toad, 0x300 ); + if(Eoffset) + { + cout << "Toad: character (not reliable) = 0x" << hex << Eoffset - toad << endl; + } + Eoffset = sf.FindInRange ("FEMALE",vectorStringFirst, toad, 0x300 ); + if(Eoffset) + { + cout << "Toad: caste vector = 0x" << hex << Eoffset - toad << endl; + } + Eoffset = sf.FindInRange ("SKIN",vectorStringFirst, toad, 0x2000 ); + if(Eoffset) + { + cout << "Toad: extract? vector = 0x" << hex << Eoffset - toad << endl; + } + tilecolors toadtc = {2,0,0}; + Bytestream bs_toadc(&toadtc, sizeof(tilecolors)); + Eoffset = sf.FindInRange (bs_toadc, findBytestream, toad, 0x300 ); + if(Eoffset) + { + cout << "Toad: colors = 0x" << hex << Eoffset - toad << endl; + } + }*/ +} + +int main (void) +{ + string select; + DFHack::ContextManager DFMgr("Memory.xml"); + DFHack::Context * DF = DFMgr.getSingleContext(); + try + { + DF->Attach(); + } + catch (exception& e) + { + cerr << e.what() << endl; + #ifndef LINUX_BUILD + cin.ignore(); + #endif + return 1; + } + DFHack::Process * p = DF->getProcess(); + vector selected_ranges; + getRanges(p,selected_ranges); + + DFHack::VersionInfo *minfo = DF->getMemoryInfo(); + autoSearch(DF,selected_ranges, minfo->getOS()); + #ifndef LINUX_BUILD + cout << "Done. Press any key to continue" << endl; + cin.ignore(); + #endif + return 0; +} diff --git a/tools/playground/incrementalsearch.cpp b/tools/playground/incrementalsearch.cpp index 8c347d0c7..676fbc522 100644 --- a/tools/playground/incrementalsearch.cpp +++ b/tools/playground/incrementalsearch.cpp @@ -21,146 +21,12 @@ using namespace std; #include #include "SegmentedFinder.h" -template -class holder -{ - public: - vector values; - SegmentedFinder & sf; - holder(SegmentedFinder& sff):sf(sff){}; - bool isValid(size_t idx) - { - - }; -}; - -class address -{ - public: - uint64_t addr_; - unsigned int valid : 1; - virtual void print(SegmentedFinder& sff) - { - cout << hex << "0x" << addr_ << endl; - }; - address(const uint64_t addr) - { - addr_ = addr; - valid = false; - } - virtual address & operator=(const uint64_t in) - { - addr_ = in; - valid = false; - return *this; - } - virtual bool isValid(SegmentedFinder& sff) - { - if(valid) return true; - if(sff.getSegmentForAddress(addr_)) - { - valid = 1; - } - } - virtual bool equals (SegmentedFinder & sf, address & rhs) - { - return rhs.addr_ == addr_; - } -}; - -// pointer to a null-terminated byte string -class Cstr: public address -{ - void print(SegmentedFinder & sf) - { - cout << hex << "0x" << addr_ << ": \"" << sf.Translate(addr_) << "\"" << endl; - } - bool equals(SegmentedFinder & sf,const char * rhs) - { - uint32_t addr2 = *(sf.Translate(addr_)); - return strcmp(sf.Translate(addr2), rhs) == 0; - } - template - bool equalsP(SegmentedFinder & sf,inType rhs) - { - return Predicate(addr_, sf, rhs); - } - bool isValid(SegmentedFinder& sf) - { - if (address::isValid(sf)) - { - // read the pointer - uint32_t addr2 = *(sf.Translate(addr_)); - // is it a real pointer? a pretty weak test, but whatever. - if(sf.getSegmentForAddress(addr2)) - return true; - } - return false; - } -}; - -// STL STRING -#ifdef LINUX_BUILD -class STLstr: public address -{ - -}; -#endif -#ifndef LINUX_BUILD -class STLstr: public address -{ - -}; -#endif - -// STL VECTOR -#ifdef LINUX_BUILD -class Vector: public address -{ - -}; -#endif -#ifndef LINUX_BUILD -class Vector: public address -{ - -}; -#endif -class Int64: public address{}; -class Int32: public address{}; -class Int16: public address{}; -class Int8: public address{}; inline void printRange(DFHack::t_memrange * tpr) { std::cout << std::hex << tpr->start << " - " << tpr->end << "|" << (tpr->read ? "r" : "-") << (tpr->write ? "w" : "-") << (tpr->execute ? "x" : "-") << "|" << tpr->name << std::endl; } -string rdWinString( char * offset, SegmentedFinder & sf ) -{ - char * start_offset = offset + 4; - uint32_t length = *(uint32_t *)(offset + 20); - uint32_t capacity = *(uint32_t *)(offset + 24); - char * temp = new char[capacity+1]; - - // read data from inside the string structure - if(capacity < 16) - { - memcpy(temp, start_offset,capacity); - //read(start_offset, capacity, (uint8_t *)temp); - } - else // read data from what the offset + 4 dword points to - { - start_offset = sf.Translate(*(uint32_t*)start_offset); - memcpy(temp, start_offset,capacity); - } - - temp[length] = 0; - string ret = temp; - delete temp; - return ret; -} - bool getRanges(DFHack::Process * p, vector & selected_ranges) { vector ranges; @@ -182,12 +48,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::VersionInfo::OS_WINDOWS) + if(p->getDescriptor()->getOS() == DFHack::OS_WINDOWS) { start = min(11, (int)ranges.size()); end = min(14, (int)ranges.size()); } - else if(p->getDescriptor()->getOS() == DFHack::VersionInfo::OS_LINUX) + else if(p->getDescriptor()->getOS() == DFHack::OS_LINUX) { start = min(2, (int)ranges.size()); end = min(4, (int)ranges.size()); @@ -736,7 +602,7 @@ struct tilecolors }; #pragma pack() -void automatedLangtables(DFHack::Context * DF, vector & ranges) +void autoSearch(DFHack::Context * DF, vector & ranges) { vector allVectors; vector filtVectors; @@ -968,7 +834,7 @@ int main (void) getRanges(p,selected_ranges); DFHack::VersionInfo *minfo = DF->getMemoryInfo(); - DFHack::VersionInfo::OSType os = minfo->getOS(); + DFHack::OSType os = minfo->getOS(); string prompt = "Select search type: 1=number(default), 2=vector by length, 3=vector>object>string,\n" @@ -999,7 +865,7 @@ int main (void) FindStrings(DFMgr, selected_ranges); break; case 5: - automatedLangtables(DF,selected_ranges); + autoSearch(DF,selected_ranges); break; case 6: DF->Detach(); diff --git a/tools/playground/primitives.cpp b/tools/playground/primitives.cpp new file mode 100644 index 000000000..bdf837d62 --- /dev/null +++ b/tools/playground/primitives.cpp @@ -0,0 +1,27 @@ +#include +#include +#include +#include +#include +#include +#include +using namespace std; +std::string teststr1; + std::string * teststr2; + std::string teststr3("test"); +int main (int numargs, const char ** args) +{ + printf("std::string E : 0x%x\n", &teststr1); + teststr1 = "This is a fairly long string, much longer than the one made by default constructor."; + cin.ignore(); + printf("std::string L : 0x%x\n", &teststr1); + teststr1 = "This one is shorter"; + cin.ignore(); + printf("std::string S : 0x%x\n", &teststr1); + cin.ignore(); + teststr2 = new string(); + printf("std::string * : 0x%x\n", &teststr2); + printf("std::string(\"test\") : 0x%x\n", &teststr3); + cin.ignore(); + return 0; +} From e958b8432a8cfd98d3941ea79f3b0a22daa7f29f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Sat, 12 Feb 2011 10:26:36 +0100 Subject: [PATCH 61/94] More work on windos VM map method (compiles, needs testing), some MSVC 2010 nonsense warnings disabled. --- library/DFProcess-windows.cpp | 50 ++++++++++++++++++++++--------- library/include/DFHack_C.h | 2 ++ library/include/dfhack/DFError.h | 1 + library/include/dfhack/DFPragma.h | 12 +++++++- library/modules/Maps_C.cpp | 1 + 5 files changed, 51 insertions(+), 15 deletions(-) diff --git a/library/DFProcess-windows.cpp b/library/DFProcess-windows.cpp index 7b5063b2a..f8f997ea5 100644 --- a/library/DFProcess-windows.cpp +++ b/library/DFProcess-windows.cpp @@ -57,7 +57,7 @@ NormalProcess::NormalProcess(uint32_t pid, vector & known_versio : d(new Private()) { HMODULE hmod = NULL; - DWORD junk; + DWORD needed; HANDLE hProcess; bool found = false; @@ -70,7 +70,7 @@ NormalProcess::NormalProcess(uint32_t pid, vector & known_versio return; // try getting the first module of the process - if(EnumProcessModules(hProcess, &hmod, 1 * sizeof(HMODULE), &junk) == 0) + if(EnumProcessModules(hProcess, &hmod, sizeof(hmod), &needed) == 0) { CloseHandle(hProcess); // cout << "EnumProcessModules fail'd" << endl; @@ -290,7 +290,7 @@ bool NormalProcess::getThreadIDs(vector & threads ) CloseHandle( AllThreads ); return true; } - +/* typedef struct _MEMORY_BASIC_INFORMATION { void * BaseAddress; @@ -301,32 +301,54 @@ typedef struct _MEMORY_BASIC_INFORMATION uint32_t Protect; uint32_t Type; } MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION; - +*/ // FIXME: NEEDS TESTING! void NormalProcess::getMemRanges( vector & ranges ) { MEMORY_BASIC_INFORMATION MBI; - const uint64_t PageSize = 4096; + DWORD needed; + HMODULE hmod; + HMODULE * allModules = 0; + bool hasModules = false; + // get page size + SYSTEM_INFO si; + GetSystemInfo(&si); + uint64_t PageSize = si.dwPageSize; + uint64_t page = 0; - while (VirtualQuery(this->d->my_handle, page * PageSize, sizeof(MBI)) == sizeof(MBI)) + + // get all the modules + if(EnumProcessModules(this->d->my_handle, &hmod, sizeof(hmod), &needed)) + { + allModules = (HMODULE *) malloc(needed); + hasModules = EnumProcessModules(this->d->my_handle, allModules, needed, &needed); + } + + // go through all the VM regions, convert them to our internal format + while (VirtualQueryEx(this->d->my_handle, (const void*) (page * PageSize), &MBI, sizeof(MBI)) == sizeof(MBI)) { page = MBI.RegionSize / PageSize; if(MBI.RegionSize - MBI.RegionSize / PageSize != 0) page ++; // skip over non-whole page - if( !(MBI.Protect & MEM_COMMIT) ) // skip empty regions + if( !(MBI.State & MEM_COMMIT) ) // skip empty regions continue; + // TODO: we could possibly discard regions shared with other processes (DLLs)? + // MBI.Type & MEM_PRIVATE + t_memrange temp; - temp.start = MBI.BaseAddress; - temp.end = MBI.BaseAddress + MBI.RegionSize; - temp.read = MBI.Protect & PAGE_EXECUTE_READ | MBI.Protect & PAGE_EXECUTE_READWRITE | MBI.Protect & PAGE_READONLY | MBI.Protect & PAGE_READWRITE; - temp.write = MBI.Protect & PAGE_EXECUTE_READWRITE | MBI.Protect & PAGE_READWRITE; - temp.execute = MBI.Protect & PAGE_EXECUTE_READ | MBI.Protect & PAGE_EXECUTE_READWRITE | MBI.Protect & PAGE_EXECUTE; - temp.name = "N/A"; // FIXME: pull some relevant names from somewhere... + temp.start = (uint64_t) MBI.BaseAddress; + temp.end = ((uint64_t)MBI.BaseAddress + (uint64_t)MBI.RegionSize); + temp.read = MBI.Protect & PAGE_EXECUTE_READ || MBI.Protect & PAGE_EXECUTE_READWRITE || MBI.Protect & PAGE_READONLY || MBI.Protect & PAGE_READWRITE; + temp.write = MBI.Protect & PAGE_EXECUTE_READWRITE || MBI.Protect & PAGE_READWRITE; + temp.execute = MBI.Protect & PAGE_EXECUTE_READ || MBI.Protect & PAGE_EXECUTE_READWRITE || MBI.Protect & PAGE_EXECUTE; + // FIXME: some relevant description text would be helpful + strcpy(temp.name,"N/A"); ranges.push_back(temp); } - + if(allModules) + free(allModules); } uint8_t NormalProcess::readByte (const uint32_t offset) diff --git a/library/include/DFHack_C.h b/library/include/DFHack_C.h index 6c5dd004f..b23457fda 100644 --- a/library/include/DFHack_C.h +++ b/library/include/DFHack_C.h @@ -25,6 +25,8 @@ distribution. #ifndef DFHACK_C_API #define DFHACK_C_API +#include "dfhack/DFPragma.h" + #include #include #include diff --git a/library/include/dfhack/DFError.h b/library/include/dfhack/DFError.h index 28e11df33..0e4d00145 100644 --- a/library/include/dfhack/DFError.h +++ b/library/include/dfhack/DFError.h @@ -26,6 +26,7 @@ distribution. #define ERROR_H_INCLUDED #include "DFExport.h" +#include "DFPragma.h" #include #include #include diff --git a/library/include/dfhack/DFPragma.h b/library/include/dfhack/DFPragma.h index e678093cc..fb0d395c4 100644 --- a/library/include/dfhack/DFPragma.h +++ b/library/include/dfhack/DFPragma.h @@ -7,8 +7,18 @@ #ifdef _MSC_VER // don't spew nonsense #pragma warning( disable: 4251 ) - // don't display bogus 'deprecation' and 'unsafe' warnings + // don't display bogus 'deprecation' and 'unsafe' warnings. + // See the idiocy: http://msdn.microsoft.com/en-us/magazine/cc163794.aspx + #define _CRT_SECURE_NO_DEPRECATE + #define _SCL_SECURE_NO_DEPRECATE #pragma warning( disable: 4996 ) + // Let me demonstrate: + /** + * [peterix@peterix dfhack]$ man wcscpy_s + * No manual entry for wcscpy_s + * + * Proprietary extensions. + */ // disable stupid #pragma warning( disable: 4800 ) // disable more stupid diff --git a/library/modules/Maps_C.cpp b/library/modules/Maps_C.cpp index 0c5647b16..58e9bb76c 100644 --- a/library/modules/Maps_C.cpp +++ b/library/modules/Maps_C.cpp @@ -22,6 +22,7 @@ must not be misrepresented as being the original software. distribution. */ +#include "dfhack/DFPragma.h" #include #include From 3835ba0f75dad5816a05b45c3720d2c2a241c97f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Mon, 14 Feb 2011 03:58:32 +0100 Subject: [PATCH 62/94] Search tools run on windows and moved to supported, some windows segment/heap/PE section enumeration work. New windows dependency: ntdll.lib --- library/CMakeLists.txt | 2 +- library/DFProcess-linux-SHM.cpp | 1 + library/DFProcess-linux-wine.cpp | 1 + library/DFProcess-linux.cpp | 1 + library/DFProcess-windows-SHM.cpp | 1 + library/DFProcess-windows.cpp | 144 +++++++++++++----- library/depends/ntdll/ntdll.lib | Bin 0 -> 360008 bytes library/include/dfhack/DFProcess.h | 1 + library/include/dfhack/modules/Materials.h | 2 +- library/private/Internal.h | 51 +++++++ tools/playground/CMakeLists.txt | 16 -- tools/supported/CMakeLists.txt | 8 + .../SegmentedFinder.h | 32 +++- .../{playground => supported}/autosearch.cpp | 1 + .../incrementalsearch.cpp | 1 + 15 files changed, 200 insertions(+), 62 deletions(-) create mode 100644 library/depends/ntdll/ntdll.lib rename tools/{playground => supported}/SegmentedFinder.h (94%) rename tools/{playground => supported}/autosearch.cpp (99%) rename tools/{playground => supported}/incrementalsearch.cpp (99%) diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 094d598b3..f921fd140 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -191,7 +191,7 @@ IF(UNIX) SET(PROJECT_LIBS ${X11_LIBRARY} rt ) #dfhack-md5 dfhack-tixml ELSE(UNIX) - SET(PROJECT_LIBS psapi) + SET(PROJECT_LIBS psapi ${CMAKE_SOURCE_DIR}/library/depends/ntdll/ntdll.lib) ENDIF(UNIX) ADD_LIBRARY(dfhack SHARED ${PROJECT_SRCS}) diff --git a/library/DFProcess-linux-SHM.cpp b/library/DFProcess-linux-SHM.cpp index 4eaf47b90..79cf17e1b 100644 --- a/library/DFProcess-linux-SHM.cpp +++ b/library/DFProcess-linux-SHM.cpp @@ -403,6 +403,7 @@ void SHMProcess::getMemRanges( vector & ranges ) temp.read = permissions[0] == 'r'; temp.write = permissions[1] == 'w'; temp.execute = permissions[2] == 'x'; + temp.valid = true; ranges.push_back(temp); } } diff --git a/library/DFProcess-linux-wine.cpp b/library/DFProcess-linux-wine.cpp index ce1916e54..b918f5738 100644 --- a/library/DFProcess-linux-wine.cpp +++ b/library/DFProcess-linux-wine.cpp @@ -219,6 +219,7 @@ void WineProcess::getMemRanges( vector & ranges ) temp.read = permissions[0] == 'r'; temp.write = permissions[1] == 'w'; temp.execute = permissions[2] == 'x'; + temp.valid = true; ranges.push_back(temp); } } diff --git a/library/DFProcess-linux.cpp b/library/DFProcess-linux.cpp index 7d82aa851..64980f6fc 100644 --- a/library/DFProcess-linux.cpp +++ b/library/DFProcess-linux.cpp @@ -201,6 +201,7 @@ void NormalProcess::getMemRanges( vector & ranges ) temp.read = permissions[0] == 'r'; temp.write = permissions[1] == 'w'; temp.execute = permissions[2] == 'x'; + temp.valid = true; ranges.push_back(temp); } } diff --git a/library/DFProcess-windows-SHM.cpp b/library/DFProcess-windows-SHM.cpp index 5630d3146..62a98128c 100644 --- a/library/DFProcess-windows-SHM.cpp +++ b/library/DFProcess-windows-SHM.cpp @@ -440,6 +440,7 @@ void SHMProcess::getMemRanges( vector & ranges ) temp.read = 1; temp.write = 1; temp.execute = 0; // fake + temp.valid = true; strcpy(temp.name,"pants"); ranges.push_back(temp); } diff --git a/library/DFProcess-windows.cpp b/library/DFProcess-windows.cpp index f8f997ea5..6743d0923 100644 --- a/library/DFProcess-windows.cpp +++ b/library/DFProcess-windows.cpp @@ -25,6 +25,7 @@ distribution. #include "dfhack/DFProcess.h" #include "dfhack/VersionInfo.h" #include "dfhack/DFError.h" +#include using namespace DFHack; class NormalProcess::Private @@ -38,6 +39,8 @@ class NormalProcess::Private my_pid = 0; attached = false; suspended = false; + base = 0; + sections = 0; }; ~Private(){}; VersionInfo * my_descriptor; @@ -51,6 +54,9 @@ class NormalProcess::Private uint32_t STLSTR_buf_off; uint32_t STLSTR_size_off; uint32_t STLSTR_cap_off; + IMAGE_NT_HEADERS32 pe_header; + IMAGE_SECTION_HEADER * sections; + uint32_t base; }; NormalProcess::NormalProcess(uint32_t pid, vector & known_versions) @@ -61,8 +67,6 @@ NormalProcess::NormalProcess(uint32_t pid, vector & known_versio HANDLE hProcess; bool found = false; - IMAGE_NT_HEADERS32 pe_header; - IMAGE_SECTION_HEADER sections[16]; d->identified = false; // open process hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pid ); @@ -78,7 +82,7 @@ NormalProcess::NormalProcess(uint32_t pid, vector & known_versio } // got base ;) - uint32_t base = (uint32_t)hmod; + d->base = (uint32_t)hmod; // temporarily assign this to allow some checks d->my_handle = hProcess; @@ -86,9 +90,11 @@ NormalProcess::NormalProcess(uint32_t pid, vector & known_versio // read from this process try { - uint32_t pe_offset = readDWord(base+0x3C); - read(base + pe_offset , sizeof(pe_header), (uint8_t *)&pe_header); - read(base + pe_offset+ sizeof(pe_header), sizeof(sections) , (uint8_t *)§ions ); + uint32_t pe_offset = readDWord(d->base+0x3C); + read(d->base + pe_offset , sizeof(d->pe_header), (uint8_t *)&d->pe_header); + const size_t sectionsSize = sizeof(IMAGE_SECTION_HEADER) * d->pe_header.FileHeader.NumberOfSections; + d->sections = (IMAGE_SECTION_HEADER *) malloc(sectionsSize); + read(d->base + pe_offset + sizeof(d->pe_header), sectionsSize, (uint8_t *)d->sections); d->my_handle = 0; } catch (exception &) @@ -115,7 +121,7 @@ NormalProcess::NormalProcess(uint32_t pid, vector & known_versio { continue; } - if (pe_timestamp != pe_header.FileHeader.TimeDateStamp) + if (pe_timestamp != d->pe_header.FileHeader.TimeDateStamp) continue; // all went well @@ -124,7 +130,7 @@ NormalProcess::NormalProcess(uint32_t pid, vector & known_versio d->identified = true; // give the process a data model and memory layout fixed for the base of first module VersionInfo *m = new VersionInfo(**it); - m->RebaseAll(base); + m->RebaseAll(d->base); // keep track of created memory_info object so we can destroy it later d->my_descriptor = m; m->setParentProcess(this); @@ -170,6 +176,8 @@ NormalProcess::~NormalProcess() { CloseHandle(d->my_main_thread); } + if(d->sections != NULL) + free(d->sections); delete d; } @@ -302,53 +310,111 @@ typedef struct _MEMORY_BASIC_INFORMATION uint32_t Type; } MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION; */ +/* +//Internal structure used to store heap block information. +struct HeapBlock +{ + PVOID dwAddress; + DWORD dwSize; + DWORD dwFlags; + ULONG reserved; +}; +*/ +void HeapNodes(DWORD pid, map & heaps) +{ + // Create debug buffer + PDEBUG_BUFFER db = RtlCreateQueryDebugBuffer(0, FALSE); + // Get process heap data + RtlQueryProcessDebugInformation( pid, PDI_HEAPS/* | PDI_HEAP_BLOCKS*/, db); + ULONG heapNodeCount = db->HeapInformation ? *PULONG(db->HeapInformation):0; + PDEBUG_HEAP_INFORMATION heapInfo = PDEBUG_HEAP_INFORMATION(PULONG(db-> HeapInformation) + 1); + // Go through each of the heap nodes and dispaly the information + for (unsigned int i = 0; i < heapNodeCount; i++) + { + heaps[heapInfo[i].Base] = i; + } + // Clean up the buffer + RtlDestroyQueryDebugBuffer( db ); +} // FIXME: NEEDS TESTING! void NormalProcess::getMemRanges( vector & ranges ) { MEMORY_BASIC_INFORMATION MBI; - DWORD needed; - HMODULE hmod; - HMODULE * allModules = 0; - bool hasModules = false; + map heaps; + uint64_t movingStart = 0; + map nameMap; + // get page size SYSTEM_INFO si; GetSystemInfo(&si); uint64_t PageSize = si.dwPageSize; - - uint64_t page = 0; - - // get all the modules - if(EnumProcessModules(this->d->my_handle, &hmod, sizeof(hmod), &needed)) - { - allModules = (HMODULE *) malloc(needed); - hasModules = EnumProcessModules(this->d->my_handle, allModules, needed, &needed); - } - + // enumerate heaps + HeapNodes(d->my_pid, heaps); // go through all the VM regions, convert them to our internal format - while (VirtualQueryEx(this->d->my_handle, (const void*) (page * PageSize), &MBI, sizeof(MBI)) == sizeof(MBI)) + while (VirtualQueryEx(this->d->my_handle, (const void*) (movingStart), &MBI, sizeof(MBI)) == sizeof(MBI)) { - page = MBI.RegionSize / PageSize; - if(MBI.RegionSize - MBI.RegionSize / PageSize != 0) - page ++; // skip over non-whole page - if( !(MBI.State & MEM_COMMIT) ) // skip empty regions + movingStart = ((uint64_t)MBI.BaseAddress + MBI.RegionSize); + if(movingStart % PageSize != 0) + movingStart = (movingStart / PageSize + 1) * PageSize; + // skip empty regions and regions we share with other processes (DLLs) + if( !(MBI.State & MEM_COMMIT) /*|| !(MBI.Type & MEM_PRIVATE)*/ ) continue; - - // TODO: we could possibly discard regions shared with other processes (DLLs)? - // MBI.Type & MEM_PRIVATE - t_memrange temp; - temp.start = (uint64_t) MBI.BaseAddress; - temp.end = ((uint64_t)MBI.BaseAddress + (uint64_t)MBI.RegionSize); - temp.read = MBI.Protect & PAGE_EXECUTE_READ || MBI.Protect & PAGE_EXECUTE_READWRITE || MBI.Protect & PAGE_READONLY || MBI.Protect & PAGE_READWRITE; - temp.write = MBI.Protect & PAGE_EXECUTE_READWRITE || MBI.Protect & PAGE_READWRITE; + temp.start = (uint64_t) MBI.BaseAddress; + temp.end = ((uint64_t)MBI.BaseAddress + (uint64_t)MBI.RegionSize); + temp.read = MBI.Protect & PAGE_EXECUTE_READ || MBI.Protect & PAGE_EXECUTE_READWRITE || MBI.Protect & PAGE_READONLY || MBI.Protect & PAGE_READWRITE; + temp.write = MBI.Protect & PAGE_EXECUTE_READWRITE || MBI.Protect & PAGE_READWRITE; temp.execute = MBI.Protect & PAGE_EXECUTE_READ || MBI.Protect & PAGE_EXECUTE_READWRITE || MBI.Protect & PAGE_EXECUTE; - // FIXME: some relevant description text would be helpful - strcpy(temp.name,"N/A"); + temp.valid = true; + if(!GetModuleBaseName(this->d->my_handle, (HMODULE) temp.start, temp.name, 1024)) + { + if(nameMap.count(temp.start)) + { + // potential buffer overflow... + strcpy(temp.name, nameMap[temp.start].c_str()); + } + else + { + // filter away shared segments without a name. + if( !(MBI.Type & MEM_PRIVATE) ) + continue; + else + { + // could be a heap? + if(heaps.count(temp.start)) + { + sprintf(temp.name,"HEAP %d",heaps[temp.start]); + } + else temp.name[0]=0; + } + + + + } + } + else + { + // this is our executable! (could be generalized to pull segments from libs, but whatever) + if(d->base == temp.start) + { + for(int i = 0; i < d->pe_header.FileHeader.NumberOfSections; i++) + { + char sectionName[9]; + memcpy(sectionName,d->sections[i].Name,8); + sectionName[8] = 0; + string nm; + nm.append(temp.name); + nm.append(" : "); + nm.append(sectionName); + nameMap[temp.start + d->sections[i].VirtualAddress] = nm; + } + } + else + continue; + } ranges.push_back(temp); } - if(allModules) - free(allModules); } uint8_t NormalProcess::readByte (const uint32_t offset) diff --git a/library/depends/ntdll/ntdll.lib b/library/depends/ntdll/ntdll.lib new file mode 100644 index 0000000000000000000000000000000000000000..9f9cf2108e417b1c26793b6051179ac33f5e561c GIT binary patch literal 360008 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%0Ay!lgp2j>nPin!wFL=daza9!HGXwA1j*~ z<#7F!^5hWfaB)Z7UMEA^Rclsebm1zA4@p+%w8Qlxc*SIFpMuO8A(P8C6fc zv68LyvIZY6bVS`-dmWLktBH@c4sun*zQ4ucj#fXvWd4U+?wc-7a{s<-t9DyZLCj@a9=6DC1KB3@8oNzBtFWG zx_#t3x`w2pZN%zwX(}GiBqI5#Yoy@{yf!Gm_H*Q+rO5`Tak(_+PWE+B?n{2Vzm8z977FNO@$SktC)tal}Slc0} z6ss98HMdc4L|PYK(+g9KB%$_D#Tlz5BBP)7!M^TtbF@*JV$+e=wA8mgE5f5gzE0?Y z9pKzC+QtTSvsKg4N@sHh<Xf>S;8;Q=kCbvGL;+m;#Dq14sZH{&!)ICOt_)wG9 zkMfkut8E8n&gy=eA3Q|mSgX_4LwU$L`QZto$XmiDuf5p#WV z(#m`FQ>j%(o1*=j;^%MjAH+E^R&!f*s=eO<4lu0|M7)=KeC)q&h|N@A5}=& zhV3bCwr>50Qn9LS=hlqhF*$LnQRVKk+iObK%so~A`0DEza2o;1xvQMUthFv^Fnd$+wN=NlV!VlW!MF zlU8yY+V23ptVZIbT{LU(TeN5F>m)reis9ur&i%nQ3Q3WfnfO&H35D4KytufXX;oFro5)?sk|qJ*q9streL~GDSvu~xf)_UJ;HRQJT$FqZi(S>mN2&Ab!TH` zS?0^ON{EdeJFs|&lfkwO-rX@PNhM_o3++{tV}94nRS;XfqVzQClP9g~?e-H(iB!MT zaz_#Vxg}$Ql+;)?T7w%(yhY3HJ5hI{MNc*@_$pzHNa>o>1AZ@7w0K7iYuWU1(^lIZ zq-RQFtDb6Ub5qms)<>+BFSSeDT@sfMd)xnd)b_SbOkKPF@2-y7>S_oY9{ z6vR=6inZ7K?F02X2b#K;wFmzghcD1cskrvN&2Xj4FPvGZccsQEoCTU2c(Ro~Q7f4W zS+;)v$zkvIjk8zQyU~KzJ&DN=v+A&M?MH;MYv+$_ne(5p7zmqL; zzm2leXzxs<#>%}l9^L~?bVj^<#(8s(r(}J^uWFHX1#cOZdU2ji3B|@vItWLYGR%@2 zOTC}8A4j#Fp7G>ud23W;gHNjXc{;{JcYf1#TWA|K<7ee`qrv`IC$VG~lda)dM_UCp ztxL85Yn{-r*8URw&{UJ4yXm6ZK)i({cv=dQi0g8krhZBy6(*CrooRjCHw1$TUV@fypA1Ki=W?b*6&a%9~5p z>l3ZcgxcKK_Gi@Q-6-u;t-n@T`gDH`CB{y?YUgMivB>$+@dKrB8j7|T@EjK zl9vGM=JM$B=yn~Uhql`4mAjyslOtZ6;!CV{V%`&-cA}q<8H=$~rsWX~^9ob1s=doL z_U$#TxAq=VQnd>AxtKYKJF6Hhr(|Nm>QQ}?;jdSvPGqE$p%JzadE<*2awU|!c=hDH zHpWjgDMFvy!P8~FlC!m!x3>D%s{M2BAQPv_sK2A`!7S~~;y z^(8Z-U@)F;ANhKrr*8HyO$^C4Hm}dp?EA9NLN>+q*5v%^@Y zcR4UyEOw*Ay8V^{d+&+N6cH(#eC#w!*3P^-%8-dgc{199mAGS;78!k0{K(3wjpz~( z-S^GX%J!1HrIXhfym z-WuPi;4vxghB(jW{BNzY^yOh6_Y#)MhE>S2^@sB*OBMTeCowf^mB-Ac(p>Yjmhqym zwxS9W!=m^}_8HYsi0+fe=dhfBUMJc{C(}cshe?}9_vBT?Zabbo^*V9;NN+k9?R6zL z%v;TfBvA%GUNq&ExeWR@m*vvuZqUyWN_1%|tZh9bhwI^4>YZ8b)r=q8iRj*6_bP#H zLZtdzIn43e468qW-SDD@3^|s4_4?N7Dchg99hY=%Zn`rmw)3@rjzlZ+k{lp-#W8uw zQc?TO%&NsL#kFY@4As0fIFIXcIH?QIwWx~Lt+v}TAlP}n&<)~+G(+| zE7{w_@r}(yt&V1Eh_&uiP2NWIVq>lJO%ks>##N?LEil2G08_1Mu(*Ies|+mdX{3+ zS8{`dXK#hr^fq;?OK)wgyu&Ot`pM?VV@qq~c5BuqmZ-K_5RoB8r6w<7VXqErliU&Z z`jTEA7i0NvEJx3HVghL|UCGQ2Cq$~R7o4tbJQ=GqC+}k2+su%vm5jyuXam*mQ-+pz z*IUOV)5=y*Tes6+H96JVnH<#iHuF@n?Y&D~hOr$*_BI)}ng;$D7Z0I;OQDu1=+16b%S{n^(ZPOgCn@pVQow<^^EQM^_u9<9A z!PqWMm)TwSB;jn0Y->t1gSFAH)>%c0u6&YomO{2|s?15-sLVCFvl0#B{HjXJBsJNX zSLHg)M(SuwzJ+Fn-TG<+E%}PZpXB_Icv)T-r?Yt$LY@RDs zQ$O-@E19OsSjHQJ#_y*JMZUhY8CkIL`z3u@milw$o~3*H$~jbFMqIIP7fw}jQjE_6 z8li8gTe)&dXZCrC(6ccYOtZX~W0_R(?A=R>TyVU_&A4u})N=jokCSkZQJh3#;K{C- z?0pCOZQOjv^#C~*zR2pk z^TpJ`PYSKgO12Wnn;^~Em8`{-)LJ=v=94DANc7{E=*hBxpRu$|Ey&Q|w$gBYeJRn2 zP9`Ltb~v5$`-sTI6^C~H+HWQ{=J$$;D+#rujYN8tWkFIt4&q-h#57k;{EV@dTN$sE z8{T$YuXW_AV86Q5obcMdpMJI&J6^44A6N7afFEu2WF24b%IR8y*H@yQ5*iy>7Wbd* z@$SQ5n5_|7k0y3YX79jMH*Hm|zx~*sCcg63j32vREEVBzkjFSFGZyXkR7MwAtlQ}s zPyONXGK=$xJz==WR0wU!oxF=w-VBjE-Yk~;!qDcVYJH?s)t$=T)Kk++2(1mXO1;$k zy}lTD602>V^VDy>x_5oO6G&{^=owFabyiB7)POAeo3*86j&oG3y{;_DRGMivccCj) zUTP)2hRQtgS>h?ybak6#X12*lK{idvCjgj(p3*Rxwu8@9y?Lq3U}sbE_SvSYAtjBi zqUB=uLQnlmvaZZnwA)wew(NF##*ego&E&)0h-Ld(vYLE}ryX6bI2MU= zTdRbIwcfv7uar)6eEE<|(Ge>&I`Amv7XDpxbWWJr^ zr^=L)8Y{E1lUmA2_MUCjLO+Q+R%E)1dxLgXqmvBQPnVCeawcn0$@b5U-;`K9^Nfw` zoR0^bamz@F&<|f%YgP^QCWTiMIr7lbeSXxd0<}v@t(8eDRfQ&Tx04YkGbvl2$#s1( zwQ*L%n`=guB6^<0YDYKuQ>F4GR$GTa-f&X_e9qh ziN1cRdo7EF3@H5@%V|-hZ%16$4s?%&G@gZ*=*3;D8-szVsS4Hflht<;1 z-o4sL2twVQ#VYmV%hW<%46M5^m^bUL3jgvck8@@z__nz=;TbA!%%CRzZh&CBajw)HhJpd(ORXi8845m<&CwY zSvMy06i6i$xi=223vVbpgP!BbE^+Gy6khh^XFhb3r4;!vS0r~JZOo#0)tusj#zQ!fST*AF8%&Hwpk?1$#SJ~Kh>|Xz}#bS5nbcxrPIB$O2w)+%@f0nD%}-sJCoJtrkVXFx8VFQZ1yt+zbf`4OJb1cyRWjf+!f7B z{9V(TSxtFz+2>s}D3T=9~8s7PW)!X`ZwSHs5q#El!qB?7{YUx=ULU^>=F9H|u07#XfZ4laX>5?`Y~Q-Q51l zGVsN*oimW~kF_acLLA%44bR-vJfYe&cq1Dh;?gHE6Sq0L%V}ZCCXqMSLPV-BpJI`x z=NcTBX}%xtT?@>&N|NFXyF^O9({x(?P|isu9HX14aMjR0i02<6Nh7TgFw6wvs7wQXJX!*UejQ z+)I%$aU_v;{-Sl<$!iYt72EmBXe1eq>?p_NGI62KXfPQXQ6A*nkQLDQ97)$hrcUf3 zu`FeBC5y9oinKDa6}8^+62qnbDS4-d-x7U+`WmG}myVb_6r1G%9{*tuc|t!!?pfLn z)Vq@!+c{FTqQ~V^xwV#@s)^oTKA7Rl)S|@hXTDTePR;ch9G1q*JuJl}in*T_?Y$>j zPOi`BsN_GK_C33Tp4->LGPpXD}ka`DF{`S}2+bO9J^ZL_h+Zj)exQ!ruRbxUf zmTcVRoxjeE*&UT;N&e#~tyIqPj-btdzGk+! znS9uzZ@kBsAFn}X38U21#-ABF`YMQZ?IYmc0*=*oM3KH}LhI{QCf3fa?4Ej69-8!8 zg&zAE^<&TJ#~s{m&g3a<5YDYM(}Njtc$t!yo2QKv(kSKBpe${gr4rd^jL6c>JX2RN?QqUyJQ%;A zcaPsd)YWM4mOj4&BN=Y!<*3De5@j(~;aE{hl6_J{SBQKSn?`)MFj)(p#A@fQcMsPS zR|Rr5gRb@HZqUo}k|DR2vZR<%fBwNIA8qs;PkxtS&BETet{d5PNq)HQu7LZUURyOy z%lN6t&SYLBHKl(f4{@$e>;YRY?e-bmumyxK?eI<+lckyTW6!k7=t^$eb)rHwdpT;3 zAMW??w$eIp0_NT+FS^gFsi7>T*oWMfo4LBPwPG((4j2MydRaNiR5CtTH8I~+mv_lW zb(0(g@n)wsdg@7+uNjZZSF+D4kFhu*OCYkO<8@bNK_pKv_QVELzFw$vYT5pn=_N}i z_OP-sdW`$Y>@10mlM%fgd3z6M%koV^W-U1UekYqMWu``Ko!$EMYjBPz*3Z3dCV3>S zq&#VvuE5AhMWOzv?49-BilHgQ@kVo!jp6PKto-hEGD9qO-1YNc=i-@VN!5y#$>_Fh z-1l>fGL8=Qc=3{|dfkL*Is(z1DEl9L_cD?p3~kb59e;Q!rrA272euZR(wLgyllNnZ znX$hnrdgapS$&pxNXM?HCyp{5f-e&N(iC6DlXpmsZVksFe&fwiNZ7_tNBb4vSoe8z+vaB??Y3$;e&iJ$?&+D8 zmesKyAPv^Zx+*y|y6Mysfs2PD0LXL~i9zT9)F$BPrm zhNY5(+**1Gdn+@Na7r3lCEoL(x+X5vkPBRQxmGEU#fKzSrFzJ+w9;N|ox969nrfU* ztdVJ*JW=hdkWA{>s@%1dE@%79+0RtV@Dpb*?h2)fr2y7Ptdeb?Q-s($Dgy^@rj>uM z-`GEW$yJ^vXN))cn@O>quf$a=FG*EXKl+ZC@SdNY{QBj~(MVfI6J-B-GU_?-lwu!Q z?*;BMmX1jD?VGi^&bN8fQd=$c!n`>B?ToGwH=0`Ed8e$8xn@ZQ#&?*PESnu~aUEm` zh~l+ijJ2(9-0NgXG%kGbJRVS_qKT0GsTt|}(fzHr%ZF`N?O;J&U-A?63|W%?mVQBU zeWlT2&!M^eIphCau@%^lkL&ZGaVME0w9&Hqd=jHTZWzRuqHLKHo2{#{Xz?QFzWR3E z0X0ynICmnlWhQntZxhNjNePV&lTAJVw7F`(D({?-`SM6&_ncW<_YJviRU#qxHFy#D zHo2!7cPV+&C|=)6n`@Pj@^IzYq|7kAkANg&`+3ZKvNW~6Qr<3ahNK^2$63^`zEPoTpFRQe{ikiUC#XaH8%;qeoArpL375HYFnEr)*{7ZmZp!>>P{?k)v-HV%(z_ z88|Y>VoiO-E;MH);z@a$QtvryBMV!V+fU?(v72tnTr^#plpxX#a~qAkvn0eZ_eOP` zBjq0ZM6~Gf^`A^dKORjsl$Mxkj!8F^>L8-c>HDFGirvp&leY9y`0Mw6Rq zM zBKy3?o;rclLbciP(c~Ie(Jv=@7aN}amw`!2A+}9)BB~zs8LLWJ=erZDe!9!LeQ;fG zAM0P!^1QEm?dJ6WS#sBsce$3_2avO6ZtQBFSk<=%4=@+ZPA;Wl?b%C6p*Tx3uLOEn zlXA7R_iHkSGUgQlr~ztJw4UOxS}@de8W?`WXl~%1tsoU>EUxLI5JHtM7C<;v=VC(Mn`()wV@`D?wJzK z`ODiXqvcpEc4SC;u{dX5GFej3YP8H$OY)Hz>Nt**D%tklWh2X46|8Mo@c3Yb^=exn z-%}mUXe(Z{_^Pp)!#3R5mlG*E@<}h-MzzOq8-BJlv`P&s;xxo*N-TEzgz`|CsX8CW z^#`w+!pLUrG%xmdp2yD+L{StuYgNJ~kdTU%d9cHr)A3w0(I3yCCVom|{z`&-&CQk? ztFQsfOU&Gnp4cR1#zHP;L)^lp^Y_-F#3Ct+EizT@iq)Weq$;}7_}NH{@F|h3uJV}} zS!?mm__U~>p*2sm@aZYrbGlWNAyR#w|Cn(uiETTz(2u{G==8 zc5_TM%2IG`yKJXtwp1m!+gH z+eg~eCP(UQQ0S}FwuU2i=fc@eC(KLK3nkhjum1H!kv@Zz=))uFL#4wMUmjcPIg*i% zS*R3&)y z@eX~uTyNZ{h6!0{F|vg*V7hjlS&Y@RSA<&kBxRjO9A=P6nu{R~V}BeG7+;8S(zv>h{tcUq_` zGn4eT=CMjT^{`#GbKvS^c#w;9Tk}vMZ5z+I+d1&H(q80h+cpQ0LfTgD_P4c-6s)bh zkuTbc&{WUPfL0HDwu-ek^MF)wX*3t}hT zT+{KPmmxpaYH63M{c>Vjs@f@O%E}vWC2Z^%D~`=kcJzjJwjGLzs~i=Rvv{=S){>e< z<1mqg+Gfm@){WzhroD2673D6zit`L{+Aei4Tq_lNHmS<8>P~H?8fE-$JL4)-!HDe8 zCRubR+UPMli6+3#pjb+s5Jmc_g31UduJ!mTm`vQ47=PY?Cuxup8XN88-GQ0pHi|Sl z+D++pilkFt;%KMJWxBe!WYJZ|)O$)lOWxn=uk-5gootTfT?66Zks9M+0H+getK|ET z+K#{alP&XOqkL%{xmRj8*|b)FYi)guyhqm%cO@-Dgnn{gg`3e#q1wn()&mnen`|QI zCBwWWI$W=Cj~(W1^|C#A2Pw;iZMkb%&KxewLrEnTqs`31xlrVYCC#nn0roHOxJRv( zZI>bL=Pq8my(HOEW92>y?Bq~P5+b8dzanoHw_EpEfYHY1v^}xRRWd%b;kd_AY@$ff z(S0lKf}j%>$=%1b5|QR-dcTUeiDS`{7pv5g%btF0f2+4?Rw~T$xjbz+$ukV2?jDpj zDq?SYsN(J@V`c=lbjdTr-qeY$C8d`>HLJfxNSTfA0Tx9pia67kOAEQ!X2 z10dTKJ9lDnl@_XvS^IbPH8^b@t1PkF<=*SUC?)G}^)&5>Ejkavfp=PhHt!4ehs5q6 zBU@^$Qk|aHrHN&>2G;W4U#)NZ@T0RdktMShZL%p2(_(9<7p7oSR12bP9~^Xna#wl$jD85b;qw933tpCc?boLZg|0$?Idnt z!;&TB{jKN~dFjf`5IOqxis|+Qk%1$_qSEA^)lT~Wlyk6B0(AB6o(vv!D`@Kc%#(|y zyk{ypa8B9Nl2F@Z)0tqpEzX!_s)Y85)5cgt=Z*PkiV&Y$er)I|JS^VrSflERLVZ0y z+^W>lhq0if&6&UnyyS%f1C&zGCk5 zWqvGL4S98s+{~3%N9sk+UB}81hjyk3AL~qpj6ob9Y0B%@yeqxcjN&6rv$PpM1C${M zqp~Kz&UMcuk)ss(h-Sm-g2!`ck;N9KZ*$K?o0RSKL=tKQ6c;YshMla1GwfyG zmUs0uijE-k=+Eo@YV~EIg+H-R`fiig26Z+r0fRAh+yTf7N@o&I)KJ6w-XODCu8bnw7SNJ>0pubW2ruyuKeuF<_{ z=PF=pAHVkJ4(@O?Un91b4gBsWB(fw&(LR^5#yVoP~~3wJLAiI&-?*>peTr zMn!VLGjw)#?li7MwAC}q6js|kAmSt`#KwOf-Oj?j+RW7mt@Vpvxt2+(SdGPFNH>d# zc-2fzyyT(Ya59F5J|3(0O;+rbuiZ%ztGcwqgDCMyzGA2OLTu+UH^KiK0J0ua|)AI@>2E&HclOAywRMJ>s@rs z@me&8A}!^Ms%uC122}jX)6LN&DNCgKdCFcqn(|JJFwXJnNB502^u;JU_4}i1Wv6Yq zsZE=`zs}rXW<4~_BZRW#S#HP*Yuvl$2yHY=q*dqTw#nG&cbBYp$b)vAaQY@?7V)PU zaYjvke>BkvAM~<4Rx}mM6giRh@)OV9vSkv>Ivt;jDe-|N_8Mb1!c5D}W}bqv<$WwV zju0o#`{KhZqjM$Le|<8;%SbqM3HMeLimg`=^VR%^dqz zxo*ii+Y0{J>bJu-I(U$F=d?htP#H3{Fzqj1&`d>fC46LnB@kAD)=5C5o0M zv^GN%mC02#CV=Jco$PDoW`NtA#4u9>YguV-)JMx>)4asVywJt3&^!fWOA|DgG4Bq1 zwk#2wN+$B960~*kGpAym_et-Mrs%L}8g>od#~QL_iP%*;u!+|j@}!CQXtLBU!K9M) zp$~`f&}w*8+?FI|$&g!1Gf@jqW!uf9GoP=9pJ)YDPZz%TCVio~!A-l?sM5r!8p$2{(w+o~8L8|od?IRAOllPkJ!KQHUiMSo_!?vc&nWd+N!TLY^Q1N+Dmk4Xse<^dGMuG z*0NPZwdid&rx}6en`JAgEteW|_Pe=_4ne$ zhP!!O786Hj2F=i$xl<6GvZ?4WLM8;mb$LoirzYao5{c zB^Gj_x2Ex>HBTz>=2fe*L$p5aJO`I4iX-ipXYCzUKa<8|S|eqx8{E7%CpY=Jl{|y! zA9tHa>v0CFR4Vom__g8X(b2#DQMU6`r{quG2G2agEs7+4=U92D;X@N}GpP4fb~R^=@3%JurC6z^cLF zx3BN&TeqsSb6|ytC31ZiD*eNqonmry=RnuVC$C!4xzToO|KF2w5(u+DT(>2Xa;!2r z%`J#6s8^DKuJr@vg=Dr})Ek|hSw;H)p5j}>6#B}w&8>;9rc<($XDHdpC#{O}{QvCd zowe3jwYsT)U0>g(;nnNH{zr^S9C3G$mKTO$=(smTFY9+(IeX)R1RdxjbVk5#q!;aAM0lrkmxl zAe5jpv}*OH@>Hc-mnBU3fq(fi>&*-Ne@8D~@|NXCA9w6=$NKS$?a$@M9CNG@oiXc@ zHw3{^?Prj3%`p2tg`fdX!1Buq!BwyqPJeG9xDS?H zUI?y*;`<801Uw9juP6kU!mF_1{rHCYR~CYE;92PTKq0sZ4!R28@Hj00AiiNQoPKp7 zxEBulP$4)Eo`;@m3c-zVz=sRL7I*{}UrQO_RoL*6LU1R{y{-_P4bMW)M@a_`x}J34 z2{`^^h2R<}+)xO{;UPHcK=w-kc2;A!ajH1!7u-C78y;Bi>~nL=h;QPq~JPkcxB@PaG zfcl1KVa>l#4{*qX)B`*NJ^xBQ!0d+#!8X_hCw`6mL-Aqq4-dnVe=7u6z+M=6q!2s+ zi@r`ff<18Bqm&7b{04Eb2R1&&v4Vx)q@3^y3_nggfcgK<@q_1}?+MBY^S(tKJP&B@;30s)`WAxy0SoSjQ73ThgdV$wr>=k6t^Ix2guw*wnaL7-o6W9&ouNH#G;Kcvt zT!T4#Xcw>>PWu_h2~K#8^x&|ca~xnFYT}f3YLDAC7-RM{p|~_QsCjDmds@JAw-# zIG`h#g6E|y3I}%t+u#K_0|4 zfKKuXPeD&tM{o};T7e7>UfB_x4|`!-cSrCXtY1Yv!SOvE!HqEQBKhiV=?JcbH=aycVJ~dy>j<8P{PZk z_-pK87xbLo5!?ocZ^AbOXHb543VKS&;Ls7u1_zANE?^H-$FPUta!2qmEFY(B!h+2l zGuQ{?6SPe@uflIQXAAj)En8{Vu)4~zgu^FkCos20{lcs|Ht;%ZnIbQ+`b>@`EN-9+ zbDOjqD6}~4@B$1@)3)IFZL|%Tvz_w|_Cae$NAN84?WAvjp0ns1VE*5r1H0jjv&k0> zzJoGB-#Hz@!3(Wrq z`UjYOA?d+BX#6AX3^rWU5j+Y#|3n$#sEaw4F!x>52OMxoM{pLr0weDxkI-`|y0GXy z)CbJEj6MK%LEn366R_lR`ZSpHKJp9upmhax1rzTlZP;)nWrQ^!AcUT)I)Zy)=?7`^ zu<&Ypz}ydUo%+5qf>i4Sv5!}@Eqz@Zz zpuXUQk5gZ;@J8wj=6r(l5DGVuS9lKkKZy<;b~9}Y3ZLQ}gWYh(Ez}3}eHwqzeJkf9 zbbp3&z?$1Q2cY}2v^7|EJL$mu&ygqC4HI|Z13EuXe+UcjS^(?6 zNWTwj?xv1m`Il%%aQr=lu<*+q514l^d4&VM!tsVzVf;SYAPoL9?G(E2#|JF?Ds>GD z9^m|hebD+B`VQFeApHY${wsNdBOjulfO%izctGJ{jtA_9@qgnO!oVYx9hQ6@zp&s@ z$^&ow2D-2Zs*jNu*zis22f81peqiyx)AnHA6WGA4Z*eZdZkTwIejY~tgF1koUD&`; z-^K>!K7|b&_#Mg)2R==Dup1`6%Xtj_&tL<~zenC+-m|n#*bCL~(|)1wnI1h0fRU z2Z#R;=R6#^7ae#W&iDm>pl2WXg(bfvO_(1PgUg`sE5+b!2nxmEJUF1E7@P&q!)e80 z@FWbrp%~l)$G@={+ysaIDz*?DPz<)fF6jQXVsJYgKC2kq0!!ai4DN!Z2Vw*Be;pe* z@StLFKJ1n7H;TclP@Rnr82rs*@Bkcta51lK z1;yZgSoVj-;09Q97`kxS9~FbEVfI4OhP^QL$K(M<4lf3e!-_vC2DiboBgi)#_NT?* zDwuO*F*p}?L-o&!!Bfz;h_b?xKQ9K?!|bDq!Nsr#YHvmdPFq|I9)-T6i@_bRWC?W% zM;${53zt$>n0st7xEy9LD+U+B9vD9kAJDhF7~Bhs-$MRj_VMH&UWU{Dq8K~^Jtq`{ z2VwbNa_r#n6N|wWP&O$Fu%6=xb55oFum>hK(7s{C+wlVnH_{$p_Ftg` zufpl4aSWjQuQ{eL|8#uAZW!By430m8;{o$ZloNsxjv+h+t4BF6V98i9xEAJ>v4`C- zK8`)C-puiZBPY;-`4#E_4%ku*&V|=tVk_+&da9Hi7EKm|>tJrJ7+eBDow|jWV0@|= zJPrM4QeUvBfj^klq@BZV7;oVZx~EASj@U-op|G7}4o^V$4$2G*b{2z+U>~&3;<&-^ z-_U;H#Iq?M9QqD);8hquhvNl(@8q0>MdwoYFz;{Cf!AT|JlYj>{~h+Q_IvpuM7iLgf8tz+7h(Oy#o%FB_Ab(d`Ipe|zya^3 zF5xw(U0MuYfYaYY9-!|s>J%2fm$nTDT~6Nwd!YJ0@&E%@P?vDj`^hIPxDs8M^#S@% zcnQ{D#d!qFKZp*@znb#G9@z3B{J`pKC<7e%VeFxBE&T{Q3wE8Wfjq;JAIA^Oxsf`6=V9Oz_<@BtaX!GTPa=a?VB}_w4Ge#Z^A48Y zLOsFUPtz{pHK^T6S}^z-{J`SdsBf6{*+_@qFTvQI zoO`hR3#0)D-^DS2m*I>r7K4Z2#Jf3n;E*p-=dcfI_fS``=F6lHN8C&Q25Id4I9qISao8+VQJYC&g4b|1v)zwv?U;KR+e;2na6JHV&$ zckOp#tnv42{4KpJi$0FOeeXtj{N3z5SR?rRJ^tG7Mcw$@_dd)6{%-Mp!0`8b{4IR| zw2i;14`LqicaIN&Ht~0}52J7RyXHsGe*FC$f5$$G{^M`&$H3$8x9j8R5B~Ok0_y^Q zJ3k4Yg1;Mo3VRm*qEBNE@%LH$&3*=X@OSoSQ5JtU{v6tXzwGm%ef(YS3-}j*(HB7* z`1?Hm4t@!3!rwid(;^{QVk#$9{qK;cxnvpgsKU z{1yJi-_Boy&*1M?zrlLO-{pP_I>X;j@%N(NWl{I{Sd)Lidi^8l;7{OJe?gnC)`<4q zq!E4pj*aL^2OH7XAJB+?-fBcIX*Z&$oNPqbxk3~@s`1FiBN`8HJgo81#zPtpZak=Q zs&TTh-Z;@%YxEnvMz?WEW3|y~v>Pjp<;L;G0~@WzvBuHHQX_9HHWnI38qLN78iyPA zZ``kOapS&?`Nl|(=WZ%xdm3=e& zM)vjWYuQ(`uVi1&zLb42`vS=GbJ=IJ&t#v@K9zkk`$YEf>|@zSvyWsS&OVfVF#ACE z{_K6(d$ads@6O(py)%19_V(;;*;})>WN*&il)W)~L-zXYb=m)AugzYQy*hhU_R8!P z*~_z+WiQQMlD#;4QTD&t|78E2{a5y%*?(mJp8Z?)uh|Q;7i9mE{d4yG?0MO9v*%?0 zl>KA&?Ce?DKV*NO{ayCA+23T(%$|`wJ$qXA)a)tQld~sfPt2Z>JwAI}_Soz(*`u>Z zWsl4rkv%+nSoYBDA=!ho2W6+Sli7N9B3sM)Sug8mmt?D1Cu?Ub*>ZL~dtlbej%7!) zr7X`DvxV$P*32G|9nS8b-7mX1yKgq1U6fsz9m)=7bJ=V*lTBy$$)>Uc*<`jqo5=2+ z-76c<_GK4jd$X}@G~1Ky&PK9b**&v+WOvW*mfbbGOLpgMXLf#eUUqJ_Bio*B%g)Kp z&hC_*mEAGBLw5V@cG+#S+hn)SZk63KyG3^M>}J_bvoo`sWH-)kl-)49L3aJ@df9ce z>txr?u9aOgyGC~P>}uInv#VrR&aRYQF}p%`Mt1q^a@l3G%Vdo#%hD{#Vlb7zq<>ET zl>RaOL;Cylcj<4_-=x1zf0h0+{YCoo^k?Z$)1Rb2PJfjCF#SRL{q%e3chm2r-%h`k zelz_>`t|f{=~vUQq+d?IlzuV&Li+jibLnT(&!nGDKb3wm{Y3il^keBq(~qPdPCt}> zF#SOK{`7t6d(-!%?@r&9zB7GC`u6l~>08scq;F2&l)f>2L;Cvkb?N`5uT5W*zB+wX z`pWbb>C4lXr7ulilD;^7QTo5>|D^w&{#W{+>3^jEp8i|TG-?DSdbKcs)3{$2XF>EEQ!OrMcHJ$+jG)buIolhY@qPfVYXK0bY1`q=a_ z>7&y}rH@P>kv=?qSo+ZPA?btD2c@Udlj(YTB3(=SX)o=jm!zv{CvB%I>2i8JePG&3 zkEKV`r8G|$(}na%+Dspi9!~F{-Y>m4y>B|7UX) !d|UbLnh4lTN4iNvF~S>14V; zok;JU-YXqX_oWx4d(*LWG~JW#PDj#R={?hXq<2s6mfkhJOM2&YXL^2mUV3i2Bi){E zOV3HqPVbbSmEJMELwfu4cIj=?+oZQnZ!jCCua#aiy+(TV^lIr<)2pOcPOp?+F}*^1Mtb@5a_ME$%cPAoOVcz-<1|YD zlKeUOQ}V~;56SP7-zC3Iev|w<`Bn1E-%Y-g zd^`D8^3CKM$=8#wC0|Xxl6*P&Qu4**3(4n`&n2HtK9hVp`Bd`BzpalYdM8HF;t3g5+P4e@>pC zJTG}}@|@(Kl7CE|ojfb~hve^*zf1l$`J3dK$up9tCr?YBnmi?Wa`L3)iOCa^$0v_V z9-BNSd35rqrZ!(sQCVP_I$w;y*xo2{Z46@{Pp;2@mJ%o#9xlT6n`=PLj3vobMa^6&%~dOKNWv6{zUxo_+#-$ z?5zdC+Z{L1(h@yp|v#V?It62CZpQT)I0|HS_t|5yB<@qfhs9{*eXukj1x7sUS( z|8xBO_<8Yj9R(ACB)I-!Hy6zHdAqUld;$ABqpgbMb6E6HmwY ziKpTN@npO|o`~-q-zy%E_r({)d*iWqG~N^Mjz{8M@jc^v#CMPH7T-0#OMK^eXMBEq zUVLu6Bi%`ZNuN7Z2zD9iY_-gT0w82upne)PTQyU}-|Z%5yXz8QTZ`g-)W=&R9JqAy2ZioO_qA^Lpux#+XeXQEF> zpNc*ieIojJ^s(rp(MO^WM<0ql7=0jmfAqfSz0rH3cSrAv-Wk0kdVBP?=&jLPqBlox ziryH#A$ooEI^3zfHhN9;>gZL`E2CFLFOOapy)=4B^y276(f>yO6a9DeU(tU?{}KIr z^l#C>MlXzB5dBN^&(ZUv=S9zro)i63^pDZAqi03`5dD4hchTQMkM+#x8PU_Dr$tYV zo)SGddQ$Yn=n2u|qsK*$jUE#{I(k&}$mkK#;~Ec-9u_?`dPwx(=t0q`=w!4Woru<= ze$9o;IrWps<^=F!cf zn?`3wH;HZ>-3T|mH;AquT`#(Bbe-th(Y2y$M%Re09$hWEYIK$8%F&ggD@Ip{&WJ7_ zT`sz8beX6TWlQLOv+xW-c&rhiX_l>DT|laccOrl(JB6#M$5##Z(A(T(A4&HrE8 z;tO0`^M2uU4=Ac0ZP+yL$;M88vQd6U5_*{;U={CP0QKMC_%CLB*r4xo#2X@qN4!U( zM0P<-Z(7CECYNqr_K7D`09L-jLiz>zg}!;og`~jqFhIR0X86Y227b^cpP`vF_s9(y zt6t0D8J_>D&b`YszvOGZ;tN2|W8V(qEA+|`_)9Mo=@}D>%~idJ$0G1_oZPmL9xv0raO_n?Y52%*#b89tKl-ulT_D^zV}EUp`Z9 zHSeuep)nK9OgyQ^8?Dp78Mis?OLBU}Myc`*JAD^@waAz8fS=}JedvKdN~78C%_Q{{ zF9n4s0puX>2BwY5H-S#fyKo>=c6k6Oxm*Z(ObGjAFxYCGJs7ZcGodk>bnQQaQpxjh zY5a_T2E6n{9*{Bo1!(_LdJ1HkcGjVCf)$kAe*hHn8dBqmga)prY4q|Il~N9JWuO~X z?Q?}&)azCGc|jG-LBf7zOfFqfwKp4N!UElhGaZ!^%`Us_A&?ILu94AWTaoG>`y!EC zAk~i$ID^eYW8}U)r!{IIPve)Vg63MM(z`rAb z%U&Z@+#e7)YA8CYBuAOFBnVXJGZQe#8col^CM8rj=dAVd*@ZJ-?L(BRa}L|cb1kP> zi34AFAlc7Zpb&0PZF;K<=MEhka)V?U11q~;%3k{JV*tX(?p?~ zTl9vD?|f0UhuE^gT3Z7R9r24Jn*g%bzu&AZMgc%A=n zc!Red(`f6Yd_=OI|8jggx0Sp!s$HjBa#rA=!*=N&o{&&~7m{T|;TL@o;B<6z&Mg47ODY z1g7GU*`tryDw%;&cr(5E_}^kHtO$YTZ-cgEaTBDH)JR2d`pfQiwwT${Y(j}gQam%& z4I}5PS8cv~Zb%AsVXXvkTDp=^bdRu&G_ zsBt*~;s#ZN+>)t=3sJ3Dt62)w1vQP<09l6eU=^X9^|-P-pA!h5rz3N?3G~>2sEyXV z_%s};AQ*6e^x7A>%_K4XaUNP>B7V1S)>J6uHw~MZ05eps&eO#%H(WwA3`xb%>$)k9 zfynH29EAH+Elp`Q706*3iO3^5TCRYYjXJq;3B`LvGdY12UCV169$v9P&RaEK1t!5F zqRNa4R&vo4pXk?eIEnOVl3hSrWv6CloVc&qT^#Fn;nzrUFjAd!Z7Slk`81oXOVzOs zMw|VnC|YPT(|{5c5TQ%Osnwo-R6rl@6VzXMvzLRC?S934U8ifZ<)xsL91*A?B(3xb zmfkt01-uC9HK72SB>D8J1fJ;}&Vvb~`9xHz1^zY_t}dTqexT9fla4;q`9egMBH$hoF`4@Y*d({Off<2dQ5p(IU9T-QwVgc~>gL3=*$u=Kq@?;gz;F|^8u?qr|W zvKNI!Q4vn-_E2}A3t#DKE_AZDg&~bL?fj&^X0SPVNN4XQwfsaL@?byR|Q?-LNrQ*n2rmgCr6Shz@? zSVR!MewU)xDc(eBRU?K(8qMmluH1ZViwgUUrJkBCL#=?kUk$d)9t~AF#GsoMVn8CW zWdSSiA_kKhT&p2rSGtz^^#)_}Qoyp(_JYPx#Fd#m=ddSCv4!0RSq=ua6r=Z7ebTgz zFf`3&D3odB;X`x=y02xU57EQhZ+1!ET_PQpB7L~^^%K^5kT(_$b*W4$&Eq+z5G{6v zSA&t=6-CUN&BPHr4~9)QHT$Wu?pg3*)>G4U#$8KkH8Pis!(Bk5L*iVoJqo)LY%vOt8CHPyWLOR!8DTZL?Dh@6pMg}XWRF!)0d1Pdx zbvoMO@2EQ62#IRJt82l@e&tLuTPH}x>Z0WGg5-UMIg?`Z_WJ@19+R5xF0@dzWqsaa?aI03f?AVSVV>kMf|CNSl&VrU;6TiJQO z-ejV~@QFEc1e^Tyh0w86U7Wyz8vw>aQEh6Kg+*JPP%_nJ%j z-e!+I%Ti9<|FCCux{O)R@u9-&Rf9CEs{ksRqSB-ll^I6!cB{Hx3#q79!K!No4n4}$ zcoL~+J8H&=J!sqrSTx(A1LG`RmD{nS>n?0AN7mE;yP~8K*G1PBTRO@S_s7-g0jSZg zs}AJaOeC+Wqs#l^#TTc5WIlj!DXxW0kc!(b9~c*&(j zN60A(52$;#qumPAhiN)s%GSt2XAny}0L8??FTAN5(abQSy@gimL0Fp#rdz@w;@V@& z`3f#6{4xeMKM;XRf1E58|xNhZLvVYk{YDgM}RmkujQ?Ut?9afl|UL#1! zGFS>-73IAPunF}YV*spusus4p)$j48qU~%qr!?&HHU*V-``hgD;ZHN?g-Cg5wKgL& z>_<(#PJ~3VaC|rZc;|F=tdc`{2AX1ex)c?VqT?ub1Dlv*YwUCnbXVcVHHZC43xVF7 zuqxwa-P5DOx;VY3Pc^$Z!a<-^vE-Oe-SbvA|%`7?^tK&XvCne%R^ZC@m1}s1{>6vDz>>lyS0|e6P|#Ymn2W>2=)u<4 z`knDMqzVL?C}@m4Omi*riH-cL{6ln@LS7L~B7SVA4tZOP6%Eu|)SeD9 zNES&6KD}wId@((;01GBf6*_?h3a~e`to1ggZrp*G4nL!Yv*=X2`^viM@K5KNwH_&v zSYlL6QWX-h(@kHw1-#@uq-BPnxvi>*Rc0(A>!l+bQNb=4OZ|W=FrP@uho;Ul=`l3z zan9N1QEsso$W)Wu!HsA}<)gzJnu?&?vUvT}c#ypaTcLJ9Z>-p6M%x>BV?qGaMJ1;g z8Ai2+;QEwg%E8K~v$AK(E=k7>un4h?s88SnJTQEO)jb}~C)vk0SdE-0!-_|9u+bVh zS4~tPhmc~`pz$<=wZR+#&FN_&d^BGGOBBpglaEW^+if0Y`9QN(tst6Qr3GNBCbI?R11M=#jj|7*?c7U|B&&oC4_x9c28!mxp?yBu z>5=qF`zu9A#U86Oz+hfmQzEcNw{w(;(@<->w-35RF2jm3?C)LrvXj!u*-~TdB!;Qy z>g@Dbyd+LKjt!iTj3R8};W>y{tiB38Y7@OUNV+2C7p%p*bt8u-( z05!hmOG3UM?RbzGPkJ9+TUjmAmocyLSe)to7~=DY8COK3!i|kJyUV8v%Z$|`%+%;s zKy5H%?PU^5aHL@&RI5YG(lJml7bv+PAGJ=j7VTlU2rU)HWEGmA=bTKjH966aU>2l} zKUcB%D`9ToSAr*6$MX?ufneBrW!6Kj{xMjLGvA;Cl^IK@{K-08HmHzQwBeGqrja-m zmFik3eYCUEY_*woMXHdf#weFk&yW-&G8I2PqTyoI)X{Y$s0mH2I4qXF+|~FvHg)|B48#@M1t?%*n=Ogx(18L$+43lzjv=8OAbFo;-gOk7%zfu+0b zA0S+ccY1*4tBH`Pd~YTL)=8;SlN~9^O4W2he?7B`u#|ypa_V|+H zlnUCTNOf-usbnYTUuK;JN=_ZAkVxg(420n%szyDue7mg$hR2bwEWMLt2f;%?=#Nk zZLcW>E9g+Cdwd3(0CX1`D_1w2ju8082ub4HCh{o5S<9=zbsP!>gECo<4!vq=E>u=% zyH_D4x*98hj*FvqraDE-u8EL~A$O= zZ&Nl17SRMpIntXBWg^TFNe*c=|C%SW_ zYx0+|X6gDZCp4l^+aQu!t52#5U5cMM*_A-|zNZinl8j4C>6PZue3BGy?u5;SrcX3+ z>{R=inPCSwC@KIQ^g0wbo$hZ8UKrq#ZrWoZr0O;yJivs!{t~5lv z{}OSPA)rx<0SlmC!ALEUwres_*9;-I`{(VjS`*$$tciisWxxHjRyK^M#U zq7o9kep}d7XO$O~lr!k~ql;4PKmj*%NZL`ix9il^6Fc;dXzo5n%%qn=hXhFV61|2yBY`kFTC6!hlV~dL;>k6YP@eVGmMPTO?Uv!`1}W zlXT1{)OrZff+^+(iTxKO+(SF%# z^P^sV_l&ch-qpqtFL1fF=m~c^ZM?mhpVR<74D#%P!8dc^C4+q*!}UvRVdhwC$zCkU zEdJ3(LMG8;sL~WYNdVV1kyqEpz-gFHRbqqDY9F>6fT>+tR_m`P92-vH!o<5^(i5U2 z0WwR#MgF4Oom6^x|MZH9?DUS2G+v%QRCgCkwXne|Vj!ad-dNqI+-pcZM`n!%dXxoW zck!lJ_(Z33d~KEXg7LP~ikWF;U={l^O{2mUa3?3yYmRE`2W&8U4eW3Bj_bKaq8T(6 z@MfWE(juVh2OA4o4r4dZ{ZJ_T=U`T|K)r>VUXKkLe-~=~R$f`Dktu_u#12mq^w^0W zbD9QgwYXk)$Y22aGFIKcnh6nbqfb{oECH~0YbA3DMC(`UlW=3k*ILvfqq7U@(VY$t za+A|Kn&n`|oqt?r}7+Fa!LVNIX%@; z=Vg^@&zEkGq@z_W&{GVduq}oQ3N`g))2<&Wk_4-1b82C>L#k3OQK}^{)#7C%7mo&X zR@GTZwL`0{JlrbHqfW!1A+Xb{4_@B7K5V$MLRKUf*R5XcTFJbMvy9l>IaR2x*!c}C zTu67NRs-iCobnK($An=boiF+n=PZLtSAMDwl^H9})0!je?2tK@a9)nMF;Ztc7@QO%Cr`M48G#&BKKaLof?oQ5%EIt)Coi+7RYp zW>ATUZT1g!)*%|QnY^K0)V7wBl3^SckY=0;=KQKZoaixE@YThRu@6!oU_LrGnV0aR zdnQUfMbi*~{fSW|LFu)J8CRAxxr?xn@AYs$ZScT|V~x#NM4Gza;qjCDEYi0eA%&1B zEAD~xTF^Srl9*KPaJ*YLu+I2t-Y^S~0gH7&2e$JiGKYO-Aw5R!= z58PP<=EuFJXabgdJ_Pt9$`W#BbepZzSwu>>u@eJ}2feXYRP~w?tO-7|V6C>3r%}P7Vo}O4WV31kJ&l?SIg0FBFD^g?+Yro} z0K$6St{^vHl|+YPemaiuMnoWus`;|zgJkdhNXr%_lThi1g%Ju@?`D+eH~v!V>z ztjCc?QD-GG`HZ*(0Q1va1R%v`%PmsrQyu7T$$owBT6@7we?1GQ8nMRkj7qIfd}~R7 zrUVBu!wLuhA%wMr%zEt#<8;1#mn@maT79ccU0w2PVx<;JYeHiGa-uBhv7kZ|ODc2I zpS2@a5yz?AGmJ_L5CE9L5Od zL_c8=wv6l1e9`3*g;>|;akl_)=h+^xTp?Nela}!aZVkmrmu(qMy0VBd8?pxiRg(RI zUL_vLUbvb$@St=}WJGfhK$1vRb?U7^6@(A=bevW+G21-_MNZuv^j!NGgo0&ZBMcE3 zxeXt$gX_vY;TC+J6sJx&uY!6Kav=i~UA|}qelt>qY{qs_v$O(~O4l}_u4*U*)|5Gu zwPMoM&UWlU(Vid5AjtqN6v$+eC0x7NVS}hued<^9$_rf0pGuI6*gyHtwbuph%&k_N zTzKh96J|$O7O_e)rvf*_T$QbM#;P)x2Vdr@ngSnQF%f?!=_jXt#i;8 zbcGoTf9tVO3~jClZMkHwyq0KpRdd0g_Mt~J{attJcF=^hNml{!Z*uT}WlU;)F34j5=I zsHSMuI3}WZSGt)vn`dwjNRw_<8v#hZ$Jo7q5DwMjhD0ZK|nx zu1)4@HH{75;_L?8n0e( zc40Lh^=^KhR9&kCX=Cj9AuWxxO7HcQgACGXc`1-6NBA+!a+4Tgv4HTD=M}5-lvj}n zrz-6SudaHR!*30_-V0XfW%oSgp%^_K!nv9lC4Z4RmoHCf8Bj`#jAqy z1jww;&=(0xr%2=kEeL{B2`HhgHJX7I4L{zTVpPp+T zE+=Q0b}4^E*fRb!9Wn%!g@HeLMCe z5*3Y5Yg8snzUos^rr^&ODb|49+n6BKbtjP+TQsSPd6r6^@qo;j?wX^xs=}l?&v^6e zc8fOcr-%NW-9nfuxl=Ytohdyn3%2JT=t1?sX0)A9Ta_})G&I3z)X7ISiB4sLwex+t zl1Qv)y!mxbt@MniVRooFr_WdwD_{W2U;6rrhm-B!YFIbHDr+iv#+zSPpFFaYBiOEDnTM&#!fI?s6X>v&OSOlU^ho%X4f&YIrEc#;IT=o!x|tDB`J zOxk9Uy0^;`8S=B03S?qDM()y@!R4oFS=lola@Tvtn_s6(6ZkG8pDo;DcFm0EZ|bEE z;BZxpNmK9V?5D{qJmV28;2BSW&4qy_11eKBcQu~z=GQ$DRWBqSU|grx?d??{h31Qgo#bmdEN*&~l^UsrL4VoZ%@z}$@#fblSBXcuZkU}(5hP{SDcUWatyCrx zkK%2G@*7U%8s+vTkyf!Y*}Ba#vUREi-Gr)CQh@SIQ491Q#?=`Hpn1F=s!Gpz^XpcE zRf4~2txYVAnwl>Qhjnz9T&;?|N3{tr_aW zAb@Zyq*HnGReJ%cPx+d}g4l-;3)>axzM~*h#t3-aDs}APW)(?a$t4UDp7C@oQWWGY z)t>QmZh198ClfWGTuy-0>f!k>g4~j+E-GZ0Vo|dcstalwtpQrkc(xzCKD6bP9FJ>%(0XxPLAn4xl0 zQ0bgVu~@F%a0$^2Bo#g5X>5*x$n13-MAgqW&P8cTv#CH1%Sc2X(a~}R#B9__jY}xr zBbvzxbPX#!yZKOR7BMS%8z`bWVj^dd9PP4?)%E zdB!71Py1^#y~VeXbIqXfb-fcBNRQ-s#^aihr1=|fKEgBJ{JQTMPkpnooAZo^L|V(9 z%0W>PPUlsdm`?V#Fr-xo`$#QqYpQDusrHOV?J0Z4lc`0o8KNTXRj)|H!&ZEInlvD8z209UICO{)gmWp8tc zxzf_61&IS{0W0q!hPKq;T9;r#c0)~igRyz(UZ}LaAfNP%$HQ3IZIC6jrI_--2F|O&$nI)4oUQbXH@|Mv4c+n(*;HA#=NS(r zeb0EDP~jPGew}VG5&K9SuvH2zE<)&t#7q z7akd@)}ZBp^wN&1(~Xd*7Q8a|vz7Ti4*B3zv$`m`ydZg>5h8^B7M}5dOkKaJZP0kv z)ye*dD6yvO8Sn6(@r6z=I*fmpJ4gB7)y_Kq+iSJezn66T_%XhJ>cI5u;nA^~J=5b; zvj?URxBH9B%YaPIO-z)*0L+Z-JDjh!RK@hMif4|DDEV)$uF;iqdPKBh&UX_0B#&t>~U zMQmsAAptgh@ATN1YWz6Hhn4~j3H>(M#?e2Uj^8qUN&;-x$AQcO@Y|N47D<5Z(fEWz zJ>f7<*a;ioKR01Z;-e+JTq(aV!TDNYcA5waE{N+?RI(QcDu53 zyIs?f$u=D=S4dsEU9%@fcb;vadk&djW0MEX&xvh%^e09qCN-T-j82Uk_`LcddW@f@ zvH0nx9v^ms@!L-D)X40}q^f0VdQ1~C{nE{zvf$~-(eX(=g3~itv#Qk0$U)u4nLQ&D z=I6MsbLKwNy2y{KAt4BpJ_j2=9Uyv;hd+g3lf z+YN-A9QrLXiIqYSJ6`l*2Miw)VAE$!2j{Q|)X>l`y@dIv{(a$yhF`d6pUQaQ?DWVU zJw6vrY`ajU(yu8s4N!`coUzt}MfM^=5r2{V4yvCEy;Cdh*Ao5gcMQCFq|I)S4nxp` zXBc+Qf*eqHEVfSQA1At09!X%C>Id#~iNPMp)n_-?8G6TbhTgF*f%=^m4dJ(YBwm-K8u;kB+aUWeh-0-Cyc=s2NB3-Sgo! zwoIZL&=z#u{GgquwX%A6_^`sd9@tnz*n#?<>`HMX(Z^F^9r}0Iu8S@ho7z3sZyuc) zn;svT7@r>-oti!{H8wqa(ZP|4xv^clE|?l2IHevOL7vIkUAv}64o)dk7JZ2hWA$CT zXjya19mcH*F|5!~(BQ(GOuD*Ik3N{)QDZ0<`vM`?d^79HVG%deLdegcg+jt|&>r4h z_bq6L1|3F7T;1L)YQ4xli5l|jK;IOX5HocsKG4H+ZfT1Jf*0F7cmt+o zZdnrb`GJgWegk1C(H|q6RiI_(clCRgn{X#(#{hwK{m{m$IwYe&o7OZD76k_8Zwhnl zrxb%73n1I9V2Q!+ta)}$=NV=}7*Gk(dLs#AR=bErZMx^t1RXN*PJCso zjdhcco@zH&S_^LZpn7L-FnesRecYdMvIGc(b++wb3j!V7StNSViycD)R=q($Z%-C_ zuw~ed9|h#hH<=7cM_?6OM%_z#9gBPoAFKHIEdHn6*8BRCpz;SkWQW3i2(sl=SC z0zkV8%VD5Pu;QMEdX?6vZggemR8BO)n>eKtqLI%LTpNQY=^D1HFg)hL+s`aXS*1d2 zFDAGYDq1zW957m>!(i5Vf+0-=lPN+4SDM61s5FeNNcSvE*_y8+lQ5F4h58loDL}MQ zx1ut%bZwPb{Ivn52QB0o&)UMmgjS^4OAj}<80kuLT35>RTQ7`iZH_9_S`Vm+)si4^ z)|=V7lDw2_jBQJ~tjTQ=Qc&s1M%0<#+A0D@xF(NTK8$t7WJ=;EdzVAywuq~)QY!!h zpBIeZG>^uIEK__;1$DU(EExqCz|J(-2b2wjeR#o4xBw(;K6d~#&DUEZn+z8Uc!t9z z*b>t!rggf($?mcyo)H9j^QnKo%I!FiR5^=u1PU!NND=2AW0 zZKZ`4gMb?V1{})AaJS^3O)UvL1mRY?DY(pF?s>+ScQ;usGTZVH?tn*>0^ok)(slN6pcZOY-OcMxh)9x05R-n?hMOI zpwdi8Iys$@xvQN#X#*|)jDK} zZ=>huFozSxNd+fV_zk#1=-~{)Ox>%ue5B#*)h6p+Nnr)X@2;dM&2@+jiYo~IRLtO* zK&TpP%3jwHvy?-X=v5TVVvXAih(Jw%q zp?(2Sy_YN7d{5$$)2hIlPw|0Wiprh=zeDGl@yldu%+ZD$Z(BT*0y-zkNj^QXPKGMj`f51<<>L*x$v| z0E5Pv$YH*cZ`W zk*g%F_+TfiNU7h?!&E0^aUZH%P+#1TXMK)}vw)AId>&wUt$aezI_U(k!m|Z2yn&Ig zd%_?}SBeRRZWm+$xyaG7>MgoJt<{+djL%jkXrZ`jR7Hhn4x&E_&U?I1a!PDTQMIjLYVEG6_G^0{3K=#vb`{id5w%XG@j<6XEPb6Hr_fWznm!3-$AQe2h z`ssuzH(U9Dq69UoOw58US;px-sjzkV4=Y4+#q$aS)pz72g_=qy)*-efn+ReR4OKVl zB~GQ1eZfesrs^jcreXd=43kRiwfr2T07a{&k;)OmBTvN!H(4&tb`&kRw8Sk=ZRdo5%B~SZI2!`|v^!x-e51Hx5E7$I>%- zDG-~sT!B@P;|=V6(rb;*rS0#$1{e^9!u976K0?WzrgcMTd~3QDZM}%vJjUB#FpqN* z>#}jE4;9iH97g5v+Q}Ixz?%+OQfMrLRk=WU&-DEC`RZ~kBmN|<4K_nVfHQi|xr-u) z$o?#!s$in4ILLDHWQXrZeVT%m<1$z%dDPE)I_`+i9+9IBhnvA1jw~DlEWrSj>7+e%J@MpIOUqQ%wqVh=Yv^LF4B!H>f04dHp0~CrprW zYwt=CfK&a3<6VXy_rj|Uk0%S^r^{=jKly75wV2UxzW>WvbZ|be z7ufD9I^hWl)X0iWg_3=m_m&_V>T&P|dy`8vt&>Ypay+6?nK(EwWMn7xy9%u2RK`iS zigemv>ycA>K99)FMYTY<@$turQ8VN435wIp4A9%RRMo8RXT?|XU6^ftEt6y{r<+QZ ziBIHZ^+IP^hx~N2%=t}_9Z%YpHgx`!t1_e?L3d!>R-T^IO}z)FXbMU`sTgfGR#Fy+ zz8s*MM_@A~N=o(RSeHxd5d1k=gI0QF&y-~^MTQ540yae(Gk6^jDl3z`aT?9*!-?5( z9?h}k5F4(D>LjT&kWZYN_#oVSj$9awQvj+lQ)@0p(>_ z1mb+>_q5Bc&AX(tDKtoeO67VKro)|0{gyINa?c8|Iw`5sSQVH~OBLxA+*KS3^aHaJ zcl9fRREh`Vxd`e8mj5 zot&NBj-7;<(JNx<^w@_#?LgxYzWC51UKAak!&v%fXW48-e=I}~cjVo{L8RGTI7S(O z)u&V+Sb<}`T@eRERPMoND$bjuYb&eOlx|FcJ?8I^83%lI)FnxFtWC<0v1WJqRDoIW zl@&93a&0TO^RYHu<{!;*fbUZ@V6FJ{&mJZZ*eg`(kda|JwOCL*74y_o1o|p8&7&-` zP1a;gGK9}utl_eZ0O_sS${a=JR+(v{bvz%jwuSx%Sy@1bi)Ri=uV(#ufVnEdz~{1| zg#x8kU9#3RCl<9*yc!8Q3iH=in^#c@R+6yCsDx6=>Yz%NLK#$@SV63uJ4BCNgfsHt zl2>49bF3*NTL_Lcc5<~zFGx?cx}7%dt!k|hAMm6H3Um$Dx5FMV^$^o zvLSoExW9R{wIHGi+ff4>TCO_yy7Y=uFEr^*ynYsTXV|CFCJ8slw$!n|SSOw~#S4}@b+Nu6UeAY@=cyFnld14o*eb-24k zjtV^y=gN_dJe#$apz3N(*z^c5Mx?BZ5daKYWv{zE71hHAT@`c(7&(O~N{+0;W2s1nwe&}dyug_FgLDpn zR*CjJpX4}`88ARcLgngj%Wc)Jmx~vP`KOcPN*PgUYZjS#S(WQ;ejf zA7>Swx3f`ZpUjKZ(}<|*RB1^>6uXWja=nZ^P~K+lzH<>V)Rj;puVC=XgRf=e0B{-( zHx)-4*(iD-(p<(H(w=#6?&F31j5>{g8&I6q8EEM+NQhYM@jU&`1isRY&@8kXrJUvH zltrW}2d>q;@dcLA=0YWk!f;faI6N{%O%+*+J0x=LZDB2_l~?SBif=3>8_EwCM0G+S zz@Z44cKsnAu`L^Mc4_)l+$voT zdh6CQWDM%bOb#DJP1uQnyA}wH)QMn;s$x|^alR%YL!ZdiDc!RfDNGn~!0KV1>|ekR zm^h?lse1BFvj{gRbY}3DIR*!ogPR>MET-fW?0djUtL%dVA=Sy` z)URm;A?GGZjbGGhaRt*Sno!y32xlHOIq<;J$Pkn}S$_(JnPz<$z3p zw^ja+>?lP9YQuz#^sgQ9S(BI#_k1qpHuI;�RHNkS#21ttZkdM|a!nJZ#=@s0 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 B{lEYK literal 0 HcmV?d00001 diff --git a/library/include/dfhack/DFProcess.h b/library/include/dfhack/DFProcess.h index 3743cf4b7..7044e8021 100644 --- a/library/include/dfhack/DFProcess.h +++ b/library/include/dfhack/DFProcess.h @@ -72,6 +72,7 @@ namespace DFHack if (address >= start && address <= end) return true; return false; } + bool valid; uint8_t * buffer; }; diff --git a/library/include/dfhack/modules/Materials.h b/library/include/dfhack/modules/Materials.h index f3ac6425c..9c686f968 100644 --- a/library/include/dfhack/modules/Materials.h +++ b/library/include/dfhack/modules/Materials.h @@ -145,7 +145,7 @@ namespace DFHack void ReadAllMaterials(void); - std::string getType(t_material & mat); + std::string getType(t_material & mat); std::string getDescription(t_material & mat); private: class Private; diff --git a/library/private/Internal.h b/library/private/Internal.h index 3f5d561fa..4c913f8fe 100644 --- a/library/private/Internal.h +++ b/library/private/Internal.h @@ -81,6 +81,57 @@ using namespace std; #include #include #include + #include + #pragma comment(lib,"ntdll.lib") + #pragma comment(lib,"psapi.lib") + typedef LONG NTSTATUS; + #define STATUS_SUCCESS ((NTSTATUS)0x00000000L) + + typedef struct _DEBUG_BUFFER { + HANDLE SectionHandle; + PVOID SectionBase; + PVOID RemoteSectionBase; + ULONG SectionBaseDelta; + HANDLE EventPairHandle; + ULONG Unknown[2]; + HANDLE RemoteThreadHandle; + ULONG InfoClassMask; + ULONG SizeOfInfo; + ULONG AllocatedSize; + ULONG SectionSize; + PVOID ModuleInformation; + PVOID BackTraceInformation; + PVOID HeapInformation; + PVOID LockInformation; + PVOID Reserved[8]; + } DEBUG_BUFFER, *PDEBUG_BUFFER; + + typedef struct _DEBUG_HEAP_INFORMATION + { + ULONG Base; // 0×00 + ULONG Flags; // 0×04 + USHORT Granularity; // 0×08 + USHORT Unknown; // 0x0A + ULONG Allocated; // 0x0C + ULONG Committed; // 0×10 + ULONG TagCount; // 0×14 + ULONG BlockCount; // 0×18 + ULONG Reserved[7]; // 0x1C + PVOID Tags; // 0×38 + PVOID Blocks; // 0x3C + } DEBUG_HEAP_INFORMATION, *PDEBUG_HEAP_INFORMATION; + + // RtlQueryProcessDebugInformation.DebugInfoClassMask constants + #define PDI_MODULES 0x01 + #define PDI_BACKTRACE 0x02 + #define PDI_HEAPS 0x04 + #define PDI_HEAP_TAGS 0x08 + #define PDI_HEAP_BLOCKS 0x10 + #define PDI_LOCKS 0x20 + + extern "C" __declspec(dllimport) NTSTATUS __stdcall RtlQueryProcessDebugInformation( IN ULONG ProcessId, IN ULONG DebugInfoClassMask, IN OUT PDEBUG_BUFFER DebugBuffer); + extern "C" __declspec(dllimport) PDEBUG_BUFFER __stdcall RtlCreateQueryDebugBuffer( IN ULONG Size, IN BOOLEAN EventPair); + extern "C" __declspec(dllimport) NTSTATUS __stdcall RtlDestroyQueryDebugBuffer( IN PDEBUG_BUFFER DebugBuffer); #endif // dfhack dependencies diff --git a/tools/playground/CMakeLists.txt b/tools/playground/CMakeLists.txt index ab1b70165..b47eba0e0 100644 --- a/tools/playground/CMakeLists.txt +++ b/tools/playground/CMakeLists.txt @@ -32,15 +32,6 @@ ADD_EXECUTABLE(primitives primitives.cpp) #ADD_EXECUTABLE(dfitemdesignator itemdesignator.cpp) #TARGET_LINK_LIBRARIES(dfitemdesignator dfhack) -# incrementalsearch - a bit like cheat engine, only DF-specific, very basic -# and Linux-only -IF(UNIX) - ADD_EXECUTABLE(dfautosearch autosearch.cpp) - TARGET_LINK_LIBRARIES(dfautosearch dfhack) - ADD_EXECUTABLE(dfincremental incrementalsearch.cpp) - TARGET_LINK_LIBRARIES(dfincremental dfhack) -ENDIF(UNIX) - # catsplosion - Accelerates pregnancy # Author: Zhentar ADD_EXECUTABLE(dfcatsplosion catsplosion.cpp) @@ -117,10 +108,3 @@ dfprinttiletypes dfhellhole RUNTIME DESTINATION bin ) -IF(UNIX) - install(TARGETS - dfautosearch - dfincremental - RUNTIME DESTINATION bin - ) -ENDIF(UNIX) diff --git a/tools/supported/CMakeLists.txt b/tools/supported/CMakeLists.txt index bc080448a..138ac6a20 100644 --- a/tools/supported/CMakeLists.txt +++ b/tools/supported/CMakeLists.txt @@ -72,6 +72,12 @@ TARGET_LINK_LIBRARIES(dfdoffsets dfhack) ADD_EXECUTABLE(dfweather weather.cpp) TARGET_LINK_LIBRARIES(dfweather dfhack) +# incrementalsearch - a bit like cheat engine, only DF-specific, very basic +ADD_EXECUTABLE(dfautosearch autosearch.cpp) +TARGET_LINK_LIBRARIES(dfautosearch dfhack) +ADD_EXECUTABLE(dfincremental incrementalsearch.cpp) +TARGET_LINK_LIBRARIES(dfincremental dfhack) + IF(UNIX) SET(VEINLOOK_BUILT "NO") @@ -126,5 +132,7 @@ dfsuspend dfflows dfliquids dfweather +dfautosearch +dfincremental RUNTIME DESTINATION bin ) diff --git a/tools/playground/SegmentedFinder.h b/tools/supported/SegmentedFinder.h similarity index 94% rename from tools/playground/SegmentedFinder.h rename to tools/supported/SegmentedFinder.h index eae2d1bf3..f8911e96f 100644 --- a/tools/playground/SegmentedFinder.h +++ b/tools/supported/SegmentedFinder.h @@ -12,18 +12,37 @@ class SegmentFinder { _DF = DF; mr_ = mr; - mr_.buffer = (uint8_t *)malloc (mr_.end - mr_.start); - DF->ReadRaw(mr_.start,(mr_.end - mr_.start),mr_.buffer); - _SF = SF; + if(mr.valid) + { + mr_.buffer = (uint8_t *)malloc (mr_.end - mr_.start); + _SF = SF; + try + { + DF->ReadRaw(mr_.start,(mr_.end - mr_.start),mr_.buffer); + valid = true; + } + catch (DFHack::Error::MemoryAccessDenied &) + { + free(mr_.buffer); + valid = false; + mr.valid = false; // mark the range passed in as bad + cout << "Range 0x" << hex << mr_.start << " - 0x" << mr_.end << dec << " not readable." << endl; + } + } } ~SegmentFinder() { - delete mr_.buffer; + if(valid) + free(mr_.buffer); + } + bool isValid() + { + return valid; } - template bool Find (needleType needle, const uint8_t increment , vector &newfound, comparator oper) { + if(!valid) return !newfound.empty(); //loop for(uint64_t offset = 0; offset < (mr_.end - mr_.start) - sizeof(hayType); offset += increment) { @@ -36,6 +55,7 @@ class SegmentFinder template < class needleType, class hayType, typename comparator > uint64_t FindInRange (needleType needle, comparator oper, uint64_t start, uint64_t length) { + if(!valid) return 0; uint64_t stopper = min((mr_.end - mr_.start) - sizeof(hayType), (start - mr_.start) - sizeof(hayType) + length); //loop for(uint64_t offset = start - mr_.start; offset < stopper; offset +=1) @@ -49,6 +69,7 @@ class SegmentFinder template bool Filter (needleType needle, vector &found, vector &newfound, comparator oper) { + if(!valid) return !newfound.empty(); for( uint64_t i = 0; i < found.size(); i++) { if(mr_.isInRange(found[i])) @@ -65,6 +86,7 @@ class SegmentFinder SegmentedFinder * _SF; DFHack::Context * _DF; DFHack::t_memrange mr_; + bool valid; }; class SegmentedFinder diff --git a/tools/playground/autosearch.cpp b/tools/supported/autosearch.cpp similarity index 99% rename from tools/playground/autosearch.cpp rename to tools/supported/autosearch.cpp index 1edab9797..85540ae88 100644 --- a/tools/playground/autosearch.cpp +++ b/tools/supported/autosearch.cpp @@ -391,6 +391,7 @@ bool getRanges(DFHack::Process * p, vector & selected_ranges } it++; } + return true; } bool getNumber (string prompt, int & output, int def, bool pdef = true) diff --git a/tools/playground/incrementalsearch.cpp b/tools/supported/incrementalsearch.cpp similarity index 99% rename from tools/playground/incrementalsearch.cpp rename to tools/supported/incrementalsearch.cpp index 676fbc522..4c85b181e 100644 --- a/tools/playground/incrementalsearch.cpp +++ b/tools/supported/incrementalsearch.cpp @@ -92,6 +92,7 @@ bool getRanges(DFHack::Process * p, vector & selected_ranges } it++; } + return true; } bool getNumber (string prompt, int & output, int def, bool pdef = true) From 6c9652258d75cf7d1b7a27498737388efda8fce3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Mon, 14 Feb 2011 21:25:02 +0100 Subject: [PATCH 63/94] memory xml bugfix related to valid attribute of the Offsets tag --- data/Memory-ng.xml | 6 +++ library/VersionInfoFactory.cpp | 7 ++- library/private/Internal.h | 96 +++++++++++++++++----------------- 3 files changed, 59 insertions(+), 50 deletions(-) diff --git a/data/Memory-ng.xml b/data/Memory-ng.xml index 537e2a2da..b348abc33 100644 --- a/data/Memory-ng.xml +++ b/data/Memory-ng.xml @@ -2329,6 +2329,12 @@ + + + + + + diff --git a/library/VersionInfoFactory.cpp b/library/VersionInfoFactory.cpp index 3aa3d924c..e41923f4a 100644 --- a/library/VersionInfoFactory.cpp +++ b/library/VersionInfoFactory.cpp @@ -172,8 +172,6 @@ void VersionInfoFactory::ParseOffsets(TiXmlElement * parent, VersionInfo* target TiXmlElement* pEntry; // we get the , look at the children pEntry = parent->FirstChildElement(); - if(!pEntry) - return; const char *cstr_invalid = parent->Attribute("valid"); INVAL_TYPE parent_inval = NOT_SET; if(cstr_invalid) @@ -185,6 +183,11 @@ void VersionInfoFactory::ParseOffsets(TiXmlElement * parent, VersionInfo* target } OffsetGroup * currentGroup = reinterpret_cast (target); currentGroup->setInvalid(parent_inval); + + // we end here if there are no child tags. + if(!pEntry) + return; + breadcrumbs.push_back(groupTriple(pEntry,currentGroup, parent_inval)); } diff --git a/library/private/Internal.h b/library/private/Internal.h index 4c913f8fe..8a6ad69b0 100644 --- a/library/private/Internal.h +++ b/library/private/Internal.h @@ -82,54 +82,54 @@ using namespace std; #include #include #include - #pragma comment(lib,"ntdll.lib") - #pragma comment(lib,"psapi.lib") - typedef LONG NTSTATUS; - #define STATUS_SUCCESS ((NTSTATUS)0x00000000L) - - typedef struct _DEBUG_BUFFER { - HANDLE SectionHandle; - PVOID SectionBase; - PVOID RemoteSectionBase; - ULONG SectionBaseDelta; - HANDLE EventPairHandle; - ULONG Unknown[2]; - HANDLE RemoteThreadHandle; - ULONG InfoClassMask; - ULONG SizeOfInfo; - ULONG AllocatedSize; - ULONG SectionSize; - PVOID ModuleInformation; - PVOID BackTraceInformation; - PVOID HeapInformation; - PVOID LockInformation; - PVOID Reserved[8]; - } DEBUG_BUFFER, *PDEBUG_BUFFER; - - typedef struct _DEBUG_HEAP_INFORMATION - { - ULONG Base; // 0×00 - ULONG Flags; // 0×04 - USHORT Granularity; // 0×08 - USHORT Unknown; // 0x0A - ULONG Allocated; // 0x0C - ULONG Committed; // 0×10 - ULONG TagCount; // 0×14 - ULONG BlockCount; // 0×18 - ULONG Reserved[7]; // 0x1C - PVOID Tags; // 0×38 - PVOID Blocks; // 0x3C - } DEBUG_HEAP_INFORMATION, *PDEBUG_HEAP_INFORMATION; - - // RtlQueryProcessDebugInformation.DebugInfoClassMask constants - #define PDI_MODULES 0x01 - #define PDI_BACKTRACE 0x02 - #define PDI_HEAPS 0x04 - #define PDI_HEAP_TAGS 0x08 - #define PDI_HEAP_BLOCKS 0x10 - #define PDI_LOCKS 0x20 - - extern "C" __declspec(dllimport) NTSTATUS __stdcall RtlQueryProcessDebugInformation( IN ULONG ProcessId, IN ULONG DebugInfoClassMask, IN OUT PDEBUG_BUFFER DebugBuffer); + typedef LONG NTSTATUS; + #define STATUS_SUCCESS ((NTSTATUS)0x00000000L) + + // FIXME: it is uncertain how these map to 64bit + typedef struct _DEBUG_BUFFER + { + HANDLE SectionHandle; + PVOID SectionBase; + PVOID RemoteSectionBase; + ULONG SectionBaseDelta; + HANDLE EventPairHandle; + ULONG Unknown[2]; + HANDLE RemoteThreadHandle; + ULONG InfoClassMask; + ULONG SizeOfInfo; + ULONG AllocatedSize; + ULONG SectionSize; + PVOID ModuleInformation; + PVOID BackTraceInformation; + PVOID HeapInformation; + PVOID LockInformation; + PVOID Reserved[8]; + } DEBUG_BUFFER, *PDEBUG_BUFFER; + + typedef struct _DEBUG_HEAP_INFORMATION + { + ULONG Base; // 0×00 + ULONG Flags; // 0×04 + USHORT Granularity; // 0×08 + USHORT Unknown; // 0x0A + ULONG Allocated; // 0x0C + ULONG Committed; // 0×10 + ULONG TagCount; // 0×14 + ULONG BlockCount; // 0×18 + ULONG Reserved[7]; // 0x1C + PVOID Tags; // 0×38 + PVOID Blocks; // 0x3C + } DEBUG_HEAP_INFORMATION, *PDEBUG_HEAP_INFORMATION; + + // RtlQueryProcessDebugInformation.DebugInfoClassMask constants + #define PDI_MODULES 0x01 + #define PDI_BACKTRACE 0x02 + #define PDI_HEAPS 0x04 + #define PDI_HEAP_TAGS 0x08 + #define PDI_HEAP_BLOCKS 0x10 + #define PDI_LOCKS 0x20 + + extern "C" __declspec(dllimport) NTSTATUS __stdcall RtlQueryProcessDebugInformation( IN ULONG ProcessId, IN ULONG DebugInfoClassMask, IN OUT PDEBUG_BUFFER DebugBuffer); extern "C" __declspec(dllimport) PDEBUG_BUFFER __stdcall RtlCreateQueryDebugBuffer( IN ULONG Size, IN BOOLEAN EventPair); extern "C" __declspec(dllimport) NTSTATUS __stdcall RtlDestroyQueryDebugBuffer( IN PDEBUG_BUFFER DebugBuffer); #endif From 44e9f542376dd9286aa8c01c7313e2a546fe0a30 Mon Sep 17 00:00:00 2001 From: potato Date: Tue, 15 Feb 2011 00:35:43 +0100 Subject: [PATCH 64/94] added some memory offsets to v0.31.18 linux version (enough for dfreveal) --- data/Memory-ng.xml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/data/Memory-ng.xml b/data/Memory-ng.xml index b348abc33..13b477164 100644 --- a/data/Memory-ng.xml +++ b/data/Memory-ng.xml @@ -2332,6 +2332,23 @@ + +
+
+
+
+
+
+
+
+
+
+
+
+ + +
+ From ad5e20727626fc3080e5ea2f404951ede3370f87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Tue, 15 Feb 2011 00:45:37 +0100 Subject: [PATCH 65/94] make veinlook work with less offsets (maybe) --- library/modules/Maps.cpp | 40 ++++++++++++++++++++++++++---------- tools/supported/veinlook.cpp | 40 ++++++++++++++++++++++-------------- 2 files changed, 54 insertions(+), 26 deletions(-) diff --git a/library/modules/Maps.cpp b/library/modules/Maps.cpp index 4df9c38a0..d695cc26f 100644 --- a/library/modules/Maps.cpp +++ b/library/modules/Maps.cpp @@ -57,6 +57,8 @@ struct Maps::Private OffsetGroup *OG_vector; bool Inited; bool Started; + bool hasGeology; + bool hasFeatures; // map between feature address and the read object map local_feature_store; @@ -74,6 +76,7 @@ Maps::Maps(DFContextShared* _d) DFHack::VersionInfo * mem = p->getDescriptor(); Server::Maps::maps_offsets &off = d->offsets; + d->hasFeatures = d->hasGeology = true; // get the offsets once here OffsetGroup *OG_Maps = mem->getGroup("Maps"); @@ -87,7 +90,6 @@ Maps::Maps(DFContextShared* _d) 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"); @@ -100,18 +102,31 @@ Maps::Maps(DFContextShared* _d) off.temperature1_offset = OG_MapBlock->getOffset ("temperature1"); off.temperature2_offset = OG_MapBlock->getOffset ("temperature2"); } - - OffsetGroup *OG_Geology = OG_Maps->getGroup("geology"); + try + { + 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"); + } + } + catch(Error::AllMemdef &) + { + d->hasGeology = false; + } + try + { + d->OG_global_features = OG_Maps->getGroup("features")->getGroup("global"); + d->OG_local_features = OG_Maps->getGroup("features")->getGroup("local"); + } + catch(Error::AllMemdef &) { - 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->hasFeatures = false; } - 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"); @@ -661,6 +676,7 @@ __int16 __userpurge GetGeologicalRegion(__int16 block_X, int X, __i bool Maps::ReadGeology (vector < vector >& assign) { MAPS_GUARD + if(!d->hasGeology) return false; Process *p = d->owner; // get needed addresses and offsets. Now this is what I call crazy. uint16_t worldSizeX, worldSizeY; @@ -730,6 +746,7 @@ bool Maps::ReadGeology (vector < vector >& assign) bool Maps::ReadLocalFeatures( std::map > & local_features ) { MAPS_GUARD + if(!d->hasFeatures) return false; // can't be used without a map! if(!d->block) return false; @@ -822,6 +839,7 @@ bool Maps::ReadLocalFeatures( std::map > & bool Maps::ReadGlobalFeatures( std::vector & features) { MAPS_GUARD + if(!d->hasGeology) return false; // can't be used without a map! if(!d->block) return false; diff --git a/tools/supported/veinlook.cpp b/tools/supported/veinlook.cpp index 90e2f9c29..cb0cbe1a0 100644 --- a/tools/supported/veinlook.cpp +++ b/tools/supported/veinlook.cpp @@ -574,21 +574,18 @@ main(int argc, char *argv[]) y_max = y_max_a; z_max = z_max_a; + bool hasimats = 1; + bool hascmats = 1; + // get stone matgloss mapping if(!Mats->ReadInorganicMaterials()) { - error = "Can't read stone types."; - pDF = 0; - finish(0); + hasimats = 0; } - /* if(!Mats->ReadCreatureTypes()) { - error = "Can't read stone types."; - pDF = 0; - finish(0); + hascmats = 0; } - */ /* // get region geology if(!DF.ReadGeology( layerassign )) @@ -730,8 +727,14 @@ main(int argc, char *argv[]) // restart cleared modules Maps->Start(); Mats->Start(); - Mats->ReadInorganicMaterials(); - Mats->ReadCreatureTypes(); + if(hasimats) + { + Mats->ReadInorganicMaterials(); + } + if(hascmats) + { + Mats->ReadCreatureTypes(); + } uint32_t effectnum; /* if(DF.InitReadEffects(effectnum)) @@ -755,7 +758,8 @@ main(int argc, char *argv[]) // extra processing of the block in the middle if(i == 0 && j == 0) { - do_features(DF, Block, cursorX, cursorY, 50,10, Mats->inorganic); + if(hasimats) + do_features(DF, Block, cursorX, cursorY, 50,10, Mats->inorganic); // read veins Maps->ReadVeins(cursorX+i,cursorY+j,cursorZ,&veinVector,&IceVeinVector,&splatter); @@ -891,8 +895,11 @@ main(int argc, char *argv[]) } } } - gotoxy(50,3); - cprintf("Mineral: %s",Mats->inorganic[veinVector[vein].type].id); + if(hasimats) + { + gotoxy(50,3); + cprintf("Mineral: %s",Mats->inorganic[veinVector[vein].type].id); + } } else if (vein < mineralsize + icesize) { @@ -931,8 +938,11 @@ main(int argc, char *argv[]) } } } - gotoxy(50,3); - cprintf("Spatter: %s",PrintSplatterType(splatter[realvein].mat1,splatter[realvein].mat2,Mats->race).c_str()); + if(hascmats) + { + gotoxy(50,3); + cprintf("Spatter: %s",PrintSplatterType(splatter[realvein].mat1,splatter[realvein].mat2,Mats->race).c_str()); + } } } } From 2d28d1aaf9953fa3cdfd33a039cf3cc7146b4487 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Tue, 15 Feb 2011 00:59:19 +0100 Subject: [PATCH 66/94] memxml fixes --- data/Memory-ng.xml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/data/Memory-ng.xml b/data/Memory-ng.xml index 13b477164..91602c586 100644 --- a/data/Memory-ng.xml +++ b/data/Memory-ng.xml @@ -2332,7 +2332,7 @@ - +
@@ -2345,10 +2345,16 @@
+ + +
+ + + From 4ead59e6986f0feb184cedf0e110d65064e350b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Tue, 15 Feb 2011 01:14:44 +0100 Subject: [PATCH 67/94] Veinlook only needs base maps now. --- tools/supported/veinlook.cpp | 54 +++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/tools/supported/veinlook.cpp b/tools/supported/veinlook.cpp index cb0cbe1a0..222209796 100644 --- a/tools/supported/veinlook.cpp +++ b/tools/supported/veinlook.cpp @@ -549,7 +549,6 @@ main(int argc, char *argv[]) { pDF = DF = DFMgr.getSingleContext(); DF->Attach(); - Mats = DF->getMaterials(); Maps = DF->getMaps(); } catch (exception& e) @@ -560,6 +559,15 @@ main(int argc, char *argv[]) #endif finish(0); } + bool hasmats = true; + try + { + Mats = DF->getMaterials(); + } + catch (exception& e) + { + hasmats = false; + } Process* p = DF->getProcess(); // init the map @@ -568,23 +576,28 @@ main(int argc, char *argv[]) error = "Can't find a map to look at."; finish(0); } - + Maps->getSize(x_max_a,y_max_a,z_max_a); x_max = x_max_a; y_max = y_max_a; z_max = z_max_a; - bool hasimats = 1; - bool hascmats = 1; - - // get stone matgloss mapping - if(!Mats->ReadInorganicMaterials()) - { - hasimats = 0; - } - if(!Mats->ReadCreatureTypes()) + bool hasimats = false; + bool hascmats = false; + + if(hasmats) { - hascmats = 0; + + hascmats = true; + // get stone matgloss mapping + if(Mats->ReadInorganicMaterials()) + { + hasimats = true; + } + if(Mats->ReadCreatureTypes()) + { + hascmats = true; + } } /* // get region geology @@ -726,14 +739,17 @@ main(int argc, char *argv[]) DF->Suspend(); // restart cleared modules Maps->Start(); - Mats->Start(); - if(hasimats) + if(hasmats) { - Mats->ReadInorganicMaterials(); - } - if(hascmats) - { - Mats->ReadCreatureTypes(); + Mats->Start(); + if(hasimats) + { + Mats->ReadInorganicMaterials(); + } + if(hascmats) + { + Mats->ReadCreatureTypes(); + } } uint32_t effectnum; /* From eb1a0b6b22984b863d965a444f43be0572131c51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Wed, 16 Feb 2011 19:29:16 +0100 Subject: [PATCH 68/94] A little cleanup in Context.cpp, started work on 31.19 --- data/Memory-ng.xml | 88 ++++++- library/DFContext.cpp | 439 ---------------------------------- library/modules/Graveyard.cpp | 170 +++++++++++++ library/modules/Items.cpp | 123 ++++++++++ 4 files changed, 380 insertions(+), 440 deletions(-) create mode 100644 library/modules/Graveyard.cpp diff --git a/data/Memory-ng.xml b/data/Memory-ng.xml index 91602c586..f3c3b153a 100644 --- a/data/Memory-ng.xml +++ b/data/Memory-ng.xml @@ -1871,6 +1871,89 @@ + + + + + + + + + +
0xb127f0 +
0xb1307c +
0xe8dee4 +
0xebbfb8 +
0xebbf94 + + + .-"""-. ' \ @@ -2357,7 +2440,10 @@ - + + + + diff --git a/library/DFContext.cpp b/library/DFContext.cpp index c0be5b872..fa4f85b59 100644 --- a/library/DFContext.cpp +++ b/library/DFContext.cpp @@ -99,62 +99,6 @@ bool Context::Detach() } d->allModules.clear(); memset(&(d->s_mods), 0, sizeof(d->s_mods)); - /* - if(d->creatures) - { - delete d->creatures; - d->creatures = 0; - } - if(d->maps) - { - delete d->maps; - d->maps = 0; - } - if(d->gui) - { - delete d->gui; - d->gui = 0; - } - if(d->world) - { - delete d->world; - d->world = 0; - } - if(d->position) - { - delete d->position; - d->position = 0; - } - if(d->materials) - { - delete d->materials; - d->materials = 0; - } - if(d->items) - { - delete d->items; - d->items = 0; - } - if(d->translation) - { - delete d->translation; - d->translation = 0; - } - if(d->vegetation) - { - delete d->vegetation; - d->vegetation = 0; - } - if(d->constructions) - { - delete d->constructions; - d->constructions = 0; - } - if(d->translation) - { - delete d->translation; - d->translation = 0; - }*/ return true; } @@ -236,386 +180,3 @@ MODULE_GETTER(Translation); MODULE_GETTER(Vegetation); MODULE_GETTER(Buildings); MODULE_GETTER(Constructions); -/* -Creatures * Context::getCreatures() -{ - if(!d->creatures) - d->creatures = new Creatures(d); - return d->creatures; -} -*/ -/* -Maps * Context::getMaps() -{ - if(!d->maps) - d->maps = new Maps(d); - return d->maps; -} - -Gui * Context::getGui() -{ - if(!d->gui) - d->gui = new Gui(d); - return d->gui; -} - -WindowIO * Context::getWindow() -{ - if(!d->windowio) - d->windowio = new WindowIO(d); - return d->windowio; -} - -World * Context::getWorld() -{ - if(!d->world) - d->world = new World(d); - return d->world; -} - -Position * Context::getPosition() -{ - if(!d->position) - d->position = new Position(d); - return d->position; -} - -Materials * Context::getMaterials() -{ - if(!d->materials) - d->materials = new Materials(d); - return d->materials; -} - -Items * Context::getItems() -{ - if(!d->items) - d->items = new Items(d); - return d->items; -} - -Translation * Context::getTranslation() -{ - if(!d->translation) - d->translation = new Translation(d); - return d->translation; -} - -Vegetation * Context::getVegetation() -{ - if(!d->vegetation) - d->vegetation = new Vegetation(d); - return d->vegetation; -} - -Buildings * Context::getBuildings() -{ - if(!d->buildings) - d->buildings = new Buildings(d); - return d->buildings; -} - -Constructions * Context::getConstructions() -{ - if(!d->constructions) - d->constructions = new Constructions(d); - return d->constructions; -} -*/ -/* -// returns number of buildings, expects v_buildingtypes that will later map t_building.type to its name - -bool API::InitReadEffects ( uint32_t & numeffects ) -{ - if(d->effectsInited) - FinishReadEffects(); - int effects = 0; - try - { - effects = d->offset_descriptor->getAddress ("effects_vector"); - } - catch(Error::AllMemdef) - { - return false; - } - d->effectsInited = true; - d->p_effect = new DfVector (d->p, effects); - numeffects = d->p_effect->getSize(); - return true; -} - -bool API::ReadEffect(const uint32_t index, t_effect_df40d & effect) -{ - if(!d->effectsInited) - return false; - if(index >= d->p_effect->getSize()) - return false; - - // read pointer from vector at position - uint32_t temp = d->p_effect->at (index); - //read effect from memory - d->p->read (temp, sizeof (t_effect_df40d), (uint8_t *) &effect); - return true; -} - -// use with care! -bool API::WriteEffect(const uint32_t index, const t_effect_df40d & effect) -{ - if(!d->effectsInited) - return false; - if(index >= d->p_effect->getSize()) - return false; - // read pointer from vector at position - uint32_t temp = d->p_effect->at (index); - // write effect to memory - d->p->write(temp,sizeof(t_effect_df40d), (uint8_t *) &effect); - return true; -} - -void API::FinishReadEffects() -{ - if(d->p_effect) - { - delete d->p_effect; - d->p_effect = NULL; - } - d->effectsInited = false; -} - -*/ -/* -bool API::InitReadNotes( uint32_t &numnotes ) -{ - try - { - memory_info * minfo = d->offset_descriptor; - int notes = minfo->getAddress ("notes"); - d->note_foreground_offset = minfo->getOffset ("note_foreground"); - d->note_background_offset = minfo->getOffset ("note_background"); - d->note_name_offset = minfo->getOffset ("note_name"); - d->note_xyz_offset = minfo->getOffset ("note_xyz"); - - d->p_notes = new DfVector (d->p, notes); - d->notesInited = true; - numnotes = d->p_notes->getSize(); - return true; - } - catch (Error::AllMemdef&) - { - d->notesInited = false; - numnotes = 0; - throw; - } -} -bool API::ReadNote (const int32_t index, t_note & note) -{ - if(!d->notesInited) return false; - // read pointer from vector at position - uint32_t temp = d->p_notes->at (index); - note.symbol = d->p->readByte(temp); - note.foreground = d->p->readWord(temp + d->note_foreground_offset); - note.background = d->p->readWord(temp + d->note_background_offset); - d->p->readSTLString (temp + d->note_name_offset, note.name, 128); - d->p->read (temp + d->note_xyz_offset, 3*sizeof (uint16_t), (uint8_t *) ¬e.x); - return true; -} -bool API::InitReadSettlements( uint32_t & numsettlements ) -{ - if(!d->InitReadNames()) return false; - try - { - - memory_info * minfo = d->offset_descriptor; - int allSettlements = minfo->getAddress ("settlements"); - int currentSettlement = minfo->getAddress("settlement_current"); - d->settlement_name_offset = minfo->getOffset ("settlement_name"); - d->settlement_world_xy_offset = minfo->getOffset ("settlement_world_xy"); - d->settlement_local_xy_offset = minfo->getOffset ("settlement_local_xy"); - - d->p_settlements = new DfVector (d->p, allSettlements); - d->p_current_settlement = new DfVector(d->p, currentSettlement); - d->settlementsInited = true; - numsettlements = d->p_settlements->getSize(); - return true; - } - catch (Error::AllMemdef&) - { - d->settlementsInited = false; - numsettlements = 0; - throw; - } -} -bool API::ReadSettlement(const int32_t index, t_settlement & settlement) -{ - if(!d->settlementsInited) return false; - if(!d->p_settlements->getSize()) return false; - - // read pointer from vector at position - uint32_t temp = d->p_settlements->at (index); - settlement.origin = temp; - d->readName(settlement.name, temp + d->settlement_name_offset); - d->p->read(temp + d->settlement_world_xy_offset, 2 * sizeof(int16_t), (uint8_t *) &settlement.world_x); - d->p->read(temp + d->settlement_local_xy_offset, 4 * sizeof(int16_t), (uint8_t *) &settlement.local_x1); - return true; -} - -bool API::ReadCurrentSettlement(t_settlement & settlement) -{ - if(!d->settlementsInited) return false; - if(!d->p_current_settlement->getSize()) return false; - - uint32_t temp = d->p_current_settlement->at(0); - settlement.origin = temp; - d->readName(settlement.name, temp + d->settlement_name_offset); - d->p->read(temp + d->settlement_world_xy_offset, 2 * sizeof(int16_t), (uint8_t *) &settlement.world_x); - d->p->read(temp + d->settlement_local_xy_offset, 4 * sizeof(int16_t), (uint8_t *) &settlement.local_x1); - return true; -} - -void API::FinishReadSettlements() -{ - if(d->p_settlements) - { - delete d->p_settlements; - d->p_settlements = NULL; - } - if(d->p_current_settlement) - { - delete d->p_current_settlement; - d->p_current_settlement = NULL; - } - d->settlementsInited = false; -} - -bool API::getItemIndexesInBox(vector &indexes, - const uint16_t x1, const uint16_t y1, const uint16_t z1, - const uint16_t x2, const uint16_t y2, const uint16_t z2) -{ - if(!d->itemsInited) return false; - indexes.clear(); - uint32_t size = d->p_itm->getSize(); - struct temp2{ - uint16_t coords[3]; - uint32_t flags; - }; - temp2 temp2; - for(uint32_t i =0;ip_itm->at(i); - d->p->read(temp+sizeof(uint32_t),5 * sizeof(uint16_t), (uint8_t *) &temp2); - if(temp2.flags & (1 << 0)){ - if (temp2.coords[0] >= x1 && temp2.coords[0] < x2) - { - if (temp2.coords[1] >= y1 && temp2.coords[1] < y2) - { - if (temp2.coords[2] >= z1 && temp2.coords[2] < z2) - { - indexes.push_back(i); - } - } - } - } - } - return true; -} -*/ -/* -void API::FinishReadNotes() -{ - if(d->p_notes) - { - delete d->p_notes; - d->p_notes = 0; - } - d->notesInited = false; -} -*/ - -/* -bool API::InitReadItems(uint32_t & numitems) -{ - try - { - int items = d->offset_descriptor->getAddress ("items"); - d->item_material_offset = d->offset_descriptor->getOffset ("item_materials"); - - d->p_itm = new DfVector (d->p, items); - d->itemsInited = true; - numitems = d->p_itm->getSize(); - return true; - } - catch (Error::AllMemdef&) - { - d->itemsInited = false; - numitems = 0; - throw; - } -} -bool API::ReadItem (const uint32_t index, t_item & item) -{ - if (!d->itemsInited) return false; - - t_item_df40d item_40d; - - // read pointer from vector at position - uint32_t temp = d->p_itm->at (index); - - //read building from memory - d->p->read (temp, sizeof (t_item_df40d), (uint8_t *) &item_40d); - - // transform - int32_t type = -1; - d->offset_descriptor->resolveObjectToClassID (temp, type); - item.origin = temp; - item.vtable = item_40d.vtable; - item.x = item_40d.x; - item.y = item_40d.y; - item.z = item_40d.z; - item.type = type; - item.ID = item_40d.ID; - item.flags.whole = item_40d.flags; - - //TODO certain item types (creature based, threads, seeds, bags do not have the first matType byte, instead they have the material index only located at 0x68 - d->p->read (temp + d->item_material_offset, sizeof (t_matglossPair), (uint8_t *) &item.material); - //for(int i = 0; i < 0xCC; i++){ // used for item research - // uint8_t byte = MreadByte(temp+i); - // item.bytes.push_back(byte); - //} - return true; -} -void API::FinishReadItems() -{ - if(d->p_itm) - { - delete d->p_itm; - d->p_itm = NULL; - } - d->itemsInited = false; -} -*/ -/* -bool API::ReadItemTypes(vector< vector< t_itemType > > & itemTypes) -{ - memory_info * minfo = d->offset_descriptor; - int matgloss_address = minfo->getAddress("matgloss"); - int matgloss_skip = minfo->getHexValue("matgloss_skip"); - int item_type_name_offset = minfo->getOffset("item_type_name"); - for(int i = 8;i<20;i++) - { - DfVector p_temp (d->p, matgloss_address + i*matgloss_skip); - vector< t_itemType > typesForVec; - for(uint32_t j =0; jp->readSTLString(temp+4,currType.id,128); - d->p->readSTLString(temp+item_type_name_offset,currType.name,128); - //stringsForVec.push_back(string(name)); - typesForVec.push_back(currType); - } - itemTypes.push_back(typesForVec); - } - return true; -} -*/ - diff --git a/library/modules/Graveyard.cpp b/library/modules/Graveyard.cpp new file mode 100644 index 000000000..4abe854f1 --- /dev/null +++ b/library/modules/Graveyard.cpp @@ -0,0 +1,170 @@ +// This is just a graveyard of old 40d code. Things in here COULD be turned into modules, but it requires research. + +bool API::InitReadEffects ( uint32_t & numeffects ) +{ + if(d->effectsInited) + FinishReadEffects(); + int effects = 0; + try + { + effects = d->offset_descriptor->getAddress ("effects_vector"); + } + catch(Error::AllMemdef) + { + return false; + } + d->effectsInited = true; + d->p_effect = new DfVector (d->p, effects); + numeffects = d->p_effect->getSize(); + return true; +} + +bool API::ReadEffect(const uint32_t index, t_effect_df40d & effect) +{ + if(!d->effectsInited) + return false; + if(index >= d->p_effect->getSize()) + return false; + + // read pointer from vector at position + uint32_t temp = d->p_effect->at (index); + //read effect from memory + d->p->read (temp, sizeof (t_effect_df40d), (uint8_t *) &effect); + return true; +} + +// use with care! +bool API::WriteEffect(const uint32_t index, const t_effect_df40d & effect) +{ + if(!d->effectsInited) + return false; + if(index >= d->p_effect->getSize()) + return false; + // read pointer from vector at position + uint32_t temp = d->p_effect->at (index); + // write effect to memory + d->p->write(temp,sizeof(t_effect_df40d), (uint8_t *) &effect); + return true; +} + +void API::FinishReadEffects() +{ + if(d->p_effect) + { + delete d->p_effect; + d->p_effect = NULL; + } + d->effectsInited = false; +} + +bool API::InitReadNotes( uint32_t &numnotes ) +{ + try + { + memory_info * minfo = d->offset_descriptor; + int notes = minfo->getAddress ("notes"); + d->note_foreground_offset = minfo->getOffset ("note_foreground"); + d->note_background_offset = minfo->getOffset ("note_background"); + d->note_name_offset = minfo->getOffset ("note_name"); + d->note_xyz_offset = minfo->getOffset ("note_xyz"); + + d->p_notes = new DfVector (d->p, notes); + d->notesInited = true; + numnotes = d->p_notes->getSize(); + return true; + } + catch (Error::AllMemdef&) + { + d->notesInited = false; + numnotes = 0; + throw; + } +} +bool API::ReadNote (const int32_t index, t_note & note) +{ + if(!d->notesInited) return false; + // read pointer from vector at position + uint32_t temp = d->p_notes->at (index); + note.symbol = d->p->readByte(temp); + note.foreground = d->p->readWord(temp + d->note_foreground_offset); + note.background = d->p->readWord(temp + d->note_background_offset); + d->p->readSTLString (temp + d->note_name_offset, note.name, 128); + d->p->read (temp + d->note_xyz_offset, 3*sizeof (uint16_t), (uint8_t *) ¬e.x); + return true; +} +bool API::InitReadSettlements( uint32_t & numsettlements ) +{ + if(!d->InitReadNames()) return false; + try + { + memory_info * minfo = d->offset_descriptor; + int allSettlements = minfo->getAddress ("settlements"); + int currentSettlement = minfo->getAddress("settlement_current"); + d->settlement_name_offset = minfo->getOffset ("settlement_name"); + d->settlement_world_xy_offset = minfo->getOffset ("settlement_world_xy"); + d->settlement_local_xy_offset = minfo->getOffset ("settlement_local_xy"); + + d->p_settlements = new DfVector (d->p, allSettlements); + d->p_current_settlement = new DfVector(d->p, currentSettlement); + d->settlementsInited = true; + numsettlements = d->p_settlements->getSize(); + return true; + } + catch (Error::AllMemdef&) + { + d->settlementsInited = false; + numsettlements = 0; + throw; + } +} +bool API::ReadSettlement(const int32_t index, t_settlement & settlement) +{ + if(!d->settlementsInited) return false; + if(!d->p_settlements->getSize()) return false; + + // read pointer from vector at position + uint32_t temp = d->p_settlements->at (index); + settlement.origin = temp; + d->readName(settlement.name, temp + d->settlement_name_offset); + d->p->read(temp + d->settlement_world_xy_offset, 2 * sizeof(int16_t), (uint8_t *) &settlement.world_x); + d->p->read(temp + d->settlement_local_xy_offset, 4 * sizeof(int16_t), (uint8_t *) &settlement.local_x1); + return true; +} + +bool API::ReadCurrentSettlement(t_settlement & settlement) +{ + if(!d->settlementsInited) return false; + if(!d->p_current_settlement->getSize()) return false; + + uint32_t temp = d->p_current_settlement->at(0); + settlement.origin = temp; + d->readName(settlement.name, temp + d->settlement_name_offset); + d->p->read(temp + d->settlement_world_xy_offset, 2 * sizeof(int16_t), (uint8_t *) &settlement.world_x); + d->p->read(temp + d->settlement_local_xy_offset, 4 * sizeof(int16_t), (uint8_t *) &settlement.local_x1); + return true; +} + +void API::FinishReadSettlements() +{ + if(d->p_settlements) + { + delete d->p_settlements; + d->p_settlements = NULL; + } + if(d->p_current_settlement) + { + delete d->p_current_settlement; + d->p_current_settlement = NULL; + } + d->settlementsInited = false; +} + +void API::FinishReadNotes() +{ + if(d->p_notes) + { + delete d->p_notes; + d->p_notes = 0; + } + d->notesInited = false; +} diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp index c381184d8..dcb137848 100644 --- a/library/modules/Items.cpp +++ b/library/modules/Items.cpp @@ -357,3 +357,126 @@ std::string Items::getItemDescription(uint32_t itemptr, Materials * Materials) out.append(this->getItemClass(item.matdesc.itemType)); return out; } + +// The OLD items code follows (40d era) +// TODO: merge with the current Items module +/* +bool API::InitReadItems(uint32_t & numitems) +{ + try + { + int items = d->offset_descriptor->getAddress ("items"); + d->item_material_offset = d->offset_descriptor->getOffset ("item_materials"); + + d->p_itm = new DfVector (d->p, items); + d->itemsInited = true; + numitems = d->p_itm->getSize(); + return true; + } + catch (Error::AllMemdef&) + { + d->itemsInited = false; + numitems = 0; + throw; + } +} + +bool API::getItemIndexesInBox(vector &indexes, + const uint16_t x1, const uint16_t y1, const uint16_t z1, + const uint16_t x2, const uint16_t y2, const uint16_t z2) +{ + if(!d->itemsInited) return false; + indexes.clear(); + uint32_t size = d->p_itm->getSize(); + struct temp2{ + uint16_t coords[3]; + uint32_t flags; + }; + temp2 temp2; + for(uint32_t i =0;ip_itm->at(i); + d->p->read(temp+sizeof(uint32_t),5 * sizeof(uint16_t), (uint8_t *) &temp2); + if(temp2.flags & (1 << 0)){ + if (temp2.coords[0] >= x1 && temp2.coords[0] < x2) + { + if (temp2.coords[1] >= y1 && temp2.coords[1] < y2) + { + if (temp2.coords[2] >= z1 && temp2.coords[2] < z2) + { + indexes.push_back(i); + } + } + } + } + } + return true; +} + +bool API::ReadItem (const uint32_t index, t_item & item) +{ + if (!d->itemsInited) return false; + + t_item_df40d item_40d; + + // read pointer from vector at position + uint32_t temp = d->p_itm->at (index); + + //read building from memory + d->p->read (temp, sizeof (t_item_df40d), (uint8_t *) &item_40d); + + // transform + int32_t type = -1; + d->offset_descriptor->resolveObjectToClassID (temp, type); + item.origin = temp; + item.vtable = item_40d.vtable; + item.x = item_40d.x; + item.y = item_40d.y; + item.z = item_40d.z; + item.type = type; + item.ID = item_40d.ID; + item.flags.whole = item_40d.flags; + + //TODO certain item types (creature based, threads, seeds, bags do not have the first matType byte, instead they have the material index only located at 0x68 + d->p->read (temp + d->item_material_offset, sizeof (t_matglossPair), (uint8_t *) &item.material); + //for(int i = 0; i < 0xCC; i++){ // used for item research + // uint8_t byte = MreadByte(temp+i); + // item.bytes.push_back(byte); + //} + return true; +} +void API::FinishReadItems() +{ + if(d->p_itm) + { + delete d->p_itm; + d->p_itm = NULL; + } + d->itemsInited = false; +} +*/ +/* +bool API::ReadItemTypes(vector< vector< t_itemType > > & itemTypes) +{ + memory_info * minfo = d->offset_descriptor; + int matgloss_address = minfo->getAddress("matgloss"); + int matgloss_skip = minfo->getHexValue("matgloss_skip"); + int item_type_name_offset = minfo->getOffset("item_type_name"); + for(int i = 8;i<20;i++) + { + DfVector p_temp (d->p, matgloss_address + i*matgloss_skip); + vector< t_itemType > typesForVec; + for(uint32_t j =0; jp->readSTLString(temp+4,currType.id,128); + d->p->readSTLString(temp+item_type_name_offset,currType.name,128); + //stringsForVec.push_back(string(name)); + typesForVec.push_back(currType); + } + itemTypes.push_back(typesForVec); + } + return true; +} +*/ \ No newline at end of file From 72fd88cff39902b833b3da3dc7981f1c70bcbcd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Thu, 17 Feb 2011 01:18:27 +0100 Subject: [PATCH 69/94] Windows base map offsets --- data/Memory-ng.xml | 65 ++++++++++++++++++++++++++++++++++++---- library/modules/Maps.cpp | 2 +- 2 files changed, 61 insertions(+), 6 deletions(-) diff --git a/data/Memory-ng.xml b/data/Memory-ng.xml index f3c3b153a..37b10b83b 100644 --- a/data/Memory-ng.xml +++ b/data/Memory-ng.xml @@ -1880,11 +1880,66 @@ -
0xb127f0 -
0xb1307c -
0xe8dee4 -
0xebbfb8 -
0xebbf94 +
+
+
+
+
+ + + +
+
+
+
+
+
+
+
+
+
TODO: it's signed! +
+
+ + + + + + + + + + + + + + +
+ + + + + +
+ + + + + LOOKS FINE? +
+
VERIFIED + + VERIFIED + + VERIFIED + + + +
+
+
+
+
+ + +
+
+
+ diff --git a/tools/supported/SegmentedFinder.h b/tools/supported/SegmentedFinder.h index b4ec7c804..852001165 100644 --- a/tools/supported/SegmentedFinder.h +++ b/tools/supported/SegmentedFinder.h @@ -454,7 +454,7 @@ std::istream& operator>> ( std::istream& out, Bytestream& bs ) { small = reads - '0'; state = 0; - bs.insert(big*16 + small); + bs.insert(big*16 + small); } } if((reads >= 'a' && reads <= 'f')) @@ -468,7 +468,7 @@ std::istream& operator>> ( std::istream& out, Bytestream& bs ) { small = reads - 'a' + 10; state = 0; - bs.insert(big*16 + small); + bs.insert(big*16 + small); } } it++; @@ -478,7 +478,7 @@ std::istream& operator>> ( std::istream& out, Bytestream& bs ) if (state == 1) { small = 0; - bs.insert(big*16 + small); + bs.insert(big*16 + small); } } else From f2f79e0c09114d96d105bc3ed5cd414b2a26d53e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Mon, 21 Feb 2011 10:25:21 +0100 Subject: [PATCH 77/94] Fixes for MSVC build errors. --- tools/supported/SegmentedFinder.h | 2 +- tools/supported/autosearch.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/supported/SegmentedFinder.h b/tools/supported/SegmentedFinder.h index 852001165..1ab9cead7 100644 --- a/tools/supported/SegmentedFinder.h +++ b/tools/supported/SegmentedFinder.h @@ -393,7 +393,7 @@ public: return false; if(d->length+sizeof(T) >= d->allocated) Allocate((d->length+sizeof(T)) * 2); - (*(T *)(d->object + d->length)) = what; + (*(T *)( (uint64_t)d->object + d->length)) = what; d->length += sizeof(T); } Bytestreamdata * d; diff --git a/tools/supported/autosearch.cpp b/tools/supported/autosearch.cpp index 85540ae88..6bdff90a3 100644 --- a/tools/supported/autosearch.cpp +++ b/tools/supported/autosearch.cpp @@ -59,6 +59,7 @@ public: virtual bool AcquireOffset(DFHack::VersionInfo * vinfo) { vinfo->getOffset(full_offset_name); + return true; } virtual uint32_t Length() = 0; virtual uint64_t getAbsolute(){if(parent) return parent->getAbsolute() + offset; else return offset;}; From fd831eb2a83152ba0779c44ad066bc1f20389a64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Tue, 22 Feb 2011 22:20:16 +0100 Subject: [PATCH 78/94] LICENSE stuff, some offsets, some search tool tweaks --- LICENSE | 119 ++++++++++++++++++++++++++ data/Memory-ng.xml | 26 +++--- tools/playground/digger2.cpp | 1 - tools/supported/SegmentedFinder.h | 1 + tools/supported/incrementalsearch.cpp | 7 +- tools/supported/vdig.cpp | 15 ++-- 6 files changed, 150 insertions(+), 19 deletions(-) diff --git a/LICENSE b/LICENSE index 9c8259200..4cfc6a66d 100644 --- a/LICENSE +++ b/LICENSE @@ -1,3 +1,5 @@ +---------------------------------------------------------------------- +License of dfhack github.com/peterix/dfhack Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf @@ -19,3 +21,120 @@ must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. + +---------------------------------------------------------------------- +License of library/include/dfhack/DFstdint_win.h + +ISO C9x compliant stdint.h for Microsoft Visual Studio +Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 + + Copyright (c) 2006-2008 Alexander Chemeris + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------------- +License of argstream (used by some utilities for parsing command line params) + +Copyright (C) 2004 Xavier Decoret + +argsteam is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +Foobar is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +This library is used by: +tools/playground/catsplosion.cpp +tools/playground/digger.cpp +tools/supported/vdig.cpp + +---------------------------------------------------------------------------- +License of "RSA Data Security, Inc. MD5 Message-Digest Algorithm" +Used to identify DF binaries. + +Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. +----------------------------------------------------------------- +License of the "RSA Data Security, Inc. MD5 Message-Digest Algorithm" C++ wrapper: + +This is my wrapper-class to create +a MD5 Hash from a string and a file. + +This code is completly free, you +can copy it, modify it, or do +what ever you want with it. + +Feb. 2005 +Benjamin Grüdelbach +------------------------------------------------------------------ +License of the used XML reader library + +www.sourceforge.net/projects/tinyxml +Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com) + +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. \ No newline at end of file diff --git a/data/Memory-ng.xml b/data/Memory-ng.xml index cfe9b833b..23455ce71 100644 --- a/data/Memory-ng.xml +++ b/data/Memory-ng.xml @@ -1939,10 +1939,10 @@
-
-
-
-
+
+
+
+
@@ -2476,14 +2476,14 @@
-
-
-
-
-
+
+
+
+
+
@@ -2496,9 +2496,13 @@ - + - + + + ... stuff + + diff --git a/tools/playground/digger2.cpp b/tools/playground/digger2.cpp index 91507bcc1..dc4e9d271 100644 --- a/tools/playground/digger2.cpp +++ b/tools/playground/digger2.cpp @@ -21,7 +21,6 @@ #include using namespace std; -#include #include #include #define BLOCK_SIZE 16 diff --git a/tools/supported/SegmentedFinder.h b/tools/supported/SegmentedFinder.h index 1ab9cead7..6a0c1042e 100644 --- a/tools/supported/SegmentedFinder.h +++ b/tools/supported/SegmentedFinder.h @@ -395,6 +395,7 @@ public: Allocate((d->length+sizeof(T)) * 2); (*(T *)( (uint64_t)d->object + d->length)) = what; d->length += sizeof(T); + return true; } Bytestreamdata * d; bool constant; diff --git a/tools/supported/incrementalsearch.cpp b/tools/supported/incrementalsearch.cpp index 8b4e93c1c..8dc04cbc4 100644 --- a/tools/supported/incrementalsearch.cpp +++ b/tools/supported/incrementalsearch.cpp @@ -749,8 +749,11 @@ void autoSearch(DFHack::Context * DF, vector & ranges) // organics vector to_filter = filtVectors; - sf.Filter(52 * 4,to_filter,vectorLength); - sf.Filter("MUSHROOM_HELMET_PLUMP",to_filter, vectorStringFirst); + sf.Filter("MUSHROOM_HELMET_PLUMP",to_filter, vectorString); + sf.Filter("MEADOW-GRASS",to_filter, vectorString); + sf.Filter("TUNNEL_TUBE",to_filter, vectorString); + sf.Filter("WEED_BLADE",to_filter, vectorString); + sf.Filter("EYEBALL",to_filter, vectorString); printFound(to_filter,"organics"); // tree vector diff --git a/tools/supported/vdig.cpp b/tools/supported/vdig.cpp index 2b235d4a3..19cb037a5 100644 --- a/tools/supported/vdig.cpp +++ b/tools/supported/vdig.cpp @@ -10,7 +10,7 @@ using namespace std; #include #include -#include +//#include #define MAX_DIM 0x300 @@ -271,10 +271,12 @@ int main (int argc, char* argv[]) { // Command line options bool updown = false; + /* argstream as(argc,argv); as >>option('x',"updown",updown,"Dig up and down stairs to reach other z-levels.") >>help(); + // sane check if (!as.isOk()) @@ -282,6 +284,9 @@ int main (int argc, char* argv[]) cout << as.errorLog(); return 1; } + */ + if(argc > 1 && strcmp(argv[1],"-x") == 0) + updown = true; DFHack::ContextManager DFMgr("Memory.xml"); DFHack::Context * DF; @@ -298,12 +303,12 @@ int main (int argc, char* argv[]) #endif return 1; } - + uint32_t x_max,y_max,z_max; DFHack::Maps * Maps = DF->getMaps(); DFHack::Materials * Mats = DF->getMaterials(); DFHack::Position * Pos = DF->getPosition(); - + // init the map if(!Maps->Start()) { @@ -314,12 +319,12 @@ int main (int argc, char* argv[]) #endif return 1; } - + int32_t cx, cy, cz; Maps->getSize(x_max,y_max,z_max); uint32_t tx_max = x_max * 16; uint32_t ty_max = y_max * 16; - + Pos->getCursorCoords(cx,cy,cz); while(cx == -30000) { From 6ca0dd7c1dbd821da5cf5117446e2cbf0997d2aa Mon Sep 17 00:00:00 2001 From: Tom Prince Date: Wed, 23 Feb 2011 04:01:07 +0100 Subject: [PATCH 79/94] Fix Process class. --- library/DFProcess-linux-SHM.cpp | 2 +- library/DFProcess-linux-wine.cpp | 2 +- library/DFProcess-linux.cpp | 2 +- library/DFProcess-windows-SHM.cpp | 2 +- library/DFProcess-windows.cpp | 2 +- library/DFProcessEnumerator.cpp | 2 +- library/include/dfhack/DFProcess.h | 198 ----------------------------- 7 files changed, 6 insertions(+), 204 deletions(-) diff --git a/library/DFProcess-linux-SHM.cpp b/library/DFProcess-linux-SHM.cpp index 79cf17e1b..db161bc4e 100644 --- a/library/DFProcess-linux-SHM.cpp +++ b/library/DFProcess-linux-SHM.cpp @@ -22,7 +22,7 @@ must not be misrepresented as being the original software. distribution. */ #include "Internal.h" -#include "dfhack/DFProcess.h" +#include "ProcessInternal.h" #include "dfhack/VersionInfo.h" #include "dfhack/DFError.h" diff --git a/library/DFProcess-linux-wine.cpp b/library/DFProcess-linux-wine.cpp index b918f5738..e3b40502f 100644 --- a/library/DFProcess-linux-wine.cpp +++ b/library/DFProcess-linux-wine.cpp @@ -22,7 +22,7 @@ must not be misrepresented as being the original software. distribution. */ #include "Internal.h" -#include "dfhack/DFProcess.h" +#include "ProcessInternal.h" #include "dfhack/VersionInfo.h" #include "dfhack/DFError.h" #include diff --git a/library/DFProcess-linux.cpp b/library/DFProcess-linux.cpp index 64980f6fc..860f4ee16 100644 --- a/library/DFProcess-linux.cpp +++ b/library/DFProcess-linux.cpp @@ -22,7 +22,7 @@ must not be misrepresented as being the original software. distribution. */ #include "Internal.h" -#include "dfhack/DFProcess.h" +#include "ProcessInternal.h" #include "dfhack/VersionInfo.h" #include "dfhack/DFError.h" #include diff --git a/library/DFProcess-windows-SHM.cpp b/library/DFProcess-windows-SHM.cpp index c068bb84f..d01de5c01 100644 --- a/library/DFProcess-windows-SHM.cpp +++ b/library/DFProcess-windows-SHM.cpp @@ -22,7 +22,7 @@ must not be misrepresented as being the original software. distribution. */ #include "Internal.h" -#include "dfhack/DFProcess.h" +#include "ProcessInternal.h" #include "dfhack/VersionInfo.h" #include "dfhack/DFError.h" #include "shms.h" diff --git a/library/DFProcess-windows.cpp b/library/DFProcess-windows.cpp index 2d318ddf4..72940dd43 100644 --- a/library/DFProcess-windows.cpp +++ b/library/DFProcess-windows.cpp @@ -22,7 +22,7 @@ must not be misrepresented as being the original software. distribution. */ #include "Internal.h" -#include "dfhack/DFProcess.h" +#include "ProcessInternal.h" #include "dfhack/VersionInfo.h" #include "dfhack/DFError.h" #include diff --git a/library/DFProcessEnumerator.cpp b/library/DFProcessEnumerator.cpp index 5105be170..fdd96ec27 100644 --- a/library/DFProcessEnumerator.cpp +++ b/library/DFProcessEnumerator.cpp @@ -23,10 +23,10 @@ distribution. */ #include "Internal.h" +#include "ProcessInternal.h" #include "dfhack/VersionInfoFactory.h" #include "dfhack/DFProcessEnumerator.h" -#include "dfhack/DFProcess.h" #include "dfhack/VersionInfo.h" diff --git a/library/include/dfhack/DFProcess.h b/library/include/dfhack/DFProcess.h index 7044e8021..d0159cce4 100644 --- a/library/include/dfhack/DFProcess.h +++ b/library/include/dfhack/DFProcess.h @@ -174,203 +174,5 @@ namespace DFHack virtual bool SetAndWait (uint32_t state) = 0; }; - //////////////////////////////////////////////////////////////////////////// - // Compiler appeasement area. Not worth a look really... // - //////////////////////////////////////////////////////////////////////////// - - class DFHACK_EXPORT NormalProcess : virtual public Process - { - friend class ProcessEnumerator; - class Private; - private: - Private * const d; - public: - NormalProcess(uint32_t pid, std::vector & known_versions); - ~NormalProcess(); - bool attach(); - bool detach(); - - bool suspend(); - bool asyncSuspend(); - bool resume(); - bool forceresume(); - - uint64_t readQuad(const uint32_t address); - void readQuad(const uint32_t address, uint64_t & value); - void writeQuad(const uint32_t address, const uint64_t value); - - uint32_t readDWord(const uint32_t address); - void readDWord(const uint32_t address, uint32_t & value); - void writeDWord(const uint32_t address, const uint32_t value); - - float readFloat(const uint32_t address); - void readFloat(const uint32_t address, float & value); - - uint16_t readWord(const uint32_t address); - void readWord(const uint32_t address, uint16_t & value); - void writeWord(const uint32_t address, const uint16_t value); - - uint8_t readByte(const uint32_t address); - void readByte(const uint32_t address, uint8_t & value); - void writeByte(const uint32_t address, const uint8_t value); - - void read( uint32_t address, uint32_t length, uint8_t* buffer); - void write(uint32_t address, uint32_t length, uint8_t* buffer); - - const std::string readSTLString (uint32_t offset); - size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity); - void writeSTLString(const uint32_t address, const std::string writeString){}; - // get class name of an object with rtti/type info - std::string readClassName(uint32_t vptr); - - const std::string readCString (uint32_t offset); - - bool isSuspended(); - bool isAttached(); - bool isIdentified(); - - bool getThreadIDs(std::vector & threads ); - void getMemRanges(std::vector & ranges ); - VersionInfo *getDescriptor(); - int getPID(); - std::string getPath(); - // 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;}; - // get the SHM start if available - char * getSHMStart (void){return 0;}; - // set a SHM command and wait for a response - bool SetAndWait (uint32_t state){return false;}; - }; - - class DFHACK_EXPORT SHMProcess : virtual public Process - { - friend class ProcessEnumerator; - class Private; - private: - Private * const d; - - public: - SHMProcess(uint32_t PID, std::vector & known_versions); - ~SHMProcess(); - // Set up stuff so we can read memory - bool attach(); - bool detach(); - - bool suspend(); - bool asyncSuspend(); - bool resume(); - bool forceresume(); - - uint64_t readQuad(const uint32_t address); - void readQuad(const uint32_t address, uint64_t & value); - void writeQuad(const uint32_t address, const uint64_t value); - - uint32_t readDWord(const uint32_t address); - void readDWord(const uint32_t address, uint32_t & value); - void writeDWord(const uint32_t address, const uint32_t value); - - float readFloat(const uint32_t address); - void readFloat(const uint32_t address, float & value); - - uint16_t readWord(const uint32_t address); - void readWord(const uint32_t address, uint16_t & value); - void writeWord(const uint32_t address, const uint16_t value); - - uint8_t readByte(const uint32_t address); - void readByte(const uint32_t address, uint8_t & value); - void writeByte(const uint32_t address, const uint8_t value); - - void read( uint32_t address, uint32_t length, uint8_t* buffer); - void write(uint32_t address, uint32_t length, uint8_t* buffer); - - const std::string readSTLString (uint32_t offset); - size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity); - void writeSTLString(const uint32_t address, const std::string writeString); - // get class name of an object with rtti/type info - std::string readClassName(uint32_t vptr); - - const std::string readCString (uint32_t offset); - - bool isSuspended(); - bool isAttached(); - bool isIdentified(); - - bool getThreadIDs(std::vector & threads ); - void getMemRanges(std::vector & ranges ); - VersionInfo *getDescriptor(); - int getPID(); - std::string getPath(); - // get module index by name and version. bool 1 = error - bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT); - // get the SHM start if available - char * getSHMStart (void); - bool SetAndWait (uint32_t state); - }; - -#ifdef LINUX_BUILD - class DFHACK_EXPORT WineProcess : virtual public Process - { - friend class ProcessEnumerator; - class Private; - private: - Private * const d; - - public: - WineProcess(uint32_t pid, std::vector & known_versions); - ~WineProcess(); - bool attach(); - bool detach(); - - bool suspend(); - bool asyncSuspend(); - bool resume(); - bool forceresume(); - - uint64_t readQuad(const uint32_t address); - void readQuad(const uint32_t address, uint64_t & value); - void writeQuad(const uint32_t address, const uint64_t value); - - uint32_t readDWord(const uint32_t address); - void readDWord(const uint32_t address, uint32_t & value); - void writeDWord(const uint32_t address, const uint32_t value); - - float readFloat(const uint32_t address); - void readFloat(const uint32_t address, float & value); - - uint16_t readWord(const uint32_t address); - void readWord(const uint32_t address, uint16_t & value); - void writeWord(const uint32_t address, const uint16_t value); - - uint8_t readByte(const uint32_t address); - void readByte(const uint32_t address, uint8_t & value); - void writeByte(const uint32_t address, const uint8_t value); - - void read( uint32_t address, uint32_t length, uint8_t* buffer); - void write(uint32_t address, uint32_t length, uint8_t* buffer); - - const std::string readSTLString (uint32_t offset); - size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity); - void writeSTLString(const uint32_t address, const std::string writeString){}; - // get class name of an object with rtti/type info - std::string readClassName(uint32_t vptr); - - const std::string readCString (uint32_t offset); - - bool isSuspended(); - bool isAttached(); - bool isIdentified(); - - bool getThreadIDs(std::vector & threads ); - void getMemRanges(std::vector & ranges ); - 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;}; - // get the SHM start if available - char * getSHMStart (void){return 0;}; - bool SetAndWait (uint32_t state){return false;}; - std::string getPath(); - }; -#endif } #endif From 8862a5b6e06cd344962e71ad44248cd93b5a12de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Wed, 23 Feb 2011 05:53:37 +0100 Subject: [PATCH 80/94] offset search improvements, some linux offsets --- data/Memory-ng.xml | 68 ++++++++++++++++++++++++++- tools/supported/incrementalsearch.cpp | 8 +++- 2 files changed, 73 insertions(+), 3 deletions(-) diff --git a/data/Memory-ng.xml b/data/Memory-ng.xml index 23455ce71..313a67e22 100644 --- a/data/Memory-ng.xml +++ b/data/Memory-ng.xml @@ -2496,11 +2496,75 @@ - + - ... stuff +
+
+
+
+
+ + + + +
+ + + +
+ + + + + +
+
+
+
+
+ ------------------- + !!LANGUAGE TABLES!! + ------------------- + translation vector: 0x943a21c + lang vector: 0x943a204 + word table offset: 0x1c + ------------- + !!MATERIALS!! + ------------- + inorganics: + 0x9439fc0 + organics: + 0x9439fd8 + organics 31.19: + trees: + 0x9439ffc + plants: + 0x9439fe4 + color descriptors: + 0x943e368 + Amber color:0xa380190 + all descriptors: + 0x943e380 + toad-first creature types: + 0x943a074 + all creature types: + 0x943a068 + 0x943a074 + Toad: 0xa441f10 + Toad: rawname = 0x0 + Toad: character (not reliable) = 0x20 + Toad: caste vector = 0x60 + Toad: extract? vector = 0x1f74 + Toad: colors = 0x38 diff --git a/tools/supported/incrementalsearch.cpp b/tools/supported/incrementalsearch.cpp index 8dc04cbc4..f95fba34f 100644 --- a/tools/supported/incrementalsearch.cpp +++ b/tools/supported/incrementalsearch.cpp @@ -749,12 +749,18 @@ void autoSearch(DFHack::Context * DF, vector & ranges) // organics vector to_filter = filtVectors; + sf.Filter(52 * 4,to_filter,vectorLength); + sf.Filter("MUSHROOM_HELMET_PLUMP",to_filter, vectorStringFirst); + printFound(to_filter,"organics"); + + // new organics vector + to_filter = filtVectors; sf.Filter("MUSHROOM_HELMET_PLUMP",to_filter, vectorString); sf.Filter("MEADOW-GRASS",to_filter, vectorString); sf.Filter("TUNNEL_TUBE",to_filter, vectorString); sf.Filter("WEED_BLADE",to_filter, vectorString); sf.Filter("EYEBALL",to_filter, vectorString); - printFound(to_filter,"organics"); + printFound(to_filter,"organics 31.19"); // tree vector to_filter = filtVectors; From 3f282f7d349256d3904c51436f65e7ed30908fb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Wed, 23 Feb 2011 06:18:10 +0100 Subject: [PATCH 81/94] 31.19 linux geology offsets --- data/Memory-ng.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/data/Memory-ng.xml b/data/Memory-ng.xml index 313a67e22..2f8a5f820 100644 --- a/data/Memory-ng.xml +++ b/data/Memory-ng.xml @@ -2507,6 +2507,8 @@
+
+
@@ -2524,6 +2526,10 @@ --> + +
+
+
From 8d1707d0c55b8a236c4a665904d648a1a66edb42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Wed, 23 Feb 2011 06:28:04 +0100 Subject: [PATCH 82/94] Pause state, 31.19, linux. --- data/Memory-ng.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/data/Memory-ng.xml b/data/Memory-ng.xml index 2f8a5f820..55f7b19be 100644 --- a/data/Memory-ng.xml +++ b/data/Memory-ng.xml @@ -2531,6 +2531,9 @@
+ +
+
From 9964dbac72539b3cc1dbd32ad623b4d10c5d440a Mon Sep 17 00:00:00 2001 From: Tom Prince Date: Wed, 23 Feb 2011 01:07:22 -0500 Subject: [PATCH 83/94] Add missing private/ProcessInternal.h --- library/private/ProcessInternal.h | 231 ++++++++++++++++++++++++++++++ 1 file changed, 231 insertions(+) create mode 100644 library/private/ProcessInternal.h diff --git a/library/private/ProcessInternal.h b/library/private/ProcessInternal.h new file mode 100644 index 000000000..9e048bc7b --- /dev/null +++ b/library/private/ProcessInternal.h @@ -0,0 +1,231 @@ +/* +www.sourceforge.net/projects/dfhack +Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#ifndef PROCESS_INTERNAL_H_INCLUDED +#define PROCESS_INTERNAL_H_INCLUDED + +#include "dfhack/DFProcess.h" + +namespace DFHack +{ + //////////////////////////////////////////////////////////////////////////// + // Compiler appeasement area. Not worth a look really... // + //////////////////////////////////////////////////////////////////////////// + + class DFHACK_EXPORT NormalProcess : public Process + { + friend class ProcessEnumerator; + class Private; + private: + Private * const d; + public: + NormalProcess(uint32_t pid, std::vector & known_versions); + ~NormalProcess(); + bool attach(); + bool detach(); + + bool suspend(); + bool asyncSuspend(); + bool resume(); + bool forceresume(); + + uint64_t readQuad(const uint32_t address); + void readQuad(const uint32_t address, uint64_t & value); + void writeQuad(const uint32_t address, const uint64_t value); + + uint32_t readDWord(const uint32_t address); + void readDWord(const uint32_t address, uint32_t & value); + void writeDWord(const uint32_t address, const uint32_t value); + + float readFloat(const uint32_t address); + void readFloat(const uint32_t address, float & value); + + uint16_t readWord(const uint32_t address); + void readWord(const uint32_t address, uint16_t & value); + void writeWord(const uint32_t address, const uint16_t value); + + uint8_t readByte(const uint32_t address); + void readByte(const uint32_t address, uint8_t & value); + void writeByte(const uint32_t address, const uint8_t value); + + void read( uint32_t address, uint32_t length, uint8_t* buffer); + void write(uint32_t address, uint32_t length, uint8_t* buffer); + + const std::string readSTLString (uint32_t offset); + size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity); + void writeSTLString(const uint32_t address, const std::string writeString){}; + // get class name of an object with rtti/type info + std::string readClassName(uint32_t vptr); + + const std::string readCString (uint32_t offset); + + bool isSuspended(); + bool isAttached(); + bool isIdentified(); + + bool getThreadIDs(std::vector & threads ); + void getMemRanges(std::vector & ranges ); + VersionInfo *getDescriptor(); + int getPID(); + std::string getPath(); + // 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;}; + // get the SHM start if available + char * getSHMStart (void){return 0;}; + // set a SHM command and wait for a response + bool SetAndWait (uint32_t state){return false;}; + }; + + class DFHACK_EXPORT SHMProcess : public Process + { + friend class ProcessEnumerator; + class Private; + private: + Private * const d; + + public: + SHMProcess(uint32_t PID, std::vector & known_versions); + ~SHMProcess(); + // Set up stuff so we can read memory + bool attach(); + bool detach(); + + bool suspend(); + bool asyncSuspend(); + bool resume(); + bool forceresume(); + + uint64_t readQuad(const uint32_t address); + void readQuad(const uint32_t address, uint64_t & value); + void writeQuad(const uint32_t address, const uint64_t value); + + uint32_t readDWord(const uint32_t address); + void readDWord(const uint32_t address, uint32_t & value); + void writeDWord(const uint32_t address, const uint32_t value); + + float readFloat(const uint32_t address); + void readFloat(const uint32_t address, float & value); + + uint16_t readWord(const uint32_t address); + void readWord(const uint32_t address, uint16_t & value); + void writeWord(const uint32_t address, const uint16_t value); + + uint8_t readByte(const uint32_t address); + void readByte(const uint32_t address, uint8_t & value); + void writeByte(const uint32_t address, const uint8_t value); + + void read( uint32_t address, uint32_t length, uint8_t* buffer); + void write(uint32_t address, uint32_t length, uint8_t* buffer); + + const std::string readSTLString (uint32_t offset); + size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity); + void writeSTLString(const uint32_t address, const std::string writeString); + // get class name of an object with rtti/type info + std::string readClassName(uint32_t vptr); + + const std::string readCString (uint32_t offset); + + bool isSuspended(); + bool isAttached(); + bool isIdentified(); + + bool getThreadIDs(std::vector & threads ); + void getMemRanges(std::vector & ranges ); + VersionInfo *getDescriptor(); + int getPID(); + std::string getPath(); + // get module index by name and version. bool 1 = error + bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT); + // get the SHM start if available + char * getSHMStart (void); + bool SetAndWait (uint32_t state); + }; + +#ifdef LINUX_BUILD + class DFHACK_EXPORT WineProcess : public Process + { + friend class ProcessEnumerator; + class Private; + private: + Private * const d; + + public: + WineProcess(uint32_t pid, std::vector & known_versions); + ~WineProcess(); + bool attach(); + bool detach(); + + bool suspend(); + bool asyncSuspend(); + bool resume(); + bool forceresume(); + + uint64_t readQuad(const uint32_t address); + void readQuad(const uint32_t address, uint64_t & value); + void writeQuad(const uint32_t address, const uint64_t value); + + uint32_t readDWord(const uint32_t address); + void readDWord(const uint32_t address, uint32_t & value); + void writeDWord(const uint32_t address, const uint32_t value); + + float readFloat(const uint32_t address); + void readFloat(const uint32_t address, float & value); + + uint16_t readWord(const uint32_t address); + void readWord(const uint32_t address, uint16_t & value); + void writeWord(const uint32_t address, const uint16_t value); + + uint8_t readByte(const uint32_t address); + void readByte(const uint32_t address, uint8_t & value); + void writeByte(const uint32_t address, const uint8_t value); + + void read( uint32_t address, uint32_t length, uint8_t* buffer); + void write(uint32_t address, uint32_t length, uint8_t* buffer); + + const std::string readSTLString (uint32_t offset); + size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity); + void writeSTLString(const uint32_t address, const std::string writeString){}; + // get class name of an object with rtti/type info + std::string readClassName(uint32_t vptr); + + const std::string readCString (uint32_t offset); + + bool isSuspended(); + bool isAttached(); + bool isIdentified(); + + bool getThreadIDs(std::vector & threads ); + void getMemRanges(std::vector & ranges ); + 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;}; + // get the SHM start if available + char * getSHMStart (void){return 0;}; + bool SetAndWait (uint32_t state){return false;}; + std::string getPath(); + }; +#endif +} +#endif From 9b854be3278124b7761a6b983a7211204e6fc85f Mon Sep 17 00:00:00 2001 From: Tom Prince Date: Wed, 23 Feb 2011 01:50:21 -0500 Subject: [PATCH 84/94] Remove duplicate code implementing readInt. Implement one version in terms of the other. --- library/DFProcess-linux-SHM.cpp | 53 ++------------------------ library/DFProcess-linux-wine.cpp | 57 ++++++---------------------- library/DFProcess-linux.cpp | 48 ++++-------------------- library/DFProcess-windows-SHM.cpp | 56 +++------------------------- library/DFProcess-windows.cpp | 60 +++++------------------------- library/include/dfhack/DFProcess.h | 10 ++--- library/private/ProcessInternal.h | 15 -------- 7 files changed, 43 insertions(+), 256 deletions(-) diff --git a/library/DFProcess-linux-SHM.cpp b/library/DFProcess-linux-SHM.cpp index db161bc4e..9fe3684a5 100644 --- a/library/DFProcess-linux-SHM.cpp +++ b/library/DFProcess-linux-SHM.cpp @@ -627,16 +627,6 @@ 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); - return D_SHMHDR->value; -} - void SHMProcess::readByte (const uint32_t offset, uint8_t &val ) { if(!d->locked) throw Error::MemoryAccessDenied(); @@ -647,16 +637,6 @@ void SHMProcess::readByte (const uint32_t offset, uint8_t &val ) val = D_SHMHDR->value; } -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); - return D_SHMHDR->value; -} - void SHMProcess::readWord (const uint32_t offset, uint16_t &val) { if(!d->locked) throw Error::MemoryAccessDenied(); @@ -667,15 +647,6 @@ void SHMProcess::readWord (const uint32_t offset, uint16_t &val) val = D_SHMHDR->value; } -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); - return D_SHMHDR->value; -} void SHMProcess::readDWord (const uint32_t offset, uint32_t &val) { if(!d->locked) throw Error::MemoryAccessDenied(); @@ -686,15 +657,6 @@ void SHMProcess::readDWord (const uint32_t offset, uint32_t &val) val = D_SHMHDR->value; } -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); - return D_SHMHDR->Qvalue; -} void SHMProcess::readQuad (const uint32_t offset, uint64_t &val) { if(!d->locked) throw Error::MemoryAccessDenied(); @@ -705,15 +667,6 @@ void SHMProcess::readQuad (const uint32_t offset, uint64_t &val) val = D_SHMHDR->Qvalue; } -float SHMProcess::readFloat (const uint32_t offset) -{ - if(!d->locked) throw Error::MemoryAccessDenied(); - - D_SHMHDR->address = offset; - gcc_barrier - d->SetAndWait(CORE_READ_DWORD); - return reinterpret_cast (D_SHMHDR->value); -} void SHMProcess::readFloat (const uint32_t offset, float &val) { if(!d->locked) throw Error::MemoryAccessDenied(); @@ -817,7 +770,7 @@ const std::string SHMProcess::readCString (uint32_t offset) char r; do { - r = readByte(offset+counter); + r = Process::readByte(offset+counter); temp_c[counter] = r; counter++; } while (r && counter < 255); @@ -864,8 +817,8 @@ string SHMProcess::readClassName (uint32_t vptr) { if(!d->locked) throw Error::MemoryAccessDenied(); - int typeinfo = readDWord(vptr - 0x4); - int typestring = readDWord(typeinfo + 0x4); + int typeinfo = Process::readDWord(vptr - 0x4); + int typestring = Process::readDWord(typeinfo + 0x4); string raw = readCString(typestring); size_t start = raw.find_first_of("abcdefghijklmnopqrstuvwxyz");// trim numbers size_t end = raw.length(); diff --git a/library/DFProcess-linux-wine.cpp b/library/DFProcess-linux-wine.cpp index e3b40502f..7f880afbb 100644 --- a/library/DFProcess-linux-wine.cpp +++ b/library/DFProcess-linux-wine.cpp @@ -395,47 +395,21 @@ void WineProcess::read (const uint32_t offset, const uint32_t size, uint8_t *tar } } -uint8_t WineProcess::readByte (const uint32_t offset) -{ - uint8_t val; - read(offset, 1, &val); - return val; -} - void WineProcess::readByte (const uint32_t offset, uint8_t &val ) { read(offset, 1, &val); } -uint16_t WineProcess::readWord (const uint32_t offset) -{ - uint16_t val; - read(offset, 2, (uint8_t *) &val); - return val; -} - void WineProcess::readWord (const uint32_t offset, uint16_t &val) { read(offset, 2, (uint8_t *) &val); } -uint32_t WineProcess::readDWord (const uint32_t offset) -{ - uint32_t val; - read(offset, 4, (uint8_t *) &val); - return val; -} void WineProcess::readDWord (const uint32_t offset, uint32_t &val) { read(offset, 4, (uint8_t *) &val); } -float WineProcess::readFloat (const uint32_t offset) -{ - float val; - read(offset, 4, (uint8_t *) &val); - return val; -} void WineProcess::readFloat (const uint32_t offset, float &val) { read(offset, 4, (uint8_t *) &val); @@ -446,13 +420,6 @@ void WineProcess::readQuad (const uint32_t offset, uint64_t &val) read(offset, 8, (uint8_t *) &val); } -uint64_t WineProcess::readQuad (const uint32_t offset) -{ - uint64_t val; - read(offset, 8, (uint8_t *) &val); - return val; -} - /* * WRITING */ @@ -470,7 +437,7 @@ void WineProcess::writeQuad (uint32_t offset, const uint64_t data) void WineProcess::writeDWord (uint32_t offset, uint32_t data) { #ifdef HAVE_64_BIT - uint64_t orig = readQuad(offset); + uint64_t orig = Process::readQuad(offset); orig &= 0xFFFFFFFF00000000; orig |= data; ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig); @@ -483,7 +450,7 @@ void WineProcess::writeDWord (uint32_t offset, uint32_t data) void WineProcess::writeWord (uint32_t offset, uint16_t data) { #ifdef HAVE_64_BIT - uint64_t orig = readQuad(offset); + uint64_t orig = Process::readQuad(offset); orig &= 0xFFFFFFFFFFFF0000; orig |= data; ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig); @@ -498,7 +465,7 @@ void WineProcess::writeWord (uint32_t offset, uint16_t data) void WineProcess::writeByte (uint32_t offset, uint8_t data) { #ifdef HAVE_64_BIT - uint64_t orig = readQuad(offset); + uint64_t orig = Process::readQuad(offset); orig &= 0xFFFFFFFFFFFFFF00; orig |= data; ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig); @@ -560,7 +527,7 @@ const std::string WineProcess::readCString (uint32_t offset) char r; do { - r = readByte(offset+counter); + r = Process::readByte(offset+counter); temp_c[counter] = r; counter++; } while (r && counter < 255); @@ -572,8 +539,8 @@ const std::string WineProcess::readCString (uint32_t offset) size_t WineProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) { 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 length = Process::readDWord(offset + d->STLSTR_size_off); + size_t capacity = Process::readDWord(offset + d->STLSTR_cap_off); size_t read_real = min(length, bufcapacity-1);// keep space for null termination @@ -584,7 +551,7 @@ size_t WineProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcap } else // read data from what the offset + 4 dword points to { - start_offset = readDWord(start_offset);// dereference the start offset + start_offset = Process::readDWord(start_offset);// dereference the start offset read(start_offset, read_real, (uint8_t *)buffer); } @@ -595,8 +562,8 @@ size_t WineProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcap const string WineProcess::readSTLString (uint32_t offset) { 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 length = Process::readDWord(offset + d->STLSTR_size_off); + size_t capacity = Process::readDWord(offset + d->STLSTR_cap_off); char * temp = new char[capacity+1]; @@ -607,7 +574,7 @@ const string WineProcess::readSTLString (uint32_t offset) } else // read data from what the offset + 4 dword points to { - start_offset = readDWord(start_offset);// dereference the start offset + start_offset = Process::readDWord(start_offset);// dereference the start offset read(start_offset, capacity, (uint8_t *)temp); } @@ -619,8 +586,8 @@ const string WineProcess::readSTLString (uint32_t offset) string WineProcess::readClassName (uint32_t vptr) { - int rtti = readDWord(vptr - 0x4); - int typeinfo = readDWord(rtti + 0xC); + int rtti = Process::readDWord(vptr - 0x4); + int typeinfo = Process::readDWord(rtti + 0xC); string raw = readCString(typeinfo + 0xC); // skips the .?AV raw.resize(raw.length() - 2);// trim @@ from end return raw; diff --git a/library/DFProcess-linux.cpp b/library/DFProcess-linux.cpp index 860f4ee16..284bb2dc2 100644 --- a/library/DFProcess-linux.cpp +++ b/library/DFProcess-linux.cpp @@ -373,58 +373,26 @@ void NormalProcess::read (const uint32_t offset, const uint32_t size, uint8_t *t } } -uint8_t NormalProcess::readByte (const uint32_t offset) -{ - uint8_t val; - read(offset, 1, &val); - return val; -} - void NormalProcess::readByte (const uint32_t offset, uint8_t &val ) { read(offset, 1, &val); } -uint16_t NormalProcess::readWord (const uint32_t offset) -{ - uint16_t val; - read(offset, 2, (uint8_t *) &val); - return val; -} - void NormalProcess::readWord (const uint32_t offset, uint16_t &val) { read(offset, 2, (uint8_t *) &val); } -uint32_t NormalProcess::readDWord (const uint32_t offset) -{ - uint32_t val; - read(offset, 4, (uint8_t *) &val); - return val; -} void NormalProcess::readDWord (const uint32_t offset, uint32_t &val) { read(offset, 4, (uint8_t *) &val); } -float NormalProcess::readFloat (const uint32_t offset) -{ - float val; - read(offset, 4, (uint8_t *) &val); - return val; -} void NormalProcess::readFloat (const uint32_t offset, float &val) { read(offset, 4, (uint8_t *) &val); } -uint64_t NormalProcess::readQuad (const uint32_t offset) -{ - uint64_t val; - read(offset, 8, (uint8_t *) &val); - return val; -} void NormalProcess::readQuad (const uint32_t offset, uint64_t &val) { read(offset, 8, (uint8_t *) &val); @@ -446,7 +414,7 @@ void NormalProcess::writeQuad (uint32_t offset, const uint64_t data) void NormalProcess::writeDWord (uint32_t offset, uint32_t data) { #ifdef HAVE_64_BIT - uint64_t orig = readQuad(offset); + uint64_t orig = Process::readQuad(offset); orig &= 0xFFFFFFFF00000000; orig |= data; ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig); @@ -459,7 +427,7 @@ void NormalProcess::writeDWord (uint32_t offset, uint32_t data) void NormalProcess::writeWord (uint32_t offset, uint16_t data) { #ifdef HAVE_64_BIT - uint64_t orig = readQuad(offset); + uint64_t orig = Process::readQuad(offset); orig &= 0xFFFFFFFFFFFF0000; orig |= data; ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig); @@ -474,7 +442,7 @@ void NormalProcess::writeWord (uint32_t offset, uint16_t data) void NormalProcess::writeByte (uint32_t offset, uint8_t data) { #ifdef HAVE_64_BIT - uint64_t orig = readQuad(offset); + uint64_t orig = Process::readQuad(offset); orig &= 0xFFFFFFFFFFFFFF00; orig |= data; ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig); @@ -536,7 +504,7 @@ const std::string NormalProcess::readCString (uint32_t offset) char r; do { - r = readByte(offset+counter); + r = Process::readByte(offset+counter); temp_c[counter] = r; counter++; } while (r && counter < 255); @@ -555,7 +523,7 @@ struct _Rep_base size_t NormalProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) { _Rep_base header; - offset = readDWord(offset); + offset = Process::readDWord(offset); read(offset - sizeof(_Rep_base),sizeof(_Rep_base),(uint8_t *)&header); size_t read_real = min((size_t)header._M_length, bufcapacity-1);// keep space for null termination read(offset,read_real,(uint8_t * )buffer); @@ -567,7 +535,7 @@ const string NormalProcess::readSTLString (uint32_t offset) { _Rep_base header; - offset = readDWord(offset); + offset = Process::readDWord(offset); read(offset - sizeof(_Rep_base),sizeof(_Rep_base),(uint8_t *)&header); // FIXME: use char* everywhere, avoid string @@ -580,8 +548,8 @@ const string NormalProcess::readSTLString (uint32_t offset) string NormalProcess::readClassName (uint32_t vptr) { - int typeinfo = readDWord(vptr - 0x4); - int typestring = readDWord(typeinfo + 0x4); + int typeinfo = Process::readDWord(vptr - 0x4); + int typestring = Process::readDWord(typeinfo + 0x4); string raw = readCString(typestring); size_t start = raw.find_first_of("abcdefghijklmnopqrstuvwxyz");// trim numbers size_t end = raw.length(); diff --git a/library/DFProcess-windows-SHM.cpp b/library/DFProcess-windows-SHM.cpp index d01de5c01..4d23d8837 100644 --- a/library/DFProcess-windows-SHM.cpp +++ b/library/DFProcess-windows-SHM.cpp @@ -340,7 +340,7 @@ bool SHMProcess::Private::validate(vector & known_versions) uint32_t base = (uint32_t)hmod; // read from this process - uint32_t pe_offset = self->readDWord(base+0x3C); + uint32_t pe_offset = self->Process::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 ); @@ -436,7 +436,7 @@ void SHMProcess::getMemRanges( vector & ranges ) t_memrange temp; uint32_t base = d->memdescriptor->getBase(); temp.start = base + 0x1000; // more fakery. - temp.end = base + readDWord(base+readDWord(base+0x3C)+0x50)-1; // yay for magic. + temp.end = base + Process::readDWord(base+readDWord(base+0x3C)+0x50)-1; // yay for magic. temp.read = 1; temp.write = 1; temp.execute = 0; // fake @@ -688,16 +688,6 @@ 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); - return D_SHMHDR->value; -} - void SHMProcess::readByte (const uint32_t offset, uint8_t &val ) { if(!d->locked) throw Error::MemoryAccessDenied(); @@ -708,16 +698,6 @@ void SHMProcess::readByte (const uint32_t offset, uint8_t &val ) val = D_SHMHDR->value; } -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); - return D_SHMHDR->value; -} - void SHMProcess::readWord (const uint32_t offset, uint16_t &val) { if(!d->locked) throw Error::MemoryAccessDenied(); @@ -728,15 +708,6 @@ void SHMProcess::readWord (const uint32_t offset, uint16_t &val) val = D_SHMHDR->value; } -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); - return D_SHMHDR->value; -} void SHMProcess::readDWord (const uint32_t offset, uint32_t &val) { if(!d->locked) throw Error::MemoryAccessDenied(); @@ -747,15 +718,6 @@ void SHMProcess::readDWord (const uint32_t offset, uint32_t &val) val = D_SHMHDR->value; } -float SHMProcess::readFloat (const uint32_t offset) -{ - if(!d->locked) throw Error::MemoryAccessDenied(); - - D_SHMHDR->address = offset; - full_barrier - d->SetAndWait(CORE_READ_DWORD); - return reinterpret_cast (D_SHMHDR->value); -} void SHMProcess::readFloat (const uint32_t offset, float &val) { if(!d->locked) throw Error::MemoryAccessDenied(); @@ -765,15 +727,7 @@ void SHMProcess::readFloat (const uint32_t offset, float &val) d->SetAndWait(CORE_READ_DWORD); val = reinterpret_cast (D_SHMHDR->value); } -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); - return D_SHMHDR->Qvalue; -} void SHMProcess::readQuad (const uint32_t offset, uint64_t &val) { if(!d->locked) throw Error::MemoryAccessDenied(); @@ -878,7 +832,7 @@ const std::string SHMProcess::readCString (uint32_t offset) char r; do { - r = readByte(offset+counter); + r = Process::readByte(offset+counter); temp_c[counter] = r; counter++; } while (r && counter < 255); @@ -923,8 +877,8 @@ void SHMProcess::writeSTLString(const uint32_t address, const std::string writeS string SHMProcess::readClassName (uint32_t vptr) { - int rtti = readDWord(vptr - 0x4); - int typeinfo = readDWord(rtti + 0xC); + int rtti = Process::readDWord(vptr - 0x4); + int typeinfo = Process::readDWord(rtti + 0xC); string raw = readCString(typeinfo + 0xC); // skips the .?AV raw.resize(raw.length() - 2);// trim @@ from end return raw; diff --git a/library/DFProcess-windows.cpp b/library/DFProcess-windows.cpp index 72940dd43..0d7d32f8c 100644 --- a/library/DFProcess-windows.cpp +++ b/library/DFProcess-windows.cpp @@ -90,7 +90,7 @@ NormalProcess::NormalProcess(uint32_t pid, vector & known_versio // read from this process try { - uint32_t pe_offset = readDWord(d->base+0x3C); + uint32_t pe_offset = Process::readDWord(d->base+0x3C); read(d->base + pe_offset , sizeof(d->pe_header), (uint8_t *)&d->pe_header); const size_t sectionsSize = sizeof(IMAGE_SECTION_HEADER) * d->pe_header.FileHeader.NumberOfSections; d->sections = (IMAGE_SECTION_HEADER *) malloc(sectionsSize); @@ -417,70 +417,30 @@ void NormalProcess::getMemRanges( vector & ranges ) } } -uint8_t NormalProcess::readByte (const uint32_t offset) -{ - uint8_t result; - if(!ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint8_t), NULL)) - throw Error::MemoryAccessDenied(); - return result; -} - void NormalProcess::readByte (const uint32_t offset,uint8_t &result) { if(!ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint8_t), NULL)) throw Error::MemoryAccessDenied(); } -uint16_t NormalProcess::readWord (const uint32_t offset) -{ - uint16_t result; - if(!ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint16_t), NULL)) - throw Error::MemoryAccessDenied(); - return result; -} - void NormalProcess::readWord (const uint32_t offset, uint16_t &result) { if(!ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint16_t), NULL)) throw Error::MemoryAccessDenied(); } -uint32_t NormalProcess::readDWord (const uint32_t offset) -{ - uint32_t result; - if(!ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint32_t), NULL)) - throw Error::MemoryAccessDenied(); - return result; -} - void NormalProcess::readDWord (const uint32_t offset, uint32_t &result) { if(!ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint32_t), NULL)) throw Error::MemoryAccessDenied(); } -uint64_t NormalProcess::readQuad (const uint32_t offset) -{ - uint64_t result; - if(!ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint64_t), NULL)) - throw Error::MemoryAccessDenied(); - return result; -} - void NormalProcess::readQuad (const uint32_t offset, uint64_t &result) { if(!ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint64_t), NULL)) throw Error::MemoryAccessDenied(); } -float NormalProcess::readFloat (const uint32_t offset) -{ - float result; - if(!ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(float), NULL)) - throw Error::MemoryAccessDenied(); - return result; -} - void NormalProcess::readFloat (const uint32_t offset, float &result) { if(!ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(float), NULL)) @@ -544,8 +504,8 @@ const string NormalProcess::readCString (const uint32_t offset) size_t NormalProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) { 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 length = Process::readDWord(offset + d->STLSTR_size_off); + size_t capacity = Process::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 @@ -555,7 +515,7 @@ size_t NormalProcess::readSTLString (uint32_t offset, char * buffer, size_t bufc } else // read data from what the offset + 4 dword points to { - start_offset = readDWord(start_offset);// dereference the start offset + start_offset = Process::readDWord(start_offset);// dereference the start offset read(start_offset, read_real, (uint8_t *)buffer); } @@ -566,8 +526,8 @@ size_t NormalProcess::readSTLString (uint32_t offset, char * buffer, size_t bufc const string NormalProcess::readSTLString (uint32_t offset) { 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 length = Process::readDWord(offset + d->STLSTR_size_off); + size_t capacity = Process::readDWord(offset + d->STLSTR_cap_off); char * temp = new char[capacity+1]; // read data from inside the string structure @@ -577,7 +537,7 @@ const string NormalProcess::readSTLString (uint32_t offset) } else // read data from what the offset + 4 dword points to { - start_offset = readDWord(start_offset);// dereference the start offset + start_offset = Process::readDWord(start_offset);// dereference the start offset read(start_offset, capacity, (uint8_t *)temp); } @@ -589,8 +549,8 @@ const string NormalProcess::readSTLString (uint32_t offset) string NormalProcess::readClassName (uint32_t vptr) { - int rtti = readDWord(vptr - 0x4); - int typeinfo = readDWord(rtti + 0xC); + int rtti = Process::readDWord(vptr - 0x4); + int typeinfo = Process::readDWord(rtti + 0xC); string raw = readCString(typeinfo + 0xC); // skips the .?AV raw.resize(raw.length() - 2);// trim @@ from end return raw; @@ -604,4 +564,4 @@ string NormalProcess::getPath() GetModuleFileNameEx(d->my_handle,hmod,String,sizeof(String)); //get the filename from the module string out(String); return(out.substr(0,out.find_last_of("\\"))); -} \ No newline at end of file +} diff --git a/library/include/dfhack/DFProcess.h b/library/include/dfhack/DFProcess.h index d0159cce4..7e81a94de 100644 --- a/library/include/dfhack/DFProcess.h +++ b/library/include/dfhack/DFProcess.h @@ -99,33 +99,33 @@ namespace DFHack virtual bool forceresume() = 0; /// read a 8-byte integer - virtual uint64_t readQuad(const uint32_t address) = 0; + uint64_t readQuad(const uint32_t address) { uint64_t result; readQuad(address, result); return result; } /// read a 8-byte integer virtual void readQuad(const uint32_t address, uint64_t & value) = 0; /// write a 8-byte integer virtual void writeQuad(const uint32_t address, const uint64_t value) = 0; /// read a 4-byte integer - virtual uint32_t readDWord(const uint32_t address) = 0; + uint32_t readDWord(const uint32_t address) { uint32_t result; readDWord(address, result); return result; } /// read a 4-byte integer virtual void readDWord(const uint32_t address, uint32_t & value) = 0; /// write a 4-byte integer virtual void writeDWord(const uint32_t address, const uint32_t value) = 0; /// read a float - virtual float readFloat(const uint32_t address) = 0; + float readFloat(const uint32_t address) { float result; readFloat(address, result); return result; } /// write a float virtual void readFloat(const uint32_t address, float & value) = 0; /// read a 2-byte integer - virtual uint16_t readWord(const uint32_t address) = 0; + uint16_t readWord(const uint32_t address) { uint16_t result; readWord(address, result); return result; } /// read a 2-byte integer virtual void readWord(const uint32_t address, uint16_t & value) = 0; /// write a 2-byte integer virtual void writeWord(const uint32_t address, const uint16_t value) = 0; /// read a byte - virtual uint8_t readByte(const uint32_t address) = 0; + uint8_t readByte(const uint32_t address) { uint8_t result; readByte(address, result); return result; } /// read a byte virtual void readByte(const uint32_t address, uint8_t & value) = 0; /// write a byte diff --git a/library/private/ProcessInternal.h b/library/private/ProcessInternal.h index 9e048bc7b..0bca44d54 100644 --- a/library/private/ProcessInternal.h +++ b/library/private/ProcessInternal.h @@ -50,22 +50,17 @@ namespace DFHack bool resume(); bool forceresume(); - uint64_t readQuad(const uint32_t address); void readQuad(const uint32_t address, uint64_t & value); void writeQuad(const uint32_t address, const uint64_t value); - uint32_t readDWord(const uint32_t address); void readDWord(const uint32_t address, uint32_t & value); void writeDWord(const uint32_t address, const uint32_t value); - float readFloat(const uint32_t address); void readFloat(const uint32_t address, float & value); - uint16_t readWord(const uint32_t address); void readWord(const uint32_t address, uint16_t & value); void writeWord(const uint32_t address, const uint16_t value); - uint8_t readByte(const uint32_t address); void readByte(const uint32_t address, uint8_t & value); void writeByte(const uint32_t address, const uint8_t value); @@ -116,22 +111,17 @@ namespace DFHack bool resume(); bool forceresume(); - uint64_t readQuad(const uint32_t address); void readQuad(const uint32_t address, uint64_t & value); void writeQuad(const uint32_t address, const uint64_t value); - uint32_t readDWord(const uint32_t address); void readDWord(const uint32_t address, uint32_t & value); void writeDWord(const uint32_t address, const uint32_t value); - float readFloat(const uint32_t address); void readFloat(const uint32_t address, float & value); - uint16_t readWord(const uint32_t address); void readWord(const uint32_t address, uint16_t & value); void writeWord(const uint32_t address, const uint16_t value); - uint8_t readByte(const uint32_t address); void readByte(const uint32_t address, uint8_t & value); void writeByte(const uint32_t address, const uint8_t value); @@ -181,22 +171,17 @@ namespace DFHack bool resume(); bool forceresume(); - uint64_t readQuad(const uint32_t address); void readQuad(const uint32_t address, uint64_t & value); void writeQuad(const uint32_t address, const uint64_t value); - uint32_t readDWord(const uint32_t address); void readDWord(const uint32_t address, uint32_t & value); void writeDWord(const uint32_t address, const uint32_t value); - float readFloat(const uint32_t address); void readFloat(const uint32_t address, float & value); - uint16_t readWord(const uint32_t address); void readWord(const uint32_t address, uint16_t & value); void writeWord(const uint32_t address, const uint16_t value); - uint8_t readByte(const uint32_t address); void readByte(const uint32_t address, uint8_t & value); void writeByte(const uint32_t address, const uint8_t value); From 9ba80d517f730cfe17546d5dc040d00a4f93fc05 Mon Sep 17 00:00:00 2001 From: Tom Prince Date: Wed, 23 Feb 2011 02:26:55 -0500 Subject: [PATCH 85/94] Remove some gratuitous differences in the SHM implementations. --- library/DFProcess-linux-SHM.cpp | 105 +++++++++++++++--------------- library/DFProcess-windows-SHM.cpp | 66 ++++--------------- 2 files changed, 66 insertions(+), 105 deletions(-) diff --git a/library/DFProcess-linux-SHM.cpp b/library/DFProcess-linux-SHM.cpp index 9fe3684a5..700dec976 100644 --- a/library/DFProcess-linux-SHM.cpp +++ b/library/DFProcess-linux-SHM.cpp @@ -39,9 +39,6 @@ distribution. using namespace DFHack; -// a full memory barrier! better be safe than sorry. -#define gcc_barrier asm volatile("" ::: "memory"); __sync_synchronize(); - class SHMProcess::Private { public: @@ -81,14 +78,14 @@ class SHMProcess::Private bool validate(std::vector< VersionInfo* >& known_versions); - bool Aux_Core_Attach(bool & versionOK, pid_t & PID); - //bool waitWhile (uint32_t state); + bool Aux_Core_Attach(bool & versionOK, pid_t& PID); bool SetAndWait (uint32_t state); bool GetLocks(); bool AreLocksOk(); void FreeLocks(); }; +// some helpful macros to keep the code bloat in check #define SHMCMD ( (uint32_t *) shm_addr)[attachmentIdx] #define D_SHMCMD ( (uint32_t *) (d->shm_addr))[d->attachmentIdx] @@ -103,12 +100,17 @@ bool SHMProcess::Private::SetAndWait (uint32_t state) uint32_t cnt = 0; if(!attached) return false; SHMCMD = state; + while (SHMCMD == state) { - // check if the other process is still there + // yield the CPU, only on single-core CPUs + if(useYield) + { + SCHED_YIELD + } if(cnt == 10000) { - if(!AreLocksOk()) + if(!AreLocksOk())// DF not there anymore? { //detach the shared memory shmdt(shm_addr); @@ -122,10 +124,6 @@ bool SHMProcess::Private::SetAndWait (uint32_t state) cnt = 0; } } - if(useYield) - { - SCHED_YIELD - } cnt++; } // server returned a generic error @@ -155,21 +153,6 @@ uint32_t OS_getAffinity() return affinity; } -// test if we have client and server locks and the server is present -bool SHMProcess::Private::AreLocksOk() -{ - // both locks are inited (we hold our lock) - if(client_lock != -1 && server_lock != -1) - { - if(lockf(server_lock,F_TEST,0) == -1) // and server holds its lock - { - return true; // OK, locks are good - } - } - // locks are bad - return false; -} - void SHMProcess::Private::FreeLocks() { attachmentIdx = -1; @@ -258,6 +241,21 @@ bool SHMProcess::Private::GetLocks() return false; } +// test if we have client and server locks and the server is present +bool SHMProcess::Private::AreLocksOk() +{ + // both locks are inited (we hold our lock) + if(client_lock != -1 && server_lock != -1) + { + if(lockf(server_lock,F_TEST,0) == -1) // and server holds its lock + { + return true; // OK, locks are good + } + } + // locks are bad + return false; +} + SHMProcess::SHMProcess(uint32_t PID, vector< VersionInfo* >& known_versions) : d(new Private(this)) { @@ -425,8 +423,8 @@ bool SHMProcess::suspend() if(D_SHMCMD == CORE_RUN) { //fprintf(stderr,"%d invokes step\n",d->attachmentIdx); - /* // wait for the next window + /* if(!d->SetAndWait(CORE_STEP)) { throw Error::SHMLockingError("if(!d->SetAndWait(CORE_STEP))"); @@ -599,7 +597,7 @@ void SHMProcess::read (uint32_t src_address, uint32_t size, uint8_t *target_buff { D_SHMHDR->address = src_address; D_SHMHDR->length = size; - gcc_barrier + full_barrier d->SetAndWait(CORE_READ); memcpy (target_buffer, D_SHMDATA(void),size); } @@ -613,7 +611,7 @@ void SHMProcess::read (uint32_t src_address, uint32_t size, uint8_t *target_buff // read to_read bytes from src_cursor D_SHMHDR->address = src_address; D_SHMHDR->length = to_read; - gcc_barrier + full_barrier d->SetAndWait(CORE_READ); memcpy (target_buffer, D_SHMDATA(void) ,to_read); // decrease size by bytes read @@ -632,7 +630,7 @@ void SHMProcess::readByte (const uint32_t offset, uint8_t &val ) if(!d->locked) throw Error::MemoryAccessDenied(); D_SHMHDR->address = offset; - gcc_barrier + full_barrier d->SetAndWait(CORE_READ_BYTE); val = D_SHMHDR->value; } @@ -642,7 +640,7 @@ void SHMProcess::readWord (const uint32_t offset, uint16_t &val) if(!d->locked) throw Error::MemoryAccessDenied(); D_SHMHDR->address = offset; - gcc_barrier + full_barrier d->SetAndWait(CORE_READ_WORD); val = D_SHMHDR->value; } @@ -652,7 +650,7 @@ void SHMProcess::readDWord (const uint32_t offset, uint32_t &val) if(!d->locked) throw Error::MemoryAccessDenied(); D_SHMHDR->address = offset; - gcc_barrier + full_barrier d->SetAndWait(CORE_READ_DWORD); val = D_SHMHDR->value; } @@ -662,7 +660,7 @@ void SHMProcess::readQuad (const uint32_t offset, uint64_t &val) if(!d->locked) throw Error::MemoryAccessDenied(); D_SHMHDR->address = offset; - gcc_barrier + full_barrier d->SetAndWait(CORE_READ_QUAD); val = D_SHMHDR->Qvalue; } @@ -672,7 +670,7 @@ void SHMProcess::readFloat (const uint32_t offset, float &val) if(!d->locked) throw Error::MemoryAccessDenied(); D_SHMHDR->address = offset; - gcc_barrier + full_barrier d->SetAndWait(CORE_READ_DWORD); val = reinterpret_cast (D_SHMHDR->value); } @@ -681,13 +679,13 @@ void SHMProcess::readFloat (const uint32_t offset, float &val) * WRITING */ -void SHMProcess::writeQuad (const uint32_t offset, const uint64_t data) +void SHMProcess::writeQuad (uint32_t offset, uint64_t data) { if(!d->locked) throw Error::MemoryAccessDenied(); D_SHMHDR->address = offset; D_SHMHDR->Qvalue = data; - gcc_barrier + full_barrier d->SetAndWait(CORE_WRITE_QUAD); } @@ -697,7 +695,7 @@ void SHMProcess::writeDWord (uint32_t offset, uint32_t data) D_SHMHDR->address = offset; D_SHMHDR->value = data; - gcc_barrier + full_barrier d->SetAndWait(CORE_WRITE_DWORD); } @@ -708,7 +706,7 @@ void SHMProcess::writeWord (uint32_t offset, uint16_t data) D_SHMHDR->address = offset; D_SHMHDR->value = data; - gcc_barrier + full_barrier d->SetAndWait(CORE_WRITE_WORD); } @@ -718,7 +716,7 @@ void SHMProcess::writeByte (uint32_t offset, uint8_t data) D_SHMHDR->address = offset; D_SHMHDR->value = data; - gcc_barrier + full_barrier d->SetAndWait(CORE_WRITE_BYTE); } @@ -732,7 +730,7 @@ void SHMProcess::write (uint32_t dst_address, uint32_t size, uint8_t *source_buf D_SHMHDR->address = dst_address; D_SHMHDR->length = size; memcpy(D_SHMDATA(void),source_buffer, size); - gcc_barrier + full_barrier d->SetAndWait(CORE_WRITE); } // a big write, we push this over the shm in iterations @@ -746,7 +744,7 @@ void SHMProcess::write (uint32_t dst_address, uint32_t size, uint8_t *source_buf D_SHMHDR->address = dst_address; D_SHMHDR->length = to_write; memcpy(D_SHMDATA(void),source_buffer, to_write); - gcc_barrier + full_barrier d->SetAndWait(CORE_WRITE); // decrease size by bytes written size -= to_write; @@ -825,6 +823,19 @@ string SHMProcess::readClassName (uint32_t vptr) return raw.substr(start,end-start); } +string SHMProcess::getPath() +{ + char cwd_name[256]; + char target_name[1024]; + int target_result; + + sprintf(cwd_name,"/proc/%d/cwd", getPID()); + // resolve /proc/PID/exe link + target_result = readlink(cwd_name, target_name, sizeof(target_name)); + target_name[target_result] = '\0'; + return(string(target_name)); +} + // get module index by name and version. bool 0 = error bool SHMProcess::getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) { @@ -874,15 +885,3 @@ bool SHMProcess::Private::Aux_Core_Attach(bool & versionOK, pid_t & PID) #endif return true; } -string SHMProcess::getPath() -{ - char cwd_name[256]; - char target_name[1024]; - int target_result; - - sprintf(cwd_name,"/proc/%d/cwd", getPID()); - // resolve /proc/PID/exe link - target_result = readlink(cwd_name, target_name, sizeof(target_name)); - target_name[target_result] = '\0'; - return(string(target_name)); -} diff --git a/library/DFProcess-windows-SHM.cpp b/library/DFProcess-windows-SHM.cpp index 4d23d8837..97711a979 100644 --- a/library/DFProcess-windows-SHM.cpp +++ b/library/DFProcess-windows-SHM.cpp @@ -29,7 +29,6 @@ distribution. #include "mod-core.h" using namespace DFHack; -// a full memory barrier! better be safe than sorry. class SHMProcess::Private { public: @@ -81,11 +80,6 @@ class SHMProcess::Private #define SHMDATA(type) ((type *)(shm_addr + SHM_HEADER)) #define D_SHMDATA(type) ((type *)(d->shm_addr + SHM_HEADER)) -bool SHMProcess::SetAndWait (uint32_t state) -{ - return d->SetAndWait(state); -} - bool SHMProcess::Private::SetAndWait (uint32_t state) { uint32_t cnt = 0; @@ -116,6 +110,7 @@ bool SHMProcess::Private::SetAndWait (uint32_t state) } cnt++; } + // server returned a generic error if(SHMCMD == CORE_ERROR) { return false; @@ -123,6 +118,11 @@ bool SHMProcess::Private::SetAndWait (uint32_t state) return true; } +bool SHMProcess::SetAndWait (uint32_t state) +{ + return d->SetAndWait(state); +} + uint32_t OS_getAffinity() { HANDLE hProcess = GetCurrentProcess(); @@ -253,27 +253,6 @@ bool SHMProcess::Private::AreLocksOk() return false; } - - - /* - 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) - { - return; - } - d->DFCLMutex = OpenMutex(SYNCHRONIZE,false, clmutexname); - if(d->DFCLMutex == 0) - { - return; - } - */ - SHMProcess::SHMProcess(uint32_t PID, vector & known_versions) : d(new Private()) { @@ -463,7 +442,7 @@ bool SHMProcess::suspend() { //fprintf(stderr,"%d invokes step\n",d->attachmentIdx); // wait for the next window - /* + /* if(!d->SetAndWait(CORE_STEP)) { throw Error::SHMLockingError("if(!d->SetAndWait(CORE_STEP))"); @@ -577,21 +556,6 @@ bool SHMProcess::attach() //cerr << "server is full or not really there!" << endl; return false; } - /* - // check if DF is there - if(!d->isValidSV()) - { - return false; // NOT - } - */ - /* - // try locking client mutex - uint32_t result = WaitForSingleObject(d->DFCLMutex,0); - if( result != WAIT_OBJECT_0 && result != WAIT_ABANDONED) - { - return false; // we couldn't lock it - } - */ /* * Locate the segment. @@ -634,12 +598,10 @@ bool SHMProcess::attach() bool SHMProcess::detach() { if(!d->attached) return true; - //cerr << "detach" << endl;// FIXME: throw if(d->locked) { resume(); } - //cerr << "detach after resume" << endl;// FIXME: throw // detach segment UnmapViewOfFile(d->shm_addr); // release it for some other client @@ -718,24 +680,24 @@ void SHMProcess::readDWord (const uint32_t offset, uint32_t &val) val = D_SHMHDR->value; } -void SHMProcess::readFloat (const uint32_t offset, float &val) +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_DWORD); - val = reinterpret_cast (D_SHMHDR->value); + d->SetAndWait(CORE_READ_QUAD); + val = D_SHMHDR->Qvalue; } -void SHMProcess::readQuad (const uint32_t offset, uint64_t &val) +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_QUAD); - val = D_SHMHDR->Qvalue; + d->SetAndWait(CORE_READ_DWORD); + val = reinterpret_cast (D_SHMHDR->value); } /* @@ -752,7 +714,6 @@ void SHMProcess::writeQuad (uint32_t offset, uint64_t data) d->SetAndWait(CORE_WRITE_QUAD); } - void SHMProcess::writeDWord (uint32_t offset, uint32_t data) { if(!d->locked) throw Error::MemoryAccessDenied(); @@ -895,6 +856,7 @@ string SHMProcess::getPath() string out(String); return(out.substr(0,out.find_last_of("\\"))); } + // get module index by name and version. bool 0 = error bool SHMProcess::getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) { From c287e547938f65313360a7cafc4bccf18d341485 Mon Sep 17 00:00:00 2001 From: Tom Prince Date: Wed, 23 Feb 2011 04:02:14 -0500 Subject: [PATCH 86/94] Merge much of DFProcess-*-SHM.cpp into DFProcess-SHM.cpp. --- library/CMakeLists.txt | 3 + library/DFProcess-SHM.cpp | 479 +++++++++++++++++++++++++++ library/DFProcess-linux-SHM.cpp | 518 ++---------------------------- library/DFProcess-windows-SHM.cpp | 508 ++--------------------------- library/DFProcessEnumerator.cpp | 1 + library/private/ProcessInternal.h | 64 ---- library/private/SHMProcess.h | 144 +++++++++ 7 files changed, 666 insertions(+), 1051 deletions(-) create mode 100644 library/DFProcess-SHM.cpp create mode 100644 library/private/SHMProcess.h diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index bb7a9c199..e3ba69df4 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -29,6 +29,8 @@ include_directories (${CMAKE_SOURCE_DIR}/library/private/) SET(PROJECT_HDRS_INTERNAL private/ContextShared.h private/Internal.h + private/ProcessInternal.h + private/SHMProcess.h ) SET(PROJECT_HDRS @@ -89,6 +91,7 @@ DFContext.cpp DFTileTypes.cpp DFProcessEnumerator.cpp ContextShared.cpp +DFProcess-SHM.cpp depends/md5/md5.cpp depends/md5/md5wrapper.cpp diff --git a/library/DFProcess-SHM.cpp b/library/DFProcess-SHM.cpp new file mode 100644 index 000000000..ad7ebc8a5 --- /dev/null +++ b/library/DFProcess-SHM.cpp @@ -0,0 +1,479 @@ +/* +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 "SHMProcess.h" +#include "dfhack/VersionInfo.h" +#include "dfhack/DFError.h" +#include "shms.h" +#include "mod-core.h" + +using namespace DFHack; + +SHMProcess::SHMProcess(uint32_t PID, vector & known_versions) +: d(new Private(this)) +{ + d->process_ID = PID; + // attach the SHM + if(!attach()) + { + return; + } + // Test bridge version, get PID, sync Yield + bool bridgeOK; + if(!d->Aux_Core_Attach(bridgeOK,d->process_ID)) + { + detach(); + throw Error::SHMAttachFailure(); + } + else if(!bridgeOK) + { + detach(); + throw Error::SHMVersionMismatch(); + } + + // try to identify the DF version (md5 the binary, compare with known versions) + d->validate(known_versions); + // at this point, DF is attached and suspended, make it run + detach(); +} + +SHMProcess::~SHMProcess() +{ + if(d->attached) + { + detach(); + } + // destroy data model. this is assigned by processmanager + if(d->memdescriptor) + delete d->memdescriptor; + delete d; +} + +VersionInfo * SHMProcess::getDescriptor() +{ + return d->memdescriptor; +} + +int SHMProcess::getPID() +{ + return d->process_ID; +} + + +bool SHMProcess::isSuspended() +{ + return d->locked; +} +bool SHMProcess::isAttached() +{ + return d->attached; +} + +bool SHMProcess::isIdentified() +{ + return d->identified; +} + +bool SHMProcess::suspend() +{ + if(!d->attached) + { + return false; + } + if(d->locked) + { + return true; + } + //cerr << "suspend" << endl;// FIXME: throw + // 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? + if(D_SHMCMD == CORE_RUN) + { + //fprintf(stderr,"%d invokes step\n",attachmentIdx); + // wait for the next window + /* + if(!d->SetAndWait(CORE_STEP)) + { + throw Error::SHMLockingError("if(!d->SetAndWait(CORE_STEP))"); + } + */ + D_SHMCMD = CORE_STEP; + } + else + { + //fprintf(stderr,"%d invokes suspend\n",attachmentIdx); + // lock now + /* + if(!d->SetAndWait(CORE_SUSPEND)) + { + throw Error::SHMLockingError("if(!d->SetAndWait(CORE_SUSPEND))"); + } + */ + D_SHMCMD = CORE_SUSPEND; + } + //fprintf(stderr,"waiting for lock\n"); + // we wait for the server to give up our suspend lock (held by default) + if(acquireSuspendLock()) + { + d->locked = true; + return true; + } + return false; +} + +// FIXME: needs a good think-through +bool SHMProcess::asyncSuspend() +{ + if(!d->attached) + { + return false; + } + if(d->locked) + { + return true; + } + //cerr << "async suspend" << endl;// FIXME: throw + uint32_t cmd = D_SHMCMD; + if(cmd == CORE_SUSPENDED) + { + // we have to hold the lock to be really suspended + if(acquireSuspendLock()) + { + d->locked = true; + return true; + } + return false; + } + else + { + // did we just resume a moment ago? + if(cmd == CORE_STEP) + { + return false; + } + else if(cmd == CORE_RUN) + { + D_SHMCMD = CORE_STEP; + } + else + { + D_SHMCMD = CORE_SUSPEND; + } + return false; + } +} + +bool SHMProcess::forceresume() +{ + return resume(); +} + +// FIXME: wait for the server to advance a step! +bool SHMProcess::resume() +{ + if(!d->attached) + return false; + if(!d->locked) + return true; + //cerr << "resume" << endl;// FIXME: throw + // unlock the suspend lock + if(releaseSuspendLock()) + { + d->locked = false; + if(d->SetAndWait(CORE_RUN)) // we have to make sure the server responds! + { + return true; + } + throw Error::SHMLockingError("if(d->SetAndWait(CORE_RUN))"); + } + throw Error::SHMLockingError("if(releaseSuspendLock())"); + return false; +} + +// get module index by name and version. bool 0 = error +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 + } + if(D_SHMHDR->error) + { + return false; + } + //fprintf(stderr,"%s v%d : %d\n", name, version, D_SHMHDR->value); + OUTPUT = D_SHMHDR->value; + return true; +} + +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; + /* + cerr <<"CORE_VERSION" << CORE_VERSION << endl; + cerr <<"server CORE_VERSION" << SHMDATA(coreattach)->sv_version << endl; + */ + versionOK =( SHMDATA(coreattach)->sv_version == CORE_VERSION ); + PID = SHMDATA(coreattach)->sv_PID; + useYield = SHMDATA(coreattach)->sv_useYield; + #ifdef DEBUG + if(useYield) cerr << "Using Yield!" << endl; + #endif + return true; +} + +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) + { + D_SHMHDR->address = src_address; + D_SHMHDR->length = size; + full_barrier + d->SetAndWait(CORE_READ); + memcpy (target_buffer, D_SHMDATA(void),size); + } + // a big read, we pull data over the shm in iterations + else + { + // first read equals the size of the SHM window + uint32_t to_read = SHM_BODY; + while (size) + { + // read to_read bytes from src_cursor + D_SHMHDR->address = src_address; + D_SHMHDR->length = to_read; + full_barrier + d->SetAndWait(CORE_READ); + memcpy (target_buffer, D_SHMDATA(void) ,to_read); + // decrease size by bytes read + size -= to_read; + // move the cursors + src_address += to_read; + target_buffer += to_read; + // check how much to write in the next iteration + to_read = min(size, (uint32_t) SHM_BODY); + } + } +} + +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); + val = D_SHMHDR->value; +} + +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); + val = D_SHMHDR->value; +} + +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); + val = D_SHMHDR->value; +} + +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); + val = D_SHMHDR->Qvalue; +} + +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); + val = reinterpret_cast (D_SHMHDR->value); +} + +/* + * WRITING + */ + +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 + d->SetAndWait(CORE_WRITE_QUAD); +} + +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 + d->SetAndWait(CORE_WRITE_DWORD); +} + +// using these is expensive. +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 + d->SetAndWait(CORE_WRITE_WORD); +} + +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 + d->SetAndWait(CORE_WRITE_BYTE); +} + +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) + { + D_SHMHDR->address = dst_address; + D_SHMHDR->length = size; + memcpy(D_SHMDATA(void),source_buffer, size); + full_barrier + d->SetAndWait(CORE_WRITE); + } + // a big write, we push this over the shm in iterations + else + { + // first write equals the size of the SHM window + uint32_t to_write = SHM_BODY; + while (size) + { + // write to_write bytes to dst_cursor + D_SHMHDR->address = dst_address; + D_SHMHDR->length = to_write; + memcpy(D_SHMDATA(void),source_buffer, to_write); + full_barrier + d->SetAndWait(CORE_WRITE); + // decrease size by bytes written + size -= to_write; + // move the cursors + source_buffer += to_write; + dst_address += to_write; + // check how much to write in the next iteration + to_write = min(size, (uint32_t) SHM_BODY); + } + } +} + +// FIXME: butt-fugly +const std::string SHMProcess::readCString (uint32_t offset) +{ + if(!d->locked) throw Error::MemoryAccessDenied(); + + std::string temp; + char temp_c[256]; + int counter = 0; + char r; + do + { + r = Process::readByte(offset+counter); + temp_c[counter] = r; + counter++; + } while (r && counter < 255); + temp_c[counter] = 0; + temp = temp_c; + return temp; +} + +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); + return(string( D_SHMDATA(char) )); +} + +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); + size_t length = D_SHMHDR->value; + size_t fit = min(bufcapacity - 1, length); + strncpy(buffer,D_SHMDATA(char),fit); + buffer[fit] = 0; + return fit; +} + +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 + d->SetAndWait(CORE_WRITE_STL_STRING); +} diff --git a/library/DFProcess-linux-SHM.cpp b/library/DFProcess-linux-SHM.cpp index 700dec976..8229b6adb 100644 --- a/library/DFProcess-linux-SHM.cpp +++ b/library/DFProcess-linux-SHM.cpp @@ -22,7 +22,7 @@ must not be misrepresented as being the original software. distribution. */ #include "Internal.h" -#include "ProcessInternal.h" +#include "SHMProcess.h" #include "dfhack/VersionInfo.h" #include "dfhack/DFError.h" @@ -39,61 +39,20 @@ distribution. using namespace DFHack; -class SHMProcess::Private +SHMProcess::Private::Private(SHMProcess * self_) { - public: - Private(Process * self_) - { - memdescriptor = NULL; - process_ID = 0; - shm_addr = 0; - //shm_addr_with_cl_idx = 0; - shm_ID = -1; - attached = false; - identified = false; - useYield = false; - server_lock = -1; - client_lock = -1; - suspend_lock = -1; - attachmentIdx = 0; - locked = false; - self = self_; - }; - ~Private(){}; - VersionInfo * memdescriptor; - Process * self; - pid_t process_ID; - char *shm_addr; - int shm_ID; - Process* q; - int server_lock; - int client_lock; - int suspend_lock; - int attachmentIdx; - - bool attached; - bool locked; - bool identified; - bool useYield; - - bool validate(std::vector< VersionInfo* >& known_versions); - - bool Aux_Core_Attach(bool & versionOK, pid_t& PID); - bool SetAndWait (uint32_t state); - bool GetLocks(); - bool AreLocksOk(); - void FreeLocks(); -}; - -// some helpful macros to keep the code bloat in check -#define SHMCMD ( (uint32_t *) shm_addr)[attachmentIdx] -#define D_SHMCMD ( (uint32_t *) (d->shm_addr))[d->attachmentIdx] - -#define SHMHDR ((shm_core_hdr *)shm_addr) -#define D_SHMHDR ((shm_core_hdr *)(d->shm_addr)) - -#define SHMDATA(type) ((type *)(shm_addr + SHM_HEADER)) -#define D_SHMDATA(type) ((type *)(d->shm_addr + SHM_HEADER)) + memdescriptor = NULL; + process_ID = 0; + shm_ID = -1; + attached = false; + identified = false; + useYield = false; + server_lock = -1; + client_lock = -1; + suspend_lock = -1; + locked = false; + self = self_; +} bool SHMProcess::Private::SetAndWait (uint32_t state) { @@ -256,50 +215,6 @@ bool SHMProcess::Private::AreLocksOk() return false; } -SHMProcess::SHMProcess(uint32_t PID, vector< VersionInfo* >& known_versions) -: d(new Private(this)) -{ - d->process_ID = PID; - d->memdescriptor = 0; - if(!attach()) - { - // couldn't attach to process - return; - } - /* - * Test bridge version, get PID, sync Yield - */ - bool bridgeOK; - if(!d->Aux_Core_Attach(bridgeOK,d->process_ID)) - { - detach(); - throw Error::SHMAttachFailure(); - } - if(!bridgeOK) - { - detach(); - throw Error::SHMVersionMismatch(); - } - - // try to identify the DF version (md5 the binary, compare with known versions) - d->validate(known_versions); - // detach - detach(); -} - -bool SHMProcess::isSuspended() -{ - return d->locked; -} -bool SHMProcess::isAttached() -{ - return d->attached; -} - -bool SHMProcess::isIdentified() -{ - return d->identified; -} bool SHMProcess::Private::validate(vector & known_versions) { @@ -331,7 +246,7 @@ bool SHMProcess::Private::validate(vector & known_versions) { VersionInfo *m = new VersionInfo(**it); memdescriptor = m; - m->setParentProcess(dynamic_cast( self )); + m->setParentProcess(self); identified = true; // cerr << "identified " << m->getVersion() << endl; return true; @@ -345,27 +260,6 @@ bool SHMProcess::Private::validate(vector & known_versions) return false; } -SHMProcess::~SHMProcess() -{ - if(d->attached) - { - detach(); - } - if(d->memdescriptor) - delete d->memdescriptor; - delete d; -} - -VersionInfo * SHMProcess::getDescriptor() -{ - return d->memdescriptor; -} - -int SHMProcess::getPID() -{ - return d->process_ID; -} - // there is only one we care about. bool SHMProcess::getThreadIDs(vector & threads ) { @@ -406,119 +300,14 @@ void SHMProcess::getMemRanges( vector & ranges ) } } -bool SHMProcess::suspend() +bool SHMProcess::acquireSuspendLock() { - if(!d->attached) - { - return false; - } - if(d->locked) - { - 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? - if(D_SHMCMD == CORE_RUN) - { - //fprintf(stderr,"%d invokes step\n",d->attachmentIdx); - // wait for the next window - /* - if(!d->SetAndWait(CORE_STEP)) - { - throw Error::SHMLockingError("if(!d->SetAndWait(CORE_STEP))"); - } - */ - D_SHMCMD = CORE_STEP; - } - else - { - //fprintf(stderr,"%d invokes suspend\n",d->attachmentIdx); - // lock now - /* - if(!d->SetAndWait(CORE_SUSPEND)) - { - throw Error::SHMLockingError("if(!d->SetAndWait(CORE_SUSPEND))"); - } - */ - D_SHMCMD = CORE_SUSPEND; - } - //fprintf(stderr,"waiting for lock\n"); - // we wait for the server to give up our suspend lock (held by default) - if(lockf(d->suspend_lock,F_LOCK,0) == 0) - { - d->locked = true; - return true; - } - return false; -} - -// FIXME: needs a good think-through -bool SHMProcess::asyncSuspend() -{ - if(!d->attached) - { - return false; - } - if(d->locked) - { - return true; - } - uint32_t cmd = D_SHMCMD; - if(cmd == CORE_SUSPENDED) - { - // we have to hold the lock to be really suspended - if(lockf(d->suspend_lock,F_LOCK,0) == 0) - { - d->locked = true; - return true; - } - return false; - } - else - { - // did we just resume a moment ago? - if(cmd == CORE_STEP) - { - return false; - } - else if(cmd == CORE_RUN) - { - D_SHMCMD = CORE_STEP; - } - else - { - D_SHMCMD = CORE_SUSPEND; - } - return false; - } + return (lockf(d->suspend_lock,F_LOCK,0) == 0); } -bool SHMProcess::forceresume() +bool SHMProcess::releaseSuspendLock() { - return resume(); -} - -// FIXME: wait for the server to advance a step! -bool SHMProcess::resume() -{ - if(!d->attached) - return false; - if(!d->locked) - return true; - // unlock the suspend lock - if(lockf(d->suspend_lock,F_ULOCK,0) == 0) - { - d->locked = false; - if(d->SetAndWait(CORE_RUN)) // we have to make sure the server responds! - { - return true; - } - throw Error::SHMLockingError("if(d->SetAndWait(CORE_RUN))"); - } - throw Error::SHMLockingError("if(lockf(d->suspend_lock,F_ULOCK,0) == 0)"); - return false; + return (lockf(d->suspend_lock,F_ULOCK,0) == 0); } @@ -530,6 +319,7 @@ bool SHMProcess::attach() return suspend(); return true; } + //cerr << "attach" << endl;// FIXME: throw if(!d->GetLocks()) { //cerr << "server is full or not really there!" << endl; @@ -588,229 +378,6 @@ bool SHMProcess::detach() return false; } -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) - { - D_SHMHDR->address = src_address; - D_SHMHDR->length = size; - full_barrier - d->SetAndWait(CORE_READ); - memcpy (target_buffer, D_SHMDATA(void),size); - } - // a big read, we pull data over the shm in iterations - else - { - // first read equals the size of the SHM window - uint32_t to_read = SHM_BODY; - while (size) - { - // read to_read bytes from src_cursor - D_SHMHDR->address = src_address; - D_SHMHDR->length = to_read; - full_barrier - d->SetAndWait(CORE_READ); - memcpy (target_buffer, D_SHMDATA(void) ,to_read); - // decrease size by bytes read - size -= to_read; - // move the cursors - src_address += to_read; - target_buffer += to_read; - // check how much to write in the next iteration - to_read = min(size, (uint32_t) SHM_BODY); - } - } -} - -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); - val = D_SHMHDR->value; -} - -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); - val = D_SHMHDR->value; -} - -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); - val = D_SHMHDR->value; -} - -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); - val = D_SHMHDR->Qvalue; -} - -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); - val = reinterpret_cast (D_SHMHDR->value); -} - -/* - * WRITING - */ - -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 - d->SetAndWait(CORE_WRITE_QUAD); -} - -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 - d->SetAndWait(CORE_WRITE_DWORD); -} - -// using these is expensive. -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 - d->SetAndWait(CORE_WRITE_WORD); -} - -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 - d->SetAndWait(CORE_WRITE_BYTE); -} - -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) - { - D_SHMHDR->address = dst_address; - D_SHMHDR->length = size; - memcpy(D_SHMDATA(void),source_buffer, size); - full_barrier - d->SetAndWait(CORE_WRITE); - } - // a big write, we push this over the shm in iterations - else - { - // first write equals the size of the SHM window - uint32_t to_write = SHM_BODY; - while (size) - { - // write to_write bytes to dst_cursor - D_SHMHDR->address = dst_address; - D_SHMHDR->length = to_write; - memcpy(D_SHMDATA(void),source_buffer, to_write); - full_barrier - d->SetAndWait(CORE_WRITE); - // decrease size by bytes written - size -= to_write; - // move the cursors - source_buffer += to_write; - dst_address += to_write; - // check how much to write in the next iteration - to_write = min(size, (uint32_t) SHM_BODY); - } - } -} - -// FIXME: butt-fugly -const std::string SHMProcess::readCString (uint32_t offset) -{ - if(!d->locked) throw Error::MemoryAccessDenied(); - - std::string temp; - char temp_c[256]; - int counter = 0; - char r; - do - { - r = Process::readByte(offset+counter); - temp_c[counter] = r; - counter++; - } while (r && counter < 255); - temp_c[counter] = 0; - temp = temp_c; - return temp; -} - -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); - return(string( D_SHMDATA(char) )); -} - -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); - size_t length = D_SHMHDR->value; - size_t fit = min(bufcapacity - 1, length); - strncpy(buffer,D_SHMDATA(char),fit); - buffer[fit] = 0; - return fit; -} - -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 - d->SetAndWait(CORE_WRITE_STL_STRING); -} - string SHMProcess::readClassName (uint32_t vptr) { if(!d->locked) throw Error::MemoryAccessDenied(); @@ -836,52 +403,9 @@ string SHMProcess::getPath() return(string(target_name)); } -// get module index by name and version. bool 0 = error -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 - } - if(D_SHMHDR->error) - { - return false; - } - //fprintf(stderr,"%s v%d : %d\n", name, version, D_SHMHDR->value); - OUTPUT = D_SHMHDR->value; - return true; -} - 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; - /* - cerr <<"CORE_VERSION" << CORE_VERSION << endl; - cerr <<"server CORE_VERSION" << SHMDATA(coreattach)->sv_version << endl; - */ - versionOK =( SHMDATA(coreattach)->sv_version == CORE_VERSION ); - PID = SHMDATA(coreattach)->sv_PID; - useYield = SHMDATA(coreattach)->sv_useYield; - #ifdef DEBUG - if(useYield) cerr << "Using Yield!" << endl; - #endif - return true; + return d->shm_addr; } diff --git a/library/DFProcess-windows-SHM.cpp b/library/DFProcess-windows-SHM.cpp index 97711a979..7966cf58c 100644 --- a/library/DFProcess-windows-SHM.cpp +++ b/library/DFProcess-windows-SHM.cpp @@ -22,63 +22,26 @@ must not be misrepresented as being the original software. distribution. */ #include "Internal.h" -#include "ProcessInternal.h" +#include "SHMProcess.h" #include "dfhack/VersionInfo.h" #include "dfhack/DFError.h" #include "shms.h" #include "mod-core.h" using namespace DFHack; -class SHMProcess::Private +SHMProcess::Private::Private(SHMProcess * self_) { - public: - Private() - { - memdescriptor = NULL; - process_ID = 0; - shm_addr = 0; - attached = false; - locked = false; - identified = false; - useYield = 0; - DFSVMutex = 0; - DFCLMutex = 0; - DFCLSuspendMutex = 0; - attachmentIdx = -1; - }; - ~Private(){}; - VersionInfo * memdescriptor; - SHMProcess * self; - uint32_t process_ID; - char *shm_addr; - HANDLE DFSVMutex; - HANDLE DFCLMutex; - HANDLE DFCLSuspendMutex; - int attachmentIdx; - - bool attached; - bool locked; - bool identified; - bool useYield; - - bool validate(std::vector< VersionInfo* >& known_versions); - - bool Aux_Core_Attach(bool & versionOK, uint32_t & PID); - bool SetAndWait (uint32_t state); - bool GetLocks(); - bool AreLocksOk(); - void FreeLocks(); -}; - -// some helpful macros to keep the code bloat in check -#define SHMCMD ( (uint32_t *) shm_addr)[attachmentIdx] -#define D_SHMCMD ( (uint32_t *) (d->shm_addr))[d->attachmentIdx] - -#define SHMHDR ((shm_core_hdr *)shm_addr) -#define D_SHMHDR ((shm_core_hdr *)(d->shm_addr)) - -#define SHMDATA(type) ((type *)(shm_addr + SHM_HEADER)) -#define D_SHMDATA(type) ((type *)(d->shm_addr + SHM_HEADER)) + memdescriptor = NULL; + process_ID = 0; + attached = false; + locked = false; + identified = false; + useYield = 0; + DFSVMutex = 0; + DFCLMutex = 0; + DFCLSuspendMutex = 0; + self = self_; +} bool SHMProcess::Private::SetAndWait (uint32_t state) { @@ -253,46 +216,6 @@ bool SHMProcess::Private::AreLocksOk() return false; } -SHMProcess::SHMProcess(uint32_t PID, vector & known_versions) -: d(new Private()) -{ - d->process_ID = PID; - d->self = this; - // attach the SHM - if(!attach()) - { - return; - } - // Test bridge version, get PID, sync Yield - bool bridgeOK; - if(!d->Aux_Core_Attach(bridgeOK,d->process_ID)) - { - detach(); - throw Error::SHMAttachFailure(); - } - else if(!bridgeOK) - { - detach(); - throw Error::SHMVersionMismatch(); - } - d->validate(known_versions); - // at this point, DF is attached and suspended, make it run - detach(); -} - -bool SHMProcess::isSuspended() -{ - return d->locked; -} -bool SHMProcess::isAttached() -{ - return d->attached; -} - -bool SHMProcess::isIdentified() -{ - return d->identified; -} bool SHMProcess::Private::validate(vector & known_versions) { // try to identify the DF version @@ -350,29 +273,6 @@ bool SHMProcess::Private::validate(vector & known_versions) } return false; } -SHMProcess::~SHMProcess() -{ - if(d->attached) - { - detach(); - } - // destroy data model. this is assigned by processmanager - if(d->memdescriptor) - { - delete d->memdescriptor; - } - delete d; -} - -VersionInfo * SHMProcess::getDescriptor() -{ - return d->memdescriptor; -} - -int SHMProcess::getPID() -{ - return d->process_ID; -} bool SHMProcess::getThreadIDs(vector & threads ) { @@ -424,121 +324,14 @@ void SHMProcess::getMemRanges( vector & ranges ) ranges.push_back(temp); } -bool SHMProcess::suspend() +bool SHMProcess::acquireSuspendLock() { - if(!d->attached) - { - return false; - } - if(d->locked) - { - return true; - } - //cerr << "suspend" << endl;// FIXME: throw - // 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? - if(D_SHMCMD == CORE_RUN) - { - //fprintf(stderr,"%d invokes step\n",d->attachmentIdx); - // wait for the next window - /* - if(!d->SetAndWait(CORE_STEP)) - { - throw Error::SHMLockingError("if(!d->SetAndWait(CORE_STEP))"); - } - */ - D_SHMCMD = CORE_STEP; - } - else - { - //fprintf(stderr,"%d invokes suspend\n",d->attachmentIdx); - // lock now - /* - if(!d->SetAndWait(CORE_SUSPEND)) - { - throw Error::SHMLockingError("if(!d->SetAndWait(CORE_SUSPEND))"); - } - */ - D_SHMCMD = CORE_SUSPEND; - } - //fprintf(stderr,"waiting for lock\n"); - // we wait for the server to give up our suspend lock (held by default) - if( WaitForSingleObject(d->DFCLSuspendMutex,INFINITE) == 0 ) - { - d->locked = true; - return true; - } - return false; -} - -// FIXME: needs a good think-through -bool SHMProcess::asyncSuspend() -{ - if(!d->attached) - { - return false; - } - if(d->locked) - { - return true; - } - //cerr << "async suspend" << endl;// FIXME: throw - uint32_t cmd = D_SHMCMD; - if(cmd == CORE_SUSPENDED) - { - // we have to hold the lock to be really suspended - if( WaitForSingleObject(d->DFCLSuspendMutex,INFINITE) == 0 ) - { - d->locked = true; - return true; - } - return false; - } - else - { - // did we just resume a moment ago? - if(cmd == CORE_STEP) - { - return false; - } - else if(cmd == CORE_RUN) - { - D_SHMCMD = CORE_STEP; - } - else - { - D_SHMCMD = CORE_SUSPEND; - } - return false; - } + return ( WaitForSingleObject(d->DFCLSuspendMutex,INFINITE) == 0 ); } -bool SHMProcess::forceresume() +bool SHMProcess::releaseSuspendLock() { - return resume(); -} - -// FIXME: wait for the server to advance a step! -bool SHMProcess::resume() -{ - if(!d->attached) - return false; - if(!d->locked) - return true; - //cerr << "resume" << endl;// FIXME: throw - // unlock the suspend lock - if( ReleaseMutex(d->DFCLSuspendMutex) != 0) - { - d->locked = false; - if(d->SetAndWait(CORE_RUN)) // we have to make sure the server responds! - { - return true; - } - throw Error::SHMLockingError("if(d->SetAndWait(CORE_RUN))"); - } - throw Error::SHMLockingError("if( ReleaseMutex(d->DFCLSuspendMutex) != 0)"); - return false; + return ( ReleaseMutex(d->DFCLSuspendMutex) != 0); } @@ -613,229 +406,6 @@ bool SHMProcess::detach() return true; } -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) - { - D_SHMHDR->address = src_address; - D_SHMHDR->length = size; - full_barrier - d->SetAndWait(CORE_READ); - memcpy (target_buffer, D_SHMDATA(void),size); - } - // a big read, we pull data over the shm in iterations - else - { - // first read equals the size of the SHM window - uint32_t to_read = SHM_BODY; - while (size) - { - // read to_read bytes from src_cursor - D_SHMHDR->address = src_address; - D_SHMHDR->length = to_read; - full_barrier - d->SetAndWait(CORE_READ); - memcpy (target_buffer, D_SHMDATA(void) ,to_read); - // decrease size by bytes read - size -= to_read; - // move the cursors - src_address += to_read; - target_buffer += to_read; - // check how much to write in the next iteration - to_read = min(size, (uint32_t) SHM_BODY); - } - } -} - -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); - val = D_SHMHDR->value; -} - -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); - val = D_SHMHDR->value; -} - -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); - val = D_SHMHDR->value; -} - -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); - val = D_SHMHDR->Qvalue; -} - -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); - val = reinterpret_cast (D_SHMHDR->value); -} - -/* - * WRITING - */ - -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 - d->SetAndWait(CORE_WRITE_QUAD); -} - -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 - d->SetAndWait(CORE_WRITE_DWORD); -} - -// using these is expensive. -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 - d->SetAndWait(CORE_WRITE_WORD); -} - -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 - d->SetAndWait(CORE_WRITE_BYTE); -} - -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) - { - D_SHMHDR->address = dst_address; - D_SHMHDR->length = size; - memcpy(D_SHMDATA(void),source_buffer, size); - full_barrier - d->SetAndWait(CORE_WRITE); - } - // a big write, we push this over the shm in iterations - else - { - // first write equals the size of the SHM window - uint32_t to_write = SHM_BODY; - while (size) - { - // write to_write bytes to dst_cursor - D_SHMHDR->address = dst_address; - D_SHMHDR->length = to_write; - memcpy(D_SHMDATA(void),source_buffer, to_write); - full_barrier - d->SetAndWait(CORE_WRITE); - // decrease size by bytes written - size -= to_write; - // move the cursors - source_buffer += to_write; - dst_address += to_write; - // check how much to write in the next iteration - to_write = min(size, (uint32_t) SHM_BODY); - } - } -} - -// FIXME: butt-fugly -const std::string SHMProcess::readCString (uint32_t offset) -{ - if(!d->locked) throw Error::MemoryAccessDenied(); - - std::string temp; - char temp_c[256]; - int counter = 0; - char r; - do - { - r = Process::readByte(offset+counter); - temp_c[counter] = r; - counter++; - } while (r && counter < 255); - temp_c[counter] = 0; - temp = temp_c; - return temp; -} - -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); - return(string( D_SHMDATA(char) )); -} - -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); - size_t length = D_SHMHDR->value; - size_t fit = min(bufcapacity - 1, length); - strncpy(buffer,D_SHMDATA(char),fit); - buffer[fit] = 0; - return fit; -} - -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 - d->SetAndWait(CORE_WRITE_STL_STRING); -} - string SHMProcess::readClassName (uint32_t vptr) { int rtti = Process::readDWord(vptr - 0x4); @@ -857,51 +427,9 @@ string SHMProcess::getPath() return(out.substr(0,out.find_last_of("\\"))); } -// get module index by name and version. bool 0 = error -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 - } - if(D_SHMHDR->error) - { - return false; - } - //fprintf(stderr,"%s v%d : %d\n", name, version, D_SHMHDR->value); - OUTPUT = D_SHMHDR->value; - return true; -} - char * SHMProcess::getSHMStart (void) { if(!d->locked) throw Error::MemoryAccessDenied(); - return /*d->shm_addr_with_cl_idx*/ d->shm_addr; -} - -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; - /* - cerr <<"CORE_VERSION" << CORE_VERSION << endl; - cerr <<"server CORE_VERSION" << SHMDATA(coreattach)->sv_version << endl; - */ - versionOK =( SHMDATA(coreattach)->sv_version == CORE_VERSION ); - PID = SHMDATA(coreattach)->sv_PID; - useYield = SHMDATA(coreattach)->sv_useYield; - #ifdef DEBUG - if(useYield) cerr << "Using Yield!" << endl; - #endif - return true; + return d->shm_addr; } diff --git a/library/DFProcessEnumerator.cpp b/library/DFProcessEnumerator.cpp index fdd96ec27..e9d785fdb 100644 --- a/library/DFProcessEnumerator.cpp +++ b/library/DFProcessEnumerator.cpp @@ -24,6 +24,7 @@ distribution. #include "Internal.h" #include "ProcessInternal.h" +#include "SHMProcess.h" #include "dfhack/VersionInfoFactory.h" #include "dfhack/DFProcessEnumerator.h" diff --git a/library/private/ProcessInternal.h b/library/private/ProcessInternal.h index 0bca44d54..8bab5b2c2 100644 --- a/library/private/ProcessInternal.h +++ b/library/private/ProcessInternal.h @@ -29,10 +29,6 @@ distribution. namespace DFHack { - //////////////////////////////////////////////////////////////////////////// - // Compiler appeasement area. Not worth a look really... // - //////////////////////////////////////////////////////////////////////////// - class DFHACK_EXPORT NormalProcess : public Process { friend class ProcessEnumerator; @@ -92,66 +88,6 @@ namespace DFHack bool SetAndWait (uint32_t state){return false;}; }; - class DFHACK_EXPORT SHMProcess : public Process - { - friend class ProcessEnumerator; - class Private; - private: - Private * const d; - - public: - SHMProcess(uint32_t PID, std::vector & known_versions); - ~SHMProcess(); - // Set up stuff so we can read memory - bool attach(); - bool detach(); - - bool suspend(); - bool asyncSuspend(); - bool resume(); - bool forceresume(); - - void readQuad(const uint32_t address, uint64_t & value); - void writeQuad(const uint32_t address, const uint64_t value); - - void readDWord(const uint32_t address, uint32_t & value); - void writeDWord(const uint32_t address, const uint32_t value); - - void readFloat(const uint32_t address, float & value); - - void readWord(const uint32_t address, uint16_t & value); - void writeWord(const uint32_t address, const uint16_t value); - - void readByte(const uint32_t address, uint8_t & value); - void writeByte(const uint32_t address, const uint8_t value); - - void read( uint32_t address, uint32_t length, uint8_t* buffer); - void write(uint32_t address, uint32_t length, uint8_t* buffer); - - const std::string readSTLString (uint32_t offset); - size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity); - void writeSTLString(const uint32_t address, const std::string writeString); - // get class name of an object with rtti/type info - std::string readClassName(uint32_t vptr); - - const std::string readCString (uint32_t offset); - - bool isSuspended(); - bool isAttached(); - bool isIdentified(); - - bool getThreadIDs(std::vector & threads ); - void getMemRanges(std::vector & ranges ); - VersionInfo *getDescriptor(); - int getPID(); - std::string getPath(); - // get module index by name and version. bool 1 = error - bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT); - // get the SHM start if available - char * getSHMStart (void); - bool SetAndWait (uint32_t state); - }; - #ifdef LINUX_BUILD class DFHACK_EXPORT WineProcess : public Process { diff --git a/library/private/SHMProcess.h b/library/private/SHMProcess.h new file mode 100644 index 000000000..a4fe6e55f --- /dev/null +++ b/library/private/SHMProcess.h @@ -0,0 +1,144 @@ +/* +www.sourceforge.net/projects/dfhack +Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#ifndef SHM_PROCESS_H_INCLUDED +#define SHM_PROCESS_H_INCLUDED + +#include "dfhack/DFProcess.h" + +namespace DFHack +{ + class DFHACK_EXPORT SHMProcess : public Process + { + friend class ProcessEnumerator; + class Private; + private: + Private * const d; + + public: + SHMProcess(uint32_t PID, std::vector & known_versions); + ~SHMProcess(); + // Set up stuff so we can read memory + bool attach(); + bool detach(); + + bool suspend(); + bool asyncSuspend(); + bool resume(); + bool forceresume(); + + void readQuad(const uint32_t address, uint64_t & value); + void writeQuad(const uint32_t address, const uint64_t value); + + void readDWord(const uint32_t address, uint32_t & value); + void writeDWord(const uint32_t address, const uint32_t value); + + void readFloat(const uint32_t address, float & value); + + void readWord(const uint32_t address, uint16_t & value); + void writeWord(const uint32_t address, const uint16_t value); + + void readByte(const uint32_t address, uint8_t & value); + void writeByte(const uint32_t address, const uint8_t value); + + void read( uint32_t address, uint32_t length, uint8_t* buffer); + void write(uint32_t address, uint32_t length, uint8_t* buffer); + + const std::string readSTLString (uint32_t offset); + size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity); + void writeSTLString(const uint32_t address, const std::string writeString); + // get class name of an object with rtti/type info + std::string readClassName(uint32_t vptr); + + const std::string readCString (uint32_t offset); + + bool isSuspended(); + bool isAttached(); + bool isIdentified(); + + bool getThreadIDs(std::vector & threads ); + void getMemRanges(std::vector & ranges ); + VersionInfo *getDescriptor(); + int getPID(); + std::string getPath(); + // get module index by name and version. bool 1 = error + bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT); + // get the SHM start if available + char * getSHMStart (void); + bool SetAndWait (uint32_t state); + private: + bool acquireSuspendLock(); + bool releaseSuspendLock(); + }; + + class SHMProcess::Private + { + public: + Private(SHMProcess * self_); + ~Private(){} + VersionInfo * memdescriptor; + SHMProcess * self; + char *shm_addr; + int attachmentIdx; + + bool attached; + bool locked; + bool identified; + bool useYield; + +#ifdef LINUX_BUILD + pid_t process_ID; + int shm_ID; + int server_lock; + int client_lock; + int suspend_lock; +#else + typedef unit32_t pid_t; + uint32_t process_ID; + HANDLE DFSVMutex; + HANDLE DFCLMutex; + HANDLE DFCLSuspendMutex; +#endif + + bool validate(std::vector< VersionInfo* >& known_versions); + + bool Aux_Core_Attach(bool & versionOK, pid_t& PID); + bool SetAndWait (uint32_t state); + bool GetLocks(); + bool AreLocksOk(); + void FreeLocks(); + }; +} + +// some helpful macros to keep the code bloat in check +#define SHMCMD ( (uint32_t *) shm_addr)[attachmentIdx] +#define D_SHMCMD ( (uint32_t *) (d->shm_addr))[d->attachmentIdx] + +#define SHMHDR ((shm_core_hdr *)shm_addr) +#define D_SHMHDR ((shm_core_hdr *)(d->shm_addr)) + +#define SHMDATA(type) ((type *)(shm_addr + SHM_HEADER)) +#define D_SHMDATA(type) ((type *)(d->shm_addr + SHM_HEADER)) + +#endif From b3c490857cc15428a7b8c2af522c953642228126 Mon Sep 17 00:00:00 2001 From: Tom Prince Date: Wed, 23 Feb 2011 05:26:33 -0500 Subject: [PATCH 87/94] Refactor DFProcess-linux-{,wine}.cpp into DFProcess-linux-base.cpp. --- library/CMakeLists.txt | 4 +- library/DFProcess-linux-base.cpp | 439 ++++++++++++++++ library/DFProcess-linux-wine.cpp | 482 ++---------------- library/DFProcess-linux.cpp | 451 +--------------- library/DFProcess-windows.cpp | 2 +- library/DFProcessEnumerator.cpp | 3 +- .../{ProcessInternal.h => LinuxProcess.h} | 113 ++-- library/private/WindowsProcess.h | 94 ++++ 8 files changed, 634 insertions(+), 954 deletions(-) create mode 100644 library/DFProcess-linux-base.cpp rename library/private/{ProcessInternal.h => LinuxProcess.h} (65%) create mode 100644 library/private/WindowsProcess.h diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index e3ba69df4..f22c53fd4 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -29,8 +29,9 @@ include_directories (${CMAKE_SOURCE_DIR}/library/private/) SET(PROJECT_HDRS_INTERNAL private/ContextShared.h private/Internal.h - private/ProcessInternal.h private/SHMProcess.h + private/LinuxProcess.h + private/WindowsProcess.h ) SET(PROJECT_HDRS @@ -141,6 +142,7 @@ include/dfhack/DFstdint_win.h SET(PROJECT_SRCS_LINUX DFProcess-linux.cpp +DFProcess-linux-base.cpp DFProcess-linux-SHM.cpp DFProcess-linux-wine.cpp modules/WindowIO-linux.cpp diff --git a/library/DFProcess-linux-base.cpp b/library/DFProcess-linux-base.cpp new file mode 100644 index 000000000..7683cb121 --- /dev/null +++ b/library/DFProcess-linux-base.cpp @@ -0,0 +1,439 @@ +/* +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 "LinuxProcess.h" +#include "dfhack/VersionInfo.h" +#include "dfhack/DFError.h" +#include +#include +using namespace DFHack; + +LinuxProcessBase::Private::Private(LinuxProcessBase * self_, pid_t pid) +{ + my_descriptor = NULL; + my_pid = pid; + attached = false; + suspended = false; + memFileHandle = 0; + self = self_; +} + +LinuxProcessBase::LinuxProcessBase(uint32_t pid) +: d(new Private(this, pid)) +{ +} + +bool LinuxProcessBase::isSuspended() +{ + return d->suspended; +} +bool LinuxProcessBase::isAttached() +{ + return d->attached; +} + +bool LinuxProcessBase::isIdentified() +{ + return d->identified; +} + +LinuxProcessBase::~LinuxProcessBase() +{ + if(d->attached) + { + detach(); + } + // destroy our copy of the memory descriptor + if(d->my_descriptor) + delete d->my_descriptor; + delete d; +} + +VersionInfo * LinuxProcessBase::getDescriptor() +{ + return d->my_descriptor; +} + +int LinuxProcessBase::getPID() +{ + return d->my_pid; +} + +//FIXME: implement +bool LinuxProcessBase::getThreadIDs(vector & threads ) +{ + return false; +} + +//FIXME: cross-reference with ELF segment entries? +void LinuxProcessBase::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; + temp.name[0] = 0; + sscanf(buffer, "%llx-%llx %s %llx %2llu:%2llu %llu %s", + &temp.start, + &temp.end, + (char*)&permissions, + &offset, &device1, &device2, &node, + (char*)&temp.name); + temp.read = permissions[0] == 'r'; + temp.write = permissions[1] == 'w'; + temp.execute = permissions[2] == 'x'; + temp.valid = true; + ranges.push_back(temp); + } +} + +bool LinuxProcessBase::asyncSuspend() +{ + return suspend(); +} + +bool LinuxProcessBase::suspend() +{ + int status; + if(!d->attached) + return false; + if(d->suspended) + return true; + if (kill(d->my_pid, SIGSTOP) == -1) + { + // no, we got an error + perror("kill SIGSTOP error"); + return false; + } + while(true) + { + // we wait on the pid + pid_t w = waitpid(d->my_pid, &status, 0); + if (w == -1) + { + // child died + perror("DF exited during suspend call"); + return false; + } + // stopped -> let's continue + if (WIFSTOPPED(status)) + { + break; + } + } + d->suspended = true; + return true; +} + +bool LinuxProcessBase::forceresume() +{ + return resume(); +} + +bool LinuxProcessBase::resume() +{ + if(!d->attached) + return false; + if(!d->suspended) + return true; + if (ptrace(PTRACE_CONT, d->my_pid, NULL, NULL) == -1) + { + // no, we got an error + perror("ptrace resume error"); + return false; + } + d->suspended = false; + return true; +} + + +bool LinuxProcessBase::attach() +{ + int status; + if(d->attached) + { + if(!d->suspended) + return suspend(); + return true; + } + // can we attach? + if (ptrace(PTRACE_ATTACH , d->my_pid, NULL, NULL) == -1) + { + // no, we got an error + perror("ptrace attach error"); + cerr << "attach failed on pid " << d->my_pid << endl; + return false; + } + while(true) + { + // we wait on the pid + pid_t w = waitpid(d->my_pid, &status, 0); + if (w == -1) + { + // child died + perror("wait inside attach()"); + return false; + } + // stopped -> let's continue + if (WIFSTOPPED(status)) + { + break; + } + } + d->suspended = true; + + int proc_pid_mem = open(d->memFile.c_str(),O_RDONLY); + if(proc_pid_mem == -1) + { + ptrace(PTRACE_DETACH, d->my_pid, NULL, NULL); + cerr << d->memFile << endl; + cerr << "couldn't open /proc/" << d->my_pid << "/mem" << endl; + perror("open(memFile.c_str(),O_RDONLY)"); + return false; + } + else + { + d->attached = true; + + d->memFileHandle = proc_pid_mem; + return true; // we are attached + } +} + +bool LinuxProcessBase::detach() +{ + if(!d->attached) return true; + if(!d->suspended) suspend(); + int result = 0; + // close /proc/PID/mem + result = close(d->memFileHandle); + if(result == -1) + { + cerr << "couldn't close /proc/"<< d->my_pid <<"/mem" << endl; + perror("mem file close"); + return false; + } + else + { + // detach + result = ptrace(PTRACE_DETACH, d->my_pid, NULL, NULL); + if(result == -1) + { + cerr << "couldn't detach from process pid" << d->my_pid << endl; + perror("ptrace detach"); + return false; + } + else + { + d->attached = false; + return true; + } + } +} + + +void LinuxProcessBase::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; + while (total != size) + { + result = pread(d->memFileHandle, target + total ,remaining,offset + total); + if(result == -1) + { + cerr << "pread failed: can't read " << size << " bytes at addres " << offset << endl; + cerr << "errno: " << errno << endl; + errno = 0; + throw Error::MemoryAccessDenied(); + } + else + { + total += result; + remaining -= result; + } + } +} + +void LinuxProcessBase::readByte (const uint32_t offset, uint8_t &val ) +{ + read(offset, 1, &val); +} + +void LinuxProcessBase::readWord (const uint32_t offset, uint16_t &val) +{ + read(offset, 2, (uint8_t *) &val); +} + +void LinuxProcessBase::readDWord (const uint32_t offset, uint32_t &val) +{ + read(offset, 4, (uint8_t *) &val); +} + +void LinuxProcessBase::readFloat (const uint32_t offset, float &val) +{ + read(offset, 4, (uint8_t *) &val); +} + +void LinuxProcessBase::readQuad (const uint32_t offset, uint64_t &val) +{ + read(offset, 8, (uint8_t *) &val); +} + +/* + * WRITING + */ + +void LinuxProcessBase::writeQuad (uint32_t offset, const uint64_t data) +{ + #ifdef HAVE_64_BIT + ptrace(PTRACE_POKEDATA,d->my_pid, offset, data); + #else + ptrace(PTRACE_POKEDATA,d->my_pid, offset, (uint32_t) data); + ptrace(PTRACE_POKEDATA,d->my_pid, offset+4, (uint32_t) (data >> 32)); + #endif +} + +void LinuxProcessBase::writeDWord (uint32_t offset, uint32_t data) +{ + #ifdef HAVE_64_BIT + uint64_t orig = Process::readQuad(offset); + orig &= 0xFFFFFFFF00000000; + orig |= data; + ptrace(PTRACE_POKEDATA,d->my_pid, offset, orig); + #else + ptrace(PTRACE_POKEDATA,d->my_pid, offset, data); + #endif +} + +// using these is expensive. +void LinuxProcessBase::writeWord (uint32_t offset, uint16_t data) +{ + #ifdef HAVE_64_BIT + uint64_t orig = Process::readQuad(offset); + orig &= 0xFFFFFFFFFFFF0000; + orig |= data; + ptrace(PTRACE_POKEDATA,d->my_pid, offset, orig); + #else + uint32_t orig = readDWord(offset); + orig &= 0xFFFF0000; + orig |= data; + ptrace(PTRACE_POKEDATA,d->my_pid, offset, orig); + #endif +} + +void LinuxProcessBase::writeByte (uint32_t offset, uint8_t data) +{ + #ifdef HAVE_64_BIT + uint64_t orig = Process::readQuad(offset); + orig &= 0xFFFFFFFFFFFFFF00; + orig |= data; + ptrace(PTRACE_POKEDATA,d->my_pid, offset, orig); + #else + uint32_t orig = readDWord(offset); + orig &= 0xFFFFFF00; + orig |= data; + ptrace(PTRACE_POKEDATA,d->my_pid, offset, orig); + #endif +} + +// blah. I hate the kernel devs for crippling /proc/PID/mem. THIS IS RIDICULOUS +void LinuxProcessBase::write (uint32_t offset, uint32_t size, uint8_t *source) +{ + uint32_t indexptr = 0; + while (size > 0) + { + #ifdef HAVE_64_BIT + // quad! + if(size >= 8) + { + writeQuad(offset, *(uint64_t *) (source + indexptr)); + offset +=8; + indexptr +=8; + size -=8; + } + else + #endif + // default: we push 4 bytes + if(size >= 4) + { + writeDWord(offset, *(uint32_t *) (source + indexptr)); + offset +=4; + indexptr +=4; + size -=4; + } + // last is either three or 2 bytes + else if(size >= 2) + { + writeWord(offset, *(uint16_t *) (source + indexptr)); + offset +=2; + indexptr +=2; + size -=2; + } + // finishing move + else if(size == 1) + { + writeByte(offset, *(uint8_t *) (source + indexptr)); + return; + } + } +} + +const std::string LinuxProcessBase::readCString (uint32_t offset) +{ + std::string temp; + char temp_c[256]; + int counter = 0; + char r; + do + { + r = Process::readByte(offset+counter); + temp_c[counter] = r; + counter++; + } while (r && counter < 255); + temp_c[counter] = 0; + temp = temp_c; + return temp; +} + +string LinuxProcessBase::getPath() +{ + char cwd_name[256]; + char target_name[1024]; + int target_result; + + sprintf(cwd_name,"/proc/%d/cwd", getPID()); + // resolve /proc/PID/exe link + target_result = readlink(cwd_name, target_name, sizeof(target_name)); + target_name[target_result] = '\0'; + return(string(target_name)); +} diff --git a/library/DFProcess-linux-wine.cpp b/library/DFProcess-linux-wine.cpp index 7f880afbb..7e794f497 100644 --- a/library/DFProcess-linux-wine.cpp +++ b/library/DFProcess-linux-wine.cpp @@ -22,7 +22,7 @@ must not be misrepresented as being the original software. distribution. */ #include "Internal.h" -#include "ProcessInternal.h" +#include "LinuxProcess.h" #include "dfhack/VersionInfo.h" #include "dfhack/DFError.h" #include @@ -30,37 +30,8 @@ distribution. #include using namespace DFHack; -class WineProcess::Private -{ - public: - Private(Process * self_) - { - my_descriptor = NULL; - my_handle = NULL; - my_pid = 0; - attached = false; - suspended = false; - memFileHandle = 0; - self = self_; - }; - ~Private(){}; - VersionInfo * my_descriptor; - Process * self; - pid_t my_handle; - uint32_t my_pid; - string memFile; - int memFileHandle; - bool attached; - bool suspended; - bool identified; - 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) -: d(new Private(this)) +WineProcess::WineProcess(uint32_t pid, vector & known_versions) : LinuxProcessBase(pid) { char dir_name [256]; char exe_link_name [256]; @@ -107,27 +78,14 @@ WineProcess::WineProcess(uint32_t pid, vector & known_versions) sprintf(exe_link,"%s/%s",target_name,cmdline.c_str()); // create wine process, add it to the vector - d->identified = d->validate(exe_link,pid,mem_name,known_versions); + d->identified = validate(exe_link,pid,mem_name,known_versions); return; } } } -bool WineProcess::isSuspended() -{ - return d->suspended; -} -bool WineProcess::isAttached() -{ - return d->attached; -} - -bool WineProcess::isIdentified() -{ - return d->identified; -} -bool WineProcess::Private::validate(char* exe_file, uint32_t pid, char* mem_file, std::vector< VersionInfo* >& known_versions) +bool WineProcess::validate(char * exe_file,uint32_t pid, char * memFile, vector & known_versions) { md5wrapper md5; // get hash of the running DF process @@ -137,410 +95,42 @@ bool WineProcess::Private::validate(char* exe_file, uint32_t pid, char* mem_file // iterate over the list of memory locations for ( it=known_versions.begin() ; it < known_versions.end(); it++ ) { - string thishash; try { - thishash = (*it)->getMD5(); - } - catch (Error::AllMemdef& e) - { - continue; - } - // are the md5 hashes the same? - if(OS_WINDOWS == (*it)->getOS() && hash == thishash) - { - - // keep track of created memory_info object so we can destroy it later - 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; - } - } - return false; -} - -WineProcess::~WineProcess() -{ - if(d->attached) - { - detach(); - } - // destroy our copy of the memory descriptor - if(d->my_descriptor) - delete d->my_descriptor; - delete d; -} - -VersionInfo * WineProcess::getDescriptor() -{ - return d->my_descriptor; -} - -int WineProcess::getPID() -{ - return d->my_pid; -} - -//FIXME: implement -bool WineProcess::getThreadIDs(vector & threads ) -{ - return false; -} - -//FIXME: cross-reference with ELF segment entries? -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; - temp.name[0] = 0; - sscanf(buffer, "%llx-%llx %s %llx %2llu:%2llu %llu %s", - &temp.start, - &temp.end, - (char*)&permissions, - &offset, &device1, &device2, &node, - (char*)&temp.name); - temp.read = permissions[0] == 'r'; - temp.write = permissions[1] == 'w'; - temp.execute = permissions[2] == 'x'; - temp.valid = true; - ranges.push_back(temp); - } -} - -bool WineProcess::asyncSuspend() -{ - return suspend(); -} - -bool WineProcess::suspend() -{ - int status; - if(!d->attached) - return false; - if(d->suspended) - return true; - if (kill(d->my_handle, SIGSTOP) == -1) - { - // no, we got an error - perror("kill SIGSTOP error"); - return false; - } - while(true) - { - // we wait on the pid - pid_t w = waitpid(d->my_handle, &status, 0); - if (w == -1) - { - // child died - perror("DF exited during suspend call"); - return false; - } - // stopped -> let's continue - if (WIFSTOPPED(status)) - { - break; - } - } - d->suspended = true; - return true; -} - -bool WineProcess::forceresume() -{ - return resume(); -} - -bool WineProcess::resume() -{ - if(!d->attached) - return false; - if(!d->suspended) - return true; - if (ptrace(PTRACE_CONT, d->my_handle, NULL, NULL) == -1) - { - // no, we got an error - perror("ptrace resume error"); - return false; - } - d->suspended = false; - return true; -} - - -bool WineProcess::attach() -{ - int status; - if(d->attached) - { - if(!d->suspended) - return suspend(); - return true; - } - // can we attach? - if (ptrace(PTRACE_ATTACH , d->my_handle, NULL, NULL) == -1) - { - // no, we got an error - perror("ptrace attach error"); - cerr << "attach failed on pid " << d->my_handle << endl; - return false; - } - while(true) - { - // we wait on the pid - pid_t w = waitpid(d->my_handle, &status, 0); - if (w == -1) - { - // child died - perror("wait inside attach()"); - return false; - } - // stopped -> let's continue - if (WIFSTOPPED(status)) - { - break; - } - } - d->suspended = true; - - int proc_pid_mem = open(d->memFile.c_str(),O_RDONLY); - if(proc_pid_mem == -1) - { - ptrace(PTRACE_DETACH, d->my_handle, NULL, NULL); - cerr << d->memFile << endl; - cerr << "couldn't open /proc/" << d->my_handle << "/mem" << endl; - perror("open(memFile.c_str(),O_RDONLY)"); - return false; - } - else - { - d->attached = true; - - d->memFileHandle = proc_pid_mem; - return true; // we are attached - } -} - -bool WineProcess::detach() -{ - if(!d->attached) return true; - if(!d->suspended) suspend(); - int result = 0; - // close /proc/PID/mem - result = close(d->memFileHandle); - if(result == -1) - { - cerr << "couldn't close /proc/"<< d->my_handle <<"/mem" << endl; - perror("mem file close"); - return false; - } - else - { - // detach - result = ptrace(PTRACE_DETACH, d->my_handle, NULL, NULL); - if(result == -1) - { - cerr << "couldn't detach from process pid" << d->my_handle << endl; - perror("ptrace detach"); - return false; - } - else - { - d->attached = false; - return true; - } - } -} - - -// danger: uses recursion! -void WineProcess::read (const uint32_t offset, const uint32_t size, uint8_t *target) -{ - if(size == 0) return; - - ssize_t result; - ssize_t total = 0; - ssize_t remaining = size; - while (total != size) - { - result = pread(d->memFileHandle, target + total ,remaining,offset + total); - if(result == -1) - { - cerr << "pread failed: can't read " << size << " bytes at addres " << offset << endl; - cerr << "errno: " << errno << endl; - errno = 0; - throw Error::MemoryAccessDenied(); - } - else - { - total += result; - remaining -= result; - } - } -} - -void WineProcess::readByte (const uint32_t offset, uint8_t &val ) -{ - read(offset, 1, &val); -} - -void WineProcess::readWord (const uint32_t offset, uint16_t &val) -{ - read(offset, 2, (uint8_t *) &val); -} - -void WineProcess::readDWord (const uint32_t offset, uint32_t &val) -{ - read(offset, 4, (uint8_t *) &val); -} - -void WineProcess::readFloat (const uint32_t offset, float &val) -{ - read(offset, 4, (uint8_t *) &val); -} - -void WineProcess::readQuad (const uint32_t offset, uint64_t &val) -{ - read(offset, 8, (uint8_t *) &val); -} - -/* - * WRITING - */ - -void WineProcess::writeQuad (uint32_t offset, const uint64_t data) -{ - #ifdef HAVE_64_BIT - ptrace(PTRACE_POKEDATA,d->my_handle, offset, data); - #else - ptrace(PTRACE_POKEDATA,d->my_handle, offset, (uint32_t) data); - ptrace(PTRACE_POKEDATA,d->my_handle, offset+4, (uint32_t) (data >> 32)); - #endif -} - -void WineProcess::writeDWord (uint32_t offset, uint32_t data) -{ - #ifdef HAVE_64_BIT - uint64_t orig = Process::readQuad(offset); - orig &= 0xFFFFFFFF00000000; - orig |= data; - ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig); - #else - ptrace(PTRACE_POKEDATA,d->my_handle, offset, data); - #endif -} - -// using these is expensive. -void WineProcess::writeWord (uint32_t offset, uint16_t data) -{ - #ifdef HAVE_64_BIT - uint64_t orig = Process::readQuad(offset); - orig &= 0xFFFFFFFFFFFF0000; - orig |= data; - ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig); - #else - uint32_t orig = readDWord(offset); - orig &= 0xFFFF0000; - orig |= data; - ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig); - #endif -} - -void WineProcess::writeByte (uint32_t offset, uint8_t data) -{ - #ifdef HAVE_64_BIT - uint64_t orig = Process::readQuad(offset); - orig &= 0xFFFFFFFFFFFFFF00; - orig |= data; - ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig); - #else - uint32_t orig = readDWord(offset); - orig &= 0xFFFFFF00; - orig |= data; - ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig); - #endif -} - -// blah. I hate the kernel devs for crippling /proc/PID/mem. THIS IS RIDICULOUS -void WineProcess::write (uint32_t offset, uint32_t size, uint8_t *source) -{ - uint32_t indexptr = 0; - while (size > 0) - { - #ifdef HAVE_64_BIT - // quad! - if(size >= 8) + if (hash == (*it)->getMD5()) // are the md5 hashes the same? { - writeQuad(offset, *(uint64_t *) (source + indexptr)); - offset +=8; - indexptr +=8; - size -=8; + if (OS_WINDOWS == (*it)->getOS()) + { + VersionInfo *m = new VersionInfo(**it); + // keep track of created memory_info object so we can destroy it later + d->my_descriptor = m; + m->setParentProcess(this); + // tell Process about the /proc/PID/mem file + d->memFile = memFile; + d->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; + } } - else - #endif - // default: we push 4 bytes - if(size >= 4) - { - writeDWord(offset, *(uint32_t *) (source + indexptr)); - offset +=4; - indexptr +=4; - size -=4; } - // last is either three or 2 bytes - else if(size >= 2) + catch (Error::AllMemdef&) { - writeWord(offset, *(uint16_t *) (source + indexptr)); - offset +=2; - indexptr +=2; - size -=2; - } - // finishing move - else if(size == 1) - { - writeByte(offset, *(uint8_t *) (source + indexptr)); - return; + continue; } } + return false; } -const std::string WineProcess::readCString (uint32_t offset) -{ - std::string temp; - char temp_c[256]; - int counter = 0; - char r; - do - { - r = Process::readByte(offset+counter); - temp_c[counter] = r; - counter++; - } while (r && counter < 255); - temp_c[counter] = 0; - temp = temp_c; - return temp; -} size_t WineProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) { - uint32_t start_offset = offset + d->STLSTR_buf_off; - size_t length = Process::readDWord(offset + d->STLSTR_size_off); - size_t capacity = Process::readDWord(offset + d->STLSTR_cap_off); + uint32_t start_offset = offset + STLSTR_buf_off; + size_t length = Process::readDWord(offset + STLSTR_size_off); + size_t capacity = Process::readDWord(offset + STLSTR_cap_off); size_t read_real = min(length, bufcapacity-1);// keep space for null termination @@ -561,9 +151,9 @@ size_t WineProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcap const string WineProcess::readSTLString (uint32_t offset) { - uint32_t start_offset = offset + d->STLSTR_buf_off; - size_t length = Process::readDWord(offset + d->STLSTR_size_off); - size_t capacity = Process::readDWord(offset + d->STLSTR_cap_off); + uint32_t start_offset = offset + STLSTR_buf_off; + size_t length = Process::readDWord(offset + STLSTR_size_off); + size_t capacity = Process::readDWord(offset + STLSTR_cap_off); char * temp = new char[capacity+1]; @@ -592,15 +182,3 @@ string WineProcess::readClassName (uint32_t vptr) raw.resize(raw.length() - 2);// trim @@ from end return raw; } -string WineProcess::getPath() -{ - char cwd_name[256]; - char target_name[1024]; - int target_result; - - sprintf(cwd_name,"/proc/%d/cwd", getPID()); - // resolve /proc/PID/exe link - target_result = readlink(cwd_name, target_name, sizeof(target_name)); - target_name[target_result] = '\0'; - return(string(target_name)); -} diff --git a/library/DFProcess-linux.cpp b/library/DFProcess-linux.cpp index 284bb2dc2..bb2509c5f 100644 --- a/library/DFProcess-linux.cpp +++ b/library/DFProcess-linux.cpp @@ -22,42 +22,14 @@ must not be misrepresented as being the original software. distribution. */ #include "Internal.h" -#include "ProcessInternal.h" +#include "LinuxProcess.h" #include "dfhack/VersionInfo.h" #include "dfhack/DFError.h" #include #include using namespace DFHack; -class NormalProcess::Private -{ - public: - Private(Process * self_) - { - my_descriptor = NULL; - my_handle = NULL; - my_pid = 0; - attached = false; - suspended = false; - memFileHandle = 0; - self = self_; - }; - ~Private(){}; - Window* my_window; - VersionInfo * my_descriptor; - pid_t my_handle; - uint32_t my_pid; - string memFile; - int memFileHandle; - bool attached; - bool suspended; - bool identified; - Process * self; - bool validate(char * exe_file, uint32_t pid, char * mem_file, vector & known_versions); -}; - -NormalProcess::NormalProcess(uint32_t pid, vector< VersionInfo* >& known_versions) -: d(new Private(this)) +NormalProcess::NormalProcess(uint32_t pid, vector & known_versions) : LinuxProcessBase(pid) { char dir_name [256]; char exe_link_name [256]; @@ -89,26 +61,12 @@ NormalProcess::NormalProcess(uint32_t pid, vector< VersionInfo* >& known_version if (strstr(target_name, "dwarfort.exe") != 0 || strstr(target_name,"Dwarf_Fortress") != 0) { // create linux process, add it to the vector - d->identified = d->validate(target_name,pid,mem_name,known_versions ); + d->identified = validate(target_name,pid,mem_name,known_versions); return; } } -bool NormalProcess::isSuspended() -{ - return d->suspended; -} -bool NormalProcess::isAttached() -{ - return d->attached; -} - -bool NormalProcess::isIdentified() -{ - return d->identified; -} - -bool NormalProcess::Private::validate(char * exe_file,uint32_t pid, char * memFile, vector & known_versions) +bool NormalProcess::validate(char * exe_file,uint32_t pid, char * memFile, vector & known_versions) { md5wrapper md5; // get hash of the running DF process @@ -120,26 +78,19 @@ bool NormalProcess::Private::validate(char * exe_file,uint32_t pid, char * memFi { try { - //cout << hash << " ?= " << (*it)->getMD5() << endl; - if(hash == (*it)->getMD5()) // are the md5 hashes the same? + if (hash == (*it)->getMD5()) // are the md5 hashes the same? { - VersionInfo * m = *it; - if (OS_LINUX == m->getOS()) + if (OS_LINUX == (*it)->getOS()) { - VersionInfo *m2 = new VersionInfo(*m); - my_descriptor = m2; - m2->setParentProcess(dynamic_cast( self )); - my_handle = my_pid = pid; + VersionInfo *m = new VersionInfo(**it); + // keep track of created memory_info object so we can destroy it later + d->my_descriptor = m; + m->setParentProcess(this); + // tell Process about the /proc/PID/mem file + d->memFile = memFile; + d->identified = true; + return true; } - else - { - // some error happened, continue with next process - continue; - } - // tell NormalProcess about the /proc/PID/mem file - this->memFile = memFile; - identified = true; - return true; } } catch (Error::AllMemdef&) @@ -150,368 +101,6 @@ bool NormalProcess::Private::validate(char * exe_file,uint32_t pid, char * memFi return false; } -NormalProcess::~NormalProcess() -{ - if(d->attached) - { - detach(); - } - // destroy our copy of the memory descriptor - if(d->my_descriptor) - delete d->my_descriptor; - delete d; -} - -VersionInfo * NormalProcess::getDescriptor() -{ - return d->my_descriptor; -} - -int NormalProcess::getPID() -{ - return d->my_pid; -} - -//FIXME: implement -bool NormalProcess::getThreadIDs(vector & threads ) -{ - return false; -} - -//FIXME: cross-reference with ELF segment entries? -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; - temp.name[0] = 0; - sscanf(buffer, "%llx-%llx %s %llx %2llu:%2llu %llu %s", - &temp.start, - &temp.end, - (char*)&permissions, - &offset, &device1, &device2, &node, - (char*)&temp.name); - temp.read = permissions[0] == 'r'; - temp.write = permissions[1] == 'w'; - temp.execute = permissions[2] == 'x'; - temp.valid = true; - ranges.push_back(temp); - } -} - -bool NormalProcess::asyncSuspend() -{ - return suspend(); -} - -bool NormalProcess::suspend() -{ - int status; - if(!d->attached) - return false; - if(d->suspended) - return true; - if (kill(d->my_handle, SIGSTOP) == -1) - { - // no, we got an error - perror("kill SIGSTOP error"); - return false; - } - while(true) - { - // we wait on the pid - pid_t w = waitpid(d->my_handle, &status, 0); - if (w == -1) - { - // child died - perror("DF exited during suspend call"); - return false; - } - // stopped -> let's continue - if (WIFSTOPPED(status)) - { - break; - } - } - d->suspended = true; - return true; -} - -bool NormalProcess::forceresume() -{ - return resume(); -} - -bool NormalProcess::resume() -{ - if(!d->attached) - return false; - if(!d->suspended) - return true; - if (ptrace(PTRACE_CONT, d->my_handle, NULL, NULL) == -1) - { - // no, we got an error - perror("ptrace resume error"); - return false; - } - d->suspended = false; - return true; -} - - -bool NormalProcess::attach() -{ - int status; - if(d->attached) - { - if(!d->suspended) - return suspend(); - return true; - } - // can we attach? - if (ptrace(PTRACE_ATTACH , d->my_handle, NULL, NULL) == -1) - { - // no, we got an error - perror("ptrace attach error"); - cerr << "attach failed on pid " << d->my_handle << endl; - return false; - } - while(true) - { - // we wait on the pid - pid_t w = waitpid(d->my_handle, &status, 0); - if (w == -1) - { - // child died - perror("wait inside attach()"); - return false; - } - // stopped -> let's continue - if (WIFSTOPPED(status)) - { - break; - } - } - d->suspended = true; - - int proc_pid_mem = open(d->memFile.c_str(),O_RDONLY); - if(proc_pid_mem == -1) - { - ptrace(PTRACE_DETACH, d->my_handle, NULL, NULL); - cerr << "couldn't open /proc/" << d->my_handle << "/mem" << endl; - perror("open(memFile.c_str(),O_RDONLY)"); - return false; - } - else - { - d->attached = true; - - d->memFileHandle = proc_pid_mem; - return true; // we are attached - } -} - -bool NormalProcess::detach() -{ - if(!d->attached) return true; - if(!d->suspended) suspend(); - int result = 0; - // close /proc/PID/mem - result = close(d->memFileHandle); - if(result == -1) - { - cerr << "couldn't close /proc/"<< d->my_handle <<"/mem" << endl; - perror("mem file close"); - return false; - } - else - { - // detach - result = ptrace(PTRACE_DETACH, d->my_handle, NULL, NULL); - if(result == -1) - { - cerr << "couldn't detach from process pid" << d->my_handle << endl; - perror("ptrace detach"); - return false; - } - else - { - d->attached = false; - return true; - } - } -} - - -// danger: uses recursion! -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) - { - if(result == -1) - { - cerr << "pread failed: can't read 0x" << hex << size << " bytes at address 0x" << offset << endl; - cerr << "errno: " << errno << endl; - errno = 0; - throw Error::MemoryAccessDenied(); - } - else - { - this->read(offset + result, size - result, target + result); - } - } -} - -void NormalProcess::readByte (const uint32_t offset, uint8_t &val ) -{ - read(offset, 1, &val); -} - -void NormalProcess::readWord (const uint32_t offset, uint16_t &val) -{ - read(offset, 2, (uint8_t *) &val); -} - -void NormalProcess::readDWord (const uint32_t offset, uint32_t &val) -{ - read(offset, 4, (uint8_t *) &val); -} - -void NormalProcess::readFloat (const uint32_t offset, float &val) -{ - read(offset, 4, (uint8_t *) &val); -} - -void NormalProcess::readQuad (const uint32_t offset, uint64_t &val) -{ - read(offset, 8, (uint8_t *) &val); -} -/* - * WRITING - */ - -void NormalProcess::writeQuad (uint32_t offset, const uint64_t data) -{ - #ifdef HAVE_64_BIT - ptrace(PTRACE_POKEDATA,d->my_handle, offset, data); - #else - ptrace(PTRACE_POKEDATA,d->my_handle, offset, (uint32_t) data); - ptrace(PTRACE_POKEDATA,d->my_handle, offset+4, (uint32_t) (data >> 32)); - #endif -} - -void NormalProcess::writeDWord (uint32_t offset, uint32_t data) -{ - #ifdef HAVE_64_BIT - uint64_t orig = Process::readQuad(offset); - orig &= 0xFFFFFFFF00000000; - orig |= data; - ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig); - #else - ptrace(PTRACE_POKEDATA,d->my_handle, offset, data); - #endif -} - -// using these is expensive. -void NormalProcess::writeWord (uint32_t offset, uint16_t data) -{ - #ifdef HAVE_64_BIT - uint64_t orig = Process::readQuad(offset); - orig &= 0xFFFFFFFFFFFF0000; - orig |= data; - ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig); - #else - uint32_t orig = readDWord(offset); - orig &= 0xFFFF0000; - orig |= data; - ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig); - #endif -} - -void NormalProcess::writeByte (uint32_t offset, uint8_t data) -{ - #ifdef HAVE_64_BIT - uint64_t orig = Process::readQuad(offset); - orig &= 0xFFFFFFFFFFFFFF00; - orig |= data; - ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig); - #else - uint32_t orig = readDWord(offset); - orig &= 0xFFFFFF00; - orig |= data; - ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig); - #endif -} - -// blah. I hate the kernel devs for crippling /proc/PID/mem. THIS IS RIDICULOUS -void NormalProcess::write (uint32_t offset, uint32_t size, uint8_t *source) -{ - uint32_t indexptr = 0; - while (size > 0) - { - #ifdef HAVE_64_BIT - // quad! - if(size >= 8) - { - writeQuad(offset, *(uint64_t *) (source + indexptr)); - offset +=8; - indexptr +=8; - size -=8; - } - else - #endif - // default: we push 4 bytes - if(size >= 4) - { - writeDWord(offset, *(uint32_t *) (source + indexptr)); - offset +=4; - indexptr +=4; - size -=4; - } - // last is either three or 2 bytes - else if(size >= 2) - { - writeWord(offset, *(uint16_t *) (source + indexptr)); - offset +=2; - indexptr +=2; - size -=2; - } - // finishing move - else if(size == 1) - { - writeByte(offset, *(uint8_t *) (source + indexptr)); - return; - } - } -} - -const std::string NormalProcess::readCString (uint32_t offset) -{ - std::string temp; - char temp_c[256]; - int counter = 0; - char r; - do - { - r = Process::readByte(offset+counter); - temp_c[counter] = r; - counter++; - } while (r && counter < 255); - temp_c[counter] = 0; - temp = temp_c; - return temp; -} struct _Rep_base { @@ -555,15 +144,3 @@ string NormalProcess::readClassName (uint32_t vptr) size_t end = raw.length(); return raw.substr(start,end-start); } -string NormalProcess::getPath() -{ - char cwd_name[256]; - char target_name[1024]; - int target_result; - - sprintf(cwd_name,"/proc/%d/cwd", getPID()); - // resolve /proc/PID/exe link - target_result = readlink(cwd_name, target_name, sizeof(target_name)); - target_name[target_result] = '\0'; - return(string(target_name)); -} diff --git a/library/DFProcess-windows.cpp b/library/DFProcess-windows.cpp index 0d7d32f8c..4c4fae337 100644 --- a/library/DFProcess-windows.cpp +++ b/library/DFProcess-windows.cpp @@ -22,7 +22,7 @@ must not be misrepresented as being the original software. distribution. */ #include "Internal.h" -#include "ProcessInternal.h" +#include "WindowsProcess.h" #include "dfhack/VersionInfo.h" #include "dfhack/DFError.h" #include diff --git a/library/DFProcessEnumerator.cpp b/library/DFProcessEnumerator.cpp index e9d785fdb..2dbfd806b 100644 --- a/library/DFProcessEnumerator.cpp +++ b/library/DFProcessEnumerator.cpp @@ -23,8 +23,9 @@ distribution. */ #include "Internal.h" -#include "ProcessInternal.h" #include "SHMProcess.h" +#include "LinuxProcess.h" +#include "WindowsProcess.h" #include "dfhack/VersionInfoFactory.h" #include "dfhack/DFProcessEnumerator.h" diff --git a/library/private/ProcessInternal.h b/library/private/LinuxProcess.h similarity index 65% rename from library/private/ProcessInternal.h rename to library/private/LinuxProcess.h index 8bab5b2c2..17d30b85a 100644 --- a/library/private/ProcessInternal.h +++ b/library/private/LinuxProcess.h @@ -22,22 +22,26 @@ must not be misrepresented as being the original software. distribution. */ -#ifndef PROCESS_INTERNAL_H_INCLUDED -#define PROCESS_INTERNAL_H_INCLUDED +#ifndef LINUX_PROCESS_H_INCLUDED +#define LINUX_PROCESS_H_INCLUDED + +#ifdef LINUX_BUILD #include "dfhack/DFProcess.h" namespace DFHack { - class DFHACK_EXPORT NormalProcess : public Process + class LinuxProcessBase : public Process { - friend class ProcessEnumerator; + public: class Private; - private: + protected: Private * const d; + bool readProgramName(char *target_name, char *mem_name, char *cmdline_name); public: - NormalProcess(uint32_t pid, std::vector & known_versions); - ~NormalProcess(); + LinuxProcessBase(uint32_t pid); + ~LinuxProcessBase(); + bool attach(); bool detach(); @@ -63,23 +67,18 @@ namespace DFHack void read( uint32_t address, uint32_t length, uint8_t* buffer); void write(uint32_t address, uint32_t length, uint8_t* buffer); - const std::string readSTLString (uint32_t offset); - size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity); - void writeSTLString(const uint32_t address, const std::string writeString){}; - // get class name of an object with rtti/type info - std::string readClassName(uint32_t vptr); - const std::string readCString (uint32_t offset); bool isSuspended(); bool isAttached(); bool isIdentified(); - bool getThreadIDs(std::vector & threads ); - void getMemRanges(std::vector & ranges ); VersionInfo *getDescriptor(); int getPID(); std::string getPath(); + + bool getThreadIDs(std::vector & threads ); + void getMemRanges(std::vector & ranges ); // 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;}; // get the SHM start if available @@ -88,65 +87,55 @@ namespace DFHack bool SetAndWait (uint32_t state){return false;}; }; -#ifdef LINUX_BUILD - class DFHACK_EXPORT WineProcess : public Process + class DFHACK_EXPORT NormalProcess : public LinuxProcessBase { friend class ProcessEnumerator; - class Private; - private: - Private * const d; - public: - WineProcess(uint32_t pid, std::vector & known_versions); - ~WineProcess(); - bool attach(); - bool detach(); - - bool suspend(); - bool asyncSuspend(); - bool resume(); - bool forceresume(); - - void readQuad(const uint32_t address, uint64_t & value); - void writeQuad(const uint32_t address, const uint64_t value); - - void readDWord(const uint32_t address, uint32_t & value); - void writeDWord(const uint32_t address, const uint32_t value); - - void readFloat(const uint32_t address, float & value); - - void readWord(const uint32_t address, uint16_t & value); - void writeWord(const uint32_t address, const uint16_t value); - - void readByte(const uint32_t address, uint8_t & value); - void writeByte(const uint32_t address, const uint8_t value); - - void read( uint32_t address, uint32_t length, uint8_t* buffer); - void write(uint32_t address, uint32_t length, uint8_t* buffer); + NormalProcess(uint32_t pid, std::vector & known_versions); const std::string readSTLString (uint32_t offset); size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity); void writeSTLString(const uint32_t address, const std::string writeString){}; // get class name of an object with rtti/type info std::string readClassName(uint32_t vptr); + private: + bool validate(char * exe_file,uint32_t pid, char * memFile, vector & known_versions); + }; - const std::string readCString (uint32_t offset); + class DFHACK_EXPORT WineProcess : public LinuxProcessBase + { + friend class ProcessEnumerator; + private: + uint32_t STLSTR_buf_off; + uint32_t STLSTR_size_off; + uint32_t STLSTR_cap_off; + public: + WineProcess(uint32_t pid, std::vector & known_versions); - bool isSuspended(); - bool isAttached(); - bool isIdentified(); + const std::string readSTLString (uint32_t offset); + size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity); + void writeSTLString(const uint32_t address, const std::string writeString){}; + // get class name of an object with rtti/type info + std::string readClassName(uint32_t vptr); + private: + bool validate(char * exe_file,uint32_t pid, char * memFile, vector & known_versions); + }; - bool getThreadIDs(std::vector & threads ); - void getMemRanges(std::vector & ranges ); - 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;}; - // get the SHM start if available - char * getSHMStart (void){return 0;}; - bool SetAndWait (uint32_t state){return false;}; - std::string getPath(); + class LinuxProcessBase::Private + { + public: + Private(LinuxProcessBase * self_, pid_t); + ~Private(){}; + VersionInfo * my_descriptor; + LinuxProcessBase * self; + pid_t my_pid; + string memFile; + int memFileHandle; + bool attached; + bool suspended; + bool identified; }; -#endif } + +#endif #endif diff --git a/library/private/WindowsProcess.h b/library/private/WindowsProcess.h new file mode 100644 index 000000000..96ed504a1 --- /dev/null +++ b/library/private/WindowsProcess.h @@ -0,0 +1,94 @@ +/* +www.sourceforge.net/projects/dfhack +Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#ifndef WINDOWS_PROCESS_H_INCLUDED +#define WINDOWS_PROCESS_H_INCLUDED +#ifndef LINUX_BUILD + +#include "dfhack/DFProcess.h" + +namespace DFHack +{ + class DFHACK_EXPORT NormalProcess : public Process + { + friend class ProcessEnumerator; + class Private; + private: + Private * const d; + public: + NormalProcess(uint32_t pid, std::vector & known_versions); + ~NormalProcess(); + bool attach(); + bool detach(); + + bool suspend(); + bool asyncSuspend(); + bool resume(); + bool forceresume(); + + void readQuad(const uint32_t address, uint64_t & value); + void writeQuad(const uint32_t address, const uint64_t value); + + void readDWord(const uint32_t address, uint32_t & value); + void writeDWord(const uint32_t address, const uint32_t value); + + void readFloat(const uint32_t address, float & value); + + void readWord(const uint32_t address, uint16_t & value); + void writeWord(const uint32_t address, const uint16_t value); + + void readByte(const uint32_t address, uint8_t & value); + void writeByte(const uint32_t address, const uint8_t value); + + void read( uint32_t address, uint32_t length, uint8_t* buffer); + void write(uint32_t address, uint32_t length, uint8_t* buffer); + + const std::string readSTLString (uint32_t offset); + size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity); + void writeSTLString(const uint32_t address, const std::string writeString){}; + // get class name of an object with rtti/type info + std::string readClassName(uint32_t vptr); + + const std::string readCString (uint32_t offset); + + bool isSuspended(); + bool isAttached(); + bool isIdentified(); + + bool getThreadIDs(std::vector & threads ); + void getMemRanges(std::vector & ranges ); + VersionInfo *getDescriptor(); + int getPID(); + std::string getPath(); + // 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;}; + // get the SHM start if available + char * getSHMStart (void){return 0;}; + // set a SHM command and wait for a response + bool SetAndWait (uint32_t state){return false;}; + }; + +} +#endif +#endif From 2927b08f936773016d19097b53dfd79faf25f841 Mon Sep 17 00:00:00 2001 From: Tom Prince Date: Wed, 23 Feb 2011 05:49:33 -0500 Subject: [PATCH 88/94] Remove handle-body idiom of DFProcess on linux. Since the classes aren't exposed to the client, there is no reason to split the class. --- library/DFProcess-linux-base.cpp | 105 +++++++++++++++---------------- library/DFProcess-linux-wine.cpp | 18 +++--- library/DFProcess-linux.cpp | 15 +++-- library/private/LinuxProcess.h | 34 ++++------ 4 files changed, 75 insertions(+), 97 deletions(-) diff --git a/library/DFProcess-linux-base.cpp b/library/DFProcess-linux-base.cpp index 7683cb121..7549c1387 100644 --- a/library/DFProcess-linux-base.cpp +++ b/library/DFProcess-linux-base.cpp @@ -29,55 +29,48 @@ distribution. #include using namespace DFHack; -LinuxProcessBase::Private::Private(LinuxProcessBase * self_, pid_t pid) +LinuxProcessBase::LinuxProcessBase(uint32_t pid) +: my_pid(pid) { my_descriptor = NULL; - my_pid = pid; attached = false; suspended = false; memFileHandle = 0; - self = self_; -} - -LinuxProcessBase::LinuxProcessBase(uint32_t pid) -: d(new Private(this, pid)) -{ } bool LinuxProcessBase::isSuspended() { - return d->suspended; + return suspended; } bool LinuxProcessBase::isAttached() { - return d->attached; + return attached; } bool LinuxProcessBase::isIdentified() { - return d->identified; + return identified; } LinuxProcessBase::~LinuxProcessBase() { - if(d->attached) + if(attached) { detach(); } // destroy our copy of the memory descriptor - if(d->my_descriptor) - delete d->my_descriptor; - delete d; + if(my_descriptor) + delete my_descriptor; } VersionInfo * LinuxProcessBase::getDescriptor() { - return d->my_descriptor; + return my_descriptor; } int LinuxProcessBase::getPID() { - return d->my_pid; + return my_pid; } //FIXME: implement @@ -92,7 +85,7 @@ void LinuxProcessBase::getMemRanges( vector & ranges ) char buffer[1024]; char permissions[5]; // r/-, w/-, x/-, p/s, 0 - sprintf(buffer, "/proc/%lu/maps", d->my_pid); + sprintf(buffer, "/proc/%lu/maps", my_pid); FILE *mapFile = ::fopen(buffer, "r"); uint64_t offset, device1, device2, node; @@ -122,11 +115,11 @@ bool LinuxProcessBase::asyncSuspend() bool LinuxProcessBase::suspend() { int status; - if(!d->attached) + if(!attached) return false; - if(d->suspended) + if(suspended) return true; - if (kill(d->my_pid, SIGSTOP) == -1) + if (kill(my_pid, SIGSTOP) == -1) { // no, we got an error perror("kill SIGSTOP error"); @@ -135,7 +128,7 @@ bool LinuxProcessBase::suspend() while(true) { // we wait on the pid - pid_t w = waitpid(d->my_pid, &status, 0); + pid_t w = waitpid(my_pid, &status, 0); if (w == -1) { // child died @@ -148,7 +141,7 @@ bool LinuxProcessBase::suspend() break; } } - d->suspended = true; + suspended = true; return true; } @@ -159,17 +152,17 @@ bool LinuxProcessBase::forceresume() bool LinuxProcessBase::resume() { - if(!d->attached) + if(!attached) return false; - if(!d->suspended) + if(!suspended) return true; - if (ptrace(PTRACE_CONT, d->my_pid, NULL, NULL) == -1) + if (ptrace(PTRACE_CONT, my_pid, NULL, NULL) == -1) { // no, we got an error perror("ptrace resume error"); return false; } - d->suspended = false; + suspended = false; return true; } @@ -177,24 +170,24 @@ bool LinuxProcessBase::resume() bool LinuxProcessBase::attach() { int status; - if(d->attached) + if(attached) { - if(!d->suspended) + if(!suspended) return suspend(); return true; } // can we attach? - if (ptrace(PTRACE_ATTACH , d->my_pid, NULL, NULL) == -1) + if (ptrace(PTRACE_ATTACH , my_pid, NULL, NULL) == -1) { // no, we got an error perror("ptrace attach error"); - cerr << "attach failed on pid " << d->my_pid << endl; + cerr << "attach failed on pid " << my_pid << endl; return false; } while(true) { // we wait on the pid - pid_t w = waitpid(d->my_pid, &status, 0); + pid_t w = waitpid(my_pid, &status, 0); if (w == -1) { // child died @@ -207,52 +200,52 @@ bool LinuxProcessBase::attach() break; } } - d->suspended = true; + suspended = true; - int proc_pid_mem = open(d->memFile.c_str(),O_RDONLY); + int proc_pid_mem = open(memFile.c_str(),O_RDONLY); if(proc_pid_mem == -1) { - ptrace(PTRACE_DETACH, d->my_pid, NULL, NULL); - cerr << d->memFile << endl; - cerr << "couldn't open /proc/" << d->my_pid << "/mem" << endl; + ptrace(PTRACE_DETACH, my_pid, NULL, NULL); + cerr << memFile << endl; + cerr << "couldn't open /proc/" << my_pid << "/mem" << endl; perror("open(memFile.c_str(),O_RDONLY)"); return false; } else { - d->attached = true; + attached = true; - d->memFileHandle = proc_pid_mem; + memFileHandle = proc_pid_mem; return true; // we are attached } } bool LinuxProcessBase::detach() { - if(!d->attached) return true; - if(!d->suspended) suspend(); + if(!attached) return true; + if(!suspended) suspend(); int result = 0; // close /proc/PID/mem - result = close(d->memFileHandle); + result = close(memFileHandle); if(result == -1) { - cerr << "couldn't close /proc/"<< d->my_pid <<"/mem" << endl; + cerr << "couldn't close /proc/"<< my_pid <<"/mem" << endl; perror("mem file close"); return false; } else { // detach - result = ptrace(PTRACE_DETACH, d->my_pid, NULL, NULL); + result = ptrace(PTRACE_DETACH, my_pid, NULL, NULL); if(result == -1) { - cerr << "couldn't detach from process pid" << d->my_pid << endl; + cerr << "couldn't detach from process pid" << my_pid << endl; perror("ptrace detach"); return false; } else { - d->attached = false; + attached = false; return true; } } @@ -268,7 +261,7 @@ void LinuxProcessBase::read (const uint32_t offset, const uint32_t size, uint8_t ssize_t remaining = size; while (total != size) { - result = pread(d->memFileHandle, target + total ,remaining,offset + total); + result = pread(memFileHandle, target + total ,remaining,offset + total); if(result == -1) { cerr << "pread failed: can't read " << size << " bytes at addres " << offset << endl; @@ -316,10 +309,10 @@ void LinuxProcessBase::readQuad (const uint32_t offset, uint64_t &val) void LinuxProcessBase::writeQuad (uint32_t offset, const uint64_t data) { #ifdef HAVE_64_BIT - ptrace(PTRACE_POKEDATA,d->my_pid, offset, data); + ptrace(PTRACE_POKEDATA,my_pid, offset, data); #else - ptrace(PTRACE_POKEDATA,d->my_pid, offset, (uint32_t) data); - ptrace(PTRACE_POKEDATA,d->my_pid, offset+4, (uint32_t) (data >> 32)); + ptrace(PTRACE_POKEDATA,my_pid, offset, (uint32_t) data); + ptrace(PTRACE_POKEDATA,my_pid, offset+4, (uint32_t) (data >> 32)); #endif } @@ -329,9 +322,9 @@ void LinuxProcessBase::writeDWord (uint32_t offset, uint32_t data) uint64_t orig = Process::readQuad(offset); orig &= 0xFFFFFFFF00000000; orig |= data; - ptrace(PTRACE_POKEDATA,d->my_pid, offset, orig); + ptrace(PTRACE_POKEDATA,my_pid, offset, orig); #else - ptrace(PTRACE_POKEDATA,d->my_pid, offset, data); + ptrace(PTRACE_POKEDATA,my_pid, offset, data); #endif } @@ -342,12 +335,12 @@ void LinuxProcessBase::writeWord (uint32_t offset, uint16_t data) uint64_t orig = Process::readQuad(offset); orig &= 0xFFFFFFFFFFFF0000; orig |= data; - ptrace(PTRACE_POKEDATA,d->my_pid, offset, orig); + ptrace(PTRACE_POKEDATA,my_pid, offset, orig); #else uint32_t orig = readDWord(offset); orig &= 0xFFFF0000; orig |= data; - ptrace(PTRACE_POKEDATA,d->my_pid, offset, orig); + ptrace(PTRACE_POKEDATA,my_pid, offset, orig); #endif } @@ -357,12 +350,12 @@ void LinuxProcessBase::writeByte (uint32_t offset, uint8_t data) uint64_t orig = Process::readQuad(offset); orig &= 0xFFFFFFFFFFFFFF00; orig |= data; - ptrace(PTRACE_POKEDATA,d->my_pid, offset, orig); + ptrace(PTRACE_POKEDATA,my_pid, offset, orig); #else uint32_t orig = readDWord(offset); orig &= 0xFFFFFF00; orig |= data; - ptrace(PTRACE_POKEDATA,d->my_pid, offset, orig); + ptrace(PTRACE_POKEDATA,my_pid, offset, orig); #endif } diff --git a/library/DFProcess-linux-wine.cpp b/library/DFProcess-linux-wine.cpp index 7e794f497..419f633b9 100644 --- a/library/DFProcess-linux-wine.cpp +++ b/library/DFProcess-linux-wine.cpp @@ -30,7 +30,6 @@ distribution. #include using namespace DFHack; - WineProcess::WineProcess(uint32_t pid, vector & known_versions) : LinuxProcessBase(pid) { char dir_name [256]; @@ -41,8 +40,8 @@ WineProcess::WineProcess(uint32_t pid, vector & known_versions) char target_name[1024]; int target_result; - d->identified = false; - d->my_descriptor = 0; + identified = false; + my_descriptor = 0; sprintf(dir_name,"/proc/%d/", pid); sprintf(exe_link_name,"/proc/%d/exe", pid); @@ -78,7 +77,7 @@ WineProcess::WineProcess(uint32_t pid, vector & known_versions) sprintf(exe_link,"%s/%s",target_name,cmdline.c_str()); // create wine process, add it to the vector - d->identified = validate(exe_link,pid,mem_name,known_versions); + identified = validate(exe_link,pid,mem_name,known_versions); return; } } @@ -101,15 +100,14 @@ bool WineProcess::validate(char * exe_file,uint32_t pid, char * memFile, vector { if (OS_WINDOWS == (*it)->getOS()) { - VersionInfo *m = new VersionInfo(**it); // keep track of created memory_info object so we can destroy it later - d->my_descriptor = m; - m->setParentProcess(this); + my_descriptor = new VersionInfo(**it); + my_descriptor->setParentProcess(this); // tell Process about the /proc/PID/mem file - d->memFile = memFile; - d->identified = true; + memFile = memFile; + identified = true; - OffsetGroup * strGrp = m->getGroup("string")->getGroup("MSVC"); + OffsetGroup * strGrp = my_descriptor->getGroup("string")->getGroup("MSVC"); STLSTR_buf_off = strGrp->getOffset("buffer"); STLSTR_size_off = strGrp->getOffset("size"); STLSTR_cap_off = strGrp->getOffset("capacity"); diff --git a/library/DFProcess-linux.cpp b/library/DFProcess-linux.cpp index bb2509c5f..7ce1d2152 100644 --- a/library/DFProcess-linux.cpp +++ b/library/DFProcess-linux.cpp @@ -39,8 +39,8 @@ NormalProcess::NormalProcess(uint32_t pid, vector & known_versio char target_name[1024]; int target_result; - d->identified = false; - d->my_descriptor = 0; + identified = false; + my_descriptor = 0; sprintf(dir_name,"/proc/%d/", pid); sprintf(exe_link_name,"/proc/%d/exe", pid); @@ -61,7 +61,7 @@ NormalProcess::NormalProcess(uint32_t pid, vector & known_versio if (strstr(target_name, "dwarfort.exe") != 0 || strstr(target_name,"Dwarf_Fortress") != 0) { // create linux process, add it to the vector - d->identified = validate(target_name,pid,mem_name,known_versions); + identified = validate(target_name,pid,mem_name,known_versions); return; } } @@ -82,13 +82,12 @@ bool NormalProcess::validate(char * exe_file,uint32_t pid, char * memFile, vecto { if (OS_LINUX == (*it)->getOS()) { - VersionInfo *m = new VersionInfo(**it); // keep track of created memory_info object so we can destroy it later - d->my_descriptor = m; - m->setParentProcess(this); + my_descriptor = new VersionInfo(**it); + my_descriptor->setParentProcess(this); // tell Process about the /proc/PID/mem file - d->memFile = memFile; - d->identified = true; + memFile = memFile; + identified = true; return true; } } diff --git a/library/private/LinuxProcess.h b/library/private/LinuxProcess.h index 17d30b85a..a9e3c094e 100644 --- a/library/private/LinuxProcess.h +++ b/library/private/LinuxProcess.h @@ -33,11 +33,14 @@ namespace DFHack { class LinuxProcessBase : public Process { - public: - class Private; protected: - Private * const d; - bool readProgramName(char *target_name, char *mem_name, char *cmdline_name); + VersionInfo * my_descriptor; + pid_t my_pid; + string memFile; + int memFileHandle; + bool attached; + bool suspended; + bool identified; public: LinuxProcessBase(uint32_t pid); ~LinuxProcessBase(); @@ -98,8 +101,8 @@ namespace DFHack void writeSTLString(const uint32_t address, const std::string writeString){}; // get class name of an object with rtti/type info std::string readClassName(uint32_t vptr); - private: - bool validate(char * exe_file,uint32_t pid, char * memFile, vector & known_versions); + private: + bool validate(char * exe_file,uint32_t pid, char * memFile, vector & known_versions); }; class DFHACK_EXPORT WineProcess : public LinuxProcessBase @@ -117,23 +120,8 @@ namespace DFHack void writeSTLString(const uint32_t address, const std::string writeString){}; // get class name of an object with rtti/type info std::string readClassName(uint32_t vptr); - private: - bool validate(char * exe_file,uint32_t pid, char * memFile, vector & known_versions); - }; - - class LinuxProcessBase::Private - { - public: - Private(LinuxProcessBase * self_, pid_t); - ~Private(){}; - VersionInfo * my_descriptor; - LinuxProcessBase * self; - pid_t my_pid; - string memFile; - int memFileHandle; - bool attached; - bool suspended; - bool identified; + private: + bool validate(char * exe_file,uint32_t pid, char * memFile, vector & known_versions); }; } From 63ab8672d3da6e8ab92ee8266847caaec2c09d07 Mon Sep 17 00:00:00 2001 From: Tom Prince Date: Wed, 23 Feb 2011 06:08:30 -0500 Subject: [PATCH 89/94] Add create*Process functions to create process instances. This allows us to remove friendship of DFProcessEnumerator for Process subclasses. --- library/CMakeLists.txt | 1 + library/DFProcess-SHM.cpp | 6 +++++ library/DFProcess-linux-wine.cpp | 26 ++++++++++++++++++++++ library/DFProcess-linux.cpp | 22 ++++++++++++++++++ library/DFProcess-windows.cpp | 6 +++++ library/DFProcessEnumerator.cpp | 10 ++++----- library/private/LinuxProcess.h | 33 --------------------------- library/private/ProcessFactory.h | 38 ++++++++++++++++++++++++++++++++ library/private/SHMProcess.h | 3 +-- library/private/WindowsProcess.h | 3 +-- 10 files changed, 105 insertions(+), 43 deletions(-) create mode 100644 library/private/ProcessFactory.h diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index f22c53fd4..d54fc79d5 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -32,6 +32,7 @@ SET(PROJECT_HDRS_INTERNAL private/SHMProcess.h private/LinuxProcess.h private/WindowsProcess.h + private/ProcessFactory.h ) SET(PROJECT_HDRS diff --git a/library/DFProcess-SHM.cpp b/library/DFProcess-SHM.cpp index ad7ebc8a5..3246e567e 100644 --- a/library/DFProcess-SHM.cpp +++ b/library/DFProcess-SHM.cpp @@ -23,6 +23,7 @@ distribution. */ #include "Internal.h" #include "SHMProcess.h" +#include "ProcessFactory.h" #include "dfhack/VersionInfo.h" #include "dfhack/DFError.h" #include "shms.h" @@ -30,6 +31,11 @@ distribution. using namespace DFHack; +Process* DFHack::createSHMProcess(uint32_t pid, vector & known_versions) +{ + return new SHMProcess(pid, known_versions); +} + SHMProcess::SHMProcess(uint32_t PID, vector & known_versions) : d(new Private(this)) { diff --git a/library/DFProcess-linux-wine.cpp b/library/DFProcess-linux-wine.cpp index 419f633b9..a75b8077d 100644 --- a/library/DFProcess-linux-wine.cpp +++ b/library/DFProcess-linux-wine.cpp @@ -23,6 +23,7 @@ distribution. */ #include "Internal.h" #include "LinuxProcess.h" +#include "ProcessFactory.h" #include "dfhack/VersionInfo.h" #include "dfhack/DFError.h" #include @@ -30,6 +31,31 @@ distribution. #include using namespace DFHack; +namespace { + class WineProcess : public LinuxProcessBase + { + private: + uint32_t STLSTR_buf_off; + uint32_t STLSTR_size_off; + uint32_t STLSTR_cap_off; + public: + WineProcess(uint32_t pid, std::vector & known_versions); + + const std::string readSTLString (uint32_t offset); + size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity); + void writeSTLString(const uint32_t address, const std::string writeString){}; + // get class name of an object with rtti/type info + std::string readClassName(uint32_t vptr); + private: + bool validate(char * exe_file,uint32_t pid, char * memFile, vector & known_versions); + }; +} + +Process* DFHack::createWineProcess(uint32_t pid, vector & known_versions) +{ + return new WineProcess(pid, known_versions); +} + WineProcess::WineProcess(uint32_t pid, vector & known_versions) : LinuxProcessBase(pid) { char dir_name [256]; diff --git a/library/DFProcess-linux.cpp b/library/DFProcess-linux.cpp index 7ce1d2152..44ba5afea 100644 --- a/library/DFProcess-linux.cpp +++ b/library/DFProcess-linux.cpp @@ -23,12 +23,34 @@ distribution. */ #include "Internal.h" #include "LinuxProcess.h" +#include "ProcessFactory.h" #include "dfhack/VersionInfo.h" #include "dfhack/DFError.h" #include #include using namespace DFHack; +namespace { + class NormalProcess : public LinuxProcessBase + { + public: + NormalProcess(uint32_t pid, std::vector & known_versions); + + const std::string readSTLString (uint32_t offset); + size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity); + void writeSTLString(const uint32_t address, const std::string writeString){}; + // get class name of an object with rtti/type info + std::string readClassName(uint32_t vptr); + private: + bool validate(char * exe_file,uint32_t pid, char * memFile, vector & known_versions); + }; +} + +Process* DFHack::createNormalProcess(uint32_t pid, vector & known_versions) +{ + return new NormalProcess(pid, known_versions); +} + NormalProcess::NormalProcess(uint32_t pid, vector & known_versions) : LinuxProcessBase(pid) { char dir_name [256]; diff --git a/library/DFProcess-windows.cpp b/library/DFProcess-windows.cpp index 4c4fae337..5a9967ffb 100644 --- a/library/DFProcess-windows.cpp +++ b/library/DFProcess-windows.cpp @@ -23,11 +23,17 @@ distribution. */ #include "Internal.h" #include "WindowsProcess.h" +#include "ProcessFactory.h" #include "dfhack/VersionInfo.h" #include "dfhack/DFError.h" #include using namespace DFHack; +Process* DFHack::createNormalProcess(uint32_t pid, vector & known_versions) +{ + return new NormalProcess(pid, known_versions); +} + class NormalProcess::Private { public: diff --git a/library/DFProcessEnumerator.cpp b/library/DFProcessEnumerator.cpp index 2dbfd806b..be33d41fd 100644 --- a/library/DFProcessEnumerator.cpp +++ b/library/DFProcessEnumerator.cpp @@ -23,9 +23,7 @@ distribution. */ #include "Internal.h" -#include "SHMProcess.h" -#include "LinuxProcess.h" -#include "WindowsProcess.h" +#include "ProcessFactory.h" #include "dfhack/VersionInfoFactory.h" #include "dfhack/DFProcessEnumerator.h" @@ -122,19 +120,19 @@ Process * BadProcesses::operator[](uint32_t index) Process *ProcessEnumerator::Private::GetProcessObject(ProcessID ID) { - Process *p1 = new SHMProcess(ID.pid,meminfo->versions); + Process *p1 = createSHMProcess(ID.pid,meminfo->versions); if(p1->isIdentified()) return p1; else delete p1; - Process *p2 = new NormalProcess(ID.pid,meminfo->versions); + Process *p2 = createNormalProcess(ID.pid,meminfo->versions); if(p2->isIdentified()) return p2; else delete p2; #ifdef LINUX_BUILD - Process *p3 = new WineProcess(ID.pid,meminfo->versions); + Process *p3 = createWineProcess(ID.pid,meminfo->versions); if(p3->isIdentified()) return p3; else diff --git a/library/private/LinuxProcess.h b/library/private/LinuxProcess.h index a9e3c094e..cc9df1a05 100644 --- a/library/private/LinuxProcess.h +++ b/library/private/LinuxProcess.h @@ -90,39 +90,6 @@ namespace DFHack bool SetAndWait (uint32_t state){return false;}; }; - class DFHACK_EXPORT NormalProcess : public LinuxProcessBase - { - friend class ProcessEnumerator; - public: - NormalProcess(uint32_t pid, std::vector & known_versions); - - const std::string readSTLString (uint32_t offset); - size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity); - void writeSTLString(const uint32_t address, const std::string writeString){}; - // get class name of an object with rtti/type info - std::string readClassName(uint32_t vptr); - private: - bool validate(char * exe_file,uint32_t pid, char * memFile, vector & known_versions); - }; - - class DFHACK_EXPORT WineProcess : public LinuxProcessBase - { - friend class ProcessEnumerator; - private: - uint32_t STLSTR_buf_off; - uint32_t STLSTR_size_off; - uint32_t STLSTR_cap_off; - public: - WineProcess(uint32_t pid, std::vector & known_versions); - - const std::string readSTLString (uint32_t offset); - size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity); - void writeSTLString(const uint32_t address, const std::string writeString){}; - // get class name of an object with rtti/type info - std::string readClassName(uint32_t vptr); - private: - bool validate(char * exe_file,uint32_t pid, char * memFile, vector & known_versions); - }; } #endif diff --git a/library/private/ProcessFactory.h b/library/private/ProcessFactory.h new file mode 100644 index 000000000..217dbe839 --- /dev/null +++ b/library/private/ProcessFactory.h @@ -0,0 +1,38 @@ +/* +www.sourceforge.net/projects/dfhack +Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#ifndef PROCESS_FACTORY_H_INCLUDED +#define PROCESS_FACTORY_H_INCLUDED + +#include "dfhack/DFProcess.h" + +namespace DFHack +{ + Process* createNormalProcess(uint32_t pid, std::vector & known_versions); + Process* createSHMProcess(uint32_t pid, std::vector & known_versions); +#ifdef LINUX_BUILD + Process* createWineProcess(uint32_t pid, std::vector & known_versions); +#endif +} +#endif diff --git a/library/private/SHMProcess.h b/library/private/SHMProcess.h index a4fe6e55f..5fb704b07 100644 --- a/library/private/SHMProcess.h +++ b/library/private/SHMProcess.h @@ -31,9 +31,8 @@ namespace DFHack { class DFHACK_EXPORT SHMProcess : public Process { - friend class ProcessEnumerator; - class Private; private: + class Private; Private * const d; public: diff --git a/library/private/WindowsProcess.h b/library/private/WindowsProcess.h index 96ed504a1..97565f47c 100644 --- a/library/private/WindowsProcess.h +++ b/library/private/WindowsProcess.h @@ -30,9 +30,8 @@ distribution. namespace DFHack { - class DFHACK_EXPORT NormalProcess : public Process + class NormalProcess : public Process { - friend class ProcessEnumerator; class Private; private: Private * const d; From a5479a4bef8f153f9305bfa10a1b76e77529c758 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Wed, 23 Feb 2011 20:13:29 +0100 Subject: [PATCH 90/94] Linux 32bit fix. --- library/DFProcess-linux.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/DFProcess-linux.cpp b/library/DFProcess-linux.cpp index 284bb2dc2..867492181 100644 --- a/library/DFProcess-linux.cpp +++ b/library/DFProcess-linux.cpp @@ -432,7 +432,7 @@ void NormalProcess::writeWord (uint32_t offset, uint16_t data) orig |= data; ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig); #else - uint32_t orig = readDWord(offset); + uint32_t orig = Process::readDWord(offset); orig &= 0xFFFF0000; orig |= data; ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig); @@ -447,7 +447,7 @@ void NormalProcess::writeByte (uint32_t offset, uint8_t data) orig |= data; ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig); #else - uint32_t orig = readDWord(offset); + uint32_t orig = Process::readDWord(offset); orig &= 0xFFFFFF00; orig |= data; ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig); From aac3056b1242b933289b9719acdaa7eeb99a787e Mon Sep 17 00:00:00 2001 From: Tom Prince Date: Wed, 23 Feb 2011 15:27:15 -0500 Subject: [PATCH 91/94] Get rid of NormalProcess::Private on windows. --- library/DFProcess-windows.cpp | 294 ++++++++++++++++++------------- library/private/WindowsProcess.h | 93 ---------- 2 files changed, 170 insertions(+), 217 deletions(-) delete mode 100644 library/private/WindowsProcess.h diff --git a/library/DFProcess-windows.cpp b/library/DFProcess-windows.cpp index 5a9967ffb..a094e1e0f 100644 --- a/library/DFProcess-windows.cpp +++ b/library/DFProcess-windows.cpp @@ -29,84 +29,131 @@ distribution. #include using namespace DFHack; -Process* DFHack::createNormalProcess(uint32_t pid, vector & known_versions) +namespace { - return new NormalProcess(pid, known_versions); + class NormalProcess : public Process + { + private: + VersionInfo * my_descriptor; + HANDLE my_handle; + HANDLE my_main_thread; + uint32_t my_pid; + string memFile; + bool attached; + bool suspended; + bool identified; + uint32_t STLSTR_buf_off; + uint32_t STLSTR_size_off; + uint32_t STLSTR_cap_off; + IMAGE_NT_HEADERS pe_header; + IMAGE_SECTION_HEADER * sections; + uint32_t base; + public: + NormalProcess(uint32_t pid, std::vector & known_versions); + ~NormalProcess(); + bool attach(); + bool detach(); + + bool suspend(); + bool asyncSuspend(); + bool resume(); + bool forceresume(); + + void readQuad(const uint32_t address, uint64_t & value); + void writeQuad(const uint32_t address, const uint64_t value); + + void readDWord(const uint32_t address, uint32_t & value); + void writeDWord(const uint32_t address, const uint32_t value); + + void readFloat(const uint32_t address, float & value); + + void readWord(const uint32_t address, uint16_t & value); + void writeWord(const uint32_t address, const uint16_t value); + + void readByte(const uint32_t address, uint8_t & value); + void writeByte(const uint32_t address, const uint8_t value); + + void read( uint32_t address, uint32_t length, uint8_t* buffer); + void write(uint32_t address, uint32_t length, uint8_t* buffer); + + const std::string readSTLString (uint32_t offset); + size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity); + void writeSTLString(const uint32_t address, const std::string writeString){}; + // get class name of an object with rtti/type info + std::string readClassName(uint32_t vptr); + + const std::string readCString (uint32_t offset); + + bool isSuspended(); + bool isAttached(); + bool isIdentified(); + + bool getThreadIDs(std::vector & threads ); + void getMemRanges(std::vector & ranges ); + VersionInfo *getDescriptor(); + int getPID(); + std::string getPath(); + // 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;}; + // get the SHM start if available + char * getSHMStart (void){return 0;}; + // set a SHM command and wait for a response + bool SetAndWait (uint32_t state){return false;}; + }; + } -class NormalProcess::Private +Process* DFHack::createNormalProcess(uint32_t pid, vector & known_versions) { - public: - Private() - { - my_descriptor = NULL; - my_handle = NULL; - my_main_thread = NULL; - my_pid = 0; - attached = false; - suspended = false; - base = 0; - sections = 0; - }; - ~Private(){}; - VersionInfo * my_descriptor; - HANDLE my_handle; - HANDLE my_main_thread; - uint32_t my_pid; - string memFile; - bool attached; - bool suspended; - bool identified; - uint32_t STLSTR_buf_off; - uint32_t STLSTR_size_off; - uint32_t STLSTR_cap_off; - IMAGE_NT_HEADERS pe_header; - IMAGE_SECTION_HEADER * sections; - uint32_t base; -}; + return new NormalProcess(pid, known_versions); +} NormalProcess::NormalProcess(uint32_t pid, vector & known_versions) -: d(new Private()) +: my_pid(pid) { + my_descriptor = NULL; + my_main_thread = NULL; + attached = false; + suspended = false; + base = 0; + sections = 0; + HMODULE hmod = NULL; DWORD needed; - HANDLE hProcess; bool found = false; - d->identified = false; + identified = false; // open process - hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pid ); - if (NULL == hProcess) + my_handle = OpenProcess( PROCESS_ALL_ACCESS, FALSE, my_pid ); + if (NULL == my_handle) return; // try getting the first module of the process - if(EnumProcessModules(hProcess, &hmod, sizeof(hmod), &needed) == 0) + if(EnumProcessModules(my_handle, &hmod, sizeof(hmod), &needed) == 0) { - CloseHandle(hProcess); + CloseHandle(my_handle); // cout << "EnumProcessModules fail'd" << endl; return; //if enumprocessModules fails, give up } // got base ;) - d->base = (uint32_t)hmod; + base = (uint32_t)hmod; - // temporarily assign this to allow some checks - d->my_handle = hProcess; - d->my_main_thread = 0; + my_main_thread = 0; // read from this process try { - uint32_t pe_offset = Process::readDWord(d->base+0x3C); - read(d->base + pe_offset , sizeof(d->pe_header), (uint8_t *)&d->pe_header); - const size_t sectionsSize = sizeof(IMAGE_SECTION_HEADER) * d->pe_header.FileHeader.NumberOfSections; - d->sections = (IMAGE_SECTION_HEADER *) malloc(sectionsSize); - read(d->base + pe_offset + sizeof(d->pe_header), sectionsSize, (uint8_t *)d->sections); - d->my_handle = 0; + uint32_t pe_offset = Process::readDWord(base+0x3C); + read(base + pe_offset , sizeof(pe_header), (uint8_t *)&pe_header); + const size_t sectionsSize = sizeof(IMAGE_SECTION_HEADER) * pe_header.FileHeader.NumberOfSections; + sections = (IMAGE_SECTION_HEADER *) malloc(sectionsSize); + read(base + pe_offset + sizeof(pe_header), sectionsSize, (uint8_t *)sections); + my_handle = 0; } catch (exception &) { - CloseHandle(hProcess); - d->my_handle = 0; + CloseHandle(my_handle); + my_handle = 0; return; } @@ -127,32 +174,30 @@ NormalProcess::NormalProcess(uint32_t pid, vector & known_versio { continue; } - if (pe_timestamp != d->pe_header.FileHeader.TimeDateStamp) + 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; + identified = true; // give the process a data model and memory layout fixed for the base of first module - VersionInfo *m = new VersionInfo(**it); - m->RebaseAll(d->base); + my_descriptor = new VersionInfo(**it); + my_descriptor->RebaseAll(base); // keep track of created memory_info object so we can destroy it later - d->my_descriptor = m; - m->setParentProcess(this); + my_descriptor->setParentProcess(this); // process is responsible for destroying its data model - d->my_pid = pid; - d->my_handle = hProcess; - d->identified = true; + my_handle = my_handle; + 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"); + my_main_thread = OpenThread(THREAD_ALL_ACCESS, FALSE, (DWORD) threads[0]); + OffsetGroup * strGrp = my_descriptor->getGroup("string")->getGroup("MSVC"); + STLSTR_buf_off = strGrp->getOffset("buffer"); + STLSTR_size_off = strGrp->getOffset("size"); + STLSTR_cap_off = strGrp->getOffset("capacity"); found = true; break; // break the iterator loop } @@ -160,7 +205,7 @@ NormalProcess::NormalProcess(uint32_t pid, vector & known_versio // close handle of processes that aren't DF if(!found) { - CloseHandle(hProcess); + CloseHandle(my_handle); } } /* @@ -168,47 +213,47 @@ NormalProcess::NormalProcess(uint32_t pid, vector & known_versio NormalProcess::~NormalProcess() { - if(d->attached) + if(attached) { detach(); } // destroy our rebased copy of the memory descriptor - delete d->my_descriptor; - if(d->my_handle != NULL) + delete my_descriptor; + if(my_handle != NULL) { - CloseHandle(d->my_handle); + CloseHandle(my_handle); } - if(d->my_main_thread != NULL) + if(my_main_thread != NULL) { - CloseHandle(d->my_main_thread); + CloseHandle(my_main_thread); } - if(d->sections != NULL) - free(d->sections); + if(sections != NULL) + free(sections); delete d; } VersionInfo * NormalProcess::getDescriptor() { - return d->my_descriptor; + return my_descriptor; } int NormalProcess::getPID() { - return d->my_pid; + return my_pid; } bool NormalProcess::isSuspended() { - return d->suspended; + return suspended; } bool NormalProcess::isAttached() { - return d->attached; + return attached; } bool NormalProcess::isIdentified() { - return d->identified; + return identified; } bool NormalProcess::asyncSuspend() @@ -218,49 +263,49 @@ bool NormalProcess::asyncSuspend() bool NormalProcess::suspend() { - if(!d->attached) + if(!attached) return false; - if(d->suspended) + if(suspended) { return true; } - SuspendThread(d->my_main_thread); - d->suspended = true; + SuspendThread(my_main_thread); + suspended = true; return true; } bool NormalProcess::forceresume() { - if(!d->attached) + if(!attached) return false; - while (ResumeThread(d->my_main_thread) > 1); - d->suspended = false; + while (ResumeThread(my_main_thread) > 1); + suspended = false; return true; } bool NormalProcess::resume() { - if(!d->attached) + if(!attached) return false; - if(!d->suspended) + if(!suspended) { return true; } - ResumeThread(d->my_main_thread); - d->suspended = false; + ResumeThread(my_main_thread); + suspended = false; return true; } bool NormalProcess::attach() { - if(d->attached) + if(attached) { - if(!d->suspended) + if(!suspended) return suspend(); return true; } - d->attached = true; + attached = true; suspend(); return true; @@ -269,9 +314,9 @@ bool NormalProcess::attach() bool NormalProcess::detach() { - if(!d->attached) return true; + if(!attached) return true; resume(); - d->attached = false; + attached = false; return true; } @@ -295,7 +340,7 @@ bool NormalProcess::getThreadIDs(vector & threads ) do { - if( te32.th32OwnerProcessID == d->my_pid ) + if( te32.th32OwnerProcessID == my_pid ) { threads.push_back(te32.th32ThreadID); } @@ -356,9 +401,9 @@ void NormalProcess::getMemRanges( vector & ranges ) GetSystemInfo(&si); uint64_t PageSize = si.dwPageSize; // enumerate heaps - HeapNodes(d->my_pid, heaps); + HeapNodes(my_pid, heaps); // go through all the VM regions, convert them to our internal format - while (VirtualQueryEx(this->d->my_handle, (const void*) (movingStart), &MBI, sizeof(MBI)) == sizeof(MBI)) + while (VirtualQueryEx(this->my_handle, (const void*) (movingStart), &MBI, sizeof(MBI)) == sizeof(MBI)) { movingStart = ((uint64_t)MBI.BaseAddress + MBI.RegionSize); if(movingStart % PageSize != 0) @@ -373,7 +418,7 @@ void NormalProcess::getMemRanges( vector & ranges ) temp.write = MBI.Protect & PAGE_EXECUTE_READWRITE || MBI.Protect & PAGE_READWRITE; temp.execute = MBI.Protect & PAGE_EXECUTE_READ || MBI.Protect & PAGE_EXECUTE_READWRITE || MBI.Protect & PAGE_EXECUTE; temp.valid = true; - if(!GetModuleBaseName(this->d->my_handle, (HMODULE) temp.start, temp.name, 1024)) + if(!GetModuleBaseName(this->my_handle, (HMODULE) temp.start, temp.name, 1024)) { if(nameMap.count(temp.start)) { @@ -402,18 +447,18 @@ void NormalProcess::getMemRanges( vector & ranges ) else { // this is our executable! (could be generalized to pull segments from libs, but whatever) - if(d->base == temp.start) + if(base == temp.start) { - for(int i = 0; i < d->pe_header.FileHeader.NumberOfSections; i++) + for(int i = 0; i < pe_header.FileHeader.NumberOfSections; i++) { char sectionName[9]; - memcpy(sectionName,d->sections[i].Name,8); + memcpy(sectionName,sections[i].Name,8); sectionName[8] = 0; string nm; nm.append(temp.name); nm.append(" : "); nm.append(sectionName); - nameMap[temp.start + d->sections[i].VirtualAddress] = nm; + nameMap[temp.start + sections[i].VirtualAddress] = nm; } } else @@ -425,81 +470,79 @@ void NormalProcess::getMemRanges( vector & ranges ) void NormalProcess::readByte (const uint32_t offset,uint8_t &result) { - if(!ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint8_t), NULL)) + if(!ReadProcessMemory(my_handle, (int*) offset, &result, sizeof(uint8_t), NULL)) throw Error::MemoryAccessDenied(); } void NormalProcess::readWord (const uint32_t offset, uint16_t &result) { - if(!ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint16_t), NULL)) + if(!ReadProcessMemory(my_handle, (int*) offset, &result, sizeof(uint16_t), NULL)) throw Error::MemoryAccessDenied(); } void NormalProcess::readDWord (const uint32_t offset, uint32_t &result) { - if(!ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint32_t), NULL)) + if(!ReadProcessMemory(my_handle, (int*) offset, &result, sizeof(uint32_t), NULL)) throw Error::MemoryAccessDenied(); } void NormalProcess::readQuad (const uint32_t offset, uint64_t &result) { - if(!ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint64_t), NULL)) + if(!ReadProcessMemory(my_handle, (int*) offset, &result, sizeof(uint64_t), NULL)) throw Error::MemoryAccessDenied(); } void NormalProcess::readFloat (const uint32_t offset, float &result) { - if(!ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(float), NULL)) + if(!ReadProcessMemory(my_handle, (int*) offset, &result, sizeof(float), NULL)) throw Error::MemoryAccessDenied(); } void NormalProcess::read (const uint32_t offset, uint32_t size, uint8_t *target) { - if(!ReadProcessMemory(d->my_handle, (int*) offset, target, size, NULL)) + if(!ReadProcessMemory(my_handle, (int*) offset, target, size, NULL)) throw Error::MemoryAccessDenied(); } // WRITING void NormalProcess::writeQuad (const uint32_t offset, uint64_t data) { - if(!WriteProcessMemory(d->my_handle, (int*) offset, &data, sizeof(data), NULL)) + if(!WriteProcessMemory(my_handle, (int*) offset, &data, sizeof(data), NULL)) throw Error::MemoryAccessDenied(); } void NormalProcess::writeDWord (const uint32_t offset, uint32_t data) { - if(!WriteProcessMemory(d->my_handle, (int*) offset, &data, sizeof(data), NULL)) + if(!WriteProcessMemory(my_handle, (int*) offset, &data, sizeof(data), NULL)) throw Error::MemoryAccessDenied(); } // using these is expensive. void NormalProcess::writeWord (uint32_t offset, uint16_t data) { - if(!WriteProcessMemory(d->my_handle, (int*) offset, &data, sizeof(data), NULL)) + if(!WriteProcessMemory(my_handle, (int*) offset, &data, sizeof(data), NULL)) throw Error::MemoryAccessDenied(); } void NormalProcess::writeByte (uint32_t offset, uint8_t data) { - if(!WriteProcessMemory(d->my_handle, (int*) offset, &data, sizeof(data), NULL)) + if(!WriteProcessMemory(my_handle, (int*) offset, &data, sizeof(data), NULL)) throw Error::MemoryAccessDenied(); } void NormalProcess::write (uint32_t offset, uint32_t size, uint8_t *source) { - if(!WriteProcessMemory(d->my_handle, (int*) offset, source, size, NULL)) + if(!WriteProcessMemory(my_handle, (int*) offset, source, size, NULL)) throw Error::MemoryAccessDenied(); } - - ///FIXME: reduce use of temporary objects const string NormalProcess::readCString (const uint32_t offset) { string temp; char temp_c[256]; SIZE_T read; - if(!ReadProcessMemory(d->my_handle, (int *) offset, temp_c, 254, &read)) + if(!ReadProcessMemory(my_handle, (int *) offset, temp_c, 254, &read)) throw Error::MemoryAccessDenied(); // needs to be 254+1 byte for the null term temp_c[read+1] = 0; @@ -509,9 +552,10 @@ const string NormalProcess::readCString (const uint32_t offset) size_t NormalProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) { - uint32_t start_offset = offset + d->STLSTR_buf_off; - size_t length = Process::readDWord(offset + d->STLSTR_size_off); - size_t capacity = Process::readDWord(offset + d->STLSTR_cap_off); + uint32_t start_offset = offset + STLSTR_buf_off; + size_t length = Process::readDWord(offset + STLSTR_size_off); + size_t capacity = Process::readDWord(offset + STLSTR_cap_off); + size_t read_real = min(length, bufcapacity-1);// keep space for null termination // read data from inside the string structure @@ -531,9 +575,10 @@ size_t NormalProcess::readSTLString (uint32_t offset, char * buffer, size_t bufc const string NormalProcess::readSTLString (uint32_t offset) { - uint32_t start_offset = offset + d->STLSTR_buf_off; - size_t length = Process::readDWord(offset + d->STLSTR_size_off); - size_t capacity = Process::readDWord(offset + d->STLSTR_cap_off); + uint32_t start_offset = offset + STLSTR_buf_off; + size_t length = Process::readDWord(offset + STLSTR_size_off); + size_t capacity = Process::readDWord(offset + STLSTR_cap_off); + char * temp = new char[capacity+1]; // read data from inside the string structure @@ -561,13 +606,14 @@ string NormalProcess::readClassName (uint32_t vptr) raw.resize(raw.length() - 2);// trim @@ from end return raw; } + string NormalProcess::getPath() { HMODULE hmod; DWORD junk; char String[255]; - EnumProcessModules(d->my_handle, &hmod, 1 * sizeof(HMODULE), &junk); //get the module from the handle - GetModuleFileNameEx(d->my_handle,hmod,String,sizeof(String)); //get the filename from the module + EnumProcessModules(my_handle, &hmod, 1 * sizeof(HMODULE), &junk); //get the module from the handle + GetModuleFileNameEx(my_handle,hmod,String,sizeof(String)); //get the filename from the module string out(String); return(out.substr(0,out.find_last_of("\\"))); } diff --git a/library/private/WindowsProcess.h b/library/private/WindowsProcess.h deleted file mode 100644 index 97565f47c..000000000 --- a/library/private/WindowsProcess.h +++ /dev/null @@ -1,93 +0,0 @@ -/* -www.sourceforge.net/projects/dfhack -Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must -not claim that you wrote the original software. If you use this -software in a product, an acknowledgment in the product documentation -would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. -*/ - -#ifndef WINDOWS_PROCESS_H_INCLUDED -#define WINDOWS_PROCESS_H_INCLUDED -#ifndef LINUX_BUILD - -#include "dfhack/DFProcess.h" - -namespace DFHack -{ - class NormalProcess : public Process - { - class Private; - private: - Private * const d; - public: - NormalProcess(uint32_t pid, std::vector & known_versions); - ~NormalProcess(); - bool attach(); - bool detach(); - - bool suspend(); - bool asyncSuspend(); - bool resume(); - bool forceresume(); - - void readQuad(const uint32_t address, uint64_t & value); - void writeQuad(const uint32_t address, const uint64_t value); - - void readDWord(const uint32_t address, uint32_t & value); - void writeDWord(const uint32_t address, const uint32_t value); - - void readFloat(const uint32_t address, float & value); - - void readWord(const uint32_t address, uint16_t & value); - void writeWord(const uint32_t address, const uint16_t value); - - void readByte(const uint32_t address, uint8_t & value); - void writeByte(const uint32_t address, const uint8_t value); - - void read( uint32_t address, uint32_t length, uint8_t* buffer); - void write(uint32_t address, uint32_t length, uint8_t* buffer); - - const std::string readSTLString (uint32_t offset); - size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity); - void writeSTLString(const uint32_t address, const std::string writeString){}; - // get class name of an object with rtti/type info - std::string readClassName(uint32_t vptr); - - const std::string readCString (uint32_t offset); - - bool isSuspended(); - bool isAttached(); - bool isIdentified(); - - bool getThreadIDs(std::vector & threads ); - void getMemRanges(std::vector & ranges ); - VersionInfo *getDescriptor(); - int getPID(); - std::string getPath(); - // 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;}; - // get the SHM start if available - char * getSHMStart (void){return 0;}; - // set a SHM command and wait for a response - bool SetAndWait (uint32_t state){return false;}; - }; - -} -#endif -#endif From 48063184948bd03fcd528ca47fbda301d75a1143 Mon Sep 17 00:00:00 2001 From: Tom Prince Date: Wed, 23 Feb 2011 15:55:07 -0500 Subject: [PATCH 92/94] Factor out microsoft string handling functions. --- library/CMakeLists.txt | 3 +- library/DFProcess-linux-wine.cpp | 58 ++----------------- library/DFProcess-windows.cpp | 58 ++----------------- library/MicrosoftSTL.cpp | 96 ++++++++++++++++++++++++++++++++ library/private/MicrosoftSTL.h | 46 +++++++++++++++ 5 files changed, 156 insertions(+), 105 deletions(-) create mode 100644 library/MicrosoftSTL.cpp create mode 100644 library/private/MicrosoftSTL.h diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index d54fc79d5..fdf49f8d3 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -31,8 +31,8 @@ SET(PROJECT_HDRS_INTERNAL private/Internal.h private/SHMProcess.h private/LinuxProcess.h - private/WindowsProcess.h private/ProcessFactory.h + private/MicrosoftSTL.h ) SET(PROJECT_HDRS @@ -94,6 +94,7 @@ DFTileTypes.cpp DFProcessEnumerator.cpp ContextShared.cpp DFProcess-SHM.cpp +MicrosoftSTL.cpp depends/md5/md5.cpp depends/md5/md5wrapper.cpp diff --git a/library/DFProcess-linux-wine.cpp b/library/DFProcess-linux-wine.cpp index a75b8077d..7f28f8d9e 100644 --- a/library/DFProcess-linux-wine.cpp +++ b/library/DFProcess-linux-wine.cpp @@ -24,6 +24,7 @@ distribution. #include "Internal.h" #include "LinuxProcess.h" #include "ProcessFactory.h" +#include "MicrosoftSTL.h" #include "dfhack/VersionInfo.h" #include "dfhack/DFError.h" #include @@ -35,9 +36,7 @@ namespace { class WineProcess : public LinuxProcessBase { private: - uint32_t STLSTR_buf_off; - uint32_t STLSTR_size_off; - uint32_t STLSTR_cap_off; + MicrosoftSTL stl; public: WineProcess(uint32_t pid, std::vector & known_versions); @@ -133,10 +132,7 @@ bool WineProcess::validate(char * exe_file,uint32_t pid, char * memFile, vector memFile = memFile; identified = true; - OffsetGroup * strGrp = my_descriptor->getGroup("string")->getGroup("MSVC"); - STLSTR_buf_off = strGrp->getOffset("buffer"); - STLSTR_size_off = strGrp->getOffset("size"); - STLSTR_cap_off = strGrp->getOffset("capacity"); + stl.init(this); return true; } } @@ -152,57 +148,15 @@ bool WineProcess::validate(char * exe_file,uint32_t pid, char * memFile, vector size_t WineProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) { - uint32_t start_offset = offset + STLSTR_buf_off; - size_t length = Process::readDWord(offset + STLSTR_size_off); - size_t capacity = Process::readDWord(offset + 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) - { - read(start_offset, read_real , (uint8_t *)buffer); - } - else // read data from what the offset + 4 dword points to - { - start_offset = Process::readDWord(start_offset);// dereference the start offset - read(start_offset, read_real, (uint8_t *)buffer); - } - - buffer[read_real] = 0; - return read_real; + return stl.readSTLString(offset, buffer, bufcapacity); } const string WineProcess::readSTLString (uint32_t offset) { - uint32_t start_offset = offset + STLSTR_buf_off; - size_t length = Process::readDWord(offset + STLSTR_size_off); - size_t capacity = Process::readDWord(offset + STLSTR_cap_off); - - char * temp = new char[capacity+1]; - - // read data from inside the string structure - if(capacity < 16) - { - read(start_offset, capacity, (uint8_t *)temp); - } - else // read data from what the offset + 4 dword points to - { - start_offset = Process::readDWord(start_offset);// dereference the start offset - read(start_offset, capacity, (uint8_t *)temp); - } - - temp[length] = 0; - string ret = temp; - delete temp; - return ret; + return stl.readSTLString(offset); } string WineProcess::readClassName (uint32_t vptr) { - int rtti = Process::readDWord(vptr - 0x4); - int typeinfo = Process::readDWord(rtti + 0xC); - string raw = readCString(typeinfo + 0xC); // skips the .?AV - raw.resize(raw.length() - 2);// trim @@ from end - return raw; + stl.readClassName(vptr); } diff --git a/library/DFProcess-windows.cpp b/library/DFProcess-windows.cpp index a094e1e0f..da0055709 100644 --- a/library/DFProcess-windows.cpp +++ b/library/DFProcess-windows.cpp @@ -24,6 +24,7 @@ distribution. #include "Internal.h" #include "WindowsProcess.h" #include "ProcessFactory.h" +#include "MicrosoftSTL.h" #include "dfhack/VersionInfo.h" #include "dfhack/DFError.h" #include @@ -42,12 +43,10 @@ namespace bool attached; bool suspended; bool identified; - uint32_t STLSTR_buf_off; - uint32_t STLSTR_size_off; - uint32_t STLSTR_cap_off; IMAGE_NT_HEADERS pe_header; IMAGE_SECTION_HEADER * sections; uint32_t base; + MicrosoftSTL stl; public: NormalProcess(uint32_t pid, std::vector & known_versions); ~NormalProcess(); @@ -194,10 +193,7 @@ NormalProcess::NormalProcess(uint32_t pid, vector & known_versio vector threads; getThreadIDs( threads ); my_main_thread = OpenThread(THREAD_ALL_ACCESS, FALSE, (DWORD) threads[0]); - OffsetGroup * strGrp = my_descriptor->getGroup("string")->getGroup("MSVC"); - STLSTR_buf_off = strGrp->getOffset("buffer"); - STLSTR_size_off = strGrp->getOffset("size"); - STLSTR_cap_off = strGrp->getOffset("capacity"); + stl.init(this); found = true; break; // break the iterator loop } @@ -552,59 +548,17 @@ const string NormalProcess::readCString (const uint32_t offset) size_t NormalProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) { - uint32_t start_offset = offset + STLSTR_buf_off; - size_t length = Process::readDWord(offset + STLSTR_size_off); - size_t capacity = Process::readDWord(offset + 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) - { - read(start_offset, read_real , (uint8_t *)buffer); - } - else // read data from what the offset + 4 dword points to - { - start_offset = Process::readDWord(start_offset);// dereference the start offset - read(start_offset, read_real, (uint8_t *)buffer); - } - - buffer[read_real] = 0; - return read_real; + return stl.readSTLString(offset, buffer, bufcapacity); } const string NormalProcess::readSTLString (uint32_t offset) { - uint32_t start_offset = offset + STLSTR_buf_off; - size_t length = Process::readDWord(offset + STLSTR_size_off); - size_t capacity = Process::readDWord(offset + STLSTR_cap_off); - - char * temp = new char[capacity+1]; - - // read data from inside the string structure - if(capacity < 16) - { - read(start_offset, capacity, (uint8_t *)temp); - } - else // read data from what the offset + 4 dword points to - { - start_offset = Process::readDWord(start_offset);// dereference the start offset - read(start_offset, capacity, (uint8_t *)temp); - } - - temp[length] = 0; - string ret = temp; - delete temp; - return ret; + return stl.readSTLString(offset); } string NormalProcess::readClassName (uint32_t vptr) { - int rtti = Process::readDWord(vptr - 0x4); - int typeinfo = Process::readDWord(rtti + 0xC); - string raw = readCString(typeinfo + 0xC); // skips the .?AV - raw.resize(raw.length() - 2);// trim @@ from end - return raw; + stl.readClassName(vptr); } string NormalProcess::getPath() diff --git a/library/MicrosoftSTL.cpp b/library/MicrosoftSTL.cpp new file mode 100644 index 000000000..9d619600e --- /dev/null +++ b/library/MicrosoftSTL.cpp @@ -0,0 +1,96 @@ +/* +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 "MicrosoftSTL.h" +#include "dfhack/DFProcess.h" +#include "dfhack/VersionInfo.h" +#include +using namespace DFHack; + +void MicrosoftSTL::init(Process* self) +{ + p = self; + OffsetGroup * strGrp = p->getDescriptor()->getGroup("string")->getGroup("MSVC"); + STLSTR_buf_off = strGrp->getOffset("buffer"); + STLSTR_size_off = strGrp->getOffset("size"); + STLSTR_cap_off = strGrp->getOffset("capacity"); +} + +size_t MicrosoftSTL::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) +{ + uint32_t start_offset = offset + STLSTR_buf_off; + size_t length = p->readDWord(offset + STLSTR_size_off); + size_t capacity = p->readDWord(offset + 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) + { + p->read(start_offset, read_real , (uint8_t *)buffer); + } + else // read data from what the offset + 4 dword points to + { + start_offset = p->readDWord(start_offset);// dereference the start offset + p->read(start_offset, read_real, (uint8_t *)buffer); + } + + buffer[read_real] = 0; + return read_real; +} + +const string MicrosoftSTL::readSTLString (uint32_t offset) +{ + uint32_t start_offset = offset + STLSTR_buf_off; + size_t length = p->readDWord(offset + STLSTR_size_off); + size_t capacity = p->readDWord(offset + STLSTR_cap_off); + + char * temp = new char[capacity+1]; + + // read data from inside the string structure + if(capacity < 16) + { + p->read(start_offset, capacity, (uint8_t *)temp); + } + else // read data from what the offset + 4 dword points to + { + start_offset = p->readDWord(start_offset);// dereference the start offset + p->read(start_offset, capacity, (uint8_t *)temp); + } + + temp[length] = 0; + string ret = temp; + delete temp; + return ret; +} + +string MicrosoftSTL::readClassName (uint32_t vptr) +{ + int rtti = p->readDWord(vptr - 0x4); + int typeinfo = p->readDWord(rtti + 0xC); + string raw = p->readCString(typeinfo + 0xC); // skips the .?AV + raw.resize(raw.length() - 2);// trim @@ from end + return raw; +} diff --git a/library/private/MicrosoftSTL.h b/library/private/MicrosoftSTL.h new file mode 100644 index 000000000..a25ee1797 --- /dev/null +++ b/library/private/MicrosoftSTL.h @@ -0,0 +1,46 @@ +/* +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 + +namespace DFHack { + class Process; + class MicrosoftSTL + { + private: + uint32_t STLSTR_buf_off; + uint32_t STLSTR_size_off; + uint32_t STLSTR_cap_off; + + Process* p; + public: + void init(Process* p); + + const std::string readSTLString (uint32_t offset); + size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity); + void writeSTLString(const uint32_t address, const std::string writeString){}; + // get class name of an object with rtti/type info + std::string readClassName(uint32_t vptr); + }; +} From 62bec260b17493d9bb8c968af58d50fd8b009cca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Wed, 23 Feb 2011 21:57:36 +0100 Subject: [PATCH 93/94] Fix 32bit linux build again. --- library/DFProcess-linux-base.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/DFProcess-linux-base.cpp b/library/DFProcess-linux-base.cpp index 7549c1387..f704d384e 100644 --- a/library/DFProcess-linux-base.cpp +++ b/library/DFProcess-linux-base.cpp @@ -337,7 +337,7 @@ void LinuxProcessBase::writeWord (uint32_t offset, uint16_t data) orig |= data; ptrace(PTRACE_POKEDATA,my_pid, offset, orig); #else - uint32_t orig = readDWord(offset); + uint32_t orig = Process::readDWord(offset); orig &= 0xFFFF0000; orig |= data; ptrace(PTRACE_POKEDATA,my_pid, offset, orig); @@ -352,7 +352,7 @@ void LinuxProcessBase::writeByte (uint32_t offset, uint8_t data) orig |= data; ptrace(PTRACE_POKEDATA,my_pid, offset, orig); #else - uint32_t orig = readDWord(offset); + uint32_t orig = Process::readDWord(offset); orig &= 0xFFFFFF00; orig |= data; ptrace(PTRACE_POKEDATA,my_pid, offset, orig); From 79b78673e569051574403d335e41c467a4d2d7a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Thu, 24 Feb 2011 01:32:15 +0100 Subject: [PATCH 94/94] Fix build on MSVC --- library/DFProcess-windows-SHM.cpp | 17 ++--------------- library/DFProcess-windows.cpp | 4 +--- library/private/SHMProcess.h | 3 ++- 3 files changed, 5 insertions(+), 19 deletions(-) diff --git a/library/DFProcess-windows-SHM.cpp b/library/DFProcess-windows-SHM.cpp index 7966cf58c..37d74697a 100644 --- a/library/DFProcess-windows-SHM.cpp +++ b/library/DFProcess-windows-SHM.cpp @@ -307,21 +307,8 @@ bool SHMProcess::getThreadIDs(vector & threads ) //FIXME: use VirtualQuery to probe for memory ranges, cross-reference with base-corrected PE segment entries 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. - temp.end = base + Process::readDWord(base+readDWord(base+0x3C)+0x50)-1; // yay for magic. - temp.read = 1; - temp.write = 1; - temp.execute = 0; // fake - temp.valid = true; - strcpy(temp.name,"pants"); - ranges.push_back(temp); + // BLAH + ranges.clear(); } bool SHMProcess::acquireSuspendLock() diff --git a/library/DFProcess-windows.cpp b/library/DFProcess-windows.cpp index da0055709..9f637e944 100644 --- a/library/DFProcess-windows.cpp +++ b/library/DFProcess-windows.cpp @@ -22,7 +22,6 @@ must not be misrepresented as being the original software. distribution. */ #include "Internal.h" -#include "WindowsProcess.h" #include "ProcessFactory.h" #include "MicrosoftSTL.h" #include "dfhack/VersionInfo.h" @@ -225,7 +224,6 @@ NormalProcess::~NormalProcess() } if(sections != NULL) free(sections); - delete d; } VersionInfo * NormalProcess::getDescriptor() @@ -558,7 +556,7 @@ const string NormalProcess::readSTLString (uint32_t offset) string NormalProcess::readClassName (uint32_t vptr) { - stl.readClassName(vptr); + return stl.readClassName(vptr); } string NormalProcess::getPath() diff --git a/library/private/SHMProcess.h b/library/private/SHMProcess.h index 5fb704b07..3f8a8f75c 100644 --- a/library/private/SHMProcess.h +++ b/library/private/SHMProcess.h @@ -26,6 +26,7 @@ distribution. #define SHM_PROCESS_H_INCLUDED #include "dfhack/DFProcess.h" +#include "dfhack/DFIntegers.h" namespace DFHack { @@ -113,7 +114,7 @@ namespace DFHack int client_lock; int suspend_lock; #else - typedef unit32_t pid_t; + typedef uint32_t pid_t; uint32_t process_ID; HANDLE DFSVMutex; HANDLE DFCLMutex;