From 33131754d475845a4a8a5d2767b5ec9c9150d5ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Wed, 31 Mar 2010 17:31:49 +0200 Subject: [PATCH 01/29] Prospector detects regionoffsets overflows. --- output/stones.py | 9 ++++----- tools/prospector.cpp | 21 ++++++++++++++++++++- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/output/stones.py b/output/stones.py index 5feb53210..de90f8e7e 100644 --- a/output/stones.py +++ b/output/stones.py @@ -1,12 +1,11 @@ # -*- coding: utf-8 -*- import pydfhack -x = pydfhack.API("Memory.xml") -y = pydfhack.MatglossVector() +DF = pydfhack.API("Memory.xml") -if x.Attach(): - success,stones = x.ReadStoneMatgloss() +if DF.Attach(): + success,stones = DF.ReadStoneMatgloss() if success: print "Dumping all stone" for matgloss in stones: print "ID %s, name %s" % (matgloss.id, matgloss.name) - x.Detach() + DF.Detach() diff --git a/tools/prospector.cpp b/tools/prospector.cpp index d07a7ae23..5cd8acfbf 100644 --- a/tools/prospector.cpp +++ b/tools/prospector.cpp @@ -13,6 +13,7 @@ #include #include #include +#include using namespace std; #include @@ -103,6 +104,8 @@ int main (int argc, const char* argv[]) int16_t tempvein [16][16]; vector veins; vector iceveins; + uint32_t maximum_regionoffset = 0; + uint32_t num_overflows = 0; // walk the map! for(uint32_t x = 0; x< x_max;x++) { @@ -129,9 +132,17 @@ int main (int argc, const char* argv[]) { for (uint32_t yy = 0; yy< 16;yy++) { + uint8_t test = designations[xx][yy].bits.biome; + if(test > maximum_regionoffset) + maximum_regionoffset = test; + if( test >= sizeof(regionoffsets)) + { + num_overflows++; + continue; + } tempvein[xx][yy] = layerassign - [regionoffsets[designations[xx][yy].bits.biome]] + [regionoffsets[test]] [designations[xx][yy].bits.geolayer_index]; } } @@ -182,6 +193,14 @@ int main (int argc, const char* argv[]) } } // print report + cout << "Maximal regionoffset seen: " << maximum_regionoffset << "."; + if(maximum_regionoffset >= sizeof(regionoffsets) ) + { + cout << " This is above the regionoffsets array size!" << endl; + cout << "Number of overflows: " << num_overflows; + } + cout << endl; + map::iterator p; for(p = materials.begin(); p != materials.end(); p++) { From 35960db5aadf8f154cc39a211e393231569e9859 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Wed, 31 Mar 2010 18:16:18 +0200 Subject: [PATCH 02/29] Fix for out-of-bounds access error with regionoffsets. Breaks compatibility. --- library/DFHackAPI.cpp | 16 ++++++++-------- library/DFTypes.h | 2 +- shmserver/mod-maps.h | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/library/DFHackAPI.cpp b/library/DFHackAPI.cpp index fbd659f3c..07a53f32e 100644 --- a/library/DFHackAPI.cpp +++ b/library/DFHackAPI.cpp @@ -220,7 +220,7 @@ bool API::InitMap() /* * --> SHM initialization (if possible) <-- */ - g_pProcess->getModuleIndex("Maps",2,d->maps_module); + g_pProcess->getModuleIndex("Maps",3,d->maps_module); if(d->maps_module) { @@ -351,7 +351,7 @@ bool API::ReadTileTypes (uint32_t x, uint32_t y, uint32_t z, tiletypes40d *buffe uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if (addr) { - g_pProcess->read (addr + d->tile_type_offset, 256 * sizeof (uint16_t), (uint8_t *) buffer); + g_pProcess->read (addr + d->tile_type_offset, sizeof (tiletypes40d), (uint8_t *) buffer); return true; } return false; @@ -413,7 +413,7 @@ bool API::ReadDesignations (uint32_t x, uint32_t y, uint32_t z, designations40d uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if (addr) { - g_pProcess->read (addr + d->designation_offset, 256 * sizeof (uint32_t), (uint8_t *) buffer); + g_pProcess->read (addr + d->designation_offset, sizeof (designations40d), (uint8_t *) buffer); return true; } return false; @@ -426,7 +426,7 @@ bool API::ReadOccupancy (uint32_t x, uint32_t y, uint32_t z, occupancies40d *buf uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if (addr) { - g_pProcess->read (addr + d->occupancy_offset, 256 * sizeof (uint32_t), (uint8_t *) buffer); + g_pProcess->read (addr + d->occupancy_offset, sizeof (occupancies40d), (uint8_t *) buffer); return true; } return false; @@ -439,7 +439,7 @@ bool API::WriteTileTypes (uint32_t x, uint32_t y, uint32_t z, tiletypes40d *buff uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if (addr) { - g_pProcess->write (addr + d->tile_type_offset, 256 * sizeof (uint16_t), (uint8_t *) buffer); + g_pProcess->write (addr + d->tile_type_offset, sizeof (tiletypes40d), (uint8_t *) buffer); return true; } return false; @@ -457,7 +457,7 @@ bool API::WriteDesignations (uint32_t x, uint32_t y, uint32_t z, designations40d uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if (addr) { - g_pProcess->write (addr + d->designation_offset, 256 * sizeof (uint32_t), (uint8_t *) buffer); + g_pProcess->write (addr + d->designation_offset, sizeof (designations40d), (uint8_t *) buffer); return true; } return false; @@ -469,7 +469,7 @@ bool API::WriteOccupancy (uint32_t x, uint32_t y, uint32_t z, occupancies40d *bu uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if (addr) { - g_pProcess->write (addr + d->occupancy_offset, 256 * sizeof (uint32_t), (uint8_t *) buffer); + g_pProcess->write (addr + d->occupancy_offset, sizeof (occupancies40d), (uint8_t *) buffer); return true; } return false; @@ -483,7 +483,7 @@ bool API::ReadRegionOffsets (uint32_t x, uint32_t y, uint32_t z, biome_indices40 uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if (addr) { - g_pProcess->read (addr + d->biome_stuffs, 16 * sizeof (uint8_t), (uint8_t *) buffer); + g_pProcess->read (addr + d->biome_stuffs, sizeof (biome_indices40d), (uint8_t *) buffer); return true; } return false; diff --git a/library/DFTypes.h b/library/DFTypes.h index 5ef92670c..40b5c57cc 100644 --- a/library/DFTypes.h +++ b/library/DFTypes.h @@ -853,7 +853,7 @@ union t_blockflags typedef int16_t tiletypes40d [16][16]; typedef DFHack::t_designation designations40d [16][16]; typedef DFHack::t_occupancy occupancies40d [16][16]; -typedef uint8_t biome_indices40d [8]; +typedef uint8_t biome_indices40d [16]; typedef struct { diff --git a/shmserver/mod-maps.h b/shmserver/mod-maps.h index af6b8f48e..bd1ad94a9 100644 --- a/shmserver/mod-maps.h +++ b/shmserver/mod-maps.h @@ -33,7 +33,7 @@ namespace DFHack namespace Maps { -#define MAPS_VERSION 2 +#define MAPS_VERSION 3 typedef struct { uint32_t map_offset;// = d->offset_descriptor->getAddress ("map_data"); From d540f4cbd76d1838b44c46bea67c655a5ab9cbdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Wed, 31 Mar 2010 18:59:03 +0200 Subject: [PATCH 03/29] Update precompiled libs --- precompiled/linux/libdfconnect.so | Bin 186846 -> 40483 bytes precompiled/windows/SDL.dll | Bin 32768 -> 34304 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/precompiled/linux/libdfconnect.so b/precompiled/linux/libdfconnect.so index 98aaad1d0786878cb82e0349073d851517bbb2dd..633f5c5e50b67b62d44d3586925e7e7e6895f444 100755 GIT binary patch literal 40483 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

5lcL)qlXoxj*h%Z>c1Fqit`GHphAWs$bfTL#=p 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 Q^|c6DV%D+cn^WZf1I=`mEdT%j delta 11459 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 Z)HE|$Ofgf-Y-j2jym3lX<6zzOe*tEB4W$48 From 8137c73b983d3c9e9bbb7bc6309c42a6ce5203a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Fri, 2 Apr 2010 15:47:08 +0200 Subject: [PATCH 04/29] Beginning DF2010 support --- examples/CMakeLists.txt | 4 +- examples/creaturedump.cpp | 2 +- examples/veccheck.cpp | 69 +++++++++++++++++++++++-------- examples/veinlook.cpp | 6 ++- output/Memory.xml | 86 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 145 insertions(+), 22 deletions(-) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 71a8d6bb8..2e3be5a4b 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -54,8 +54,8 @@ ADD_EXECUTABLE(dfsettlementdump settlementdump.cpp) TARGET_LINK_LIBRARIES(dfsettlementdump dfhack) # veccheck - read vector values at address -#ADD_EXECUTABLE(dfvecc veccheck.cpp) -#TARGET_LINK_LIBRARIES(dfvecc dfhack) +ADD_EXECUTABLE(dfvecc veccheck.cpp) +TARGET_LINK_LIBRARIES(dfvecc dfhack) # catsplosion - Makes every cat pregnant, and almost due... # Author: Zhentar diff --git a/examples/creaturedump.cpp b/examples/creaturedump.cpp index ebeaccd3c..125f802dc 100644 --- a/examples/creaturedump.cpp +++ b/examples/creaturedump.cpp @@ -355,7 +355,7 @@ int main (void) { DFHack::t_creature temp; DF.ReadCreature(i,temp); - if(string(creaturestypes[temp.type].id) == "DWARF") + //if(string(creaturestypes[temp.type].id) == "DWARF") { cout << "index " << i << " "; printCreature(DF,temp); diff --git a/examples/veccheck.cpp b/examples/veccheck.cpp index 06244e793..66c6431c5 100644 --- a/examples/veccheck.cpp +++ b/examples/veccheck.cpp @@ -12,6 +12,31 @@ using namespace std; #include #include #include +#include + +void DumpObjStr0Vector (const char * name, DFHack::Process *p, uint32_t addr) +{ + cout << "----==== " << name << " ====----" << endl; + DFHack::DfVector vect(p,addr,4); + for(int i = 0; i < vect.getSize();i++) + { + uint32_t addr = *(uint32_t *) vect[i]; + cout << p->readSTLString(addr) << endl; + } + cout << endl; +} + +void DumpDWordVector (const char * name, DFHack::Process *p, uint32_t addr) +{ + cout << "----==== " << name << " ====----" << endl; + DFHack::DfVector vect(p,addr,4); + for(int i = 0; i < vect.getSize();i++) + { + uint32_t number = *(uint32_t *) vect[i]; + cout << number << endl; + } + cout << endl; +} int main (int numargs, const char ** args) { @@ -37,23 +62,33 @@ int main (int numargs, const char ** args) DFHack::Process* p = DF.getProcess(); DFHack::memory_info* mem = DF.getMemoryInfo(); - const vector * names = mem->getClassIDMapping(); - for(int i = 0; i < names->size();i++) - { - cout << i << " " << names->at(i) << endl; - } - /* - #ifdef LINUX_BUILD - cout << "start 0x" << hex << p->readDWord(addr+0x0) << endl; - cout << "end 0x" << hex << p->readDWord(addr+0x4) << endl; - cout << "cap 0x" << hex << p->readDWord(addr+0x8) << endl; - #else - cout << "start 0x" << hex << p->readDWord(addr+0x4) << endl; - cout << "end 0x" << hex << p->readDWord(addr+0x8) << endl; - cout << "cap 0x" << hex << p->readDWord(addr+0xC) << endl; - #endif - */ - + //const vector * names = mem->getClassIDMapping(); + + DumpObjStr0Vector("Inorganics",p,0x16afd04); + + DumpObjStr0Vector("Organics - all",p,0x16afd1C); + + DumpObjStr0Vector("Organics - filtered",p,0x16afd34); + + DumpDWordVector("Some weird numbers",p,0x16afd4C); + + DumpObjStr0Vector("Trees/wood",p,0x16afd64); + + DumpDWordVector("More weird numbers",p,0x16afd7C); + + DumpObjStr0Vector("WTF",p,0x16afd7C + 0x18 ); + + DumpObjStr0Vector("WTF2",p,0x16afd7C + 0x18 + 0x18); + + DumpObjStr0Vector("WTF3",p,0x16afd7C + 0x18 + 0x18 + 0x18 ); + + DumpObjStr0Vector("WTF4",p,0x16afd7C + 0x18 + 0x18 + 0x18 + 0x18); + + DumpObjStr0Vector("WTF5",p,0x16afd7C + 0x18 + 0x18 + 0x18 + 0x18 + 0x18); + + DumpObjStr0Vector("Creature types",p,0x16afd7C + 0x18 + 0x18 + 0x18 + 0x18 + 0x18 + 0x18); + + #ifndef LINUX_BUILD cout << "Done. Press any key to continue" << endl; cin.ignore(); diff --git a/examples/veinlook.cpp b/examples/veinlook.cpp index c39dc2b65..32980fa40 100644 --- a/examples/veinlook.cpp +++ b/examples/veinlook.cpp @@ -507,7 +507,7 @@ main(int argc, char *argv[]) { int color = COLOR_BLACK; color = pickColor(Block->tiletypes[x][y]); - if(!Block->designation[x][y].bits.hidden) + //if(!Block->designation[x][y].bits.hidden) /*{ puttile(x+(i+1)*16,y+(j+1)*16,Block->tiletypes[x][y], color); } @@ -524,7 +524,7 @@ main(int argc, char *argv[]) { for(uint zz = 0; zz < effects.size();zz++) { - if(effects[zz].z == cursorZ && !effects[zz].isHidden) + if(effects[zz].z == cursorZ /*&& !effects[zz].isHidden*/) { // block coords to tile coords uint16_t x = effects[zz].x - (cursorX * 16); @@ -564,8 +564,10 @@ main(int argc, char *argv[]) { if(tileTypeTable[blocks[1][1].tiletypes[k][j]].m != VEIN) continue; + /* if(blocks[1][1].designation[k][j].bits.hidden) continue; + */ // and the bit array with a one-bit mask, check if the bit is set bool set = !!(((1 << k) & veinVector[realvein].assignment[j]) >> k); if(set) diff --git a/output/Memory.xml b/output/Memory.xml index 6675cceb7..abcef55fd 100644 --- a/output/Memory.xml +++ b/output/Memory.xml @@ -1986,5 +1986,91 @@
0x09048d18
+ + 851c1190b6a7b42f2463967623d18575 + 0x4BB45F99 + + + 0x0 + 0xC + + +
0xe32798
+
0xe60838
+
0xe60814
+
0xae82cc
+ +
0x17f5ab8
+ Found addresses: (next to each other!) + 0x17f5ab8 + 0x17f5ac0 + 0x17f5ac8 + 0x17f5ad0 + +
0x146e45f
+ Found addresses: + 0x146e45f + 0x185b677 + +
0xae82cc bogus
+
0xae82cc bogus
+
0xae82cc bogus
+ + + +
0x016ad738
+
0x016ad73C
+
0x016ad740
+ +
0x016ad744
+
0x016ad748
+
0x016ad74C
+ +
0x016ad750
+
0x016ad754
+
0x016ad758
+ +
0x016AD718
+ 0x10 + 0x0092 + 0x029C + + +
From c503808a822cf3f1d5ab7d994f0402ac69ead642 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Fri, 2 Apr 2010 15:59:17 +0200 Subject: [PATCH 05/29] Offsets from belal --- output/Memory.xml | 44 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/output/Memory.xml b/output/Memory.xml index abcef55fd..8cc7534d5 100644 --- a/output/Memory.xml +++ b/output/Memory.xml @@ -2012,9 +2012,11 @@ 0x146e45f 0x185b677 -
0xae82cc bogus
-
0xae82cc bogus
-
0xae82cc bogus
+ Bogus:
0xae82cc
+ +
0x017f6f38
+ + Bogus:
0xae82cc
@@ -2035,10 +2037,44 @@ 0x0092 0x029C + + + 0x18 0x0 0xC + 0x1C
0xe32798
@@ -2036,6 +2038,21 @@ 0x10 0x0092 0x029C + + + 0x0 + 0x1C + 0x38 + + + 0x0 + 0x90 + 0xF8 + 0xFC + 0x110 + 0x114 + 0x6D0 + 0x770 + + + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 30 + 31 + 32 + 33 + 34 + 35 + 36 + 37 + 38 + 39 + 40 + 41 + 42 + 43 + 44 + 45 + 46 + 47 + 48 + 49 + 50 + 51 + 52 + 53 + 54 + 55 + 56 + 57 + 58 + 59 + 60 + 61 + 62 + 63 + 64 + 65 + 66 + 67 + 68 + 69 + 70 + 71 + 72 + 73 + 74 + 75 + 76 + 77 + 78 + 79 + 80 + 81 + 82 + 83 + 84 + 85 + 86 + 87 + 88 + 89 + 90 + 91 + 92 + 93 + 94 + 95 + 96 + 97 + 98 + 99 + 100 + 101 + 102 + 103 + 104 + 105 + 106 + 107 + 108 + 109 + 110 + 111 + 112 + 113 + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 30 + 31 + 32 + 33 + 34 + 35 + 36 + 37 + 38 + 39 + 40 + 41 + 42 + 43 + 44 + 45 + 46 + 47 + 48 + 49 + 50 + 51 + 52 + 53 + 54 + 55 + 56 + 57 + 58 + 59 + 60 + 61 + 62 + 63 + 64 + 65 + 66 + 67 + 68 + 69 + 70 + 71 + 72 + 73 + 74 + 75 + 76 + 77 + 78 + 79 + 80 + 81 + 82 + 83 + 84 + 85 + 86 + 87 + 88 + 89 + 90 + 91 + 92 + 93 + 94 + 95 + 96 + 97 + 98 + 99 + 100 + 101 + 102 + 103 + 104 + 105 + 106 + 107 + 108 + 109 + 110 + 111 + 112 + 113 + 114 + 115 + 116 + 117 + 118 + 119 + 120 + 121 + 122 + 123 + 124 + 125 + 126 + 127 + 128 + 129 + 130 + 131 + 132 + 133 + 134 + 135 + 136 + 137 + 138 + 139 + 140 + 141 + 142 + 143 + 144 + 145 + 146 + 147 + 148 + 149 + 150 + 151 + 152 + 153 + 154 + 155 + 156 + 157 + 158 + 159 + 160 + 161 + 162 + 163 + 164 + 165 + 166 + 167 + 168 + 169 + 170 + 171 + 172 + 173 + 174 + 175 + 176 + 177 + 178 + 179 + 180 + 181 + 182 + 183 + 184 + 185 + 186 + 187 + 188 + 189 + 190 + 191 + 192 + 193 + 194 + 195 + 196 + 197 + 198 + 199 + 200 + 201 + 202 + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 30 + 31 + 32 + 33 + 34 + 35 + 36 + 37 + 38 + 39 + 40 + 41 + 42 + 43 + 44 + 45 + 46 + 47 + 48 + 49 + 50 + 51 + 52 + 53 + 54 + 55 + 56 + 57 + 58 + 59 + 60 + 61 + 62 + 63 + 64 + 65 + 66 + 67 + 68 + 69 + 70 + 71 + 72 + 73 + 74 + 75 + 76 + 77 + 78 + 79 + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 0 + 66 + 11 + 10 + 13 + 12 + 14 + 15 + 16 + 20 + 38 + 19 + 41 + 39 + 43 + 42 + 40 + 44 + 45 + 48 + 27 + 49 + 21 + 47 + 26 + 46 + 50 + 23 + 18 + 30 + 32 + 71 + 33 + 34 + 70 + 31 + 28 + 69 + 25 + 22 + 29 + 72 + 35 + 36 + 37 + 67 + 73 + 64 + 65 + 17 + 8 + 2 + 6 + 4 + 1 + 5 + 7 + 9 + 3 + 24 + 51 + 52 + 53 + 54 + 55 + 57 + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + .,:rsr, + :2;,;r2A@@5 + @2::s5A#@@@ @r. . + sd;:riXA#@@ :@@@Gir;;AS9 + Bs::sS3A#@2 @@#AhXirsS#; + iHrLr5d#@@@ .@#95sr;;rie + i*' `*@3 @@A2sr;:;r#5 + :..:rll: @@A5sr::r3@ + @Hr;iZ#@@@@ `:rr;;;;: + S@r.;i2#@@@ @s. .. + @2::ri2A@@# B@G2ir:...5i + :@r,r3X##@@ @G5sr:..,:A + .@Ar;;rSB@@# H#2sr;,..,is + .' `* ,@ASs;:..,:B + ;rr;:,..,:. + `''' + W I N D O W S + and + W I N E + + + 0x47b6fac2 + 48c831b6f3950913b8e1aeada563d2db + 0x0 + 0x4 +
0x014639f4
+
0x01463288
+
0x01463388
+
0x00c7bc00
+
0x01287d14
+
0x00941288
+
0x01287a9c
+
0x01463358
+
0x014a6994
+
0x014a4eac
+
0x014a6834
+
0xffffffff
+
0x8b010127
+
0x014a4edc
+
0x014a4ee0
+
0x014a4ee4
+
0x014a6680
+
0x014a671c
+
0x014a69b4
+
0x01467b78
+
0x01295d58
+
0x01284184
+
0x00941288
+
0x00c2358c
+
0x00c68350
+
0x014a64dc
+
0x014a4ec4
+
0x014a4ec8
+
0x014a4ecc
+ + 0x08 + + 0x08 + 0x2C + 0x0062 + 0x0264 + 0x0664 + 0x1D64 + + 0x0 + 0x1C + 0x38 + 0x1C + + 0x00 + 0x6c + 0x88 + 0x8C + 0x94 + 0xE4 + 0xE8 + 0xF2 + 0xF4 + 0x158 + 0x1F8 + 0x1FC + 0x228 + 0x2F8 + 0x2AC + 0x328 + 0x32C + 0x330 + 0x3CC + 0x438 + 0x43C + 0x440 + 0x444 + 0x454 + 0x474 + 0x520 + 0x5D0 + + 0x70 + + 0x84 + 0x86 + 0x684 + 0x6B4 + + 0x5C + 0x58 + + 0x4 + + 0x10 + + 0x84 + 0x60 + 0x08 + 0x2C + 0x0062 + 0x0264 + 0x0664 + 0x1D64 + 0x3C + 0x2 + 0x4 + 0x8 + 0x24 + 0x1C + 0x20 + 0x00 + 0x7a + 0xD8 + 0x68 + 0x24 + 0x1C + 0x28 + 0x24 + 0x24 + 0x24 + 0x5C + 0x94 + 0xB0 +
+ + 0x47c12f36 + 8bd90fb6db8388f129fde224a35459de +
0x01463bec
+
0x01463480
+
0x01463580
+
0x00c7bc04
+
0x01287d14
+
0x0094128c
+
0x01287a9c
+
0x01463550
+
0x014a6c60
+
0x014a50a4
+
0x014a6b00
+
0xffffffff
+
0x8b010127
+
0x014a50d4
+
0x014a50d8
+
0x014a50dc
+
0x014a694c
+
0x014a69e8
+
0x014a6c80
+
0x01467d70
+
0x01295d58
+
0x01284184
+
0x00c3fb40
+
0x00c23594
+
0x00c68354
+
0x014a66d4
+
0x014a50bc
+
0x014a50c0
+
0x014a50c4
+
+ + 0x47c29583 + 9147b5e922a30873fd1a742b1dea1724 +
0xffffffff
+
0x8b010127
+
+ + 0x487b4e8b + 4b3857a05590b9d9488900e575079e9d +
0x01512b70
+
0x014feb80
+
0x01512504
+
0x00d16c20
+
0x01322d58
+
0x009d6284
+
0x01322adc
+
0x014fec50
+
0x01555f88
+
0x01554028
+
0x01555e28
+
0xffffffff
+
0x8b010131
+
0x01554058
+
0x0155405c
+
0x01554060
+
0x01555ce8
+
0x01555c6c
+
0x01555fa8
+
0x01516cf4
+
0x01330d98
+
0x0131f1b4
+
0x00cd5398
+
0x00cb8dec
+
0x00d03370
+
0x01555658
+
0x01554040
+
0x01554044
+
0x01554048
+
+ + 0x487c9338 + 52155dea390c2080fc16e4bbeb077164 +
0xffffffff
+
0x8b010131
+
+ + 0x487f2f30 + 8f8cf06b1cd5ea102881a7cced767d4f +
0x01513b90
+
0x014ffba0
+
0x01513524
+
0x00d17c44
+
0x01323d78
+
0x009d7284
+
0xffffffff
+ +
0x014ffc70
+
0x01556fa8
+
0x01555048
+
0x01556e48
+
0xffffffff
+ +
0x8b010131
+
0x01555078
+
0x0155507c
+
0x01555080
+
0x01556d08
+
0x01556c8c
+
0x01556fc8
+
0x01517d14
+
0x01331db8
+
0x013201d4
+
0x00cd63bc
+
0x00cb9dec
+
0x00d04394
+
0x01556678
+
0x01555060
+
0x01555064
+
0x01555068
+
+ + 0x48873bc3 + 8614a01593baef6e4a341e2f1a92ba06 +
0x0151ffb8
+
0x0150bfc8
+
0x0151f94c
+
0x00d23c4c
+
0x0132fdb0
+
0x009e3284
+
0x0132fb34
+
0x0150c098
+
0x015635cc
+
0x01561470
+
0x0156346c
+
0x0132faac
+
0x8b010131
+
0x015614a0
+
0x015614a4
+
0x015614a8
+
0x01563154
+
0x015630d8
+
0x015635ec
+
0x0152413c
+
0x0133ddf0
+
0x0132c1dc
+
0x00ce23c4
+
0x00cc5df4
+
0x00d1039c
+
0x01562aa0
+
0x01561488
+
0x0156148c
+
0x01561490
+
+ + 0x4888672c + 32f68422f5b4d938549eed0565bcfb92 + + + 0x489d8c7f + 33db0401081058fb54252210bf371344 +
0x01576468
+
0x01562478
+
0x01575dfc
+
0x00d7a0fc
+
0x01386260
+
0x009ef294
+
0x01385fe4
+
0x01562548
+
0x015b9a7c
+
0x015b7920
+
0x015b991c
+
0x01385f5c
+
0x5f010137
+
0x015b7950
+
0x015b7954
+
0x015b7958
+
0x015b9604
+
0x015b9588
+
0x015b9a9c
+
0x0157a5ec
+
0x013942a0
+
0x0138268c
+
0x00d387fc
+
0x00d66870
+
0x00d6684c
+
0x015b8f50
+
0x015b7938
+
0x015b793c
+
0x015b7940
+
+ + 0x48a9727f + 441c76f45cfffc6abc6548e41c7e2218 +
0x015828a8
+
0x0156e8b8
+
0x0158223c
+
0x00d860fc
+
0x01392268
+
0x009fb294
+
0x01391fc0
+
0x0156e988
+
0x015c5ecc
+
0x015c3d60
+
0x015c5d6c
+
0x01391f64
+
0x5f010138
+
0x015c3d90
+
0x015c3d94
+
0x015c3d98
+
0x015c5a54
+
0x015c59c8
+
0x015c5eec
+
0x01586a2c
+
0x013a02a8
+
0x0138e694
+
0x00d447fc
+
0x00d72870
+
0x00d7284c
+
0x015c5390
+
0x015c3d78
+
0x015c3d7c
+
0x015c3d80
+
+ + 0x48ad547a + 65b4fa339d4081e934c1297d2a22234a + + + 0x48ad802b + 15e95727019e76aa653538618c7e0cfd + + + 0x48c330df + 2c686c26307dcccd7c36cc79737ebe4f +
0x015838a0
+
0x0156f8b0
+
0x01583234
+
0x00D870F4
+
0x01393260
+
0x009fc294
+
0x1583234
+
0x01392fb8
+
0x0156f980
+
0x015c6ed0
+
0x015c4d58
+
0x015c6d70
+
0x01392f5c
+
0x0138147f
+
0x015c4d88
+
0x015c4d8c
+
0x015c4d90
+
0x015c6a58
+
0x015c69cc
+
0x015c6ef0
+
0x01587a24
+
0x013a12a0
+
0x0138f68c
+
0x00d457f4
+
0x00d73868
+
0x00d73844
+
0x015c6388
+
0x015c4d70
+
0x015c4d74
+
0x015c4d78
+
+ + + 0x4953556c + b1a8ca1f91734eb492b7f54f6823cddb + -0x8 + 0x4 +
0x014d1db0
+
0x014bda18
+
0x014D141C
+
0x00cd4c3c
+
0x0165b5a8
+
0x0094b27c
+
0x165b410
+
0x012e101c
+
0x014d14f8
+
0x01517678
+
0x015152f8
+
0x01517468
+
0x012e0fe4
+
0x012cefbf
+
0x01515330
+
0x01515334
+
0x01515338
+
0x015170f8
+
0x0151702c
+
0x015176a8
+
0x014d7f84
+
0x012ef340
+
0x0165a34c
+
0x00c9333c
+
0x00cc13b0
+
0x00cc138c
+
0x01516930
+
0x01515318
+
0x0151531c
+
0x01515320
+ 0x54 + + 0x0 + 0x1C + 0x38 + 0x1C + + + 0xFC + 0x100 + 0x10A + 0x10C + 0x198 + 0x238 + 0x23C + 0x268 + 0x2F8 + 0x314 + 0x3C0 + 0x3C4 + 0x3C8 + 0x484 + 0x4F0 + 0x4F4 + 0x4F8 + 0x504 + 0x51C + 0x544 + 0x610 + 0x700 + + 0x70 + + 0x10 + 0x2C + 0x0082 + 0x0284 + 0x0684 + 0x1D84 + 0x84 + 0x86 + 0x75C + 0x79C + + 0x64 + 0x60 + + 0xC + 0x2 + 0x4 + 0x8 + 0x24 + 0x1C + 0x20 + 0x2C + 0x0 + 0x7a + 0x100 + 0x68 + 0x24 + + 0x18 + 0x1C + 0x28 + 0x24 + 0x24 + 0x24 + 0x5C + 0x94 + 0xB0 + + + + + + + +
+ + 0x4957716f + 9b6da355562a4cdd345ea3046290499b +
0x00cd6c3c
+
0x0094d27c
+
0x012d0fbf
+
0x00c9533c
+
0x00cc33b0
+
0x00cc338c
+
+ + 0x4957a0a2 + b77759db7a6dd787bf98953fc5749d81 + + + 0x495991c3 + a0792b81e5b8ec1dbdd627643e93b40d +
0xcd8c34
+
0x0094f27c
+
0x012d2fbb
+
0x00c97334
+
0x00cc53a8
+
0x00cc5384
+
+ + 0x495cafd2 + d09e88a32fe57de5973f78ef213271b6 +
0xcefc68
+
0x009662a4
+
0x012e9fef
+
0x00cae368
+
0x00cdc3dc
+
0x00cdc3b8
+
+ + 0x495fcfef + 8e8e2a83d421e356a8047dc8830a7426 +
0xcefc68
+
0x009662a4
+
0x012e9fef
+
0x00cae368
+
0x00cdc3dc
+
0x00cdc3b8
+
+ + 0x4963c928 + 32253bee114dd25ebbaa50d90b5c0a2a + + + 0x4967c2e0 + aea5a207b8b1cda942502f97a429f6c3 + + + 0x49c59b94 + 193193d8624f2f3f6d9d556fab09b122 +
0x0151bd00
+
0x01507968
+
0x0151b36c
+
0x00d20ed8
+
0x016a54f8
+
0x009652a4
+
0x16a5360
+
0x0132e574
+
0x0151b448
+
0x015615c8
+
0x0155f248
+
0x015613b8
+
0x0132e53c
+
0x0131b25f
+
0x0155f280
+
0x0155f284
+
0x0155f288
+
0x01561048
+
0x01560f7c
+
0x015615f8
+
0x01521ed4
+
0x0133c898
+
0x016a429c
+
0x00cdf5a0
+
0x00d0d64c
+
0x00d0d628
+
0x01560880
+
0x0155f268
+
0x0155f26c
+
0x0155f270
+
+ + 0x49c82d3f + 6f81231b845e9c9dc29aaf57705ccc7c + + + 0x4a3ccb7f + 6ea1de36af8e1666bd6478736e298c4c +
0x015b7750
+
0x015a33b8
+
0x015b6dbc
+
0x00ddaed8
+
0x0095f410
+
0x0095f2b4
+
0x1740e60
+
0x013e8574
+
0x015b6e98
+
0x015fd04c
+
0x015faccc
+
0x015fce3c
+
0x013e853c
+
0x013d525f
+
0x015fad04
+
0x015fad08
+
0x015fad0c
+
0x015fcacc
+
0x015fca00
+
0x015fd07c
+
0x015bd924
+
0x015b6dc4
+
0x0173fde0
+
0x00d995a0
+
0x00dc764c
+
0x00dc7628
+
0x015fc304
+
0x015facec
+
0x015facf0
+
0x015facf4
+
+ + 0x4a51c26e + 04a8d8ce311d8ac75e4241bef68d3147 +
0x00ddff38
+
0x00964430
+
0x009642b4
+
0x013da2bf
+
0x00d9e600
+
0x00dcc6ac
+
0x00dcc688
+
+ + 0x4a8623d2 + 781a2e51be4056a7320108f8f0df8a13 +
0x00de1f44
+
0x00966430
+
0x009662b4
+
0x013dc2c7
+
0x00da060c
+
0x00dce6b8
+
0x00dce694
+
+ + 0x4a9a6090 + 12cc4a3dbb6e6dfd7bc7aee458b9471a +
0x015be808
+
0x015aa470
+
0x015bde74
+
0x00de1f54
+
0x00966430
+
0x009662b4
+
0x1747f20
+
0x013ef62c
+
0x015bdf50
+
0x01604104
+
0x01601d84
+
0x01603ef4
+
0x013ef5f4
+
0x013dc2eb
+
0x01601dbc
+
0x01601dc0
+
0x01601dc4
+
0x01603b84
+
0x01603ab8
+
0x01604134
+
0x015c49dc
+
0x015bde7c
+
0x01746e98
+
0x00da061c
+
0x00dce6c8
+
0x00dce6a4
+
0x016033bc
+
0x01601da4
+
0x01601da8
+
0x01601dac
+
+ + 0x4a9b1a72 + 59ab29021aca9f3c66b1ab102fb3ceea + + + 0x4b6b7879 + de66405f54d98297303d439b3b7aa30e +
0x015f3260
+
0x015deec8
+
0x015f28cc
+
0x00e16924
+
0x0099ae08
+
0x0099ac88
+
0x177c978
+
0x014240dc
+
0x015f29a8
+
0x01638b5c
+
0x016367dc
+
0x0163894c
+
0x014240a4
+
0x01410cc1
+
0x01636814
+
0x01636818
+
0x0163681c
+
0x016385dc
+
0x01638510
+
0x01638b8c
+
0x015f9434
+
0x014243c4
+
0x0177b8f0
+
0x00dd4fec
+
0x00e03098
+
0x00e03074
+
0x01637e14
+
0x016367fc
+
0x01636800
+
0x01636804
+
0x0177c978
+
+ + + + 0x4b81b00d + 5cdc6f4804809f4d5cacdb66785e8cda + +
0x00df2ebc
+
0x00977438
+
0x009772b8
+
0x014ad278
+
0x00db1584
+
0x00ddf630
+
0x00ddf60c
+
+ + 0x4b90268a + 13640a273d90af39425b798ae9823757 +
0x01512898
+
0x014fe500
+
0x01511f04
+
0x00d35b68
+
0x016ac1a0
+
0x0097a2b8
+
0x169bfb0
+
0x01343714
+
0x01511fe0
+
0x01558194
+
0x01555e14
+
0x01557f84
+
0x013436dc
+
0x0132ff1e
+
0x01555e4c
+
0x01555e50
+
0x01555e54
+
0x01557c14
+
0x01557b48
+
0x015581c4
+
0x01518a6c
+
0x013439fc
+
0x0169af28
+
0x00cf4230
+
0x00d222dc
+
0x00d222b8
+
0x0155744c
+
0x01555e34
+
0x01555e38
+
0x01555e3c
+
+ + 0x4B918BB9 + af29004e1763bb3460faa11907c3ac90 + + .-"""-. + ' \ + |,. ,-. | + |()L( ()| | + |,' `".| | + |.___.',| ` + .j `--"' ` `. + / ' ' \ + / / ` `. + / / ` . + / / l | + . , L I N U X | | + ,"`. .| | + _.' ``. | `..-'l + | `.`, | `. + | `. __.j ) + |__ |--""___| ,-' + `"--...,+"""" `._,.-' + + + + 7a0859795e972574e80fa3cebc9fcf85 + 0x0 + 0x0 +
0x093154e0
+
0x093016b8
+
0x09355940
+
0x09314ffc
+
0x09301560
+
0x08859fc0
+
0x08cfa060
+
0x0930140c
+
0x09356fd0
+
0x09314ffc
+
0x09355964
+
0x09357808
+
0x093013e4
+
0x092f0580
+
0x0935596c
+
0x09355970
+
0x09355974
+
0x0935754c
+
0x093574e0
+
0x09357928
+
0x09318630
+
0x08b36c80
+
0x09355968
+
0x08b36c84
+
0x08cfa978
+
0x08cfa97c
+
0x09356f6c
+
0x09355954
+
0x09355958
+
0x0935595c
+ 0x1C + + 0x0 + 0x4 + 0x8 + 0x4 + + 0x08 + + 0x00 + 0x4C + 0x44 + 0x90 + 0x94 + 0x003c + 0x0040 + 0x009E + 0x00A0 + 0x00F0 + 0x160 + 0x164 + 0x190 + 0x02F8 + 0x0200 + 0x264 + 0x268 + 0x26C + 0x02F8 + 0x0334 + 0x0338 + 0x033C + 0x0340 + 0x034C + 0x0364 + 0x0400 + 0x0490 + + 0x40 + + 0x08 + 0x2C + 0x0052 + 0x0254 + 0x0654 + 0x1D54 + + 0x54 + 0x56 + 0x5A4 + 0x5C8 + + 0x58 + 0x54 + + 0x4 + + 0xC + 0x24 + 0x18 + 0x2 + 0x4 + 0x8 + 0xC + 0x4 + 0x8 + 0x14 + 0x00 + 0x4a + 0x94 + 0x50 + 0x0C + + 0x20 + + 0xC + 0x4 + 0x10 + 0xC + 0xC + 0xC + 0x14 + 0x1C + 0x20 + + + + + + +
+ + 51c73ff46b2688aafaee0204efe91a94 +
0x09315f00
+
0x093020d8
+
0x09356360
+
0x09315a1c
+
0x09301f80
+
0x0885a9e4
+
0x08cfaa80
+
0x09301e2c
+
0x093579f0
+
0x09315a1c
+
0x09356384
+
0x09358228
+
0x09301e04
+
0x092f0fa0
+
0x0935638c
+
0x09356390
+
0x09356394
+
0x09357f6c
+
0x09357f00
+
0x09358348
+
0x09319050
+
0x08b376a0
+
0x09356388
+
0x08b376a4
+
0x08cfb398
+
0x08cfb39c
+
0x0935798c
+
0x09356374
+
0x09356378
+
0x0935637c
+
+ + c1eb408868c80fd1c726d2a917cd1b9a +
0x0885ad54
+
+ + 59d497bfc3a523f0f40f34283ad59796 +
0x0885bbf0
+
+ + f756194db073f05b98fc6ce872c8757d +
0x09333e00
+
0x0931ffd8
+
0x09374260
+
0x0933391c
+
0x0931fe80
+
0x088788e4
+
0x08d18980
+
0x0931fd2c
+
0x093758f0
+
0x0933391c
+
0x09374284
+
0x09376128
+
0x0931fd04
+
0x0930eea0
+
0x0937428c
+
0x09374290
+
0x09374294
+
0x09375e6c
+
0x09375e00
+
0x09376248
+
0x09336f50
+
0x08b555a0
+
0x09374288
+
0x08b555a4
+
0x08d19298
+
0x08d1929c
+
0x0937588c
+
0x09374274
+
0x09374278
+
0x0937427c
+
+ + b004b3876193633875956af752663f26 + + + c8616fc74d79b3c8c40bbc1182fbd61c +
0x088786a0
+
+ + 992afd73855e787860277f53d18afcbb +
0x08877630
+
+ + cba6354000ec54865a161627605c3837 +
0x092bf340
+
0x092ab518
+
0x092bee5c
+
0x0929a3c8
+
0x092ab3c0
+
0x088073d4
+
0x08ca3eb8
+
0x092ab26c
+
0x092beecc
+
0x09301770
+
0x092ff7a0
+
0x09301668
+
0x092ab244
+
0x0929a3e0
+
0x092ff7cc
+
0x092ff7d0
+
0x092ff7d4
+
0x093013ac
+
0x09301340
+
0x09301788
+
0x092c2490
+
0x08ae40a0
+
0x09510050
+
0x08ca47d4
+
0x08ca47d8
+
0x08ca47dc
+
0x09300dcc
+
0x092ff7b4
+
0x092ff7b8
+
0x092ff7bc
+
+ + fb8ecac8a12af5d0d7b1707078985d0d + + + 4367c59934cbcf14f43fd3af6444c455 +
0x08f55740
+
0x08f41918
+
0x08f5525c
+
0x08f307c8
+
0x08f417c0
+
0x0877b33c
+
0x0893a2ac
+
0x08f4166c
+
0x08f552cc
+
0x08f97b8c
+
0x08f95bbc
+
0x08f97a84
+
0x08f41644
+
0x08f307e0
+
0x08f95be8
+
0x08f95bec
+
0x08f95bf0
+
0x08f977c8
+
0x08f9775c
+
0x08f97ba4
+
0x08f58890
+
0x0877f8e0
+
0x091a647c
+
0x0893abd4
+
0x0893abd8
+
0x0893abdc
+
0x08f971e8
+
0x08f95bd0
+
0x08f95bd4
+
0x08f95bd8
+
+ + 2f3cb9d720e9fe8844c02c72a2b20bbd +
0x08780344
+
0x0893f2d0
+
+ + dab3ce6bc074529706a1e5fe1273108c +
0x08f5a760
+
0x08f46938
+
0x08f5a27c
+
0x08f357e8
+
0x08f467e0
+
0x08780354
+
0x0893f2d0
+
0x08f4668c
+
0x08f5a2ec
+
0x08f9cbac
+
0x08f9abdc
+
0x08f9caa4
+
0x08f46664
+
0x08f35800
+
0x08f9ac08
+
0x08f9ac0c
+
0x08f9ac10
+
0x08f9c7e8
+
0x08f9c77c
+
0x08f9cbc4
+
0x08f5d8b0
+
0x08784900
+
0x091ab49c
+
0x0893fbf4
+
0x0893fbf8
+
0x0893fbfc
+
0x08f9c208
+
0x08f9abf0
+
0x08f9abf4
+
0x08f9abf8
+
+ + 4f55a1dcc326786271f221de23c425b5 + + + 022b933926e08da49c6df8649295f2b7 + + + 8f55a6250f2550e28535b79db43d5f1a +
0x08f628c0
+
0x08f4ea98
+
0x08f623dc
+
0x08f3d948
+
0x08f4e940
+
0x0878c340
+
0x08947438
+
0x08f4e7ec
+
0x08f6244c
+
0x08fa4d0c
+
0x08fa2d3c
+
0x08fa4c04
+
0x08f4e7c4
+
0x660008f3
+
0x08fa2d68
+
0x08fa2d6c
+
0x08fa2d70
+
0x08fa4948
+
0x08fa48dc
+
0x08fa4d24
+
0x08f65a10
+
0x0878caa0
+
0x091b35fc
+
0x08947d54
+
0x08947d58
+
0x08947d5c
+
0x08fa4368
+
0x08fa2d50
+
0x08fa2d54
+
0x08fa2d58
+
+ + 777e7d674d8908042307994cb75250ff +
0x09009860
+
0x08ff5a38
+
0x0900937C
+
0x08fe48e8
+
0x08ff58e0
+
0x08833324
+
0x089ee3d8
+
0x08FF578C
+
0x090093ec
+
0x0904bcac
+
0x09049cdc
+
0x0904bba4
+
0x08ff5764
+
0x08fe4900
+
0x09049d08
+
0x09049d0c
+
0x09049d10
+
0x0904b8e8
+
0x0904b87c
+
0x0904bcc4
+
0x0900c9b0
+
0x08833a40
+
0x0925a59c
+
0x089eecf4
+
0x089eecf8
+
0x089eecfc
+
0x0904b308
+
0x09049cf0
+
0x09049cf4
+
0x09049cf8
+
+ + 04c3ad13c657f59ba6fc135e156d721d +
0x09008880
+
0x08ff4a58
+
0x0900839C
+
0x08fe3908
+
0x08ff4900
+
0x08832328
+
0x089ed3f8
+
0x08ff47ac
+
0x0900840c
+
0x0904accc
+
0x09048cfc
+
0x0904abc4
+
0x08ff4784
+
0xc60008fe
+
0x09048d28
+
0x09048d2c
+
0x09048d30
+
0x0904a908
+
0x0904a89c
+
0x0904ace4
+
0x0900b9d0
+
0x08832a60
+
0x091995fc
+
0x089edd14
+
0x089edd18
+
0x089edd1c
+
0x0904a328
+
0x09048d10
+
0x09048d14
+
0x09048d18
+
+ + + 851c1190b6a7b42f2463967623d18575 + 0x4BB45F99 + + + 0x18 + 0x0 + 0xC + 0x1C + + +
0xe32798
+
0xe60838
+
0xe60814
+
0xae82cc
+ +
0x17f5ab8
+ Found addresses: (next to each other!) + 0x17f5ab8 + 0x17f5ac0 + 0x17f5ac8 + 0x17f5ad0 + +
0x146e45f
+ Found addresses: + 0x146e45f + 0x185b677 + + Bogus:
0xae82cc
+ +
0x017f6f38
+ + Bogus:
0xae82cc
+ + + +
0x016ad738
+
0x016ad73C
+
0x016ad740
+ +
0x016ad744
+
0x016ad748
+
0x016ad74C
+ +
0x016ad750
+
0x016ad754
+
0x016ad758
+ +
0x016AD718
+ 0x10 + 0x0092 + 0x029C + + + 0x0 + 0x1C + 0x38 + + + 0x0 + 0x90 + 0xF8 + 0xFC + 0x110 + 0x114 + 0x6D0 + 0x770 + + + + +
+
+ diff --git a/output/Memory.xml b/output/Memory.xml index b6d5ce1f5..bba958a69 100644 --- a/output/Memory.xml +++ b/output/Memory.xml @@ -3,789 +3,39 @@ - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - 20 - 21 - 22 - 23 - 24 - 25 - 26 - 27 - 28 - 29 - 30 - 31 - 32 - 33 - 34 - 35 - 36 - 37 - 38 - 39 - 40 - 41 - 42 - 43 - 44 - 45 - 46 - 47 - 48 - 49 - 50 - 51 - 52 - 53 - 54 - 55 - 56 - 57 - 58 - 59 - 60 - 61 - 62 - 63 - 64 - 65 - 66 - 67 - 68 - 69 - 70 - 71 - 72 - 73 - 74 - 75 - 76 - 77 - 78 - 79 - 80 - 81 - 82 - 83 - 84 - 85 - 86 - 87 - 88 - 89 - 90 - 91 - 92 - 93 - 94 - 95 - 96 - 97 - 98 - 99 - 100 - 101 - 102 - 103 - 104 - 105 - 106 - 107 - 108 - 109 - 110 - 111 - 112 - 113 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - 20 - 21 - 22 - 23 - 24 - 25 - 26 - 27 - 28 - 29 - 30 - 31 - 32 - 33 - 34 - 35 - 36 - 37 - 38 - 39 - 40 - 41 - 42 - 43 - 44 - 45 - 46 - 47 - 48 - 49 - 50 - 51 - 52 - 53 - 54 - 55 - 56 - 57 - 58 - 59 - 60 - 61 - 62 - 63 - 64 - 65 - 66 - 67 - 68 - 69 - 70 - 71 - 72 - 73 - 74 - 75 - 76 - 77 - 78 - 79 - 80 - 81 - 82 - 83 - 84 - 85 - 86 - 87 - 88 - 89 - 90 - 91 - 92 - 93 - 94 - 95 - 96 - 97 - 98 - 99 - 100 - 101 - 102 - 103 - 104 - 105 - 106 - 107 - 108 - 109 - 110 - 111 - 112 - 113 - 114 - 115 - 116 - 117 - 118 - 119 - 120 - 121 - 122 - 123 - 124 - 125 - 126 - 127 - 128 - 129 - 130 - 131 - 132 - 133 - 134 - 135 - 136 - 137 - 138 - 139 - 140 - 141 - 142 - 143 - 144 - 145 - 146 - 147 - 148 - 149 - 150 - 151 - 152 - 153 - 154 - 155 - 156 - 157 - 158 - 159 - 160 - 161 - 162 - 163 - 164 - 165 - 166 - 167 - 168 - 169 - 170 - 171 - 172 - 173 - 174 - 175 - 176 - 177 - 178 - 179 - 180 - 181 - 182 - 183 - 184 - 185 - 186 - 187 - 188 - 189 - 190 - 191 - 192 - 193 - 194 - 195 - 196 - 197 - 198 - 199 - 200 - 201 - 202 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - 20 - 21 - 22 - 23 - 24 - 25 - 26 - 27 - 28 - 29 - 30 - 31 - 32 - 33 - 34 - 35 - 36 - 37 - 38 - 39 - 40 - 41 - 42 - 43 - 44 - 45 - 46 - 47 - 48 - 49 - 50 - 51 - 52 - 53 - 54 - 55 - 56 - 57 - 58 - 59 - 60 - 61 - 62 - 63 - 64 - 65 - 66 - 67 - 68 - 69 - 70 - 71 - 72 - 73 - 74 - 75 - 76 - 77 - 78 - 79 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - 20 - 21 - 22 - 23 - 24 - 25 - 26 - 27 - 28 - 29 0 - 66 - 11 - 10 - 13 - 12 - 14 - 15 - 16 - 20 - 38 - 19 - 41 - 39 - 43 - 42 - 40 - 44 - 45 - 48 - 27 - 49 - 21 - 47 - 26 - 46 - 50 - 23 - 18 - 30 - 32 - 71 - 33 - 34 - 70 - 31 - 28 - 69 - 25 - 22 - 29 - 72 - 35 - 36 - 37 - 67 - 73 - 64 - 65 - 17 - 8 - 2 - 6 - 4 - 1 - 5 - 7 - 9 - 3 - 24 - 51 - 52 - 53 - 54 - 55 - 57 - -1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + --> - - .,:rsr, - :2;,;r2A@@5 - @2::s5A#@@@ @r. . - sd;:riXA#@@ :@@@Gir;;AS9 - Bs::sS3A#@2 @@#AhXirsS#; - iHrLr5d#@@@ .@#95sr;;rie - i*' `*@3 @@A2sr;:;r#5 - :..:rll: @@A5sr::r3@ - @Hr;iZ#@@@@ `:rr;;;;: - S@r.;i2#@@@ @s. .. - @2::ri2A@@# B@G2ir:...5i - :@r,r3X##@@ @G5sr:..,:A - .@Ar;;rSB@@# H#2sr;,..,is - .' `* ,@ASs;:..,:B - ;rr;:,..,:. - `''' - W I N D O W S - and - W I N E - + - 0x4 + + where a vector actually starts: 0x0 + where the vector triplet is: 0x4 +
0x014639f4
0x01463288
0x01463388
@@ -815,21 +65,29 @@
0x014a4ec4
0x014a4ec8
0x014a4ecc
- + + job object offsets + ================== 0x08 - + + map block offsets + ================= 0x08 0x2C 0x0062 0x0264 0x0664 0x1D64 - + + name struct + =========== 0x0 0x1C 0x38 0x1C - + + creature offsets + ================ 0x00 0x6c 0x88 @@ -857,29 +115,45 @@ 0x474 0x520 0x5D0 - + + tree and shrub offsets + ====================== 0x70 - + + the world and its offsets + ========================= 0x84 0x86 0x684 0x6B4 - + + values for the region structure + =============================== 0x5C 0x58 - + + geoblock offset(s?) + =================== 0x4 - + + matgloss vectors + ================ 0x10 - + + only stone and metal have color loaded... + ========================================= 0x84 0x60 + + map block offsets + ================= 0x08 0x2C 0x0062 0x0264 0x0664 0x1D64 + 0x3C 0x2 0x4 @@ -892,6 +166,8 @@ 0xD8 0x68 0x24 + + 0x1C 0x28 0x24 @@ -901,655 +177,184 @@ 0x94 0xB0 - - 0x47c12f36 - 8bd90fb6db8388f129fde224a35459de -
0x01463bec
-
0x01463480
-
0x01463580
-
0x00c7bc04
-
0x01287d14
-
0x0094128c
-
0x01287a9c
-
0x01463550
-
0x014a6c60
-
0x014a50a4
-
0x014a6b00
-
0xffffffff
-
0x8b010127
-
0x014a50d4
-
0x014a50d8
-
0x014a50dc
-
0x014a694c
-
0x014a69e8
-
0x014a6c80
-
0x01467d70
-
0x01295d58
-
0x01284184
-
0x00c3fb40
-
0x00c23594
-
0x00c68354
-
0x014a66d4
-
0x014a50bc
-
0x014a50c0
-
0x014a50c4
-
- - 0x47c29583 - 9147b5e922a30873fd1a742b1dea1724 -
0xffffffff
-
0x8b010127
-
- - 0x487b4e8b - 4b3857a05590b9d9488900e575079e9d -
0x01512b70
-
0x014feb80
-
0x01512504
-
0x00d16c20
-
0x01322d58
-
0x009d6284
-
0x01322adc
-
0x014fec50
-
0x01555f88
-
0x01554028
-
0x01555e28
-
0xffffffff
-
0x8b010131
-
0x01554058
-
0x0155405c
-
0x01554060
-
0x01555ce8
-
0x01555c6c
-
0x01555fa8
-
0x01516cf4
-
0x01330d98
-
0x0131f1b4
-
0x00cd5398
-
0x00cb8dec
-
0x00d03370
-
0x01555658
-
0x01554040
-
0x01554044
-
0x01554048
-
- - 0x487c9338 - 52155dea390c2080fc16e4bbeb077164 -
0xffffffff
-
0x8b010131
-
- - 0x487f2f30 - 8f8cf06b1cd5ea102881a7cced767d4f -
0x01513b90
-
0x014ffba0
-
0x01513524
-
0x00d17c44
-
0x01323d78
-
0x009d7284
-
0xffffffff
- -
0x014ffc70
-
0x01556fa8
-
0x01555048
-
0x01556e48
-
0xffffffff
- -
0x8b010131
-
0x01555078
-
0x0155507c
-
0x01555080
-
0x01556d08
-
0x01556c8c
-
0x01556fc8
-
0x01517d14
-
0x01331db8
-
0x013201d4
-
0x00cd63bc
-
0x00cb9dec
-
0x00d04394
-
0x01556678
-
0x01555060
-
0x01555064
-
0x01555068
-
- - 0x48873bc3 - 8614a01593baef6e4a341e2f1a92ba06 -
0x0151ffb8
-
0x0150bfc8
-
0x0151f94c
-
0x00d23c4c
-
0x0132fdb0
-
0x009e3284
-
0x0132fb34
-
0x0150c098
-
0x015635cc
-
0x01561470
-
0x0156346c
-
0x0132faac
-
0x8b010131
-
0x015614a0
-
0x015614a4
-
0x015614a8
-
0x01563154
-
0x015630d8
-
0x015635ec
-
0x0152413c
-
0x0133ddf0
-
0x0132c1dc
-
0x00ce23c4
-
0x00cc5df4
-
0x00d1039c
-
0x01562aa0
-
0x01561488
-
0x0156148c
-
0x01561490
-
- - 0x4888672c - 32f68422f5b4d938549eed0565bcfb92 - - - 0x489d8c7f - 33db0401081058fb54252210bf371344 -
0x01576468
-
0x01562478
-
0x01575dfc
-
0x00d7a0fc
-
0x01386260
-
0x009ef294
-
0x01385fe4
-
0x01562548
-
0x015b9a7c
-
0x015b7920
-
0x015b991c
-
0x01385f5c
-
0x5f010137
-
0x015b7950
-
0x015b7954
-
0x015b7958
-
0x015b9604
-
0x015b9588
-
0x015b9a9c
-
0x0157a5ec
-
0x013942a0
-
0x0138268c
-
0x00d387fc
-
0x00d66870
-
0x00d6684c
-
0x015b8f50
-
0x015b7938
-
0x015b793c
-
0x015b7940
-
- - 0x48a9727f - 441c76f45cfffc6abc6548e41c7e2218 -
0x015828a8
-
0x0156e8b8
-
0x0158223c
-
0x00d860fc
-
0x01392268
-
0x009fb294
-
0x01391fc0
-
0x0156e988
-
0x015c5ecc
-
0x015c3d60
-
0x015c5d6c
-
0x01391f64
-
0x5f010138
-
0x015c3d90
-
0x015c3d94
-
0x015c3d98
-
0x015c5a54
-
0x015c59c8
-
0x015c5eec
-
0x01586a2c
-
0x013a02a8
-
0x0138e694
-
0x00d447fc
-
0x00d72870
-
0x00d7284c
-
0x015c5390
-
0x015c3d78
-
0x015c3d7c
-
0x015c3d80
-
- - 0x48ad547a - 65b4fa339d4081e934c1297d2a22234a - - - 0x48ad802b - 15e95727019e76aa653538618c7e0cfd - - - 0x48c330df - 2c686c26307dcccd7c36cc79737ebe4f -
0x015838a0
-
0x0156f8b0
-
0x01583234
-
0x00D870F4
-
0x01393260
-
0x009fc294
-
0x1583234
-
0x01392fb8
-
0x0156f980
-
0x015c6ed0
-
0x015c4d58
-
0x015c6d70
-
0x01392f5c
-
0x0138147f
-
0x015c4d88
-
0x015c4d8c
-
0x015c4d90
-
0x015c6a58
-
0x015c69cc
-
0x015c6ef0
-
0x01587a24
-
0x013a12a0
-
0x0138f68c
-
0x00d457f4
-
0x00d73868
-
0x00d73844
-
0x015c6388
-
0x015c4d70
-
0x015c4d74
-
0x015c4d78
-
- - - 0x4953556c - b1a8ca1f91734eb492b7f54f6823cddb - -0x8 - 0x4 -
0x014d1db0
-
0x014bda18
-
0x014D141C
-
0x00cd4c3c
-
0x0165b5a8
-
0x0094b27c
-
0x165b410
-
0x012e101c
-
0x014d14f8
-
0x01517678
-
0x015152f8
-
0x01517468
-
0x012e0fe4
-
0x012cefbf
-
0x01515330
-
0x01515334
-
0x01515338
-
0x015170f8
-
0x0151702c
-
0x015176a8
-
0x014d7f84
-
0x012ef340
-
0x0165a34c
-
0x00c9333c
-
0x00cc13b0
-
0x00cc138c
-
0x01516930
-
0x01515318
-
0x0151531c
-
0x01515320
- 0x54 - - 0x0 - 0x1C - 0x38 - 0x1C - - - 0xFC - 0x100 - 0x10A - 0x10C - 0x198 - 0x238 - 0x23C - 0x268 - 0x2F8 - 0x314 - 0x3C0 - 0x3C4 - 0x3C8 - 0x484 - 0x4F0 - 0x4F4 - 0x4F8 - 0x504 - 0x51C - 0x544 - 0x610 - 0x700 - - 0x70 - - 0x10 - 0x2C - 0x0082 - 0x0284 - 0x0684 - 0x1D84 - 0x84 - 0x86 - 0x75C - 0x79C - - 0x64 - 0x60 - - 0xC - 0x2 - 0x4 - 0x8 - 0x24 - 0x1C - 0x20 - 0x2C - 0x0 - 0x7a - 0x100 - 0x68 - 0x24 - - 0x18 - 0x1C - 0x28 - 0x24 - 0x24 - 0x24 - 0x5C - 0x94 - 0xB0 - - - - - - - -
- - 0x4957716f - 9b6da355562a4cdd345ea3046290499b -
0x00cd6c3c
-
0x0094d27c
-
0x012d0fbf
-
0x00c9533c
-
0x00cc33b0
-
0x00cc338c
-
- - 0x4957a0a2 - b77759db7a6dd787bf98953fc5749d81 - - - 0x495991c3 - a0792b81e5b8ec1dbdd627643e93b40d -
0xcd8c34
-
0x0094f27c
-
0x012d2fbb
-
0x00c97334
-
0x00cc53a8
-
0x00cc5384
-
- - 0x495cafd2 - d09e88a32fe57de5973f78ef213271b6 -
0xcefc68
-
0x009662a4
-
0x012e9fef
-
0x00cae368
-
0x00cdc3dc
-
0x00cdc3b8
-
- - 0x495fcfef - 8e8e2a83d421e356a8047dc8830a7426 -
0xcefc68
-
0x009662a4
-
0x012e9fef
-
0x00cae368
-
0x00cdc3dc
-
0x00cdc3b8
-
- - 0x4963c928 - 32253bee114dd25ebbaa50d90b5c0a2a - - - 0x4967c2e0 - aea5a207b8b1cda942502f97a429f6c3 - - - 0x49c59b94 - 193193d8624f2f3f6d9d556fab09b122 -
0x0151bd00
-
0x01507968
-
0x0151b36c
-
0x00d20ed8
-
0x016a54f8
-
0x009652a4
-
0x16a5360
-
0x0132e574
-
0x0151b448
-
0x015615c8
-
0x0155f248
-
0x015613b8
-
0x0132e53c
-
0x0131b25f
-
0x0155f280
-
0x0155f284
-
0x0155f288
-
0x01561048
-
0x01560f7c
-
0x015615f8
-
0x01521ed4
-
0x0133c898
-
0x016a429c
-
0x00cdf5a0
-
0x00d0d64c
-
0x00d0d628
-
0x01560880
-
0x0155f268
-
0x0155f26c
-
0x0155f270
-
- - 0x49c82d3f - 6f81231b845e9c9dc29aaf57705ccc7c - - - 0x4a3ccb7f - 6ea1de36af8e1666bd6478736e298c4c -
0x015b7750
-
0x015a33b8
-
0x015b6dbc
-
0x00ddaed8
-
0x0095f410
-
0x0095f2b4
-
0x1740e60
-
0x013e8574
-
0x015b6e98
-
0x015fd04c
-
0x015faccc
-
0x015fce3c
-
0x013e853c
-
0x013d525f
-
0x015fad04
-
0x015fad08
-
0x015fad0c
-
0x015fcacc
-
0x015fca00
-
0x015fd07c
-
0x015bd924
-
0x015b6dc4
-
0x0173fde0
-
0x00d995a0
-
0x00dc764c
-
0x00dc7628
-
0x015fc304
-
0x015facec
-
0x015facf0
-
0x015facf4
-
- - 0x4a51c26e - 04a8d8ce311d8ac75e4241bef68d3147 -
0x00ddff38
-
0x00964430
-
0x009642b4
-
0x013da2bf
-
0x00d9e600
-
0x00dcc6ac
-
0x00dcc688
-
- - 0x4a8623d2 - 781a2e51be4056a7320108f8f0df8a13 -
0x00de1f44
-
0x00966430
-
0x009662b4
-
0x013dc2c7
-
0x00da060c
-
0x00dce6b8
-
0x00dce694
-
- - 0x4a9a6090 - 12cc4a3dbb6e6dfd7bc7aee458b9471a -
0x015be808
-
0x015aa470
-
0x015bde74
-
0x00de1f54
-
0x00966430
-
0x009662b4
-
0x1747f20
-
0x013ef62c
-
0x015bdf50
-
0x01604104
-
0x01601d84
-
0x01603ef4
-
0x013ef5f4
-
0x013dc2eb
-
0x01601dbc
-
0x01601dc0
-
0x01601dc4
-
0x01603b84
-
0x01603ab8
-
0x01604134
-
0x015c49dc
-
0x015bde7c
-
0x01746e98
-
0x00da061c
-
0x00dce6c8
-
0x00dce6a4
-
0x016033bc
-
0x01601da4
-
0x01601da8
-
0x01601dac
-
- - 0x4a9b1a72 - 59ab29021aca9f3c66b1ab102fb3ceea - - - 0x4b6b7879 - de66405f54d98297303d439b3b7aa30e -
0x015f3260
-
0x015deec8
-
0x015f28cc
-
0x00e16924
-
0x0099ae08
-
0x0099ac88
-
0x177c978
-
0x014240dc
-
0x015f29a8
-
0x01638b5c
-
0x016367dc
-
0x0163894c
-
0x014240a4
-
0x01410cc1
-
0x01636814
-
0x01636818
-
0x0163681c
-
0x016385dc
-
0x01638510
-
0x01638b8c
-
0x015f9434
-
0x014243c4
-
0x0177b8f0
-
0x00dd4fec
-
0x00e03098
-
0x00e03074
-
0x01637e14
-
0x016367fc
-
0x01636800
-
0x01636804
-
0x0177c978
-
- - - - 0x4b81b00d - 5cdc6f4804809f4d5cacdb66785e8cda - -
0x00df2ebc
-
0x00977438
-
0x009772b8
-
0x014ad278
-
0x00db1584
-
0x00ddf630
-
0x00ddf60c
-
- - 0x4b90268a - 13640a273d90af39425b798ae9823757 -
0x01512898
-
0x014fe500
-
0x01511f04
-
0x00d35b68
-
0x016ac1a0
-
0x0097a2b8
-
0x169bfb0
-
0x01343714
-
0x01511fe0
-
0x01558194
-
0x01555e14
-
0x01557f84
-
0x013436dc
-
0x0132ff1e
-
0x01555e4c
-
0x01555e50
-
0x01555e54
-
0x01557c14
-
0x01557b48
-
0x015581c4
-
0x01518a6c
-
0x013439fc
-
0x0169af28
-
0x00cf4230
-
0x00d222dc
-
0x00d222b8
-
0x0155744c
-
0x01555e34
-
0x01555e38
-
0x01555e3c
-
- - 0x4B918BB9 - af29004e1763bb3460faa11907c3ac90 + --> + + + .,:rsr, + :2;,;r2A@@5 + @2::s5A#@@@ @r. . + sd;:riXA#@@ :@@@Gir;;AS9 + Bs::sS3A#@2 @@#AhXirsS#; + iHrLr5d#@@@ .@#95sr;;rie + i*' `*@3 @@A2sr;:;r#5 + :..:rll: @@A5sr::r3@ + @Hr;iZ#@@@@ `:rr;;;;: + S@r.;i2#@@@ @s. .. + @2::ri2A@@# B@G2ir:...5i + :@r,r3X##@@ @G5sr:..,:A + .@Ar;;rSB@@# H#2sr;,..,is + .' `* ,@ASs;:..,:B + ;rr;:,..,:. + `''' + W I N D O W S + and + W I N E + + + + + 851c1190b6a7b42f2463967623d18575 + 0x4BB45F99 + + Basic things + ============ + 0x18 + 0xC + 0x1C + + Position and window dimensions + ============================== +
0xe32798
+
0xe60838
+
0xe60814
+
0xae82cc
+ +
0x17f5ab8
+ Found addresses: (next to each other!) + 0x17f5ab8 + 0x17f5ac0 + 0x17f5ac8 + 0x17f5ad0 + +
0x146e45f
+ Found addresses: + 0x146e45f + 0x185b677 + + Bogus:
0xae82cc
+ +
0x017f6f38
+ + Bogus:
0xae82cc
+ + Map stuff + ========= +
0x016AD718
+ 0x10 + 0x0092 + 0x029C + + + * map size in blocks * +
0x016ad738
+
0x016ad73C
+
0x016ad740
+ + * map size in tiles * +
0x016ad744
+
0x016ad748
+
0x016ad74C
+ + * Suspected region coords * +
0x016ad750
+
0x016ad754
+
0x016ad758
+ + name struct + =========== + 0x0 + 0x1C + 0x38 + + Creatures + ========= + 0x0 + 0x90 + 0xF8 + 0xFC + 0x110 + 0x114 + 0x6D0 + 0x770 + + + +
+ .-"""-. ' \ - |,. ,-. | - |()L( ()| | - |,' `".| | - |.___.',| ` + |,. ,-. | _________________________ + |()L( ()| | \ \ + |,' `".| | /_ Nothing here yet :( \ + |.___.',| ` \________________________\ .j `--"' ` `. / ' ' \ / / ` `. @@ -1562,568 +367,8 @@ | `. __.j ) |__ |--""___| ,-' `"--...,+"""" `._,.-' - - - 7a0859795e972574e80fa3cebc9fcf85 - 0x0 - 0x0 -
0x093154e0
-
0x093016b8
-
0x09355940
-
0x09314ffc
-
0x09301560
-
0x08859fc0
-
0x08cfa060
-
0x0930140c
-
0x09356fd0
-
0x09314ffc
-
0x09355964
-
0x09357808
-
0x093013e4
-
0x092f0580
-
0x0935596c
-
0x09355970
-
0x09355974
-
0x0935754c
-
0x093574e0
-
0x09357928
-
0x09318630
-
0x08b36c80
-
0x09355968
-
0x08b36c84
-
0x08cfa978
-
0x08cfa97c
-
0x09356f6c
-
0x09355954
-
0x09355958
-
0x0935595c
- 0x1C - - 0x0 - 0x4 - 0x8 - 0x4 - - 0x08 - - 0x00 - 0x4C - 0x44 - 0x90 - 0x94 - 0x003c - 0x0040 - 0x009E - 0x00A0 - 0x00F0 - 0x160 - 0x164 - 0x190 - 0x02F8 - 0x0200 - 0x264 - 0x268 - 0x26C - 0x02F8 - 0x0334 - 0x0338 - 0x033C - 0x0340 - 0x034C - 0x0364 - 0x0400 - 0x0490 - - 0x40 - - 0x08 - 0x2C - 0x0052 - 0x0254 - 0x0654 - 0x1D54 - - 0x54 - 0x56 - 0x5A4 - 0x5C8 - - 0x58 - 0x54 - - 0x4 - - 0xC - 0x24 - 0x18 - 0x2 - 0x4 - 0x8 - 0xC - 0x4 - 0x8 - 0x14 - 0x00 - 0x4a - 0x94 - 0x50 - 0x0C - - 0x20 - - 0xC - 0x4 - 0x10 - 0xC - 0xC - 0xC - 0x14 - 0x1C - 0x20 - - - - - - -
- - 51c73ff46b2688aafaee0204efe91a94 -
0x09315f00
-
0x093020d8
-
0x09356360
-
0x09315a1c
-
0x09301f80
-
0x0885a9e4
-
0x08cfaa80
-
0x09301e2c
-
0x093579f0
-
0x09315a1c
-
0x09356384
-
0x09358228
-
0x09301e04
-
0x092f0fa0
-
0x0935638c
-
0x09356390
-
0x09356394
-
0x09357f6c
-
0x09357f00
-
0x09358348
-
0x09319050
-
0x08b376a0
-
0x09356388
-
0x08b376a4
-
0x08cfb398
-
0x08cfb39c
-
0x0935798c
-
0x09356374
-
0x09356378
-
0x0935637c
-
- - c1eb408868c80fd1c726d2a917cd1b9a -
0x0885ad54
-
- - 59d497bfc3a523f0f40f34283ad59796 -
0x0885bbf0
-
- - f756194db073f05b98fc6ce872c8757d -
0x09333e00
-
0x0931ffd8
-
0x09374260
-
0x0933391c
-
0x0931fe80
-
0x088788e4
-
0x08d18980
-
0x0931fd2c
-
0x093758f0
-
0x0933391c
-
0x09374284
-
0x09376128
-
0x0931fd04
-
0x0930eea0
-
0x0937428c
-
0x09374290
-
0x09374294
-
0x09375e6c
-
0x09375e00
-
0x09376248
-
0x09336f50
-
0x08b555a0
-
0x09374288
-
0x08b555a4
-
0x08d19298
-
0x08d1929c
-
0x0937588c
-
0x09374274
-
0x09374278
-
0x0937427c
-
- - b004b3876193633875956af752663f26 - - - c8616fc74d79b3c8c40bbc1182fbd61c -
0x088786a0
-
- - 992afd73855e787860277f53d18afcbb -
0x08877630
-
- - cba6354000ec54865a161627605c3837 -
0x092bf340
-
0x092ab518
-
0x092bee5c
-
0x0929a3c8
-
0x092ab3c0
-
0x088073d4
-
0x08ca3eb8
-
0x092ab26c
-
0x092beecc
-
0x09301770
-
0x092ff7a0
-
0x09301668
-
0x092ab244
-
0x0929a3e0
-
0x092ff7cc
-
0x092ff7d0
-
0x092ff7d4
-
0x093013ac
-
0x09301340
-
0x09301788
-
0x092c2490
-
0x08ae40a0
-
0x09510050
-
0x08ca47d4
-
0x08ca47d8
-
0x08ca47dc
-
0x09300dcc
-
0x092ff7b4
-
0x092ff7b8
-
0x092ff7bc
-
- - fb8ecac8a12af5d0d7b1707078985d0d - - - 4367c59934cbcf14f43fd3af6444c455 -
0x08f55740
-
0x08f41918
-
0x08f5525c
-
0x08f307c8
-
0x08f417c0
-
0x0877b33c
-
0x0893a2ac
-
0x08f4166c
-
0x08f552cc
-
0x08f97b8c
-
0x08f95bbc
-
0x08f97a84
-
0x08f41644
-
0x08f307e0
-
0x08f95be8
-
0x08f95bec
-
0x08f95bf0
-
0x08f977c8
-
0x08f9775c
-
0x08f97ba4
-
0x08f58890
-
0x0877f8e0
-
0x091a647c
-
0x0893abd4
-
0x0893abd8
-
0x0893abdc
-
0x08f971e8
-
0x08f95bd0
-
0x08f95bd4
-
0x08f95bd8
-
- - 2f3cb9d720e9fe8844c02c72a2b20bbd -
0x08780344
-
0x0893f2d0
-
- - dab3ce6bc074529706a1e5fe1273108c -
0x08f5a760
-
0x08f46938
-
0x08f5a27c
-
0x08f357e8
-
0x08f467e0
-
0x08780354
-
0x0893f2d0
-
0x08f4668c
-
0x08f5a2ec
-
0x08f9cbac
-
0x08f9abdc
-
0x08f9caa4
-
0x08f46664
-
0x08f35800
-
0x08f9ac08
-
0x08f9ac0c
-
0x08f9ac10
-
0x08f9c7e8
-
0x08f9c77c
-
0x08f9cbc4
-
0x08f5d8b0
-
0x08784900
-
0x091ab49c
-
0x0893fbf4
-
0x0893fbf8
-
0x0893fbfc
-
0x08f9c208
-
0x08f9abf0
-
0x08f9abf4
-
0x08f9abf8
-
- - 4f55a1dcc326786271f221de23c425b5 - - - 022b933926e08da49c6df8649295f2b7 - - - 8f55a6250f2550e28535b79db43d5f1a -
0x08f628c0
-
0x08f4ea98
-
0x08f623dc
-
0x08f3d948
-
0x08f4e940
-
0x0878c340
-
0x08947438
-
0x08f4e7ec
-
0x08f6244c
-
0x08fa4d0c
-
0x08fa2d3c
-
0x08fa4c04
-
0x08f4e7c4
-
0x660008f3
-
0x08fa2d68
-
0x08fa2d6c
-
0x08fa2d70
-
0x08fa4948
-
0x08fa48dc
-
0x08fa4d24
-
0x08f65a10
-
0x0878caa0
-
0x091b35fc
-
0x08947d54
-
0x08947d58
-
0x08947d5c
-
0x08fa4368
-
0x08fa2d50
-
0x08fa2d54
-
0x08fa2d58
-
- - 777e7d674d8908042307994cb75250ff -
0x09009860
-
0x08ff5a38
-
0x0900937C
-
0x08fe48e8
-
0x08ff58e0
-
0x08833324
-
0x089ee3d8
-
0x08FF578C
-
0x090093ec
-
0x0904bcac
-
0x09049cdc
-
0x0904bba4
-
0x08ff5764
-
0x08fe4900
-
0x09049d08
-
0x09049d0c
-
0x09049d10
-
0x0904b8e8
-
0x0904b87c
-
0x0904bcc4
-
0x0900c9b0
-
0x08833a40
-
0x0925a59c
-
0x089eecf4
-
0x089eecf8
-
0x089eecfc
-
0x0904b308
-
0x09049cf0
-
0x09049cf4
-
0x09049cf8
-
- - 04c3ad13c657f59ba6fc135e156d721d -
0x09008880
-
0x08ff4a58
-
0x0900839C
-
0x08fe3908
-
0x08ff4900
-
0x08832328
-
0x089ed3f8
-
0x08ff47ac
-
0x0900840c
-
0x0904accc
-
0x09048cfc
-
0x0904abc4
-
0x08ff4784
-
0xc60008fe
-
0x09048d28
-
0x09048d2c
-
0x09048d30
-
0x0904a908
-
0x0904a89c
-
0x0904ace4
-
0x0900b9d0
-
0x08832a60
-
0x091995fc
-
0x089edd14
-
0x089edd18
-
0x089edd1c
-
0x0904a328
-
0x09048d10
-
0x09048d14
-
0x09048d18
-
- - - 851c1190b6a7b42f2463967623d18575 - 0x4BB45F99 - - - 0x18 - 0x0 - 0xC - 0x1C - - -
0xe32798
-
0xe60838
-
0xe60814
-
0xae82cc
- -
0x17f5ab8
- Found addresses: (next to each other!) - 0x17f5ab8 - 0x17f5ac0 - 0x17f5ac8 - 0x17f5ad0 - -
0x146e45f
- Found addresses: - 0x146e45f - 0x185b677 - - Bogus:
0xae82cc
- -
0x017f6f38
- - Bogus:
0xae82cc
- - - -
0x016ad738
-
0x016ad73C
-
0x016ad740
- -
0x016ad744
-
0x016ad748
-
0x016ad74C
- -
0x016ad750
-
0x016ad754
-
0x016ad758
- -
0x016AD718
- 0x10 - 0x0092 - 0x029C - - - 0x0 - 0x1C - 0x38 - - - 0x0 - 0x90 - 0xF8 - 0xFC - 0x110 - 0x114 - 0x6D0 - 0x770 - - - - -
-
+ + +
From 5b8fa0ffa611cd6f1bf3993cd4ae9c555d5b179f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Fri, 2 Apr 2010 22:00:33 +0200 Subject: [PATCH 13/29] Added material addresses to veccheck and Memory.xml --- dfhack/DFHackAPI.cpp | 4 ++-- dfhack/DFVector.cpp | 2 +- examples/veccheck.cpp | 26 ++++++++++++++------------ output/Memory.xml | 31 ++++++++++++++++++++++++++++++- 4 files changed, 47 insertions(+), 16 deletions(-) diff --git a/dfhack/DFHackAPI.cpp b/dfhack/DFHackAPI.cpp index fcaaf4db0..2d649c638 100644 --- a/dfhack/DFHackAPI.cpp +++ b/dfhack/DFHackAPI.cpp @@ -1079,8 +1079,8 @@ bool API::InitReadCreatures( uint32_t &numcreatures ) off.name_nickname_offset = minfo->getOffset("name_nickname"); off.name_words_offset = minfo->getOffset("name_words"); - // HACK: vector correction - off.vector_correct = minfo->getOffset("hacked_vector_start"); + // HACK: vector correction. No longer relevant. + off.vector_correct = 0; d->p_cre = new DfVector (d->p, off.creature_vector, 4); d->creaturesInited = true; diff --git a/dfhack/DFVector.cpp b/dfhack/DFVector.cpp index d03eabacb..4123940ca 100644 --- a/dfhack/DFVector.cpp +++ b/dfhack/DFVector.cpp @@ -33,7 +33,7 @@ DfVector::DfVector(Process * p, uint32_t address, uint32_t _item_size) uint32_t triplet[3]; item_size = _item_size; memory_info * mem = p->getDescriptor(); - uint32_t offs = mem->getOffset("hacked_vector_triplet"); + uint32_t offs = mem->getOffset("vector_triplet"); p->read(address + offs, sizeof(triplet), (uint8_t *) &triplet); start = triplet[0]; diff --git a/examples/veccheck.cpp b/examples/veccheck.cpp index 66c6431c5..ba82b2f87 100644 --- a/examples/veccheck.cpp +++ b/examples/veccheck.cpp @@ -64,29 +64,31 @@ int main (int numargs, const char ** args) DFHack::memory_info* mem = DF.getMemoryInfo(); //const vector * names = mem->getClassIDMapping(); - DumpObjStr0Vector("Inorganics",p,0x16afd04); + DumpObjStr0Vector("Material templates",p, mem->getAddress("mat_templates")); - DumpObjStr0Vector("Organics - all",p,0x16afd1C); + DumpObjStr0Vector("Inorganics",p, mem->getAddress("mat_inorganics")); - DumpObjStr0Vector("Organics - filtered",p,0x16afd34); + DumpObjStr0Vector("Organics - all",p, mem->getAddress("mat_organics_all")); - DumpDWordVector("Some weird numbers",p,0x16afd4C); + DumpObjStr0Vector("Organics - plants",p, mem->getAddress("mat_organics_plants")); - DumpObjStr0Vector("Trees/wood",p,0x16afd64); + DumpDWordVector("Maybe map between all organics and plants",p, mem->getAddress("mat_unk1_numbers")); - DumpDWordVector("More weird numbers",p,0x16afd7C); + DumpObjStr0Vector("Trees/wood",p, mem->getAddress("mat_organics_trees")); - DumpObjStr0Vector("WTF",p,0x16afd7C + 0x18 ); + DumpDWordVector("Maybe map between all organics and trees",p, mem->getAddress("mat_unk2_numbers")); - DumpObjStr0Vector("WTF2",p,0x16afd7C + 0x18 + 0x18); + DumpObjStr0Vector("Body material templates",p, mem->getAddress("mat_body_material_templates")); - DumpObjStr0Vector("WTF3",p,0x16afd7C + 0x18 + 0x18 + 0x18 ); + DumpObjStr0Vector("Body detail plans",p, mem->getAddress("mat_body_detail_plans")); - DumpObjStr0Vector("WTF4",p,0x16afd7C + 0x18 + 0x18 + 0x18 + 0x18); + DumpObjStr0Vector("Bodies",p, mem->getAddress("mat_bodies")); - DumpObjStr0Vector("WTF5",p,0x16afd7C + 0x18 + 0x18 + 0x18 + 0x18 + 0x18); + DumpObjStr0Vector("Bodygloss",p, mem->getAddress("mat_bodygloss")); - DumpObjStr0Vector("Creature types",p,0x16afd7C + 0x18 + 0x18 + 0x18 + 0x18 + 0x18 + 0x18); + DumpObjStr0Vector("Creature variations",p, mem->getAddress("mat_creature_variations")); + + DumpObjStr0Vector("Creature types",p, mem->getAddress("mat_creature_types")); #ifndef LINUX_BUILD diff --git a/output/Memory.xml b/output/Memory.xml index bba958a69..d39ba5400 100644 --- a/output/Memory.xml +++ b/output/Memory.xml @@ -210,6 +210,14 @@ ============ 0x18 0xC + Vector layout in MSVC 9: + DWORD Allocator + DWORD ? + DWORD ? + DWORD Start + DWORD End + DWORD AllocationEnd + 0x1C Position and window dimensions @@ -281,8 +289,27 @@ 0x6D0 0x770 + Materials + ========= + + +
0x16afcec
+
0x16afcec
+
0x16afd04
+
0x16afd1C
+
0x16afd34
+
0x16afd4C
+
0x16afd64
+
0x16afd7C
+
0x16AFD94
+
0x16AFDAC
+
0x16AFDC4
+
0x16AFDDC
+
0x16AFDF4
+
0x16AFE0C
+ + + From 6b42923f6b5b411204fcb3c0a5f89f37e41483ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Sat, 3 Apr 2010 00:04:38 +0200 Subject: [PATCH 14/29] Added back labors, base meta entry is connected to 0.31.01 --- output/Memory.xml | 283 +++++++++++++++++----------------------------- 1 file changed, 105 insertions(+), 178 deletions(-) diff --git a/output/Memory.xml b/output/Memory.xml index d39ba5400..1bcb1bc1e 100644 --- a/output/Memory.xml +++ b/output/Memory.xml @@ -1,184 +1,110 @@ - + - - - - - - - - 0x0 - + + + 0x0 + + ==================================================================== + L A B O R S + ==================================================================== + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 30 + 31 + 32 + 33 + 34 + 35 + 36 + 37 + 38 + 39 + 40 + 41 + 42 + 43 + 44 + 45 + 46 + 47 + 48 + 49 + 50 + 51 + 52 + 53 + 54 + 55 + 56 + 57 + 58 + 59 + 60 + 61 + 62 + 63 + 64 + 65 + + * Labor groups * + 4294967294 + 4294967293 + 4294967292 + 4294967291 + 4294967290 + 4294967289 + 4294967288 + 4294967287 + 4294967286 + 4294967285 + 4294967284 + 4294967283 + ==================================================================== + V -- T A B L E S + (for stonesense) + ==================================================================== + + + + + + - - .,:rsr, :2;,;r2A@@5 @@ -202,7 +128,7 @@ - + 851c1190b6a7b42f2463967623d18575 0x4BB45F99 @@ -280,6 +206,7 @@ Creatures ========= +
0x0166eccc
0x0 0x90 0xF8 From 7678ba7b633e36f2f056666a7914a55a90c34268 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Sat, 3 Apr 2010 00:13:29 +0200 Subject: [PATCH 15/29] Added back skills --- output/Memory.xml | 111 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/output/Memory.xml b/output/Memory.xml index 1bcb1bc1e..d6ffb9ec2 100644 --- a/output/Memory.xml +++ b/output/Memory.xml @@ -10,6 +10,117 @@ 0 0 --> + ==================================================================== + S K I L L S + ==================================================================== + 0 + 1 + 2 + 49 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 22 + 23 + 57 + 71 + 72 + 73 + 74 + 75 + 76 + 77 + 78 + 79 + 80 + 81 + 82 + 83 + 84 + 85 + 24 + 25 + 26 + 67 + 68 + 66 + 65 + 27 + 28 + 29 + 30 + 31 + 32 + 33 + 34 + 35 + 86 + 87 + 88 + 89 + 90 + 91 + 92 + 93 + 94 + 95 + 96 + 97 + 98 + 99 + 100 + 101 + 102 + 103 + 104 + 105 + 38 + 39 + 41 + 42 + 43 + 44 + 50 + 52 + 45 + 46 + 47 + 48 + 70 + 36 + 12 + 69 + 37 + 13 + 14 + 16 + 17 + 18 + 53 + 54 + 55 + 56 + 40 + 51 + 21 + 15 + 58 + 19 + 20 + 106 + 59 + 60 + 61 + 62 + 63 + 64 + ==================================================================== L A B O R S ==================================================================== From ea6c5f726f723e2f7fe5306cbbc8f6f5971304f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Sat, 3 Apr 2010 00:44:17 +0200 Subject: [PATCH 16/29] More stuff! Ridiculous amounts of stuff! --- output/Memory.xml | 1533 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 1530 insertions(+), 3 deletions(-) diff --git a/output/Memory.xml b/output/Memory.xml index d6ffb9ec2..16731cd91 100644 --- a/output/Memory.xml +++ b/output/Memory.xml @@ -4,12 +4,1538 @@ 0x0 + ==================================================================== + T R A I T S + ==================================================================== + ==================================================================== + P R O F E S S I O N S + ==================================================================== + TODO: Parse this and turn it into Profession tags. + Cross-reference with Memory-40d.xml + + ==================================================================== + J O B S + ==================================================================== + TODO: Parse this and turn it into Job tags + ==================================================================== S K I L L S ==================================================================== @@ -435,6 +1961,7 @@ +
From 265034b9d2ad64ac15ef1b908a4db14416c1fff9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Sat, 3 Apr 2010 00:50:24 +0200 Subject: [PATCH 17/29] More stuff to parse. --- output/Memory.xml | 1285 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1285 insertions(+) diff --git a/output/Memory.xml b/output/Memory.xml index 16731cd91..412f73623 100644 --- a/output/Memory.xml +++ b/output/Memory.xml @@ -10,6 +10,1291 @@ + TODO: parse this, turn into Trait tags. Maybe most of it will be same as 40d. + ==================================================================== P R O F E S S I O N S ==================================================================== From 021fb1e0e9154392c62ebd31272a4e9210c92f25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Sat, 3 Apr 2010 01:17:35 +0200 Subject: [PATCH 18/29] Small Memory.xml fixes --- output/Memory.xml | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/output/Memory.xml b/output/Memory.xml index 412f73623..b38aaa0c1 100644 --- a/output/Memory.xml +++ b/output/Memory.xml @@ -3082,6 +3082,8 @@ 0x17f5ac8 0x17f5ad0 + GUI State + =========
0x146e45f
Found addresses: 0x146e45f @@ -3120,7 +3122,7 @@
0x016ad754
0x016ad758
- name struct + Name struct =========== 0x0 0x1C @@ -3128,7 +3130,7 @@ Creatures ========= -
0x0166eccc
+
0x0166ecc4
0x0 0x90 0xF8 @@ -3137,24 +3139,42 @@ 0x114 0x6D0 0x770 + 0x830 Materials ========= +
0x16afcec
0x16afcec
+ +
0x16afd04
+ +
0x16afd1C
+ +
0x16afd34
-
0x16afd4C
+ + +
0x16afd4C
+ +
0x16afd64
-
0x16afd7C
+ + +
0x16afd7C
+ +
0x16AFD94
0x16AFDAC
0x16AFDC4
0x16AFDDC
0x16AFDF4
+ +
0x16AFE0C
SHM initialization (if possible) <-- - */ - g_pProcess->getModuleIndex("Maps",3,d->maps_module); - - if(d->maps_module) + // detach all processes, destroy manager + if (d->pm == 0) { - // supply the module with offsets so it can work with them - Maps::maps_offsets *off = SHMDATA(Maps::maps_offsets); - off->biome_stuffs = d->biome_stuffs; - off->designation_offset = d->designation_offset; - off->map_offset = map_offset; - off->occupancy_offset = d->occupancy_offset; - off->tile_type_offset = d->tile_type_offset; - off->vein_ice_vptr = d->vein_ice_vptr; // FIXME: not necessarily true, the shm server side needs a class lookup >_< - off->vein_mineral_vptr = d->vein_mineral_vptr; // FIXME: not necessarily true, the shm server side needs a class lookup >_< - off->veinvector = d->veinvector; - off->x_count_offset = x_count_offset; - off->y_count_offset = y_count_offset; - off->z_count_offset = z_count_offset; - full_barrier - const uint32_t cmd = Maps::MAP_INIT + (d->maps_module << 16); - g_pProcess->SetAndWait(cmd); - //cerr << "Map acceleration enabled!" << endl; + d->pm = new ProcessEnumerator (d->xml); // FIXME: handle bad XML better } - - // get the map pointer - uint32_t x_array_loc = g_pProcess->readDWord (map_offset); - if (!x_array_loc) + else { - return false; - // FIXME: only throw this due to programmer error, in the other map functions - //throw Error::NoMapLoaded(); + d->pm->purge(); } - - // get the size - uint32_t mx, my, mz; - mx = d->x_block_count = g_pProcess->readDWord (x_count_offset); - my = d->y_block_count = g_pProcess->readDWord (y_count_offset); - mz = d->z_block_count = g_pProcess->readDWord (z_count_offset); - - // test for wrong map dimensions - if (mx == 0 || mx > 48 || my == 0 || my > 48 || mz == 0) + + // find a process (ProcessManager can find multiple when used properly) + if (!d->pm->findProcessess()) { - throw Error::BadMapDimensions(mx, my); + throw Error::NoProcess(); + //cerr << "couldn't find a suitable process" << endl; //return false; } - - // alloc array for pointers to all blocks - d->block = new uint32_t[mx*my*mz]; - uint32_t *temp_x = new uint32_t[mx]; - uint32_t *temp_y = new uint32_t[my]; - uint32_t *temp_z = new uint32_t[mz]; - - g_pProcess->read (x_array_loc, mx * sizeof (uint32_t), (uint8_t *) temp_x); - for (uint32_t x = 0; x < mx; x++) + d->p = (*d->pm) [0]; + if (!d->p->attach()) { - g_pProcess->read (temp_x[x], my * sizeof (uint32_t), (uint8_t *) temp_y); - // y -> map column - for (uint32_t y = 0; y < my; y++) - { - g_pProcess->read (temp_y[y], - mz * sizeof (uint32_t), - (uint8_t *) (d->block + x*my*mz + y*mz)); - } + throw Error::CantAttach(); + //cerr << "couldn't attach to process" << endl; + //return false; // couldn't attach to process, no go } - delete [] temp_x; - delete [] temp_y; - delete [] temp_z; + d->shm_start = d->p->getSHMStart(); + d->offset_descriptor = d->p->getDescriptor(); + // process is attached, everything went just fine... hopefully return true; } -bool API::DestroyMap() -{ - if (d->block != NULL) - { - delete [] d->block; - d->block = NULL; - } - return true; -} -bool API::isValidBlock (uint32_t x, uint32_t y, uint32_t z) +bool API::Detach() { - if ( x >= d->x_block_count || y >= d->y_block_count || z >= d->z_block_count) + if(!d->p) return false; - return d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z] != 0; -} - -uint32_t API::getBlockPtr (uint32_t x, uint32_t y, uint32_t z) -{ - if ( x >= d->x_block_count || y >= d->y_block_count || z >= d->z_block_count) - return 0; - return d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; -} - -bool API::ReadBlock40d(uint32_t x, uint32_t y, uint32_t z, mapblock40d * buffer) -{ - if(d->shm_start && d->maps_module) // ACCELERATE! - { - SHMMAPSHDR->x = x; - SHMMAPSHDR->y = y; - SHMMAPSHDR->z = z; - volatile uint32_t cmd = Maps::MAP_READ_BLOCK_BY_COORDS + (d->maps_module << 16); - if(!g_pProcess->SetAndWait(cmd)) - return false; - memcpy(buffer,SHMDATA(mapblock40d),sizeof(mapblock40d)); - return true; - } - else // plain old block read + if (!d->p->detach()) { - uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; - if (addr) - { - g_pProcess->read (addr + d->tile_type_offset, sizeof (buffer->tiletypes), (uint8_t *) buffer->tiletypes); - g_pProcess->read (addr + d->occupancy_offset, sizeof (buffer->occupancy), (uint8_t *) buffer->occupancy); - g_pProcess->read (addr + d->designation_offset, sizeof (buffer->designation), (uint8_t *) buffer->designation); - g_pProcess->read (addr + d->biome_stuffs, sizeof (buffer->biome_indices), (uint8_t *) buffer->biome_indices); - buffer->origin = addr; - uint32_t addr_of_struct = g_pProcess->readDWord(addr); - buffer->blockflags.whole = g_pProcess->readDWord(addr_of_struct); - return true; - } return false; } -} - - -// 256 * sizeof(uint16_t) -bool API::ReadTileTypes (uint32_t x, uint32_t y, uint32_t z, tiletypes40d *buffer) -{ - uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; - if (addr) - { - g_pProcess->read (addr + d->tile_type_offset, sizeof (tiletypes40d), (uint8_t *) buffer); - return true; - } - return false; -} - -bool API::ReadDirtyBit(uint32_t x, uint32_t y, uint32_t z, bool &dirtybit) -{ - uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; - if(addr) - { - uint32_t addr_of_struct = g_pProcess->readDWord(addr); - dirtybit = g_pProcess->readDWord(addr_of_struct) & 1; - return true; - } - return false; -} - -bool API::WriteDirtyBit(uint32_t x, uint32_t y, uint32_t z, bool dirtybit) -{ - uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; - if (addr) - { - uint32_t addr_of_struct = g_pProcess->readDWord(addr); - uint32_t dirtydword = g_pProcess->readDWord(addr_of_struct); - dirtydword &= 0xFFFFFFFE; - dirtydword |= (uint32_t) dirtybit; - g_pProcess->writeDWord (addr_of_struct, dirtydword); - return true; - } - return false; -} - -/// read/write the block flags -bool API::ReadBlockFlags(uint32_t x, uint32_t y, uint32_t z, t_blockflags &blockflags) -{ - uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; - if(addr) - { - uint32_t addr_of_struct = g_pProcess->readDWord(addr); - blockflags.whole = g_pProcess->readDWord(addr_of_struct); - return true; - } - return false; -} -bool API::WriteBlockFlags(uint32_t x, uint32_t y, uint32_t z, t_blockflags blockflags) -{ - uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; - if (addr) - { - uint32_t addr_of_struct = g_pProcess->readDWord(addr); - g_pProcess->writeDWord (addr_of_struct, blockflags.whole); - return true; - } - return false; -} - -bool API::ReadDesignations (uint32_t x, uint32_t y, uint32_t z, designations40d *buffer) -{ - uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; - if (addr) - { - g_pProcess->read (addr + d->designation_offset, sizeof (designations40d), (uint8_t *) buffer); - return true; - } - return false; -} - - -// 256 * sizeof(uint32_t) -bool API::ReadOccupancy (uint32_t x, uint32_t y, uint32_t z, occupancies40d *buffer) -{ - uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; - if (addr) - { - g_pProcess->read (addr + d->occupancy_offset, sizeof (occupancies40d), (uint8_t *) buffer); - return true; - } - return false; -} - - -// 256 * sizeof(uint16_t) -bool API::WriteTileTypes (uint32_t x, uint32_t y, uint32_t z, tiletypes40d *buffer) -{ - uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; - if (addr) + if (d->pm != NULL) { - g_pProcess->write (addr + d->tile_type_offset, sizeof (tiletypes40d), (uint8_t *) buffer); - return true; + delete d->pm; } - return false; -} - -bool API::getCurrentCursorCreature(uint32_t & creature_index) -{ - if(!d->cursorWindowInited) return false; - creature_index = g_pProcess->readDWord(d->current_cursor_creature_offset); + d->pm = NULL; + d->p = NULL; + d->shm_start = 0; + d->offset_descriptor = NULL; return true; } -// 256 * sizeof(uint32_t) -bool API::WriteDesignations (uint32_t x, uint32_t y, uint32_t z, designations40d *buffer) -{ - uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; - if (addr) - { - g_pProcess->write (addr + d->designation_offset, sizeof (designations40d), (uint8_t *) buffer); - return true; - } - return false; -} -// 256 * sizeof(uint32_t) -bool API::WriteOccupancy (uint32_t x, uint32_t y, uint32_t z, occupancies40d *buffer) +bool API::isAttached() { - uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; - if (addr) - { - g_pProcess->write (addr + d->occupancy_offset, sizeof (occupancies40d), (uint8_t *) buffer); - return true; - } - return false; + return d->p != NULL; } -// FIXME: this is bad. determine the real size! -//16 of them? IDK... there's probably just 7. Reading more doesn't cause errors as it's an array nested inside a block -// 16 * sizeof(uint8_t) -bool API::ReadRegionOffsets (uint32_t x, uint32_t y, uint32_t z, biome_indices40d *buffer) +bool API::Suspend() { - uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; - if (addr) - { - g_pProcess->read (addr + d->biome_stuffs, sizeof (biome_indices40d), (uint8_t *) buffer); - return true; - } - return false; + return d->p->suspend(); } - -// veins of a block, expects empty vein vectors -bool API::ReadVeins(uint32_t x, uint32_t y, uint32_t z, vector & veins, vector & ices) +bool API::AsyncSuspend() { - uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; - veins.clear(); - ices.clear(); - if (addr && d->veinvector && d->veinsize) - { - // veins are stored as a vector of pointers to veins - /*pointer is 4 bytes! we work with a 32bit program here, no matter what architecture we compile khazad for*/ - DfVector p_veins (d->p, addr + d->veinvector, 4); - uint32_t size = p_veins.getSize(); - veins.reserve (size); - - // read all veins - for (uint32_t i = 0; i < size;i++) - { - t_vein v; - t_frozenliquidvein fv; - - // read the vein pointer from the vector - uint32_t temp = * (uint32_t *) p_veins[i]; - uint32_t type = g_pProcess->readDWord(temp); -try_again: - if(type == d->vein_mineral_vptr) - { - // read the vein data (dereference pointer) - g_pProcess->read (temp, sizeof(t_vein), (uint8_t *) &v); - v.address_of = temp; - // store it in the vector - veins.push_back (v); - } - else if(type == d->vein_ice_vptr) - { - // read the ice vein data (dereference pointer) - g_pProcess->read (temp, sizeof(t_frozenliquidvein), (uint8_t *) &fv); - // store it in the vector - ices.push_back (fv); - } - else if(g_pProcess->readClassName(type) == "block_square_event_frozen_liquid") - { - d->vein_ice_vptr = type; - goto try_again; - } - else if(g_pProcess->readClassName(type) == "block_square_event_mineral") - { - d->vein_mineral_vptr = type; - goto try_again; - } - } - return true; - } - return false; + return d->p->asyncSuspend(); } - -// getter for map size -void API::getSize (uint32_t& x, uint32_t& y, uint32_t& z) +bool API::Resume() { - x = d->x_block_count; - y = d->y_block_count; - z = d->z_block_count; + return d->p->resume(); } - -bool API::ReadWoodMatgloss (vector & woods) +bool API::ForceResume() { - - int matgloss_address = d->offset_descriptor->getAddress ("matgloss"); - int matgloss_wood_name_offset = d->offset_descriptor->getOffset("matgloss_wood_name"); - // TODO: find flag for autumnal coloring? - DfVector p_matgloss(d->p, matgloss_address, 4); - - woods.clear(); - - t_matgloss mat; - // TODO: use brown? - mat.fore = 7; - mat.back = 0; - mat.bright = 0; - uint32_t size = p_matgloss.getSize(); - for (uint32_t i = 0; i < size ;i++) - { - // read the matgloss pointer from the vector into temp - uint32_t temp = * (uint32_t *) p_matgloss[i]; - // read the string pointed at by - /* - fill_char_buf(mat.id, d->p->readSTLString(temp)); // reads a C string given an address - */ - d->p->readSTLString (temp, mat.id, 128); - d->p->readSTLString (temp+matgloss_wood_name_offset, mat.name, 128); - woods.push_back (mat); - } - return true; + return d->p->forceresume(); } - -bool API::ReadStoneMatgloss (vector & stones) +bool API::isSuspended() { - memory_info * minfo = d->offset_descriptor; - int matgloss_address = minfo->getAddress ("matgloss"); - int matgloss_offset = minfo->getHexValue ("matgloss_skip"); - int matgloss_colors = minfo->getOffset ("matgloss_stone_color"); - int matgloss_stone_name_offset = minfo->getOffset("matgloss_stone_name"); - - DfVector p_matgloss (d->p, matgloss_address + matgloss_offset, 4); - - uint32_t size = p_matgloss.getSize(); - stones.resize (0); - stones.reserve (size); - for (uint32_t i = 0; i < size;i++) - { - // read the matgloss pointer from the vector into temp - uint32_t temp = * (uint32_t *) p_matgloss[i]; - // read the string pointed at by - t_matgloss mat; - //fill_char_buf(mat.id, d->p->readSTLString(temp)); // reads a C string given an address - d->p->readSTLString (temp, mat.id, 128); - d->p->readSTLString (temp+matgloss_stone_name_offset, mat.name, 128); - mat.fore = (uint8_t) g_pProcess->readWord (temp + matgloss_colors); - mat.back = (uint8_t) g_pProcess->readWord (temp + matgloss_colors + 2); - mat.bright = (uint8_t) g_pProcess->readWord (temp + matgloss_colors + 4); - stones.push_back (mat); - } - return true; + return d->p->isSuspended(); } - -bool API::ReadMetalMatgloss (vector & metals) +void API::ReadRaw (const uint32_t offset, const uint32_t size, uint8_t *target) { - memory_info * minfo = d->offset_descriptor; - int matgloss_address = minfo->getAddress ("matgloss"); - int matgloss_offset = minfo->getHexValue ("matgloss_skip"); - int matgloss_colors = minfo->getOffset ("matgloss_metal_color"); - int matgloss_metal_name_offset = minfo->getOffset("matgloss_metal_name"); - DfVector p_matgloss(d->p, matgloss_address + matgloss_offset * 3, 4); - - metals.clear(); - - for (uint32_t i = 0; i < p_matgloss.getSize();i++) - { - // read the matgloss pointer from the vector into temp - uint32_t temp = * (uint32_t *) p_matgloss[i]; - // read the string pointed at by - t_matgloss mat; - //fill_char_buf(mat.id, d->p->readSTLString(temp)); // reads a C string given an address - d->p->readSTLString (temp, mat.id, 128); - d->p->readSTLString (temp+matgloss_metal_name_offset, mat.name, 128); - mat.fore = (uint8_t) g_pProcess->readWord (temp + matgloss_colors); - mat.back = (uint8_t) g_pProcess->readWord (temp + matgloss_colors + 2); - mat.bright = (uint8_t) g_pProcess->readWord (temp + matgloss_colors + 4); - metals.push_back (mat); - } - return true; + g_pProcess->read (offset, size, target); } -bool API::ReadPlantMatgloss (vector & plants) +void API::WriteRaw (const uint32_t offset, const uint32_t size, uint8_t *source) { - memory_info * minfo = d->offset_descriptor; - int matgloss_address = minfo->getAddress ("matgloss"); - int matgloss_offset = minfo->getHexValue ("matgloss_skip"); - int matgloss_plant_name_offset = minfo->getOffset("matgloss_plant_name"); - DfVector p_matgloss(d->p, matgloss_address + matgloss_offset * 2, 4); - - plants.clear(); - - // TODO: use green? - t_matgloss mat; - mat.fore = 7; - mat.back = 0; - mat.bright = 0; - for (uint32_t i = 0; i < p_matgloss.getSize();i++) - { - // read the matgloss pointer from the vector into temp - uint32_t temp = * (uint32_t *) p_matgloss[i]; - // read the string pointed at by - //fill_char_buf(mat.id, d->p->readSTLString(temp)); // reads a C string given an address - d->p->readSTLString (temp, mat.id, 128); - d->p->readSTLString (temp+matgloss_plant_name_offset, mat.name, 128); - plants.push_back (mat); - } - return true; + g_pProcess->write (offset, size, source); } -bool API::ReadPlantMatgloss (vector & plants) +memory_info *API::getMemoryInfo() { - memory_info * minfo = d->offset_descriptor; - int matgloss_address = minfo->getAddress ("matgloss"); - int matgloss_offset = minfo->getHexValue ("matgloss_skip"); - int matgloss_plant_name_offset = minfo->getOffset("matgloss_plant_name"); - int matgloss_plant_drink_offset = minfo->getOffset("matgloss_plant_drink"); - int matgloss_plant_food_offset = minfo->getOffset("matgloss_plant_food"); - int matgloss_plant_extract_offset = minfo->getOffset("matgloss_plant_extract"); - DfVector p_matgloss(d->p, matgloss_address + matgloss_offset * 2, 4); - - plants.clear(); - - // TODO: use green? - t_matglossPlant mat; - mat.fore = 7; - mat.back = 0; - mat.bright = 0; - for (uint32_t i = 0; i < p_matgloss.getSize();i++) - { - // read the matgloss pointer from the vector into temp - uint32_t temp = * (uint32_t *) p_matgloss[i]; - // read the string pointed at by - //fill_char_buf(mat.id, d->p->readSTLString(temp)); // reads a C string given an address - d->p->readSTLString (temp, mat.id, 128); - d->p->readSTLString (temp+matgloss_plant_name_offset, mat.name, 128); - d->p->readSTLString (temp+matgloss_plant_drink_offset, mat.drink_name, 128); - d->p->readSTLString (temp+matgloss_plant_food_offset, mat.food_name, 128); - d->p->readSTLString (temp+matgloss_plant_extract_offset, mat.extract_name, 128); - - //d->p->readSTLString (temp - plants.push_back (mat); - } - return true; + return d->offset_descriptor; } - -bool API::ReadCreatureMatgloss (vector & creatures) +Process * API::getProcess() { - memory_info * minfo = d->offset_descriptor; - int matgloss_address = minfo->getAddress ("matgloss"); - int matgloss_offset = minfo->getHexValue ("matgloss_skip"); - int matgloss_creature_name_offset = minfo->getOffset("matgloss_creature_name"); - DfVector p_matgloss (d->p, matgloss_address + matgloss_offset * 6, 4); - - creatures.clear(); - - // TODO: use green? - t_matgloss mat; - mat.fore = 7; - mat.back = 0; - mat.bright = 0; - for (uint32_t i = 0; i < p_matgloss.getSize();i++) - { - // read the matgloss pointer from the vector into temp - uint32_t temp = * (uint32_t *) p_matgloss[i]; - // read the string pointed at by - //fill_char_buf(mat.id, d->p->readSTLString(temp)); // reads a C string given an address - d->p->readSTLString (temp, mat.id, 128); - d->p->readSTLString (temp+matgloss_creature_name_offset, mat.name, 128); - creatures.push_back (mat); - } - return true; + return d->p; } - -//vector v_geology[eBiomeCount]; -bool API::ReadGeology (vector < vector >& assign) +DFWindow * API::getWindow() { - memory_info * minfo = d->offset_descriptor; - // get needed addresses and offsets. Now this is what I call crazy. - int region_x_offset = minfo->getAddress ("region_x"); - int region_y_offset = minfo->getAddress ("region_y"); - int region_z_offset = minfo->getAddress ("region_z"); - int world_offset = minfo->getAddress ("world"); - int world_regions_offset = minfo->getOffset ("w_regions_arr"); - int region_size = minfo->getHexValue ("region_size"); - int region_geo_index_offset = minfo->getOffset ("region_geo_index_off"); - int world_geoblocks_offset = minfo->getOffset ("w_geoblocks"); - int world_size_x = minfo->getOffset ("world_size_x"); - int world_size_y = minfo->getOffset ("world_size_y"); - int geolayer_geoblock_offset = minfo->getOffset ("geolayer_geoblock_offset"); - - uint32_t regionX, regionY, regionZ; - uint16_t worldSizeX, worldSizeY; - - // read position of the region inside DF world - g_pProcess->readDWord (region_x_offset, regionX); - g_pProcess->readDWord (region_y_offset, regionY); - g_pProcess->readDWord (region_z_offset, regionZ); - - // get world size - g_pProcess->readWord (world_offset + world_size_x, worldSizeX); - g_pProcess->readWord (world_offset + world_size_y, worldSizeY); - - // get pointer to first part of 2d array of regions - uint32_t regions = g_pProcess->readDWord (world_offset + world_regions_offset); - - // read the geoblock vector - DfVector geoblocks (d->p, world_offset + world_geoblocks_offset, 4); - - // iterate over 8 surrounding regions + local region - for (int i = eNorthWest; i < eBiomeCount; i++) - { - // check bounds, fix them if needed - int bioRX = regionX / 16 + (i % 3) - 1; - if (bioRX < 0) bioRX = 0; - if (bioRX >= worldSizeX) bioRX = worldSizeX - 1; - int bioRY = regionY / 16 + (i / 3) - 1; - if (bioRY < 0) bioRY = 0; - if (bioRY >= worldSizeY) bioRY = worldSizeY - 1; - - // get pointer to column of regions - uint32_t geoX; - g_pProcess->readDWord (regions + bioRX*4, geoX); - - // get index into geoblock vector - uint16_t geoindex; - g_pProcess->readWord (geoX + bioRY*region_size + region_geo_index_offset, geoindex); - - // get the geoblock from the geoblock vector using the geoindex - // read the matgloss pointer from the vector into temp - uint32_t geoblock_off = * (uint32_t *) geoblocks[geoindex]; - - // get the vector with pointer to layers - DfVector geolayers (d->p, geoblock_off + geolayer_geoblock_offset , 4); // let's hope - // make sure we don't load crap - assert (geolayers.getSize() > 0 && geolayers.getSize() <= 16); - - d->v_geology[i].reserve (geolayers.getSize()); - // finally, read the layer matgloss - for (uint32_t j = 0;j < geolayers.getSize();j++) - { - // read pointer to a layer - uint32_t geol_offset = * (uint32_t *) geolayers[j]; - // read word at pointer + 2, store in our geology vectors - d->v_geology[i].push_back (g_pProcess->readWord (geol_offset + 2)); - } - } - assign.clear(); - assign.reserve (eBiomeCount); -// // TODO: clean this up - for (int i = 0; i < eBiomeCount;i++) - { - assign.push_back (d->v_geology[i]); - } - return true; + return d->p->getWindow(); } - +/* // returns number of buildings, expects v_buildingtypes that will later map t_building.type to its name bool API::InitReadBuildings ( uint32_t& numbuildings ) { @@ -1034,86 +366,8 @@ void API::FinishReadVegetation() } d->vegetationInited = false; } - - -bool API::InitReadCreatures( uint32_t &numcreatures ) -{ - if(!d->InitReadNames()) return false; - try - { - memory_info * minfo = d->offset_descriptor; - Creatures::creature_offsets & off = d->creatures; - off.creature_vector = minfo->getAddress ("creatures"); - off.creature_pos_offset = minfo->getOffset ("creature_position"); - off.creature_type_offset = minfo->getOffset ("creature_race"); - off.creature_flags1_offset = minfo->getOffset ("creature_flags1"); - off.creature_flags2_offset = minfo->getOffset ("creature_flags2"); - off.creature_name_offset = minfo->getOffset ("creature_name"); - off.creature_custom_profession_offset = minfo->getOffset ("creature_custom_profession"); - off.creature_profession_offset = minfo->getOffset ("creature_profession"); - off.creature_sex_offset = minfo->getOffset ("creature_sex"); - off.creature_id_offset = minfo->getOffset ("creature_id"); - off.creature_squad_name_offset = minfo->getOffset ("creature_squad_name"); - off.creature_squad_leader_id_offset = minfo->getOffset ("creature_squad_leader_id"); - off.creature_money_offset = minfo->getOffset ("creature_money"); - off.creature_current_job_offset = minfo->getOffset ("creature_current_job"); - off.creature_current_job_id_offset = minfo->getOffset ("current_job_id"); - off.creature_strength_offset = minfo->getOffset ("creature_strength"); - off.creature_agility_offset = minfo->getOffset ("creature_agility"); - off.creature_toughness_offset = minfo->getOffset ("creature_toughness"); - off.creature_skills_offset = minfo->getOffset ("creature_skills"); - off.creature_labors_offset = minfo->getOffset ("creature_labors"); - off.creature_happiness_offset = minfo->getOffset ("creature_happiness"); - off.creature_traits_offset = minfo->getOffset ("creature_traits"); - off.creature_likes_offset = minfo->getOffset("creature_likes"); - off.creature_artifact_name_offset = minfo->getOffset("creature_artifact_name"); - off.creature_mood_offset = minfo->getOffset("creature_mood"); - - off.creature_pregnancy_offset = minfo->getOffset("creature_pregnancy"); - off.creature_blood_max_offset = minfo->getOffset("creature_blood_max"); - off.creature_blood_current_offset = minfo->getOffset("creature_blood_current"); - off.creature_bleed_offset = minfo->getOffset("creature_bleed"); - - // name offsets for the creature module - off.name_firstname_offset = minfo->getOffset("name_firstname"); - off.name_nickname_offset = minfo->getOffset("name_nickname"); - off.name_words_offset = minfo->getOffset("name_words"); - - // HACK: vector correction. No longer relevant. - off.vector_correct = 0; - - d->p_cre = new DfVector (d->p, off.creature_vector, 4); - d->creaturesInited = true; - numcreatures = d->p_cre->getSize(); - - /* - * --> SHM initialization (if possible) <-- - */ - g_pProcess->getModuleIndex("Creatures40d",1,d->creature_module); - - if(d->creature_module) - { - // supply the module with offsets so it can work with them - memcpy(SHMDATA(Creatures::creature_offsets),&d->creatures,sizeof(Creatures::creature_offsets)); - const uint32_t cmd = Creatures::CREATURE_INIT + (d->creature_module << 16); - g_pProcess->SetAndWait(cmd); - //cerr << "Creature acceleration enabled!" << endl; - } - /* - else - { - cerr << "Creature acceleration NOT enabled!" << endl; - } - */ - return true; - } - catch (Error::MissingMemoryDefinition&) - { - d->creaturesInited = false; - numcreatures = 0; - throw; - } -} +*/ +/* bool API::InitReadNotes( uint32_t &numnotes ) { try @@ -1328,104 +582,8 @@ bool API::getItemIndexesInBox(vector &indexes, } return true; } - -bool API::ReadCreature (const int32_t index, t_creature & furball) -{ - if(!d->creaturesInited) return false; - if(d->creature_module) - { - // supply the module with offsets so it can work with them - SHMCREATURESHDR->index = index; - const uint32_t cmd = Creatures::CREATURE_AT_INDEX + (d->creature_module << 16); - g_pProcess->SetAndWait(cmd); - memcpy(&furball,SHMDATA(t_creature),sizeof(t_creature)); - // cerr << "creature read from SHM!" << endl; - return true; - } - // read pointer from vector at position - uint32_t temp = * (uint32_t *) d->p_cre->at (index); - furball.origin = temp; - Creatures::creature_offsets &offs = d->creatures; - //read creature from memory - g_pProcess->read (temp + offs.creature_pos_offset, 3 * sizeof (uint16_t), (uint8_t *) & (furball.x)); // xyz really - g_pProcess->readDWord (temp + offs.creature_type_offset, furball.type); - g_pProcess->readDWord (temp + offs.creature_flags1_offset, furball.flags1.whole); - g_pProcess->readDWord (temp + offs.creature_flags2_offset, furball.flags2.whole); - // names - d->readName(furball.name,temp + offs.creature_name_offset); - d->readName(furball.squad_name, temp + offs.creature_squad_name_offset); - d->readName(furball.artifact_name, temp + offs.creature_artifact_name_offset); - // custom profession - fill_char_buf (furball.custom_profession, d->p->readSTLString (temp + offs.creature_custom_profession_offset)); - - // labors - g_pProcess->read (temp + offs.creature_labors_offset, NUM_CREATURE_LABORS, furball.labors); - // traits - g_pProcess->read (temp + offs.creature_traits_offset, sizeof (uint16_t) * NUM_CREATURE_TRAITS, (uint8_t *) &furball.traits); - // learned skills - DfVector skills (d->p, temp + offs.creature_skills_offset, 4 ); - furball.numSkills = skills.getSize(); - for (uint32_t i = 0; i < furball.numSkills;i++) - { - uint32_t temp2 = * (uint32_t *) skills[i]; - //skills.read(i, (uint8_t *) &temp2); - // a byte: this gives us 256 skills maximum. - furball.skills[i].id = g_pProcess->readByte (temp2); - furball.skills[i].rating = g_pProcess->readByte (temp2 + 4); - furball.skills[i].experience = g_pProcess->readWord (temp2 + 8); - } - // profession - furball.profession = g_pProcess->readByte (temp + offs.creature_profession_offset); - // current job HACK: the job object isn't cleanly represented here - uint32_t jobIdAddr = g_pProcess->readDWord (temp + offs.creature_current_job_offset); - - if (jobIdAddr) - { - furball.current_job.active = true; - furball.current_job.jobId = g_pProcess->readByte (jobIdAddr + offs.creature_current_job_id_offset); - } - else - { - furball.current_job.active = false; - } - - //likes - DfVector likes(d->p, temp + offs.creature_likes_offset, 4); - furball.numLikes = likes.getSize(); - for(uint32_t i = 0;iread(temp2,sizeof(t_like),(uint8_t *) &furball.likes[i]); - } - - furball.mood = (int16_t) g_pProcess->readWord (temp + offs.creature_mood_offset); - - - g_pProcess->readDWord (temp + offs.creature_happiness_offset, furball.happiness); - g_pProcess->readDWord (temp + offs.creature_id_offset, furball.id); - g_pProcess->readDWord (temp + offs.creature_agility_offset, furball.agility); - g_pProcess->readDWord (temp + offs.creature_strength_offset, furball.strength); - g_pProcess->readDWord (temp + offs.creature_toughness_offset, furball.toughness); - g_pProcess->readDWord (temp + offs.creature_money_offset, furball.money); - furball.squad_leader_id = (int32_t) g_pProcess->readDWord (temp + offs.creature_squad_leader_id_offset); - g_pProcess->readByte (temp + offs.creature_sex_offset, furball.sex); - - g_pProcess->readDWord(temp + offs.creature_pregnancy_offset, furball.pregnancy_timer); - furball.blood_max = (int32_t) g_pProcess->readDWord(temp + offs.creature_blood_max_offset); - furball.blood_current = (int32_t) g_pProcess->readDWord(temp + offs.creature_blood_current_offset); - g_pProcess->readDWord(temp + offs.creature_bleed_offset, furball.bleed_rate); - - - return true; -} - -bool API::WriteLabors(const uint32_t index, uint8_t labors[NUM_CREATURE_LABORS]) -{ - if(!d->creaturesInited) return false; - uint32_t temp = * (uint32_t *) d->p_cre->at (index); - WriteRaw(temp + d->creatures.creature_labors_offset, NUM_CREATURE_LABORS, labors); -} - +*/ +/* bool API::InitReadNameTables(vector > & translations , vector > & foreign_languages) //(map< string, vector > & nameTable) { try @@ -1569,208 +727,9 @@ void API::FinishReadNotes() } d->notesInited = false; } - -bool API::Attach() -{ - // detach all processes, destroy manager - if (d->pm == 0) - { - d->pm = new ProcessEnumerator (d->xml); // FIXME: handle bad XML better - } - else - { - d->pm->purge(); - } - - // find a process (ProcessManager can find multiple when used properly) - if (!d->pm->findProcessess()) - { - throw Error::NoProcess(); - //cerr << "couldn't find a suitable process" << endl; - //return false; - } - d->p = (*d->pm) [0]; - if (!d->p->attach()) - { - throw Error::CantAttach(); - //cerr << "couldn't attach to process" << endl; - //return false; // couldn't attach to process, no go - } - d->shm_start = d->p->getSHMStart(); - d->offset_descriptor = d->p->getDescriptor(); - // process is attached, everything went just fine... hopefully - return true; -} - - -bool API::Detach() -{ - if(!d->p) - return false; - if (!d->p->detach()) - { - return false; - } - if (d->pm != NULL) - { - delete d->pm; - } - d->pm = NULL; - d->p = NULL; - d->shm_start = 0; - d->offset_descriptor = NULL; - return true; -} - -bool API::isAttached() -{ - return d->p != NULL; -} - -bool API::Suspend() -{ - return d->p->suspend(); -} -bool API::AsyncSuspend() -{ - return d->p->asyncSuspend(); -} - -bool API::Resume() -{ - return d->p->resume(); -} -bool API::ForceResume() -{ - return d->p->forceresume(); -} -bool API::isSuspended() -{ - return d->p->isSuspended(); -} - -void API::ReadRaw (const uint32_t offset, const uint32_t size, uint8_t *target) -{ - g_pProcess->read (offset, size, target); -} - -void API::WriteRaw (const uint32_t offset, const uint32_t size, uint8_t *source) -{ - g_pProcess->write (offset, size, source); -} - -bool API::InitViewAndCursor() -{ - try - { - d->window_x_offset = d->offset_descriptor->getAddress ("window_x"); - d->window_y_offset = d->offset_descriptor->getAddress ("window_y"); - d->window_z_offset = d->offset_descriptor->getAddress ("window_z"); - d->cursor_xyz_offset = d->offset_descriptor->getAddress ("cursor_xyz"); - d->current_cursor_creature_offset = d->offset_descriptor->getAddress ("current_cursor_creature"); - - d->current_menu_state_offset = d->offset_descriptor->getAddress("current_menu_state"); - d->pause_state_offset = d->offset_descriptor->getAddress ("pause_state"); - d->view_screen_offset = d->offset_descriptor->getAddress ("view_screen"); - - d->cursorWindowInited = true; - return true; - } - catch (Error::MissingMemoryDefinition&) - { - d->cursorWindowInited = false; - throw; - } -} - -bool API::InitViewSize() -{ - try - { - d->window_dims_offset = d->offset_descriptor->getAddress ("window_dims"); - - d->viewSizeInited = true; - return true; - } - catch (Error::MissingMemoryDefinition&) - { - d->viewSizeInited = false; - throw; - } -} - -bool API::getViewCoords (int32_t &x, int32_t &y, int32_t &z) -{ - if (!d->cursorWindowInited) return false; - g_pProcess->readDWord (d->window_x_offset, (uint32_t &) x); - g_pProcess->readDWord (d->window_y_offset, (uint32_t &) y); - g_pProcess->readDWord (d->window_z_offset, (uint32_t &) z); - return true; -} -//FIXME: confine writing of coords to map bounds? -bool API::setViewCoords (const int32_t x, const int32_t y, const int32_t z) -{ - if (!d->cursorWindowInited) return false; - g_pProcess->writeDWord (d->window_x_offset, (uint32_t) x); - g_pProcess->writeDWord (d->window_y_offset, (uint32_t) y); - g_pProcess->writeDWord (d->window_z_offset, (uint32_t) z); - return true; -} - -bool API::getCursorCoords (int32_t &x, int32_t &y, int32_t &z) -{ - if(!d->cursorWindowInited) return false; - int32_t coords[3]; - g_pProcess->read (d->cursor_xyz_offset, 3*sizeof (int32_t), (uint8_t *) coords); - x = coords[0]; - y = coords[1]; - z = coords[2]; - if (x == -30000) return false; - return true; -} -//FIXME: confine writing of coords to map bounds? -bool API::setCursorCoords (const int32_t x, const int32_t y, const int32_t z) -{ - if (!d->cursorWindowInited) return false; - int32_t coords[3] = {x, y, z}; - g_pProcess->write (d->cursor_xyz_offset, 3*sizeof (int32_t), (uint8_t *) coords); - return true; -} -bool API::getWindowSize (int32_t &width, int32_t &height) -{ - if(! d->viewSizeInited) return false; - - int32_t coords[2]; - g_pProcess->read (d->window_dims_offset, 2*sizeof (int32_t), (uint8_t *) coords); - width = coords[0]; - height = coords[1]; - return true; -} -/* -bool API::getClassIDMapping (vector & objecttypes) -{ - if(isAttached()) - { - d->offset_descriptor->getClassIDMapping(objecttypes); - return true; - } - return false; -} */ -memory_info *API::getMemoryInfo() -{ - return d->offset_descriptor; -} -Process * API::getProcess() -{ - return d->p; -} - -DFWindow * API::getWindow() -{ - return d->p->getWindow(); -} +/* bool API::InitReadItems(uint32_t & numitems) { try @@ -1831,39 +790,8 @@ void API::FinishReadItems() } d->itemsInited = false; } - -bool API::ReadPauseState() -{ - // replace with an exception - if(!d->cursorWindowInited) return false; - - uint32_t pauseState = g_pProcess->readDWord (d->pause_state_offset); - return pauseState & 1; -} - -uint32_t API::ReadMenuState() -{ - if(d->cursorWindowInited) - return(g_pProcess->readDWord(d->current_menu_state_offset)); - return false; -} - -bool API::ReadViewScreen (t_viewscreen &screen) -{ - if (!d->cursorWindowInited) return false; - - uint32_t last = g_pProcess->readDWord (d->view_screen_offset); - uint32_t screenAddr = g_pProcess->readDWord (last); - uint32_t nextScreenPtr = g_pProcess->readDWord (last + 4); - while (nextScreenPtr != 0) - { - last = nextScreenPtr; - screenAddr = g_pProcess->readDWord (nextScreenPtr); - nextScreenPtr = g_pProcess->readDWord (nextScreenPtr + 4); - } - return d->offset_descriptor->resolveObjectToClassID (last, screen.type); -} - +*/ +/* bool API::ReadItemTypes(vector< vector< t_itemType > > & itemTypes) { memory_info * minfo = d->offset_descriptor; @@ -1887,4 +815,5 @@ bool API::ReadItemTypes(vector< vector< t_itemType > > & itemTypes) itemTypes.push_back(typesForVec); } return true; -} \ No newline at end of file +} +*/ \ No newline at end of file diff --git a/dfhack/DFProcess-windows-SHM.cpp b/dfhack/DFProcess-windows-SHM.cpp index 983b1f83e..33a1ceb7b 100644 --- a/dfhack/DFProcess-windows-SHM.cpp +++ b/dfhack/DFProcess-windows-SHM.cpp @@ -22,8 +22,8 @@ must not be misrepresented as being the original software. distribution. */ #include "DFCommonInternal.h" -#include "../shmserver/shms.h" -#include "../shmserver/mod-core.h" +#include "shms.h" +#include "mod-core.h" using namespace DFHack; // a full memory barrier! better be safe than sorry. diff --git a/dfhack/depends/md5/CMakeLists.txt b/dfhack/depends/md5/CMakeLists.txt index 842573605..fc4845bd4 100644 --- a/dfhack/depends/md5/CMakeLists.txt +++ b/dfhack/depends/md5/CMakeLists.txt @@ -1,18 +1 @@ -# main project file. use it from a build sub-folder, see COMPILE for details -PROJECT (dfhack-md5) -cmake_minimum_required(VERSION 2.6) - -# disable warning, autosearch -if(COMMAND cmake_policy) - cmake_policy(SET CMP0003 NEW) -endif(COMMAND cmake_policy) - -if("${PROJECT_SOURCE_DIR}" STREQUAL "${PROJECT_BINARY_DIR}") - message(SEND_ERROR "In-source builds are not allowed.") -endif("${PROJECT_SOURCE_DIR}" STREQUAL "${PROJECT_BINARY_DIR}") - -IF(NOT DEFINED CMAKE_BUILD_TYPE) - SET(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.") -ENDIF(NOT DEFINED CMAKE_BUILD_TYPE) - ADD_LIBRARY(dfhack-md5 SHARED md5.cpp md5wrapper.cpp) diff --git a/dfhack/depends/tinyxml/CMakeLists.txt b/dfhack/depends/tinyxml/CMakeLists.txt index 888527046..effdf8945 100644 --- a/dfhack/depends/tinyxml/CMakeLists.txt +++ b/dfhack/depends/tinyxml/CMakeLists.txt @@ -1,18 +1 @@ -# main project file. use it from a build sub-folder, see COMPILE for details -PROJECT (dfhack-tixml) -cmake_minimum_required(VERSION 2.6) - -# disable warning, autosearch -if(COMMAND cmake_policy) - cmake_policy(SET CMP0003 NEW) -endif(COMMAND cmake_policy) - -if("${PROJECT_SOURCE_DIR}" STREQUAL "${PROJECT_BINARY_DIR}") - message(SEND_ERROR "In-source builds are not allowed.") -endif("${PROJECT_SOURCE_DIR}" STREQUAL "${PROJECT_BINARY_DIR}") - -IF(NOT DEFINED CMAKE_BUILD_TYPE) - SET(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.") -ENDIF(NOT DEFINED CMAKE_BUILD_TYPE) - -ADD_LIBRARY(tixml-static SHARED tinystr.cpp tinyxml.cpp tinyxmlerror.cpp tinyxmlparser.cpp) \ No newline at end of file +ADD_LIBRARY(dfhack-tixml SHARED tinystr.cpp tinyxml.cpp tinyxmlerror.cpp tinyxmlparser.cpp) \ No newline at end of file diff --git a/dfhack/include/DFHackAPI.h b/dfhack/include/DFHackAPI.h index 7896cf9b4..70416fa2c 100644 --- a/dfhack/include/DFHackAPI.h +++ b/dfhack/include/DFHackAPI.h @@ -37,15 +37,16 @@ distribution. namespace DFHack { + class APIPrivate; class memory_info; class Process; class DFHACK_EXPORT API { - class Private; - Private * const d; + APIPrivate * const d; public: API(const std::string path_to_xml); ~API(); + /* * Basic control over DF's process state */ @@ -66,236 +67,114 @@ namespace DFHack /// forces resume on Windows. This can be a bad thing with multiple DF tools running! bool ForceResume(); - - /* - * Query the DF's GUI state - */ - ///true if paused, false if not - bool ReadPauseState(); - /// read the DF menu view state (stock screen, unit screen, other screens - bool ReadViewScreen(t_viewscreen &); - /// read the DF menu state (designation menu ect) - uint32_t ReadMenuState(); - - - /* - * Matgloss. next four methods look very similar. I could use two and move the processing one level up... - * I'll keep it like this, even with the code duplication as it will hopefully get more features and separate data types later. - * Yay for nebulous plans for a rock survey tool that tracks how much of which metal could be smelted from available resorces - */ - bool ReadStoneMatgloss(std::vector & output); - bool ReadWoodMatgloss (std::vector & output); - bool ReadMetalMatgloss(std::vector & output); - bool ReadPlantMatgloss(std::vector & output); - bool ReadPlantMatgloss (std::vector & plants); - bool ReadCreatureMatgloss(std::vector & output); - - // read region surroundings, get their vectors of geolayers so we can do translation (or just hand the translation table to the client) - // returns an array of 9 vectors of indices into stone matgloss - /** - Method for reading the geological surrounding of the currently loaded region. - assign is a reference to an array of nine vectors of unsigned words that are to be filled with the data - array is indexed by the BiomeOffset enum - - I omitted resolving the layer matgloss in this API, because it would - introduce overhead by calling some method for each tile. You have to do it - yourself. First get the stuff from ReadGeology and then for each block get - the RegionOffsets. For each tile get the real region from RegionOffsets and - cross-reference it with the geology stuff (region -- array of vectors, depth -- - vector). I'm thinking about turning that Geology stuff into a - two-dimensional array with static size. - - this is the algorithm for applying matgloss: - void DfMap::applyGeoMatgloss(Block * b) - { - // load layer matgloss - for(int x_b = 0; x_b < BLOCK_SIZE; x_b++) - { - for(int y_b = 0; y_b < BLOCK_SIZE; y_b++) - { - int geolayer = b->designation[x_b][y_b].bits.geolayer_index; - int biome = b->designation[x_b][y_b].bits.biome; - b->material[x_b][y_b].type = Mat_Stone; - b->material[x_b][y_b].index = v_geology[b->RegionOffsets[biome]][geolayer]; - } - } - } - */ - bool ReadGeology( std::vector < std::vector >& assign ); - - /* - * BLOCK DATA - */ - /// allocate and read pointers to map blocks - bool InitMap(); - /// destroy the mapblock cache - bool DestroyMap(); - /// get size of the map in tiles - void getSize(uint32_t& x, uint32_t& y, uint32_t& z); - - /** - * Return false/0 on failure, buffer allocated by client app, 256 items long - */ - bool isValidBlock(uint32_t blockx, uint32_t blocky, uint32_t blockz); - /** - * Get the address of a block or 0 if block is not valid - */ - uint32_t getBlockPtr (uint32_t blockx, uint32_t blocky, uint32_t blockz); - - /// read the whole map block at block coords (see DFTypes.h for the block structure) - bool ReadBlock40d(uint32_t blockx, uint32_t blocky, uint32_t blockz, mapblock40d * buffer); - - /// read/write block tile types - bool ReadTileTypes(uint32_t blockx, uint32_t blocky, uint32_t blockz, tiletypes40d *buffer); - bool WriteTileTypes(uint32_t blockx, uint32_t blocky, uint32_t blockz, tiletypes40d *buffer); - /// read/write block designations - bool ReadDesignations(uint32_t blockx, uint32_t blocky, uint32_t blockz, designations40d *buffer); - bool WriteDesignations (uint32_t blockx, uint32_t blocky, uint32_t blockz, designations40d *buffer); - - /// read/write block occupancies - bool ReadOccupancy(uint32_t blockx, uint32_t blocky, uint32_t blockz, occupancies40d *buffer); - bool WriteOccupancy(uint32_t blockx, uint32_t blocky, uint32_t blockz, occupancies40d *buffer); - - /// read/write the block dirty bit - this is used to mark a map block so that DF scans it for designated jobs like digging - bool ReadDirtyBit(uint32_t blockx, uint32_t blocky, uint32_t blockz, bool &dirtybit); - bool WriteDirtyBit(uint32_t blockx, uint32_t blocky, uint32_t blockz, bool dirtybit); - - /// read/write the block flags - bool ReadBlockFlags(uint32_t blockx, uint32_t blocky, uint32_t blockz, t_blockflags &blockflags); - bool WriteBlockFlags(uint32_t blockx, uint32_t blocky, uint32_t blockz, t_blockflags blockflags); + memory_info *getMemoryInfo(); + Process * getProcess(); + DFWindow * getWindow(); - /// read region offsets of a block - used for determining layer stone matgloss - bool ReadRegionOffsets(uint32_t blockx, uint32_t blocky, uint32_t blockz, biome_indices40d *buffer); + /// read/write size bytes of raw data at offset. DANGEROUS, CAN SEGFAULT DF! + void ReadRaw (const uint32_t offset, const uint32_t size, uint8_t *target); + void WriteRaw (const uint32_t offset, const uint32_t size, uint8_t *source); - /// read aggregated veins of a block - bool ReadVeins(uint32_t blockx, uint32_t blocky, uint32_t blockz, std::vector & veins, std::vector & ices); + #include "../modules/Position-proc.h" + #include "../modules/Gui-proc.h" + #include "../modules/Maps-proc.h" + #include "../modules/Materials-proc.h" + #include "../modules/Creatures-proc.h" /* * Constructions (costructed walls, floors, ramps, etc...) */ + /* /// start reading constructions. numconstructions is an output - total constructions present bool InitReadConstructions( uint32_t & numconstructions ); /// read a construiction at index bool ReadConstruction(const int32_t index, t_construction & construction); /// cleanup after reading constructions void FinishReadConstructions(); - +*/ /* * Buildings - also includes zones and stockpiles */ + /* bool InitReadBuildings ( uint32_t & numbuildings ); bool ReadBuilding(const int32_t index, t_building & building); void FinishReadBuildings(); - + */ /* * Effects like mist, dragonfire or dust */ + /* bool InitReadEffects ( uint32_t & numeffects ); bool ReadEffect(const uint32_t index, t_effect_df40d & effect); bool WriteEffect(const uint32_t index, const t_effect_df40d & effect); void FinishReadEffects(); - + */ /* * Trees and shrubs */ + /* bool InitReadVegetation( uint32_t & numplants ); bool ReadVegetation(const int32_t index, t_tree_desc & shrubbery); void FinishReadVegetation(); - - /* - * Creatures - */ - bool InitReadCreatures( uint32_t & numcreatures ); - /** - * Read creatures in a box, starting with index. Returns -1 if no more creatures - * found. Call repeatedly do get all creatures in a specified box (uses tile coords) - */ - int32_t ReadCreatureInBox(const int32_t index, t_creature & furball, - const uint16_t x1, const uint16_t y1,const uint16_t z1, - const uint16_t x2, const uint16_t y2,const uint16_t z2); - bool ReadCreature(const int32_t index, t_creature & furball); - void FinishReadCreatures(); - - /// read/write size bytes of raw data at offset. DANGEROUS, CAN SEGFAULT DF! - void ReadRaw (const uint32_t offset, const uint32_t size, uint8_t *target); - void WriteRaw (const uint32_t offset, const uint32_t size, uint8_t *source); - /// write labors of a creature (for Dwarf Therapist) - bool WriteLabors(const uint32_t index, uint8_t labors[NUM_CREATURE_LABORS]); - + */ + /* * Notes placed by the player */ - + /* /// start reading notes. numnotes is an output - total notes present bool InitReadNotes( uint32_t & numnotes ); /// read note from the note vector at index bool ReadNote(const int32_t index, t_note & note); /// free the note vector void FinishReadNotes(); - + */ /* * Settlements */ + /* bool InitReadSettlements( uint32_t & numsettlements ); bool ReadSettlement(const int32_t index, t_settlement & settlement); bool ReadCurrentSettlement(t_settlement & settlement); void FinishReadSettlements(); - + */ /* * Hotkeys (DF's zoom locations) */ + /* bool InitReadHotkeys( ); bool ReadHotkeys(t_hotkey hotkeys[]); - - /* - * Cursor, and view coords - */ - bool InitViewAndCursor(); - bool getViewCoords (int32_t &x, int32_t &y, int32_t &z); - bool setViewCoords (const int32_t x, const int32_t y, const int32_t z); - - bool getCursorCoords (int32_t &x, int32_t &y, int32_t &z); - bool setCursorCoords (const int32_t x, const int32_t y, const int32_t z); - - /// get the creature vector index of the creature currently under DF' cursor - bool getCurrentCursorCreature (uint32_t & creature_index); - - /* - * Window size in tiles - */ - bool InitViewSize(); - bool getWindowSize(int32_t & width, int32_t & height); - + */ /* * DF translation tables and name translation */ + /* bool InitReadNameTables (std::vector< std::vector > & translations , std::vector< std::vector > & foreign_languages); void FinishReadNameTables(); std::string TranslateName(const t_name & name,const std::vector< std::vector > & translations ,const std::vector< std::vector > & foreign_languages, bool inEnglish=true); - + */ /* * Item reading */ + /* bool InitReadItems(uint32_t & numitems); bool getItemIndexesInBox(std::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); bool ReadItem(const uint32_t index, t_item & item); void FinishReadItems(); - + */ /* * Get the other API parts for raw access */ - memory_info *getMemoryInfo(); - Process * getProcess(); - DFWindow * getWindow(); + /* // FIXME: BAD! bool ReadAllMatgloss(vector< vector< string > > & all); */ - bool ReadItemTypes(std::vector< std::vector< t_itemType > > & itemTypes); + //bool ReadItemTypes(std::vector< std::vector< t_itemType > > & itemTypes); }; } // namespace DFHack #endif // SIMPLEAPI_H_INCLUDED diff --git a/dfhack/modules/Creatures.cpp b/dfhack/modules/Creatures.cpp new file mode 100644 index 000000000..b16c7b2ad --- /dev/null +++ b/dfhack/modules/Creatures.cpp @@ -0,0 +1,206 @@ +/* +www.sourceforge.net/projects/dfhack +Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#include "DFCommonInternal.h" +#include "../private/APIPrivate.h" + +#define SHMCREATURESHDR ((Creatures::shm_creature_hdr *)d->shm_start) + +using namespace DFHack; +/* +bool API::InitReadCreatures( uint32_t &numcreatures ) +{ + if(!d->InitReadNames()) return false; + try + { + memory_info * minfo = d->offset_descriptor; + Creatures::creature_offsets & off = d->creatures; + off.creature_vector = minfo->getAddress ("creatures"); + off.creature_pos_offset = minfo->getOffset ("creature_position"); + off.creature_type_offset = minfo->getOffset ("creature_race"); + off.creature_flags1_offset = minfo->getOffset ("creature_flags1"); + off.creature_flags2_offset = minfo->getOffset ("creature_flags2"); + off.creature_name_offset = minfo->getOffset ("creature_name"); + off.creature_custom_profession_offset = minfo->getOffset ("creature_custom_profession"); + off.creature_profession_offset = minfo->getOffset ("creature_profession"); + off.creature_sex_offset = minfo->getOffset ("creature_sex"); + off.creature_id_offset = minfo->getOffset ("creature_id"); + off.creature_squad_name_offset = minfo->getOffset ("creature_squad_name"); + off.creature_squad_leader_id_offset = minfo->getOffset ("creature_squad_leader_id"); + off.creature_money_offset = minfo->getOffset ("creature_money"); + off.creature_current_job_offset = minfo->getOffset ("creature_current_job"); + off.creature_current_job_id_offset = minfo->getOffset ("current_job_id"); + off.creature_strength_offset = minfo->getOffset ("creature_strength"); + off.creature_agility_offset = minfo->getOffset ("creature_agility"); + off.creature_toughness_offset = minfo->getOffset ("creature_toughness"); + off.creature_skills_offset = minfo->getOffset ("creature_skills"); + off.creature_labors_offset = minfo->getOffset ("creature_labors"); + off.creature_happiness_offset = minfo->getOffset ("creature_happiness"); + off.creature_traits_offset = minfo->getOffset ("creature_traits"); + off.creature_likes_offset = minfo->getOffset("creature_likes"); + off.creature_artifact_name_offset = minfo->getOffset("creature_artifact_name"); + off.creature_mood_offset = minfo->getOffset("creature_mood"); + + off.creature_pregnancy_offset = minfo->getOffset("creature_pregnancy"); + off.creature_blood_max_offset = minfo->getOffset("creature_blood_max"); + off.creature_blood_current_offset = minfo->getOffset("creature_blood_current"); + off.creature_bleed_offset = minfo->getOffset("creature_bleed"); + + // name offsets for the creature module + off.name_firstname_offset = minfo->getOffset("name_firstname"); + off.name_nickname_offset = minfo->getOffset("name_nickname"); + off.name_words_offset = minfo->getOffset("name_words"); + + // HACK: vector correction. No longer relevant. + off.vector_correct = 0; + + d->p_cre = new DfVector (d->p, off.creature_vector, 4); + d->creaturesInited = true; + numcreatures = d->p_cre->getSize(); + + // --> SHM initialization (if possible) <-- + g_pProcess->getModuleIndex("Creatures40d",1,d->creature_module); + + if(d->creature_module) + { + // supply the module with offsets so it can work with them + memcpy(SHMDATA(Creatures::creature_offsets),&d->creatures,sizeof(Creatures::creature_offsets)); + const uint32_t cmd = Creatures::CREATURE_INIT + (d->creature_module << 16); + g_pProcess->SetAndWait(cmd); + } + return true; + } + catch (Error::MissingMemoryDefinition&) + { + d->creaturesInited = false; + numcreatures = 0; + throw; + } +} + +bool API::ReadCreature (const int32_t index, t_creature & furball) +{ + if(!d->creaturesInited) return false; + if(d->creature_module) + { + // supply the module with offsets so it can work with them + SHMCREATURESHDR->index = index; + const uint32_t cmd = Creatures::CREATURE_AT_INDEX + (d->creature_module << 16); + g_pProcess->SetAndWait(cmd); + memcpy(&furball,SHMDATA(t_creature),sizeof(t_creature)); + // cerr << "creature read from SHM!" << endl; + return true; + } + // read pointer from vector at position + uint32_t temp = * (uint32_t *) d->p_cre->at (index); + furball.origin = temp; + Creatures::creature_offsets &offs = d->creatures; + //read creature from memory + g_pProcess->read (temp + offs.creature_pos_offset, 3 * sizeof (uint16_t), (uint8_t *) & (furball.x)); // xyz really + g_pProcess->readDWord (temp + offs.creature_type_offset, furball.type); + g_pProcess->readDWord (temp + offs.creature_flags1_offset, furball.flags1.whole); + g_pProcess->readDWord (temp + offs.creature_flags2_offset, furball.flags2.whole); + // names + d->readName(furball.name,temp + offs.creature_name_offset); + d->readName(furball.squad_name, temp + offs.creature_squad_name_offset); + d->readName(furball.artifact_name, temp + offs.creature_artifact_name_offset); + // custom profession + fill_char_buf (furball.custom_profession, d->p->readSTLString (temp + offs.creature_custom_profession_offset)); + + // labors + g_pProcess->read (temp + offs.creature_labors_offset, NUM_CREATURE_LABORS, furball.labors); + // traits + g_pProcess->read (temp + offs.creature_traits_offset, sizeof (uint16_t) * NUM_CREATURE_TRAITS, (uint8_t *) &furball.traits); + // learned skills + DfVector skills (d->p, temp + offs.creature_skills_offset, 4 ); + furball.numSkills = skills.getSize(); + for (uint32_t i = 0; i < furball.numSkills;i++) + { + uint32_t temp2 = * (uint32_t *) skills[i]; + //skills.read(i, (uint8_t *) &temp2); + // a byte: this gives us 256 skills maximum. + furball.skills[i].id = g_pProcess->readByte (temp2); + furball.skills[i].rating = g_pProcess->readByte (temp2 + 4); + furball.skills[i].experience = g_pProcess->readWord (temp2 + 8); + } + // profession + furball.profession = g_pProcess->readByte (temp + offs.creature_profession_offset); + // current job HACK: the job object isn't cleanly represented here + uint32_t jobIdAddr = g_pProcess->readDWord (temp + offs.creature_current_job_offset); + + if (jobIdAddr) + { + furball.current_job.active = true; + furball.current_job.jobId = g_pProcess->readByte (jobIdAddr + offs.creature_current_job_id_offset); + } + else + { + furball.current_job.active = false; + } + + //likes + DfVector likes(d->p, temp + offs.creature_likes_offset, 4); + furball.numLikes = likes.getSize(); + for(uint32_t i = 0;iread(temp2,sizeof(t_like),(uint8_t *) &furball.likes[i]); + } + + furball.mood = (int16_t) g_pProcess->readWord (temp + offs.creature_mood_offset); + + + g_pProcess->readDWord (temp + offs.creature_happiness_offset, furball.happiness); + g_pProcess->readDWord (temp + offs.creature_id_offset, furball.id); + g_pProcess->readDWord (temp + offs.creature_agility_offset, furball.agility); + g_pProcess->readDWord (temp + offs.creature_strength_offset, furball.strength); + g_pProcess->readDWord (temp + offs.creature_toughness_offset, furball.toughness); + g_pProcess->readDWord (temp + offs.creature_money_offset, furball.money); + furball.squad_leader_id = (int32_t) g_pProcess->readDWord (temp + offs.creature_squad_leader_id_offset); + g_pProcess->readByte (temp + offs.creature_sex_offset, furball.sex); + + g_pProcess->readDWord(temp + offs.creature_pregnancy_offset, furball.pregnancy_timer); + furball.blood_max = (int32_t) g_pProcess->readDWord(temp + offs.creature_blood_max_offset); + furball.blood_current = (int32_t) g_pProcess->readDWord(temp + offs.creature_blood_current_offset); + g_pProcess->readDWord(temp + offs.creature_bleed_offset, furball.bleed_rate); + + + return true; +} + +bool API::WriteLabors(const uint32_t index, uint8_t labors[NUM_CREATURE_LABORS]) +{ + if(!d->creaturesInited) return false; + uint32_t temp = * (uint32_t *) d->p_cre->at (index); + WriteRaw(temp + d->creatures.creature_labors_offset, NUM_CREATURE_LABORS, labors); +} + + +bool API::getCurrentCursorCreature(uint32_t & creature_index) +{ + if(!d->cursorWindowInited) return false; + creature_index = g_pProcess->readDWord(d->current_cursor_creature_offset); + return true; +} +*/ \ No newline at end of file diff --git a/dfhack/modules/Gui.cpp b/dfhack/modules/Gui.cpp new file mode 100644 index 000000000..d7b814e6e --- /dev/null +++ b/dfhack/modules/Gui.cpp @@ -0,0 +1,59 @@ +/* +www.sourceforge.net/projects/dfhack +Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#include "DFCommonInternal.h" +#include "../private/APIPrivate.h" +using namespace DFHack; + +bool API::ReadPauseState() +{ + // replace with an exception + if(!d->cursorWindowInited) return false; + + uint32_t pauseState = g_pProcess->readDWord (d->pause_state_offset); + return pauseState & 1; +} + +uint32_t API::ReadMenuState() +{ + if(d->cursorWindowInited) + return(g_pProcess->readDWord(d->current_menu_state_offset)); + return false; +} + +bool API::ReadViewScreen (t_viewscreen &screen) +{ + if (!d->cursorWindowInited) return false; + + uint32_t last = g_pProcess->readDWord (d->view_screen_offset); + uint32_t screenAddr = g_pProcess->readDWord (last); + uint32_t nextScreenPtr = g_pProcess->readDWord (last + 4); + while (nextScreenPtr != 0) + { + last = nextScreenPtr; + screenAddr = g_pProcess->readDWord (nextScreenPtr); + nextScreenPtr = g_pProcess->readDWord (nextScreenPtr + 4); + } + return d->offset_descriptor->resolveObjectToClassID (last, screen.type); +} diff --git a/dfhack/modules/Maps.cpp b/dfhack/modules/Maps.cpp new file mode 100644 index 000000000..75008851e --- /dev/null +++ b/dfhack/modules/Maps.cpp @@ -0,0 +1,442 @@ +/* +www.sourceforge.net/projects/dfhack +Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#include "DFCommonInternal.h" +#include "../private/APIPrivate.h" + +#define SHMMAPSHDR ((Maps::shm_maps_hdr *)d->shm_start) + +using namespace DFHack; + +/*-----------------------------------* + * Init the mapblock pointer array * + *-----------------------------------*/ +bool API::InitMap() +{ + uint32_t map_offset = d->offset_descriptor->getAddress ("map_data"); + uint32_t x_count_offset = d->offset_descriptor->getAddress ("x_count_block"); + uint32_t y_count_offset = d->offset_descriptor->getAddress ("y_count_block"); + uint32_t z_count_offset = d->offset_descriptor->getAddress ("z_count_block"); + + // get the offsets once here + d->tile_type_offset = d->offset_descriptor->getOffset ("type"); + d->designation_offset = d->offset_descriptor->getOffset ("designation"); + //d->occupancy_offset = d->offset_descriptor->getOffset ("occupancy"); + //d->biome_stuffs = d->offset_descriptor->getOffset ("biome_stuffs"); + + d->veinvector = d->offset_descriptor->getOffset ("v_vein"); + + // these can fail and will be found when looking at the actual veins later + // basically a cache + d->vein_ice_vptr = 0; + d->offset_descriptor->resolveClassnameToVPtr("block_square_event_frozen_liquid", d->vein_ice_vptr); + d->vein_mineral_vptr = 0; + d->offset_descriptor->resolveClassnameToVPtr("block_square_event_mineral",d->vein_mineral_vptr); + + /* + * --> SHM initialization (if possible) <-- + */ + g_pProcess->getModuleIndex("Maps2010",1,d->maps_module); + + if(d->maps_module) + { + // supply the module with offsets so it can work with them + Maps::maps_offsets *off = SHMDATA(Maps::maps_offsets); + off->designation_offset = d->designation_offset; + off->map_offset = map_offset; + off->tile_type_offset = d->tile_type_offset; + off->vein_ice_vptr = d->vein_ice_vptr; // FIXME: not necessarily true, the shm server side needs a class lookup >_< + off->vein_mineral_vptr = d->vein_mineral_vptr; // FIXME: not necessarily true, the shm server side needs a class lookup >_< + off->veinvector = d->veinvector; + off->x_count_offset = x_count_offset; + off->y_count_offset = y_count_offset; + off->z_count_offset = z_count_offset; + full_barrier + const uint32_t cmd = Maps::MAP_INIT + (d->maps_module << 16); + g_pProcess->SetAndWait(cmd); + //cerr << "Map acceleration enabled!" << endl; + } + + // get the map pointer + uint32_t x_array_loc = g_pProcess->readDWord (map_offset); + if (!x_array_loc) + { + return false; + // FIXME: only throw this due to programmer error, in the other map functions + //throw Error::NoMapLoaded(); + } + + // get the size + uint32_t mx, my, mz; + mx = d->x_block_count = g_pProcess->readDWord (x_count_offset); + my = d->y_block_count = g_pProcess->readDWord (y_count_offset); + mz = d->z_block_count = g_pProcess->readDWord (z_count_offset); + + // test for wrong map dimensions + if (mx == 0 || mx > 48 || my == 0 || my > 48 || mz == 0) + { + throw Error::BadMapDimensions(mx, my); + //return false; + } + + // alloc array for pointers to all blocks + d->block = new uint32_t[mx*my*mz]; + uint32_t *temp_x = new uint32_t[mx]; + uint32_t *temp_y = new uint32_t[my]; + uint32_t *temp_z = new uint32_t[mz]; + + g_pProcess->read (x_array_loc, mx * sizeof (uint32_t), (uint8_t *) temp_x); + for (uint32_t x = 0; x < mx; x++) + { + g_pProcess->read (temp_x[x], my * sizeof (uint32_t), (uint8_t *) temp_y); + // y -> map column + for (uint32_t y = 0; y < my; y++) + { + g_pProcess->read (temp_y[y], + mz * sizeof (uint32_t), + (uint8_t *) (d->block + x*my*mz + y*mz)); + } + } + delete [] temp_x; + delete [] temp_y; + delete [] temp_z; + return true; +} + +bool API::DestroyMap() +{ + if (d->block != NULL) + { + delete [] d->block; + d->block = NULL; + } + return true; +} + +bool API::isValidBlock (uint32_t x, uint32_t y, uint32_t z) +{ + if ( x >= d->x_block_count || y >= d->y_block_count || z >= d->z_block_count) + return false; + return d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z] != 0; +} + +uint32_t API::getBlockPtr (uint32_t x, uint32_t y, uint32_t z) +{ + if ( x >= d->x_block_count || y >= d->y_block_count || z >= d->z_block_count) + return 0; + return d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; +} + +bool API::ReadBlock40d(uint32_t x, uint32_t y, uint32_t z, mapblock40d * buffer) +{ + if(d->shm_start && d->maps_module) // ACCELERATE! + { + SHMMAPSHDR->x = x; + SHMMAPSHDR->y = y; + SHMMAPSHDR->z = z; + volatile uint32_t cmd = Maps::MAP_READ_BLOCK_BY_COORDS + (d->maps_module << 16); + if(!g_pProcess->SetAndWait(cmd)) + return false; + memcpy(buffer,SHMDATA(mapblock40d),sizeof(mapblock40d)); + return true; + } + else // plain old block read + { + uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; + if (addr) + { + g_pProcess->read (addr + d->tile_type_offset, sizeof (buffer->tiletypes), (uint8_t *) buffer->tiletypes); + buffer->origin = addr; + uint32_t addr_of_struct = g_pProcess->readDWord(addr); + buffer->blockflags.whole = g_pProcess->readDWord(addr_of_struct); + return true; + } + return false; + } +} + + +// 256 * sizeof(uint16_t) +bool API::ReadTileTypes (uint32_t x, uint32_t y, uint32_t z, tiletypes40d *buffer) +{ + uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; + if (addr) + { + g_pProcess->read (addr + d->tile_type_offset, sizeof (tiletypes40d), (uint8_t *) buffer); + return true; + } + return false; +} + +bool API::ReadDirtyBit(uint32_t x, uint32_t y, uint32_t z, bool &dirtybit) +{ + uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; + if(addr) + { + uint32_t addr_of_struct = g_pProcess->readDWord(addr); + dirtybit = g_pProcess->readDWord(addr_of_struct) & 1; + return true; + } + return false; +} + +bool API::WriteDirtyBit(uint32_t x, uint32_t y, uint32_t z, bool dirtybit) +{ + uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; + if (addr) + { + uint32_t addr_of_struct = g_pProcess->readDWord(addr); + uint32_t dirtydword = g_pProcess->readDWord(addr_of_struct); + dirtydword &= 0xFFFFFFFE; + dirtydword |= (uint32_t) dirtybit; + g_pProcess->writeDWord (addr_of_struct, dirtydword); + return true; + } + return false; +} + +/// read/write the block flags +bool API::ReadBlockFlags(uint32_t x, uint32_t y, uint32_t z, t_blockflags &blockflags) +{ + uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; + if(addr) + { + uint32_t addr_of_struct = g_pProcess->readDWord(addr); + blockflags.whole = g_pProcess->readDWord(addr_of_struct); + return true; + } + return false; +} +bool API::WriteBlockFlags(uint32_t x, uint32_t y, uint32_t z, t_blockflags blockflags) +{ + uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; + if (addr) + { + uint32_t addr_of_struct = g_pProcess->readDWord(addr); + g_pProcess->writeDWord (addr_of_struct, blockflags.whole); + return true; + } + return false; +} + +bool API::ReadDesignations (uint32_t x, uint32_t y, uint32_t z, designations40d *buffer) +{ + uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; + if (addr) + { + g_pProcess->read (addr + d->designation_offset, sizeof (designations40d), (uint8_t *) buffer); + return true; + } + return false; +} + +// 256 * sizeof(uint16_t) +bool API::WriteTileTypes (uint32_t x, uint32_t y, uint32_t z, tiletypes40d *buffer) +{ + uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; + if (addr) + { + g_pProcess->write (addr + d->tile_type_offset, sizeof (tiletypes40d), (uint8_t *) buffer); + return true; + } + return false; +} + + +// 256 * sizeof(uint32_t) +bool API::WriteDesignations (uint32_t x, uint32_t y, uint32_t z, designations40d *buffer) +{ + uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; + if (addr) + { + g_pProcess->write (addr + d->designation_offset, sizeof (designations40d), (uint8_t *) buffer); + return true; + } + return false; +} + +// FIXME: this is bad. determine the real size! +//16 of them? IDK... there's probably just 7. Reading more doesn't cause errors as it's an array nested inside a block +// 16 * sizeof(uint8_t) +/* +bool API::ReadRegionOffsets (uint32_t x, uint32_t y, uint32_t z, biome_indices40d *buffer) +{ + uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; + if (addr) + { + g_pProcess->read (addr + d->biome_stuffs, sizeof (biome_indices40d), (uint8_t *) buffer); + return true; + } + return false; +} +*/ + +// veins of a block, expects empty vein vectors +bool API::ReadVeins(uint32_t x, uint32_t y, uint32_t z, vector & veins, vector & ices) +{ + uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; + veins.clear(); + ices.clear(); + if (addr && d->veinvector) + { + // veins are stored as a vector of pointers to veins + /*pointer is 4 bytes! we work with a 32bit program here, no matter what architecture we compile khazad for*/ + DfVector p_veins (d->p, addr + d->veinvector, 4); + uint32_t size = p_veins.getSize(); + veins.reserve (size); + + // read all veins + for (uint32_t i = 0; i < size;i++) + { + t_vein v; + t_frozenliquidvein fv; + + // read the vein pointer from the vector + uint32_t temp = * (uint32_t *) p_veins[i]; + uint32_t type = g_pProcess->readDWord(temp); +try_again: + if(type == d->vein_mineral_vptr) + { + // read the vein data (dereference pointer) + g_pProcess->read (temp, sizeof(t_vein), (uint8_t *) &v); + v.address_of = temp; + // store it in the vector + veins.push_back (v); + } + else if(type == d->vein_ice_vptr) + { + // read the ice vein data (dereference pointer) + g_pProcess->read (temp, sizeof(t_frozenliquidvein), (uint8_t *) &fv); + // store it in the vector + ices.push_back (fv); + } + else if(g_pProcess->readClassName(type) == "block_square_event_frozen_liquid") + { + d->vein_ice_vptr = type; + goto try_again; + } + else if(g_pProcess->readClassName(type) == "block_square_event_mineral") + { + d->vein_mineral_vptr = type; + goto try_again; + } + } + return true; + } + return false; +} + + +// getter for map size +void API::getSize (uint32_t& x, uint32_t& y, uint32_t& z) +{ + x = d->x_block_count; + y = d->y_block_count; + z = d->z_block_count; +} + +/* +//vector v_geology[eBiomeCount]; +bool API::ReadGeology (vector < vector >& assign) +{ + memory_info * minfo = d->offset_descriptor; + // get needed addresses and offsets. Now this is what I call crazy. + int region_x_offset = minfo->getAddress ("region_x"); + int region_y_offset = minfo->getAddress ("region_y"); + int region_z_offset = minfo->getAddress ("region_z"); + int world_offset = minfo->getAddress ("world"); + int world_regions_offset = minfo->getOffset ("w_regions_arr"); + int region_size = minfo->getHexValue ("region_size"); + int region_geo_index_offset = minfo->getOffset ("region_geo_index_off"); + int world_geoblocks_offset = minfo->getOffset ("w_geoblocks"); + int world_size_x = minfo->getOffset ("world_size_x"); + int world_size_y = minfo->getOffset ("world_size_y"); + int geolayer_geoblock_offset = minfo->getOffset ("geolayer_geoblock_offset"); + + uint32_t regionX, regionY, regionZ; + uint16_t worldSizeX, worldSizeY; + + // read position of the region inside DF world + g_pProcess->readDWord (region_x_offset, regionX); + g_pProcess->readDWord (region_y_offset, regionY); + g_pProcess->readDWord (region_z_offset, regionZ); + + // get world size + g_pProcess->readWord (world_offset + world_size_x, worldSizeX); + g_pProcess->readWord (world_offset + world_size_y, worldSizeY); + + // get pointer to first part of 2d array of regions + uint32_t regions = g_pProcess->readDWord (world_offset + world_regions_offset); + + // read the geoblock vector + DfVector geoblocks (d->p, world_offset + world_geoblocks_offset, 4); + + // iterate over 8 surrounding regions + local region + for (int i = eNorthWest; i < eBiomeCount; i++) + { + // check bounds, fix them if needed + int bioRX = regionX / 16 + (i % 3) - 1; + if (bioRX < 0) bioRX = 0; + if (bioRX >= worldSizeX) bioRX = worldSizeX - 1; + int bioRY = regionY / 16 + (i / 3) - 1; + if (bioRY < 0) bioRY = 0; + if (bioRY >= worldSizeY) bioRY = worldSizeY - 1; + + // get pointer to column of regions + uint32_t geoX; + g_pProcess->readDWord (regions + bioRX*4, geoX); + + // get index into geoblock vector + uint16_t geoindex; + g_pProcess->readWord (geoX + bioRY*region_size + region_geo_index_offset, geoindex); + + // get the geoblock from the geoblock vector using the geoindex + // read the matgloss pointer from the vector into temp + uint32_t geoblock_off = * (uint32_t *) geoblocks[geoindex]; + + // get the vector with pointer to layers + DfVector geolayers (d->p, geoblock_off + geolayer_geoblock_offset , 4); // let's hope + // make sure we don't load crap + assert (geolayers.getSize() > 0 && geolayers.getSize() <= 16); + + d->v_geology[i].reserve (geolayers.getSize()); + // finally, read the layer matgloss + for (uint32_t j = 0;j < geolayers.getSize();j++) + { + // read pointer to a layer + uint32_t geol_offset = * (uint32_t *) geolayers[j]; + // read word at pointer + 2, store in our geology vectors + d->v_geology[i].push_back (g_pProcess->readWord (geol_offset + 2)); + } + } + assign.clear(); + assign.reserve (eBiomeCount); +// // TODO: clean this up + for (int i = 0; i < eBiomeCount;i++) + { + assign.push_back (d->v_geology[i]); + } + return true; +} +*/ \ No newline at end of file diff --git a/dfhack/modules/Materials.cpp b/dfhack/modules/Materials.cpp new file mode 100644 index 000000000..756a95bf8 --- /dev/null +++ b/dfhack/modules/Materials.cpp @@ -0,0 +1,188 @@ +/* +www.sourceforge.net/projects/dfhack +Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#include "DFCommonInternal.h" +#include "../private/APIPrivate.h" +using namespace DFHack; + + + +bool API::ReadWoodMaterials (vector & woods) +{ +/* + int matgloss_address = d->offset_descriptor->getAddress ("matgloss"); + int matgloss_wood_name_offset = d->offset_descriptor->getOffset("matgloss_wood_name"); + // TODO: find flag for autumnal coloring? + DfVector p_matgloss(d->p, matgloss_address, 4); + + woods.clear(); + + t_matgloss mat; + // TODO: use brown? + mat.fore = 7; + mat.back = 0; + mat.bright = 0; + uint32_t size = p_matgloss.getSize(); + for (uint32_t i = 0; i < size ;i++) + { + // read the matgloss pointer from the vector into temp + uint32_t temp = * (uint32_t *) p_matgloss[i]; + // read the string pointed at by + d->p->readSTLString (temp, mat.id, 128); + d->p->readSTLString (temp+matgloss_wood_name_offset, mat.name, 128); + woods.push_back (mat); + } + */ + return true; +} + +bool API::ReadInorganicMaterials (vector & inorganic) +{ + memory_info * minfo = d->offset_descriptor; + int matgloss_address = minfo->getAddress ("mat_inorganics"); + //int matgloss_colors = minfo->getOffset ("material_color"); + //int matgloss_stone_name_offset = minfo->getOffset("matgloss_stone_name"); + + DfVector p_matgloss (d->p, matgloss_address, 4); + + uint32_t size = p_matgloss.getSize(); + inorganic.resize (0); + inorganic.reserve (size); + for (uint32_t i = 0; i < size;i++) + { + // read the matgloss pointer from the vector into temp + uint32_t temp = * (uint32_t *) p_matgloss[i]; + // read the string pointed at by + t_matgloss mat; + //fill_char_buf(mat.id, d->p->readSTLString(temp)); // reads a C string given an address + d->p->readSTLString (temp, mat.id, 128); + /* + d->p->readSTLString (temp+matgloss_stone_name_offset, mat.name, 128); + mat.fore = (uint8_t) g_pProcess->readWord (temp + matgloss_colors); + mat.back = (uint8_t) g_pProcess->readWord (temp + matgloss_colors + 2); + mat.bright = (uint8_t) g_pProcess->readWord (temp + matgloss_colors + 4); + */ + inorganic.push_back (mat); + } + return true; + +} + +bool API::ReadPlantMaterials (vector & plants) +{ + /* + memory_info * minfo = d->offset_descriptor; + int matgloss_address = minfo->getAddress ("matgloss"); + int matgloss_offset = minfo->getHexValue ("matgloss_skip"); + int matgloss_plant_name_offset = minfo->getOffset("matgloss_plant_name"); + DfVector p_matgloss(d->p, matgloss_address + matgloss_offset * 2, 4); + + plants.clear(); + + // TODO: use green? + t_matgloss mat; + mat.fore = 7; + mat.back = 0; + mat.bright = 0; + for (uint32_t i = 0; i < p_matgloss.getSize();i++) + { + // read the matgloss pointer from the vector into temp + uint32_t temp = * (uint32_t *) p_matgloss[i]; + // read the string pointed at by + //fill_char_buf(mat.id, d->p->readSTLString(temp)); // reads a C string given an address + d->p->readSTLString (temp, mat.id, 128); + d->p->readSTLString (temp+matgloss_plant_name_offset, mat.name, 128); + plants.push_back (mat); + } + */ + return true; +} + +bool API::ReadPlantMaterials (vector & plants) +{ + /* + memory_info * minfo = d->offset_descriptor; + int matgloss_address = minfo->getAddress ("matgloss"); + int matgloss_offset = minfo->getHexValue ("matgloss_skip"); + int matgloss_plant_name_offset = minfo->getOffset("matgloss_plant_name"); + int matgloss_plant_drink_offset = minfo->getOffset("matgloss_plant_drink"); + int matgloss_plant_food_offset = minfo->getOffset("matgloss_plant_food"); + int matgloss_plant_extract_offset = minfo->getOffset("matgloss_plant_extract"); + DfVector p_matgloss(d->p, matgloss_address + matgloss_offset * 2, 4); + + plants.clear(); + + // TODO: use green? + t_matglossPlant mat; + mat.fore = 7; + mat.back = 0; + mat.bright = 0; + for (uint32_t i = 0; i < p_matgloss.getSize();i++) + { + // read the matgloss pointer from the vector into temp + uint32_t temp = * (uint32_t *) p_matgloss[i]; + // read the string pointed at by + //fill_char_buf(mat.id, d->p->readSTLString(temp)); // reads a C string given an address + d->p->readSTLString (temp, mat.id, 128); + d->p->readSTLString (temp+matgloss_plant_name_offset, mat.name, 128); + d->p->readSTLString (temp+matgloss_plant_drink_offset, mat.drink_name, 128); + d->p->readSTLString (temp+matgloss_plant_food_offset, mat.food_name, 128); + d->p->readSTLString (temp+matgloss_plant_extract_offset, mat.extract_name, 128); + + //d->p->readSTLString (temp + plants.push_back (mat); + } + */ + return true; +} + +bool API::ReadCreatureTypes (vector & creatures) +{ + /* + memory_info * minfo = d->offset_descriptor; + int matgloss_address = minfo->getAddress ("matgloss"); + int matgloss_offset = minfo->getHexValue ("matgloss_skip"); + int matgloss_creature_name_offset = minfo->getOffset("matgloss_creature_name"); + DfVector p_matgloss (d->p, matgloss_address + matgloss_offset * 6, 4); + + creatures.clear(); + + // TODO: use green? + t_matgloss mat; + mat.fore = 7; + mat.back = 0; + mat.bright = 0; + for (uint32_t i = 0; i < p_matgloss.getSize();i++) + { + // read the matgloss pointer from the vector into temp + uint32_t temp = * (uint32_t *) p_matgloss[i]; + // read the string pointed at by + //fill_char_buf(mat.id, d->p->readSTLString(temp)); // reads a C string given an address + d->p->readSTLString (temp, mat.id, 128); + d->p->readSTLString (temp+matgloss_creature_name_offset, mat.name, 128); + creatures.push_back (mat); + } + */ + return true; +} diff --git a/dfhack/modules/Position.cpp b/dfhack/modules/Position.cpp new file mode 100644 index 000000000..679d1b10c --- /dev/null +++ b/dfhack/modules/Position.cpp @@ -0,0 +1,103 @@ +/* +www.sourceforge.net/projects/dfhack +Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#include "DFCommonInternal.h" +#include "../private/APIPrivate.h" +using namespace DFHack; + +bool API::InitViewAndCursor() +{ + try + { + d->window_x_offset = d->offset_descriptor->getAddress ("window_x"); + d->window_y_offset = d->offset_descriptor->getAddress ("window_y"); + d->window_z_offset = d->offset_descriptor->getAddress ("window_z"); + d->cursor_xyz_offset = d->offset_descriptor->getAddress ("cursor_xyz"); + d->current_cursor_creature_offset = d->offset_descriptor->getAddress ("current_cursor_creature"); + d->window_dims_offset = d->offset_descriptor->getAddress ("window_dims"); + + d->current_menu_state_offset = d->offset_descriptor->getAddress("current_menu_state"); + d->pause_state_offset = d->offset_descriptor->getAddress ("pause_state"); + d->view_screen_offset = d->offset_descriptor->getAddress ("view_screen"); + + d->cursorWindowInited = true; + return true; + } + catch (Error::MissingMemoryDefinition&) + { + d->cursorWindowInited = false; + throw; + } +} + +bool API::getViewCoords (int32_t &x, int32_t &y, int32_t &z) +{ + if (!d->cursorWindowInited) return false; + g_pProcess->readDWord (d->window_x_offset, (uint32_t &) x); + g_pProcess->readDWord (d->window_y_offset, (uint32_t &) y); + g_pProcess->readDWord (d->window_z_offset, (uint32_t &) z); + return true; +} + +//FIXME: confine writing of coords to map bounds? +bool API::setViewCoords (const int32_t x, const int32_t y, const int32_t z) +{ + if (!d->cursorWindowInited) return false; + g_pProcess->writeDWord (d->window_x_offset, (uint32_t) x); + g_pProcess->writeDWord (d->window_y_offset, (uint32_t) y); + g_pProcess->writeDWord (d->window_z_offset, (uint32_t) z); + return true; +} + +bool API::getCursorCoords (int32_t &x, int32_t &y, int32_t &z) +{ + if(!d->cursorWindowInited) return false; + int32_t coords[3]; + g_pProcess->read (d->cursor_xyz_offset, 3*sizeof (int32_t), (uint8_t *) coords); + x = coords[0]; + y = coords[1]; + z = coords[2]; + if (x == -30000) return false; + return true; +} + +//FIXME: confine writing of coords to map bounds? +bool API::setCursorCoords (const int32_t x, const int32_t y, const int32_t z) +{ + if (!d->cursorWindowInited) return false; + int32_t coords[3] = {x, y, z}; + g_pProcess->write (d->cursor_xyz_offset, 3*sizeof (int32_t), (uint8_t *) coords); + return true; +} + +bool API::getWindowSize (int32_t &width, int32_t &height) +{ + if(! d->cursorWindowInited) return false; + + int32_t coords[2]; + g_pProcess->read (d->window_dims_offset, 2*sizeof (int32_t), (uint8_t *) coords); + width = coords[0]; + height = coords[1]; + return true; +} \ No newline at end of file diff --git a/dfhack/private/APIPrivate.h b/dfhack/private/APIPrivate.h new file mode 100644 index 000000000..6c3752a7f --- /dev/null +++ b/dfhack/private/APIPrivate.h @@ -0,0 +1,113 @@ +/* +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. +*/ + +/* +* WARNING: Only include from API modules +*/ + +#ifndef APIPRIVATE_H_INCLUDED +#define APIPRIVATE_H_INCLUDED + +// we connect to those +#include +#include +#include +#include + +#define SHMCMD(num) ((shm_cmd *)d->shm_start)[num]->pingpong +#define SHMHDR ((shm_core_hdr *)d->shm_start) +#define SHMDATA(type) ((type *)(d->shm_start + SHM_HEADER)) + +namespace DFHack +{ + +class APIPrivate +{ +public: + APIPrivate(); + void readName(t_name & name, uint32_t address); + // get the name offsets + bool InitReadNames(); + + #include "../modules/Creatures-data.h" + #include "../modules/Maps-data.h" + #include "../modules/Position-data.h" + #include "../modules/Gui-data.h" + #include "../modules/Materials-data.h" + + uint32_t name_firstname_offset; + uint32_t name_nickname_offset; + uint32_t name_words_offset; + + ProcessEnumerator* pm; + Process* p; + char * shm_start; + memory_info* offset_descriptor; + string xml; + + /* + uint32_t item_material_offset; + + uint32_t note_foreground_offset; + uint32_t note_background_offset; + uint32_t note_name_offset; + uint32_t note_xyz_offset; + uint32_t hotkey_start; + uint32_t hotkey_mode_offset; + uint32_t hotkey_xyz_offset; + uint32_t hotkey_size; + + uint32_t settlement_name_offset; + uint32_t settlement_world_xy_offset; + uint32_t settlement_local_xy_offset; + + uint32_t dwarf_lang_table_offset; + + bool constructionsInited; + bool buildingsInited; + bool effectsInited; + bool vegetationInited; + + + bool itemsInited; + bool notesInited; + bool namesInited; + bool hotkeyInited; + bool settlementsInited; + bool nameTablesInited; + + uint32_t tree_offset; + + DfVector *p_cons; + DfVector *p_bld; + DfVector *p_effect; + DfVector *p_veg; + DfVector *p_itm; + DfVector *p_notes; + DfVector *p_settlements; + DfVector *p_current_settlement; + */ +}; +} +#endif \ No newline at end of file diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 2e3be5a4b..1181c83d6 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -9,17 +9,17 @@ ENDIF(UNIX) ADD_EXECUTABLE(dfattachtest attachtest.cpp) TARGET_LINK_LIBRARIES(dfattachtest dfhack) +# buildingsdump - dump buildings and their raw data filtered by type +#ADD_EXECUTABLE(dfbuildingsdump buildingsdump.cpp) +#TARGET_LINK_LIBRARIES(dfbuildingsdump dfhack) + # a benchmark program, reads the map 1000x ADD_EXECUTABLE(dfexpbench expbench.cpp) TARGET_LINK_LIBRARIES(dfexpbench dfhack) # creaturedump - basic creature dump - a test of the creature related exports -ADD_EXECUTABLE(dfcreaturedump creaturedump.cpp) -TARGET_LINK_LIBRARIES(dfcreaturedump dfhack) - -# buildingsdump - dump buildings and their raw data filtered by type -ADD_EXECUTABLE(dfbuildingsdump buildingsdump.cpp) -TARGET_LINK_LIBRARIES(dfbuildingsdump dfhack) +# ADD_EXECUTABLE(dfcreaturedump creaturedump.cpp) +# TARGET_LINK_LIBRARIES(dfcreaturedump dfhack) # materialtest - just list the first material of each type ADD_EXECUTABLE(dfmaterialtest materialtest.cpp) @@ -35,13 +35,13 @@ ADD_EXECUTABLE(dfsuspend suspendtest.cpp) TARGET_LINK_LIBRARIES(dfsuspend dfhack) # itemdump - dump the item under the cursor -ADD_EXECUTABLE(dfitemdump dfitemdump.cpp) -TARGET_LINK_LIBRARIES(dfitemdump dfhack) +# ADD_EXECUTABLE(dfitemdump dfitemdump.cpp) +# TARGET_LINK_LIBRARIES(dfitemdump dfhack) # hotkeynotedump - dumps the hotkeys and notes for the loaded map # Author: belal -ADD_EXECUTABLE(dfhotkeynotedump hotkeynotedump.cpp) -TARGET_LINK_LIBRARIES(dfhotkeynotedump dfhack) +# ADD_EXECUTABLE(dfhotkeynotedump hotkeynotedump.cpp) +# TARGET_LINK_LIBRARIES(dfhotkeynotedump dfhack) # findnameindexes # Author: belal @@ -50,8 +50,8 @@ TARGET_LINK_LIBRARIES(dfhotkeynotedump dfhack) # settlementdump - dumps the settlements on the loaded map # Author: belal -ADD_EXECUTABLE(dfsettlementdump settlementdump.cpp) -TARGET_LINK_LIBRARIES(dfsettlementdump dfhack) +# ADD_EXECUTABLE(dfsettlementdump settlementdump.cpp) +# TARGET_LINK_LIBRARIES(dfsettlementdump dfhack) # veccheck - read vector values at address ADD_EXECUTABLE(dfvecc veccheck.cpp) @@ -59,67 +59,67 @@ TARGET_LINK_LIBRARIES(dfvecc dfhack) # catsplosion - Makes every cat pregnant, and almost due... # Author: Zhentar -ADD_EXECUTABLE(dfcatsplosion catsplosion.cpp) -TARGET_LINK_LIBRARIES(dfcatsplosion dfhack) - -IF(UNIX) - SET(CURSES_NEED_WIDE "YES") - SET(CURSES_NEED_NCURSES "YES") - find_package(Curses) - - IF(CURSES_FOUND) - if(CURSES_HAVE_NCURSESW_NCURSES_H) - SET(NCURSES_H "ncursesw/ncurses.h") - elseif(CURSES_HAVE_NCURSESW_CURSES_H) - SET(NCURSES_H "ncursesw/curses.h") - elseif(CURSES_HAVE_NCURSESW_H) - SET(NCURSES_H "ncursesw.h") - elseif(CURSES_HAVE_CURSESW_H) - SET(NCURSES_H "cursesw.h") - endif(CURSES_HAVE_NCURSESW_NCURSES_H) - IF(NCURSES_H) - # OPTION( VARIABLE "Description" Initial state) - #OPTION( WITH_FOO "Enable FOO support" ON ) - #OPTION( WITH_BAR "Enable BAR component" OFF ) - #SET( BAZ 18 ) - CONFIGURE_FILE( ${CMAKE_CURRENT_SOURCE_DIR}/fake-curses.h.cmake ${CMAKE_CURRENT_SOURCE_DIR}/fake-curses.h ) - - # veinlook - look at the map... sort of - ADD_EXECUTABLE(dfveinlook veinlook.cpp) - INCLUDE_DIRECTORIES(${CURSES_INCLUDE_DIR}) - TARGET_LINK_LIBRARIES(dfveinlook dfhack ${CURSES_LIBRARIES}) - install(TARGETS - dfveinlook - RUNTIME DESTINATION bin - ) - ENDIF(NCURSES_H) - ELSE(CURSES_FOUND) - MESSAGE(STATUS "Wide-character ncurses library not found - vainlook can't be built") - ENDIF(CURSES_FOUND) -ENDIF(UNIX) +# ADD_EXECUTABLE(dfcatsplosion catsplosion.cpp) +# TARGET_LINK_LIBRARIES(dfcatsplosion dfhack) + +# IF(UNIX) +# SET(CURSES_NEED_WIDE "YES") +# SET(CURSES_NEED_NCURSES "YES") +# find_package(Curses) +# +# IF(CURSES_FOUND) +# if(CURSES_HAVE_NCURSESW_NCURSES_H) +# SET(NCURSES_H "ncursesw/ncurses.h") +# elseif(CURSES_HAVE_NCURSESW_CURSES_H) +# SET(NCURSES_H "ncursesw/curses.h") +# elseif(CURSES_HAVE_NCURSESW_H) +# SET(NCURSES_H "ncursesw.h") +# elseif(CURSES_HAVE_CURSESW_H) +# SET(NCURSES_H "cursesw.h") +# endif(CURSES_HAVE_NCURSESW_NCURSES_H) +# IF(NCURSES_H) +# # OPTION( VARIABLE "Description" Initial state) +# #OPTION( WITH_FOO "Enable FOO support" ON ) +# #OPTION( WITH_BAR "Enable BAR component" OFF ) +# #SET( BAZ 18 ) +# CONFIGURE_FILE( ${CMAKE_CURRENT_SOURCE_DIR}/fake-curses.h.cmake ${CMAKE_CURRENT_SOURCE_DIR}/fake-curses.h ) +# +# # veinlook - look at the map... sort of +# ADD_EXECUTABLE(dfveinlook veinlook.cpp) +# INCLUDE_DIRECTORIES(${CURSES_INCLUDE_DIR}) +# TARGET_LINK_LIBRARIES(dfveinlook dfhack ${CURSES_LIBRARIES}) +# install(TARGETS +# dfveinlook +# RUNTIME DESTINATION bin +# ) +# ENDIF(NCURSES_H) +# ELSE(CURSES_FOUND) +# MESSAGE(STATUS "Wide-character ncurses library not found - vainlook can't be built") +# ENDIF(CURSES_FOUND) +# ENDIF(UNIX) # renamer - change the custom names and professions of creatures, sends keys to # df directly # Author: belal -ADD_EXECUTABLE(dfrenamer renamer.cpp) -TARGET_LINK_LIBRARIES(dfrenamer dfhack) +#ADD_EXECUTABLE(dfrenamer renamer.cpp) +#TARGET_LINK_LIBRARIES(dfrenamer dfhack) IF(UNIX) install(TARGETS dfattachtest -dfexpbench -dfcreaturedump -dfbuildingsdump +#dfexpbench +#dfcreaturedump +#dfbuildingsdump dfmaterialtest dfposition dfsuspend -dfitemdump -dfhotkeynotedump +#dfitemdump +#dfhotkeynotedump #dffindnameindexes -dfsettlementdump -dfrenamer -#dfvecc -dfcatsplosion +#dfsettlementdump +#dfrenamer +dfvecc +#dfcatsplosion RUNTIME DESTINATION bin ) ENDIF(UNIX) \ No newline at end of file diff --git a/examples/materialtest.cpp b/examples/materialtest.cpp index 2337b3fc9..ba82b2f87 100644 --- a/examples/materialtest.cpp +++ b/examples/materialtest.cpp @@ -1,15 +1,51 @@ +// Just show some position data + #include #include #include #include +#include #include using namespace std; #include #include +#include +#include +#include -int main (void) +void DumpObjStr0Vector (const char * name, DFHack::Process *p, uint32_t addr) { + cout << "----==== " << name << " ====----" << endl; + DFHack::DfVector vect(p,addr,4); + for(int i = 0; i < vect.getSize();i++) + { + uint32_t addr = *(uint32_t *) vect[i]; + cout << p->readSTLString(addr) << endl; + } + cout << endl; +} + +void DumpDWordVector (const char * name, DFHack::Process *p, uint32_t addr) +{ + cout << "----==== " << name << " ====----" << endl; + DFHack::DfVector vect(p,addr,4); + for(int i = 0; i < vect.getSize();i++) + { + uint32_t number = *(uint32_t *) vect[i]; + cout << number << endl; + } + cout << endl; +} + +int main (int numargs, const char ** args) +{ + uint32_t addr; + if (numargs == 2) + { + istringstream input (args[1],istringstream::in); + input >> std::hex >> addr; + } DFHack::API DF("Memory.xml"); try { @@ -24,48 +60,40 @@ int main (void) return 1; } - if(!DF.InitMap()) - { - cerr << "No map loaded, it would be unsafe to enumerate materials" << endl; - #ifndef LINUX_BUILD - cin.ignore(); - #endif - return 1; - } - DF.DestroyMap(); + DFHack::Process* p = DF.getProcess(); + DFHack::memory_info* mem = DF.getMemoryInfo(); + //const vector * names = mem->getClassIDMapping(); - vector Woods; - DF.ReadWoodMatgloss(Woods); + DumpObjStr0Vector("Material templates",p, mem->getAddress("mat_templates")); - vector Plants; - DF.ReadPlantMatgloss(Plants); + DumpObjStr0Vector("Inorganics",p, mem->getAddress("mat_inorganics")); - vector Metals; - DF.ReadMetalMatgloss(Metals); + DumpObjStr0Vector("Organics - all",p, mem->getAddress("mat_organics_all")); - vector Stones; - DF.ReadStoneMatgloss(Stones); + DumpObjStr0Vector("Organics - plants",p, mem->getAddress("mat_organics_plants")); - vector CreatureTypes; - DF.ReadCreatureMatgloss(CreatureTypes); + DumpDWordVector("Maybe map between all organics and plants",p, mem->getAddress("mat_unk1_numbers")); + + DumpObjStr0Vector("Trees/wood",p, mem->getAddress("mat_organics_trees")); + + DumpDWordVector("Maybe map between all organics and trees",p, mem->getAddress("mat_unk2_numbers")); + + DumpObjStr0Vector("Body material templates",p, mem->getAddress("mat_body_material_templates")); + + DumpObjStr0Vector("Body detail plans",p, mem->getAddress("mat_body_detail_plans")); + + DumpObjStr0Vector("Bodies",p, mem->getAddress("mat_bodies")); + + DumpObjStr0Vector("Bodygloss",p, mem->getAddress("mat_bodygloss")); + + DumpObjStr0Vector("Creature variations",p, mem->getAddress("mat_creature_variations")); + + DumpObjStr0Vector("Creature types",p, mem->getAddress("mat_creature_types")); - cout << "Wood: " << Woods[0].id << endl; - cout << "Plant: " << Plants[0].id << endl; - cout << "Metal: " << Metals[0].id << endl; - cout << "Stone: " << Stones[0].id << endl; - cout << "Creature: " << CreatureTypes[0].id << endl; - cout << endl; - cout << "Dumping all stones!" << endl; - for(uint32_t i = 0; i < Stones.size();i++) - { - cout << Stones[i].id << "$" << endl;; - } - DF.Detach(); #ifndef LINUX_BUILD cout << "Done. Press any key to continue" << endl; cin.ignore(); #endif - return 0; } diff --git a/examples/position.cpp b/examples/position.cpp index 05bcc4b87..a2120bac7 100644 --- a/examples/position.cpp +++ b/examples/position.cpp @@ -29,27 +29,20 @@ int main (void) if (DF.InitViewAndCursor()) { int32_t x,y,z; + int32_t width,height; + if(DF.getViewCoords(x,y,z)) cout << "view coords: " << x << "/" << y << "/" << z << endl; if(DF.getCursorCoords(x,y,z)) cout << "cursor coords: " << x << "/" << y << "/" << z << endl; + if(DF.getWindowSize(width,height)) + cout << "window size : " << width << " " << height << endl; } else { cerr << "cursor and window parameters are unsupported on your version of DF" << endl; } - if(DF.InitViewSize()) - { - int32_t width,height; - if(DF.getWindowSize(width,height)) - cout << "window size : " << width << " " << height << endl; - } - else - { - cerr << "view size is unsupported on your version of DF" << endl; - } - if(!DF.Detach()) { cerr << "Can't detach from DF" << endl; diff --git a/output/Memory.xml b/output/Memory.xml index b38aaa0c1..f4c52240e 100644 --- a/output/Memory.xml +++ b/output/Memory.xml @@ -3098,7 +3098,7 @@ Map stuff =========
0x016AD718
- 0x10 + 0x08 0x0092 0x029C
0x16AFE0C
+ SHM initialization (if possible) <-- - g_pProcess->getModuleIndex("Creatures40d",1,d->creature_module); + g_pProcess->getModuleIndex("Creatures2010",1,d->creature_module); if(d->creature_module) { // supply the module with offsets so it can work with them - memcpy(SHMDATA(Creatures::creature_offsets),&d->creatures,sizeof(Creatures::creature_offsets)); - const uint32_t cmd = Creatures::CREATURE_INIT + (d->creature_module << 16); + memcpy(SHMDATA(Creatures2010::creature_offsets),&d->creatures,sizeof(Creatures2010::creature_offsets)); + const uint32_t cmd = Creatures2010::CREATURE_INIT + (d->creature_module << 16); g_pProcess->SetAndWait(cmd); } return true; @@ -106,7 +85,7 @@ bool API::ReadCreature (const int32_t index, t_creature & furball) { // supply the module with offsets so it can work with them SHMCREATURESHDR->index = index; - const uint32_t cmd = Creatures::CREATURE_AT_INDEX + (d->creature_module << 16); + const uint32_t cmd = Creatures2010::CREATURE_AT_INDEX + (d->creature_module << 16); g_pProcess->SetAndWait(cmd); memcpy(&furball,SHMDATA(t_creature),sizeof(t_creature)); // cerr << "creature read from SHM!" << endl; @@ -115,24 +94,25 @@ bool API::ReadCreature (const int32_t index, t_creature & furball) // read pointer from vector at position uint32_t temp = * (uint32_t *) d->p_cre->at (index); furball.origin = temp; - Creatures::creature_offsets &offs = d->creatures; + Creatures2010::creature_offsets &offs = d->creatures; //read creature from memory g_pProcess->read (temp + offs.creature_pos_offset, 3 * sizeof (uint16_t), (uint8_t *) & (furball.x)); // xyz really - g_pProcess->readDWord (temp + offs.creature_type_offset, furball.type); + g_pProcess->readDWord (temp + offs.creature_race_offset, furball.type); g_pProcess->readDWord (temp + offs.creature_flags1_offset, furball.flags1.whole); g_pProcess->readDWord (temp + offs.creature_flags2_offset, furball.flags2.whole); // names d->readName(furball.name,temp + offs.creature_name_offset); - d->readName(furball.squad_name, temp + offs.creature_squad_name_offset); + //d->readName(furball.squad_name, temp + offs.creature_squad_name_offset); d->readName(furball.artifact_name, temp + offs.creature_artifact_name_offset); // custom profession - fill_char_buf (furball.custom_profession, d->p->readSTLString (temp + offs.creature_custom_profession_offset)); + //fill_char_buf (furball.custom_profession, d->p->readSTLString (temp + offs.creature_custom_profession_offset)); // labors g_pProcess->read (temp + offs.creature_labors_offset, NUM_CREATURE_LABORS, furball.labors); // traits - g_pProcess->read (temp + offs.creature_traits_offset, sizeof (uint16_t) * NUM_CREATURE_TRAITS, (uint8_t *) &furball.traits); + //g_pProcess->read (temp + offs.creature_traits_offset, sizeof (uint16_t) * NUM_CREATURE_TRAITS, (uint8_t *) &furball.traits); // learned skills + /* DfVector skills (d->p, temp + offs.creature_skills_offset, 4 ); furball.numSkills = skills.getSize(); for (uint32_t i = 0; i < furball.numSkills;i++) @@ -144,9 +124,11 @@ bool API::ReadCreature (const int32_t index, t_creature & furball) furball.skills[i].rating = g_pProcess->readByte (temp2 + 4); furball.skills[i].experience = g_pProcess->readWord (temp2 + 8); } + */ // profession furball.profession = g_pProcess->readByte (temp + offs.creature_profession_offset); // current job HACK: the job object isn't cleanly represented here + /* uint32_t jobIdAddr = g_pProcess->readDWord (temp + offs.creature_current_job_offset); if (jobIdAddr) @@ -158,8 +140,9 @@ bool API::ReadCreature (const int32_t index, t_creature & furball) { furball.current_job.active = false; } - +*/ //likes + /* DfVector likes(d->p, temp + offs.creature_likes_offset, 4); furball.numLikes = likes.getSize(); for(uint32_t i = 0;ireadWord (temp + offs.creature_mood_offset); - +*/ g_pProcess->readDWord (temp + offs.creature_happiness_offset, furball.happiness); g_pProcess->readDWord (temp + offs.creature_id_offset, furball.id); + /* g_pProcess->readDWord (temp + offs.creature_agility_offset, furball.agility); g_pProcess->readDWord (temp + offs.creature_strength_offset, furball.strength); g_pProcess->readDWord (temp + offs.creature_toughness_offset, furball.toughness); g_pProcess->readDWord (temp + offs.creature_money_offset, furball.money); furball.squad_leader_id = (int32_t) g_pProcess->readDWord (temp + offs.creature_squad_leader_id_offset); + */ g_pProcess->readByte (temp + offs.creature_sex_offset, furball.sex); - +/* g_pProcess->readDWord(temp + offs.creature_pregnancy_offset, furball.pregnancy_timer); furball.blood_max = (int32_t) g_pProcess->readDWord(temp + offs.creature_blood_max_offset); furball.blood_current = (int32_t) g_pProcess->readDWord(temp + offs.creature_blood_current_offset); g_pProcess->readDWord(temp + offs.creature_bleed_offset, furball.bleed_rate); - +*/ return true; } - +/* bool API::WriteLabors(const uint32_t index, uint8_t labors[NUM_CREATURE_LABORS]) { if(!d->creaturesInited) return false; uint32_t temp = * (uint32_t *) d->p_cre->at (index); WriteRaw(temp + d->creatures.creature_labors_offset, NUM_CREATURE_LABORS, labors); } - - +*/ +/* bool API::getCurrentCursorCreature(uint32_t & creature_index) { if(!d->cursorWindowInited) return false; creature_index = g_pProcess->readDWord(d->current_cursor_creature_offset); return true; } -*/ \ No newline at end of file +*/ +void API::FinishReadCreatures() +{ + if(d->p_cre) + { + delete d->p_cre; + d->p_cre = 0; + } + d->creaturesInited = false; + //FinishReadNameTables(); +} \ No newline at end of file diff --git a/dfhack/modules/Materials.cpp b/dfhack/modules/Materials.cpp index bdd1ba2d9..b3ee08f2a 100644 --- a/dfhack/modules/Materials.cpp +++ b/dfhack/modules/Materials.cpp @@ -188,9 +188,16 @@ bool API::ReadPlantMaterials (vector & plants) { return ReadNamesOnly(d->p, d->offset_descriptor->getAddress ("mat_organics_plants"), plants ); } - +/* +Gives bad results combined with the creature race field! bool API::ReadCreatureTypes (vector & creatures) { return ReadNamesOnly(d->p, d->offset_descriptor->getAddress ("mat_creature_types"), creatures ); return true; } +*/ +bool API::ReadCreatureTypes (vector & creatures) +{ + return ReadNamesOnly(d->p, d->offset_descriptor->getAddress ("creature_type_vector"), creatures ); + return true; +} diff --git a/dfhack/private/APIPrivate.h b/dfhack/private/APIPrivate.h index 6c3752a7f..930691ad0 100644 --- a/dfhack/private/APIPrivate.h +++ b/dfhack/private/APIPrivate.h @@ -33,7 +33,8 @@ distribution. #include #include #include -#include +// #include +#include #define SHMCMD(num) ((shm_cmd *)d->shm_start)[num]->pingpong #define SHMHDR ((shm_core_hdr *)d->shm_start) diff --git a/dfhack/shm/mod-creature2010.h b/dfhack/shm/mod-creature2010.h new file mode 100644 index 000000000..620d21f9d --- /dev/null +++ b/dfhack/shm/mod-creature2010.h @@ -0,0 +1,87 @@ +/* +www.sourceforge.net/projects/dfhack +Copyright (c) 2009 Petr Mrázek (peterix) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#ifndef MOD_CREATURES2010_H +#define MOD_CREATURES2010_H + +namespace DFHack +{ + namespace Creatures2010 + { + +#define CREATURES2010_VERSION 1 +typedef struct +{ + // creature offsets + uint32_t creature_vector; + uint32_t creature_pos_offset; + uint32_t creature_profession_offset; + uint32_t creature_race_offset; + uint32_t creature_flags1_offset; + uint32_t creature_flags2_offset; + uint32_t creature_name_offset; + uint32_t creature_sex_offset; + uint32_t creature_id_offset; + uint32_t creature_labors_offset; + uint32_t creature_happiness_offset; + uint32_t creature_artifact_name_offset; + // name offsets (needed for reading creature names) + uint32_t name_firstname_offset; + uint32_t name_nickname_offset; + uint32_t name_words_offset; +} creature_offsets; + +typedef struct +{ + bool inited; + creature_offsets offsets; +} creature_modulestate; + +typedef struct +{ + shm_cmd cmd[SHM_MAX_CLIENTS]; // MANDATORY! + // box + uint32_t x; + uint32_t y; + uint32_t z; + uint32_t x2; + uint32_t y2; + uint32_t z2; + // starting index + int32_t index; +} shm_creature_hdr; + +enum CREATURE_COMMAND +{ + CREATURE_INIT = 0, // initialization + CREATURE_FIND_IN_BOX, + CREATURE_AT_INDEX, + NUM_CREATURE_CMDS, +}; +DFPP_module Init(void); + + } +} + +#endif \ No newline at end of file diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 4569dd33f..e430b94b0 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -18,8 +18,8 @@ ADD_EXECUTABLE(dfexpbench expbench.cpp) TARGET_LINK_LIBRARIES(dfexpbench dfhack) # creaturedump - basic creature dump - a test of the creature related exports -# ADD_EXECUTABLE(dfcreaturedump creaturedump.cpp) -# TARGET_LINK_LIBRARIES(dfcreaturedump dfhack) +ADD_EXECUTABLE(dfcreaturedump creaturedump.cpp) +TARGET_LINK_LIBRARIES(dfcreaturedump dfhack) # materialtest - just list the first material of each type ADD_EXECUTABLE(dfmaterialtest materialtest.cpp) diff --git a/examples/creaturedump.cpp b/examples/creaturedump.cpp index 125f802dc..73d9afdcc 100644 --- a/examples/creaturedump.cpp +++ b/examples/creaturedump.cpp @@ -43,8 +43,8 @@ vector< vector > itemTypes; DFHack::memory_info *mem; vector< vector > englishWords; vector< vector > foreignWords; - -likeType printLike(DFHack::t_like like, const matGlosses & mat,const vector< vector > & itemTypes) +/* +likeType printLike40d(DFHack::t_like like, const matGlosses & mat,const vector< vector > & itemTypes) { // The function in DF which prints out the likes is a monster, it is a huge switch statement with tons of options and calls a ton of other functions as well, //so I am not going to try and put all the possibilites here, only the low hanging fruit, with stones and metals, as well as items, //you can easily find good canidates for military duty for instance @@ -147,7 +147,7 @@ likeType printLike(DFHack::t_like like, const matGlosses & mat,const vector< vec } return(FAIL); } - +*/ void printCreature(DFHack::API & DF, const DFHack::t_creature & creature) { @@ -163,13 +163,15 @@ void printCreature(DFHack::API & DF, const DFHack::t_creature & creature) cout << ", nick name: " << creature.name.nickname; addendl = true; } + /* string transName = DF.TranslateName(creature.name,englishWords,foreignWords,false); if(!transName.empty()) { cout << ", trans name: " << transName; addendl=true; } - +*/ + /* cout << ", likes: "; for(uint32_t i = 0;igetProfession(creature.profession) << "(" << (int) creature.profession << ")"; + cout << "profession: " /*<< mem->getProfession(creature.profession) <<*/ "(" << (int) creature.profession << ")"; + /* if(creature.custom_profession[0]) { cout << ", custom profession: " << creature.custom_profession; @@ -192,16 +196,18 @@ void printCreature(DFHack::API & DF, const DFHack::t_creature & creature) { cout << ", current job: " << mem->getJob(creature.current_job.jobId); } + */ cout << endl; - cout << "happiness: " << creature.happiness << ", strength: " << creature.strength << ", agility: " - << creature.agility << ", toughness: " << creature.toughness << ", money: " << creature.money << ", id: " << creature.id; + cout << "happiness: " << creature.happiness /*<< ", strength: " << creature.strength << ", agility: " + << creature.agility << ", toughness: " << creature.toughness << ", money: " << creature.money*/ << ", id: " << creature.id; + /* if(creature.squad_leader_id != -1) { cout << ", squad_leader_id: " << creature.squad_leader_id; } if(creature.mood != -1){ cout << ", mood: " << creature.mood << " "; - } + }*/ cout << ", sex: "; if(creature.sex == 0) { @@ -212,10 +218,11 @@ void printCreature(DFHack::API & DF, const DFHack::t_creature & creature) cout <<"Male"; } cout << endl; - + /* if(creature.pregnancy_timer > 0) cout << "gives birth in " << creature.pregnancy_timer/1200 << " days. "; cout << "Blood: " << creature.blood_current << "/" << creature.blood_max << " bleeding: " << creature.bleed_rate; + */ cout << endl; /* @@ -288,10 +295,12 @@ void printCreature(DFHack::API & DF, const DFHack::t_creature & creature) cout << "from the underworld, "; } cout << endl; - if(creature.flags1.bits.had_mood && (creature.mood == -1 || creature.mood == 8 ) ){ + /* + if(creature.flags1.bits.had_mood && (creature.mood == -1 || creature.mood == 8 ) ) + { string artifact_name = DF.TranslateName(creature.artifact_name,englishWords,foreignWords,false); cout << "artifact: " << artifact_name << endl; - } + }*/ cout << endl; } @@ -329,28 +338,29 @@ int main (void) #endif return 1; } - + /* DF.ReadItemTypes(itemTypes); DF.ReadPlantMatgloss(mat.plantMat); DF.ReadWoodMatgloss(mat.woodMat); DF.ReadStoneMatgloss(mat.stoneMat); DF.ReadMetalMatgloss(mat.metalMat); DF.ReadCreatureMatgloss(mat.creatureMat); - + */ mem = DF.getMemoryInfo(); // get stone matgloss mapping - if(!DF.ReadCreatureMatgloss(creaturestypes)) + if(!DF.ReadCreatureTypes(creaturestypes)) { cerr << "Can't get the creature types." << endl; return 1; } - + /* if(!DF.InitReadNameTables(englishWords,foreignWords)) { cerr << "Can't get name tables" << endl; return 1; } - DF.InitViewAndCursor(); + */ + //DF.InitViewAndCursor(); for(uint32_t i = 0; i < numCreatures; i++) { DFHack::t_creature temp; @@ -361,6 +371,7 @@ int main (void) printCreature(DF,temp); } } + /* uint32_t currentIdx; DFHack::t_creature currentCreature; DF.getCurrentCursorCreature(currentIdx); @@ -368,6 +379,7 @@ int main (void) DF.ReadCreature(currentIdx, currentCreature); printCreature(DF,currentCreature); + */ DF.FinishReadCreatures(); DF.Detach(); #ifndef LINUX_BUILD diff --git a/output/Memory.xml b/output/Memory.xml index 933a4a8a1..227c66a0e 100644 --- a/output/Memory.xml +++ b/output/Memory.xml @@ -3132,6 +3132,8 @@ =========
0x0166ecc4
0x0 + 0x88 + 0x8C 0x90 0xF8 0xFC @@ -3174,8 +3176,10 @@
0x16AFDDC
0x16AFDF4
- +
0x16AFE0C
+ +
0x016AFE58
+ 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 30 + 31 + 32 + 33 + 34 + 35 + 36 + 37 + 38 + 39 + 40 + 41 + 42 + 43 + 44 + 45 + 46 + 47 + 48 + 49 + 50 + 51 + 52 + 53 + 54 + 55 + 56 + 57 + 60 + 62 + 63 + 64 + 65 + 66 + 58 + 59 + 61 + 67 + 68 + 69 + 70 + 71 + 72 + 73 + 74 + 75 + 76 + 77 + 78 + 79 + 80 + 81 + 82 + 83 + 84 + 85 + 86 + 87 + 90 + 91 + 92 + 93 + 94 + 95 + 96 + 97 + 98 + 88 + 89 + 90 ==================================================================== J O B S ==================================================================== From e42bf9265478b308f371d85400b99f60aa3f3784 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Sun, 4 Apr 2010 15:12:06 +0200 Subject: [PATCH 25/29] Disable SHM stuff in Maps --- dfhack/modules/Maps.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dfhack/modules/Maps.cpp b/dfhack/modules/Maps.cpp index 75008851e..d24999ff8 100644 --- a/dfhack/modules/Maps.cpp +++ b/dfhack/modules/Maps.cpp @@ -57,6 +57,7 @@ bool API::InitMap() /* * --> SHM initialization (if possible) <-- */ + /* g_pProcess->getModuleIndex("Maps2010",1,d->maps_module); if(d->maps_module) @@ -77,7 +78,7 @@ bool API::InitMap() g_pProcess->SetAndWait(cmd); //cerr << "Map acceleration enabled!" << endl; } - + */ // get the map pointer uint32_t x_array_loc = g_pProcess->readDWord (map_offset); if (!x_array_loc) From d080e73ac2cf59f0913f7346f35fc8cdbee95ca8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Sun, 4 Apr 2010 15:24:50 +0200 Subject: [PATCH 26/29] Son't build shm --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c7a474ea..84930eaca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,7 +33,7 @@ include_directories (${CMAKE_SOURCE_DIR}/dfhack/depends/tinyxml/) include_directories (${CMAKE_SOURCE_DIR}/dfhack/depends/argstream/) add_subdirectory (dfhack) -add_subdirectory (dfhack/shm) +#add_subdirectory (dfhack/shm) #FIXME: add exports for MSVC #add_subdirectory (dfhack/depends/md5) #add_subdirectory (dfhack/depends/tinyxml) From 500ee6a49bc14dc19a1803b5fae23e75284a97a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Mon, 5 Apr 2010 00:48:19 +0200 Subject: [PATCH 27/29] Modular API --- dfhack/APIPrivate.cpp | 41 ++++-- dfhack/DFHackAPI.cpp | 102 +++++++------- dfhack/DFMemInfo.cpp | 23 +-- dfhack/DFMemInfoManager.cpp | 4 + dfhack/DFProcess-linux-SHM.cpp | 5 + dfhack/DFProcess-linux-wine.cpp | 4 + dfhack/DFProcess-linux.cpp | 4 + dfhack/DFProcess-windows-SHM.cpp | 4 + dfhack/DFProcess-windows.cpp | 4 + dfhack/DFProcessEnumerator-linux.cpp | 4 + dfhack/DFProcessEnumerator-windows.cpp | 4 + dfhack/DFVector.cpp | 3 + dfhack/DFWindow-linux.cpp | 1 + dfhack/DFWindow-windows.cpp | 2 + dfhack/include/DFCommonInternal.h | 4 +- dfhack/include/DFHackAPI.h | 18 ++- dfhack/include/DFTypes.h | 36 ++--- dfhack/include/modules/Creatures.h | 33 +++++ dfhack/include/modules/Gui.h | 34 +++++ dfhack/include/modules/Maps.h | 109 +++++++++++++++ dfhack/include/modules/Materials.h | 53 +++++++ dfhack/include/modules/Position.h | 35 +++++ dfhack/modules/Creatures-data.h | 4 - dfhack/modules/Creatures-proc.h | 15 -- dfhack/modules/Creatures.cpp | 186 ++++++++++++++++++------- dfhack/modules/Gui-data.h | 4 - dfhack/modules/Gui-proc.h | 10 -- dfhack/modules/Gui.cpp | 59 +++++++- dfhack/modules/Maps-data.h | 17 --- dfhack/modules/Maps-proc.h | 80 ----------- dfhack/modules/Maps.cpp | 179 ++++++++++++++---------- dfhack/modules/Materials-data.h | 0 dfhack/modules/Materials-proc.h | 13 -- dfhack/modules/Materials.cpp | 23 ++- dfhack/modules/Position-data.h | 6 - dfhack/modules/Position-proc.h | 17 --- dfhack/modules/Position.cpp | 76 +++++++--- dfhack/private/APIPrivate.h | 157 +++++++++++---------- dfhack/shm/mod-creature2010.h | 2 +- dfhack/shm/mod-creature40d.h | 5 +- dfhack/shm/mod-maps.h | 8 +- dfhack/shm/shms.h | 2 +- examples/creaturedump.cpp | 13 +- examples/expbench.cpp | 14 +- examples/materialtest.cpp | 9 +- examples/position.cpp | 12 +- examples/veinlook.cpp | 42 +++--- tools/prospector.cpp | 20 ++- tools/reveal.cpp | 12 +- 49 files changed, 942 insertions(+), 570 deletions(-) create mode 100644 dfhack/include/modules/Creatures.h create mode 100644 dfhack/include/modules/Gui.h create mode 100644 dfhack/include/modules/Maps.h create mode 100644 dfhack/include/modules/Materials.h create mode 100644 dfhack/include/modules/Position.h delete mode 100644 dfhack/modules/Creatures-data.h delete mode 100644 dfhack/modules/Creatures-proc.h delete mode 100644 dfhack/modules/Gui-data.h delete mode 100644 dfhack/modules/Gui-proc.h delete mode 100644 dfhack/modules/Maps-data.h delete mode 100644 dfhack/modules/Maps-proc.h delete mode 100644 dfhack/modules/Materials-data.h delete mode 100644 dfhack/modules/Materials-proc.h delete mode 100644 dfhack/modules/Position-data.h delete mode 100644 dfhack/modules/Position-proc.h diff --git a/dfhack/APIPrivate.cpp b/dfhack/APIPrivate.cpp index a45be66ec..37b2ce8da 100644 --- a/dfhack/APIPrivate.cpp +++ b/dfhack/APIPrivate.cpp @@ -3,30 +3,45 @@ #include #include #include -using namespace DFHack; - #include "private/APIPrivate.h" +#include "DFMemInfo.h" +#include "DFProcess.h" + +#include "modules/Creatures.h" +#include "modules/Maps.h" +#include "modules/Materials.h" +#include "modules/Position.h" +#include "modules/Gui.h" + +using namespace DFHack; APIPrivate::APIPrivate() { + // init modules + creatures = 0; + maps = 0; + position = 0; + gui = 0; + materials = 0; +} + +APIPrivate::~APIPrivate() +{ + if(creatures) delete creatures; + if(maps) delete maps; + if(position) delete position; + if(gui) delete gui; + if(materials) delete materials; } bool APIPrivate::InitReadNames() { - try - { - name_firstname_offset = offset_descriptor->getOffset("name_firstname"); - name_nickname_offset = offset_descriptor->getOffset("name_nickname"); - name_words_offset = offset_descriptor->getOffset("name_words"); - } - catch(Error::MissingMemoryDefinition) - { - return false; - } + name_firstname_offset = offset_descriptor->getOffset("name_firstname"); + name_nickname_offset = offset_descriptor->getOffset("name_nickname"); + name_words_offset = offset_descriptor->getOffset("name_words"); return true; } - void APIPrivate::readName(t_name & name, uint32_t address) { g_pProcess->readSTLString(address + name_firstname_offset , name.first_name, 128); diff --git a/dfhack/DFHackAPI.cpp b/dfhack/DFHackAPI.cpp index 3655cb9bb..44879c0f4 100644 --- a/dfhack/DFHackAPI.cpp +++ b/dfhack/DFHackAPI.cpp @@ -23,14 +23,26 @@ distribution. */ #include "DFCommonInternal.h" + +#include "DFProcess.h" +#include "DFProcessEnumerator.h" +#include "DFHackAPI.h" +#include "DFError.h" + #include #include #include #include -using namespace DFHack; - #include "private/APIPrivate.h" +#include "modules/Maps.h" +#include "modules/Materials.h" +#include "modules/Position.h" +#include "modules/Gui.h" +#include "modules/Creatures.h" + +using namespace DFHack; + API::API (const string path_to_xml) : d (new APIPrivate()) { @@ -151,6 +163,44 @@ DFWindow * API::getWindow() return d->p->getWindow(); } +/******************************************************************************* + M O D U L E S +*******************************************************************************/ +Creatures * API::getCreatures() +{ + if(!d->creatures) + d->creatures = new Creatures(d); + return d->creatures; +} + +Maps * API::getMaps() +{ + if(!d->maps) + d->maps = new Maps(d); + return d->maps; +} + +Gui * API::getGui() +{ + if(!d->gui) + d->gui = new Gui(d); + return d->gui; +} + +Position * API::getPosition() +{ + if(!d->position) + d->position = new Position(d); + return d->position; +} + +Materials * API::getMaterials() +{ + if(!d->materials) + d->materials = new Materials(d); + return d->materials; +} + /* // returns number of buildings, expects v_buildingtypes that will later map t_building.type to its name bool API::InitReadBuildings ( uint32_t& numbuildings ) @@ -504,53 +554,7 @@ bool API::ReadHotkeys(t_hotkey hotkeys[]) } return true; } -// returns index of creature actually read or -1 if no creature can be found -int32_t API::ReadCreatureInBox (int32_t index, t_creature & furball, - const uint16_t x1, const uint16_t y1, const uint16_t z1, - const uint16_t x2, const uint16_t y2, const uint16_t z2) -{ - if (!d->creaturesInited) return -1; - if(d->creature_module) - { - // supply the module with offsets so it can work with them - SHMCREATURESHDR->index = index; - SHMCREATURESHDR->x = x1; - SHMCREATURESHDR->y = y1; - SHMCREATURESHDR->z = z1; - SHMCREATURESHDR->x2 = x2; - SHMCREATURESHDR->y2 = y2; - SHMCREATURESHDR->z2 = z2; - const uint32_t cmd = Creatures::CREATURE_FIND_IN_BOX + (d->creature_module << 16); - g_pProcess->SetAndWait(cmd); - if(SHMCREATURESHDR->index != -1) - memcpy(&furball,SHMDATA(void),sizeof(t_creature)); - return SHMCREATURESHDR->index; - } - else - { - uint16_t coords[3]; - uint32_t size = d->p_cre->getSize(); - while (uint32_t(index) < size) - { - // read pointer from vector at position - uint32_t temp = * (uint32_t *) d->p_cre->at (index); - g_pProcess->read (temp + d->creatures.creature_pos_offset, 3 * sizeof (uint16_t), (uint8_t *) &coords); - if (coords[0] >= x1 && coords[0] < x2) - { - if (coords[1] >= y1 && coords[1] < y2) - { - if (coords[2] >= z1 && coords[2] < z2) - { - ReadCreature (index, furball); - return index; - } - } - } - index++; - } - return -1; - } -} + bool API::getItemIndexesInBox(vector &indexes, const uint16_t x1, const uint16_t y1, const uint16_t z1, diff --git a/dfhack/DFMemInfo.cpp b/dfhack/DFMemInfo.cpp index 1b3050c58..f15f88c70 100644 --- a/dfhack/DFMemInfo.cpp +++ b/dfhack/DFMemInfo.cpp @@ -23,25 +23,10 @@ distribution. */ #include "DFCommonInternal.h" -/* -#if !defined(NDEBUG) -#define BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING -#define BOOST_MULTI_INDEX_ENABLE_SAFE_MODE -#endif -// really, we don't need it -#define BOOST_MULTI_INDEX_DISABLE_SERIALIZATION - -#include -#include -#include -#include -#include -#include -#include - -using boost::multi_index_container; -using namespace boost::multi_index; -*/ +#include "DFMemInfo.h" +#include "DFError.h" +#include "DFProcess.h" + using namespace DFHack; /* diff --git a/dfhack/DFMemInfoManager.cpp b/dfhack/DFMemInfoManager.cpp index 68060e9ef..3059eca66 100644 --- a/dfhack/DFMemInfoManager.cpp +++ b/dfhack/DFMemInfoManager.cpp @@ -23,6 +23,10 @@ distribution. */ #include "DFCommonInternal.h" +#include "DFMemInfo.h" +#include "DFMemInfoManager.h" +#include "DFError.h" + using namespace DFHack; MemInfoManager::~MemInfoManager() diff --git a/dfhack/DFProcess-linux-SHM.cpp b/dfhack/DFProcess-linux-SHM.cpp index d590dbb22..113149a65 100644 --- a/dfhack/DFProcess-linux-SHM.cpp +++ b/dfhack/DFProcess-linux-SHM.cpp @@ -22,6 +22,11 @@ must not be misrepresented as being the original software. distribution. */ #include "DFCommonInternal.h" +#include "DFProcess.h" +#include "DFWindow.h" +#include "DFMemInfo.h" +#include "DFError.h" + #include #include #include diff --git a/dfhack/DFProcess-linux-wine.cpp b/dfhack/DFProcess-linux-wine.cpp index 89e9f3d2f..253fef3a1 100644 --- a/dfhack/DFProcess-linux-wine.cpp +++ b/dfhack/DFProcess-linux-wine.cpp @@ -22,6 +22,10 @@ must not be misrepresented as being the original software. distribution. */ #include "DFCommonInternal.h" +#include "DFProcess.h" +#include "DFWindow.h" +#include "DFMemInfo.h" +#include "DFError.h" #include #include #include diff --git a/dfhack/DFProcess-linux.cpp b/dfhack/DFProcess-linux.cpp index 616e3fd62..e2bf16af6 100644 --- a/dfhack/DFProcess-linux.cpp +++ b/dfhack/DFProcess-linux.cpp @@ -22,6 +22,10 @@ must not be misrepresented as being the original software. distribution. */ #include "DFCommonInternal.h" +#include "DFProcess.h" +#include "DFWindow.h" +#include "DFMemInfo.h" +#include "DFError.h" #include #include using namespace DFHack; diff --git a/dfhack/DFProcess-windows-SHM.cpp b/dfhack/DFProcess-windows-SHM.cpp index 33a1ceb7b..8e5bf0920 100644 --- a/dfhack/DFProcess-windows-SHM.cpp +++ b/dfhack/DFProcess-windows-SHM.cpp @@ -22,6 +22,10 @@ must not be misrepresented as being the original software. distribution. */ #include "DFCommonInternal.h" +#include "DFProcess.h" +#include "DFWindow.h" +#include "DFMemInfo.h" +#include "DFError.h" #include "shms.h" #include "mod-core.h" using namespace DFHack; diff --git a/dfhack/DFProcess-windows.cpp b/dfhack/DFProcess-windows.cpp index 6bb5acca9..ce3e0a6cf 100644 --- a/dfhack/DFProcess-windows.cpp +++ b/dfhack/DFProcess-windows.cpp @@ -22,6 +22,10 @@ must not be misrepresented as being the original software. distribution. */ #include "DFCommonInternal.h" +#include "DFProcess.h" +#include "DFWindow.h" +#include "DFMemInfo.h" +#include "DFError.h" using namespace DFHack; class NormalProcess::Private diff --git a/dfhack/DFProcessEnumerator-linux.cpp b/dfhack/DFProcessEnumerator-linux.cpp index 6efb57e68..19103c1f3 100644 --- a/dfhack/DFProcessEnumerator-linux.cpp +++ b/dfhack/DFProcessEnumerator-linux.cpp @@ -23,6 +23,10 @@ distribution. */ #include "DFCommonInternal.h" +#include "DFProcessEnumerator.h" +#include "DFProcess.h" +#include "DFMemInfo.h" +#include "DFMemInfoManager.h" #include #include #include diff --git a/dfhack/DFProcessEnumerator-windows.cpp b/dfhack/DFProcessEnumerator-windows.cpp index 7e3c095e8..da42ebd50 100644 --- a/dfhack/DFProcessEnumerator-windows.cpp +++ b/dfhack/DFProcessEnumerator-windows.cpp @@ -23,6 +23,10 @@ distribution. */ #include "DFCommonInternal.h" +#include "DFProcessEnumerator.h" +#include "DFProcess.h" +#include "DFMemInfo.h" +#include "DFMemInfoManager.h" using namespace DFHack; /// HACK: global variables (only one process can be attached at the same time.) diff --git a/dfhack/DFVector.cpp b/dfhack/DFVector.cpp index 4123940ca..61c33c30c 100644 --- a/dfhack/DFVector.cpp +++ b/dfhack/DFVector.cpp @@ -24,6 +24,9 @@ distribution. #include "Tranquility.h" #include "DFCommonInternal.h" +#include "DFVector.h" +#include "DFMemInfo.h" +#include "DFProcess.h" using namespace DFHack; diff --git a/dfhack/DFWindow-linux.cpp b/dfhack/DFWindow-linux.cpp index 99880da44..bffe99de6 100644 --- a/dfhack/DFWindow-linux.cpp +++ b/dfhack/DFWindow-linux.cpp @@ -22,6 +22,7 @@ must not be misrepresented as being the original software. distribution. */ #include "DFCommonInternal.h" +#include "DFWindow.h" #include //need for X11 functions #include diff --git a/dfhack/DFWindow-windows.cpp b/dfhack/DFWindow-windows.cpp index 1fc100555..78e4ffc62 100644 --- a/dfhack/DFWindow-windows.cpp +++ b/dfhack/DFWindow-windows.cpp @@ -23,6 +23,8 @@ distribution. */ #include "DFCommonInternal.h" +#include "DFWindow.h" +#include "DFProcess.h" using namespace DFHack; // should always reflect the enum in DFkeys.h diff --git a/dfhack/include/DFCommonInternal.h b/dfhack/include/DFCommonInternal.h index 394333ea5..255dde145 100644 --- a/dfhack/include/DFCommonInternal.h +++ b/dfhack/include/DFCommonInternal.h @@ -77,6 +77,7 @@ namespace DFHack # define BUILD_DFHACK_LIB #endif +/* #include "DFTypes.h" //#include "DFDataModel.h" #include "DFProcess.h" @@ -86,13 +87,14 @@ namespace DFHack #include "DFVector.h" #include "DFMemInfo.h" #include "DFError.h" +*/ #include #include #include #include -#include "DFHackAPI.h" +//#include "DFHackAPI.h" #define _QUOTEME(x) #x #define QUOT(x) _QUOTEME(x) diff --git a/dfhack/include/DFHackAPI.h b/dfhack/include/DFHackAPI.h index 70416fa2c..6349f083d 100644 --- a/dfhack/include/DFHackAPI.h +++ b/dfhack/include/DFHackAPI.h @@ -40,6 +40,14 @@ namespace DFHack class APIPrivate; class memory_info; class Process; + + // modules + class Maps; + class Creatures; + class Position; + class Gui; + class Materials; + class DFHACK_EXPORT API { APIPrivate * const d; @@ -76,11 +84,11 @@ namespace DFHack void ReadRaw (const uint32_t offset, const uint32_t size, uint8_t *target); void WriteRaw (const uint32_t offset, const uint32_t size, uint8_t *source); - #include "../modules/Position-proc.h" - #include "../modules/Gui-proc.h" - #include "../modules/Maps-proc.h" - #include "../modules/Materials-proc.h" - #include "../modules/Creatures-proc.h" + Creatures * getCreatures(); + Maps * getMaps(); + Gui * getGui(); + Position * getPosition(); + Materials * getMaterials(); /* * Constructions (costructed walls, floors, ramps, etc...) diff --git a/dfhack/include/DFTypes.h b/dfhack/include/DFTypes.h index daa713039..f9ba70cd5 100644 --- a/dfhack/include/DFTypes.h +++ b/dfhack/include/DFTypes.h @@ -53,26 +53,6 @@ struct junk_fill */ }; -struct t_matgloss -{ - char id[128]; //the id in the raws - uint8_t fore; // Annoyingly the offset for this differs between types - uint8_t back; - uint8_t bright; - char name[128]; //this is the name displayed ingame -}; - -struct t_matglossPlant -{ - char id[128]; //the id in the raws - uint8_t fore; // Annoyingly the offset for this differs between types - uint8_t back; - uint8_t bright; - char name[128]; //this is the name displayed ingame - char drink_name[128]; //the name this item becomes a drink - char food_name[128]; - char extract_name[128]; -}; /* struct t_vein { @@ -548,12 +528,12 @@ CREATURE //#pragma pack(push,4) struct t_name { - char first_name[128]; - char nickname[128]; - int32_t words[7]; - uint16_t parts_of_speech[7]; - uint32_t language; - bool has_name; + char first_name[128]; + char nickname[128]; + int32_t words[7]; + uint16_t parts_of_speech[7]; + uint32_t language; + bool has_name; }; struct t_skill @@ -589,8 +569,8 @@ struct t_creature t_creaturflags1 flags1; t_creaturflags2 flags2; t_name name; - t_name squad_name; - t_name artifact_name; + t_name squad_name; + t_name artifact_name; uint8_t profession; char custom_profession[128]; // enabled labors diff --git a/dfhack/include/modules/Creatures.h b/dfhack/include/modules/Creatures.h new file mode 100644 index 000000000..a701eaef7 --- /dev/null +++ b/dfhack/include/modules/Creatures.h @@ -0,0 +1,33 @@ +#ifndef CL_MOD_CREATURES +#define CL_MOD_CREATURES +/* +* Creatures +*/ +#include "Export.h" +namespace DFHack +{ + class APIPrivate; + struct t_creature; + class DFHACK_EXPORT Creatures + { + public: + Creatures(DFHack::APIPrivate * d); + ~Creatures(); + bool Start( uint32_t & numCreatures); + bool Finish(); + + // Read creatures in a box, starting with index. Returns -1 if no more creatures + // found. Call repeatedly do get all creatures in a specified box (uses tile coords) + int32_t ReadCreatureInBox(const int32_t index, t_creature & furball, + const uint16_t x1, const uint16_t y1,const uint16_t z1, + const uint16_t x2, const uint16_t y2,const uint16_t z2); + bool ReadCreature(const int32_t index, t_creature & furball); + /// write labors of a creature (for Dwarf Therapist) + //bool WriteLabors(const uint32_t index, uint8_t labors[NUM_CREATURE_LABORS]); + + private: + struct Private; + Private *d; + }; +} +#endif \ No newline at end of file diff --git a/dfhack/include/modules/Gui.h b/dfhack/include/modules/Gui.h new file mode 100644 index 000000000..ab342e77a --- /dev/null +++ b/dfhack/include/modules/Gui.h @@ -0,0 +1,34 @@ +#ifndef CL_MOD_GUI +#define CL_MOD_GUI + +/* +* Gui: Query the DF's GUI state +*/ +#include "Export.h" + +namespace DFHack +{ + class APIPrivate; + struct t_viewscreen; + class DFHACK_EXPORT Gui + { + public: + + Gui(DFHack::APIPrivate * d); + ~Gui(); + bool Start(); + bool Finish(); + + ///true if paused, false if not + bool ReadPauseState(); + /// read the DF menu view state (stock screen, unit screen, other screens + bool ReadViewScreen(t_viewscreen &); + /// read the DF menu state (designation menu ect) + uint32_t ReadMenuState(); + + private: + struct Private; + Private *d; + }; +} +#endif \ No newline at end of file diff --git a/dfhack/include/modules/Maps.h b/dfhack/include/modules/Maps.h new file mode 100644 index 000000000..eb4856d32 --- /dev/null +++ b/dfhack/include/modules/Maps.h @@ -0,0 +1,109 @@ +#ifndef CL_MOD_MAPS +#define CL_MOD_MAPS + +#include "Export.h" +/* +* Maps: Read and write DF's map +*/ +namespace DFHack +{ + class APIPrivate; + struct t_viewscreen; + class DFHACK_EXPORT Maps + { + public: + + Maps(DFHack::APIPrivate * d); + ~Maps(); + bool Start(); + bool Finish(); + + // read region surroundings, get their vectors of geolayers so we can do translation (or just hand the translation table to the client) + // returns an array of 9 vectors of indices into stone matgloss + /** + Method for reading the geological surrounding of the currently loaded region. + assign is a reference to an array of nine vectors of unsigned words that are to be filled with the data + array is indexed by the BiomeOffset enum + + I omitted resolving the layer matgloss in this API, because it would + introduce overhead by calling some method for each tile. You have to do it + yourself. First get the stuff from ReadGeology and then for each block get + the RegionOffsets. For each tile get the real region from RegionOffsets and + cross-reference it with the geology stuff (region -- array of vectors, depth -- + vector). I'm thinking about turning that Geology stuff into a + two-dimensional array with static size. + + this is the algorithm for applying matgloss: + void DfMap::applyGeoMatgloss(Block * b) + { + // load layer matgloss + for(int x_b = 0; x_b < BLOCK_SIZE; x_b++) + { + for(int y_b = 0; y_b < BLOCK_SIZE; y_b++) + { + int geolayer = b->designation[x_b][y_b].bits.geolayer_index; + int biome = b->designation[x_b][y_b].bits.biome; + b->material[x_b][y_b].type = Mat_Stone; + b->material[x_b][y_b].index = v_geology[b->RegionOffsets[biome]][geolayer]; + } + } + } + */ + bool ReadGeology( std::vector < std::vector >& assign ); + + /* + * BLOCK DATA + */ + /* + /// allocate and read pointers to map blocks + bool InitMap(); + /// destroy the mapblock cache + bool DestroyMap(); + */ + /// get size of the map in tiles + void getSize(uint32_t& x, uint32_t& y, uint32_t& z); + + /** + * Return false/0 on failure, buffer allocated by client app, 256 items long + */ + bool isValidBlock(uint32_t blockx, uint32_t blocky, uint32_t blockz); + /** + * Get the address of a block or 0 if block is not valid + */ + uint32_t getBlockPtr (uint32_t blockx, uint32_t blocky, uint32_t blockz); + + /// read the whole map block at block coords (see DFTypes.h for the block structure) + bool ReadBlock40d(uint32_t blockx, uint32_t blocky, uint32_t blockz, mapblock40d * buffer); + + /// read/write block tile types + bool ReadTileTypes(uint32_t blockx, uint32_t blocky, uint32_t blockz, tiletypes40d *buffer); + bool WriteTileTypes(uint32_t blockx, uint32_t blocky, uint32_t blockz, tiletypes40d *buffer); + + /// read/write block designations + bool ReadDesignations(uint32_t blockx, uint32_t blocky, uint32_t blockz, designations40d *buffer); + bool WriteDesignations (uint32_t blockx, uint32_t blocky, uint32_t blockz, designations40d *buffer); + + /// read/write block occupancies + bool ReadOccupancy(uint32_t blockx, uint32_t blocky, uint32_t blockz, occupancies40d *buffer); + bool WriteOccupancy(uint32_t blockx, uint32_t blocky, uint32_t blockz, occupancies40d *buffer); + + /// read/write the block dirty bit - this is used to mark a map block so that DF scans it for designated jobs like digging + bool ReadDirtyBit(uint32_t blockx, uint32_t blocky, uint32_t blockz, bool &dirtybit); + bool WriteDirtyBit(uint32_t blockx, uint32_t blocky, uint32_t blockz, bool dirtybit); + + /// read/write the block flags + bool ReadBlockFlags(uint32_t blockx, uint32_t blocky, uint32_t blockz, t_blockflags &blockflags); + bool WriteBlockFlags(uint32_t blockx, uint32_t blocky, uint32_t blockz, t_blockflags blockflags); + + /// read region offsets of a block - used for determining layer stone matgloss + bool ReadRegionOffsets(uint32_t blockx, uint32_t blocky, uint32_t blockz, biome_indices40d *buffer); + + /// read aggregated veins of a block + bool ReadVeins(uint32_t blockx, uint32_t blocky, uint32_t blockz, std::vector & veins, std::vector & ices); + + private: + struct Private; + Private *d; + }; +} +#endif \ No newline at end of file diff --git a/dfhack/include/modules/Materials.h b/dfhack/include/modules/Materials.h new file mode 100644 index 000000000..cfbfb9471 --- /dev/null +++ b/dfhack/include/modules/Materials.h @@ -0,0 +1,53 @@ +#ifndef CL_MOD_MATERIALS +#define CL_MOD_MATERIALS +/* +* Creatures +*/ +#include "Export.h" +namespace DFHack +{ + struct APIPrivate; + + struct t_matgloss + { + char id[128]; //the id in the raws + uint8_t fore; // Annoyingly the offset for this differs between types + uint8_t back; + uint8_t bright; + char name[128]; //this is the name displayed ingame + }; + + struct t_matglossPlant + { + char id[128]; //the id in the raws + uint8_t fore; // Annoyingly the offset for this differs between types + uint8_t back; + uint8_t bright; + char name[128]; //this is the name displayed ingame + char drink_name[128]; //the name this item becomes a drink + char food_name[128]; + char extract_name[128]; + }; + + class DFHACK_EXPORT Materials + { + public: + + Materials(DFHack::APIPrivate * _d); + ~Materials(); + + bool ReadInorganicMaterials (std::vector & output); + bool ReadOrganicMaterials (std::vector & output); + + bool ReadWoodMaterials (std::vector & output); + bool ReadPlantMaterials (std::vector & output); + // bool ReadPlantMaterials (std::vector & output); + + // TODO: maybe move to creatures? + bool ReadCreatureTypes (std::vector & output); + private: + APIPrivate* d; + }; +} +#endif + diff --git a/dfhack/include/modules/Position.h b/dfhack/include/modules/Position.h new file mode 100644 index 000000000..1b1168dde --- /dev/null +++ b/dfhack/include/modules/Position.h @@ -0,0 +1,35 @@ +#ifndef CL_MOD_POSITION +#define CL_MOD_POSITION +/* +* View position and size and cursor position +*/ +#include "Export.h" +namespace DFHack +{ + struct APIPrivate; + class DFHACK_EXPORT Position + { + public: + + Position(APIPrivate * d); + ~Position(); + /* + * Cursor and window coords + */ + bool getViewCoords (int32_t &x, int32_t &y, int32_t &z); + bool setViewCoords (const int32_t x, const int32_t y, const int32_t z); + + bool getCursorCoords (int32_t &x, int32_t &y, int32_t &z); + bool setCursorCoords (const int32_t x, const int32_t y, const int32_t z); + + /* + * Window size in tiles + */ + bool getWindowSize(int32_t & width, int32_t & height); + + private: + struct Private; + Private *d; + }; +} +#endif diff --git a/dfhack/modules/Creatures-data.h b/dfhack/modules/Creatures-data.h deleted file mode 100644 index f8630ceb4..000000000 --- a/dfhack/modules/Creatures-data.h +++ /dev/null @@ -1,4 +0,0 @@ -bool creaturesInited; -Creatures2010::creature_offsets creatures; -uint32_t creature_module; -DfVector *p_cre; \ No newline at end of file diff --git a/dfhack/modules/Creatures-proc.h b/dfhack/modules/Creatures-proc.h deleted file mode 100644 index 6e9c3cfce..000000000 --- a/dfhack/modules/Creatures-proc.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Creatures - */ -bool InitReadCreatures( uint32_t & numcreatures ); - -// Read creatures in a box, starting with index. Returns -1 if no more creatures -// found. Call repeatedly do get all creatures in a specified box (uses tile coords) -int32_t ReadCreatureInBox(const int32_t index, t_creature & furball, - const uint16_t x1, const uint16_t y1,const uint16_t z1, - const uint16_t x2, const uint16_t y2,const uint16_t z2); -bool ReadCreature(const int32_t index, t_creature & furball); -/// write labors of a creature (for Dwarf Therapist) -//bool WriteLabors(const uint32_t index, uint8_t labors[NUM_CREATURE_LABORS]); - -void FinishReadCreatures(); \ No newline at end of file diff --git a/dfhack/modules/Creatures.cpp b/dfhack/modules/Creatures.cpp index c8280543b..903de54c6 100644 --- a/dfhack/modules/Creatures.cpp +++ b/dfhack/modules/Creatures.cpp @@ -25,72 +25,120 @@ distribution. #include "DFCommonInternal.h" #include "../private/APIPrivate.h" -#define SHMCREATURESHDR ((Creatures2010::shm_creature_hdr *)d->shm_start) +// we connect to those +#include +#include +#include +#include "modules/Creatures.h" +#include "DFVector.h" +#include "DFMemInfo.h" +#include "DFProcess.h" +#include "DFError.h" +#include "DFTypes.h" + +#define SHMCREATURESHDR ((Creatures2010::shm_creature_hdr *)d->d->shm_start) +#define SHMCMD(num) ((shm_cmd *)d->d->shm_start)[num]->pingpong +#define SHMHDR ((shm_core_hdr *)d->d->shm_start) +#define SHMDATA(type) ((type *)(d->d->shm_start + SHM_HEADER)) using namespace DFHack; -bool API::InitReadCreatures( uint32_t &numcreatures ) +struct Creatures::Private +{ + bool Inited; + bool Started; + Creatures2010::creature_offsets creatures; + uint32_t creature_module; + DfVector *p_cre; + APIPrivate *d; +}; + +Creatures::Creatures(APIPrivate* _d) { - if(!d->InitReadNames()) return false; + d = new Private; + d->d = _d; + d->Inited = false; + d->Started = false; + d->d->InitReadNames(); // throws on error try { - memory_info * minfo = d->offset_descriptor; - Creatures2010::creature_offsets & off = d->creatures; - off.creature_vector = minfo->getAddress ("creature_vector"); - off.creature_pos_offset = minfo->getOffset ("creature_position"); - off.creature_profession_offset = minfo->getOffset ("creature_profession"); - off.creature_race_offset = minfo->getOffset ("creature_race"); - off.creature_flags1_offset = minfo->getOffset ("creature_flags1"); - off.creature_flags2_offset = minfo->getOffset ("creature_flags2"); - off.creature_name_offset = minfo->getOffset ("creature_name"); - off.creature_sex_offset = minfo->getOffset ("creature_sex"); - off.creature_id_offset = minfo->getOffset ("creature_id"); - off.creature_labors_offset = minfo->getOffset ("creature_labors"); - off.creature_happiness_offset = minfo->getOffset ("creature_happiness"); - off.creature_artifact_name_offset = minfo->getOffset("creature_artifact_name"); + memory_info * minfo = d->d->offset_descriptor; + Creatures2010::creature_offsets &creatures = d->creatures; + creatures.creature_vector = minfo->getAddress ("creature_vector"); + creatures.creature_pos_offset = minfo->getOffset ("creature_position"); + creatures.creature_profession_offset = minfo->getOffset ("creature_profession"); + creatures.creature_race_offset = minfo->getOffset ("creature_race"); + creatures.creature_flags1_offset = minfo->getOffset ("creature_flags1"); + creatures.creature_flags2_offset = minfo->getOffset ("creature_flags2"); + creatures.creature_name_offset = minfo->getOffset ("creature_name"); + creatures.creature_sex_offset = minfo->getOffset ("creature_sex"); + creatures.creature_id_offset = minfo->getOffset ("creature_id"); + creatures.creature_labors_offset = minfo->getOffset ("creature_labors"); + creatures.creature_happiness_offset = minfo->getOffset ("creature_happiness"); + creatures.creature_artifact_name_offset = minfo->getOffset("creature_artifact_name"); // name offsets for the creature module - off.name_firstname_offset = minfo->getOffset("name_firstname"); - off.name_nickname_offset = minfo->getOffset("name_nickname"); - off.name_words_offset = minfo->getOffset("name_words"); + creatures.name_firstname_offset = minfo->getOffset("name_firstname"); + creatures.name_nickname_offset = minfo->getOffset("name_nickname"); + creatures.name_words_offset = minfo->getOffset("name_words"); - d->p_cre = new DfVector (d->p, off.creature_vector, 4); - d->creaturesInited = true; - numcreatures = d->p_cre->getSize(); - - // --> SHM initialization (if possible) <-- - g_pProcess->getModuleIndex("Creatures2010",1,d->creature_module); - - if(d->creature_module) + // upload offsets to the SHM + if(g_pProcess->getModuleIndex("Creatures2010",1,d->creature_module)) { // supply the module with offsets so it can work with them - memcpy(SHMDATA(Creatures2010::creature_offsets),&d->creatures,sizeof(Creatures2010::creature_offsets)); + memcpy(SHMDATA(Creatures2010::creature_offsets),&creatures,sizeof(Creatures2010::creature_offsets)); const uint32_t cmd = Creatures2010::CREATURE_INIT + (d->creature_module << 16); g_pProcess->SetAndWait(cmd); } - return true; + d->Inited = true; } catch (Error::MissingMemoryDefinition&) { - d->creaturesInited = false; - numcreatures = 0; + d->Inited = false; throw; } } -bool API::ReadCreature (const int32_t index, t_creature & furball) +Creatures::~Creatures() { - if(!d->creaturesInited) return false; + if(d->Started) + Finish(); +} + +bool Creatures::Start( uint32_t &numcreatures ) +{ + d->p_cre = new DfVector (d->d->p, d->creatures.creature_vector, 4); + d->Started = true; + numcreatures = d->p_cre->getSize(); + return true; +} + +bool Creatures::Finish() +{ + if(d->p_cre) + { + delete d->p_cre; + d->p_cre = 0; + } + d->Started = false; + return true; +} + +bool Creatures::ReadCreature (const int32_t index, t_creature & furball) +{ + if(!d->Started) return false; + // SHM fast path if(d->creature_module) { - // supply the module with offsets so it can work with them SHMCREATURESHDR->index = index; const uint32_t cmd = Creatures2010::CREATURE_AT_INDEX + (d->creature_module << 16); g_pProcess->SetAndWait(cmd); memcpy(&furball,SHMDATA(t_creature),sizeof(t_creature)); - // cerr << "creature read from SHM!" << endl; return true; } + + // non-SHM slow path + // read pointer from vector at position uint32_t temp = * (uint32_t *) d->p_cre->at (index); furball.origin = temp; @@ -101,9 +149,9 @@ bool API::ReadCreature (const int32_t index, t_creature & furball) g_pProcess->readDWord (temp + offs.creature_flags1_offset, furball.flags1.whole); g_pProcess->readDWord (temp + offs.creature_flags2_offset, furball.flags2.whole); // names - d->readName(furball.name,temp + offs.creature_name_offset); + d->d->readName(furball.name,temp + offs.creature_name_offset); //d->readName(furball.squad_name, temp + offs.creature_squad_name_offset); - d->readName(furball.artifact_name, temp + offs.creature_artifact_name_offset); + d->d->readName(furball.artifact_name, temp + offs.creature_artifact_name_offset); // custom profession //fill_char_buf (furball.custom_profession, d->p->readSTLString (temp + offs.creature_custom_profession_offset)); @@ -173,6 +221,56 @@ bool API::ReadCreature (const int32_t index, t_creature & furball) return true; } + +// returns index of creature actually read or -1 if no creature can be found +int32_t Creatures::ReadCreatureInBox (int32_t index, t_creature & furball, + const uint16_t x1, const uint16_t y1, const uint16_t z1, + const uint16_t x2, const uint16_t y2, const uint16_t z2) +{ + if (!d->Started) return -1; + if(d->creature_module) + { + // supply the module with offsets so it can work with them + SHMCREATURESHDR->index = index; + SHMCREATURESHDR->x = x1; + SHMCREATURESHDR->y = y1; + SHMCREATURESHDR->z = z1; + SHMCREATURESHDR->x2 = x2; + SHMCREATURESHDR->y2 = y2; + SHMCREATURESHDR->z2 = z2; + const uint32_t cmd = Creatures2010::CREATURE_FIND_IN_BOX + (d->creature_module << 16); + g_pProcess->SetAndWait(cmd); + if(SHMCREATURESHDR->index != -1) + memcpy(&furball,SHMDATA(void),sizeof(t_creature)); + return SHMCREATURESHDR->index; + } + else + { + uint16_t coords[3]; + uint32_t size = d->p_cre->getSize(); + while (uint32_t(index) < size) + { + // read pointer from vector at position + uint32_t temp = * (uint32_t *) d->p_cre->at (index); + g_pProcess->read (temp + d->creatures.creature_pos_offset, 3 * sizeof (uint16_t), (uint8_t *) &coords); + if (coords[0] >= x1 && coords[0] < x2) + { + if (coords[1] >= y1 && coords[1] < y2) + { + if (coords[2] >= z1 && coords[2] < z2) + { + ReadCreature (index, furball); + return index; + } + } + } + index++; + } + return -1; + } +} + + /* bool API::WriteLabors(const uint32_t index, uint8_t labors[NUM_CREATURE_LABORS]) { @@ -188,14 +286,4 @@ bool API::getCurrentCursorCreature(uint32_t & creature_index) creature_index = g_pProcess->readDWord(d->current_cursor_creature_offset); return true; } -*/ -void API::FinishReadCreatures() -{ - if(d->p_cre) - { - delete d->p_cre; - d->p_cre = 0; - } - d->creaturesInited = false; - //FinishReadNameTables(); -} \ No newline at end of file +*/ \ No newline at end of file diff --git a/dfhack/modules/Gui-data.h b/dfhack/modules/Gui-data.h deleted file mode 100644 index 2c1fcb058..000000000 --- a/dfhack/modules/Gui-data.h +++ /dev/null @@ -1,4 +0,0 @@ -uint32_t pause_state_offset; -uint32_t view_screen_offset; -uint32_t current_cursor_creature_offset; -uint32_t current_menu_state_offset; \ No newline at end of file diff --git a/dfhack/modules/Gui-proc.h b/dfhack/modules/Gui-proc.h deleted file mode 100644 index e964520ba..000000000 --- a/dfhack/modules/Gui-proc.h +++ /dev/null @@ -1,10 +0,0 @@ -/* -* Query the DF's GUI state -*/ -bool InitReadGuiState(); -///true if paused, false if not -bool ReadPauseState(); -/// read the DF menu view state (stock screen, unit screen, other screens -bool ReadViewScreen(t_viewscreen &); -/// read the DF menu state (designation menu ect) -uint32_t ReadMenuState(); \ No newline at end of file diff --git a/dfhack/modules/Gui.cpp b/dfhack/modules/Gui.cpp index d7b814e6e..eb1d774eb 100644 --- a/dfhack/modules/Gui.cpp +++ b/dfhack/modules/Gui.cpp @@ -24,27 +24,72 @@ distribution. #include "DFCommonInternal.h" #include "../private/APIPrivate.h" +#include "modules/Gui.h" +#include "DFProcess.h" +#include "DFMemInfo.h" +#include "DFTypes.h" + using namespace DFHack; -bool API::ReadPauseState() +struct Gui::Private +{ + bool Inited; + bool Started; + uint32_t pause_state_offset; + uint32_t view_screen_offset; + uint32_t current_cursor_creature_offset; + uint32_t current_menu_state_offset; + APIPrivate *d; +}; + +Gui::Gui(APIPrivate * _d) +{ + + d = new Private; + d->d = _d; + d->Inited = d->Started = true; + + memory_info * mem = d->d->offset_descriptor; + d->current_menu_state_offset = mem->getAddress("current_menu_state"); + d->pause_state_offset = mem->getAddress ("pause_state"); + d->view_screen_offset = mem->getAddress ("view_screen"); + d->Inited = d->Started = true; +} + +Gui::~Gui() +{ + delete d; +} + +bool Gui::Start() +{ + return true; +} + +bool Gui::Finish() +{ + return true; +} + +bool Gui::ReadPauseState() { // replace with an exception - if(!d->cursorWindowInited) return false; + if(!d->Inited) return false; uint32_t pauseState = g_pProcess->readDWord (d->pause_state_offset); return pauseState & 1; } -uint32_t API::ReadMenuState() +uint32_t Gui::ReadMenuState() { - if(d->cursorWindowInited) + if(d->Inited) return(g_pProcess->readDWord(d->current_menu_state_offset)); return false; } -bool API::ReadViewScreen (t_viewscreen &screen) +bool Gui::ReadViewScreen (t_viewscreen &screen) { - if (!d->cursorWindowInited) return false; + if (!d->Inited) return false; uint32_t last = g_pProcess->readDWord (d->view_screen_offset); uint32_t screenAddr = g_pProcess->readDWord (last); @@ -55,5 +100,5 @@ bool API::ReadViewScreen (t_viewscreen &screen) screenAddr = g_pProcess->readDWord (nextScreenPtr); nextScreenPtr = g_pProcess->readDWord (nextScreenPtr + 4); } - return d->offset_descriptor->resolveObjectToClassID (last, screen.type); + return d->d->offset_descriptor->resolveObjectToClassID (last, screen.type); } diff --git a/dfhack/modules/Maps-data.h b/dfhack/modules/Maps-data.h deleted file mode 100644 index 9e187eaab..000000000 --- a/dfhack/modules/Maps-data.h +++ /dev/null @@ -1,17 +0,0 @@ -uint32_t * block; -uint32_t x_block_count, y_block_count, z_block_count; -uint32_t regionX, regionY, regionZ; -uint32_t worldSizeX, worldSizeY; - -uint32_t tile_type_offset; -uint32_t designation_offset; -uint32_t block_flags_offset; - -uint32_t veinvector; -uint32_t vein_mineral_vptr; -uint32_t vein_ice_vptr; -uint32_t vein_spatter_vptr; -uint32_t maps_module; - -//uint32_t biome_stuffs; -//vector v_geology[eBiomeCount]; \ No newline at end of file diff --git a/dfhack/modules/Maps-proc.h b/dfhack/modules/Maps-proc.h deleted file mode 100644 index e3db2105e..000000000 --- a/dfhack/modules/Maps-proc.h +++ /dev/null @@ -1,80 +0,0 @@ -// read region surroundings, get their vectors of geolayers so we can do translation (or just hand the translation table to the client) -// returns an array of 9 vectors of indices into stone matgloss -/** - Method for reading the geological surrounding of the currently loaded region. - assign is a reference to an array of nine vectors of unsigned words that are to be filled with the data - array is indexed by the BiomeOffset enum - - I omitted resolving the layer matgloss in this API, because it would - introduce overhead by calling some method for each tile. You have to do it - yourself. First get the stuff from ReadGeology and then for each block get - the RegionOffsets. For each tile get the real region from RegionOffsets and - cross-reference it with the geology stuff (region -- array of vectors, depth -- - vector). I'm thinking about turning that Geology stuff into a - two-dimensional array with static size. - - this is the algorithm for applying matgloss: - void DfMap::applyGeoMatgloss(Block * b) - { - // load layer matgloss - for(int x_b = 0; x_b < BLOCK_SIZE; x_b++) - { - for(int y_b = 0; y_b < BLOCK_SIZE; y_b++) - { - int geolayer = b->designation[x_b][y_b].bits.geolayer_index; - int biome = b->designation[x_b][y_b].bits.biome; - b->material[x_b][y_b].type = Mat_Stone; - b->material[x_b][y_b].index = v_geology[b->RegionOffsets[biome]][geolayer]; - } - } - } - */ -bool ReadGeology( std::vector < std::vector >& assign ); - -/* - * BLOCK DATA - */ -/// allocate and read pointers to map blocks -bool InitMap(); -/// destroy the mapblock cache -bool DestroyMap(); -/// get size of the map in tiles -void getSize(uint32_t& x, uint32_t& y, uint32_t& z); - -/** - * Return false/0 on failure, buffer allocated by client app, 256 items long - */ -bool isValidBlock(uint32_t blockx, uint32_t blocky, uint32_t blockz); -/** - * Get the address of a block or 0 if block is not valid - */ -uint32_t getBlockPtr (uint32_t blockx, uint32_t blocky, uint32_t blockz); - -/// read the whole map block at block coords (see DFTypes.h for the block structure) -bool ReadBlock40d(uint32_t blockx, uint32_t blocky, uint32_t blockz, mapblock40d * buffer); - -/// read/write block tile types -bool ReadTileTypes(uint32_t blockx, uint32_t blocky, uint32_t blockz, tiletypes40d *buffer); -bool WriteTileTypes(uint32_t blockx, uint32_t blocky, uint32_t blockz, tiletypes40d *buffer); - -/// read/write block designations -bool ReadDesignations(uint32_t blockx, uint32_t blocky, uint32_t blockz, designations40d *buffer); -bool WriteDesignations (uint32_t blockx, uint32_t blocky, uint32_t blockz, designations40d *buffer); - -/// read/write block occupancies -bool ReadOccupancy(uint32_t blockx, uint32_t blocky, uint32_t blockz, occupancies40d *buffer); -bool WriteOccupancy(uint32_t blockx, uint32_t blocky, uint32_t blockz, occupancies40d *buffer); - -/// read/write the block dirty bit - this is used to mark a map block so that DF scans it for designated jobs like digging -bool ReadDirtyBit(uint32_t blockx, uint32_t blocky, uint32_t blockz, bool &dirtybit); -bool WriteDirtyBit(uint32_t blockx, uint32_t blocky, uint32_t blockz, bool dirtybit); - -/// read/write the block flags -bool ReadBlockFlags(uint32_t blockx, uint32_t blocky, uint32_t blockz, t_blockflags &blockflags); -bool WriteBlockFlags(uint32_t blockx, uint32_t blocky, uint32_t blockz, t_blockflags blockflags); - -/// read region offsets of a block - used for determining layer stone matgloss -bool ReadRegionOffsets(uint32_t blockx, uint32_t blocky, uint32_t blockz, biome_indices40d *buffer); - -/// read aggregated veins of a block -bool ReadVeins(uint32_t blockx, uint32_t blocky, uint32_t blockz, std::vector & veins, std::vector & ices); \ No newline at end of file diff --git a/dfhack/modules/Maps.cpp b/dfhack/modules/Maps.cpp index d24999ff8..1f4b48c29 100644 --- a/dfhack/modules/Maps.cpp +++ b/dfhack/modules/Maps.cpp @@ -23,76 +23,108 @@ distribution. */ #include "DFCommonInternal.h" +#include +#include +#include #include "../private/APIPrivate.h" +#include "modules/Maps.h" +#include "DFError.h" +#include "DFMemInfo.h" +#include "DFProcess.h" +#include "DFVector.h" -#define SHMMAPSHDR ((Maps::shm_maps_hdr *)d->shm_start) +#define SHMMAPSHDR ((Server::Maps::shm_maps_hdr *)d->d->shm_start) +#define SHMCMD(num) ((shm_cmd *)d->d->shm_start)[num]->pingpong +#define SHMHDR ((shm_core_hdr *)d->d->shm_start) +#define SHMDATA(type) ((type *)(d->d->shm_start + SHM_HEADER)) using namespace DFHack; -/*-----------------------------------* - * Init the mapblock pointer array * - *-----------------------------------*/ -bool API::InitMap() +struct Maps::Private { - uint32_t map_offset = d->offset_descriptor->getAddress ("map_data"); - uint32_t x_count_offset = d->offset_descriptor->getAddress ("x_count_block"); - uint32_t y_count_offset = d->offset_descriptor->getAddress ("y_count_block"); - uint32_t z_count_offset = d->offset_descriptor->getAddress ("z_count_block"); + uint32_t * block; + uint32_t x_block_count, y_block_count, z_block_count; + uint32_t regionX, regionY, regionZ; + uint32_t worldSizeX, worldSizeY; + uint32_t maps_module; + Server::Maps::maps_offsets offsets; + + APIPrivate *d; + bool Inited; + bool Started; + //uint32_t biome_stuffs; + //vector v_geology[eBiomeCount]; +}; + +Maps::Maps(APIPrivate* _d) +{ + d = new Private; + d->d = _d; + d->Inited = d->Started = false; + + DFHack::memory_info * mem = d->d->offset_descriptor; + Server::Maps::maps_offsets &off = d->offsets; + // get the offsets once here - d->tile_type_offset = d->offset_descriptor->getOffset ("type"); - d->designation_offset = d->offset_descriptor->getOffset ("designation"); - //d->occupancy_offset = d->offset_descriptor->getOffset ("occupancy"); + off.map_offset = mem->getAddress ("map_data"); + off.x_count_offset = mem->getAddress ("x_count_block"); + off.y_count_offset = mem->getAddress ("y_count_block"); + off.z_count_offset = mem->getAddress ("z_count_block"); + off.tile_type_offset = mem->getOffset ("type"); + off.designation_offset = mem->getOffset ("designation"); //d->biome_stuffs = d->offset_descriptor->getOffset ("biome_stuffs"); - - d->veinvector = d->offset_descriptor->getOffset ("v_vein"); + off.veinvector = mem->getOffset ("v_vein"); // these can fail and will be found when looking at the actual veins later // basically a cache - d->vein_ice_vptr = 0; - d->offset_descriptor->resolveClassnameToVPtr("block_square_event_frozen_liquid", d->vein_ice_vptr); - d->vein_mineral_vptr = 0; - d->offset_descriptor->resolveClassnameToVPtr("block_square_event_mineral",d->vein_mineral_vptr); - - /* - * --> SHM initialization (if possible) <-- - */ - /* - g_pProcess->getModuleIndex("Maps2010",1,d->maps_module); - - if(d->maps_module) + off.vein_ice_vptr = 0; + mem->resolveClassnameToVPtr("block_square_event_frozen_liquid", off.vein_ice_vptr); + off.vein_mineral_vptr = 0; + mem->resolveClassnameToVPtr("block_square_event_mineral",off.vein_mineral_vptr); + + // upload offsets to SHM server if possible + d->maps_module = 0; + if(g_pProcess->getModuleIndex("Maps2010",1,d->maps_module)) { // supply the module with offsets so it can work with them - Maps::maps_offsets *off = SHMDATA(Maps::maps_offsets); - off->designation_offset = d->designation_offset; - off->map_offset = map_offset; - off->tile_type_offset = d->tile_type_offset; - off->vein_ice_vptr = d->vein_ice_vptr; // FIXME: not necessarily true, the shm server side needs a class lookup >_< - off->vein_mineral_vptr = d->vein_mineral_vptr; // FIXME: not necessarily true, the shm server side needs a class lookup >_< - off->veinvector = d->veinvector; - off->x_count_offset = x_count_offset; - off->y_count_offset = y_count_offset; - off->z_count_offset = z_count_offset; + Server::Maps::maps_offsets *off2 = SHMDATA(Server::Maps::maps_offsets); + memcpy(off2, &(d->offsets), sizeof(Server::Maps::maps_offsets)); full_barrier - const uint32_t cmd = Maps::MAP_INIT + (d->maps_module << 16); + const uint32_t cmd = Server::Maps::MAP_INIT + (d->maps_module << 16); g_pProcess->SetAndWait(cmd); - //cerr << "Map acceleration enabled!" << endl; } - */ + d->Inited = true; +} + +Maps::~Maps() +{ + if(d->Started) + Finish(); +} + +/*-----------------------------------* + * Init the mapblock pointer array * + *-----------------------------------*/ +bool Maps::Start() +{ + if(!d->Inited) + return false; + if(d->Started) + Finish(); + Server::Maps::maps_offsets &off = d->offsets; // get the map pointer - uint32_t x_array_loc = g_pProcess->readDWord (map_offset); + uint32_t x_array_loc = g_pProcess->readDWord (off.map_offset); if (!x_array_loc) { return false; - // FIXME: only throw this due to programmer error, in the other map functions - //throw Error::NoMapLoaded(); } // get the size uint32_t mx, my, mz; - mx = d->x_block_count = g_pProcess->readDWord (x_count_offset); - my = d->y_block_count = g_pProcess->readDWord (y_count_offset); - mz = d->z_block_count = g_pProcess->readDWord (z_count_offset); + mx = d->x_block_count = g_pProcess->readDWord (off.x_count_offset); + my = d->y_block_count = g_pProcess->readDWord (off.y_count_offset); + mz = d->z_block_count = g_pProcess->readDWord (off.z_count_offset); // test for wrong map dimensions if (mx == 0 || mx > 48 || my == 0 || my > 48 || mz == 0) @@ -125,7 +157,7 @@ bool API::InitMap() return true; } -bool API::DestroyMap() +bool Maps::Finish() { if (d->block != NULL) { @@ -135,28 +167,28 @@ bool API::DestroyMap() return true; } -bool API::isValidBlock (uint32_t x, uint32_t y, uint32_t z) +bool Maps::isValidBlock (uint32_t x, uint32_t y, uint32_t z) { if ( x >= d->x_block_count || y >= d->y_block_count || z >= d->z_block_count) return false; return d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z] != 0; } -uint32_t API::getBlockPtr (uint32_t x, uint32_t y, uint32_t z) +uint32_t Maps::getBlockPtr (uint32_t x, uint32_t y, uint32_t z) { if ( x >= d->x_block_count || y >= d->y_block_count || z >= d->z_block_count) return 0; return d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; } -bool API::ReadBlock40d(uint32_t x, uint32_t y, uint32_t z, mapblock40d * buffer) +bool Maps::ReadBlock40d(uint32_t x, uint32_t y, uint32_t z, mapblock40d * buffer) { - if(d->shm_start && d->maps_module) // ACCELERATE! + if(d->d->shm_start && d->maps_module) // ACCELERATE! { SHMMAPSHDR->x = x; SHMMAPSHDR->y = y; SHMMAPSHDR->z = z; - volatile uint32_t cmd = Maps::MAP_READ_BLOCK_BY_COORDS + (d->maps_module << 16); + volatile uint32_t cmd = Server::Maps::MAP_READ_BLOCK_BY_COORDS + (d->maps_module << 16); if(!g_pProcess->SetAndWait(cmd)) return false; memcpy(buffer,SHMDATA(mapblock40d),sizeof(mapblock40d)); @@ -167,7 +199,7 @@ bool API::ReadBlock40d(uint32_t x, uint32_t y, uint32_t z, mapblock40d * buffer) uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if (addr) { - g_pProcess->read (addr + d->tile_type_offset, sizeof (buffer->tiletypes), (uint8_t *) buffer->tiletypes); + g_pProcess->read (addr + d->offsets.tile_type_offset, sizeof (buffer->tiletypes), (uint8_t *) buffer->tiletypes); buffer->origin = addr; uint32_t addr_of_struct = g_pProcess->readDWord(addr); buffer->blockflags.whole = g_pProcess->readDWord(addr_of_struct); @@ -179,18 +211,18 @@ bool API::ReadBlock40d(uint32_t x, uint32_t y, uint32_t z, mapblock40d * buffer) // 256 * sizeof(uint16_t) -bool API::ReadTileTypes (uint32_t x, uint32_t y, uint32_t z, tiletypes40d *buffer) +bool Maps::ReadTileTypes (uint32_t x, uint32_t y, uint32_t z, tiletypes40d *buffer) { uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if (addr) { - g_pProcess->read (addr + d->tile_type_offset, sizeof (tiletypes40d), (uint8_t *) buffer); + g_pProcess->read (addr + d->offsets.tile_type_offset, sizeof (tiletypes40d), (uint8_t *) buffer); return true; } return false; } -bool API::ReadDirtyBit(uint32_t x, uint32_t y, uint32_t z, bool &dirtybit) +bool Maps::ReadDirtyBit(uint32_t x, uint32_t y, uint32_t z, bool &dirtybit) { uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if(addr) @@ -202,7 +234,7 @@ bool API::ReadDirtyBit(uint32_t x, uint32_t y, uint32_t z, bool &dirtybit) return false; } -bool API::WriteDirtyBit(uint32_t x, uint32_t y, uint32_t z, bool dirtybit) +bool Maps::WriteDirtyBit(uint32_t x, uint32_t y, uint32_t z, bool dirtybit) { uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if (addr) @@ -218,7 +250,7 @@ bool API::WriteDirtyBit(uint32_t x, uint32_t y, uint32_t z, bool dirtybit) } /// read/write the block flags -bool API::ReadBlockFlags(uint32_t x, uint32_t y, uint32_t z, t_blockflags &blockflags) +bool Maps::ReadBlockFlags(uint32_t x, uint32_t y, uint32_t z, t_blockflags &blockflags) { uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if(addr) @@ -229,7 +261,7 @@ bool API::ReadBlockFlags(uint32_t x, uint32_t y, uint32_t z, t_blockflags &block } return false; } -bool API::WriteBlockFlags(uint32_t x, uint32_t y, uint32_t z, t_blockflags blockflags) +bool Maps::WriteBlockFlags(uint32_t x, uint32_t y, uint32_t z, t_blockflags blockflags) { uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if (addr) @@ -241,24 +273,24 @@ bool API::WriteBlockFlags(uint32_t x, uint32_t y, uint32_t z, t_blockflags block return false; } -bool API::ReadDesignations (uint32_t x, uint32_t y, uint32_t z, designations40d *buffer) +bool Maps::ReadDesignations (uint32_t x, uint32_t y, uint32_t z, designations40d *buffer) { uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if (addr) { - g_pProcess->read (addr + d->designation_offset, sizeof (designations40d), (uint8_t *) buffer); + g_pProcess->read (addr + d->offsets.designation_offset, sizeof (designations40d), (uint8_t *) buffer); return true; } return false; } // 256 * sizeof(uint16_t) -bool API::WriteTileTypes (uint32_t x, uint32_t y, uint32_t z, tiletypes40d *buffer) +bool Maps::WriteTileTypes (uint32_t x, uint32_t y, uint32_t z, tiletypes40d *buffer) { uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if (addr) { - g_pProcess->write (addr + d->tile_type_offset, sizeof (tiletypes40d), (uint8_t *) buffer); + g_pProcess->write (addr + d->offsets.tile_type_offset, sizeof (tiletypes40d), (uint8_t *) buffer); return true; } return false; @@ -266,12 +298,12 @@ bool API::WriteTileTypes (uint32_t x, uint32_t y, uint32_t z, tiletypes40d *buff // 256 * sizeof(uint32_t) -bool API::WriteDesignations (uint32_t x, uint32_t y, uint32_t z, designations40d *buffer) +bool Maps::WriteDesignations (uint32_t x, uint32_t y, uint32_t z, designations40d *buffer) { uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if (addr) { - g_pProcess->write (addr + d->designation_offset, sizeof (designations40d), (uint8_t *) buffer); + g_pProcess->write (addr + d->offsets.designation_offset, sizeof (designations40d), (uint8_t *) buffer); return true; } return false; @@ -281,7 +313,7 @@ bool API::WriteDesignations (uint32_t x, uint32_t y, uint32_t z, designations40d //16 of them? IDK... there's probably just 7. Reading more doesn't cause errors as it's an array nested inside a block // 16 * sizeof(uint8_t) /* -bool API::ReadRegionOffsets (uint32_t x, uint32_t y, uint32_t z, biome_indices40d *buffer) +bool Maps::ReadRegionOffsets (uint32_t x, uint32_t y, uint32_t z, biome_indices40d *buffer) { uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if (addr) @@ -294,16 +326,17 @@ bool API::ReadRegionOffsets (uint32_t x, uint32_t y, uint32_t z, biome_indices40 */ // veins of a block, expects empty vein vectors -bool API::ReadVeins(uint32_t x, uint32_t y, uint32_t z, vector & veins, vector & ices) +bool Maps::ReadVeins(uint32_t x, uint32_t y, uint32_t z, vector & veins, vector & ices) { uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; veins.clear(); ices.clear(); - if (addr && d->veinvector) + Server::Maps::maps_offsets &off = d->offsets; + if (addr && off.veinvector) { // veins are stored as a vector of pointers to veins /*pointer is 4 bytes! we work with a 32bit program here, no matter what architecture we compile khazad for*/ - DfVector p_veins (d->p, addr + d->veinvector, 4); + DfVector p_veins (d->d->p, addr + off.veinvector, 4); uint32_t size = p_veins.getSize(); veins.reserve (size); @@ -317,7 +350,7 @@ bool API::ReadVeins(uint32_t x, uint32_t y, uint32_t z, vector & veins, uint32_t temp = * (uint32_t *) p_veins[i]; uint32_t type = g_pProcess->readDWord(temp); try_again: - if(type == d->vein_mineral_vptr) + if(type == off.vein_mineral_vptr) { // read the vein data (dereference pointer) g_pProcess->read (temp, sizeof(t_vein), (uint8_t *) &v); @@ -325,7 +358,7 @@ try_again: // store it in the vector veins.push_back (v); } - else if(type == d->vein_ice_vptr) + else if(type == off.vein_ice_vptr) { // read the ice vein data (dereference pointer) g_pProcess->read (temp, sizeof(t_frozenliquidvein), (uint8_t *) &fv); @@ -334,12 +367,12 @@ try_again: } else if(g_pProcess->readClassName(type) == "block_square_event_frozen_liquid") { - d->vein_ice_vptr = type; + off.vein_ice_vptr = type; goto try_again; } else if(g_pProcess->readClassName(type) == "block_square_event_mineral") { - d->vein_mineral_vptr = type; + off.vein_mineral_vptr = type; goto try_again; } } @@ -350,7 +383,7 @@ try_again: // getter for map size -void API::getSize (uint32_t& x, uint32_t& y, uint32_t& z) +void Maps::getSize (uint32_t& x, uint32_t& y, uint32_t& z) { x = d->x_block_count; y = d->y_block_count; diff --git a/dfhack/modules/Materials-data.h b/dfhack/modules/Materials-data.h deleted file mode 100644 index e69de29bb..000000000 diff --git a/dfhack/modules/Materials-proc.h b/dfhack/modules/Materials-proc.h deleted file mode 100644 index bc21262ca..000000000 --- a/dfhack/modules/Materials-proc.h +++ /dev/null @@ -1,13 +0,0 @@ -/* -* Matgloss. next four methods look very similar. I could use two and move the processing one level up... -* I'll keep it like this, even with the code duplication as it will hopefully get more features and separate data types later. -* Yay for nebulous plans for a rock survey tool that tracks how much of which metal could be smelted from available resorces -*/ -bool ReadInorganicMaterials (std::vector & output); -bool ReadOrganicMaterials (std::vector & output); - -bool ReadWoodMaterials (std::vector & output); -bool ReadPlantMaterials (std::vector & output); -// bool ReadPlantMaterials (std::vector & output); - -bool ReadCreatureTypes (std::vector & output); \ No newline at end of file diff --git a/dfhack/modules/Materials.cpp b/dfhack/modules/Materials.cpp index b3ee08f2a..265f5074c 100644 --- a/dfhack/modules/Materials.cpp +++ b/dfhack/modules/Materials.cpp @@ -24,7 +24,18 @@ distribution. #include "DFCommonInternal.h" #include "../private/APIPrivate.h" +#include "modules/Materials.h" +#include "DFVector.h" +#include "DFMemInfo.h" +#include "DFProcess.h" + using namespace DFHack; + +Materials::Materials(APIPrivate * d_) +{ + d = d_; +} +Materials::~Materials(){} /* { LABEL_53: @@ -169,34 +180,34 @@ inline bool ReadNamesOnly(Process* p, uint32_t address, vector & nam return true; } -bool API::ReadInorganicMaterials (vector & inorganic) +bool Materials::ReadInorganicMaterials (vector & inorganic) { return ReadNamesOnly(d->p, d->offset_descriptor->getAddress ("mat_inorganics"), inorganic ); } -bool API::ReadOrganicMaterials (vector & organic) +bool Materials::ReadOrganicMaterials (vector & organic) { return ReadNamesOnly(d->p, d->offset_descriptor->getAddress ("mat_organics_all"), organic ); } -bool API::ReadWoodMaterials (vector & trees) +bool Materials::ReadWoodMaterials (vector & trees) { return ReadNamesOnly(d->p, d->offset_descriptor->getAddress ("mat_organics_trees"), trees ); } -bool API::ReadPlantMaterials (vector & plants) +bool Materials::ReadPlantMaterials (vector & plants) { return ReadNamesOnly(d->p, d->offset_descriptor->getAddress ("mat_organics_plants"), plants ); } /* Gives bad results combined with the creature race field! -bool API::ReadCreatureTypes (vector & creatures) +bool Materials::ReadCreatureTypes (vector & creatures) { return ReadNamesOnly(d->p, d->offset_descriptor->getAddress ("mat_creature_types"), creatures ); return true; } */ -bool API::ReadCreatureTypes (vector & creatures) +bool Materials::ReadCreatureTypes (vector & creatures) { return ReadNamesOnly(d->p, d->offset_descriptor->getAddress ("creature_type_vector"), creatures ); return true; diff --git a/dfhack/modules/Position-data.h b/dfhack/modules/Position-data.h deleted file mode 100644 index f781e332e..000000000 --- a/dfhack/modules/Position-data.h +++ /dev/null @@ -1,6 +0,0 @@ -uint32_t window_x_offset; -uint32_t window_y_offset; -uint32_t window_z_offset; -uint32_t cursor_xyz_offset; -uint32_t window_dims_offset; -bool cursorWindowInited; \ No newline at end of file diff --git a/dfhack/modules/Position-proc.h b/dfhack/modules/Position-proc.h deleted file mode 100644 index 9ef54b5a2..000000000 --- a/dfhack/modules/Position-proc.h +++ /dev/null @@ -1,17 +0,0 @@ -/* -* Cursor and window coords -*/ -bool InitViewAndCursor(); -bool getViewCoords (int32_t &x, int32_t &y, int32_t &z); -bool setViewCoords (const int32_t x, const int32_t y, const int32_t z); - -bool getCursorCoords (int32_t &x, int32_t &y, int32_t &z); -bool setCursorCoords (const int32_t x, const int32_t y, const int32_t z); - -/* -* Window size in tiles -*/ -bool InitViewSize(); -bool getWindowSize(int32_t & width, int32_t & height); -/// get the creature vector index of the creature currently under DF' cursor -bool getCurrentCursorCreature (uint32_t & creature_index); diff --git a/dfhack/modules/Position.cpp b/dfhack/modules/Position.cpp index 679d1b10c..849f1013e 100644 --- a/dfhack/modules/Position.cpp +++ b/dfhack/modules/Position.cpp @@ -24,24 +24,54 @@ distribution. #include "DFCommonInternal.h" #include "../private/APIPrivate.h" +#include "modules/Position.h" +#include "DFMemInfo.h" +#include "DFProcess.h" using namespace DFHack; -bool API::InitViewAndCursor() + + + +struct Position::Private +{ + uint32_t window_x_offset; + uint32_t window_y_offset; + uint32_t window_z_offset; + uint32_t cursor_xyz_offset; + uint32_t window_dims_offset; + + APIPrivate *d; + bool Inited; + bool Started; + //uint32_t biome_stuffs; + //vector v_geology[eBiomeCount]; +}; + +Position::Position(APIPrivate * d_) +{ + d = new Private; + d->d = d_; + d->Inited = d->Started = false; + memory_info * mem = d->d->offset_descriptor; + d->window_x_offset = mem->getAddress ("window_x"); + d->window_y_offset = mem->getAddress ("window_y"); + d->window_z_offset = mem->getAddress ("window_z"); + d->cursor_xyz_offset = mem->getAddress ("cursor_xyz"); + d->window_dims_offset = mem->getAddress ("window_dims"); + d->Inited = d->Started = true; +} + +Position::~Position() +{ + delete d; +} +/* +bool Position::InitViewAndCursor() { try { - d->window_x_offset = d->offset_descriptor->getAddress ("window_x"); - d->window_y_offset = d->offset_descriptor->getAddress ("window_y"); - d->window_z_offset = d->offset_descriptor->getAddress ("window_z"); - d->cursor_xyz_offset = d->offset_descriptor->getAddress ("cursor_xyz"); - d->current_cursor_creature_offset = d->offset_descriptor->getAddress ("current_cursor_creature"); - d->window_dims_offset = d->offset_descriptor->getAddress ("window_dims"); - d->current_menu_state_offset = d->offset_descriptor->getAddress("current_menu_state"); - d->pause_state_offset = d->offset_descriptor->getAddress ("pause_state"); - d->view_screen_offset = d->offset_descriptor->getAddress ("view_screen"); - - d->cursorWindowInited = true; + d->Inited = true; return true; } catch (Error::MissingMemoryDefinition&) @@ -50,10 +80,10 @@ bool API::InitViewAndCursor() throw; } } - -bool API::getViewCoords (int32_t &x, int32_t &y, int32_t &z) +*/ +bool Position::getViewCoords (int32_t &x, int32_t &y, int32_t &z) { - if (!d->cursorWindowInited) return false; + if (!d->Inited) return false; g_pProcess->readDWord (d->window_x_offset, (uint32_t &) x); g_pProcess->readDWord (d->window_y_offset, (uint32_t &) y); g_pProcess->readDWord (d->window_z_offset, (uint32_t &) z); @@ -61,18 +91,18 @@ bool API::getViewCoords (int32_t &x, int32_t &y, int32_t &z) } //FIXME: confine writing of coords to map bounds? -bool API::setViewCoords (const int32_t x, const int32_t y, const int32_t z) +bool Position::setViewCoords (const int32_t x, const int32_t y, const int32_t z) { - if (!d->cursorWindowInited) return false; + if (!d->Inited) return false; g_pProcess->writeDWord (d->window_x_offset, (uint32_t) x); g_pProcess->writeDWord (d->window_y_offset, (uint32_t) y); g_pProcess->writeDWord (d->window_z_offset, (uint32_t) z); return true; } -bool API::getCursorCoords (int32_t &x, int32_t &y, int32_t &z) +bool Position::getCursorCoords (int32_t &x, int32_t &y, int32_t &z) { - if(!d->cursorWindowInited) return false; + if(!d->Inited) return false; int32_t coords[3]; g_pProcess->read (d->cursor_xyz_offset, 3*sizeof (int32_t), (uint8_t *) coords); x = coords[0]; @@ -83,17 +113,17 @@ bool API::getCursorCoords (int32_t &x, int32_t &y, int32_t &z) } //FIXME: confine writing of coords to map bounds? -bool API::setCursorCoords (const int32_t x, const int32_t y, const int32_t z) +bool Position::setCursorCoords (const int32_t x, const int32_t y, const int32_t z) { - if (!d->cursorWindowInited) return false; + if (!d->Inited) return false; int32_t coords[3] = {x, y, z}; g_pProcess->write (d->cursor_xyz_offset, 3*sizeof (int32_t), (uint8_t *) coords); return true; } -bool API::getWindowSize (int32_t &width, int32_t &height) +bool Position::getWindowSize (int32_t &width, int32_t &height) { - if(! d->cursorWindowInited) return false; + if(!d->Inited) return false; int32_t coords[2]; g_pProcess->read (d->window_dims_offset, 2*sizeof (int32_t), (uint8_t *) coords); diff --git a/dfhack/private/APIPrivate.h b/dfhack/private/APIPrivate.h index 930691ad0..6a2af8d7e 100644 --- a/dfhack/private/APIPrivate.h +++ b/dfhack/private/APIPrivate.h @@ -29,86 +29,85 @@ distribution. #ifndef APIPRIVATE_H_INCLUDED #define APIPRIVATE_H_INCLUDED -// we connect to those -#include -#include -#include -// #include -#include - -#define SHMCMD(num) ((shm_cmd *)d->shm_start)[num]->pingpong -#define SHMHDR ((shm_core_hdr *)d->shm_start) -#define SHMDATA(type) ((type *)(d->shm_start + SHM_HEADER)) - namespace DFHack { - -class APIPrivate -{ -public: - APIPrivate(); - void readName(t_name & name, uint32_t address); - // get the name offsets - bool InitReadNames(); - - #include "../modules/Creatures-data.h" - #include "../modules/Maps-data.h" - #include "../modules/Position-data.h" - #include "../modules/Gui-data.h" - #include "../modules/Materials-data.h" - - uint32_t name_firstname_offset; - uint32_t name_nickname_offset; - uint32_t name_words_offset; - - ProcessEnumerator* pm; - Process* p; - char * shm_start; - memory_info* offset_descriptor; - string xml; - - /* - uint32_t item_material_offset; - - uint32_t note_foreground_offset; - uint32_t note_background_offset; - uint32_t note_name_offset; - uint32_t note_xyz_offset; - uint32_t hotkey_start; - uint32_t hotkey_mode_offset; - uint32_t hotkey_xyz_offset; - uint32_t hotkey_size; - - uint32_t settlement_name_offset; - uint32_t settlement_world_xy_offset; - uint32_t settlement_local_xy_offset; - - uint32_t dwarf_lang_table_offset; - - bool constructionsInited; - bool buildingsInited; - bool effectsInited; - bool vegetationInited; - - - bool itemsInited; - bool notesInited; - bool namesInited; - bool hotkeyInited; - bool settlementsInited; - bool nameTablesInited; - - uint32_t tree_offset; - - DfVector *p_cons; - DfVector *p_bld; - DfVector *p_effect; - DfVector *p_veg; - DfVector *p_itm; - DfVector *p_notes; - DfVector *p_settlements; - DfVector *p_current_settlement; - */ -}; + class Materials; + class Gui; + class Position; + class Maps; + class Creatures; + class ProcessEnumerator; + class Process; + class memory_info; + struct t_name; + class APIPrivate + { + public: + APIPrivate(); + ~APIPrivate(); + void readName(t_name & name, uint32_t address); + // get the name offsets + bool InitReadNames(); + + uint32_t name_firstname_offset; + uint32_t name_nickname_offset; + uint32_t name_words_offset; + + ProcessEnumerator* pm; + Process* p; + char * shm_start; + memory_info* offset_descriptor; + string xml; + + // Modules + Creatures * creatures; + Maps * maps; + Position * position; + Gui * gui; + Materials * materials; + + /* + uint32_t item_material_offset; + + uint32_t note_foreground_offset; + uint32_t note_background_offset; + uint32_t note_name_offset; + uint32_t note_xyz_offset; + uint32_t hotkey_start; + uint32_t hotkey_mode_offset; + uint32_t hotkey_xyz_offset; + uint32_t hotkey_size; + + uint32_t settlement_name_offset; + uint32_t settlement_world_xy_offset; + uint32_t settlement_local_xy_offset; + + uint32_t dwarf_lang_table_offset; + + bool constructionsInited; + bool buildingsInited; + bool effectsInited; + bool vegetationInited; + + + bool itemsInited; + bool notesInited; + bool namesInited; + bool hotkeyInited; + bool settlementsInited; + bool nameTablesInited; + + uint32_t tree_offset; + + DfVector *p_cons; + DfVector *p_bld; + DfVector *p_effect; + DfVector *p_veg; + DfVector *p_itm; + DfVector *p_notes; + DfVector *p_settlements; + DfVector *p_current_settlement; + */ + }; } #endif \ No newline at end of file diff --git a/dfhack/shm/mod-creature2010.h b/dfhack/shm/mod-creature2010.h index 620d21f9d..24795f889 100644 --- a/dfhack/shm/mod-creature2010.h +++ b/dfhack/shm/mod-creature2010.h @@ -77,7 +77,7 @@ enum CREATURE_COMMAND CREATURE_INIT = 0, // initialization CREATURE_FIND_IN_BOX, CREATURE_AT_INDEX, - NUM_CREATURE_CMDS, + NUM_CREATURE_CMDS }; DFPP_module Init(void); diff --git a/dfhack/shm/mod-creature40d.h b/dfhack/shm/mod-creature40d.h index e2cb20567..8c7f84f54 100644 --- a/dfhack/shm/mod-creature40d.h +++ b/dfhack/shm/mod-creature40d.h @@ -27,8 +27,10 @@ distribution. namespace DFHack { - namespace Creatures + namespace Server { + namespace Creatures + { #define CREATURES40D_VERSION 1 typedef struct @@ -100,6 +102,7 @@ enum CREATURE_COMMAND }; DFPP_module Init(void); + } } } diff --git a/dfhack/shm/mod-maps.h b/dfhack/shm/mod-maps.h index eba3a95d4..8023be8bf 100644 --- a/dfhack/shm/mod-maps.h +++ b/dfhack/shm/mod-maps.h @@ -30,8 +30,10 @@ distribution. namespace DFHack { - namespace Maps + namespace Server { + namespace Maps + { #define MAPS_VERSION 3 typedef struct @@ -95,10 +97,10 @@ enum MAPS_COMMAND MAP_READ_BLOCKS_3D, // read blocks between two coords (volumetric) MAP_READ_ALL_BLOCKS, // read the entire map MAP_REVEAL, // reveal the whole map - NUM_MAPS_CMDS, + NUM_MAPS_CMDS }; DFPP_module Init(void); - + } } } diff --git a/dfhack/shm/shms.h b/dfhack/shm/shms.h index ba818d434..ce7913383 100644 --- a/dfhack/shm/shms.h +++ b/dfhack/shm/shms.h @@ -41,7 +41,7 @@ enum DFPP_CmdType { CANCELLATION, // we should jump out of the Act() CLIENT_WAIT, // we are waiting for the client - FUNCTION, // we call a function as a result of the command + FUNCTION // we call a function as a result of the command }; struct DFPP_command diff --git a/examples/creaturedump.cpp b/examples/creaturedump.cpp index f9ec1cf18..60cb343be 100644 --- a/examples/creaturedump.cpp +++ b/examples/creaturedump.cpp @@ -10,6 +10,8 @@ using namespace std; #include #include #include +#include +#include template void print_bits ( T val, std::ostream& out ) @@ -321,8 +323,11 @@ int main (void) return 1; } + DFHack::Creatures * Creatures = DF.getCreatures(); + DFHack::Materials * Materials = DF.getMaterials(); + uint32_t numCreatures; - if(!DF.InitReadCreatures(numCreatures)) + if(!Creatures->Start(numCreatures)) { cerr << "Can't get creatures" << endl; #ifndef LINUX_BUILD @@ -348,7 +353,7 @@ int main (void) */ mem = DF.getMemoryInfo(); // get stone matgloss mapping - if(!DF.ReadCreatureTypes(creaturestypes)) + if(!Materials->ReadCreatureTypes(creaturestypes)) { cerr << "Can't get the creature types." << endl; return 1; @@ -364,7 +369,7 @@ int main (void) for(uint32_t i = 0; i < numCreatures; i++) { DFHack::t_creature temp; - DF.ReadCreature(i,temp); + Creatures->ReadCreature(i,temp); //if(string(creaturestypes[temp.type].id) == "DWARF") { cout << "index " << i << " "; @@ -380,7 +385,7 @@ int main (void) DF.ReadCreature(currentIdx, currentCreature); printCreature(DF,currentCreature); */ - DF.FinishReadCreatures(); + Creatures->Finish(); DF.Detach(); #ifndef LINUX_BUILD cout << "Done. Press any key to continue" << endl; diff --git a/examples/expbench.cpp b/examples/expbench.cpp index 7d674098b..579f7ab4a 100644 --- a/examples/expbench.cpp +++ b/examples/expbench.cpp @@ -11,6 +11,7 @@ using namespace std; #include #include +#include void print_progress (int current, int total) { @@ -48,11 +49,12 @@ int main (int numargs, char** args) uint32_t num_blocks = 0; uint64_t bytes_read = 0; DFHack::mapblock40d Block; - + DFHack::Maps *Maps = 0; DFHack::API DF("Memory.xml"); try { DF.Attach(); + Maps = DF.getMaps(); } catch (exception& e) { @@ -70,25 +72,25 @@ int main (int numargs, char** args) { print_progress (i, iterations); - if(!DF.InitMap()) + if(!Maps->Start()) break; - DF.getSize(x_max,y_max,z_max); + Maps->getSize(x_max,y_max,z_max); 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(DF.isValidBlock(x,y,z)) + if(Maps->isValidBlock(x,y,z)) { - DF.ReadBlock40d(x, y, z, &Block); + Maps->ReadBlock40d(x, y, z, &Block); num_blocks ++; bytes_read += sizeof(DFHack::mapblock40d); } } } } - DF.DestroyMap(); + Maps->Finish(); } DF.Detach(); time(&end); diff --git a/examples/materialtest.cpp b/examples/materialtest.cpp index c5a431cf5..5f5acdda3 100644 --- a/examples/materialtest.cpp +++ b/examples/materialtest.cpp @@ -13,6 +13,7 @@ using namespace std; #include #include #include +#include void DumpObjStr0Vector (const char * name, DFHack::Process *p, uint32_t addr) { @@ -62,6 +63,8 @@ int main (int numargs, const char ** args) DFHack::Process* p = DF.getProcess(); DFHack::memory_info* mem = DF.getMemoryInfo(); + DFHack::Materials *Materials = DF.getMaterials(); + //const vector * names = mem->getClassIDMapping(); /* DumpObjStr0Vector("Material templates",p, mem->getAddress("mat_templates")); @@ -91,7 +94,7 @@ int main (int numargs, const char ** args) cout << "----==== Inorganic ====----" << endl; vector matgloss; - DF.ReadInorganicMaterials (matgloss); + Materials->ReadInorganicMaterials (matgloss); for(int i = 0; i < matgloss.size();i++) { cout << matgloss[i].id << endl; @@ -99,14 +102,14 @@ int main (int numargs, const char ** args) cout << endl << "----==== Organic ====----" << endl; vector organic; - DF.ReadOrganicMaterials (matgloss); + Materials->ReadOrganicMaterials (matgloss); for(int i = 0; i < matgloss.size();i++) { cout << matgloss[i].id << endl; } cout << endl << "----==== Creature types ====----" << endl; vector creature; - DF.ReadCreatureTypes (matgloss); + Materials->ReadCreatureTypes (matgloss); for(int i = 0; i < matgloss.size();i++) { cout << matgloss[i].id << endl; diff --git a/examples/position.cpp b/examples/position.cpp index a2120bac7..4e1787477 100644 --- a/examples/position.cpp +++ b/examples/position.cpp @@ -9,13 +9,16 @@ using namespace std; #include #include +#include int main (void) { DFHack::API DF("Memory.xml"); + DFHack::Position * Position = 0; try { DF.Attach(); + Position = DF.getPosition(); } catch (exception& e) { @@ -25,17 +28,16 @@ int main (void) #endif return 1; } - - if (DF.InitViewAndCursor()) + if (Position) { int32_t x,y,z; int32_t width,height; - if(DF.getViewCoords(x,y,z)) + if(Position->getViewCoords(x,y,z)) cout << "view coords: " << x << "/" << y << "/" << z << endl; - if(DF.getCursorCoords(x,y,z)) + if(Position->getCursorCoords(x,y,z)) cout << "cursor coords: " << x << "/" << y << "/" << z << endl; - if(DF.getWindowSize(width,height)) + if(Position->getWindowSize(width,height)) cout << "window size : " << width << " " << height << endl; } else diff --git a/examples/veinlook.cpp b/examples/veinlook.cpp index 94c4cd20c..b22723fa5 100644 --- a/examples/veinlook.cpp +++ b/examples/veinlook.cpp @@ -8,17 +8,21 @@ #include using namespace std; +#include +#include "fake-curses.h" +#include +#include +#include + #include #include #include #include #include +#include +#include using namespace DFHack; -#include -#include "fake-curses.h" -#include -#include -#include + string error; API * pDF = 0; @@ -308,10 +312,16 @@ main(int argc, char *argv[]) vector veinVector; vector IceVeinVector; + DFHack::Materials * Mats = 0; + DFHack::Maps * Maps = 0; + + DFHack::API DF("Memory.xml"); try { DF.Attach(); + Mats = DF.getMaterials(); + Maps = DF.getMaps(); pDF = &DF; } catch (exception& e) @@ -325,20 +335,20 @@ main(int argc, char *argv[]) Process* p = DF.getProcess(); // init the map - if(!DF.InitMap()) + if(!Maps->Start()) { error = "Can't find a map to look at."; pDF = 0; finish(0); } - DF.getSize(x_max_a,y_max_a,z_max_a); + 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; // get stone matgloss mapping - if(!DF.ReadInorganicMaterials(stonetypes)) + if(!Mats->ReadInorganicMaterials(stonetypes)) { error = "Can't read stone types."; pDF = 0; @@ -455,18 +465,18 @@ main(int argc, char *argv[]) mapblock40d * Block = &blocks[i+1][j+1]; - if(DF.isValidBlock(cursorX+i,cursorY+j,cursorZ)) + if(Maps->isValidBlock(cursorX+i,cursorY+j,cursorZ)) { - DF.ReadBlock40d(cursorX+i,cursorY+j,cursorZ, Block); + Maps->ReadBlock40d(cursorX+i,cursorY+j,cursorZ, Block); // extra processing of the block in the middle if(i == 0 && j == 0) { // read veins - DF.ReadVeins(cursorX+i,cursorY+j,cursorZ,veinVector,IceVeinVector); + Maps->ReadVeins(cursorX+i,cursorY+j,cursorZ,veinVector,IceVeinVector); // get pointer to block - blockaddr = DF.getBlockPtr(cursorX+i,cursorY+j,cursorZ); + blockaddr = Maps->getBlockPtr(cursorX+i,cursorY+j,cursorZ); blockaddr2 = Block->origin; // dig all veins and trees @@ -481,7 +491,7 @@ main(int argc, char *argv[]) Block->designation[x][y].bits.dig = designation_default; } } - DF.WriteDesignations(cursorX+i,cursorY+j,cursorZ, &(Block->designation)); + Maps->WriteDesignations(cursorX+i,cursorY+j,cursorZ, &(Block->designation)); } // do a dump of the block data if(dump) @@ -490,12 +500,12 @@ main(int argc, char *argv[]) filenum++; } // read/write dirty bit of the block - DF.ReadDirtyBit(cursorX+i,cursorY+j,cursorZ,dirtybit); - DF.ReadBlockFlags(cursorX+i,cursorY+j,cursorZ,bflags); + Maps->ReadDirtyBit(cursorX+i,cursorY+j,cursorZ,dirtybit); + Maps->ReadBlockFlags(cursorX+i,cursorY+j,cursorZ,bflags); if(digbit) { dirtybit = !dirtybit; - DF.WriteDirtyBit(cursorX+i,cursorY+j,cursorZ,dirtybit); + Maps->WriteDirtyBit(cursorX+i,cursorY+j,cursorZ,dirtybit); } } } diff --git a/tools/prospector.cpp b/tools/prospector.cpp index 631a9864b..eaf9cc275 100644 --- a/tools/prospector.cpp +++ b/tools/prospector.cpp @@ -19,6 +19,8 @@ using namespace std; #include #include #include +#include +#include int main (int argc, const char* argv[]) { @@ -69,8 +71,12 @@ int main (int argc, const char* argv[]) return 1; } + + DFHack::Maps * Maps = DF.getMaps(); + DFHack::Materials * Mats = DF.getMaterials(); + // init the map - if(!DF.InitMap()) + if(!Maps->Start()) { cerr << "Can't init map." << endl; #ifndef LINUX_BUILD @@ -78,10 +84,10 @@ int main (int argc, const char* argv[]) #endif return 1; } - DF.getSize(x_max,y_max,z_max); + Maps->getSize(x_max,y_max,z_max); // get stone matgloss mapping - if(!DF.ReadInorganicMaterials(stonetypes)) + if(!Mats->ReadInorganicMaterials(stonetypes)) { //DF.DestroyMap(); cerr << "Can't get the materials." << endl; @@ -113,16 +119,16 @@ int main (int argc, const char* argv[]) { for(uint32_t z = 0; z< z_max;z++) { - if(!DF.isValidBlock(x,y,z)) + if(!Maps->isValidBlock(x,y,z)) continue; // read data - DF.ReadTileTypes(x,y,z, &tiletypes); - DF.ReadDesignations(x,y,z, &designations); + Maps->ReadTileTypes(x,y,z, &tiletypes); + Maps->ReadDesignations(x,y,z, &designations); memset(tempvein, -1, sizeof(tempvein)); veins.clear(); - DF.ReadVeins(x,y,z,veins,iceveins); + Maps->ReadVeins(x,y,z,veins,iceveins); /* if(showbaselayers) { diff --git a/tools/reveal.cpp b/tools/reveal.cpp index 654252e32..de1304e34 100644 --- a/tools/reveal.cpp +++ b/tools/reveal.cpp @@ -7,6 +7,7 @@ using namespace std; #include #include +#include int main (void) { @@ -27,8 +28,9 @@ int main (void) return 1; } + DFHack::Maps *Maps =DF.getMaps(); // init the map - if(!DF.InitMap()) + if(!Maps->Start()) { cerr << "Can't init map." << endl; #ifndef LINUX_BUILD @@ -37,7 +39,7 @@ int main (void) return 1; } - DF.getSize(x_max,y_max,z_max); + Maps->getSize(x_max,y_max,z_max); // walk the map for(uint32_t x = 0; x< x_max;x++) @@ -46,17 +48,17 @@ int main (void) { for(uint32_t z = 0; z< z_max;z++) { - if(DF.isValidBlock(x,y,z)) + if(Maps->isValidBlock(x,y,z)) { // read block designations - DF.ReadDesignations(x,y,z, &designations); + Maps->ReadDesignations(x,y,z, &designations); // change the hidden flag to 0 for (uint32_t i = 0; i < 16;i++) for (uint32_t j = 0; j < 16;j++) { designations[i][j].bits.hidden = 0; } // write the designations back - DF.WriteDesignations(x,y,z, &designations); + Maps->WriteDesignations(x,y,z, &designations); } } } From f8d1c042d7dd2d223cdc4dde42bdbb75e365a5d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Mon, 5 Apr 2010 05:29:46 +0200 Subject: [PATCH 28/29] Layer stone/geology --- dfhack/modules/Maps.cpp | 94 +++++++++++++++++++++++++++++-------- dfhack/private/APIPrivate.h | 5 +- output/Memory.xml | 44 +++++++++++++++-- tools/prospector.cpp | 12 ++--- 4 files changed, 125 insertions(+), 30 deletions(-) diff --git a/dfhack/modules/Maps.cpp b/dfhack/modules/Maps.cpp index 1f4b48c29..9bf265f5f 100644 --- a/dfhack/modules/Maps.cpp +++ b/dfhack/modules/Maps.cpp @@ -54,7 +54,7 @@ struct Maps::Private bool Inited; bool Started; //uint32_t biome_stuffs; - //vector v_geology[eBiomeCount]; + vector v_geology[eBiomeCount]; }; Maps::Maps(APIPrivate* _d) @@ -73,7 +73,7 @@ Maps::Maps(APIPrivate* _d) off.z_count_offset = mem->getAddress ("z_count_block"); off.tile_type_offset = mem->getOffset ("type"); off.designation_offset = mem->getOffset ("designation"); - //d->biome_stuffs = d->offset_descriptor->getOffset ("biome_stuffs"); + off.biome_stuffs = mem->getOffset ("biome_stuffs"); off.veinvector = mem->getOffset ("v_vein"); // these can fail and will be found when looking at the actual veins later @@ -312,18 +312,18 @@ bool Maps::WriteDesignations (uint32_t x, uint32_t y, uint32_t z, designations40 // FIXME: this is bad. determine the real size! //16 of them? IDK... there's probably just 7. Reading more doesn't cause errors as it's an array nested inside a block // 16 * sizeof(uint8_t) -/* + bool Maps::ReadRegionOffsets (uint32_t x, uint32_t y, uint32_t z, biome_indices40d *buffer) { uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if (addr) { - g_pProcess->read (addr + d->biome_stuffs, sizeof (biome_indices40d), (uint8_t *) buffer); + g_pProcess->read (addr + d->offsets.biome_stuffs, sizeof (biome_indices40d), (uint8_t *) buffer); return true; } return false; } -*/ + // veins of a block, expects empty vein vectors bool Maps::ReadVeins(uint32_t x, uint32_t y, uint32_t z, vector & veins, vector & ices) @@ -391,22 +391,79 @@ void Maps::getSize (uint32_t& x, uint32_t& y, uint32_t& z) } /* +__int16 __userpurge GetGeologicalRegion(__int16 block_X, int X, __int16 block_Y, int block_addr, int Y) +{ + char bio_off; // al@1 + int tile_designation; // ecx@1 + __int64 corrected_x; // qax@1 + __int64 corrected_y; // qax@1 + int difY; // eax@9 + int difX; // edx@9 + signed __int64 bio_off_2; // qax@9 + signed __int64 bio_off_2_; // qtt@9 + __int16 result; // ax@23 + + corrected_x = reg_off_x + (block_X + (signed int)*(_WORD *)(block_addr + 0x90)) / 48; + *(_WORD *)X = ((BYTE4(corrected_x) & 0xF) + (_DWORD)corrected_x) >> 4; + corrected_y = reg_off_y + (block_Y + (signed int)*(_WORD *)(block_addr + 0x92)) / 48; + *(_WORD *)Y = ((BYTE4(corrected_y) & 0xF) + (_DWORD)corrected_y) >> 4; + tile_designation = *(_DWORD *)(block_addr + 4 * (block_Y + 16 * block_X) + 0x29C); + bio_off = 0; + if ( tile_designation & 0x20000 ) + bio_off = 1; + if ( tile_designation & 0x40000 ) + bio_off |= 2u; + if ( tile_designation & 0x80000 ) + bio_off |= 4u; + if ( tile_designation & 0x100000 ) + bio_off |= 8u; + bio_off_2 = *(_BYTE *)(bio_off + block_addr + 0x1D9C); + bio_off_2_ = bio_off_2; + difY = bio_off_2 / 3; + difX = bio_off_2_ % 3; + if ( !difX ) + --*(_WORD *)X; + if ( difX == 2 ) + ++*(_WORD *)X; + if ( !difY ) + --*(_WORD *)Y; + if ( difY == 2 ) + ++*(_WORD *)Y; + if ( *(_WORD *)X < 0 ) + *(_WORD *)X = 0; + if ( *(_WORD *)Y < 0 ) + *(_WORD *)Y = 0; + if ( *(_WORD *)X >= (_WORD)World_size ) + *(_WORD *)X = World_size - 1; + result = HIWORD(World_size); + if ( *(_WORD *)Y >= HIWORD(World_size) ) + { + result = HIWORD(World_size) - 1; + *(_WORD *)Y = HIWORD(World_size) - 1; + } + return result; +} +*/ + //vector v_geology[eBiomeCount]; -bool API::ReadGeology (vector < vector >& assign) +bool Maps::ReadGeology (vector < vector >& assign) { - memory_info * minfo = d->offset_descriptor; + memory_info * minfo = d->d->offset_descriptor; // get needed addresses and offsets. Now this is what I call crazy. int region_x_offset = minfo->getAddress ("region_x"); int region_y_offset = minfo->getAddress ("region_y"); int region_z_offset = minfo->getAddress ("region_z"); - int world_offset = minfo->getAddress ("world"); - int world_regions_offset = minfo->getOffset ("w_regions_arr"); +/*
0x16AF52C
+
0x16AF574
*/ + int world_regions = minfo->getAddress ("ptr2_region_array"); int region_size = minfo->getHexValue ("region_size"); int region_geo_index_offset = minfo->getOffset ("region_geo_index_off"); - int world_geoblocks_offset = minfo->getOffset ("w_geoblocks"); - int world_size_x = minfo->getOffset ("world_size_x"); - int world_size_y = minfo->getOffset ("world_size_y"); + int world_geoblocks_vector = minfo->getAddress ("geoblock_vector"); + int world_size_x = minfo->getAddress ("world_size_x"); + int world_size_y = minfo->getAddress ("world_size_y"); int geolayer_geoblock_offset = minfo->getOffset ("geolayer_geoblock_offset"); + + int type_inside_geolayer = minfo->getOffset ("type_inside_geolayer"); uint32_t regionX, regionY, regionZ; uint16_t worldSizeX, worldSizeY; @@ -417,14 +474,14 @@ bool API::ReadGeology (vector < vector >& assign) g_pProcess->readDWord (region_z_offset, regionZ); // get world size - g_pProcess->readWord (world_offset + world_size_x, worldSizeX); - g_pProcess->readWord (world_offset + world_size_y, worldSizeY); + g_pProcess->readWord (world_size_x, worldSizeX); + g_pProcess->readWord (world_size_y, worldSizeY); // get pointer to first part of 2d array of regions - uint32_t regions = g_pProcess->readDWord (world_offset + world_regions_offset); + uint32_t regions = g_pProcess->readDWord (world_regions); // read the geoblock vector - DfVector geoblocks (d->p, world_offset + world_geoblocks_offset, 4); + DfVector geoblocks (d->d->p, world_geoblocks_vector, 4); // iterate over 8 surrounding regions + local region for (int i = eNorthWest; i < eBiomeCount; i++) @@ -450,7 +507,7 @@ bool API::ReadGeology (vector < vector >& assign) uint32_t geoblock_off = * (uint32_t *) geoblocks[geoindex]; // get the vector with pointer to layers - DfVector geolayers (d->p, geoblock_off + geolayer_geoblock_offset , 4); // let's hope + DfVector geolayers (d->d->p, geoblock_off + geolayer_geoblock_offset , 4); // let's hope // make sure we don't load crap assert (geolayers.getSize() > 0 && geolayers.getSize() <= 16); @@ -461,7 +518,7 @@ bool API::ReadGeology (vector < vector >& assign) // read pointer to a layer uint32_t geol_offset = * (uint32_t *) geolayers[j]; // read word at pointer + 2, store in our geology vectors - d->v_geology[i].push_back (g_pProcess->readWord (geol_offset + 2)); + d->v_geology[i].push_back (g_pProcess->readWord (geol_offset + type_inside_geolayer)); } } assign.clear(); @@ -473,4 +530,3 @@ bool API::ReadGeology (vector < vector >& assign) } return true; } -*/ \ No newline at end of file diff --git a/dfhack/private/APIPrivate.h b/dfhack/private/APIPrivate.h index 6a2af8d7e..07bd63adc 100644 --- a/dfhack/private/APIPrivate.h +++ b/dfhack/private/APIPrivate.h @@ -45,13 +45,15 @@ namespace DFHack public: APIPrivate(); ~APIPrivate(); + + // names, used by a few other modules. void readName(t_name & name, uint32_t address); // get the name offsets bool InitReadNames(); - uint32_t name_firstname_offset; uint32_t name_nickname_offset; uint32_t name_words_offset; + bool namesInited; ProcessEnumerator* pm; Process* p; @@ -92,7 +94,6 @@ namespace DFHack bool itemsInited; bool notesInited; - bool namesInited; bool hotkeyInited; bool settlementsInited; bool nameTablesInited; diff --git a/output/Memory.xml b/output/Memory.xml index dc0382c20..7c3103c51 100644 --- a/output/Memory.xml +++ b/output/Memory.xml @@ -2899,10 +2899,28 @@ 0x08 0x009A 0x029C + + + 0x1D9C + * map size in blocks * @@ -2919,7 +2937,27 @@
0x016ad750
0x016ad754
0x016ad758
- + + * World size * (WORDs) +
0x016AEDD4
+
0x016AEDD6
+ +
0x16AF52C
+
0x16AF574
+ + + + 0x64 + 0x60 + + 0x4 vector + 0x4 vector + Name struct =========== 0x0 diff --git a/tools/prospector.cpp b/tools/prospector.cpp index eaf9cc275..f944638dc 100644 --- a/tools/prospector.cpp +++ b/tools/prospector.cpp @@ -96,9 +96,9 @@ int main (int argc, const char* argv[]) #endif return 1; } - /* + // get region geology - if(!DF.ReadGeology( layerassign )) + if(!Maps->ReadGeology( layerassign )) { cerr << "Can't get region geology." << endl; #ifndef LINUX_BUILD @@ -106,7 +106,7 @@ int main (int argc, const char* argv[]) #endif return 1; } - */ + int16_t tempvein [16][16]; vector veins; vector iceveins; @@ -129,10 +129,10 @@ int main (int argc, const char* argv[]) memset(tempvein, -1, sizeof(tempvein)); veins.clear(); Maps->ReadVeins(x,y,z,veins,iceveins); - /* + if(showbaselayers) { - DF.ReadRegionOffsets(x,y,z, ®ionoffsets); + Maps->ReadRegionOffsets(x,y,z, ®ionoffsets); // get the layer materials for(uint32_t xx = 0;xx<16;xx++) { @@ -153,7 +153,7 @@ int main (int argc, const char* argv[]) } } } - */ + // for each vein for(int i = 0; i < (int)veins.size();i++) { From ea120a6709029ce24daa113476b3bae045d982ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Mon, 5 Apr 2010 05:53:38 +0200 Subject: [PATCH 29/29] Comments --- dfhack/modules/Maps.cpp | 8 ++++++-- output/Memory.xml | 8 +------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/dfhack/modules/Maps.cpp b/dfhack/modules/Maps.cpp index 9bf265f5f..af468510e 100644 --- a/dfhack/modules/Maps.cpp +++ b/dfhack/modules/Maps.cpp @@ -486,7 +486,7 @@ bool Maps::ReadGeology (vector < vector >& assign) // iterate over 8 surrounding regions + local region for (int i = eNorthWest; i < eBiomeCount; i++) { - // check bounds, fix them if needed + // check against worldmap boundaries, fix if needed int bioRX = regionX / 16 + (i % 3) - 1; if (bioRX < 0) bioRX = 0; if (bioRX >= worldSizeX) bioRX = worldSizeX - 1; @@ -494,6 +494,8 @@ bool Maps::ReadGeology (vector < vector >& assign) if (bioRY < 0) bioRY = 0; if (bioRY >= worldSizeY) bioRY = worldSizeY - 1; + /// regions are a 2d array. consists of pointers to arrays of regions + /// regions are of region_size size // get pointer to column of regions uint32_t geoX; g_pProcess->readDWord (regions + bioRX*4, geoX); @@ -502,15 +504,18 @@ bool Maps::ReadGeology (vector < vector >& assign) uint16_t geoindex; g_pProcess->readWord (geoX + bioRY*region_size + region_geo_index_offset, geoindex); + /// geology blocks are assigned to regions from a vector // get the geoblock from the geoblock vector using the geoindex // read the matgloss pointer from the vector into temp uint32_t geoblock_off = * (uint32_t *) geoblocks[geoindex]; + /// geology blocks have a vector of layer descriptors // get the vector with pointer to layers DfVector geolayers (d->d->p, geoblock_off + geolayer_geoblock_offset , 4); // let's hope // make sure we don't load crap assert (geolayers.getSize() > 0 && geolayers.getSize() <= 16); + /// layer descriptor has a field that determines the type of stone/soil d->v_geology[i].reserve (geolayers.getSize()); // finally, read the layer matgloss for (uint32_t j = 0;j < geolayers.getSize();j++) @@ -523,7 +528,6 @@ bool Maps::ReadGeology (vector < vector >& assign) } assign.clear(); assign.reserve (eBiomeCount); -// // TODO: clean this up for (int i = 0; i < eBiomeCount;i++) { assign.push_back (d->v_geology[i]); diff --git a/output/Memory.xml b/output/Memory.xml index 7c3103c51..f4d5a751d 100644 --- a/output/Memory.xml +++ b/output/Memory.xml @@ -2899,8 +2899,7 @@ 0x08 0x009A 0x029C - - + 0x1D9C - * map size in blocks *
0x016ad738