develop
Erik Youngren 2011-02-24 02:07:15 -08:00
commit 4dd5718c06
87 changed files with 7875 additions and 3892 deletions

2
.gitignore vendored

@ -29,3 +29,5 @@ dfhack/python/pydfhack/_pydfhack.so
dfhack/python/PyDFHack.egg-info dfhack/python/PyDFHack.egg-info
dfhack/python/build dfhack/python/build
dfhack/python/dist dfhack/python/dist
/cmakeall.bat

@ -29,7 +29,7 @@ SET( DATA_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/output CACHE PATH "Output directory fo
OPTION(BUILD_DFHACK_DOCUMENTATION "Create doxygen documentation for developers" OFF) OPTION(BUILD_DFHACK_DOCUMENTATION "Create doxygen documentation for developers" OFF)
OPTION(BUILD_DFHACK_EXAMPLES "Build example tools" OFF) OPTION(BUILD_DFHACK_EXAMPLES "Build example tools" OFF)
OPTION(BUILD_DFHACK_PLAYGROUND "Build tools from the playground folder" OFF) OPTION(BUILD_DFHACK_PLAYGROUND "Build tools from the playground folder" OFF)
OPTION(BUILD_DFHACK_C_BINDIGS "Build the C portion of the library" ON) OPTION(BUILD_DFHACK_C_BINDINGS "Build the C portion of the library" ON)
OPTION(BUILD_OFFSET_EDITOR "Build the Offset GUI editor (not ready for use)." OFF) OPTION(BUILD_OFFSET_EDITOR "Build the Offset GUI editor (not ready for use)." OFF)
OPTION(BUILD_DFHACK_SUPPORTED "Build the supported toold." ON) OPTION(BUILD_DFHACK_SUPPORTED "Build the supported toold." ON)
OPTION(BUILD_DFHACK_SHM "Build the SHM." OFF) OPTION(BUILD_DFHACK_SHM "Build the SHM." OFF)

@ -1,4 +1,6 @@
www.sourceforge.net/projects/dfhack ----------------------------------------------------------------------
License of dfhack
github.com/peterix/dfhack
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
@ -19,3 +21,120 @@ must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source 3. This notice may not be removed or altered from any source
distribution. distribution.
----------------------------------------------------------------------
License of library/include/dfhack/DFstdint_win.h
ISO C9x compliant stdint.h for Microsoft Visual Studio
Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
Copyright (c) 2006-2008 Alexander Chemeris
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------------
License of argstream (used by some utilities for parsing command line params)
Copyright (C) 2004 Xavier Decoret <Xavier.Decoret@imag.fr>
argsteam is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Foobar is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
This library is used by:
tools/playground/catsplosion.cpp
tools/playground/digger.cpp
tools/supported/vdig.cpp
----------------------------------------------------------------------------
License of "RSA Data Security, Inc. MD5 Message-Digest Algorithm"
Used to identify DF binaries.
Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.
License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.
License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD5 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
-----------------------------------------------------------------
License of the "RSA Data Security, Inc. MD5 Message-Digest Algorithm" C++ wrapper:
This is my wrapper-class to create
a MD5 Hash from a string and a file.
This code is completly free, you
can copy it, modify it, or do
what ever you want with it.
Feb. 2005
Benjamin Grüdelbach
------------------------------------------------------------------
License of the used XML reader library
www.sourceforge.net/projects/tinyxml
Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.

@ -664,6 +664,10 @@
<class name="building_civzonest"/><!-- zone --> <class name="building_civzonest"/><!-- zone -->
<class name="building_actualst"/> <class name="building_actualst"/>
<class name="buildingst"/> <class name="buildingst"/>
<class name="building_slabst" />
<class name="building_nestst" />
<class name="building_nest_boxst" />
<class name="building_hivest" />
</VTable> </VTable>
<Offsets> <Offsets>
<Address name="WORLD" description="A huge object that many things in DF are part of. Contains the whole game and can be used as a base <Address name="WORLD" description="A huge object that many things in DF are part of. Contains the whole game and can be used as a base
@ -1470,13 +1474,21 @@
<Address name="screen_tiles_pointer" value="0x18313D0" /> <Address name="screen_tiles_pointer" value="0x18313D0" />
</Group> </Group>
<Group name="World"> <Group name="World">
<Address name="current_weather" value="0x14BCDEE" /> <Address name="current_tick" value="0xde8910" /> MAYBE
<Address name="current_year" value="0xec78b0" />
<!--<Address name="current_weather" value="0x14BCDEE" />-->
</Group> </Group>
</Offsets> </Offsets>
</Version> </Version>
<Version name="v0.31.13 SDL" os="windows" base="DF2010"> <Version name="v0.31.13 SDL" os="windows" base="DF2010">
<MD5 value="59f194b0b2103ca5df7601a01ce21280" /> <MD5 value="59f194b0b2103ca5df7601a01ce21280" />
<PETimeStamp value="0x4C90ADA8" /> <PETimeStamp value="0x4C90ADA8" />
<VTable>
<multiclass name="building_trapst" typeoffset="0xF8" />
<multiclass name="building_workshopst" typeoffset="0xF8" />
<multiclass name="building_furnacest" typeoffset="0x10A" />
<multiclass name="building_siegeenginest" typeoffset="0xF8" />
</VTable>
<Offsets> <Offsets>
<Address name="WORLD" value="0x016425A0" /> <Address name="WORLD" value="0x016425A0" />
<Group name="vector"> <Group name="vector">
@ -1500,7 +1512,11 @@
<Offset name="capacity" value="0x14" /> <Offset name="capacity" value="0x14" />
</Group> </Group>
</Group> </Group>
0x01482874 - current race <Group name="name">
<Offset name="first" value="0x0" />
<Offset name="nick" value="0x1C" />
<Offset name="second_words" value="0x38" />
</Group>
<Group name="Position"> <Group name="Position">
<Address name="cursor_xyz" value="0xac77f0" /> <Address name="cursor_xyz" value="0xac77f0" />
<Address name="window_x" value="0xe42c74" /> <Address name="window_x" value="0xe42c74" />
@ -1513,7 +1529,7 @@
<Address name="pause_state" value="0x147E971" /> <Address name="pause_state" value="0x147E971" />
</Group> </Group>
<Group name="World"> <Group name="World">
<Address name="current_weather" value="0x147E948" /> <Address name="current_weather" value="0x147E948" />
</Group> </Group>
<Group name="Vegetation"> <Group name="Vegetation">
<Address name="vector" value="0x1656EFC" /> <Address name="vector" value="0x1656EFC" />
@ -1536,15 +1552,15 @@
<Address name="world_size_y" value="0x1699292" /> <Address name="world_size_y" value="0x1699292" />
<Group name="block"> <Group name="block">
<Offset name="vein_vector" value="0x08" /> <Offset name="vein_vector" value="0x08" />
<Offset name="feature_local" value="0x24 0x2C" /> <Offset name="feature_local" value="0x24" />
<Offset name="feature_global" value="0x28 0x30" /> <Offset name="feature_global" value="0x28" />
<Offset name="type" value="0x7A 0x009A" /> <Offset name="type" value="0x7A" />
<Offset name="designation" value="0x27C 0x029C" /> <Offset name="designation" value="0x27C" />
<Offset name="occupancy" value="0x67C 0x069c" /> <Offset name="occupancy" value="0x67C" />
<Offset name="temperature1" value="0x157C 0x159c" /> <Offset name="temperature1" value="0x157C" />
<Offset name="temperature2" value="0x177C 0x179c" /> <Offset name="temperature2" value="0x177C" />
<Offset name="biome_stuffs" value="0x1D7C 0x1D9C" /> <Offset name="biome_stuffs" value="0x1D7C" />
<Offset name="pathfinding" value="0x0D7c 0x0D9c" /> <Offset name="pathfinding" value="0x0D7c" />
</Group> </Group>
<Group name="features"> <Group name="features">
<Group name="global"> <Group name="global">
@ -1618,24 +1634,383 @@
<Address name="translation_vector" value="0x169a11C"/> <Address name="translation_vector" value="0x169a11C"/>
<Offset name="word_table" value="0x3c"/> <Offset name="word_table" value="0x3c"/>
</Group> </Group>
<Group name="Creatures">
<Address name="vector" value="0x01655fe4"/>
<Address name="current_race" value="0x1482874" />
<Address name="current_civ" value="0x1482868" />
<Group name="creature">
<Offset name="name" value="0x0" />
<Offset name="custom_profession" value="0x006C" />
<Offset name="profession" value="0x0088" />
<Offset name="race" value="0x008C" />
<Offset name="position" value="0x90" />
<Offset name="flags1" value="0x00E0" />
<Offset name="flags2" value="0x00E4" />
<Offset name="caste" value="0x00F8"/>
<Offset name="sex" value="0x00FA" /> <!-- ASSUMED -->
<Offset name="id" value="0x00FC" />
<Offset name="civ" value="0x108" />
<Group name="advanced">
<Offset name="pickup_equipment_bit" value="0x01BC" />
<Offset name="mood" value="0x210" />
<Offset name="pregnancy" value="0x214" />
<Offset name="pregnancy_ptr" value="0x218" />
<Offset name="birth_year" value="0x220" />
<Offset name="birth_time" value="0x224" />
<Offset name="inventory_vector" value="0x284" />
<Offset name="current_job" value="0x02F0" />
<Offset name="current_job_skill" value="0x02F4" />
<Offset name="physical" value="0x3C4" />
<Offset name="appearance_vector" value="0x524" />
<Offset name="artifact_name" value="0x5D4" />
<Offset name="soul_vector" value="0x640" />
<Offset name="current_soul" value="0x650" />
<Offset name="labors" value="0x0664" />
<Offset name="happiness" value="0x0704" />
</Group>
</Group>
<Group name="soul">
<Offset name="name" value="0x4" />
<Offset name="mental" value="0x88" />
<Offset name="skills_vector" value="0x1F4 0x01F0" />
<Offset name="traits" value="0x0214" /> is it a vector?
</Group>
<Group name="job">
<Offset name="id" value="0x08" />
<!--
<Offset name="type" description="seems to be just like the old occupations" />
<Offset name="materials_vector" />
<Group name="material">
<Offset name="maintype" description="like mood materials, 0=bars, 4=stone, 5=wood, 57=cloth, 54=leather ..." />
<Offset name="sectype1" description="subsubtype ?" />
<Offset name="sectype2" description="subtype ?" />
<Offset name="sectype3" description="index of material (for example, 2 is for silver)" />
<Offset name="flags" description="set only for shell / bone mood requirements ?" />
</Group>
-->
</Group>
</Group>
<Group name="Vegetation"> <Group name="Vegetation">
<Address name="vector" value="0x1656efc"/> <Address name="vector" value="0x1656efc"/>
<Offset name="tree_desc_offset" value="0x6C"/> <Offset name="tree_desc_offset" value="0x6C"/>
</Group> </Group>
<Group name="Buildings"> <Group name="Buildings">
<Address name="buildings_vector" value="0x1656890"/> <Address name="buildings_vector" value="0x1656890"/>
Second possible: 0x16568a0 (can't decide) <Offset name="building_custom_workshop_type" value="0x11C" />
<Offset name="custom_workshop_name" value="0x4" />
<Offset name="custom_workshop_type" value="0x20" />
<Address name="custom_workshop_vector" value="0x0169fB6C" /> Second possible: 0x0169fb7C
</Group>
</Offsets>
</Version>
<Version name="v0.31.14 SDL" os="windows" base="v0.31.13 SDL" rebase="0x1000">
<PETimeStamp value="0x4C9B6EFB" />
<MD5 value="2da156d1fbaf8192ede9ce91abc5f366" />
<Offsets>
<Group name="Maps">
<Group name="features">
<Group name="global">
<Address name="vector" value="0x169a8ec 0x16998e0" />
</Group>
<Group name="local">
<Address name="start_ptr" value="0x169a980 0x1699974" />
</Group>
</Group>
<Group name="geology">
<Address name="geoblock_vector" value="0x169a90C" />
<Address name="ptr2_region_array" value="0x169a93C" />
</Group>
</Group>
<Group name="Translations">
<Address name="language_vector" value="0x169b108 0x169b0fc"/>
<Address name="translation_vector" value="0x169b128 0x169b11c"/>
</Group>
<Group name="Materials">
<Address name="inorganics" value="0x169af24 0x1699f18 0x16BD0B0" />
<Address name="organics_all" value="0x169af34 0x1699f28 0x16BD0C8" />
<Address name="organics_trees" value="0x169af64 0x1699f58 0x16bd110" />
<Address name="organics_plants" value="0x169af44 0x1699f38 0x16bd0e0" />
<Address name="creature_type_vector" value="0x169b008 0x1699ffC 0x16BD204" />
<!--<Address name="other" value="0x16C647C" /> NO!-->
<Group name="descriptors">
<Address name="colors_vector" value="0x16a0b38 0x169fb2c" />
<Address name="all_colors_vector" value="0x16a0b58 0x169fb4c" />
</Group>
</Group>
<Group name="Buildings">
<Address name="custom_workshop_vector" value="0x016A0B78" /> Second possible: 0x016a0b88
</Group>
</Offsets>
</Version>
<Version name="v0.31.15 SDL" os="windows" base="v0.31.14 SDL">
<PETimeStamp value="0x4CA869EA" />
<MD5 value="b4d188dfb592fc813dad31f45407991d" />
</Version>
<Version name="v0.31.16 SDL" os="windows" base="v0.31.15 SDL" rebase="0x1050">
<PETimeStamp value="0x4CA9D544" />
<MD5 value="702b3ebaae468f73eb1411af54863013" />
<Offsets>
<Group name="Materials">
<Address name="other" value="0x16A21FC"/> 0x16445F0 + 0x5DC0C see code at 0x9CFB01
</Group>
<Group name="Creatures">
<Address name="current_civ" value="0x1484868 0x14848b8" />
<Address name="current_race" value="0x1484874 0x14848c4" />
</Group>
<Group name="Position">
<Address name="cursor_xyz" value="0xac97f0 0xac9840" />
<!--<Address name="screen_tiles_pointer" value="0x14826d4" />--> AS BOGUS AS IT GETS
<Address name="window_dims" value="0xaca07c 0xaca0cc" />
<Address name="window_x" value="0xE44C74 0xe44cc4" />
<Address name="window_y" value="0xE72D48 0xe72d98" />
<Address name="window_z" value="0xe72d24 0xe72d74" />
</Group>
<Group name="GUI">
<Address name="pause_state" value="0x1480971" />
</Group>
<Group name="World">
<Address name="current_tick" value="0xdac470" /> MAYBE
<Address name="current_year" value="0xe8b410" />
<Address name="current_weather" value="0x1480948" />
</Group>
<Group name="Items">
<Address name="items_vector" value="0x16580d8" />
<Offset name="item_type_accessor" value="0x0" />
<Offset name="item_subtype_accessor" value="0x4" />
<Offset name="item_subindex_accessor" value="0x8" />
<Offset name="item_index_accessor" value="0xC" />
<Offset name="item_quality_accessor" value="0x238" />
<Offset name="item_improvement_vector" value="0x90" />
</Group>
</Offsets>
</Version>
<Version name="v0.31.18 SDL" os="windows" base="v0.31.16 SDL" rebase="0x492D0">
<PETimeStamp value="0x4CE2841D" />
<MD5 value="b7be6b9db369d6adb72319dcf780f9f5" />
<Offsets>
<Address name="WORLD" valid="false" />
<Group name="Buildings">
<Address name="buildings_vector" value="0x16a1be0" />
<Address name="custom_workshop_vector" value="0x16eaca0" />
<!-- <!--
<Offset name="building_custom_workshop_type"/> <Offset name="building_custom_workshop_type" value="0x11c" /> INVALID!
<Address name="custom_workshop_vector"/> <Offset name="custom_workshop_name" value="0x4" /> INVALID!
<Offset name="custom_workshop_name"/> <Offset name="custom_workshop_type" value="0x20" /> INVALID!
<Offset name="custom_workshop_type"/>
--> -->
</Group> </Group>
<Group name="Position" valid="false">
<Address name="cursor_xyz" value="0xb127f0" valid="true" />
<Address name="window_dims" value="0xb1307c" valid="true" />
<Address name="window_x" value="0xe8dee4" valid="true" />
<Address name="window_y" value="0xebbfb8" valid="true" />
<Address name="window_z" value="0xebbf94" valid="true" />
</Group>
<Group name="GUI" valid="false">
<Address name="pause_state" value="0x14c9be1" valid="true" />
</Group>
<Group name="Maps">
<Group name="features">
<Group name="global">
<Address name="vector" value="0x16e4c30" />
</Group>
<Group name="local">
<Address name="start_ptr" value="0x16e4cc4" />
</Group>
</Group>
<Group name="geology">
<Address name="geoblock_vector" value="0x16E4C50" />
<Address name="ptr2_region_array" value="0x16E4C80" />
</Group>
</Group>
<Group name="Creatures" valid="false" >
0x016a12c0 vector
</Group>
<Group name="Materials" valid="false" >
<Address name="creature_type_vector" value="0x16E533C" valid="true" /> MAYBE... THE DETAILS WILL BE DIFFERENT
<Address name="inorganics" value="0x16e527C" valid="true" />
<!--<Address name="inorganics_gems?" value="0x16e528C" valid="true" />--> WTF IS THIS, I DON'T EVEN...
<Address name="organics_all" value="0x16e529C" valid="true" />
<Address name="organics_plants" value="0x16e52AC" valid="true" />
<Address name="organics_trees" value="0x16e52CC" valid="true" />
</Group>
<Group name="Constructions">
<Address name="vector" value="0x168d930"/>
</Group>
<Group name="Translations">
<Address name="language_vector" value="0x016e553c"/>
<Address name="translation_vector" value="0x016e551c"/>
</Group>
<!--
<Group name="Vegetation" valid="false">
<Address name="vector"/>
<Offset name="tree_desc_offset" valid="true"/>
</Group>
-->
<Group name="Items" valid="false">
<!-- most of those seem completely unused! -->
<Address name="items_vector" />
List of offsets in the VTable :
<Offset name="item_type_accessor" />
<Offset name="item_subtype_accessor" />
<Offset name="item_subindex_accessor" />
<Offset name="item_index_accessor" />
<Offset name="item_quality_accessor" />
<Offset name="item_improvement_vector" />
<Offset name="item_improvement_subindex" />
<Offset name="item_improvement_index" />
<Offset name="item_improvement_quality" />
<Offset name="item_type_accessor" /> (in the vtable)
</Group>
<Group name="World" valid="false">
<Address name="current_tick" description="Current time of the year" />
<Address name="current_year" description="Current year" />
<Address name="current_weather" value="0x14c9bb8" valid="true" />
</Group>
</Offsets> </Offsets>
</Version> </Version>
<Version name="v0.31.19 SDL" os="windows" base="v0.31.18 SDL">
<PETimeStamp value="0x4D5BC345" />
<MD5 value="b7d1ff74835e5e8220a7e81e31f5a28d" />
<Offsets valid="false">
<Group name="string" valid="true" />
<Group name="vector" valid="true" />
<Group name="name" valid="true" />
<Group name="Position" valid="false">
<Address name="cursor_xyz" value="0xb4a7f0" valid="true" />
<Address name="window_dims" value="0xb4b07c" valid="true" />
<Address name="window_x" value="0xec6984" valid="true" />
<Address name="window_y" value="0xef4ba0" valid="true" />
<Address name="window_z" value="0xef4b7c" valid="true" />
</Group>
<Group name="Maps" valid="true">
<Address name="map_data" value="0x171C128" />
<Address name="x_count_block" value="0x171c140" />
<Address name="y_count_block" value="0x171c144" />
<Address name="z_count_block" value="0x171c148" />
<Address name="x_count" value="0x171c14C" />
<Address name="y_count" value="0x171c150" />
<Address name="z_count" value="0x171c154" />
<Address name="region_x" value="0x171c158" />
<Address name="region_y" value="0x171c15C" />
<Address name="region_z" value="0x171c160" /> TODO: it's signed!
<Address name="world_size_x" value="0x171d7e4" />
<Address name="world_size_y" value="0x171d7e6" />
<Group name="block">
<Offset name="vein_vector" value="0x8" />
<Offset name="feature_global" value="0x28" />
<Offset name="feature_local" value="0x24" />
<Offset name="type" value="0x7a" />
<Offset name="designation" value="0x27c" />
<Offset name="occupancy" value="0x67c" />
<Offset name="pathfinding" value="0xd7c" />
<Offset name="temperature1" value="0x157c" />
<Offset name="temperature2" value="0x177c" /><!-- looks strange, possibly invalid -->
<Offset name="biome_stuffs" value="0x1d7c" /><!-- possibly invalid -->
</Group>
<Group name="features">
<Group name="global">
<Address name="vector" value="0x171de84" />
<Offset name="funcptr" value="0xd8" />
<Offset name="material" value="0x2c" />
<Offset name="submaterial" value="0x30" />
</Group>
<Group name="local">
<Address name="start_ptr" value="0x171df18" />
<Offset name="material" value="0x28" />
<Offset name="submaterial" value="0x2c" />
</Group>
</Group>
<Group name="geology"> LOOKS FINE?
<Address name="geoblock_vector" value="0x171dea4" />
<Address name="ptr2_region_array" value="0x171ded4" /> VERIFIED
<Offset name="geolayer_geoblock_offset" value="0x4" />
<Offset name="region_geo_index_off" value="0x58" /> VERIFIED
<Offset name="type_inside_geolayer" value="0x4" />
<HexValue name="region_size" value="0x5c" /> VERIFIED
</Group>
</Group>
<Group name="Materials" valid="false" >
<Address name="creature_type_vector" value="0x171e880" valid="true" />
<Address name="inorganics" value="0x171e790" valid="true" />
<Address name="organics_all" value="0x171e7B0" valid="true" />
<Address name="organics_plants" value="0x171e7C0" valid="true" />
<Address name="organics_trees" value="0x171e7E0" valid="true" />
</Group>
<Group name="GUI" valid="false">
<Address name="pause_state" value="0x14c9be1" valid="true" />
</Group>
<Group name="Vegetation" valid="true">
<Address name="vector" value="0x16db478" />
</Group>
<Group name="Constructions" valid="true">
<Address name="vector" value="0x16c6ae8" />
</Group>
<Group name="Buildings" valid="true">
<Address name="buildings_vector" value="0x16dad78" valid="true" />
One of those really. Which one is the right one?
0x16dad78
0x16dad88
<Address name="custom_workshop_vector" value="0x1724204" valid="true" />
Let's assume those didn't change...
<!--
<Offset name="building_custom_workshop_type" value="0x11c" /> INVALID?
<Offset name="custom_workshop_name" value="0x4" /> INVALID?
<Offset name="custom_workshop_type" value="0x20" /> INVALID?
-->
</Group>
<Group name="World" valid="false">
<Address name="current_tick" description="Current time of the year" />
<Address name="current_year" description="Current year" />
<Address name="current_weather" value="0x15027A0" valid="true" />
</Group>
<!--
<Address name="WORLD" valid="false" />
<Group name="Maps">
<Group name="features">
<Group name="global">
<Address name="vector" value="0x16e4c30" />
</Group>
<Group name="local">
<Address name="start_ptr" value="0x16e4cc4" />
</Group>
</Group>
<Group name="geology">
<Address name="geoblock_vector" value="0x16E4C50" />
<Address name="ptr2_region_array" value="0x16E4C80" />
</Group>
</Group>
<Group name="Creatures" valid="false" >
0x016a12c0 vector
</Group>
<Group name="Translations">
<Address name="language_vector" value="0x016e553c"/>
<Address name="translation_vector" value="0x016e551c"/>
</Group>
<Group name="Items" valid="false">
<Address name="items_vector" />
List of offsets in the VTable :
<Offset name="item_type_accessor" />
<Offset name="item_subtype_accessor" />
<Offset name="item_subindex_accessor" />
<Offset name="item_index_accessor" />
<Offset name="item_quality_accessor" />
<Offset name="item_improvement_vector" />
<Offset name="item_improvement_subindex" />
<Offset name="item_improvement_index" />
<Offset name="item_improvement_quality" />
<Offset name="item_type_accessor" /> (in the vtable)
</Group>
-->
</Offsets>
</Version>
.-"""-. .-"""-.
' \ ' \
|,. ,-. | _________________________ |,. ,-. | _________________________
@ -1662,7 +2037,7 @@
<MD5 value="fea3801a26538b1741f3cc9294139fca" /> <MD5 value="fea3801a26538b1741f3cc9294139fca" />
<Offsets> <Offsets>
<Address name="WORLD" value="0x92C60E0" valid="false" /> <Address name="WORLD" value="0x92C60E0" valid="false" />
<Group name="vector" valid="true"> <Group name="vector">
<HexValue name="sizeof" value="0xC" /> <HexValue name="sizeof" value="0xC" />
<Offset name="start" value="0x0" /> <Offset name="start" value="0x0" />
<!-- <!--
@ -1672,10 +2047,10 @@
DWORD AllocationEnd DWORD AllocationEnd
--> -->
</Group> </Group>
<Group name="string" valid="true"> <Group name="string">
<HexValue name="sizeof" value="0x4" /> <HexValue name="sizeof" value="0x4" />
</Group> </Group>
<Group name="name" valid="true"> <Group name="name">
<Offset name="first" value="0x0" /> <Offset name="first" value="0x0" />
<Offset name="nick" value="0x4" /> <Offset name="nick" value="0x4" />
<Offset name="second_words" value="0x8" /> <Offset name="second_words" value="0x8" />
@ -1703,7 +2078,7 @@
<Address name="region_z" value="0x9318D74" /> <Address name="region_z" value="0x9318D74" />
<Address name="world_size_x" value="0x931A3C0" /> <Address name="world_size_x" value="0x931A3C0" />
<Address name="world_size_y" value="0x931A3C2" /> <Address name="world_size_y" value="0x931A3C2" />
<Group name="block" valid="true"> <Group name="block">
<Offset name="vein_vector" value="0x08" /> <Offset name="vein_vector" value="0x08" />
<Offset name="feature_local" value="0x20" /> <Offset name="feature_local" value="0x20" />
<Offset name="feature_global" value="0x24" /> <Offset name="feature_global" value="0x24" />
@ -1743,7 +2118,7 @@
<Address name="vector" value="0x92D9AC0" /> <Address name="vector" value="0x92D9AC0" />
<Address name="current_race" value="0x92C1628" /> <Address name="current_race" value="0x92C1628" />
<Address name="current_civ" value="0x92C161C" /> <Address name="current_civ" value="0x92C161C" />
<Group name="creature" valid="verify" > <Group name="creature">
<Offset name="name" value="0x0" /> <Offset name="name" value="0x0" />
<Offset name="custom_profession" value="0x3c" /> <Offset name="custom_profession" value="0x3c" />
<Offset name="profession" value="0x40" /> <Offset name="profession" value="0x40" />
@ -1801,7 +2176,7 @@
<Address name="organics_plants" value="0x931aea0" /><!-- plant matter, WORLD + 0x54BAC --> <Address name="organics_plants" value="0x931aea0" /><!-- plant matter, WORLD + 0x54BAC -->
<Address name="organics_trees" value="0x931aeb8" /><!-- just wood, WORLD + 0x54BDC --> <Address name="organics_trees" value="0x931aeb8" /><!-- just wood, WORLD + 0x54BDC -->
<Address name="creature_type_vector" value="0x931af34" /><!-- creature types, WORLD + 0x54CD0 --> <Address name="creature_type_vector" value="0x931af34" /><!-- creature types, WORLD + 0x54CD0 -->
<Group name="creature" valid="verify"> <Group name="creature"> VERIFY
<Offset name="caste_vector" value="0x60" /> <Offset name="caste_vector" value="0x60" />
<Offset name="extract_vector" value="0x18f4" /> <Offset name="extract_vector" value="0x18f4" />
<Offset name="tile" value="0x20" /> <Offset name="tile" value="0x20" />
@ -1876,15 +2251,15 @@
<MD5 value="4f1f988bc1b425d4193d3d8b7b0579a5" /> <MD5 value="4f1f988bc1b425d4193d3d8b7b0579a5" />
<Offsets> <Offsets>
<Group name="Creatures"> <Group name="Creatures">
<Group name="creature" valid="verify" > <Group name="creature"> VERIFY
<Group name="advanced"> <Group name="advanced">
<Offset name="soul_vector" value="0x0524" /> <Offset name="soul_vector" value="0x0524" />
<Offset name="current_soul" value="0x0530" valid="verify" /> <Offset name="current_soul" value="0x0530" />
<Offset name="labors" value="0x540" /> <Offset name="labors" value="0x540" />
<Offset name="happiness" value="0x5d0" /> <Offset name="happiness" value="0x5d0" />
</Group> </Group>
</Group> </Group>
<Group name="soul" valid="verify"> <Group name="soul">
<Offset name="name" value="0x0" /> <Offset name="name" value="0x0" />
<Offset name="mental" value="0x88" /> <Offset name="mental" value="0x88" />
<Offset name="skills_vector" value="0x1C4" /> CHMOD <Offset name="skills_vector" value="0x1C4" /> CHMOD
@ -1995,11 +2370,76 @@
<Address name="window_z" value="0x8ceb240" /> <Address name="window_z" value="0x8ceb240" />
<Address name="cursor_xyz" value="0x8b2e740" /> <Address name="cursor_xyz" value="0x8b2e740" />
<Address name="window_dims" value="0x8b2ec48" /> <Address name="window_dims" value="0x8b2ec48" />
<Address name="screen_tiles_pointer" invalid = "true" /> <Address name="screen_tiles_pointer" valid = "false" />
</Group>
<Group name="GUI">
<Address name="pause_state" value="0x92e0e90"/>
</Group>
<Group name="Vegetation">
<Address name="vector" value="0x92fbdc8" />
</Group>
<Group name="World">
<Address name="current_year" value="0x92e0da0" />
<Address name="current_tick" value="0x92e0dc0" />
<Address name="current_weather" value="0x092E0D84" />
</Group>
</Offsets>
</Version>
<Version name="v0.31.14 linux" os="linux" base="v0.31.13 linux" rebase="0x330C">
<MD5 value="128c562c7936aa8f84786f69426f0691" />
<Offsets>
<Group name="Maps">
<Address name="map_data" value="0x933d7e0" />
<Address name="x_count_block" value="0x933d7F4" />
<Address name="y_count_block" value="0x933d7F8" />
<Address name="z_count_block" value="0x933d7FC" />
<Address name="x_count" value="0x933d800" />
<Address name="y_count" value="0x933d804" />
<Address name="z_count" value="0x933d808" />
<Address name="region_x" value="0x933d80C" />
<Address name="region_y" value="0x933d810" />
<Address name="region_z" value="0x933d814" />
<Address name="world_size_x" value="0x933ee60" />
<Address name="world_size_y" value="0x933ee62" />
<Group name="features">
<Group name="global">
<Address name="vector" value="0x933f408" />0x933c0fc
</Group>
<Group name="local">
<Address name="start_ptr" value="0x933F480" />
</Group>
</Group>
<Group name="geology">
<Address name="geoblock_vector" value="0x933f420" />
<Address name="ptr2_region_array" value="0x933f444" />
</Group>
</Group>
<Group name="Buildings">
<Address name="buildings_vector" value="0x92febdc 0x92fb8e8" /> Alt:0x92febe8
</Group>
<Group name="Constructions">
<Address name="vector" value="0x92eac04 0x92e7904" />
</Group>
<!--
<Group name="Creatures">
<Address name="current_civ" value="0x92e2d9c" />
<Address name="current_race" value="0x92e2da8" />
<Address name="vector" value="0x92fb260" />
</Group>
-->
<Group name="Position">
<Address name="window_x" value="0x8cee538 0x8ceb238" />
<Address name="window_y" value="0x8cee53C 0x8ceb23C" />
<Address name="window_z" value="0x8cee540 0x8ceb240" />
<Address name="cursor_xyz" value="0x8b31a30 0x8b2e740" />
<Address name="window_dims" value="0x8b31f48 0x8b2ec48" />
<Address name="screen_tiles_pointer" valid = "false" />
</Group> </Group>
<Group name="GUI"> <Group name="GUI">
<Address name="pause_state" value="0x92e0e90"/> <Address name="pause_state" value="0x92e0e90"/>
</Group> </Group>
<!--
<Group name="Vegetation"> <Group name="Vegetation">
<Address name="vector" value="0x92fbdc8" /> <Address name="vector" value="0x92fbdc8" />
</Group> </Group>
@ -2008,6 +2448,133 @@
<Address name="current_tick" value="0x92e0dc0" /> <Address name="current_tick" value="0x92e0dc0" />
<Address name="current_weather" value="0x092E0D84" /> <Address name="current_weather" value="0x092E0D84" />
</Group> </Group>
-->
</Offsets>
</Version>
<Version name="faek" os="linux" base="v0.31.14 linux">
<Offsets>
<Group name="Position" valid="false" />
</Offsets>
</Version>
<Version name="v0.31.16 linux" os="linux" base="faek" rebase="0x1b40">
<MD5 value="9cca2fa5da509e2f9a1042ddd1f9669c" />
<Offsets>
<Group name="Position">
<Address name="cursor_xyz" value="0x8b33550" />
</Group>
<Group name="GUI">
<Address name="pause_state" value="0x92e5cb0"/>
</Group>
</Offsets>
</Version>
<Version name="v0.31.18 linux" os="linux" base="faek">
<MD5 value="884f794d8e89e7d764057c15617c20b1" />
<Offsets valid="false">
<Group name="Maps" valid="true">
<Address name="map_data" value="0x93c0430" />
<Address name="region_x" value="0x93c045c" />
<Address name="region_y" value="0x93c0460" />
<Address name="region_z" value="0x93c0464" />
<Address name="x_count_block" value="0x93c0444" />
<Address name="y_count_block" value="0x93c0448" />
<Address name="z_count_block" value="0x93c044c" />
<Address name="x_count" value="0x93c0450" />
<Address name="y_count" value="0x93c0454" />
<Address name="z_count" value="0x93c0458" />
<Address name="world_size_x" value="0x93c1ab0" />
<Address name="world_size_y" value="0x93c1ab2" />
<Group name="block" valid="true" />
<Group name="features" valid="false" />
<Group name="geology" valid="false" />
</Group>
<Group name="GUI">
<Address name="pause_state" value="0x9366cb0"/>
</Group>
<Group name="string" valid="true" />
<Group name="vector" valid="true" />
<Group name="name" valid="true" />
</Offsets>
</Version>
<Version name="v0.31.19 linux" os="linux" base="v0.31.18 linux" rebase="0x77738">
<MD5 value="8fcb1f10af9cc2bda47d2acf42e1db54" />
<Offsets>
<Group name="Position">
<Address name="cursor_xyz" value="0x8c2b560" />
<Address name="window_dims" value="0x8ba9680" />
<Address name="window_x" value="0x8d65c70" />
<Address name="window_y" value="0x8d65c74" />
<Address name="window_z" value="0x8d65c78" />
</Group>
<Group name="Maps">
<Address name="world_size_x" value="0x94391f0" />
<Address name="world_size_y" value="0x94391f2" />
<Group name="features" valid="true">
<Group name="global">
<Address name="vector" value="0x94397cc" />
<!--
<Offset name="funcptr" value="0x94" />
<Offset name="material" value="0x28" />
<Offset name="submaterial" value="0x2c" />
-->
</Group>
<Group name="local">
<Address name="start_ptr" value="0x9439844" />
<!--
<Offset name="material" value="0x24" />
<Offset name="submaterial" value="0x28" />
-->
</Group>
</Group>
<Group name="geology" valid="true">
<Address name="geoblock_vector" value="0x94397e4" />
<Address name="ptr2_region_array" value="0x9439808" />
</Group>
</Group>
<Group name="GUI">
<Address name="pause_state" value="0x93dddf0" />
</Group>
<Group name="Materials">
<Address name="creature_type_vector" value="0x943a074" />
<Address name="inorganics" value="0x9439fc0" />
<Address name="organics_all" value="0x9439fd8" />
<Address name="organics_plants" value="0x9439fe4" />
<Address name="organics_trees" value="0x9439ffc" />
-------------------
!!LANGUAGE TABLES!!
-------------------
translation vector: 0x943a21c
lang vector: 0x943a204
word table offset: 0x1c
-------------
!!MATERIALS!!
-------------
inorganics:
0x9439fc0
organics:
0x9439fd8
organics 31.19:
trees:
0x9439ffc
plants:
0x9439fe4
color descriptors:
0x943e368
Amber color:0xa380190
all descriptors:
0x943e380
toad-first creature types:
0x943a074
all creature types:
0x943a068
0x943a074
Toad: 0xa441f10
Toad: rawname = 0x0
Toad: character (not reliable) = 0x20
Toad: caste vector = 0x60
Toad: extract? vector = 0x1f74
Toad: colors = 0x38
</Group>
</Offsets> </Offsets>
</Version> </Version>
</DFHack> </DFHack>

@ -29,6 +29,10 @@ include_directories (${CMAKE_SOURCE_DIR}/library/private/)
SET(PROJECT_HDRS_INTERNAL SET(PROJECT_HDRS_INTERNAL
private/ContextShared.h private/ContextShared.h
private/Internal.h private/Internal.h
private/SHMProcess.h
private/LinuxProcess.h
private/ProcessFactory.h
private/MicrosoftSTL.h
) )
SET(PROJECT_HDRS SET(PROJECT_HDRS
@ -86,8 +90,11 @@ VersionInfo.cpp
VersionInfoFactory.cpp VersionInfoFactory.cpp
DFContextManager.cpp DFContextManager.cpp
DFContext.cpp DFContext.cpp
DFTileTypes.cpp
DFProcessEnumerator.cpp DFProcessEnumerator.cpp
ContextShared.cpp ContextShared.cpp
DFProcess-SHM.cpp
MicrosoftSTL.cpp
depends/md5/md5.cpp depends/md5/md5.cpp
depends/md5/md5wrapper.cpp depends/md5/md5wrapper.cpp
@ -137,6 +144,7 @@ include/dfhack/DFstdint_win.h
SET(PROJECT_SRCS_LINUX SET(PROJECT_SRCS_LINUX
DFProcess-linux.cpp DFProcess-linux.cpp
DFProcess-linux-base.cpp
DFProcess-linux-SHM.cpp DFProcess-linux-SHM.cpp
DFProcess-linux-wine.cpp DFProcess-linux-wine.cpp
modules/WindowIO-linux.cpp modules/WindowIO-linux.cpp
@ -190,7 +198,12 @@ IF(UNIX)
SET(PROJECT_LIBS ${X11_LIBRARY} rt ) #dfhack-md5 dfhack-tixml SET(PROJECT_LIBS ${X11_LIBRARY} rt ) #dfhack-md5 dfhack-tixml
ELSE(UNIX) ELSE(UNIX)
SET(PROJECT_LIBS psapi) IF(MSVC)
SET(PROJECT_LIBS psapi ${CMAKE_SOURCE_DIR}/library/depends/ntdll/ntdll.lib)
ELSE(MSVC)
SET(PROJECT_LIBS psapi ntdll)
ENDIF(MSVC)
ENDIF(UNIX) ENDIF(UNIX)
ADD_LIBRARY(dfhack SHARED ${PROJECT_SRCS}) ADD_LIBRARY(dfhack SHARED ${PROJECT_SRCS})

@ -31,7 +31,7 @@ DFContextShared::DFContextShared()
DFContextShared::~DFContextShared() DFContextShared::~DFContextShared()
{ {
// invalidate all modules // invalidate all modules
for(int i = 0 ; i < allModules.size(); i++) for(unsigned int i = 0 ; i < allModules.size(); i++)
{ {
delete allModules[i]; delete allModules[i];
} }

@ -93,68 +93,12 @@ bool Context::Detach()
} }
d->shm_start = 0; d->shm_start = 0;
// invalidate all modules // invalidate all modules
for(int i = 0 ; i < d->allModules.size(); i++) for(unsigned int i = 0 ; i < d->allModules.size(); i++)
{ {
delete d->allModules[i]; delete d->allModules[i];
} }
d->allModules.clear(); d->allModules.clear();
memset(&(d->s_mods), 0, sizeof(d->s_mods)); memset(&(d->s_mods), 0, sizeof(d->s_mods));
/*
if(d->creatures)
{
delete d->creatures;
d->creatures = 0;
}
if(d->maps)
{
delete d->maps;
d->maps = 0;
}
if(d->gui)
{
delete d->gui;
d->gui = 0;
}
if(d->world)
{
delete d->world;
d->world = 0;
}
if(d->position)
{
delete d->position;
d->position = 0;
}
if(d->materials)
{
delete d->materials;
d->materials = 0;
}
if(d->items)
{
delete d->items;
d->items = 0;
}
if(d->translation)
{
delete d->translation;
d->translation = 0;
}
if(d->vegetation)
{
delete d->vegetation;
d->vegetation = 0;
}
if(d->constructions)
{
delete d->constructions;
d->constructions = 0;
}
if(d->translation)
{
delete d->translation;
d->translation = 0;
}*/
return true; return true;
} }
@ -174,7 +118,7 @@ bool Context::AsyncSuspend()
bool Context::Resume() bool Context::Resume()
{ {
for(int i = 0 ; i < d->allModules.size(); i++) for(unsigned int i = 0 ; i < d->allModules.size(); i++)
{ {
d->allModules[i]->OnResume(); d->allModules[i]->OnResume();
} }
@ -236,386 +180,3 @@ MODULE_GETTER(Translation);
MODULE_GETTER(Vegetation); MODULE_GETTER(Vegetation);
MODULE_GETTER(Buildings); MODULE_GETTER(Buildings);
MODULE_GETTER(Constructions); MODULE_GETTER(Constructions);
/*
Creatures * Context::getCreatures()
{
if(!d->creatures)
d->creatures = new Creatures(d);
return d->creatures;
}
*/
/*
Maps * Context::getMaps()
{
if(!d->maps)
d->maps = new Maps(d);
return d->maps;
}
Gui * Context::getGui()
{
if(!d->gui)
d->gui = new Gui(d);
return d->gui;
}
WindowIO * Context::getWindow()
{
if(!d->windowio)
d->windowio = new WindowIO(d);
return d->windowio;
}
World * Context::getWorld()
{
if(!d->world)
d->world = new World(d);
return d->world;
}
Position * Context::getPosition()
{
if(!d->position)
d->position = new Position(d);
return d->position;
}
Materials * Context::getMaterials()
{
if(!d->materials)
d->materials = new Materials(d);
return d->materials;
}
Items * Context::getItems()
{
if(!d->items)
d->items = new Items(d);
return d->items;
}
Translation * Context::getTranslation()
{
if(!d->translation)
d->translation = new Translation(d);
return d->translation;
}
Vegetation * Context::getVegetation()
{
if(!d->vegetation)
d->vegetation = new Vegetation(d);
return d->vegetation;
}
Buildings * Context::getBuildings()
{
if(!d->buildings)
d->buildings = new Buildings(d);
return d->buildings;
}
Constructions * Context::getConstructions()
{
if(!d->constructions)
d->constructions = new Constructions(d);
return d->constructions;
}
*/
/*
// returns number of buildings, expects v_buildingtypes that will later map t_building.type to its name
bool API::InitReadEffects ( uint32_t & numeffects )
{
if(d->effectsInited)
FinishReadEffects();
int effects = 0;
try
{
effects = d->offset_descriptor->getAddress ("effects_vector");
}
catch(Error::MissingMemoryDefinition)
{
return false;
}
d->effectsInited = true;
d->p_effect = new DfVector (d->p, effects);
numeffects = d->p_effect->getSize();
return true;
}
bool API::ReadEffect(const uint32_t index, t_effect_df40d & effect)
{
if(!d->effectsInited)
return false;
if(index >= d->p_effect->getSize())
return false;
// read pointer from vector at position
uint32_t temp = d->p_effect->at (index);
//read effect from memory
d->p->read (temp, sizeof (t_effect_df40d), (uint8_t *) &effect);
return true;
}
// use with care!
bool API::WriteEffect(const uint32_t index, const t_effect_df40d & effect)
{
if(!d->effectsInited)
return false;
if(index >= d->p_effect->getSize())
return false;
// read pointer from vector at position
uint32_t temp = d->p_effect->at (index);
// write effect to memory
d->p->write(temp,sizeof(t_effect_df40d), (uint8_t *) &effect);
return true;
}
void API::FinishReadEffects()
{
if(d->p_effect)
{
delete d->p_effect;
d->p_effect = NULL;
}
d->effectsInited = false;
}
*/
/*
bool API::InitReadNotes( uint32_t &numnotes )
{
try
{
memory_info * minfo = d->offset_descriptor;
int notes = minfo->getAddress ("notes");
d->note_foreground_offset = minfo->getOffset ("note_foreground");
d->note_background_offset = minfo->getOffset ("note_background");
d->note_name_offset = minfo->getOffset ("note_name");
d->note_xyz_offset = minfo->getOffset ("note_xyz");
d->p_notes = new DfVector (d->p, notes);
d->notesInited = true;
numnotes = d->p_notes->getSize();
return true;
}
catch (Error::MissingMemoryDefinition&)
{
d->notesInited = false;
numnotes = 0;
throw;
}
}
bool API::ReadNote (const int32_t index, t_note & note)
{
if(!d->notesInited) return false;
// read pointer from vector at position
uint32_t temp = d->p_notes->at (index);
note.symbol = d->p->readByte(temp);
note.foreground = d->p->readWord(temp + d->note_foreground_offset);
note.background = d->p->readWord(temp + d->note_background_offset);
d->p->readSTLString (temp + d->note_name_offset, note.name, 128);
d->p->read (temp + d->note_xyz_offset, 3*sizeof (uint16_t), (uint8_t *) &note.x);
return true;
}
bool API::InitReadSettlements( uint32_t & numsettlements )
{
if(!d->InitReadNames()) return false;
try
{
memory_info * minfo = d->offset_descriptor;
int allSettlements = minfo->getAddress ("settlements");
int currentSettlement = minfo->getAddress("settlement_current");
d->settlement_name_offset = minfo->getOffset ("settlement_name");
d->settlement_world_xy_offset = minfo->getOffset ("settlement_world_xy");
d->settlement_local_xy_offset = minfo->getOffset ("settlement_local_xy");
d->p_settlements = new DfVector (d->p, allSettlements);
d->p_current_settlement = new DfVector(d->p, currentSettlement);
d->settlementsInited = true;
numsettlements = d->p_settlements->getSize();
return true;
}
catch (Error::MissingMemoryDefinition&)
{
d->settlementsInited = false;
numsettlements = 0;
throw;
}
}
bool API::ReadSettlement(const int32_t index, t_settlement & settlement)
{
if(!d->settlementsInited) return false;
if(!d->p_settlements->getSize()) return false;
// read pointer from vector at position
uint32_t temp = d->p_settlements->at (index);
settlement.origin = temp;
d->readName(settlement.name, temp + d->settlement_name_offset);
d->p->read(temp + d->settlement_world_xy_offset, 2 * sizeof(int16_t), (uint8_t *) &settlement.world_x);
d->p->read(temp + d->settlement_local_xy_offset, 4 * sizeof(int16_t), (uint8_t *) &settlement.local_x1);
return true;
}
bool API::ReadCurrentSettlement(t_settlement & settlement)
{
if(!d->settlementsInited) return false;
if(!d->p_current_settlement->getSize()) return false;
uint32_t temp = d->p_current_settlement->at(0);
settlement.origin = temp;
d->readName(settlement.name, temp + d->settlement_name_offset);
d->p->read(temp + d->settlement_world_xy_offset, 2 * sizeof(int16_t), (uint8_t *) &settlement.world_x);
d->p->read(temp + d->settlement_local_xy_offset, 4 * sizeof(int16_t), (uint8_t *) &settlement.local_x1);
return true;
}
void API::FinishReadSettlements()
{
if(d->p_settlements)
{
delete d->p_settlements;
d->p_settlements = NULL;
}
if(d->p_current_settlement)
{
delete d->p_current_settlement;
d->p_current_settlement = NULL;
}
d->settlementsInited = false;
}
bool API::getItemIndexesInBox(vector<uint32_t> &indexes,
const uint16_t x1, const uint16_t y1, const uint16_t z1,
const uint16_t x2, const uint16_t y2, const uint16_t z2)
{
if(!d->itemsInited) return false;
indexes.clear();
uint32_t size = d->p_itm->getSize();
struct temp2{
uint16_t coords[3];
uint32_t flags;
};
temp2 temp2;
for(uint32_t i =0;i<size;i++){
uint32_t temp = d->p_itm->at(i);
d->p->read(temp+sizeof(uint32_t),5 * sizeof(uint16_t), (uint8_t *) &temp2);
if(temp2.flags & (1 << 0)){
if (temp2.coords[0] >= x1 && temp2.coords[0] < x2)
{
if (temp2.coords[1] >= y1 && temp2.coords[1] < y2)
{
if (temp2.coords[2] >= z1 && temp2.coords[2] < z2)
{
indexes.push_back(i);
}
}
}
}
}
return true;
}
*/
/*
void API::FinishReadNotes()
{
if(d->p_notes)
{
delete d->p_notes;
d->p_notes = 0;
}
d->notesInited = false;
}
*/
/*
bool API::InitReadItems(uint32_t & numitems)
{
try
{
int items = d->offset_descriptor->getAddress ("items");
d->item_material_offset = d->offset_descriptor->getOffset ("item_materials");
d->p_itm = new DfVector (d->p, items);
d->itemsInited = true;
numitems = d->p_itm->getSize();
return true;
}
catch (Error::MissingMemoryDefinition&)
{
d->itemsInited = false;
numitems = 0;
throw;
}
}
bool API::ReadItem (const uint32_t index, t_item & item)
{
if (!d->itemsInited) return false;
t_item_df40d item_40d;
// read pointer from vector at position
uint32_t temp = d->p_itm->at (index);
//read building from memory
d->p->read (temp, sizeof (t_item_df40d), (uint8_t *) &item_40d);
// transform
int32_t type = -1;
d->offset_descriptor->resolveObjectToClassID (temp, type);
item.origin = temp;
item.vtable = item_40d.vtable;
item.x = item_40d.x;
item.y = item_40d.y;
item.z = item_40d.z;
item.type = type;
item.ID = item_40d.ID;
item.flags.whole = item_40d.flags;
//TODO certain item types (creature based, threads, seeds, bags do not have the first matType byte, instead they have the material index only located at 0x68
d->p->read (temp + d->item_material_offset, sizeof (t_matglossPair), (uint8_t *) &item.material);
//for(int i = 0; i < 0xCC; i++){ // used for item research
// uint8_t byte = MreadByte(temp+i);
// item.bytes.push_back(byte);
//}
return true;
}
void API::FinishReadItems()
{
if(d->p_itm)
{
delete d->p_itm;
d->p_itm = NULL;
}
d->itemsInited = false;
}
*/
/*
bool API::ReadItemTypes(vector< vector< t_itemType > > & itemTypes)
{
memory_info * minfo = d->offset_descriptor;
int matgloss_address = minfo->getAddress("matgloss");
int matgloss_skip = minfo->getHexValue("matgloss_skip");
int item_type_name_offset = minfo->getOffset("item_type_name");
for(int i = 8;i<20;i++)
{
DfVector p_temp (d->p, matgloss_address + i*matgloss_skip);
vector< t_itemType > typesForVec;
for(uint32_t j =0; j<p_temp.getSize();j++)
{
t_itemType currType;
uint32_t temp = *(uint32_t *) p_temp[j];
// Mread(temp+40,sizeof(name),(uint8_t *) name);
d->p->readSTLString(temp+4,currType.id,128);
d->p->readSTLString(temp+item_type_name_offset,currType.name,128);
//stringsForVec.push_back(string(name));
typesForVec.push_back(currType);
}
itemTypes.push_back(typesForVec);
}
return true;
}
*/

@ -69,7 +69,7 @@ BadContexts::~BadContexts()
bool BadContexts::Contains(Process* p) bool BadContexts::Contains(Process* p)
{ {
for(int i = 0; i < d->bad.size(); i++) for(unsigned int i = 0; i < d->bad.size(); i++)
{ {
if((d->bad[i])->getProcess() == p) if((d->bad[i])->getProcess() == p)
return true; return true;
@ -79,7 +79,7 @@ bool BadContexts::Contains(Process* p)
bool BadContexts::Contains(Context* c) bool BadContexts::Contains(Context* c)
{ {
for(int i = 0; i < d->bad.size(); i++) for(unsigned int i = 0; i < d->bad.size(); i++)
{ {
if(d->bad[i] == c) if(d->bad[i] == c)
return true; return true;
@ -94,7 +94,7 @@ uint32_t BadContexts::size()
void BadContexts::clear() void BadContexts::clear()
{ {
for(int i = 0; i < d->bad.size(); i++) for(unsigned int i = 0; i < d->bad.size(); i++)
{ {
// delete both Process and Context! // delete both Process and Context!
// process has to be deleted after context, because Context does some // process has to be deleted after context, because Context does some
@ -227,7 +227,7 @@ Context * ContextManager::getSingleContext()
{ {
Refresh(); Refresh();
} }
for(int i = 0; i < d->contexts.size();i++) for(unsigned int i = 0; i < d->contexts.size();i++)
{ {
if(d->contexts[i]->isValid()) if(d->contexts[i]->isValid())
{ {
@ -239,7 +239,7 @@ Context * ContextManager::getSingleContext()
void ContextManager::purge(void) void ContextManager::purge(void)
{ {
for(int i = 0; i < d->contexts.size();i++) for(unsigned int i = 0; i < d->contexts.size();i++)
delete d->contexts[i]; delete d->contexts[i];
d->contexts.clear(); d->contexts.clear();
d->pEnum->purge(); d->pEnum->purge();

@ -0,0 +1,485 @@
/*
www.sourceforge.net/projects/dfhack
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#include "Internal.h"
#include "SHMProcess.h"
#include "ProcessFactory.h"
#include "dfhack/VersionInfo.h"
#include "dfhack/DFError.h"
#include "shms.h"
#include "mod-core.h"
using namespace DFHack;
Process* DFHack::createSHMProcess(uint32_t pid, vector <VersionInfo *> & known_versions)
{
return new SHMProcess(pid, known_versions);
}
SHMProcess::SHMProcess(uint32_t PID, vector <VersionInfo *> & known_versions)
: d(new Private(this))
{
d->process_ID = PID;
// attach the SHM
if(!attach())
{
return;
}
// Test bridge version, get PID, sync Yield
bool bridgeOK;
if(!d->Aux_Core_Attach(bridgeOK,d->process_ID))
{
detach();
throw Error::SHMAttachFailure();
}
else if(!bridgeOK)
{
detach();
throw Error::SHMVersionMismatch();
}
// try to identify the DF version (md5 the binary, compare with known versions)
d->validate(known_versions);
// at this point, DF is attached and suspended, make it run
detach();
}
SHMProcess::~SHMProcess()
{
if(d->attached)
{
detach();
}
// destroy data model. this is assigned by processmanager
if(d->memdescriptor)
delete d->memdescriptor;
delete d;
}
VersionInfo * SHMProcess::getDescriptor()
{
return d->memdescriptor;
}
int SHMProcess::getPID()
{
return d->process_ID;
}
bool SHMProcess::isSuspended()
{
return d->locked;
}
bool SHMProcess::isAttached()
{
return d->attached;
}
bool SHMProcess::isIdentified()
{
return d->identified;
}
bool SHMProcess::suspend()
{
if(!d->attached)
{
return false;
}
if(d->locked)
{
return true;
}
//cerr << "suspend" << endl;// FIXME: throw
// FIXME: this should be controlled on the server side
// FIXME: IF server got CORE_RUN in this frame, interpret CORE_SUSPEND as CORE_STEP
// did we just resume a moment ago?
if(D_SHMCMD == CORE_RUN)
{
//fprintf(stderr,"%d invokes step\n",attachmentIdx);
// wait for the next window
/*
if(!d->SetAndWait(CORE_STEP))
{
throw Error::SHMLockingError("if(!d->SetAndWait(CORE_STEP))");
}
*/
D_SHMCMD = CORE_STEP;
}
else
{
//fprintf(stderr,"%d invokes suspend\n",attachmentIdx);
// lock now
/*
if(!d->SetAndWait(CORE_SUSPEND))
{
throw Error::SHMLockingError("if(!d->SetAndWait(CORE_SUSPEND))");
}
*/
D_SHMCMD = CORE_SUSPEND;
}
//fprintf(stderr,"waiting for lock\n");
// we wait for the server to give up our suspend lock (held by default)
if(acquireSuspendLock())
{
d->locked = true;
return true;
}
return false;
}
// FIXME: needs a good think-through
bool SHMProcess::asyncSuspend()
{
if(!d->attached)
{
return false;
}
if(d->locked)
{
return true;
}
//cerr << "async suspend" << endl;// FIXME: throw
uint32_t cmd = D_SHMCMD;
if(cmd == CORE_SUSPENDED)
{
// we have to hold the lock to be really suspended
if(acquireSuspendLock())
{
d->locked = true;
return true;
}
return false;
}
else
{
// did we just resume a moment ago?
if(cmd == CORE_STEP)
{
return false;
}
else if(cmd == CORE_RUN)
{
D_SHMCMD = CORE_STEP;
}
else
{
D_SHMCMD = CORE_SUSPEND;
}
return false;
}
}
bool SHMProcess::forceresume()
{
return resume();
}
// FIXME: wait for the server to advance a step!
bool SHMProcess::resume()
{
if(!d->attached)
return false;
if(!d->locked)
return true;
//cerr << "resume" << endl;// FIXME: throw
// unlock the suspend lock
if(releaseSuspendLock())
{
d->locked = false;
if(d->SetAndWait(CORE_RUN)) // we have to make sure the server responds!
{
return true;
}
throw Error::SHMLockingError("if(d->SetAndWait(CORE_RUN))");
}
throw Error::SHMLockingError("if(releaseSuspendLock())");
return false;
}
// get module index by name and version. bool 0 = error
bool SHMProcess::getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT)
{
if(!d->locked) throw Error::MemoryAccessDenied();
modulelookup * payload = D_SHMDATA(modulelookup);
payload->version = version;
strncpy(payload->name,name,255);
payload->name[255] = 0;
if(!SetAndWait(CORE_ACQUIRE_MODULE))
{
return false; // FIXME: throw a fatal exception instead
}
if(D_SHMHDR->error)
{
return false;
}
//fprintf(stderr,"%s v%d : %d\n", name, version, D_SHMHDR->value);
OUTPUT = D_SHMHDR->value;
return true;
}
bool SHMProcess::Private::Aux_Core_Attach(bool & versionOK, pid_t & PID)
{
if(!locked) throw Error::MemoryAccessDenied();
SHMDATA(coreattach)->cl_affinity = OS_getAffinity();
if(!SetAndWait(CORE_ATTACH)) return false;
/*
cerr <<"CORE_VERSION" << CORE_VERSION << endl;
cerr <<"server CORE_VERSION" << SHMDATA(coreattach)->sv_version << endl;
*/
versionOK =( SHMDATA(coreattach)->sv_version == CORE_VERSION );
PID = SHMDATA(coreattach)->sv_PID;
useYield = SHMDATA(coreattach)->sv_useYield;
#ifdef DEBUG
if(useYield) cerr << "Using Yield!" << endl;
#endif
return true;
}
void SHMProcess::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer)
{
if(!d->locked) throw Error::MemoryAccessDenied();
// normal read under 1MB
if(size <= SHM_BODY)
{
D_SHMHDR->address = src_address;
D_SHMHDR->length = size;
full_barrier
d->SetAndWait(CORE_READ);
memcpy (target_buffer, D_SHMDATA(void),size);
}
// a big read, we pull data over the shm in iterations
else
{
// first read equals the size of the SHM window
uint32_t to_read = SHM_BODY;
while (size)
{
// read to_read bytes from src_cursor
D_SHMHDR->address = src_address;
D_SHMHDR->length = to_read;
full_barrier
d->SetAndWait(CORE_READ);
memcpy (target_buffer, D_SHMDATA(void) ,to_read);
// decrease size by bytes read
size -= to_read;
// move the cursors
src_address += to_read;
target_buffer += to_read;
// check how much to write in the next iteration
to_read = min(size, (uint32_t) SHM_BODY);
}
}
}
void SHMProcess::readByte (const uint32_t offset, uint8_t &val )
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_BYTE);
val = D_SHMHDR->value;
}
void SHMProcess::readWord (const uint32_t offset, uint16_t &val)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_WORD);
val = D_SHMHDR->value;
}
void SHMProcess::readDWord (const uint32_t offset, uint32_t &val)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_DWORD);
val = D_SHMHDR->value;
}
void SHMProcess::readQuad (const uint32_t offset, uint64_t &val)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_QUAD);
val = D_SHMHDR->Qvalue;
}
void SHMProcess::readFloat (const uint32_t offset, float &val)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_DWORD);
val = reinterpret_cast<float&> (D_SHMHDR->value);
}
/*
* WRITING
*/
void SHMProcess::writeQuad (uint32_t offset, uint64_t data)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
D_SHMHDR->Qvalue = data;
full_barrier
d->SetAndWait(CORE_WRITE_QUAD);
}
void SHMProcess::writeDWord (uint32_t offset, uint32_t data)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
D_SHMHDR->value = data;
full_barrier
d->SetAndWait(CORE_WRITE_DWORD);
}
// using these is expensive.
void SHMProcess::writeWord (uint32_t offset, uint16_t data)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
D_SHMHDR->value = data;
full_barrier
d->SetAndWait(CORE_WRITE_WORD);
}
void SHMProcess::writeByte (uint32_t offset, uint8_t data)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
D_SHMHDR->value = data;
full_barrier
d->SetAndWait(CORE_WRITE_BYTE);
}
void SHMProcess::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer)
{
if(!d->locked) throw Error::MemoryAccessDenied();
// normal write under 1MB
if(size <= SHM_BODY)
{
D_SHMHDR->address = dst_address;
D_SHMHDR->length = size;
memcpy(D_SHMDATA(void),source_buffer, size);
full_barrier
d->SetAndWait(CORE_WRITE);
}
// a big write, we push this over the shm in iterations
else
{
// first write equals the size of the SHM window
uint32_t to_write = SHM_BODY;
while (size)
{
// write to_write bytes to dst_cursor
D_SHMHDR->address = dst_address;
D_SHMHDR->length = to_write;
memcpy(D_SHMDATA(void),source_buffer, to_write);
full_barrier
d->SetAndWait(CORE_WRITE);
// decrease size by bytes written
size -= to_write;
// move the cursors
source_buffer += to_write;
dst_address += to_write;
// check how much to write in the next iteration
to_write = min(size, (uint32_t) SHM_BODY);
}
}
}
// FIXME: butt-fugly
const std::string SHMProcess::readCString (uint32_t offset)
{
if(!d->locked) throw Error::MemoryAccessDenied();
std::string temp;
char temp_c[256];
int counter = 0;
char r;
do
{
r = Process::readByte(offset+counter);
temp_c[counter] = r;
counter++;
} while (r && counter < 255);
temp_c[counter] = 0;
temp = temp_c;
return temp;
}
const std::string SHMProcess::readSTLString(uint32_t offset)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_STL_STRING);
return(string( D_SHMDATA(char) ));
}
size_t SHMProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_STL_STRING);
size_t length = D_SHMHDR->value;
size_t fit = min(bufcapacity - 1, length);
strncpy(buffer,D_SHMDATA(char),fit);
buffer[fit] = 0;
return fit;
}
void SHMProcess::writeSTLString(const uint32_t address, const std::string writeString)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = address;
strncpy(D_SHMDATA(char),writeString.c_str(),writeString.length()+1); // length + 1 for the null terminator
full_barrier
d->SetAndWait(CORE_WRITE_STL_STRING);
}

@ -22,7 +22,7 @@ must not be misrepresented as being the original software.
distribution. distribution.
*/ */
#include "Internal.h" #include "Internal.h"
#include "dfhack/DFProcess.h" #include "SHMProcess.h"
#include "dfhack/VersionInfo.h" #include "dfhack/VersionInfo.h"
#include "dfhack/DFError.h" #include "dfhack/DFError.h"
@ -39,76 +39,37 @@ distribution.
using namespace DFHack; using namespace DFHack;
// a full memory barrier! better be safe than sorry. SHMProcess::Private::Private(SHMProcess * self_)
#define gcc_barrier asm volatile("" ::: "memory"); __sync_synchronize();
class SHMProcess::Private
{ {
public: memdescriptor = NULL;
Private(Process * self_) process_ID = 0;
{ shm_ID = -1;
memdescriptor = NULL; attached = false;
process_ID = 0; identified = false;
shm_addr = 0; useYield = false;
//shm_addr_with_cl_idx = 0; server_lock = -1;
shm_ID = -1; client_lock = -1;
attached = false; suspend_lock = -1;
identified = false; locked = false;
useYield = false; self = self_;
server_lock = -1; }
client_lock = -1;
suspend_lock = -1;
attachmentIdx = 0;
locked = false;
self = self_;
};
~Private(){};
VersionInfo * memdescriptor;
Process * self;
pid_t process_ID;
char *shm_addr;
int shm_ID;
Process* q;
int server_lock;
int client_lock;
int suspend_lock;
int attachmentIdx;
bool attached;
bool locked;
bool identified;
bool useYield;
bool validate(std::vector< VersionInfo* >& known_versions);
bool Aux_Core_Attach(bool & versionOK, pid_t & PID);
//bool waitWhile (uint32_t state);
bool SetAndWait (uint32_t state);
bool GetLocks();
bool AreLocksOk();
void FreeLocks();
};
#define SHMCMD ( (uint32_t *) shm_addr)[attachmentIdx]
#define D_SHMCMD ( (uint32_t *) (d->shm_addr))[d->attachmentIdx]
#define SHMHDR ((shm_core_hdr *)shm_addr)
#define D_SHMHDR ((shm_core_hdr *)(d->shm_addr))
#define SHMDATA(type) ((type *)(shm_addr + SHM_HEADER))
#define D_SHMDATA(type) ((type *)(d->shm_addr + SHM_HEADER))
bool SHMProcess::Private::SetAndWait (uint32_t state) bool SHMProcess::Private::SetAndWait (uint32_t state)
{ {
uint32_t cnt = 0; uint32_t cnt = 0;
if(!attached) return false; if(!attached) return false;
SHMCMD = state; SHMCMD = state;
while (SHMCMD == state) while (SHMCMD == state)
{ {
// check if the other process is still there // yield the CPU, only on single-core CPUs
if(useYield)
{
SCHED_YIELD
}
if(cnt == 10000) if(cnt == 10000)
{ {
if(!AreLocksOk()) if(!AreLocksOk())// DF not there anymore?
{ {
//detach the shared memory //detach the shared memory
shmdt(shm_addr); shmdt(shm_addr);
@ -122,10 +83,6 @@ bool SHMProcess::Private::SetAndWait (uint32_t state)
cnt = 0; cnt = 0;
} }
} }
if(useYield)
{
SCHED_YIELD
}
cnt++; cnt++;
} }
// server returned a generic error // server returned a generic error
@ -155,21 +112,6 @@ uint32_t OS_getAffinity()
return affinity; return affinity;
} }
// test if we have client and server locks and the server is present
bool SHMProcess::Private::AreLocksOk()
{
// both locks are inited (we hold our lock)
if(client_lock != -1 && server_lock != -1)
{
if(lockf(server_lock,F_TEST,0) == -1) // and server holds its lock
{
return true; // OK, locks are good
}
}
// locks are bad
return false;
}
void SHMProcess::Private::FreeLocks() void SHMProcess::Private::FreeLocks()
{ {
attachmentIdx = -1; attachmentIdx = -1;
@ -258,50 +200,21 @@ bool SHMProcess::Private::GetLocks()
return false; return false;
} }
SHMProcess::SHMProcess(uint32_t PID, vector< VersionInfo* >& known_versions) // test if we have client and server locks and the server is present
: d(new Private(this)) bool SHMProcess::Private::AreLocksOk()
{ {
d->process_ID = PID; // both locks are inited (we hold our lock)
d->memdescriptor = 0; if(client_lock != -1 && server_lock != -1)
if(!attach())
{
// couldn't attach to process
return;
}
/*
* Test bridge version, get PID, sync Yield
*/
bool bridgeOK;
if(!d->Aux_Core_Attach(bridgeOK,d->process_ID))
{
detach();
throw Error::SHMAttachFailure();
}
if(!bridgeOK)
{ {
detach(); if(lockf(server_lock,F_TEST,0) == -1) // and server holds its lock
throw Error::SHMVersionMismatch(); {
return true; // OK, locks are good
}
} }
// locks are bad
// try to identify the DF version (md5 the binary, compare with known versions) return false;
d->validate(known_versions);
// detach
detach();
}
bool SHMProcess::isSuspended()
{
return d->locked;
}
bool SHMProcess::isAttached()
{
return d->attached;
} }
bool SHMProcess::isIdentified()
{
return d->identified;
}
bool SHMProcess::Private::validate(vector <VersionInfo *> & known_versions) bool SHMProcess::Private::validate(vector <VersionInfo *> & known_versions)
{ {
@ -333,13 +246,13 @@ bool SHMProcess::Private::validate(vector <VersionInfo *> & known_versions)
{ {
VersionInfo *m = new VersionInfo(**it); VersionInfo *m = new VersionInfo(**it);
memdescriptor = m; memdescriptor = m;
m->setParentProcess(dynamic_cast<Process *>( self )); m->setParentProcess(self);
identified = true; identified = true;
// cerr << "identified " << m->getVersion() << endl; // cerr << "identified " << m->getVersion() << endl;
return true; return true;
} }
} }
catch (Error::MissingMemoryDefinition&) catch (Error::AllMemdef&)
{ {
continue; continue;
} }
@ -347,27 +260,6 @@ bool SHMProcess::Private::validate(vector <VersionInfo *> & known_versions)
return false; return false;
} }
SHMProcess::~SHMProcess()
{
if(d->attached)
{
detach();
}
if(d->memdescriptor)
delete d->memdescriptor;
delete d;
}
VersionInfo * SHMProcess::getDescriptor()
{
return d->memdescriptor;
}
int SHMProcess::getPID()
{
return d->process_ID;
}
// there is only one we care about. // there is only one we care about.
bool SHMProcess::getThreadIDs(vector<uint32_t> & threads ) bool SHMProcess::getThreadIDs(vector<uint32_t> & threads )
{ {
@ -403,123 +295,19 @@ void SHMProcess::getMemRanges( vector<t_memrange> & ranges )
temp.read = permissions[0] == 'r'; temp.read = permissions[0] == 'r';
temp.write = permissions[1] == 'w'; temp.write = permissions[1] == 'w';
temp.execute = permissions[2] == 'x'; temp.execute = permissions[2] == 'x';
temp.valid = true;
ranges.push_back(temp); ranges.push_back(temp);
} }
} }
bool SHMProcess::suspend() bool SHMProcess::acquireSuspendLock()
{ {
if(!d->attached) return (lockf(d->suspend_lock,F_LOCK,0) == 0);
{
return false;
}
if(d->locked)
{
return true;
}
// FIXME: this should be controlled on the server side
// FIXME: IF server got CORE_RUN in this frame, interpret CORE_SUSPEND as CORE_STEP
// did we just resume a moment ago?
if(D_SHMCMD == CORE_RUN)
{
//fprintf(stderr,"%d invokes step\n",d->attachmentIdx);
/*
// wait for the next window
if(!d->SetAndWait(CORE_STEP))
{
throw Error::SHMLockingError("if(!d->SetAndWait(CORE_STEP))");
}
*/
D_SHMCMD = CORE_STEP;
}
else
{
//fprintf(stderr,"%d invokes suspend\n",d->attachmentIdx);
// lock now
/*
if(!d->SetAndWait(CORE_SUSPEND))
{
throw Error::SHMLockingError("if(!d->SetAndWait(CORE_SUSPEND))");
}
*/
D_SHMCMD = CORE_SUSPEND;
}
//fprintf(stderr,"waiting for lock\n");
// we wait for the server to give up our suspend lock (held by default)
if(lockf(d->suspend_lock,F_LOCK,0) == 0)
{
d->locked = true;
return true;
}
return false;
} }
// FIXME: needs a good think-through bool SHMProcess::releaseSuspendLock()
bool SHMProcess::asyncSuspend()
{ {
if(!d->attached) return (lockf(d->suspend_lock,F_ULOCK,0) == 0);
{
return false;
}
if(d->locked)
{
return true;
}
uint32_t cmd = D_SHMCMD;
if(cmd == CORE_SUSPENDED)
{
// we have to hold the lock to be really suspended
if(lockf(d->suspend_lock,F_LOCK,0) == 0)
{
d->locked = true;
return true;
}
return false;
}
else
{
// did we just resume a moment ago?
if(cmd == CORE_STEP)
{
return false;
}
else if(cmd == CORE_RUN)
{
D_SHMCMD = CORE_STEP;
}
else
{
D_SHMCMD = CORE_SUSPEND;
}
return false;
}
}
bool SHMProcess::forceresume()
{
return resume();
}
// FIXME: wait for the server to advance a step!
bool SHMProcess::resume()
{
if(!d->attached)
return false;
if(!d->locked)
return true;
// unlock the suspend lock
if(lockf(d->suspend_lock,F_ULOCK,0) == 0)
{
d->locked = false;
if(d->SetAndWait(CORE_RUN)) // we have to make sure the server responds!
{
return true;
}
throw Error::SHMLockingError("if(d->SetAndWait(CORE_RUN))");
}
throw Error::SHMLockingError("if(lockf(d->suspend_lock,F_ULOCK,0) == 0)");
return false;
} }
@ -531,6 +319,7 @@ bool SHMProcess::attach()
return suspend(); return suspend();
return true; return true;
} }
//cerr << "attach" << endl;// FIXME: throw
if(!d->GetLocks()) if(!d->GetLocks())
{ {
//cerr << "server is full or not really there!" << endl; //cerr << "server is full or not really there!" << endl;
@ -589,334 +378,34 @@ bool SHMProcess::detach()
return false; return false;
} }
void SHMProcess::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer)
{
if(!d->locked) throw Error::MemoryAccessDenied();
// normal read under 1MB
if(size <= SHM_BODY)
{
D_SHMHDR->address = src_address;
D_SHMHDR->length = size;
gcc_barrier
d->SetAndWait(CORE_READ);
memcpy (target_buffer, D_SHMDATA(void),size);
}
// a big read, we pull data over the shm in iterations
else
{
// first read equals the size of the SHM window
uint32_t to_read = SHM_BODY;
while (size)
{
// read to_read bytes from src_cursor
D_SHMHDR->address = src_address;
D_SHMHDR->length = to_read;
gcc_barrier
d->SetAndWait(CORE_READ);
memcpy (target_buffer, D_SHMDATA(void) ,to_read);
// decrease size by bytes read
size -= to_read;
// move the cursors
src_address += to_read;
target_buffer += to_read;
// check how much to write in the next iteration
to_read = min(size, (uint32_t) SHM_BODY);
}
}
}
uint8_t SHMProcess::readByte (const uint32_t offset)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
gcc_barrier
d->SetAndWait(CORE_READ_BYTE);
return D_SHMHDR->value;
}
void SHMProcess::readByte (const uint32_t offset, uint8_t &val )
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
gcc_barrier
d->SetAndWait(CORE_READ_BYTE);
val = D_SHMHDR->value;
}
uint16_t SHMProcess::readWord (const uint32_t offset)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
gcc_barrier
d->SetAndWait(CORE_READ_WORD);
return D_SHMHDR->value;
}
void SHMProcess::readWord (const uint32_t offset, uint16_t &val)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
gcc_barrier
d->SetAndWait(CORE_READ_WORD);
val = D_SHMHDR->value;
}
uint32_t SHMProcess::readDWord (const uint32_t offset)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
gcc_barrier
d->SetAndWait(CORE_READ_DWORD);
return D_SHMHDR->value;
}
void SHMProcess::readDWord (const uint32_t offset, uint32_t &val)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
gcc_barrier
d->SetAndWait(CORE_READ_DWORD);
val = D_SHMHDR->value;
}
uint64_t SHMProcess::readQuad (const uint32_t offset)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
gcc_barrier
d->SetAndWait(CORE_READ_QUAD);
return D_SHMHDR->Qvalue;
}
void SHMProcess::readQuad (const uint32_t offset, uint64_t &val)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
gcc_barrier
d->SetAndWait(CORE_READ_QUAD);
val = D_SHMHDR->Qvalue;
}
float SHMProcess::readFloat (const uint32_t offset)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
gcc_barrier
d->SetAndWait(CORE_READ_DWORD);
return reinterpret_cast<float&> (D_SHMHDR->value);
}
void SHMProcess::readFloat (const uint32_t offset, float &val)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
gcc_barrier
d->SetAndWait(CORE_READ_DWORD);
val = reinterpret_cast<float&> (D_SHMHDR->value);
}
/*
* WRITING
*/
void SHMProcess::writeQuad (const uint32_t offset, const uint64_t data)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
D_SHMHDR->Qvalue = data;
gcc_barrier
d->SetAndWait(CORE_WRITE_QUAD);
}
void SHMProcess::writeDWord (uint32_t offset, uint32_t data)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
D_SHMHDR->value = data;
gcc_barrier
d->SetAndWait(CORE_WRITE_DWORD);
}
// using these is expensive.
void SHMProcess::writeWord (uint32_t offset, uint16_t data)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
D_SHMHDR->value = data;
gcc_barrier
d->SetAndWait(CORE_WRITE_WORD);
}
void SHMProcess::writeByte (uint32_t offset, uint8_t data)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
D_SHMHDR->value = data;
gcc_barrier
d->SetAndWait(CORE_WRITE_BYTE);
}
void SHMProcess::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer)
{
if(!d->locked) throw Error::MemoryAccessDenied();
// normal write under 1MB
if(size <= SHM_BODY)
{
D_SHMHDR->address = dst_address;
D_SHMHDR->length = size;
memcpy(D_SHMDATA(void),source_buffer, size);
gcc_barrier
d->SetAndWait(CORE_WRITE);
}
// a big write, we push this over the shm in iterations
else
{
// first write equals the size of the SHM window
uint32_t to_write = SHM_BODY;
while (size)
{
// write to_write bytes to dst_cursor
D_SHMHDR->address = dst_address;
D_SHMHDR->length = to_write;
memcpy(D_SHMDATA(void),source_buffer, to_write);
gcc_barrier
d->SetAndWait(CORE_WRITE);
// decrease size by bytes written
size -= to_write;
// move the cursors
source_buffer += to_write;
dst_address += to_write;
// check how much to write in the next iteration
to_write = min(size, (uint32_t) SHM_BODY);
}
}
}
// FIXME: butt-fugly
const std::string SHMProcess::readCString (uint32_t offset)
{
if(!d->locked) throw Error::MemoryAccessDenied();
std::string temp;
char temp_c[256];
int counter = 0;
char r;
do
{
r = readByte(offset+counter);
temp_c[counter] = r;
counter++;
} while (r && counter < 255);
temp_c[counter] = 0;
temp = temp_c;
return temp;
}
const std::string SHMProcess::readSTLString(uint32_t offset)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_STL_STRING);
return(string( D_SHMDATA(char) ));
}
size_t SHMProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_STL_STRING);
size_t length = D_SHMHDR->value;
size_t fit = min(bufcapacity - 1, length);
strncpy(buffer,D_SHMDATA(char),fit);
buffer[fit] = 0;
return fit;
}
void SHMProcess::writeSTLString(const uint32_t address, const std::string writeString)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = address;
strncpy(D_SHMDATA(char),writeString.c_str(),writeString.length()+1); // length + 1 for the null terminator
full_barrier
d->SetAndWait(CORE_WRITE_STL_STRING);
}
string SHMProcess::readClassName (uint32_t vptr) string SHMProcess::readClassName (uint32_t vptr)
{ {
if(!d->locked) throw Error::MemoryAccessDenied(); if(!d->locked) throw Error::MemoryAccessDenied();
int typeinfo = readDWord(vptr - 0x4); int typeinfo = Process::readDWord(vptr - 0x4);
int typestring = readDWord(typeinfo + 0x4); int typestring = Process::readDWord(typeinfo + 0x4);
string raw = readCString(typestring); string raw = readCString(typestring);
size_t start = raw.find_first_of("abcdefghijklmnopqrstuvwxyz");// trim numbers size_t start = raw.find_first_of("abcdefghijklmnopqrstuvwxyz");// trim numbers
size_t end = raw.length(); size_t end = raw.length();
return raw.substr(start,end-start); return raw.substr(start,end-start);
} }
// get module index by name and version. bool 0 = error string SHMProcess::getPath()
bool SHMProcess::getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT)
{ {
if(!d->locked) throw Error::MemoryAccessDenied(); char cwd_name[256];
char target_name[1024];
modulelookup * payload = D_SHMDATA(modulelookup); int target_result;
payload->version = version;
strncpy(payload->name,name,255);
payload->name[255] = 0;
if(!SetAndWait(CORE_ACQUIRE_MODULE)) sprintf(cwd_name,"/proc/%d/cwd", getPID());
{ // resolve /proc/PID/exe link
return false; // FIXME: throw a fatal exception instead target_result = readlink(cwd_name, target_name, sizeof(target_name));
} target_name[target_result] = '\0';
if(D_SHMHDR->error) return(string(target_name));
{
return false;
}
//fprintf(stderr,"%s v%d : %d\n", name, version, D_SHMHDR->value);
OUTPUT = D_SHMHDR->value;
return true;
} }
char * SHMProcess::getSHMStart (void) char * SHMProcess::getSHMStart (void)
{ {
if(!d->locked) return 0; //THROW HERE! if(!d->locked) return 0; //THROW HERE!
return /*d->shm_addr_with_cl_idx*/ d->shm_addr; return d->shm_addr;
}
bool SHMProcess::Private::Aux_Core_Attach(bool & versionOK, pid_t & PID)
{
if(!locked) throw Error::MemoryAccessDenied();
SHMDATA(coreattach)->cl_affinity = OS_getAffinity();
if(!SetAndWait(CORE_ATTACH)) return false;
/*
cerr <<"CORE_VERSION" << CORE_VERSION << endl;
cerr <<"server CORE_VERSION" << SHMDATA(coreattach)->sv_version << endl;
*/
versionOK =( SHMDATA(coreattach)->sv_version == CORE_VERSION );
PID = SHMDATA(coreattach)->sv_PID;
useYield = SHMDATA(coreattach)->sv_useYield;
#ifdef DEBUG
if(useYield) cerr << "Using Yield!" << endl;
#endif
return true;
} }

@ -0,0 +1,432 @@
/*
www.sourceforge.net/projects/dfhack
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#include "Internal.h"
#include "LinuxProcess.h"
#include "dfhack/VersionInfo.h"
#include "dfhack/DFError.h"
#include <errno.h>
#include <sys/ptrace.h>
using namespace DFHack;
LinuxProcessBase::LinuxProcessBase(uint32_t pid)
: my_pid(pid)
{
my_descriptor = NULL;
attached = false;
suspended = false;
memFileHandle = 0;
}
bool LinuxProcessBase::isSuspended()
{
return suspended;
}
bool LinuxProcessBase::isAttached()
{
return attached;
}
bool LinuxProcessBase::isIdentified()
{
return identified;
}
LinuxProcessBase::~LinuxProcessBase()
{
if(attached)
{
detach();
}
// destroy our copy of the memory descriptor
if(my_descriptor)
delete my_descriptor;
}
VersionInfo * LinuxProcessBase::getDescriptor()
{
return my_descriptor;
}
int LinuxProcessBase::getPID()
{
return my_pid;
}
//FIXME: implement
bool LinuxProcessBase::getThreadIDs(vector<uint32_t> & threads )
{
return false;
}
//FIXME: cross-reference with ELF segment entries?
void LinuxProcessBase::getMemRanges( vector<t_memrange> & ranges )
{
char buffer[1024];
char permissions[5]; // r/-, w/-, x/-, p/s, 0
sprintf(buffer, "/proc/%lu/maps", my_pid);
FILE *mapFile = ::fopen(buffer, "r");
uint64_t offset, device1, device2, node;
while (fgets(buffer, 1024, mapFile))
{
t_memrange temp;
temp.name[0] = 0;
sscanf(buffer, "%llx-%llx %s %llx %2llu:%2llu %llu %s",
&temp.start,
&temp.end,
(char*)&permissions,
&offset, &device1, &device2, &node,
(char*)&temp.name);
temp.read = permissions[0] == 'r';
temp.write = permissions[1] == 'w';
temp.execute = permissions[2] == 'x';
temp.valid = true;
ranges.push_back(temp);
}
}
bool LinuxProcessBase::asyncSuspend()
{
return suspend();
}
bool LinuxProcessBase::suspend()
{
int status;
if(!attached)
return false;
if(suspended)
return true;
if (kill(my_pid, SIGSTOP) == -1)
{
// no, we got an error
perror("kill SIGSTOP error");
return false;
}
while(true)
{
// we wait on the pid
pid_t w = waitpid(my_pid, &status, 0);
if (w == -1)
{
// child died
perror("DF exited during suspend call");
return false;
}
// stopped -> let's continue
if (WIFSTOPPED(status))
{
break;
}
}
suspended = true;
return true;
}
bool LinuxProcessBase::forceresume()
{
return resume();
}
bool LinuxProcessBase::resume()
{
if(!attached)
return false;
if(!suspended)
return true;
if (ptrace(PTRACE_CONT, my_pid, NULL, NULL) == -1)
{
// no, we got an error
perror("ptrace resume error");
return false;
}
suspended = false;
return true;
}
bool LinuxProcessBase::attach()
{
int status;
if(attached)
{
if(!suspended)
return suspend();
return true;
}
// can we attach?
if (ptrace(PTRACE_ATTACH , my_pid, NULL, NULL) == -1)
{
// no, we got an error
perror("ptrace attach error");
cerr << "attach failed on pid " << my_pid << endl;
return false;
}
while(true)
{
// we wait on the pid
pid_t w = waitpid(my_pid, &status, 0);
if (w == -1)
{
// child died
perror("wait inside attach()");
return false;
}
// stopped -> let's continue
if (WIFSTOPPED(status))
{
break;
}
}
suspended = true;
int proc_pid_mem = open(memFile.c_str(),O_RDONLY);
if(proc_pid_mem == -1)
{
ptrace(PTRACE_DETACH, my_pid, NULL, NULL);
cerr << memFile << endl;
cerr << "couldn't open /proc/" << my_pid << "/mem" << endl;
perror("open(memFile.c_str(),O_RDONLY)");
return false;
}
else
{
attached = true;
memFileHandle = proc_pid_mem;
return true; // we are attached
}
}
bool LinuxProcessBase::detach()
{
if(!attached) return true;
if(!suspended) suspend();
int result = 0;
// close /proc/PID/mem
result = close(memFileHandle);
if(result == -1)
{
cerr << "couldn't close /proc/"<< my_pid <<"/mem" << endl;
perror("mem file close");
return false;
}
else
{
// detach
result = ptrace(PTRACE_DETACH, my_pid, NULL, NULL);
if(result == -1)
{
cerr << "couldn't detach from process pid" << my_pid << endl;
perror("ptrace detach");
return false;
}
else
{
attached = false;
return true;
}
}
}
void LinuxProcessBase::read (const uint32_t offset, const uint32_t size, uint8_t *target)
{
if(size == 0) return;
ssize_t result;
ssize_t total = 0;
ssize_t remaining = size;
while (total != size)
{
result = pread(memFileHandle, target + total ,remaining,offset + total);
if(result == -1)
{
cerr << "pread failed: can't read " << size << " bytes at addres " << offset << endl;
cerr << "errno: " << errno << endl;
errno = 0;
throw Error::MemoryAccessDenied();
}
else
{
total += result;
remaining -= result;
}
}
}
void LinuxProcessBase::readByte (const uint32_t offset, uint8_t &val )
{
read(offset, 1, &val);
}
void LinuxProcessBase::readWord (const uint32_t offset, uint16_t &val)
{
read(offset, 2, (uint8_t *) &val);
}
void LinuxProcessBase::readDWord (const uint32_t offset, uint32_t &val)
{
read(offset, 4, (uint8_t *) &val);
}
void LinuxProcessBase::readFloat (const uint32_t offset, float &val)
{
read(offset, 4, (uint8_t *) &val);
}
void LinuxProcessBase::readQuad (const uint32_t offset, uint64_t &val)
{
read(offset, 8, (uint8_t *) &val);
}
/*
* WRITING
*/
void LinuxProcessBase::writeQuad (uint32_t offset, const uint64_t data)
{
#ifdef HAVE_64_BIT
ptrace(PTRACE_POKEDATA,my_pid, offset, data);
#else
ptrace(PTRACE_POKEDATA,my_pid, offset, (uint32_t) data);
ptrace(PTRACE_POKEDATA,my_pid, offset+4, (uint32_t) (data >> 32));
#endif
}
void LinuxProcessBase::writeDWord (uint32_t offset, uint32_t data)
{
#ifdef HAVE_64_BIT
uint64_t orig = Process::readQuad(offset);
orig &= 0xFFFFFFFF00000000;
orig |= data;
ptrace(PTRACE_POKEDATA,my_pid, offset, orig);
#else
ptrace(PTRACE_POKEDATA,my_pid, offset, data);
#endif
}
// using these is expensive.
void LinuxProcessBase::writeWord (uint32_t offset, uint16_t data)
{
#ifdef HAVE_64_BIT
uint64_t orig = Process::readQuad(offset);
orig &= 0xFFFFFFFFFFFF0000;
orig |= data;
ptrace(PTRACE_POKEDATA,my_pid, offset, orig);
#else
uint32_t orig = Process::readDWord(offset);
orig &= 0xFFFF0000;
orig |= data;
ptrace(PTRACE_POKEDATA,my_pid, offset, orig);
#endif
}
void LinuxProcessBase::writeByte (uint32_t offset, uint8_t data)
{
#ifdef HAVE_64_BIT
uint64_t orig = Process::readQuad(offset);
orig &= 0xFFFFFFFFFFFFFF00;
orig |= data;
ptrace(PTRACE_POKEDATA,my_pid, offset, orig);
#else
uint32_t orig = Process::readDWord(offset);
orig &= 0xFFFFFF00;
orig |= data;
ptrace(PTRACE_POKEDATA,my_pid, offset, orig);
#endif
}
// blah. I hate the kernel devs for crippling /proc/PID/mem. THIS IS RIDICULOUS
void LinuxProcessBase::write (uint32_t offset, uint32_t size, uint8_t *source)
{
uint32_t indexptr = 0;
while (size > 0)
{
#ifdef HAVE_64_BIT
// quad!
if(size >= 8)
{
writeQuad(offset, *(uint64_t *) (source + indexptr));
offset +=8;
indexptr +=8;
size -=8;
}
else
#endif
// default: we push 4 bytes
if(size >= 4)
{
writeDWord(offset, *(uint32_t *) (source + indexptr));
offset +=4;
indexptr +=4;
size -=4;
}
// last is either three or 2 bytes
else if(size >= 2)
{
writeWord(offset, *(uint16_t *) (source + indexptr));
offset +=2;
indexptr +=2;
size -=2;
}
// finishing move
else if(size == 1)
{
writeByte(offset, *(uint8_t *) (source + indexptr));
return;
}
}
}
const std::string LinuxProcessBase::readCString (uint32_t offset)
{
std::string temp;
char temp_c[256];
int counter = 0;
char r;
do
{
r = Process::readByte(offset+counter);
temp_c[counter] = r;
counter++;
} while (r && counter < 255);
temp_c[counter] = 0;
temp = temp_c;
return temp;
}
string LinuxProcessBase::getPath()
{
char cwd_name[256];
char target_name[1024];
int target_result;
sprintf(cwd_name,"/proc/%d/cwd", getPID());
// resolve /proc/PID/exe link
target_result = readlink(cwd_name, target_name, sizeof(target_name));
target_name[target_result] = '\0';
return(string(target_name));
}

@ -22,7 +22,9 @@ must not be misrepresented as being the original software.
distribution. distribution.
*/ */
#include "Internal.h" #include "Internal.h"
#include "dfhack/DFProcess.h" #include "LinuxProcess.h"
#include "ProcessFactory.h"
#include "MicrosoftSTL.h"
#include "dfhack/VersionInfo.h" #include "dfhack/VersionInfo.h"
#include "dfhack/DFError.h" #include "dfhack/DFError.h"
#include <errno.h> #include <errno.h>
@ -30,37 +32,30 @@ distribution.
#include <stdio.h> #include <stdio.h>
using namespace DFHack; using namespace DFHack;
class WineProcess::Private namespace {
{ class WineProcess : public LinuxProcessBase
public: {
Private(Process * self_) private:
{ MicrosoftSTL stl;
my_descriptor = NULL; public:
my_handle = NULL; WineProcess(uint32_t pid, std::vector <VersionInfo *> & known_versions);
my_pid = 0;
attached = false; const std::string readSTLString (uint32_t offset);
suspended = false; size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity);
memFileHandle = 0; void writeSTLString(const uint32_t address, const std::string writeString){};
self = self_; // get class name of an object with rtti/type info
std::string readClassName(uint32_t vptr);
private:
bool validate(char * exe_file,uint32_t pid, char * memFile, vector <VersionInfo *> & known_versions);
}; };
~Private(){}; }
VersionInfo * my_descriptor;
Process * self; Process* DFHack::createWineProcess(uint32_t pid, vector <VersionInfo *> & known_versions)
pid_t my_handle; {
uint32_t my_pid; return new WineProcess(pid, known_versions);
string memFile; }
int memFileHandle;
bool attached;
bool suspended;
bool identified;
uint32_t STLSTR_buf_off;
uint32_t STLSTR_size_off;
uint32_t STLSTR_cap_off;
bool validate(char * exe_file, uint32_t pid, char * mem_file, vector <VersionInfo *> & known_versions);
};
WineProcess::WineProcess(uint32_t pid, vector <VersionInfo *> & known_versions) WineProcess::WineProcess(uint32_t pid, vector <VersionInfo *> & known_versions) : LinuxProcessBase(pid)
: d(new Private(this))
{ {
char dir_name [256]; char dir_name [256];
char exe_link_name [256]; char exe_link_name [256];
@ -70,8 +65,8 @@ WineProcess::WineProcess(uint32_t pid, vector <VersionInfo *> & known_versions)
char target_name[1024]; char target_name[1024];
int target_result; int target_result;
d->identified = false; identified = false;
d->my_descriptor = 0; my_descriptor = 0;
sprintf(dir_name,"/proc/%d/", pid); sprintf(dir_name,"/proc/%d/", pid);
sprintf(exe_link_name,"/proc/%d/exe", pid); sprintf(exe_link_name,"/proc/%d/exe", pid);
@ -107,27 +102,14 @@ WineProcess::WineProcess(uint32_t pid, vector <VersionInfo *> & known_versions)
sprintf(exe_link,"%s/%s",target_name,cmdline.c_str()); sprintf(exe_link,"%s/%s",target_name,cmdline.c_str());
// create wine process, add it to the vector // create wine process, add it to the vector
d->identified = d->validate(exe_link,pid,mem_name,known_versions); identified = validate(exe_link,pid,mem_name,known_versions);
return; return;
} }
} }
} }
bool WineProcess::isSuspended()
{
return d->suspended;
}
bool WineProcess::isAttached()
{
return d->attached;
}
bool WineProcess::isIdentified() bool WineProcess::validate(char * exe_file,uint32_t pid, char * memFile, vector <VersionInfo *> & known_versions)
{
return d->identified;
}
bool WineProcess::Private::validate(char* exe_file, uint32_t pid, char* mem_file, std::vector< VersionInfo* >& known_versions)
{ {
md5wrapper md5; md5wrapper md5;
// get hash of the running DF process // get hash of the running DF process
@ -137,490 +119,44 @@ bool WineProcess::Private::validate(char* exe_file, uint32_t pid, char* mem_file
// iterate over the list of memory locations // iterate over the list of memory locations
for ( it=known_versions.begin() ; it < known_versions.end(); it++ ) for ( it=known_versions.begin() ; it < known_versions.end(); it++ )
{ {
string thishash;
try try
{ {
thishash = (*it)->getMD5(); if (hash == (*it)->getMD5()) // are the md5 hashes the same?
}
catch (Error::MissingMemoryDefinition& e)
{
continue;
}
// are the md5 hashes the same?
if(VersionInfo::OS_WINDOWS == (*it)->getOS() && hash == thishash)
{
// keep track of created memory_info object so we can destroy it later
VersionInfo *m = new VersionInfo(**it);
my_descriptor = m;
m->setParentProcess(dynamic_cast<Process *>( self ));
my_handle = my_pid = pid;
// tell WineProcess about the /proc/PID/mem file
memFile = mem_file;
identified = true;
OffsetGroup * strGrp = m->getGroup("string")->getGroup("MSVC");
STLSTR_buf_off = strGrp->getOffset("buffer");
STLSTR_size_off = strGrp->getOffset("size");
STLSTR_cap_off = strGrp->getOffset("capacity");
return true;
}
}
return false;
}
WineProcess::~WineProcess()
{
if(d->attached)
{
detach();
}
// destroy our copy of the memory descriptor
if(d->my_descriptor)
delete d->my_descriptor;
delete d;
}
VersionInfo * WineProcess::getDescriptor()
{
return d->my_descriptor;
}
int WineProcess::getPID()
{
return d->my_pid;
}
//FIXME: implement
bool WineProcess::getThreadIDs(vector<uint32_t> & threads )
{
return false;
}
//FIXME: cross-reference with ELF segment entries?
void WineProcess::getMemRanges( vector<t_memrange> & ranges )
{
char buffer[1024];
char permissions[5]; // r/-, w/-, x/-, p/s, 0
sprintf(buffer, "/proc/%lu/maps", d->my_pid);
FILE *mapFile = ::fopen(buffer, "r");
uint64_t offset, device1, device2, node;
while (fgets(buffer, 1024, mapFile))
{
t_memrange temp;
temp.name[0] = 0;
sscanf(buffer, "%llx-%llx %s %llx %2llu:%2llu %llu %s",
&temp.start,
&temp.end,
(char*)&permissions,
&offset, &device1, &device2, &node,
(char*)&temp.name);
temp.read = permissions[0] == 'r';
temp.write = permissions[1] == 'w';
temp.execute = permissions[2] == 'x';
ranges.push_back(temp);
}
}
bool WineProcess::asyncSuspend()
{
return suspend();
}
bool WineProcess::suspend()
{
int status;
if(!d->attached)
return false;
if(d->suspended)
return true;
if (kill(d->my_handle, SIGSTOP) == -1)
{
// no, we got an error
perror("kill SIGSTOP error");
return false;
}
while(true)
{
// we wait on the pid
pid_t w = waitpid(d->my_handle, &status, 0);
if (w == -1)
{
// child died
perror("DF exited during suspend call");
return false;
}
// stopped -> let's continue
if (WIFSTOPPED(status))
{
break;
}
}
d->suspended = true;
return true;
}
bool WineProcess::forceresume()
{
return resume();
}
bool WineProcess::resume()
{
if(!d->attached)
return false;
if(!d->suspended)
return true;
if (ptrace(PTRACE_CONT, d->my_handle, NULL, NULL) == -1)
{
// no, we got an error
perror("ptrace resume error");
return false;
}
d->suspended = false;
return true;
}
bool WineProcess::attach()
{
int status;
if(d->attached)
{
if(!d->suspended)
return suspend();
return true;
}
// can we attach?
if (ptrace(PTRACE_ATTACH , d->my_handle, NULL, NULL) == -1)
{
// no, we got an error
perror("ptrace attach error");
cerr << "attach failed on pid " << d->my_handle << endl;
return false;
}
while(true)
{
// we wait on the pid
pid_t w = waitpid(d->my_handle, &status, 0);
if (w == -1)
{
// child died
perror("wait inside attach()");
return false;
}
// stopped -> let's continue
if (WIFSTOPPED(status))
{
break;
}
}
d->suspended = true;
int proc_pid_mem = open(d->memFile.c_str(),O_RDONLY);
if(proc_pid_mem == -1)
{
ptrace(PTRACE_DETACH, d->my_handle, NULL, NULL);
cerr << d->memFile << endl;
cerr << "couldn't open /proc/" << d->my_handle << "/mem" << endl;
perror("open(memFile.c_str(),O_RDONLY)");
return false;
}
else
{
d->attached = true;
d->memFileHandle = proc_pid_mem;
return true; // we are attached
}
}
bool WineProcess::detach()
{
if(!d->attached) return true;
if(!d->suspended) suspend();
int result = 0;
// close /proc/PID/mem
result = close(d->memFileHandle);
if(result == -1)
{
cerr << "couldn't close /proc/"<< d->my_handle <<"/mem" << endl;
perror("mem file close");
return false;
}
else
{
// detach
result = ptrace(PTRACE_DETACH, d->my_handle, NULL, NULL);
if(result == -1)
{
cerr << "couldn't detach from process pid" << d->my_handle << endl;
perror("ptrace detach");
return false;
}
else
{
d->attached = false;
return true;
}
}
}
// danger: uses recursion!
void WineProcess::read (const uint32_t offset, const uint32_t size, uint8_t *target)
{
if(size == 0) return;
ssize_t result;
ssize_t total = 0;
ssize_t remaining = size;
while (total != size)
{
result = pread(d->memFileHandle, target + total ,remaining,offset + total);
if(result == -1)
{
cerr << "pread failed: can't read " << size << " bytes at addres " << offset << endl;
cerr << "errno: " << errno << endl;
errno = 0;
throw Error::MemoryAccessDenied();
}
else
{
total += result;
remaining -= result;
}
}
}
uint8_t WineProcess::readByte (const uint32_t offset)
{
uint8_t val;
read(offset, 1, &val);
return val;
}
void WineProcess::readByte (const uint32_t offset, uint8_t &val )
{
read(offset, 1, &val);
}
uint16_t WineProcess::readWord (const uint32_t offset)
{
uint16_t val;
read(offset, 2, (uint8_t *) &val);
return val;
}
void WineProcess::readWord (const uint32_t offset, uint16_t &val)
{
read(offset, 2, (uint8_t *) &val);
}
uint32_t WineProcess::readDWord (const uint32_t offset)
{
uint32_t val;
read(offset, 4, (uint8_t *) &val);
return val;
}
void WineProcess::readDWord (const uint32_t offset, uint32_t &val)
{
read(offset, 4, (uint8_t *) &val);
}
float WineProcess::readFloat (const uint32_t offset)
{
float val;
read(offset, 4, (uint8_t *) &val);
return val;
}
void WineProcess::readFloat (const uint32_t offset, float &val)
{
read(offset, 4, (uint8_t *) &val);
}
void WineProcess::readQuad (const uint32_t offset, uint64_t &val)
{
read(offset, 8, (uint8_t *) &val);
}
uint64_t WineProcess::readQuad (const uint32_t offset)
{
uint64_t val;
read(offset, 8, (uint8_t *) &val);
return val;
}
/*
* WRITING
*/
void WineProcess::writeQuad (uint32_t offset, const uint64_t data)
{
#ifdef HAVE_64_BIT
ptrace(PTRACE_POKEDATA,d->my_handle, offset, data);
#else
ptrace(PTRACE_POKEDATA,d->my_handle, offset, (uint32_t) data);
ptrace(PTRACE_POKEDATA,d->my_handle, offset+4, (uint32_t) (data >> 32));
#endif
}
void WineProcess::writeDWord (uint32_t offset, uint32_t data)
{
#ifdef HAVE_64_BIT
uint64_t orig = readQuad(offset);
orig &= 0xFFFFFFFF00000000;
orig |= data;
ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig);
#else
ptrace(PTRACE_POKEDATA,d->my_handle, offset, data);
#endif
}
// using these is expensive.
void WineProcess::writeWord (uint32_t offset, uint16_t data)
{
#ifdef HAVE_64_BIT
uint64_t orig = readQuad(offset);
orig &= 0xFFFFFFFFFFFF0000;
orig |= data;
ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig);
#else
uint32_t orig = readDWord(offset);
orig &= 0xFFFF0000;
orig |= data;
ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig);
#endif
}
void WineProcess::writeByte (uint32_t offset, uint8_t data)
{
#ifdef HAVE_64_BIT
uint64_t orig = readQuad(offset);
orig &= 0xFFFFFFFFFFFFFF00;
orig |= data;
ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig);
#else
uint32_t orig = readDWord(offset);
orig &= 0xFFFFFF00;
orig |= data;
ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig);
#endif
}
// blah. I hate the kernel devs for crippling /proc/PID/mem. THIS IS RIDICULOUS
void WineProcess::write (uint32_t offset, uint32_t size, uint8_t *source)
{
uint32_t indexptr = 0;
while (size > 0)
{
#ifdef HAVE_64_BIT
// quad!
if(size >= 8)
{ {
writeQuad(offset, *(uint64_t *) (source + indexptr)); if (OS_WINDOWS == (*it)->getOS())
offset +=8; {
indexptr +=8; // keep track of created memory_info object so we can destroy it later
size -=8; my_descriptor = new VersionInfo(**it);
my_descriptor->setParentProcess(this);
// tell Process about the /proc/PID/mem file
memFile = memFile;
identified = true;
stl.init(this);
return true;
}
} }
else
#endif
// default: we push 4 bytes
if(size >= 4)
{
writeDWord(offset, *(uint32_t *) (source + indexptr));
offset +=4;
indexptr +=4;
size -=4;
} }
// last is either three or 2 bytes catch (Error::AllMemdef&)
else if(size >= 2)
{ {
writeWord(offset, *(uint16_t *) (source + indexptr)); continue;
offset +=2;
indexptr +=2;
size -=2;
}
// finishing move
else if(size == 1)
{
writeByte(offset, *(uint8_t *) (source + indexptr));
return;
} }
} }
return false;
} }
const std::string WineProcess::readCString (uint32_t offset)
{
std::string temp;
char temp_c[256];
int counter = 0;
char r;
do
{
r = readByte(offset+counter);
temp_c[counter] = r;
counter++;
} while (r && counter < 255);
temp_c[counter] = 0;
temp = temp_c;
return temp;
}
size_t WineProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) size_t WineProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
{ {
uint32_t start_offset = offset + d->STLSTR_buf_off; return stl.readSTLString(offset, buffer, bufcapacity);
size_t length = readDWord(offset + d->STLSTR_size_off);
size_t capacity = readDWord(offset + d->STLSTR_cap_off);
size_t read_real = min(length, bufcapacity-1);// keep space for null termination
// read data from inside the string structure
if(capacity < 16)
{
read(start_offset, read_real , (uint8_t *)buffer);
}
else // read data from what the offset + 4 dword points to
{
start_offset = readDWord(start_offset);// dereference the start offset
read(start_offset, read_real, (uint8_t *)buffer);
}
buffer[read_real] = 0;
return read_real;
} }
const string WineProcess::readSTLString (uint32_t offset) const string WineProcess::readSTLString (uint32_t offset)
{ {
uint32_t start_offset = offset + d->STLSTR_buf_off; return stl.readSTLString(offset);
size_t length = readDWord(offset + d->STLSTR_size_off);
size_t capacity = readDWord(offset + d->STLSTR_cap_off);
char * temp = new char[capacity+1];
// read data from inside the string structure
if(capacity < 16)
{
read(start_offset, capacity, (uint8_t *)temp);
}
else // read data from what the offset + 4 dword points to
{
start_offset = readDWord(start_offset);// dereference the start offset
read(start_offset, capacity, (uint8_t *)temp);
}
temp[length] = 0;
string ret = temp;
delete temp;
return ret;
} }
string WineProcess::readClassName (uint32_t vptr) string WineProcess::readClassName (uint32_t vptr)
{ {
int rtti = readDWord(vptr - 0x4); stl.readClassName(vptr);
int typeinfo = readDWord(rtti + 0xC);
string raw = readCString(typeinfo + 0xC); // skips the .?AV
raw.resize(raw.length() - 2);// trim @@ from end
return raw;
} }

@ -22,42 +22,36 @@ must not be misrepresented as being the original software.
distribution. distribution.
*/ */
#include "Internal.h" #include "Internal.h"
#include "dfhack/DFProcess.h" #include "LinuxProcess.h"
#include "ProcessFactory.h"
#include "dfhack/VersionInfo.h" #include "dfhack/VersionInfo.h"
#include "dfhack/DFError.h" #include "dfhack/DFError.h"
#include <errno.h> #include <errno.h>
#include <sys/ptrace.h> #include <sys/ptrace.h>
using namespace DFHack; using namespace DFHack;
class NormalProcess::Private namespace {
{ class NormalProcess : public LinuxProcessBase
public:
Private(Process * self_)
{ {
my_descriptor = NULL; public:
my_handle = NULL; NormalProcess(uint32_t pid, std::vector <VersionInfo *> & known_versions);
my_pid = 0;
attached = false; const std::string readSTLString (uint32_t offset);
suspended = false; size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity);
memFileHandle = 0; void writeSTLString(const uint32_t address, const std::string writeString){};
self = self_; // get class name of an object with rtti/type info
std::string readClassName(uint32_t vptr);
private:
bool validate(char * exe_file,uint32_t pid, char * memFile, vector <VersionInfo *> & known_versions);
}; };
~Private(){}; }
Window* my_window;
VersionInfo * my_descriptor; Process* DFHack::createNormalProcess(uint32_t pid, vector <VersionInfo *> & known_versions)
pid_t my_handle; {
uint32_t my_pid; return new NormalProcess(pid, known_versions);
string memFile; }
int memFileHandle;
bool attached;
bool suspended;
bool identified;
Process * self;
bool validate(char * exe_file, uint32_t pid, char * mem_file, vector <VersionInfo *> & known_versions);
};
NormalProcess::NormalProcess(uint32_t pid, vector< VersionInfo* >& known_versions) NormalProcess::NormalProcess(uint32_t pid, vector <VersionInfo *> & known_versions) : LinuxProcessBase(pid)
: d(new Private(this))
{ {
char dir_name [256]; char dir_name [256];
char exe_link_name [256]; char exe_link_name [256];
@ -67,8 +61,8 @@ NormalProcess::NormalProcess(uint32_t pid, vector< VersionInfo* >& known_version
char target_name[1024]; char target_name[1024];
int target_result; int target_result;
d->identified = false; identified = false;
d->my_descriptor = 0; my_descriptor = 0;
sprintf(dir_name,"/proc/%d/", pid); sprintf(dir_name,"/proc/%d/", pid);
sprintf(exe_link_name,"/proc/%d/exe", pid); sprintf(exe_link_name,"/proc/%d/exe", pid);
@ -89,26 +83,12 @@ NormalProcess::NormalProcess(uint32_t pid, vector< VersionInfo* >& known_version
if (strstr(target_name, "dwarfort.exe") != 0 || strstr(target_name,"Dwarf_Fortress") != 0) if (strstr(target_name, "dwarfort.exe") != 0 || strstr(target_name,"Dwarf_Fortress") != 0)
{ {
// create linux process, add it to the vector // create linux process, add it to the vector
d->identified = d->validate(target_name,pid,mem_name,known_versions ); identified = validate(target_name,pid,mem_name,known_versions);
return; return;
} }
} }
bool NormalProcess::isSuspended() bool NormalProcess::validate(char * exe_file,uint32_t pid, char * memFile, vector <VersionInfo *> & known_versions)
{
return d->suspended;
}
bool NormalProcess::isAttached()
{
return d->attached;
}
bool NormalProcess::isIdentified()
{
return d->identified;
}
bool NormalProcess::Private::validate(char * exe_file,uint32_t pid, char * memFile, vector <VersionInfo *> & known_versions)
{ {
md5wrapper md5; md5wrapper md5;
// get hash of the running DF process // get hash of the running DF process
@ -120,29 +100,21 @@ bool NormalProcess::Private::validate(char * exe_file,uint32_t pid, char * memFi
{ {
try try
{ {
//cout << hash << " ?= " << (*it)->getMD5() << endl; if (hash == (*it)->getMD5()) // are the md5 hashes the same?
if(hash == (*it)->getMD5()) // are the md5 hashes the same?
{ {
VersionInfo * m = *it; if (OS_LINUX == (*it)->getOS())
if (VersionInfo::OS_LINUX == m->getOS())
{ {
VersionInfo *m2 = new VersionInfo(*m); // keep track of created memory_info object so we can destroy it later
my_descriptor = m2; my_descriptor = new VersionInfo(**it);
m2->setParentProcess(dynamic_cast<Process *>( self )); my_descriptor->setParentProcess(this);
my_handle = my_pid = pid; // tell Process about the /proc/PID/mem file
memFile = memFile;
identified = true;
return true;
} }
else
{
// some error happened, continue with next process
continue;
}
// tell NormalProcess about the /proc/PID/mem file
this->memFile = memFile;
identified = true;
return true;
} }
} }
catch (Error::MissingMemoryDefinition&) catch (Error::AllMemdef&)
{ {
continue; continue;
} }
@ -150,400 +122,6 @@ bool NormalProcess::Private::validate(char * exe_file,uint32_t pid, char * memFi
return false; return false;
} }
NormalProcess::~NormalProcess()
{
if(d->attached)
{
detach();
}
// destroy our copy of the memory descriptor
if(d->my_descriptor)
delete d->my_descriptor;
delete d;
}
VersionInfo * NormalProcess::getDescriptor()
{
return d->my_descriptor;
}
int NormalProcess::getPID()
{
return d->my_pid;
}
//FIXME: implement
bool NormalProcess::getThreadIDs(vector<uint32_t> & threads )
{
return false;
}
//FIXME: cross-reference with ELF segment entries?
void NormalProcess::getMemRanges( vector<t_memrange> & ranges )
{
char buffer[1024];
char permissions[5]; // r/-, w/-, x/-, p/s, 0
sprintf(buffer, "/proc/%lu/maps", d->my_pid);
FILE *mapFile = ::fopen(buffer, "r");
uint64_t offset, device1, device2, node;
while (fgets(buffer, 1024, mapFile))
{
t_memrange temp;
temp.name[0] = 0;
sscanf(buffer, "%llx-%llx %s %llx %2llu:%2llu %llu %s",
&temp.start,
&temp.end,
(char*)&permissions,
&offset, &device1, &device2, &node,
(char*)&temp.name);
temp.read = permissions[0] == 'r';
temp.write = permissions[1] == 'w';
temp.execute = permissions[2] == 'x';
ranges.push_back(temp);
}
}
bool NormalProcess::asyncSuspend()
{
return suspend();
}
bool NormalProcess::suspend()
{
int status;
if(!d->attached)
return false;
if(d->suspended)
return true;
if (kill(d->my_handle, SIGSTOP) == -1)
{
// no, we got an error
perror("kill SIGSTOP error");
return false;
}
while(true)
{
// we wait on the pid
pid_t w = waitpid(d->my_handle, &status, 0);
if (w == -1)
{
// child died
perror("DF exited during suspend call");
return false;
}
// stopped -> let's continue
if (WIFSTOPPED(status))
{
break;
}
}
d->suspended = true;
return true;
}
bool NormalProcess::forceresume()
{
return resume();
}
bool NormalProcess::resume()
{
if(!d->attached)
return false;
if(!d->suspended)
return true;
if (ptrace(PTRACE_CONT, d->my_handle, NULL, NULL) == -1)
{
// no, we got an error
perror("ptrace resume error");
return false;
}
d->suspended = false;
return true;
}
bool NormalProcess::attach()
{
int status;
if(d->attached)
{
if(!d->suspended)
return suspend();
return true;
}
// can we attach?
if (ptrace(PTRACE_ATTACH , d->my_handle, NULL, NULL) == -1)
{
// no, we got an error
perror("ptrace attach error");
cerr << "attach failed on pid " << d->my_handle << endl;
return false;
}
while(true)
{
// we wait on the pid
pid_t w = waitpid(d->my_handle, &status, 0);
if (w == -1)
{
// child died
perror("wait inside attach()");
return false;
}
// stopped -> let's continue
if (WIFSTOPPED(status))
{
break;
}
}
d->suspended = true;
int proc_pid_mem = open(d->memFile.c_str(),O_RDONLY);
if(proc_pid_mem == -1)
{
ptrace(PTRACE_DETACH, d->my_handle, NULL, NULL);
cerr << "couldn't open /proc/" << d->my_handle << "/mem" << endl;
perror("open(memFile.c_str(),O_RDONLY)");
return false;
}
else
{
d->attached = true;
d->memFileHandle = proc_pid_mem;
return true; // we are attached
}
}
bool NormalProcess::detach()
{
if(!d->attached) return true;
if(!d->suspended) suspend();
int result = 0;
// close /proc/PID/mem
result = close(d->memFileHandle);
if(result == -1)
{
cerr << "couldn't close /proc/"<< d->my_handle <<"/mem" << endl;
perror("mem file close");
return false;
}
else
{
// detach
result = ptrace(PTRACE_DETACH, d->my_handle, NULL, NULL);
if(result == -1)
{
cerr << "couldn't detach from process pid" << d->my_handle << endl;
perror("ptrace detach");
return false;
}
else
{
d->attached = false;
return true;
}
}
}
// danger: uses recursion!
void NormalProcess::read (const uint32_t offset, const uint32_t size, uint8_t *target)
{
if(size == 0) return;
ssize_t result;
result = pread(d->memFileHandle, target,size,offset);
if(result != size)
{
if(result == -1)
{
cerr << "pread failed: can't read 0x" << hex << size << " bytes at address 0x" << offset << endl;
cerr << "errno: " << errno << endl;
errno = 0;
throw Error::MemoryAccessDenied();
}
else
{
this->read(offset + result, size - result, target + result);
}
}
}
uint8_t NormalProcess::readByte (const uint32_t offset)
{
uint8_t val;
read(offset, 1, &val);
return val;
}
void NormalProcess::readByte (const uint32_t offset, uint8_t &val )
{
read(offset, 1, &val);
}
uint16_t NormalProcess::readWord (const uint32_t offset)
{
uint16_t val;
read(offset, 2, (uint8_t *) &val);
return val;
}
void NormalProcess::readWord (const uint32_t offset, uint16_t &val)
{
read(offset, 2, (uint8_t *) &val);
}
uint32_t NormalProcess::readDWord (const uint32_t offset)
{
uint32_t val;
read(offset, 4, (uint8_t *) &val);
return val;
}
void NormalProcess::readDWord (const uint32_t offset, uint32_t &val)
{
read(offset, 4, (uint8_t *) &val);
}
float NormalProcess::readFloat (const uint32_t offset)
{
float val;
read(offset, 4, (uint8_t *) &val);
return val;
}
void NormalProcess::readFloat (const uint32_t offset, float &val)
{
read(offset, 4, (uint8_t *) &val);
}
uint64_t NormalProcess::readQuad (const uint32_t offset)
{
uint64_t val;
read(offset, 8, (uint8_t *) &val);
return val;
}
void NormalProcess::readQuad (const uint32_t offset, uint64_t &val)
{
read(offset, 8, (uint8_t *) &val);
}
/*
* WRITING
*/
void NormalProcess::writeQuad (uint32_t offset, const uint64_t data)
{
#ifdef HAVE_64_BIT
ptrace(PTRACE_POKEDATA,d->my_handle, offset, data);
#else
ptrace(PTRACE_POKEDATA,d->my_handle, offset, (uint32_t) data);
ptrace(PTRACE_POKEDATA,d->my_handle, offset+4, (uint32_t) (data >> 32));
#endif
}
void NormalProcess::writeDWord (uint32_t offset, uint32_t data)
{
#ifdef HAVE_64_BIT
uint64_t orig = readQuad(offset);
orig &= 0xFFFFFFFF00000000;
orig |= data;
ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig);
#else
ptrace(PTRACE_POKEDATA,d->my_handle, offset, data);
#endif
}
// using these is expensive.
void NormalProcess::writeWord (uint32_t offset, uint16_t data)
{
#ifdef HAVE_64_BIT
uint64_t orig = readQuad(offset);
orig &= 0xFFFFFFFFFFFF0000;
orig |= data;
ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig);
#else
uint32_t orig = readDWord(offset);
orig &= 0xFFFF0000;
orig |= data;
ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig);
#endif
}
void NormalProcess::writeByte (uint32_t offset, uint8_t data)
{
#ifdef HAVE_64_BIT
uint64_t orig = readQuad(offset);
orig &= 0xFFFFFFFFFFFFFF00;
orig |= data;
ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig);
#else
uint32_t orig = readDWord(offset);
orig &= 0xFFFFFF00;
orig |= data;
ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig);
#endif
}
// blah. I hate the kernel devs for crippling /proc/PID/mem. THIS IS RIDICULOUS
void NormalProcess::write (uint32_t offset, uint32_t size, uint8_t *source)
{
uint32_t indexptr = 0;
while (size > 0)
{
#ifdef HAVE_64_BIT
// quad!
if(size >= 8)
{
writeQuad(offset, *(uint64_t *) (source + indexptr));
offset +=8;
indexptr +=8;
size -=8;
}
else
#endif
// default: we push 4 bytes
if(size >= 4)
{
writeDWord(offset, *(uint32_t *) (source + indexptr));
offset +=4;
indexptr +=4;
size -=4;
}
// last is either three or 2 bytes
else if(size >= 2)
{
writeWord(offset, *(uint16_t *) (source + indexptr));
offset +=2;
indexptr +=2;
size -=2;
}
// finishing move
else if(size == 1)
{
writeByte(offset, *(uint8_t *) (source + indexptr));
return;
}
}
}
const std::string NormalProcess::readCString (uint32_t offset)
{
std::string temp;
char temp_c[256];
int counter = 0;
char r;
do
{
r = readByte(offset+counter);
temp_c[counter] = r;
counter++;
} while (r && counter < 255);
temp_c[counter] = 0;
temp = temp_c;
return temp;
}
struct _Rep_base struct _Rep_base
{ {
uint32_t _M_length; uint32_t _M_length;
@ -554,7 +132,7 @@ struct _Rep_base
size_t NormalProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) size_t NormalProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
{ {
_Rep_base header; _Rep_base header;
offset = readDWord(offset); offset = Process::readDWord(offset);
read(offset - sizeof(_Rep_base),sizeof(_Rep_base),(uint8_t *)&header); read(offset - sizeof(_Rep_base),sizeof(_Rep_base),(uint8_t *)&header);
size_t read_real = min((size_t)header._M_length, bufcapacity-1);// keep space for null termination size_t read_real = min((size_t)header._M_length, bufcapacity-1);// keep space for null termination
read(offset,read_real,(uint8_t * )buffer); read(offset,read_real,(uint8_t * )buffer);
@ -566,7 +144,7 @@ const string NormalProcess::readSTLString (uint32_t offset)
{ {
_Rep_base header; _Rep_base header;
offset = readDWord(offset); offset = Process::readDWord(offset);
read(offset - sizeof(_Rep_base),sizeof(_Rep_base),(uint8_t *)&header); read(offset - sizeof(_Rep_base),sizeof(_Rep_base),(uint8_t *)&header);
// FIXME: use char* everywhere, avoid string // FIXME: use char* everywhere, avoid string
@ -579,8 +157,8 @@ const string NormalProcess::readSTLString (uint32_t offset)
string NormalProcess::readClassName (uint32_t vptr) string NormalProcess::readClassName (uint32_t vptr)
{ {
int typeinfo = readDWord(vptr - 0x4); int typeinfo = Process::readDWord(vptr - 0x4);
int typestring = readDWord(typeinfo + 0x4); int typestring = Process::readDWord(typeinfo + 0x4);
string raw = readCString(typestring); string raw = readCString(typestring);
size_t start = raw.find_first_of("abcdefghijklmnopqrstuvwxyz");// trim numbers size_t start = raw.find_first_of("abcdefghijklmnopqrstuvwxyz");// trim numbers
size_t end = raw.length(); size_t end = raw.length();

@ -22,68 +22,25 @@ must not be misrepresented as being the original software.
distribution. distribution.
*/ */
#include "Internal.h" #include "Internal.h"
#include "dfhack/DFProcess.h" #include "SHMProcess.h"
#include "dfhack/VersionInfo.h" #include "dfhack/VersionInfo.h"
#include "dfhack/DFError.h" #include "dfhack/DFError.h"
#include "shms.h" #include "shms.h"
#include "mod-core.h" #include "mod-core.h"
using namespace DFHack; using namespace DFHack;
// a full memory barrier! better be safe than sorry. SHMProcess::Private::Private(SHMProcess * self_)
class SHMProcess::Private
{ {
public: memdescriptor = NULL;
Private() process_ID = 0;
{ attached = false;
memdescriptor = NULL; locked = false;
process_ID = 0; identified = false;
shm_addr = 0; useYield = 0;
attached = false; DFSVMutex = 0;
locked = false; DFCLMutex = 0;
identified = false; DFCLSuspendMutex = 0;
useYield = 0; self = self_;
DFSVMutex = 0;
DFCLMutex = 0;
DFCLSuspendMutex = 0;
attachmentIdx = -1;
};
~Private(){};
VersionInfo * memdescriptor;
SHMProcess * self;
uint32_t process_ID;
char *shm_addr;
HANDLE DFSVMutex;
HANDLE DFCLMutex;
HANDLE DFCLSuspendMutex;
int attachmentIdx;
bool attached;
bool locked;
bool identified;
bool useYield;
bool validate(std::vector< VersionInfo* >& known_versions);
bool Aux_Core_Attach(bool & versionOK, uint32_t & PID);
bool SetAndWait (uint32_t state);
bool GetLocks();
bool AreLocksOk();
void FreeLocks();
};
// some helpful macros to keep the code bloat in check
#define SHMCMD ( (uint32_t *) shm_addr)[attachmentIdx]
#define D_SHMCMD ( (uint32_t *) (d->shm_addr))[d->attachmentIdx]
#define SHMHDR ((shm_core_hdr *)shm_addr)
#define D_SHMHDR ((shm_core_hdr *)(d->shm_addr))
#define SHMDATA(type) ((type *)(shm_addr + SHM_HEADER))
#define D_SHMDATA(type) ((type *)(d->shm_addr + SHM_HEADER))
bool SHMProcess::SetAndWait (uint32_t state)
{
return d->SetAndWait(state);
} }
bool SHMProcess::Private::SetAndWait (uint32_t state) bool SHMProcess::Private::SetAndWait (uint32_t state)
@ -116,6 +73,7 @@ bool SHMProcess::Private::SetAndWait (uint32_t state)
} }
cnt++; cnt++;
} }
// server returned a generic error
if(SHMCMD == CORE_ERROR) if(SHMCMD == CORE_ERROR)
{ {
return false; return false;
@ -123,6 +81,11 @@ bool SHMProcess::Private::SetAndWait (uint32_t state)
return true; return true;
} }
bool SHMProcess::SetAndWait (uint32_t state)
{
return d->SetAndWait(state);
}
uint32_t OS_getAffinity() uint32_t OS_getAffinity()
{ {
HANDLE hProcess = GetCurrentProcess(); HANDLE hProcess = GetCurrentProcess();
@ -253,71 +216,10 @@ bool SHMProcess::Private::AreLocksOk()
return false; return false;
} }
/*
char svmutexname [256];
char clmutexname [256];
sprintf(clmutexname,"DFCLMutex-%d",PID);
// get server and client mutex
d->DFSVMutex = OpenMutex(SYNCHRONIZE,false, svmutexname);
if(d->DFSVMutex == 0)
{
return;
}
d->DFCLMutex = OpenMutex(SYNCHRONIZE,false, clmutexname);
if(d->DFCLMutex == 0)
{
return;
}
*/
SHMProcess::SHMProcess(uint32_t PID, vector <VersionInfo *> & known_versions)
: d(new Private())
{
d->process_ID = PID;
d->self = this;
// attach the SHM
if(!attach())
{
return;
}
// Test bridge version, get PID, sync Yield
bool bridgeOK;
if(!d->Aux_Core_Attach(bridgeOK,d->process_ID))
{
detach();
throw Error::SHMAttachFailure();
}
else if(!bridgeOK)
{
detach();
throw Error::SHMVersionMismatch();
}
d->validate(known_versions);
// at this point, DF is attached and suspended, make it run
detach();
}
bool SHMProcess::isSuspended()
{
return d->locked;
}
bool SHMProcess::isAttached()
{
return d->attached;
}
bool SHMProcess::isIdentified()
{
return d->identified;
}
bool SHMProcess::Private::validate(vector <VersionInfo *> & known_versions) bool SHMProcess::Private::validate(vector <VersionInfo *> & known_versions)
{ {
// try to identify the DF version // try to identify the DF version
IMAGE_NT_HEADERS32 pe_header; IMAGE_NT_HEADERS pe_header;
IMAGE_SECTION_HEADER sections[16]; IMAGE_SECTION_HEADER sections[16];
HMODULE hmod = NULL; HMODULE hmod = NULL;
DWORD junk; DWORD junk;
@ -340,7 +242,7 @@ bool SHMProcess::Private::validate(vector <VersionInfo *> & known_versions)
uint32_t base = (uint32_t)hmod; uint32_t base = (uint32_t)hmod;
// read from this process // read from this process
uint32_t pe_offset = self->readDWord(base+0x3C); uint32_t pe_offset = self->Process::readDWord(base+0x3C);
self->read(base + pe_offset , sizeof(pe_header), (uint8_t *)&pe_header); self->read(base + pe_offset , sizeof(pe_header), (uint8_t *)&pe_header);
self->read(base + pe_offset+ sizeof(pe_header), sizeof(sections) , (uint8_t *)&sections ); self->read(base + pe_offset+ sizeof(pe_header), sizeof(sections) , (uint8_t *)&sections );
@ -353,7 +255,7 @@ bool SHMProcess::Private::validate(vector <VersionInfo *> & known_versions)
{ {
pe_timestamp = (*it)->getPE(); pe_timestamp = (*it)->getPE();
} }
catch(Error::MissingMemoryDefinition&) catch(Error::AllMemdef&)
{ {
continue; continue;
} }
@ -371,29 +273,6 @@ bool SHMProcess::Private::validate(vector <VersionInfo *> & known_versions)
} }
return false; return false;
} }
SHMProcess::~SHMProcess()
{
if(d->attached)
{
detach();
}
// destroy data model. this is assigned by processmanager
if(d->memdescriptor)
{
delete d->memdescriptor;
}
delete d;
}
VersionInfo * SHMProcess::getDescriptor()
{
return d->memdescriptor;
}
int SHMProcess::getPID()
{
return d->process_ID;
}
bool SHMProcess::getThreadIDs(vector<uint32_t> & threads ) bool SHMProcess::getThreadIDs(vector<uint32_t> & threads )
{ {
@ -428,137 +307,18 @@ bool SHMProcess::getThreadIDs(vector<uint32_t> & threads )
//FIXME: use VirtualQuery to probe for memory ranges, cross-reference with base-corrected PE segment entries //FIXME: use VirtualQuery to probe for memory ranges, cross-reference with base-corrected PE segment entries
void SHMProcess::getMemRanges( vector<t_memrange> & ranges ) void SHMProcess::getMemRanges( vector<t_memrange> & ranges )
{ {
// code here is taken from hexsearch by Silas Dunmore. // BLAH
// As this IMHO isn't a 'sunstantial portion' of anything, I'm not including the MIT license here ranges.clear();
// I'm faking this, because there's no way I'm using VirtualQuery
t_memrange temp;
uint32_t base = d->memdescriptor->getBase();
temp.start = base + 0x1000; // more fakery.
temp.end = base + readDWord(base+readDWord(base+0x3C)+0x50)-1; // yay for magic.
temp.read = 1;
temp.write = 1;
temp.execute = 0; // fake
strcpy(temp.name,"pants");
ranges.push_back(temp);
} }
bool SHMProcess::suspend() bool SHMProcess::acquireSuspendLock()
{ {
if(!d->attached) return ( WaitForSingleObject(d->DFCLSuspendMutex,INFINITE) == 0 );
{
return false;
}
if(d->locked)
{
return true;
}
//cerr << "suspend" << endl;// FIXME: throw
// FIXME: this should be controlled on the server side
// FIXME: IF server got CORE_RUN in this frame, interpret CORE_SUSPEND as CORE_STEP
// did we just resume a moment ago?
if(D_SHMCMD == CORE_RUN)
{
//fprintf(stderr,"%d invokes step\n",d->attachmentIdx);
// wait for the next window
/*
if(!d->SetAndWait(CORE_STEP))
{
throw Error::SHMLockingError("if(!d->SetAndWait(CORE_STEP))");
}
*/
D_SHMCMD = CORE_STEP;
}
else
{
//fprintf(stderr,"%d invokes suspend\n",d->attachmentIdx);
// lock now
/*
if(!d->SetAndWait(CORE_SUSPEND))
{
throw Error::SHMLockingError("if(!d->SetAndWait(CORE_SUSPEND))");
}
*/
D_SHMCMD = CORE_SUSPEND;
}
//fprintf(stderr,"waiting for lock\n");
// we wait for the server to give up our suspend lock (held by default)
if( WaitForSingleObject(d->DFCLSuspendMutex,INFINITE) == 0 )
{
d->locked = true;
return true;
}
return false;
}
// FIXME: needs a good think-through
bool SHMProcess::asyncSuspend()
{
if(!d->attached)
{
return false;
}
if(d->locked)
{
return true;
}
//cerr << "async suspend" << endl;// FIXME: throw
uint32_t cmd = D_SHMCMD;
if(cmd == CORE_SUSPENDED)
{
// we have to hold the lock to be really suspended
if( WaitForSingleObject(d->DFCLSuspendMutex,INFINITE) == 0 )
{
d->locked = true;
return true;
}
return false;
}
else
{
// did we just resume a moment ago?
if(cmd == CORE_STEP)
{
return false;
}
else if(cmd == CORE_RUN)
{
D_SHMCMD = CORE_STEP;
}
else
{
D_SHMCMD = CORE_SUSPEND;
}
return false;
}
} }
bool SHMProcess::forceresume() bool SHMProcess::releaseSuspendLock()
{ {
return resume(); return ( ReleaseMutex(d->DFCLSuspendMutex) != 0);
}
// FIXME: wait for the server to advance a step!
bool SHMProcess::resume()
{
if(!d->attached)
return false;
if(!d->locked)
return true;
//cerr << "resume" << endl;// FIXME: throw
// unlock the suspend lock
if( ReleaseMutex(d->DFCLSuspendMutex) != 0)
{
d->locked = false;
if(d->SetAndWait(CORE_RUN)) // we have to make sure the server responds!
{
return true;
}
throw Error::SHMLockingError("if(d->SetAndWait(CORE_RUN))");
}
throw Error::SHMLockingError("if( ReleaseMutex(d->DFCLSuspendMutex) != 0)");
return false;
} }
@ -576,21 +336,6 @@ bool SHMProcess::attach()
//cerr << "server is full or not really there!" << endl; //cerr << "server is full or not really there!" << endl;
return false; return false;
} }
/*
// check if DF is there
if(!d->isValidSV())
{
return false; // NOT
}
*/
/*
// try locking client mutex
uint32_t result = WaitForSingleObject(d->DFCLMutex,0);
if( result != WAIT_OBJECT_0 && result != WAIT_ABANDONED)
{
return false; // we couldn't lock it
}
*/
/* /*
* Locate the segment. * Locate the segment.
@ -633,12 +378,10 @@ bool SHMProcess::attach()
bool SHMProcess::detach() bool SHMProcess::detach()
{ {
if(!d->attached) return true; if(!d->attached) return true;
//cerr << "detach" << endl;// FIXME: throw
if(d->locked) if(d->locked)
{ {
resume(); resume();
} }
//cerr << "detach after resume" << endl;// FIXME: throw
// detach segment // detach segment
UnmapViewOfFile(d->shm_addr); UnmapViewOfFile(d->shm_addr);
// release it for some other client // release it for some other client
@ -650,330 +393,30 @@ bool SHMProcess::detach()
return true; return true;
} }
void SHMProcess::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer)
{
if(!d->locked) throw Error::MemoryAccessDenied();
// normal read under 1MB
if(size <= SHM_BODY)
{
D_SHMHDR->address = src_address;
D_SHMHDR->length = size;
full_barrier
d->SetAndWait(CORE_READ);
memcpy (target_buffer, D_SHMDATA(void),size);
}
// a big read, we pull data over the shm in iterations
else
{
// first read equals the size of the SHM window
uint32_t to_read = SHM_BODY;
while (size)
{
// read to_read bytes from src_cursor
D_SHMHDR->address = src_address;
D_SHMHDR->length = to_read;
full_barrier
d->SetAndWait(CORE_READ);
memcpy (target_buffer, D_SHMDATA(void) ,to_read);
// decrease size by bytes read
size -= to_read;
// move the cursors
src_address += to_read;
target_buffer += to_read;
// check how much to write in the next iteration
to_read = min(size, (uint32_t) SHM_BODY);
}
}
}
uint8_t SHMProcess::readByte (const uint32_t offset)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_BYTE);
return D_SHMHDR->value;
}
void SHMProcess::readByte (const uint32_t offset, uint8_t &val )
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_BYTE);
val = D_SHMHDR->value;
}
uint16_t SHMProcess::readWord (const uint32_t offset)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_WORD);
return D_SHMHDR->value;
}
void SHMProcess::readWord (const uint32_t offset, uint16_t &val)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_WORD);
val = D_SHMHDR->value;
}
uint32_t SHMProcess::readDWord (const uint32_t offset)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_DWORD);
return D_SHMHDR->value;
}
void SHMProcess::readDWord (const uint32_t offset, uint32_t &val)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_DWORD);
val = D_SHMHDR->value;
}
float SHMProcess::readFloat (const uint32_t offset)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_DWORD);
return reinterpret_cast<float&> (D_SHMHDR->value);
}
void SHMProcess::readFloat (const uint32_t offset, float &val)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_DWORD);
val = reinterpret_cast<float&> (D_SHMHDR->value);
}
uint64_t SHMProcess::readQuad (const uint32_t offset)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_QUAD);
return D_SHMHDR->Qvalue;
}
void SHMProcess::readQuad (const uint32_t offset, uint64_t &val)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_QUAD);
val = D_SHMHDR->Qvalue;
}
/*
* WRITING
*/
void SHMProcess::writeQuad (uint32_t offset, uint64_t data)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
D_SHMHDR->Qvalue = data;
full_barrier
d->SetAndWait(CORE_WRITE_QUAD);
}
void SHMProcess::writeDWord (uint32_t offset, uint32_t data)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
D_SHMHDR->value = data;
full_barrier
d->SetAndWait(CORE_WRITE_DWORD);
}
// using these is expensive.
void SHMProcess::writeWord (uint32_t offset, uint16_t data)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
D_SHMHDR->value = data;
full_barrier
d->SetAndWait(CORE_WRITE_WORD);
}
void SHMProcess::writeByte (uint32_t offset, uint8_t data)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
D_SHMHDR->value = data;
full_barrier
d->SetAndWait(CORE_WRITE_BYTE);
}
void SHMProcess::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer)
{
if(!d->locked) throw Error::MemoryAccessDenied();
// normal write under 1MB
if(size <= SHM_BODY)
{
D_SHMHDR->address = dst_address;
D_SHMHDR->length = size;
memcpy(D_SHMDATA(void),source_buffer, size);
full_barrier
d->SetAndWait(CORE_WRITE);
}
// a big write, we push this over the shm in iterations
else
{
// first write equals the size of the SHM window
uint32_t to_write = SHM_BODY;
while (size)
{
// write to_write bytes to dst_cursor
D_SHMHDR->address = dst_address;
D_SHMHDR->length = to_write;
memcpy(D_SHMDATA(void),source_buffer, to_write);
full_barrier
d->SetAndWait(CORE_WRITE);
// decrease size by bytes written
size -= to_write;
// move the cursors
source_buffer += to_write;
dst_address += to_write;
// check how much to write in the next iteration
to_write = min(size, (uint32_t) SHM_BODY);
}
}
}
// FIXME: butt-fugly
const std::string SHMProcess::readCString (uint32_t offset)
{
if(!d->locked) throw Error::MemoryAccessDenied();
std::string temp;
char temp_c[256];
int counter = 0;
char r;
do
{
r = readByte(offset+counter);
temp_c[counter] = r;
counter++;
} while (r && counter < 255);
temp_c[counter] = 0;
temp = temp_c;
return temp;
}
const std::string SHMProcess::readSTLString(uint32_t offset)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_STL_STRING);
return(string( D_SHMDATA(char) ));
}
size_t SHMProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_STL_STRING);
size_t length = D_SHMHDR->value;
size_t fit = min(bufcapacity - 1, length);
strncpy(buffer,D_SHMDATA(char),fit);
buffer[fit] = 0;
return fit;
}
void SHMProcess::writeSTLString(const uint32_t address, const std::string writeString)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = address;
strncpy(D_SHMDATA(char),writeString.c_str(),writeString.length()+1); // length + 1 for the null terminator
full_barrier
d->SetAndWait(CORE_WRITE_STL_STRING);
}
string SHMProcess::readClassName (uint32_t vptr) string SHMProcess::readClassName (uint32_t vptr)
{ {
int rtti = readDWord(vptr - 0x4); int rtti = Process::readDWord(vptr - 0x4);
int typeinfo = readDWord(rtti + 0xC); int typeinfo = Process::readDWord(rtti + 0xC);
string raw = readCString(typeinfo + 0xC); // skips the .?AV string raw = readCString(typeinfo + 0xC); // skips the .?AV
raw.resize(raw.length() - 2);// trim @@ from end raw.resize(raw.length() - 2);// trim @@ from end
return raw; return raw;
} }
// get module index by name and version. bool 0 = error string SHMProcess::getPath()
bool SHMProcess::getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT)
{ {
if(!d->locked) throw Error::MemoryAccessDenied(); HMODULE hmod;
DWORD junk;
modulelookup * payload = D_SHMDATA(modulelookup); char String[255];
payload->version = version; HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, d->process_ID ); //get the handle from the process ID
EnumProcessModules(hProcess, &hmod, 1 * sizeof(HMODULE), &junk); //get the module from the handle
strncpy(payload->name,name,255); GetModuleFileNameEx(hProcess,hmod,String,sizeof(String)); //get the filename from the module
payload->name[255] = 0; string out(String);
return(out.substr(0,out.find_last_of("\\")));
if(!SetAndWait(CORE_ACQUIRE_MODULE))
{
return false; // FIXME: throw a fatal exception instead
}
if(D_SHMHDR->error)
{
return false;
}
//fprintf(stderr,"%s v%d : %d\n", name, version, D_SHMHDR->value);
OUTPUT = D_SHMHDR->value;
return true;
} }
char * SHMProcess::getSHMStart (void) char * SHMProcess::getSHMStart (void)
{ {
if(!d->locked) throw Error::MemoryAccessDenied(); if(!d->locked) throw Error::MemoryAccessDenied();
return /*d->shm_addr_with_cl_idx*/ d->shm_addr;
}
bool SHMProcess::Private::Aux_Core_Attach(bool & versionOK, uint32_t & PID)
{
if(!locked) throw Error::MemoryAccessDenied();
SHMDATA(coreattach)->cl_affinity = OS_getAffinity(); return d->shm_addr;
if(!SetAndWait(CORE_ATTACH)) return false;
/*
cerr <<"CORE_VERSION" << CORE_VERSION << endl;
cerr <<"server CORE_VERSION" << SHMDATA(coreattach)->sv_version << endl;
*/
versionOK =( SHMDATA(coreattach)->sv_version == CORE_VERSION );
PID = SHMDATA(coreattach)->sv_PID;
useYield = SHMDATA(coreattach)->sv_useYield;
#ifdef DEBUG
if(useYield) cerr << "Using Yield!" << endl;
#endif
return true;
} }

@ -22,79 +22,136 @@ must not be misrepresented as being the original software.
distribution. distribution.
*/ */
#include "Internal.h" #include "Internal.h"
#include "dfhack/DFProcess.h" #include "ProcessFactory.h"
#include "MicrosoftSTL.h"
#include "dfhack/VersionInfo.h" #include "dfhack/VersionInfo.h"
#include "dfhack/DFError.h" #include "dfhack/DFError.h"
#include <string.h>
using namespace DFHack; using namespace DFHack;
class NormalProcess::Private namespace
{ {
public: class NormalProcess : public Process
Private() {
{ private:
my_descriptor = NULL; VersionInfo * my_descriptor;
my_handle = NULL; HANDLE my_handle;
my_main_thread = NULL; HANDLE my_main_thread;
my_pid = 0; uint32_t my_pid;
attached = false; string memFile;
suspended = false; bool attached;
}; bool suspended;
~Private(){}; bool identified;
VersionInfo * my_descriptor; IMAGE_NT_HEADERS pe_header;
HANDLE my_handle; IMAGE_SECTION_HEADER * sections;
HANDLE my_main_thread; uint32_t base;
uint32_t my_pid; MicrosoftSTL stl;
string memFile; public:
bool attached; NormalProcess(uint32_t pid, std::vector <VersionInfo *> & known_versions);
bool suspended; ~NormalProcess();
bool identified; bool attach();
uint32_t STLSTR_buf_off; bool detach();
uint32_t STLSTR_size_off;
uint32_t STLSTR_cap_off; bool suspend();
}; bool asyncSuspend();
bool resume();
bool forceresume();
void readQuad(const uint32_t address, uint64_t & value);
void writeQuad(const uint32_t address, const uint64_t value);
void readDWord(const uint32_t address, uint32_t & value);
void writeDWord(const uint32_t address, const uint32_t value);
void readFloat(const uint32_t address, float & value);
void readWord(const uint32_t address, uint16_t & value);
void writeWord(const uint32_t address, const uint16_t value);
void readByte(const uint32_t address, uint8_t & value);
void writeByte(const uint32_t address, const uint8_t value);
void read( uint32_t address, uint32_t length, uint8_t* buffer);
void write(uint32_t address, uint32_t length, uint8_t* buffer);
const std::string readSTLString (uint32_t offset);
size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity);
void writeSTLString(const uint32_t address, const std::string writeString){};
// get class name of an object with rtti/type info
std::string readClassName(uint32_t vptr);
const std::string readCString (uint32_t offset);
bool isSuspended();
bool isAttached();
bool isIdentified();
bool getThreadIDs(std::vector<uint32_t> & threads );
void getMemRanges(std::vector<t_memrange> & ranges );
VersionInfo *getDescriptor();
int getPID();
std::string getPath();
// get module index by name and version. bool 1 = error
bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) { OUTPUT=0; return false;};
// get the SHM start if available
char * getSHMStart (void){return 0;};
// set a SHM command and wait for a response
bool SetAndWait (uint32_t state){return false;};
};
}
Process* DFHack::createNormalProcess(uint32_t pid, vector <VersionInfo *> & known_versions)
{
return new NormalProcess(pid, known_versions);
}
NormalProcess::NormalProcess(uint32_t pid, vector <VersionInfo *> & known_versions) NormalProcess::NormalProcess(uint32_t pid, vector <VersionInfo *> & known_versions)
: d(new Private()) : my_pid(pid)
{ {
my_descriptor = NULL;
my_main_thread = NULL;
attached = false;
suspended = false;
base = 0;
sections = 0;
HMODULE hmod = NULL; HMODULE hmod = NULL;
DWORD junk; DWORD needed;
HANDLE hProcess;
bool found = false; bool found = false;
IMAGE_NT_HEADERS32 pe_header; identified = false;
IMAGE_SECTION_HEADER sections[16];
d->identified = false;
// open process // open process
hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pid ); my_handle = OpenProcess( PROCESS_ALL_ACCESS, FALSE, my_pid );
if (NULL == hProcess) if (NULL == my_handle)
return; return;
// try getting the first module of the process // try getting the first module of the process
if(EnumProcessModules(hProcess, &hmod, 1 * sizeof(HMODULE), &junk) == 0) if(EnumProcessModules(my_handle, &hmod, sizeof(hmod), &needed) == 0)
{ {
CloseHandle(hProcess); CloseHandle(my_handle);
// cout << "EnumProcessModules fail'd" << endl; // cout << "EnumProcessModules fail'd" << endl;
return; //if enumprocessModules fails, give up return; //if enumprocessModules fails, give up
} }
// got base ;) // got base ;)
uint32_t base = (uint32_t)hmod; base = (uint32_t)hmod;
// temporarily assign this to allow some checks my_main_thread = 0;
d->my_handle = hProcess;
d->my_main_thread = 0;
// read from this process // read from this process
try try
{ {
uint32_t pe_offset = readDWord(base+0x3C); uint32_t pe_offset = Process::readDWord(base+0x3C);
read(base + pe_offset , sizeof(pe_header), (uint8_t *)&pe_header); read(base + pe_offset , sizeof(pe_header), (uint8_t *)&pe_header);
read(base + pe_offset+ sizeof(pe_header), sizeof(sections) , (uint8_t *)&sections ); const size_t sectionsSize = sizeof(IMAGE_SECTION_HEADER) * pe_header.FileHeader.NumberOfSections;
d->my_handle = 0; sections = (IMAGE_SECTION_HEADER *) malloc(sectionsSize);
read(base + pe_offset + sizeof(pe_header), sectionsSize, (uint8_t *)sections);
my_handle = 0;
} }
catch (exception &) catch (exception &)
{ {
CloseHandle(hProcess); CloseHandle(my_handle);
d->my_handle = 0; my_handle = 0;
return; return;
} }
@ -103,7 +160,7 @@ NormalProcess::NormalProcess(uint32_t pid, vector <VersionInfo *> & known_versio
for ( it=known_versions.begin() ; it < known_versions.end(); it++ ) for ( it=known_versions.begin() ; it < known_versions.end(); it++ )
{ {
// filter by OS // filter by OS
if(VersionInfo::OS_WINDOWS != (*it)->getOS()) if(OS_WINDOWS != (*it)->getOS())
continue; continue;
uint32_t pe_timestamp; uint32_t pe_timestamp;
// filter by timestamp, skip entries without a timestamp // filter by timestamp, skip entries without a timestamp
@ -111,7 +168,7 @@ NormalProcess::NormalProcess(uint32_t pid, vector <VersionInfo *> & known_versio
{ {
pe_timestamp = (*it)->getPE(); pe_timestamp = (*it)->getPE();
} }
catch(Error::MissingMemoryDefinition&) catch(Error::AllMemdef&)
{ {
continue; continue;
} }
@ -121,26 +178,21 @@ NormalProcess::NormalProcess(uint32_t pid, vector <VersionInfo *> & known_versio
// all went well // all went well
{ {
printf("Match found! Using version %s.\n", (*it)->getVersion().c_str()); printf("Match found! Using version %s.\n", (*it)->getVersion().c_str());
d->identified = true; identified = true;
// give the process a data model and memory layout fixed for the base of first module // give the process a data model and memory layout fixed for the base of first module
VersionInfo *m = new VersionInfo(**it); my_descriptor = new VersionInfo(**it);
m->RebaseAll(base); my_descriptor->RebaseAll(base);
// keep track of created memory_info object so we can destroy it later // keep track of created memory_info object so we can destroy it later
d->my_descriptor = m; my_descriptor->setParentProcess(this);
m->setParentProcess(this);
// process is responsible for destroying its data model // process is responsible for destroying its data model
d->my_pid = pid; my_handle = my_handle;
d->my_handle = hProcess; identified = true;
d->identified = true;
// TODO: detect errors in thread enumeration // TODO: detect errors in thread enumeration
vector<uint32_t> threads; vector<uint32_t> threads;
getThreadIDs( threads ); getThreadIDs( threads );
d->my_main_thread = OpenThread(THREAD_ALL_ACCESS, FALSE, (DWORD) threads[0]); my_main_thread = OpenThread(THREAD_ALL_ACCESS, FALSE, (DWORD) threads[0]);
OffsetGroup * strGrp = m->getGroup("string")->getGroup("MSVC"); stl.init(this);
d->STLSTR_buf_off = strGrp->getOffset("buffer");
d->STLSTR_size_off = strGrp->getOffset("size");
d->STLSTR_cap_off = strGrp->getOffset("capacity");
found = true; found = true;
break; // break the iterator loop break; // break the iterator loop
} }
@ -148,7 +200,7 @@ NormalProcess::NormalProcess(uint32_t pid, vector <VersionInfo *> & known_versio
// close handle of processes that aren't DF // close handle of processes that aren't DF
if(!found) if(!found)
{ {
CloseHandle(hProcess); CloseHandle(my_handle);
} }
} }
/* /*
@ -156,45 +208,46 @@ NormalProcess::NormalProcess(uint32_t pid, vector <VersionInfo *> & known_versio
NormalProcess::~NormalProcess() NormalProcess::~NormalProcess()
{ {
if(d->attached) if(attached)
{ {
detach(); detach();
} }
// destroy our rebased copy of the memory descriptor // destroy our rebased copy of the memory descriptor
delete d->my_descriptor; delete my_descriptor;
if(d->my_handle != NULL) if(my_handle != NULL)
{ {
CloseHandle(d->my_handle); CloseHandle(my_handle);
} }
if(d->my_main_thread != NULL) if(my_main_thread != NULL)
{ {
CloseHandle(d->my_main_thread); CloseHandle(my_main_thread);
} }
delete d; if(sections != NULL)
free(sections);
} }
VersionInfo * NormalProcess::getDescriptor() VersionInfo * NormalProcess::getDescriptor()
{ {
return d->my_descriptor; return my_descriptor;
} }
int NormalProcess::getPID() int NormalProcess::getPID()
{ {
return d->my_pid; return my_pid;
} }
bool NormalProcess::isSuspended() bool NormalProcess::isSuspended()
{ {
return d->suspended; return suspended;
} }
bool NormalProcess::isAttached() bool NormalProcess::isAttached()
{ {
return d->attached; return attached;
} }
bool NormalProcess::isIdentified() bool NormalProcess::isIdentified()
{ {
return d->identified; return identified;
} }
bool NormalProcess::asyncSuspend() bool NormalProcess::asyncSuspend()
@ -204,49 +257,49 @@ bool NormalProcess::asyncSuspend()
bool NormalProcess::suspend() bool NormalProcess::suspend()
{ {
if(!d->attached) if(!attached)
return false; return false;
if(d->suspended) if(suspended)
{ {
return true; return true;
} }
SuspendThread(d->my_main_thread); SuspendThread(my_main_thread);
d->suspended = true; suspended = true;
return true; return true;
} }
bool NormalProcess::forceresume() bool NormalProcess::forceresume()
{ {
if(!d->attached) if(!attached)
return false; return false;
while (ResumeThread(d->my_main_thread) > 1); while (ResumeThread(my_main_thread) > 1);
d->suspended = false; suspended = false;
return true; return true;
} }
bool NormalProcess::resume() bool NormalProcess::resume()
{ {
if(!d->attached) if(!attached)
return false; return false;
if(!d->suspended) if(!suspended)
{ {
return true; return true;
} }
ResumeThread(d->my_main_thread); ResumeThread(my_main_thread);
d->suspended = false; suspended = false;
return true; return true;
} }
bool NormalProcess::attach() bool NormalProcess::attach()
{ {
if(d->attached) if(attached)
{ {
if(!d->suspended) if(!suspended)
return suspend(); return suspend();
return true; return true;
} }
d->attached = true; attached = true;
suspend(); suspend();
return true; return true;
@ -255,9 +308,9 @@ bool NormalProcess::attach()
bool NormalProcess::detach() bool NormalProcess::detach()
{ {
if(!d->attached) return true; if(!attached) return true;
resume(); resume();
d->attached = false; attached = false;
return true; return true;
} }
@ -281,7 +334,7 @@ bool NormalProcess::getThreadIDs(vector<uint32_t> & threads )
do do
{ {
if( te32.th32OwnerProcessID == d->my_pid ) if( te32.th32OwnerProcessID == my_pid )
{ {
threads.push_back(te32.th32ThreadID); threads.push_back(te32.th32ThreadID);
} }
@ -290,143 +343,200 @@ bool NormalProcess::getThreadIDs(vector<uint32_t> & threads )
CloseHandle( AllThreads ); CloseHandle( AllThreads );
return true; return true;
} }
/*
//FIXME: use VirtualQuery to probe for memory ranges, cross-reference with base-corrected PE segment entries typedef struct _MEMORY_BASIC_INFORMATION
void NormalProcess::getMemRanges( vector<t_memrange> & ranges ) {
void * BaseAddress;
void * AllocationBase;
uint32_t AllocationProtect;
size_t RegionSize;
uint32_t State;
uint32_t Protect;
uint32_t Type;
} MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION;
*/
/*
//Internal structure used to store heap block information.
struct HeapBlock
{ {
// code here is taken from hexsearch by Silas Dunmore. PVOID dwAddress;
// As this IMHO isn't a 'sunstantial portion' of anything, I'm not including the MIT license here DWORD dwSize;
DWORD dwFlags;
// I'm faking this, because there's no way I'm using VirtualQuery ULONG reserved;
};
t_memrange temp; */
uint32_t base = d->my_descriptor->getBase(); void HeapNodes(DWORD pid, map<uint64_t, unsigned int> & heaps)
temp.start = base + 0x1000; // more fakery. {
temp.end = base + readDWord(base+readDWord(base+0x3C)+0x50)-1; // yay for magic. // Create debug buffer
temp.read = 1; PDEBUG_BUFFER db = RtlCreateQueryDebugBuffer(0, FALSE);
temp.write = 1; // Get process heap data
temp.execute = 0; // fake RtlQueryProcessDebugInformation( pid, PDI_HEAPS/* | PDI_HEAP_BLOCKS*/, db);
strcpy(temp.name,"pants");// that's right. I'm calling it pants. Windows can go to HELL ULONG heapNodeCount = db->HeapInformation ? *PULONG(db->HeapInformation):0;
ranges.push_back(temp); PDEBUG_HEAP_INFORMATION heapInfo = PDEBUG_HEAP_INFORMATION(PULONG(db-> HeapInformation) + 1);
// Go through each of the heap nodes and dispaly the information
for (unsigned int i = 0; i < heapNodeCount; i++)
{
heaps[heapInfo[i].Base] = i;
}
// Clean up the buffer
RtlDestroyQueryDebugBuffer( db );
} }
uint8_t NormalProcess::readByte (const uint32_t offset) // FIXME: NEEDS TESTING!
void NormalProcess::getMemRanges( vector<t_memrange> & ranges )
{ {
uint8_t result; MEMORY_BASIC_INFORMATION MBI;
if(!ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint8_t), NULL)) map<uint64_t, unsigned int> heaps;
throw Error::MemoryAccessDenied(); uint64_t movingStart = 0;
return result; map <uint64_t, string> nameMap;
// get page size
SYSTEM_INFO si;
GetSystemInfo(&si);
uint64_t PageSize = si.dwPageSize;
// enumerate heaps
HeapNodes(my_pid, heaps);
// go through all the VM regions, convert them to our internal format
while (VirtualQueryEx(this->my_handle, (const void*) (movingStart), &MBI, sizeof(MBI)) == sizeof(MBI))
{
movingStart = ((uint64_t)MBI.BaseAddress + MBI.RegionSize);
if(movingStart % PageSize != 0)
movingStart = (movingStart / PageSize + 1) * PageSize;
// skip empty regions and regions we share with other processes (DLLs)
if( !(MBI.State & MEM_COMMIT) /*|| !(MBI.Type & MEM_PRIVATE)*/ )
continue;
t_memrange temp;
temp.start = (uint64_t) MBI.BaseAddress;
temp.end = ((uint64_t)MBI.BaseAddress + (uint64_t)MBI.RegionSize);
temp.read = MBI.Protect & PAGE_EXECUTE_READ || MBI.Protect & PAGE_EXECUTE_READWRITE || MBI.Protect & PAGE_READONLY || MBI.Protect & PAGE_READWRITE;
temp.write = MBI.Protect & PAGE_EXECUTE_READWRITE || MBI.Protect & PAGE_READWRITE;
temp.execute = MBI.Protect & PAGE_EXECUTE_READ || MBI.Protect & PAGE_EXECUTE_READWRITE || MBI.Protect & PAGE_EXECUTE;
temp.valid = true;
if(!GetModuleBaseName(this->my_handle, (HMODULE) temp.start, temp.name, 1024))
{
if(nameMap.count(temp.start))
{
// potential buffer overflow...
strcpy(temp.name, nameMap[temp.start].c_str());
}
else
{
// filter away shared segments without a name.
if( !(MBI.Type & MEM_PRIVATE) )
continue;
else
{
// could be a heap?
if(heaps.count(temp.start))
{
sprintf(temp.name,"HEAP %d",heaps[temp.start]);
}
else temp.name[0]=0;
}
}
}
else
{
// this is our executable! (could be generalized to pull segments from libs, but whatever)
if(base == temp.start)
{
for(int i = 0; i < pe_header.FileHeader.NumberOfSections; i++)
{
char sectionName[9];
memcpy(sectionName,sections[i].Name,8);
sectionName[8] = 0;
string nm;
nm.append(temp.name);
nm.append(" : ");
nm.append(sectionName);
nameMap[temp.start + sections[i].VirtualAddress] = nm;
}
}
else
continue;
}
ranges.push_back(temp);
}
} }
void NormalProcess::readByte (const uint32_t offset,uint8_t &result) void NormalProcess::readByte (const uint32_t offset,uint8_t &result)
{ {
if(!ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint8_t), NULL)) if(!ReadProcessMemory(my_handle, (int*) offset, &result, sizeof(uint8_t), NULL))
throw Error::MemoryAccessDenied();
}
uint16_t NormalProcess::readWord (const uint32_t offset)
{
uint16_t result;
if(!ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint16_t), NULL))
throw Error::MemoryAccessDenied(); throw Error::MemoryAccessDenied();
return result;
} }
void NormalProcess::readWord (const uint32_t offset, uint16_t &result) void NormalProcess::readWord (const uint32_t offset, uint16_t &result)
{ {
if(!ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint16_t), NULL)) if(!ReadProcessMemory(my_handle, (int*) offset, &result, sizeof(uint16_t), NULL))
throw Error::MemoryAccessDenied(); throw Error::MemoryAccessDenied();
} }
uint32_t NormalProcess::readDWord (const uint32_t offset)
{
uint32_t result;
if(!ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint32_t), NULL))
throw Error::MemoryAccessDenied();
return result;
}
void NormalProcess::readDWord (const uint32_t offset, uint32_t &result) void NormalProcess::readDWord (const uint32_t offset, uint32_t &result)
{ {
if(!ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint32_t), NULL)) if(!ReadProcessMemory(my_handle, (int*) offset, &result, sizeof(uint32_t), NULL))
throw Error::MemoryAccessDenied();
}
uint64_t NormalProcess::readQuad (const uint32_t offset)
{
uint64_t result;
if(!ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint64_t), NULL))
throw Error::MemoryAccessDenied(); throw Error::MemoryAccessDenied();
return result;
} }
void NormalProcess::readQuad (const uint32_t offset, uint64_t &result) void NormalProcess::readQuad (const uint32_t offset, uint64_t &result)
{ {
if(!ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint64_t), NULL)) if(!ReadProcessMemory(my_handle, (int*) offset, &result, sizeof(uint64_t), NULL))
throw Error::MemoryAccessDenied(); throw Error::MemoryAccessDenied();
} }
float NormalProcess::readFloat (const uint32_t offset)
{
float result;
if(!ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(float), NULL))
throw Error::MemoryAccessDenied();
return result;
}
void NormalProcess::readFloat (const uint32_t offset, float &result) void NormalProcess::readFloat (const uint32_t offset, float &result)
{ {
if(!ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(float), NULL)) if(!ReadProcessMemory(my_handle, (int*) offset, &result, sizeof(float), NULL))
throw Error::MemoryAccessDenied(); throw Error::MemoryAccessDenied();
} }
void NormalProcess::read (const uint32_t offset, uint32_t size, uint8_t *target) void NormalProcess::read (const uint32_t offset, uint32_t size, uint8_t *target)
{ {
if(!ReadProcessMemory(d->my_handle, (int*) offset, target, size, NULL)) if(!ReadProcessMemory(my_handle, (int*) offset, target, size, NULL))
throw Error::MemoryAccessDenied(); throw Error::MemoryAccessDenied();
} }
// WRITING // WRITING
void NormalProcess::writeQuad (const uint32_t offset, uint64_t data) void NormalProcess::writeQuad (const uint32_t offset, uint64_t data)
{ {
if(!WriteProcessMemory(d->my_handle, (int*) offset, &data, sizeof(data), NULL)) if(!WriteProcessMemory(my_handle, (int*) offset, &data, sizeof(data), NULL))
throw Error::MemoryAccessDenied(); throw Error::MemoryAccessDenied();
} }
void NormalProcess::writeDWord (const uint32_t offset, uint32_t data) void NormalProcess::writeDWord (const uint32_t offset, uint32_t data)
{ {
if(!WriteProcessMemory(d->my_handle, (int*) offset, &data, sizeof(data), NULL)) if(!WriteProcessMemory(my_handle, (int*) offset, &data, sizeof(data), NULL))
throw Error::MemoryAccessDenied(); throw Error::MemoryAccessDenied();
} }
// using these is expensive. // using these is expensive.
void NormalProcess::writeWord (uint32_t offset, uint16_t data) void NormalProcess::writeWord (uint32_t offset, uint16_t data)
{ {
if(!WriteProcessMemory(d->my_handle, (int*) offset, &data, sizeof(data), NULL)) if(!WriteProcessMemory(my_handle, (int*) offset, &data, sizeof(data), NULL))
throw Error::MemoryAccessDenied(); throw Error::MemoryAccessDenied();
} }
void NormalProcess::writeByte (uint32_t offset, uint8_t data) void NormalProcess::writeByte (uint32_t offset, uint8_t data)
{ {
if(!WriteProcessMemory(d->my_handle, (int*) offset, &data, sizeof(data), NULL)) if(!WriteProcessMemory(my_handle, (int*) offset, &data, sizeof(data), NULL))
throw Error::MemoryAccessDenied(); throw Error::MemoryAccessDenied();
} }
void NormalProcess::write (uint32_t offset, uint32_t size, uint8_t *source) void NormalProcess::write (uint32_t offset, uint32_t size, uint8_t *source)
{ {
if(!WriteProcessMemory(d->my_handle, (int*) offset, source, size, NULL)) if(!WriteProcessMemory(my_handle, (int*) offset, source, size, NULL))
throw Error::MemoryAccessDenied(); throw Error::MemoryAccessDenied();
} }
///FIXME: reduce use of temporary objects ///FIXME: reduce use of temporary objects
const string NormalProcess::readCString (const uint32_t offset) const string NormalProcess::readCString (const uint32_t offset)
{ {
string temp; string temp;
char temp_c[256]; char temp_c[256];
SIZE_T read; SIZE_T read;
if(!ReadProcessMemory(d->my_handle, (int *) offset, temp_c, 254, &read)) if(!ReadProcessMemory(my_handle, (int *) offset, temp_c, 254, &read))
throw Error::MemoryAccessDenied(); throw Error::MemoryAccessDenied();
// needs to be 254+1 byte for the null term // needs to be 254+1 byte for the null term
temp_c[read+1] = 0; temp_c[read+1] = 0;
@ -436,55 +546,26 @@ const string NormalProcess::readCString (const uint32_t offset)
size_t NormalProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) size_t NormalProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
{ {
uint32_t start_offset = offset + d->STLSTR_buf_off; return stl.readSTLString(offset, buffer, bufcapacity);
size_t length = readDWord(offset + d->STLSTR_size_off);
size_t capacity = readDWord(offset + d->STLSTR_cap_off);
size_t read_real = min(length, bufcapacity-1);// keep space for null termination
// read data from inside the string structure
if(capacity < 16)
{
read(start_offset, read_real , (uint8_t *)buffer);
}
else // read data from what the offset + 4 dword points to
{
start_offset = readDWord(start_offset);// dereference the start offset
read(start_offset, read_real, (uint8_t *)buffer);
}
buffer[read_real] = 0;
return read_real;
} }
const string NormalProcess::readSTLString (uint32_t offset) const string NormalProcess::readSTLString (uint32_t offset)
{ {
uint32_t start_offset = offset + d->STLSTR_buf_off; return stl.readSTLString(offset);
size_t length = readDWord(offset + d->STLSTR_size_off);
size_t capacity = readDWord(offset + d->STLSTR_cap_off);
char * temp = new char[capacity+1];
// read data from inside the string structure
if(capacity < 16)
{
read(start_offset, capacity, (uint8_t *)temp);
}
else // read data from what the offset + 4 dword points to
{
start_offset = readDWord(start_offset);// dereference the start offset
read(start_offset, capacity, (uint8_t *)temp);
}
temp[length] = 0;
string ret = temp;
delete temp;
return ret;
} }
string NormalProcess::readClassName (uint32_t vptr) string NormalProcess::readClassName (uint32_t vptr)
{ {
int rtti = readDWord(vptr - 0x4); return stl.readClassName(vptr);
int typeinfo = readDWord(rtti + 0xC); }
string raw = readCString(typeinfo + 0xC); // skips the .?AV
raw.resize(raw.length() - 2);// trim @@ from end string NormalProcess::getPath()
return raw; {
HMODULE hmod;
DWORD junk;
char String[255];
EnumProcessModules(my_handle, &hmod, 1 * sizeof(HMODULE), &junk); //get the module from the handle
GetModuleFileNameEx(my_handle,hmod,String,sizeof(String)); //get the filename from the module
string out(String);
return(out.substr(0,out.find_last_of("\\")));
} }

@ -23,10 +23,10 @@ distribution.
*/ */
#include "Internal.h" #include "Internal.h"
#include "ProcessFactory.h"
#include "dfhack/VersionInfoFactory.h" #include "dfhack/VersionInfoFactory.h"
#include "dfhack/DFProcessEnumerator.h" #include "dfhack/DFProcessEnumerator.h"
#include "dfhack/DFProcess.h"
#include "dfhack/VersionInfo.h" #include "dfhack/VersionInfo.h"
@ -63,7 +63,7 @@ BadProcesses::~BadProcesses()
bool BadProcesses::Contains(Process* p) bool BadProcesses::Contains(Process* p)
{ {
for(int i = 0; i < d->bad.size(); i++) for(unsigned int i = 0; i < d->bad.size(); i++)
{ {
if(d->bad[i] == p) if(d->bad[i] == p)
return true; return true;
@ -96,7 +96,7 @@ uint32_t BadProcesses::size()
void BadProcesses::clear() void BadProcesses::clear()
{ {
for(int i = 0; i < d->bad.size(); i++) for(unsigned int i = 0; i < d->bad.size(); i++)
{ {
delete d->bad[i]; delete d->bad[i];
} }
@ -120,19 +120,19 @@ Process * BadProcesses::operator[](uint32_t index)
Process *ProcessEnumerator::Private::GetProcessObject(ProcessID ID) Process *ProcessEnumerator::Private::GetProcessObject(ProcessID ID)
{ {
Process *p1 = new SHMProcess(ID.pid,meminfo->versions); Process *p1 = createSHMProcess(ID.pid,meminfo->versions);
if(p1->isIdentified()) if(p1->isIdentified())
return p1; return p1;
else else
delete p1; delete p1;
Process *p2 = new NormalProcess(ID.pid,meminfo->versions); Process *p2 = createNormalProcess(ID.pid,meminfo->versions);
if(p2->isIdentified()) if(p2->isIdentified())
return p2; return p2;
else else
delete p2; delete p2;
#ifdef LINUX_BUILD #ifdef LINUX_BUILD
Process *p3 = new WineProcess(ID.pid,meminfo->versions); Process *p3 = createWineProcess(ID.pid,meminfo->versions);
if(p3->isIdentified()) if(p3->isIdentified())
return p3; return p3;
else else

@ -0,0 +1,31 @@
// vim: sts=4 sta et shiftwidth=4:
#include "dfhack/DFIntegers.h"
#include "dfhack/DFTileTypes.h"
#include "dfhack/DFExport.h"
namespace DFHack {
//set tile class string lookup table (e.g. for printing to user)
#define X(name,comment) #name,
const char * TileClassString[tileclass_count+1] = {
TILECLASS_MACRO
0
};
#undef X
//string lookup table (e.g. for printing to user)
#define X(name,comment) #name,
const char * TileMaterialString[tilematerial_count+1] = {
TILEMATERIAL_MACRO
0
};
#undef X
//string lookup table (e.g. for printing to user)
#define X(name,comment) #name,
const char * TileSpecialString[tilespecial_count+1] = {
TILESPECIAL_MACRO
0
};
#undef X
}

@ -39,6 +39,31 @@ using namespace std;
using namespace DFHack; using namespace DFHack;
/*
I believe this is what they call "the bad kind of clever", but writing out registration functions for each callback just feels *so* wrong...
The output of this macro is something like this...
void RegisterByteBufferCallback(int(*fptr)(int8_t*, uint32_t))
{
alloc_byte_buffer_callback = fptr;
}
*/
#define BUILD(a) a ## BufferCallback
#define REG_MACRO(type_name, type, callback) void BUILD(Register ## type_name) (int (*fptr)(type, uint32_t)) { callback = fptr; }
/*
The output of this macro is something like this...
void UnregisterByteBufferCallback()
{
alloc_byte_buffer_callback = NULL;
}
*/
#define UNREG_MACRO(type_name, callback) void BUILD(Unregister ## type_name) () { callback = NULL; }
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -80,6 +105,114 @@ int (*alloc_vein_buffer_callback)(t_vein*, uint32_t) = NULL;
int (*alloc_frozenliquidvein_buffer_callback)(t_frozenliquidvein*, uint32_t) = NULL; int (*alloc_frozenliquidvein_buffer_callback)(t_frozenliquidvein*, uint32_t) = NULL;
int (*alloc_spattervein_buffer_callback)(t_spattervein*, uint32_t) = NULL; int (*alloc_spattervein_buffer_callback)(t_spattervein*, uint32_t) = NULL;
REG_MACRO(Byte, int8_t*, alloc_byte_buffer_callback)
REG_MACRO(Short, int16_t*, alloc_short_buffer_callback)
REG_MACRO(Int, int32_t*, alloc_int_buffer_callback)
REG_MACRO(UByte, uint8_t*, alloc_ubyte_buffer_callback)
REG_MACRO(UShort, uint16_t*, alloc_ushort_buffer_callback)
REG_MACRO(UInt, uint32_t*, alloc_uint_buffer_callback)
REG_MACRO(Char, char*, alloc_char_buffer_callback)
REG_MACRO(Matgloss, t_matgloss*, alloc_matgloss_buffer_callback)
REG_MACRO(DescriptorColor, t_descriptor_color*, alloc_descriptor_buffer_callback)
REG_MACRO(MatglossOther, t_matglossOther*, alloc_matgloss_other_buffer_callback)
REG_MACRO(Feature, t_feature*, alloc_t_feature_buffer_callback)
REG_MACRO(Hotkey, t_hotkey*, alloc_t_hotkey_buffer_callback)
REG_MACRO(Screen, t_screen*, alloc_t_screen_buffer_callback)
REG_MACRO(CustomWorkshop, t_customWorkshop*, alloc_t_customWorkshop_buffer_callback)
REG_MACRO(Material, t_material*, alloc_t_material_buffer_callback)
UNREG_MACRO(Byte, alloc_byte_buffer_callback)
UNREG_MACRO(Short, alloc_short_buffer_callback)
UNREG_MACRO(Int, alloc_int_buffer_callback)
UNREG_MACRO(UByte, alloc_ubyte_buffer_callback)
UNREG_MACRO(UShort, alloc_ushort_buffer_callback)
UNREG_MACRO(UInt, alloc_uint_buffer_callback)
UNREG_MACRO(Char, alloc_char_buffer_callback)
UNREG_MACRO(Matgloss, alloc_matgloss_buffer_callback)
UNREG_MACRO(DescriptorColor, alloc_descriptor_buffer_callback)
UNREG_MACRO(MatglossOther, alloc_matgloss_other_buffer_callback)
UNREG_MACRO(Feature, alloc_t_feature_buffer_callback)
UNREG_MACRO(Hotkey, alloc_t_hotkey_buffer_callback)
UNREG_MACRO(Screen, alloc_t_screen_buffer_callback)
UNREG_MACRO(CustomWorkshop, alloc_t_customWorkshop_buffer_callback)
UNREG_MACRO(Material, alloc_t_material_buffer_callback)
void RegisterEmptyColorModifierCallback(int (*funcptr)(c_colormodifier*))
{
alloc_empty_colormodifier_callback = funcptr;
}
void RegisterNewColorModifierCallback(int (*funcptr)(c_colormodifier*, const char*, uint32_t))
{
alloc_colormodifier_callback = funcptr;
}
REG_MACRO(ColorModifier, c_colormodifier*, alloc_colormodifier_buffer_callback)
void RegisterEmptyCreatureCasteCallback(int (*funcptr)(c_creaturecaste*))
{
alloc_empty_creaturecaste_callback = funcptr;
}
void UnregisterEmptyColorModifierCallback()
{
alloc_empty_colormodifier_callback = NULL;
}
void UnregisterNewColorModifierCallback()
{
alloc_colormodifier_callback = NULL;
}
void RegisterNewCreatureCasteCallback(int (*funcptr)(c_creaturecaste*, const char*, const char*, const char*, const char*, uint32_t, uint32_t))
{
alloc_creaturecaste_callback = funcptr;
}
REG_MACRO(CreatureCaste, c_creaturecaste*, alloc_creaturecaste_buffer_callback)
UNREG_MACRO(CreatureCaste, alloc_creaturecaste_buffer_callback)
void UnregisterEmptyCreatureCasteCallback()
{
alloc_empty_creaturecaste_callback = NULL;
}
void UnregisterNewCreatureCasteCallback()
{
alloc_creaturecaste_callback = NULL;
}
void RegisterEmptyCreatureTypeCallback(int (*funcptr)(c_creaturetype*))
{
alloc_empty_creaturetype_callback = funcptr;
}
void RegisterNewCreatureTypeCallback(int (*funcptr)(c_creaturetype*, const char*, uint32_t, uint32_t, uint8_t, uint16_t, uint16_t, uint16_t))
{
alloc_creaturetype_callback = funcptr;
}
REG_MACRO(CreatureType, c_creaturetype*, alloc_creaturetype_buffer_callback)
UNREG_MACRO(CreatureType, alloc_creaturetype_buffer_callback)
void UnregisterEmptyCreatureTypeCallback()
{
alloc_empty_creaturetype_callback = NULL;
}
void UnregisterNewCreatureTypeCallback()
{
alloc_creaturetype_callback = NULL;
}
REG_MACRO(Vein, t_vein*, alloc_vein_buffer_callback)
REG_MACRO(FrozenLiquidVein, t_frozenliquidvein*, alloc_frozenliquidvein_buffer_callback)
REG_MACRO(SpatterVein, t_spattervein*, alloc_spattervein_buffer_callback)
UNREG_MACRO(Vein, alloc_vein_buffer_callback)
UNREG_MACRO(FrozenLiquidVein, alloc_frozenliquidvein_buffer_callback)
UNREG_MACRO(SpatterVein, alloc_spattervein_buffer_callback)
int DFHack_isWallTerrain(int in) int DFHack_isWallTerrain(int in)
{ {
return DFHack::isWallTerrain(in); return DFHack::isWallTerrain(in);
@ -143,7 +276,7 @@ int CreatureCasteConvert(t_creaturecaste* src, c_creaturecaste* dest)
((*alloc_creaturecaste_callback)(dest, src->rawname, src->singular, src->plural, src->adjective, src->ColorModifier.size(), src->bodypart.size())); ((*alloc_creaturecaste_callback)(dest, src->rawname, src->singular, src->plural, src->adjective, src->ColorModifier.size(), src->bodypart.size()));
for(int i = 0; i < dest->colorModifierLength; i++) for(unsigned int i = 0; i < dest->colorModifierLength; i++)
ColorListConvert(&src->ColorModifier[i], &dest->ColorModifier[i]); ColorListConvert(&src->ColorModifier[i], &dest->ColorModifier[i]);
copy(src->bodypart.begin(), src->bodypart.end(), dest->bodypart); copy(src->bodypart.begin(), src->bodypart.end(), dest->bodypart);
@ -158,7 +291,7 @@ int CreatureTypeConvert(t_creaturetype* src, c_creaturetype* dest)
((*alloc_creaturetype_callback)(dest, src->rawname, src->castes.size(), src->extract.size(), src->tile_character, src->tilecolor.fore, src->tilecolor.back, src->tilecolor.bright)); ((*alloc_creaturetype_callback)(dest, src->rawname, src->castes.size(), src->extract.size(), src->tile_character, src->tilecolor.fore, src->tilecolor.back, src->tilecolor.bright));
for(int i = 0; i < dest->castesCount; i++) for(unsigned int i = 0; i < dest->castesCount; i++)
CreatureCasteConvert(&src->castes[i], &dest->castes[i]); CreatureCasteConvert(&src->castes[i], &dest->castes[i]);
copy(src->extract.begin(), src->extract.end(), dest->extract); copy(src->extract.begin(), src->extract.end(), dest->extract);

@ -0,0 +1,96 @@
/*
www.sourceforge.net/projects/dfhack
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#include "Internal.h"
#include "MicrosoftSTL.h"
#include "dfhack/DFProcess.h"
#include "dfhack/VersionInfo.h"
#include <string>
using namespace DFHack;
void MicrosoftSTL::init(Process* self)
{
p = self;
OffsetGroup * strGrp = p->getDescriptor()->getGroup("string")->getGroup("MSVC");
STLSTR_buf_off = strGrp->getOffset("buffer");
STLSTR_size_off = strGrp->getOffset("size");
STLSTR_cap_off = strGrp->getOffset("capacity");
}
size_t MicrosoftSTL::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
{
uint32_t start_offset = offset + STLSTR_buf_off;
size_t length = p->readDWord(offset + STLSTR_size_off);
size_t capacity = p->readDWord(offset + STLSTR_cap_off);
size_t read_real = min(length, bufcapacity-1);// keep space for null termination
// read data from inside the string structure
if(capacity < 16)
{
p->read(start_offset, read_real , (uint8_t *)buffer);
}
else // read data from what the offset + 4 dword points to
{
start_offset = p->readDWord(start_offset);// dereference the start offset
p->read(start_offset, read_real, (uint8_t *)buffer);
}
buffer[read_real] = 0;
return read_real;
}
const string MicrosoftSTL::readSTLString (uint32_t offset)
{
uint32_t start_offset = offset + STLSTR_buf_off;
size_t length = p->readDWord(offset + STLSTR_size_off);
size_t capacity = p->readDWord(offset + STLSTR_cap_off);
char * temp = new char[capacity+1];
// read data from inside the string structure
if(capacity < 16)
{
p->read(start_offset, capacity, (uint8_t *)temp);
}
else // read data from what the offset + 4 dword points to
{
start_offset = p->readDWord(start_offset);// dereference the start offset
p->read(start_offset, capacity, (uint8_t *)temp);
}
temp[length] = 0;
string ret = temp;
delete temp;
return ret;
}
string MicrosoftSTL::readClassName (uint32_t vptr)
{
int rtti = p->readDWord(vptr - 0x4);
int typeinfo = p->readDWord(rtti + 0xC);
string raw = p->readCString(typeinfo + 0xC); // skips the .?AV
raw.resize(raw.length() - 2);// trim @@ from end
return raw;
}

@ -127,11 +127,11 @@ namespace DFHack
*/ */
namespace DFHack namespace DFHack
{ {
typedef pair <bool, uint32_t> nullableUint32; typedef pair <INVAL_TYPE, uint32_t> nullableUint32;
typedef map <string, nullableUint32 >::iterator uint32_Iter; typedef map <string, nullableUint32 >::iterator uint32_Iter;
typedef pair <bool, int32_t> nullableInt32; typedef pair <INVAL_TYPE, int32_t> nullableInt32;
typedef map <string, nullableInt32 >::iterator int32_Iter; typedef map <string, nullableInt32 >::iterator int32_Iter;
typedef pair <bool, string> nullableString; typedef pair <INVAL_TYPE, string> nullableString;
typedef map <string, nullableString >::iterator strings_Iter; typedef map <string, nullableString >::iterator strings_Iter;
typedef map <string, OffsetGroup *>::iterator groups_Iter; typedef map <string, OffsetGroup *>::iterator groups_Iter;
class OffsetGroupPrivate class OffsetGroupPrivate
@ -149,73 +149,126 @@ namespace DFHack
void OffsetGroup::createOffset(const string & key) void OffsetGroup::createOffset(const string & key)
{ {
OGd->offsets[key] = nullableInt32(false, 0); OGd->offsets[key] = nullableInt32(NOT_SET, 0);
} }
void OffsetGroup::createAddress(const string & key) void OffsetGroup::createAddress(const string & key)
{ {
OGd->addresses[key] = nullableUint32(false, 0); OGd->addresses[key] = nullableUint32(NOT_SET, 0);
} }
void OffsetGroup::createHexValue(const string & key) void OffsetGroup::createHexValue(const string & key)
{ {
OGd->hexvals[key] = nullableUint32(false, 0); OGd->hexvals[key] = nullableUint32(NOT_SET, 0);
} }
void OffsetGroup::createString(const string & key) void OffsetGroup::createString(const string & key)
{ {
OGd->strings[key] = nullableString(false, std::string()); OGd->strings[key] = nullableString(NOT_SET, std::string());
} }
void OffsetGroup::setOffset (const string & key, const string & value) void OffsetGroup::setOffset (const string & key, const string & value, const INVAL_TYPE inval)
{ {
int32_Iter it = OGd->offsets.find(key); int32_Iter it = OGd->offsets.find(key);
if(it != OGd->offsets.end()) if(it != OGd->offsets.end())
{ {
int32_t offset = strtol(value.c_str(), NULL, 16); int32_t offset = strtol(value.c_str(), NULL, 16);
(*it).second.second = offset; (*it).second.second = offset;
(*it).second.first = true; if(inval != NOT_SET)
(*it).second.first = inval;
} }
else throw Error::MissingMemoryDefinition("offset", getFullName() + key); else throw Error::MissingMemoryDefinition("offset", getFullName() + key);
} }
void OffsetGroup::setOffsetValidity (const string & key, const INVAL_TYPE inval)
{
if(inval != NOT_SET)
{
int32_Iter it = OGd->offsets.find(key);
if(it != OGd->offsets.end())
{
(*it).second.first = inval;
}
else throw Error::MissingMemoryDefinition("offset", getFullName() + key);
}
}
void OffsetGroup::setAddress (const string & key, const string & value) void OffsetGroup::setAddress (const string & key, const string & value, const INVAL_TYPE inval)
{ {
uint32_Iter it = OGd->addresses.find(key); uint32_Iter it = OGd->addresses.find(key);
if(it != OGd->addresses.end()) if(it != OGd->addresses.end())
{ {
int32_t address = strtol(value.c_str(), NULL, 16); int32_t address = strtol(value.c_str(), NULL, 16);
(*it).second.second = address; (*it).second.second = address;
(*it).second.first = true; if(inval != NOT_SET)
(*it).second.first = inval;
} }
else throw Error::MissingMemoryDefinition("address", getFullName() + key); else throw Error::MissingMemoryDefinition("address", getFullName() + key);
} }
void OffsetGroup::setAddressValidity (const string & key, const INVAL_TYPE inval)
{
if(inval != NOT_SET)
{
uint32_Iter it = OGd->addresses.find(key);
if(it != OGd->addresses.end())
{
(*it).second.first = inval;
}
else throw Error::MissingMemoryDefinition("address", getFullName() + key);
}
}
void OffsetGroup::setHexValue (const string & key, const string & value)
void OffsetGroup::setHexValue (const string & key, const string & value, const INVAL_TYPE inval)
{ {
uint32_Iter it = OGd->hexvals.find(key); uint32_Iter it = OGd->hexvals.find(key);
if(it != OGd->hexvals.end()) if(it != OGd->hexvals.end())
{ {
(*it).second.second = strtol(value.c_str(), NULL, 16); (*it).second.second = strtol(value.c_str(), NULL, 16);
(*it).second.first = true; if(inval != NOT_SET)
(*it).second.first = inval;
} }
else throw Error::MissingMemoryDefinition("hexvalue", getFullName() + key); else throw Error::MissingMemoryDefinition("hexvalue", getFullName() + key);
} }
void OffsetGroup::setHexValueValidity (const string & key, const INVAL_TYPE inval)
{
if(inval != NOT_SET)
{
uint32_Iter it = OGd->hexvals.find(key);
if(it != OGd->hexvals.end())
{
(*it).second.first = inval;
}
else throw Error::MissingMemoryDefinition("hexvalue", getFullName() + key);
}
}
void OffsetGroup::setString (const string & key, const string & value) void OffsetGroup::setString (const string & key, const string & value, const INVAL_TYPE inval)
{ {
strings_Iter it = OGd->strings.find(key); strings_Iter it = OGd->strings.find(key);
if(it != OGd->strings.end()) if(it != OGd->strings.end())
{ {
(*it).second.second = value; (*it).second.second = value;
(*it).second.first = true; if(inval != NOT_SET)
(*it).second.first = inval;
} }
else throw Error::MissingMemoryDefinition("string", getFullName() + key); else throw Error::MissingMemoryDefinition("string", getFullName() + key);
} }
void OffsetGroup::setStringValidity (const string & key, const INVAL_TYPE inval)
{
if(inval != NOT_SET)
{
strings_Iter it = OGd->strings.find(key);
if(it != OGd->strings.end())
{
(*it).second.first = inval;
}
else throw Error::MissingMemoryDefinition("string", getFullName() + key);
}
}
// Get named address // Get named address
uint32_t OffsetGroup::getAddress (const string & key) uint32_t OffsetGroup::getAddress (const string & key)
@ -224,8 +277,10 @@ uint32_t OffsetGroup::getAddress (const string & key)
if(iter != OGd->addresses.end()) if(iter != OGd->addresses.end())
{ {
if((*iter).second.first) if((*iter).second.first == IS_VALID)
return (*iter).second.second; return (*iter).second.second;
if((*iter).second.first == IS_INVALID)
throw Error::InvalidMemoryDefinition("address", getFullName() + key);
throw Error::UnsetMemoryDefinition("address", getFullName() + key); throw Error::UnsetMemoryDefinition("address", getFullName() + key);
} }
throw Error::MissingMemoryDefinition("address", getFullName() + key); throw Error::MissingMemoryDefinition("address", getFullName() + key);
@ -238,8 +293,10 @@ int32_t OffsetGroup::getOffset (const string & key)
int32_Iter iter = OGd->offsets.find(key); int32_Iter iter = OGd->offsets.find(key);
if(iter != OGd->offsets.end()) if(iter != OGd->offsets.end())
{ {
if((*iter).second.first) if((*iter).second.first == IS_VALID)
return (*iter).second.second; return (*iter).second.second;
if((*iter).second.first == IS_INVALID)
throw Error::InvalidMemoryDefinition("offset", getFullName() + key);
throw Error::UnsetMemoryDefinition("offset", getFullName() + key); throw Error::UnsetMemoryDefinition("offset", getFullName() + key);
} }
throw Error::MissingMemoryDefinition("offset", getFullName() + key); throw Error::MissingMemoryDefinition("offset", getFullName() + key);
@ -252,8 +309,10 @@ uint32_t OffsetGroup::getHexValue (const string & key)
uint32_Iter iter = OGd->hexvals.find(key); uint32_Iter iter = OGd->hexvals.find(key);
if(iter != OGd->hexvals.end()) if(iter != OGd->hexvals.end())
{ {
if((*iter).second.first) if((*iter).second.first == IS_VALID)
return (*iter).second.second; return (*iter).second.second;
if((*iter).second.first == IS_INVALID)
throw Error::InvalidMemoryDefinition("hexvalue", getFullName() + key);
throw Error::UnsetMemoryDefinition("hexvalue", getFullName() + key); throw Error::UnsetMemoryDefinition("hexvalue", getFullName() + key);
} }
throw Error::MissingMemoryDefinition("hexvalue", getFullName() + key); throw Error::MissingMemoryDefinition("hexvalue", getFullName() + key);
@ -265,8 +324,10 @@ std::string OffsetGroup::getString (const string &key)
strings_Iter iter = OGd->strings.find(key); strings_Iter iter = OGd->strings.find(key);
if(iter != OGd->strings.end()) if(iter != OGd->strings.end())
{ {
if((*iter).second.first) if((*iter).second.first == IS_VALID)
return (*iter).second.second; return (*iter).second.second;
if((*iter).second.first == IS_INVALID)
throw Error::InvalidMemoryDefinition("string", getFullName() + key);
throw Error::UnsetMemoryDefinition("string", getFullName() + key); throw Error::UnsetMemoryDefinition("string", getFullName() + key);
} }
throw Error::MissingMemoryDefinition("string", getFullName() + key); throw Error::MissingMemoryDefinition("string", getFullName() + key);
@ -361,6 +422,8 @@ std::string OffsetGroup::PrintOffsets(int indentation)
if((*iter).second.first) if((*iter).second.first)
ss << " value=\"" << hex << "0x" << (*iter).second.second << "\""; ss << " value=\"" << hex << "0x" << (*iter).second.second << "\"";
ss << " />"; ss << " />";
if((*iter).second.first == IS_INVALID)
ss << " INVALID!";
if(!(*iter).second.first) if(!(*iter).second.first)
ss << " MISSING!"; ss << " MISSING!";
ss << endl; ss << endl;
@ -372,6 +435,8 @@ std::string OffsetGroup::PrintOffsets(int indentation)
if((*iter2).second.first) if((*iter2).second.first)
ss << " value=\"" << hex << "0x" << (*iter2).second.second << "\""; ss << " value=\"" << hex << "0x" << (*iter2).second.second << "\"";
ss << " />"; ss << " />";
if((*iter2).second.first == IS_INVALID)
ss << " INVALID!";
if(!(*iter2).second.first) if(!(*iter2).second.first)
ss << " MISSING!"; ss << " MISSING!";
ss << endl; ss << endl;
@ -382,6 +447,8 @@ std::string OffsetGroup::PrintOffsets(int indentation)
if((*iter).second.first) if((*iter).second.first)
ss << " value=\"" << hex << "0x" << (*iter).second.second << "\""; ss << " value=\"" << hex << "0x" << (*iter).second.second << "\"";
ss << " />"; ss << " />";
if((*iter).second.first == IS_INVALID)
ss << " INVALID!";
if(!(*iter).second.first) if(!(*iter).second.first)
ss << " MISSING!"; ss << " MISSING!";
ss << endl; ss << endl;
@ -393,6 +460,8 @@ std::string OffsetGroup::PrintOffsets(int indentation)
if((*iter3).second.first) if((*iter3).second.first)
ss << " value=\"" << (*iter3).second.second << "\""; ss << " value=\"" << (*iter3).second.second << "\"";
ss << " />"; ss << " />";
if((*iter3).second.first == IS_INVALID)
ss << " INVALID!";
if(!(*iter3).second.first) if(!(*iter3).second.first)
ss << " MISSING!"; ss << " MISSING!";
ss << endl; ss << endl;
@ -409,6 +478,42 @@ std::string OffsetGroup::PrintOffsets(int indentation)
return ss.str(); return ss.str();
} }
// the big ugly method behind the curtain...
void OffsetGroup::setInvalid(INVAL_TYPE invalidity)
{
if(invalidity == NOT_SET)
return;
uint32_Iter iter;
for(iter = OGd->addresses.begin(); iter != OGd->addresses.end(); iter++)
{
if((*iter).second.first)
(*iter).second.first = invalidity;
}
int32_Iter iter2;
for(iter2 = OGd->offsets.begin(); iter2 != OGd->offsets.end(); iter2++)
{
if((*iter2).second.first)
(*iter2).second.first = invalidity;
}
for(iter = OGd->hexvals.begin(); iter != OGd->hexvals.end(); iter++)
{
if((*iter).second.first)
(*iter).second.first = invalidity;
}
strings_Iter iter3;
for(iter3 = OGd->strings.begin(); iter3 != OGd->strings.end(); iter3++)
{
if((*iter3).second.first)
(*iter3).second.first = invalidity;
}
groups_Iter iter4;
for(iter4 = OGd->groups.begin(); iter4 != OGd->groups.end(); iter4++)
{
(*iter4).second->setInvalid(invalidity);
}
}
/* /*
* Private data * Private data
*/ */
@ -440,7 +545,7 @@ namespace DFHack
Process * p; // the process this belongs to Process * p; // the process this belongs to
string version; string version;
VersionInfo::OSType OS; OSType OS;
std::string md5; std::string md5;
uint32_t PE_timestamp; uint32_t PE_timestamp;
}; };
@ -602,7 +707,7 @@ void VersionInfo::setOS(OSType os)
} }
VersionInfo::OSType VersionInfo::getOS() const OSType VersionInfo::getOS() const
{ {
return d->OS; return d->OS;
} }

@ -31,6 +31,65 @@ distribution.
using namespace DFHack; using namespace DFHack;
template<class _T1, class _T2, class _T3>
struct triple
{
typedef _T1 first_type;
typedef _T2 second_type;
typedef _T3 third_type;
_T1 first;
_T2 second;
_T3 third;
triple() : first(), second(), third() { }
triple(const _T1& __a, const _T2& __b, const _T3& __c) : first(__a), second(__b), third(__c) { }
template<class _U1, class _U2, class _U3>
triple(const triple<_U1, _U2, _U3>& __p) : first(__p.first), second(__p.second), third(__p.third) { }
};
template<class _T1, class _T2, class _T3>
inline bool operator==(const triple<_T1, _T2, _T3>& __x, const triple<_T1, _T2, _T3>& __y)
{
return __x.first == __y.first && __x.second == __y.second && __x.third == __y.third;
}
template<class _T1, class _T2, class _T3>
inline bool operator<(const triple<_T1, _T2, _T3>& __x, const triple<_T1, _T2, _T3>& __y)
{
return
__x.first < __y.first ||
(!(__y.first < __x.first) && __x.second < __y.second) ||
(!(__y.first < __x.first) && !(__x.second < __y.second) && (__x.third < __y.third));
}
template<class _T1, class _T2, class _T3>
inline bool operator!=(const triple<_T1, _T2, _T3>& __x, const triple<_T1, _T2, _T3>& __y)
{
return !(__x == __y);
}
template<class _T1, class _T2, class _T3>
inline bool operator>(const triple<_T1, _T2, _T3>& __x, const triple<_T1, _T2, _T3>& __y)
{
return __y < __x;
}
template<class _T1, class _T2, class _T3>
inline bool operator<=(const triple<_T1, _T2, _T3>& __x, const triple<_T1, _T2, _T3>& __y)
{
return !(__y < __x);
}
template<class _T1, class _T2, class _T3>
inline bool operator>=(const triple<_T1, _T2, _T3>& __x, const triple<_T1, _T2, _T3>& __y)
{
return !(__x < __y);
}
VersionInfoFactory::~VersionInfoFactory() VersionInfoFactory::~VersionInfoFactory()
{ {
// for each stored version, delete // for each stored version, delete
@ -95,35 +154,54 @@ void VersionInfoFactory::ParseVTable(TiXmlElement* vtable, VersionInfo* mem)
} }
} }
// FIXME: this is ripe for replacement with a more generic approach struct breadcrumb
{
TiXmlElement * first;
OffsetGroup * second;
};
void VersionInfoFactory::ParseOffsets(TiXmlElement * parent, VersionInfo* target, bool initial) void VersionInfoFactory::ParseOffsets(TiXmlElement * parent, VersionInfo* target, bool initial)
{ {
// we parse the groups iteratively instead of recursively // we parse the groups iteratively instead of recursively
// breadcrubs acts like a makeshift stack // breadcrubs acts like a makeshift stack
// first pair entry stores the current element of that level // first pair entry stores the current element of that level
// second pair entry the group object from OffsetGroup // second pair entry the group object from OffsetGroup
typedef pair < TiXmlElement *, OffsetGroup * > groupPair; typedef triple< TiXmlElement *, OffsetGroup *, INVAL_TYPE> groupTriple;
vector< groupPair > breadcrumbs; vector< groupTriple > breadcrumbs;
{ {
TiXmlElement* pEntry; TiXmlElement* pEntry;
// we get the <Offsets>, look at the children // we get the <Offsets>, look at the children
pEntry = parent->FirstChildElement(); pEntry = parent->FirstChildElement();
const char *cstr_invalid = parent->Attribute("valid");
INVAL_TYPE parent_inval = NOT_SET;
if(cstr_invalid)
{
if(strcmp(cstr_invalid,"false") == 0)
parent_inval = IS_INVALID;
else if(strcmp(cstr_invalid,"true") == 0)
parent_inval = IS_VALID;
}
OffsetGroup * currentGroup = reinterpret_cast<OffsetGroup *> (target);
currentGroup->setInvalid(parent_inval);
// we end here if there are no child tags.
if(!pEntry) if(!pEntry)
return; return;
OffsetGroup * currentGroup = reinterpret_cast<OffsetGroup *> (target); breadcrumbs.push_back(groupTriple(pEntry,currentGroup, parent_inval));
breadcrumbs.push_back(groupPair(pEntry,currentGroup));
} }
// work variables // work variables
OffsetGroup * currentGroup = 0; OffsetGroup * currentGroup = 0;
TiXmlElement * currentElem = 0; TiXmlElement * currentElem = 0;
INVAL_TYPE parent_inval = NOT_SET;
//cerr << "<Offsets>"<< endl; //cerr << "<Offsets>"<< endl;
while(1) while(1)
{ {
// get current work variables // get current work variables
currentElem = breadcrumbs.back().first; currentElem = breadcrumbs.back().first;
currentGroup = breadcrumbs.back().second; currentGroup = breadcrumbs.back().second;
parent_inval = breadcrumbs.back().third;
// we reached the end of the current group? // we reached the end of the current group?
if(!currentElem) if(!currentElem)
@ -144,7 +222,7 @@ void VersionInfoFactory::ParseOffsets(TiXmlElement * parent, VersionInfo* target
if(!currentGroup) if(!currentGroup)
{ {
groupPair & gp = breadcrumbs.back(); groupTriple & gp = breadcrumbs.back();
gp.first = gp.first->NextSiblingElement(); gp.first = gp.first->NextSiblingElement();
continue; continue;
} }
@ -152,7 +230,7 @@ void VersionInfoFactory::ParseOffsets(TiXmlElement * parent, VersionInfo* target
// skip non-elements // skip non-elements
if (currentElem->Type() != TiXmlNode::ELEMENT) if (currentElem->Type() != TiXmlNode::ELEMENT)
{ {
groupPair & gp = breadcrumbs.back(); groupTriple & gp = breadcrumbs.back();
gp.first = gp.first->NextSiblingElement(); gp.first = gp.first->NextSiblingElement();
continue; continue;
} }
@ -169,18 +247,27 @@ void VersionInfoFactory::ParseOffsets(TiXmlElement * parent, VersionInfo* target
// evaluate elements // evaluate elements
const char *cstr_value = currentElem->Attribute("value"); const char *cstr_value = currentElem->Attribute("value");
const char *cstr_invalid = currentElem->Attribute("valid");
INVAL_TYPE child_inval = parent_inval;
if(cstr_invalid)
{
if(strcmp(cstr_invalid,"false") == 0)
child_inval = IS_INVALID;
else if(strcmp(cstr_invalid,"true") == 0)
child_inval = IS_VALID;
}
if(type == "group") if(type == "group")
{ {
// FIXME: possibly use setGroup always, with the initial flag as parameter?
// create or get group // create or get group
OffsetGroup * og; OffsetGroup * og;
if(initial) if(initial)
og = currentGroup->createGroup(cstr_name); og = currentGroup->createGroup(cstr_name);
else else
og = currentGroup->getGroup(cstr_name); og = currentGroup->getGroup(cstr_name);
//cerr << "<group name=\"" << cstr_name << "\">" << endl;
// advance this level to the next element // advance this level to the next element
groupPair & gp = breadcrumbs.back(); groupTriple & gp = breadcrumbs.back();
gp.first = currentElem->NextSiblingElement(); gp.first = currentElem->NextSiblingElement();
if(!og) if(!og)
@ -189,73 +276,82 @@ void VersionInfoFactory::ParseOffsets(TiXmlElement * parent, VersionInfo* target
throw Error::MissingMemoryDefinition("group", fullname); throw Error::MissingMemoryDefinition("group", fullname);
} }
// add a new level that will be processed next // add a new level that will be processed in the next step
breadcrumbs.push_back(groupPair(currentElem->FirstChildElement(), og)); breadcrumbs.push_back(groupTriple(currentElem->FirstChildElement(), og, child_inval));
og->setInvalid(child_inval);
continue; continue;
} }
else if(type == "address") else if(type == "address")
{ {
if(child_inval == NOT_SET)
child_inval = IS_VALID;
if(initial) if(initial)
{ {
currentGroup->createAddress(cstr_name); currentGroup->createAddress(cstr_name);
} }
else if(cstr_value) else if(cstr_value)
{ {
currentGroup->setAddress(cstr_name, cstr_value); currentGroup->setAddress(cstr_name, cstr_value, child_inval);
} }
else else
{ {
// ERROR, missing attribute currentGroup->setAddressValidity(cstr_name, child_inval);
} }
} }
else if(type == "offset") else if(type == "offset")
{ {
if(child_inval == NOT_SET)
child_inval = IS_VALID;
if(initial) if(initial)
{ {
currentGroup->createOffset(cstr_name); currentGroup->createOffset(cstr_name);
} }
else if(cstr_value) else if(cstr_value)
{ {
currentGroup->setOffset(cstr_name, cstr_value); currentGroup->setOffset(cstr_name, cstr_value, child_inval);
} }
else else
{ {
// ERROR, missing attribute currentGroup->setOffsetValidity(cstr_name, child_inval);
} }
} }
else if(type == "string") else if(type == "string")
{ {
if(child_inval == NOT_SET)
child_inval = IS_VALID;
if(initial) if(initial)
{ {
currentGroup->createString(cstr_name); currentGroup->createString(cstr_name);
} }
else if(cstr_value) else if(cstr_value)
{ {
currentGroup->setString(cstr_name, cstr_value); currentGroup->setString(cstr_name, cstr_value, child_inval);
} }
else else
{ {
// ERROR, missing attribute currentGroup->setStringValidity(cstr_name, child_inval);
} }
} }
else if(type == "hexvalue") else if(type == "hexvalue")
{ {
if(child_inval == NOT_SET)
child_inval = IS_VALID;
if(initial) if(initial)
{ {
currentGroup->createHexValue(cstr_name); currentGroup->createHexValue(cstr_name);
} }
else if(cstr_value) else if(cstr_value)
{ {
currentGroup->setHexValue(cstr_name, cstr_value); currentGroup->setHexValue(cstr_name, cstr_value, child_inval);
} }
else else
{ {
// ERROR, missing attribute currentGroup->setHexValueValidity(cstr_name, child_inval);
} }
} }
// advance to next element // advance to next element
groupPair & gp = breadcrumbs.back(); groupTriple & gp = breadcrumbs.back();
gp.first = currentElem->NextSiblingElement(); gp.first = currentElem->NextSiblingElement();
continue; continue;
} }
@ -272,7 +368,7 @@ void VersionInfoFactory::ParseBase (TiXmlElement* entry, VersionInfo* mem)
throw Error::MemoryXmlBadAttribute("name"); throw Error::MemoryXmlBadAttribute("name");
mem->setVersion(cstr_version); mem->setVersion(cstr_version);
mem->setOS(VersionInfo::OS_BAD); mem->setOS(OS_BAD);
// process additional entries // process additional entries
pElement = entry->FirstChildElement()->ToElement(); pElement = entry->FirstChildElement()->ToElement();
@ -590,7 +686,6 @@ bool VersionInfoFactory::loadFile(string path_to_xml)
if(name) if(name)
{ {
string str_name = name; string str_name = name;
VersionInfo *base = new VersionInfo();
mem = new VersionInfo(); mem = new VersionInfo();
ParseBase( pMemInfo , mem ); ParseBase( pMemInfo , mem );
knownVersions[str_name] = v_descr (pMemInfo, mem); knownVersions[str_name] = v_descr (pMemInfo, mem);

Binary file not shown.

@ -25,6 +25,8 @@ distribution.
#ifndef DFHACK_C_API #ifndef DFHACK_C_API
#define DFHACK_C_API #define DFHACK_C_API
#include "dfhack/DFPragma.h"
#include <cstdio> #include <cstdio>
#include <string> #include <string>
#include <vector> #include <vector>

@ -32,6 +32,11 @@ distribution.
#include "dfhack/modules/Position.h" #include "dfhack/modules/Position.h"
#include "dfhack/DFTileTypes.h" #include "dfhack/DFTileTypes.h"
#define HBUILD(a) a ## BufferCallback
#define HREG_MACRO(type_name, type) DFHACK_EXPORT void HBUILD(Register ## type_name) (int (*funcptr)(type, uint32_t));
#define HUNREG_MACRO(type_name) DFHACK_EXPORT void HBUILD(Unregister ## type_name) ();
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -54,6 +59,41 @@ DFHACK_EXPORT extern int (*alloc_t_feature_buffer_callback)(t_feature*, uint32_t
DFHACK_EXPORT extern int (*alloc_t_hotkey_buffer_callback)(t_hotkey*, uint32_t); DFHACK_EXPORT extern int (*alloc_t_hotkey_buffer_callback)(t_hotkey*, uint32_t);
DFHACK_EXPORT extern int (*alloc_t_screen_buffer_callback)(t_screen*, uint32_t); DFHACK_EXPORT extern int (*alloc_t_screen_buffer_callback)(t_screen*, uint32_t);
DFHACK_EXPORT void RegisterByteBufferCallback(int (*funcptr)(int8_t*, uint32_t));
DFHACK_EXPORT void RegisterShortBufferCallback(int (*funcptr)(int16_t*, uint32_t));
DFHACK_EXPORT void RegisterIntBufferCallback(int (*funcptr)(int32_t*, uint32_t));
DFHACK_EXPORT void RegisterUByteBufferCallback(int (*funcptr)(uint8_t*, uint32_t));
DFHACK_EXPORT void RegisterUShortBufferCallback(int (*funcptr)(uint16_t*, uint32_t));
DFHACK_EXPORT void RegisterUIntBufferCallback(int (*funcptr)(uint32_t*, uint32_t));
DFHACK_EXPORT void RegisterCharBufferCallback(int (*funcptr)(char*, uint32_t));
DFHACK_EXPORT void RegisterMatglossBufferCallback(int (*funcptr)(t_matgloss*, uint32_t));
DFHACK_EXPORT void RegisterDescriptorColorBufferCallback(int (*funcptr)(t_descriptor_color*, uint32_t));
DFHACK_EXPORT void RegisterMatglossOtherBufferCallback(int (*funcptr)(t_matglossOther*, uint32_t));
DFHACK_EXPORT void RegisterFeatureBufferCallback(int (*funcptr)(t_feature*, uint32_t));
DFHACK_EXPORT void RegisterHotkeyBufferCallback(int (*funcptr)(t_hotkey*, uint32_t));
DFHACK_EXPORT void RegisterScreenBufferCallback(int (*funcptr)(t_screen*, uint32_t));
HUNREG_MACRO(Byte)
HUNREG_MACRO(Short)
HUNREG_MACRO(Int)
HUNREG_MACRO(UByte)
HUNREG_MACRO(UShort)
HUNREG_MACRO(UInt)
HUNREG_MACRO(Char)
HUNREG_MACRO(Matgloss)
HUNREG_MACRO(DescriptorColor)
HUNREG_MACRO(MatglossOther)
HUNREG_MACRO(Feature)
HUNREG_MACRO(Hotkey)
HUNREG_MACRO(Screen)
struct t_customWorkshop struct t_customWorkshop
{ {
uint32_t index; uint32_t index;
@ -61,9 +101,14 @@ struct t_customWorkshop
}; };
DFHACK_EXPORT extern int (*alloc_t_customWorkshop_buffer_callback)(t_customWorkshop*, uint32_t); DFHACK_EXPORT extern int (*alloc_t_customWorkshop_buffer_callback)(t_customWorkshop*, uint32_t);
DFHACK_EXPORT extern int (*alloc_t_material_buffer_callback)(t_material*, uint32_t); DFHACK_EXPORT extern int (*alloc_t_material_buffer_callback)(t_material*, uint32_t);
DFHACK_EXPORT void RegisterCustomWorkshopBufferCallback(int (*funcptr)(t_customWorkshop*, uint32_t));
DFHACK_EXPORT void RegisterMaterialBufferCallback(int (*funcptr)(t_material*, uint32_t));
HUNREG_MACRO(CustomWorkshop)
HUNREG_MACRO(Material)
struct c_colormodifier struct c_colormodifier
{ {
char part[128]; char part[128];
@ -75,6 +120,14 @@ DFHACK_EXPORT extern int (*alloc_empty_colormodifier_callback)(c_colormodifier*)
DFHACK_EXPORT extern int (*alloc_colormodifier_callback)(c_colormodifier*, const char*, uint32_t); DFHACK_EXPORT extern int (*alloc_colormodifier_callback)(c_colormodifier*, const char*, uint32_t);
DFHACK_EXPORT extern int (*alloc_colormodifier_buffer_callback)(c_colormodifier*, uint32_t); DFHACK_EXPORT extern int (*alloc_colormodifier_buffer_callback)(c_colormodifier*, uint32_t);
DFHACK_EXPORT void RegisterEmptyColorModifierCallback(int (*funcptr)(c_colormodifier*));
DFHACK_EXPORT void RegisterNewColorModifierCallback(int (*funcptr)(c_colormodifier*, const char*, uint32_t));
DFHACK_EXPORT void RegisterColorModifierBufferCallback(int (*funcptr)(c_colormodifier*, uint32_t));
DFHACK_EXPORT void UnregisterEmptyColorModifierCallback();
DFHACK_EXPORT void UnregisterNewColorModifierCallback();
HUNREG_MACRO(ColorModifier)
struct c_creaturecaste struct c_creaturecaste
{ {
char rawname[128]; char rawname[128];
@ -93,6 +146,14 @@ DFHACK_EXPORT extern int (*alloc_empty_creaturecaste_callback)(c_creaturecaste*)
DFHACK_EXPORT extern int (*alloc_creaturecaste_callback)(c_creaturecaste*, const char*, const char*, const char*, const char*, uint32_t, uint32_t); DFHACK_EXPORT extern int (*alloc_creaturecaste_callback)(c_creaturecaste*, const char*, const char*, const char*, const char*, uint32_t, uint32_t);
DFHACK_EXPORT extern int (*alloc_creaturecaste_buffer_callback)(c_creaturecaste*, uint32_t); DFHACK_EXPORT extern int (*alloc_creaturecaste_buffer_callback)(c_creaturecaste*, uint32_t);
DFHACK_EXPORT void RegisterEmptyCreatureCasteCallback(int (*funcptr)(c_creaturecaste*));
DFHACK_EXPORT void RegisterNewCreatureCasteCallback(int (*funcptr)(c_creaturecaste*, const char*, const char*, const char*, const char*, uint32_t, uint32_t));
DFHACK_EXPORT void RegisterCreatureCasteBufferCallback(int (*funcptr)(c_creaturecaste*, uint32_t));
DFHACK_EXPORT void UnregisterEmptyCreatureCasteCallback();
DFHACK_EXPORT void UnregisterNewCreatureCasteCallback();
HUNREG_MACRO(CreatureCaste)
struct c_creaturetype struct c_creaturetype
{ {
char rawname[128]; char rawname[128];
@ -121,14 +182,30 @@ DFHACK_EXPORT extern int (*alloc_vein_buffer_callback)(t_vein*, uint32_t);
DFHACK_EXPORT extern int (*alloc_frozenliquidvein_buffer_callback)(t_frozenliquidvein*, uint32_t); DFHACK_EXPORT extern int (*alloc_frozenliquidvein_buffer_callback)(t_frozenliquidvein*, uint32_t);
DFHACK_EXPORT extern int (*alloc_spattervein_buffer_callback)(t_spattervein*, uint32_t); DFHACK_EXPORT extern int (*alloc_spattervein_buffer_callback)(t_spattervein*, uint32_t);
DFHACK_EXPORT extern int DFHack_isWallTerrain(int in); DFHACK_EXPORT void RegisterEmptyCreatureTypeCallback(int (*funcptr)(c_creaturetype*));
DFHACK_EXPORT extern int DFHack_isFloorTerrain(int in); DFHACK_EXPORT void RegisterNewCreatureTypeCallback(int (*funcptr)(c_creaturetype*, const char*, uint32_t, uint32_t, uint8_t, uint16_t, uint16_t, uint16_t));
DFHACK_EXPORT extern int DFHack_isRampTerrain(int in); DFHACK_EXPORT void RegisterCreatureTypeBufferCallback(int (*funcptr)(c_creaturetype*, uint32_t));
DFHACK_EXPORT extern int DFHack_isStairTerrain(int in);
DFHACK_EXPORT extern int DFHack_isOpenTerrain(int in); DFHACK_EXPORT void RegisterVeinBufferCallback(int (*funcptr)(t_vein*, uint32_t));
DFHACK_EXPORT extern int DFHack_getVegetationType(int in); DFHACK_EXPORT void RegisterFrozenLiquidVeinBufferCallback(int (*funcptr)(t_frozenliquidvein*, uint32_t));
DFHACK_EXPORT void RegisterSpatterVeinBufferCallback(int (*funcptr)(t_spattervein*, uint32_t));
DFHACK_EXPORT void UnregisterEmptyCreatureTypeCallback();
DFHACK_EXPORT void UnregisterNewCreatureTypeCallback();
HUNREG_MACRO(CreatureType)
HUNREG_MACRO(Vein)
HUNREG_MACRO(FrozenLiquidVein)
HUNREG_MACRO(SpatterVein)
DFHACK_EXPORT int DFHack_isWallTerrain(int in);
DFHACK_EXPORT int DFHack_isFloorTerrain(int in);
DFHACK_EXPORT int DFHack_isRampTerrain(int in);
DFHACK_EXPORT int DFHack_isStairTerrain(int in);
DFHACK_EXPORT int DFHack_isOpenTerrain(int in);
DFHACK_EXPORT int DFHack_getVegetationType(int in);
DFHACK_EXPORT extern int DFHack_getTileType(int index, TileRow* tPtr); DFHACK_EXPORT int DFHack_getTileType(int index, TileRow* tPtr);
#ifdef __cplusplus #ifdef __cplusplus
} }

@ -45,6 +45,9 @@ DFHACK_EXPORT int32_t Creatures_ReadCreatureInBox(DFHackObject* cPtr, const int3
DFHACK_EXPORT int Creatures_ReadCreature(DFHackObject* cPtr, const int32_t index, t_creature* furball); DFHACK_EXPORT int Creatures_ReadCreature(DFHackObject* cPtr, const int32_t index, t_creature* furball);
DFHACK_EXPORT t_material* Creatures_ReadJob(DFHackObject* cPtr, const t_creature* furball); DFHACK_EXPORT t_material* Creatures_ReadJob(DFHackObject* cPtr, const t_creature* furball);
DFHACK_EXPORT uint32_t* Creatures_ReadInventoryIdx(DFHackObject* cPtr, const uint32_t index);
DFHACK_EXPORT uint32_t* Creatures_ReadInventoryPtr(DFHackObject* cPtr, const uint32_t index);
DFHACK_EXPORT uint32_t Creatures_GetDwarfRaceIndex(DFHackObject* cPtr); DFHACK_EXPORT uint32_t Creatures_GetDwarfRaceIndex(DFHackObject* cPtr);
DFHACK_EXPORT int32_t Creatures_GetDwarfCivId(DFHackObject* cPtr); DFHACK_EXPORT int32_t Creatures_GetDwarfCivId(DFHackObject* cPtr);

@ -37,6 +37,7 @@ DFHACK_EXPORT int Gui_Start(DFHackObject* gui);
DFHACK_EXPORT int Gui_Finish(DFHackObject* gui); DFHACK_EXPORT int Gui_Finish(DFHackObject* gui);
DFHACK_EXPORT int Gui_ReadPauseState(DFHackObject* gui); DFHACK_EXPORT int Gui_ReadPauseState(DFHackObject* gui);
DFHACK_EXPORT int Gui_SetPauseState(DFHackObject* gui, int8_t paused);
DFHACK_EXPORT int Gui_ReadViewScreen(DFHackObject* gui, t_viewscreen* viewscreen); DFHACK_EXPORT int Gui_ReadViewScreen(DFHackObject* gui, t_viewscreen* viewscreen);
DFHACK_EXPORT int Gui_ReadMenuState(DFHackObject* gui, uint32_t* menuState); DFHACK_EXPORT int Gui_ReadMenuState(DFHackObject* gui, uint32_t* menuState);

@ -36,6 +36,8 @@ extern "C" {
DFHACK_EXPORT int Maps_Start(DFHackObject* maps); DFHACK_EXPORT int Maps_Start(DFHackObject* maps);
DFHACK_EXPORT int Maps_Finish(DFHackObject* maps); DFHACK_EXPORT int Maps_Finish(DFHackObject* maps);
DFHACK_EXPORT uint16_t* Maps_ReadGeology(DFHackObject* maps);
DFHACK_EXPORT t_feature* Maps_ReadGlobalFeatures(DFHackObject* maps); DFHACK_EXPORT t_feature* Maps_ReadGlobalFeatures(DFHackObject* maps);
DFHACK_EXPORT void Maps_getSize(DFHackObject* maps, uint32_t* x, uint32_t* y, uint32_t* z); DFHACK_EXPORT void Maps_getSize(DFHackObject* maps, uint32_t* x, uint32_t* y, uint32_t* z);

@ -26,6 +26,7 @@ distribution.
#define ERROR_H_INCLUDED #define ERROR_H_INCLUDED
#include "DFExport.h" #include "DFExport.h"
#include "DFPragma.h"
#include <string> #include <string>
#include <sstream> #include <sstream>
#include <exception> #include <exception>
@ -39,6 +40,7 @@ namespace DFHack
* the whole array of DFHack exceptions from the rest * the whole array of DFHack exceptions from the rest
*/ */
class DFHACK_EXPORT All : public std::exception{}; class DFHACK_EXPORT All : public std::exception{};
class DFHACK_EXPORT AllMemdef : public All{};
class DFHACK_EXPORT NoProcess : public All class DFHACK_EXPORT NoProcess : public All
{ {
public: public:
@ -80,7 +82,7 @@ namespace DFHack
}; };
// a call to DFHack::mem_info::get* failed // a call to DFHack::mem_info::get* failed
class DFHACK_EXPORT MissingMemoryDefinition : public All class DFHACK_EXPORT MissingMemoryDefinition : public AllMemdef
{ {
public: public:
MissingMemoryDefinition(const char* _type, const std::string _key) : type(_type), key(_key) MissingMemoryDefinition(const char* _type, const std::string _key) : type(_type), key(_key)
@ -113,7 +115,7 @@ namespace DFHack
}; };
// a call to DFHack::mem_info::get* failed // a call to DFHack::mem_info::get* failed
class DFHACK_EXPORT UnsetMemoryDefinition : public All class DFHACK_EXPORT UnsetMemoryDefinition : public AllMemdef
{ {
public: public:
UnsetMemoryDefinition(const char* _type, const std::string _key) : type(_type), key(_key) UnsetMemoryDefinition(const char* _type, const std::string _key) : type(_type), key(_key)
@ -145,7 +147,41 @@ namespace DFHack
} }
}; };
// Syntax errors and whatnot, the xml cant be read // a call to DFHack::mem_info::get* failed
class DFHACK_EXPORT InvalidMemoryDefinition : public AllMemdef
{
public:
InvalidMemoryDefinition(const char* _type, const std::string _key) : type(_type), key(_key)
{
std::stringstream s;
s << "memory object is INVALID: type " << type << " key " << key;
full = s.str();
}
// Used by functios using integer keys, such as getTrait
InvalidMemoryDefinition(const char* _type, uint32_t _key) : type(_type)
{
std::stringstream s1;
s1 << _key;
key = s1.str();
std::stringstream s;
s << "memory object is INVALID: type " << type << " key " << key;
full = s.str();
}
virtual ~InvalidMemoryDefinition() throw(){};
std::string full;
const std::string type;
std::string key;
virtual const char* what() const throw()
{
return full.c_str();
}
};
// Syntax errors and whatnot, the xml can't be read
class DFHACK_EXPORT MemoryXmlParse : public All class DFHACK_EXPORT MemoryXmlParse : public All
{ {
public: public:
@ -157,13 +193,11 @@ namespace DFHack
full = s.str(); full = s.str();
} }
std::string full; std::string full;
const std::string desc; const std::string desc;
const int id; const int id;
const int row; const int row;
const int col; const int col;
virtual ~MemoryXmlParse() throw(){}; virtual ~MemoryXmlParse() throw(){};
virtual const char* what() const throw() virtual const char* what() const throw()

@ -7,8 +7,18 @@
#ifdef _MSC_VER #ifdef _MSC_VER
// don't spew nonsense // don't spew nonsense
#pragma warning( disable: 4251 ) #pragma warning( disable: 4251 )
// don't display bogus 'deprecation' and 'unsafe' warnings // don't display bogus 'deprecation' and 'unsafe' warnings.
// See the idiocy: http://msdn.microsoft.com/en-us/magazine/cc163794.aspx
#define _CRT_SECURE_NO_DEPRECATE
#define _SCL_SECURE_NO_DEPRECATE
#pragma warning( disable: 4996 ) #pragma warning( disable: 4996 )
// Let me demonstrate:
/**
* [peterix@peterix dfhack]$ man wcscpy_s
* No manual entry for wcscpy_s
*
* Proprietary extensions.
*/
// disable stupid // disable stupid
#pragma warning( disable: 4800 ) #pragma warning( disable: 4800 )
// disable more stupid // disable more stupid

@ -72,6 +72,7 @@ namespace DFHack
if (address >= start && address <= end) return true; if (address >= start && address <= end) return true;
return false; return false;
} }
bool valid;
uint8_t * buffer; uint8_t * buffer;
}; };
@ -98,33 +99,33 @@ namespace DFHack
virtual bool forceresume() = 0; virtual bool forceresume() = 0;
/// read a 8-byte integer /// read a 8-byte integer
virtual uint64_t readQuad(const uint32_t address) = 0; uint64_t readQuad(const uint32_t address) { uint64_t result; readQuad(address, result); return result; }
/// read a 8-byte integer /// read a 8-byte integer
virtual void readQuad(const uint32_t address, uint64_t & value) = 0; virtual void readQuad(const uint32_t address, uint64_t & value) = 0;
/// write a 8-byte integer /// write a 8-byte integer
virtual void writeQuad(const uint32_t address, const uint64_t value) = 0; virtual void writeQuad(const uint32_t address, const uint64_t value) = 0;
/// read a 4-byte integer /// read a 4-byte integer
virtual uint32_t readDWord(const uint32_t address) = 0; uint32_t readDWord(const uint32_t address) { uint32_t result; readDWord(address, result); return result; }
/// read a 4-byte integer /// read a 4-byte integer
virtual void readDWord(const uint32_t address, uint32_t & value) = 0; virtual void readDWord(const uint32_t address, uint32_t & value) = 0;
/// write a 4-byte integer /// write a 4-byte integer
virtual void writeDWord(const uint32_t address, const uint32_t value) = 0; virtual void writeDWord(const uint32_t address, const uint32_t value) = 0;
/// read a float /// read a float
virtual float readFloat(const uint32_t address) = 0; float readFloat(const uint32_t address) { float result; readFloat(address, result); return result; }
/// write a float /// write a float
virtual void readFloat(const uint32_t address, float & value) = 0; virtual void readFloat(const uint32_t address, float & value) = 0;
/// read a 2-byte integer /// read a 2-byte integer
virtual uint16_t readWord(const uint32_t address) = 0; uint16_t readWord(const uint32_t address) { uint16_t result; readWord(address, result); return result; }
/// read a 2-byte integer /// read a 2-byte integer
virtual void readWord(const uint32_t address, uint16_t & value) = 0; virtual void readWord(const uint32_t address, uint16_t & value) = 0;
/// write a 2-byte integer /// write a 2-byte integer
virtual void writeWord(const uint32_t address, const uint16_t value) = 0; virtual void writeWord(const uint32_t address, const uint16_t value) = 0;
/// read a byte /// read a byte
virtual uint8_t readByte(const uint32_t address) = 0; uint8_t readByte(const uint32_t address) { uint8_t result; readByte(address, result); return result; }
/// read a byte /// read a byte
virtual void readByte(const uint32_t address, uint8_t & value) = 0; virtual void readByte(const uint32_t address, uint8_t & value) = 0;
/// write a byte /// write a byte
@ -163,6 +164,8 @@ namespace DFHack
virtual VersionInfo *getDescriptor() = 0; virtual VersionInfo *getDescriptor() = 0;
/// get the DF Process ID /// get the DF Process ID
virtual int getPID() = 0; virtual int getPID() = 0;
/// get the DF Process FilePath
virtual std::string getPath() = 0;
/// get module index by name and version. bool 1 = error /// get module index by name and version. bool 1 = error
virtual bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) = 0; virtual bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) = 0;
/// get the SHM start if available /// get the SHM start if available
@ -171,200 +174,5 @@ namespace DFHack
virtual bool SetAndWait (uint32_t state) = 0; virtual bool SetAndWait (uint32_t state) = 0;
}; };
////////////////////////////////////////////////////////////////////////////
// Compiler appeasement area. Not worth a look really... //
////////////////////////////////////////////////////////////////////////////
class DFHACK_EXPORT NormalProcess : virtual public Process
{
friend class ProcessEnumerator;
class Private;
private:
Private * const d;
public:
NormalProcess(uint32_t pid, std::vector <VersionInfo *> & known_versions);
~NormalProcess();
bool attach();
bool detach();
bool suspend();
bool asyncSuspend();
bool resume();
bool forceresume();
uint64_t readQuad(const uint32_t address);
void readQuad(const uint32_t address, uint64_t & value);
void writeQuad(const uint32_t address, const uint64_t value);
uint32_t readDWord(const uint32_t address);
void readDWord(const uint32_t address, uint32_t & value);
void writeDWord(const uint32_t address, const uint32_t value);
float readFloat(const uint32_t address);
void readFloat(const uint32_t address, float & value);
uint16_t readWord(const uint32_t address);
void readWord(const uint32_t address, uint16_t & value);
void writeWord(const uint32_t address, const uint16_t value);
uint8_t readByte(const uint32_t address);
void readByte(const uint32_t address, uint8_t & value);
void writeByte(const uint32_t address, const uint8_t value);
void read( uint32_t address, uint32_t length, uint8_t* buffer);
void write(uint32_t address, uint32_t length, uint8_t* buffer);
const std::string readSTLString (uint32_t offset);
size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity);
void writeSTLString(const uint32_t address, const std::string writeString){};
// get class name of an object with rtti/type info
std::string readClassName(uint32_t vptr);
const std::string readCString (uint32_t offset);
bool isSuspended();
bool isAttached();
bool isIdentified();
bool getThreadIDs(std::vector<uint32_t> & threads );
void getMemRanges(std::vector<t_memrange> & ranges );
VersionInfo *getDescriptor();
int getPID();
// get module index by name and version. bool 1 = error
bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) { OUTPUT=0; return false;};
// get the SHM start if available
char * getSHMStart (void){return 0;};
// set a SHM command and wait for a response
bool SetAndWait (uint32_t state){return false;};
};
class DFHACK_EXPORT SHMProcess : virtual public Process
{
friend class ProcessEnumerator;
class Private;
private:
Private * const d;
public:
SHMProcess(uint32_t PID, std::vector <VersionInfo *> & known_versions);
~SHMProcess();
// Set up stuff so we can read memory
bool attach();
bool detach();
bool suspend();
bool asyncSuspend();
bool resume();
bool forceresume();
uint64_t readQuad(const uint32_t address);
void readQuad(const uint32_t address, uint64_t & value);
void writeQuad(const uint32_t address, const uint64_t value);
uint32_t readDWord(const uint32_t address);
void readDWord(const uint32_t address, uint32_t & value);
void writeDWord(const uint32_t address, const uint32_t value);
float readFloat(const uint32_t address);
void readFloat(const uint32_t address, float & value);
uint16_t readWord(const uint32_t address);
void readWord(const uint32_t address, uint16_t & value);
void writeWord(const uint32_t address, const uint16_t value);
uint8_t readByte(const uint32_t address);
void readByte(const uint32_t address, uint8_t & value);
void writeByte(const uint32_t address, const uint8_t value);
void read( uint32_t address, uint32_t length, uint8_t* buffer);
void write(uint32_t address, uint32_t length, uint8_t* buffer);
const std::string readSTLString (uint32_t offset);
size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity);
void writeSTLString(const uint32_t address, const std::string writeString);
// get class name of an object with rtti/type info
std::string readClassName(uint32_t vptr);
const std::string readCString (uint32_t offset);
bool isSuspended();
bool isAttached();
bool isIdentified();
bool getThreadIDs(std::vector<uint32_t> & threads );
void getMemRanges(std::vector<t_memrange> & ranges );
VersionInfo *getDescriptor();
int getPID();
// get module index by name and version. bool 1 = error
bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT);
// get the SHM start if available
char * getSHMStart (void);
bool SetAndWait (uint32_t state);
};
#ifdef LINUX_BUILD
class DFHACK_EXPORT WineProcess : virtual public Process
{
friend class ProcessEnumerator;
class Private;
private:
Private * const d;
public:
WineProcess(uint32_t pid, std::vector <VersionInfo *> & known_versions);
~WineProcess();
bool attach();
bool detach();
bool suspend();
bool asyncSuspend();
bool resume();
bool forceresume();
uint64_t readQuad(const uint32_t address);
void readQuad(const uint32_t address, uint64_t & value);
void writeQuad(const uint32_t address, const uint64_t value);
uint32_t readDWord(const uint32_t address);
void readDWord(const uint32_t address, uint32_t & value);
void writeDWord(const uint32_t address, const uint32_t value);
float readFloat(const uint32_t address);
void readFloat(const uint32_t address, float & value);
uint16_t readWord(const uint32_t address);
void readWord(const uint32_t address, uint16_t & value);
void writeWord(const uint32_t address, const uint16_t value);
uint8_t readByte(const uint32_t address);
void readByte(const uint32_t address, uint8_t & value);
void writeByte(const uint32_t address, const uint8_t value);
void read( uint32_t address, uint32_t length, uint8_t* buffer);
void write(uint32_t address, uint32_t length, uint8_t* buffer);
const std::string readSTLString (uint32_t offset);
size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity);
void writeSTLString(const uint32_t address, const std::string writeString){};
// get class name of an object with rtti/type info
std::string readClassName(uint32_t vptr);
const std::string readCString (uint32_t offset);
bool isSuspended();
bool isAttached();
bool isIdentified();
bool getThreadIDs(std::vector<uint32_t> & threads );
void getMemRanges(std::vector<t_memrange> & ranges );
VersionInfo *getDescriptor();
int getPID();
// get module index by name and version. bool 1 = error
bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) {OUTPUT=0; return false;};
// get the SHM start if available
char * getSHMStart (void){return 0;};
bool SetAndWait (uint32_t state){return false;};
};
#endif
} }
#endif #endif

@ -26,66 +26,216 @@ distribution.
#define TILETYPES_H_INCLUDED #define TILETYPES_H_INCLUDED
#include "DFPragma.h" #include "DFPragma.h"
#include "DFExport.h"
namespace DFHack namespace DFHack
{ {
// tile class -- determines the general shape of the tile // tile class -- determines the general shape of the tile
enum TileClass // enum and lookup table for string names created using X macros
{ #define TILECLASS_MACRO \
EMPTY,// empty X(EMPTY, "") \
X(WALL, "") \
WALL, X(PILLAR, "") \
PILLAR, X(FORTIFICATION, "") \
FORTIFICATION, X(STAIR_UP, "") \
X(STAIR_DOWN, "") \
STAIR_UP, X(STAIR_UPDOWN, "") \
STAIR_DOWN, X(RAMP, "ramps have no direction" ) \
STAIR_UPDOWN, X(RAMP_TOP, "used for pathing?" ) \
X(FLOOR, "") \
RAMP,// ramps have no direction X(TREE_DEAD, "") \
RAMP_TOP,// the top of a ramp. I assume it's used for path finding. X(TREE_OK, "") \
X(SAPLING_DEAD, "") \
FLOOR,// generic floor X(SAPLING_OK, "") \
TREE_DEAD, X(SHRUB_DEAD, "") \
TREE_OK, X(SHRUB_OK, "") \
SAPLING_DEAD, X(BOULDER, "") \
SAPLING_OK, X(PEBBLES, "")
SHRUB_DEAD, //end TILECLASS_MACRO
SHRUB_OK,
BOULDER, //define tile class enum
PEBBLES #define X(name,comment) name,
enum TileClass {
tileclass_invalid=-1,
TILECLASS_MACRO
tileclass_count,
}; };
// material -- what material the tile is made of #undef X
enum TileMaterial
{ DFHACK_EXPORT extern const char *TileClassString[];
AIR,// empty
SOIL,// ordinary soil. material depends on geology #define TILEMATERIAL_MACRO \
STONE,// ordinary layer stone. material depends on geology X(AIR, "empty" ) \
FEATSTONE,// map feature stone. used for things like hell, the hell temple or adamantine tubes. material depends on local/global feature X(SOIL, "ordinary soil. material depends on geology" ) \
OBSIDIAN,// cast obsidian X(STONE, "ordinary layer stone. material depends on geology" ) \
X(FEATSTONE, "map special stone. used for things like hell, the hell temple or adamantine tubes. material depends on local/global special" ) \
VEIN,// vein stone. material depends on mineral veins present X(OBSIDIAN, "cast obsidian" ) \
ICE,// frozen water... not much to say. you can determine what was on the tile before it froze by looking into the 'ice vein' objects X(VEIN, "vein stone. material depends on mineral veins present" ) \
GRASS,// grass (has 4 variants) X(ICE, "frozen water... not much to say. you can determine what was on the tile before it froze by looking into the 'ice vein' objects" ) \
GRASS2,// grass (has 4 variants) X(GRASS, "grass (has 4 variants)" ) \
GRASS_DEAD,// dead grass (has 4 variants) X(GRASS2, "grass (has 4 variants)" ) \
GRASS_DRY,// dry grass (has 4 variants) X(GRASS_DEAD, "dead grass (has 4 variants)" ) \
DRIFTWOOD,// non-specified wood - normally on top of the local layer stone/soil. X(GRASS_DRY, "dry grass (has 4 variants)" ) \
HFS,// the stuff demon pits are made of - this makes them different from ordinary pits. X(DRIFTWOOD, "non-specified wood - normally on top of the local layer stone/soil." ) \
MAGMA,// material for semi-molten rock and 'magma flow' tiles X(HFS, "the stuff demon pits are made of - this makes them different from ordinary pits." ) \
CAMPFIRE,// human armies make them when they siege. The original tile may be lost? X(MAGMA, "material for semi-molten rock and 'magma flow' tiles" ) \
FIRE,// burning grass X(CAMPFIRE, "human armies make them when they siege. The original tile may be lost?" ) \
ASHES,// what remains from a FIRE X(FIRE, "burning grass" ) \
CONSTRUCTED,// tile material depends on the construction present X(ASHES, "what remains from a FIRE" ) \
CYAN_GLOW// the glowy stuff that disappears from the demon temple when you take the sword. X(CONSTRUCTED,"tile material depends on the construction present" ) \
X(CYAN_GLOW, "the glowy stuff that disappears from the demon temple when you take the sword." )
//end TILEMATERIAL_MACRO
// material enum
#define X(name,comment) name,
enum TileMaterial {
tilematerial_invalid=-1,
TILEMATERIAL_MACRO
tilematerial_count,
};
#undef X
DFHACK_EXPORT extern const char *TileMaterialString[];
// Special specials of the tile.
// Not the best way to do this, but compatible with existing code.
// When the TileType class gets created, everything should be re-thought.
#define TILESPECIAL_MACRO \
X(NORMAL, "Default for all type, nothing present" ) \
X(SPECIAL, "General purpose, for any unique tile which can not otherwise be differenciated" ) \
X(POOL, "Murky Pool, will gather water from rain" ) \
X(STREAM, "Streams (and brooks too? maybe?)" ) \
X(STREAM_TOP, "The walkable surface of a stream/brook" ) \
X(RIVER_SOURCE, "Rivers Source, when it exists on a map" ) \
X(RIVER, "Rivers, and their entering and exiting tiles" ) \
X(WATERFALL, "Special case for Waterfall Landing. How's this used?" ) \
X(ENDLESS, "Eerie Pit and Old Chasm/Endless Pit" ) \
X(CRACKED, "Walls being dug" ) \
X(DAMAGED, "Walls being dug" ) \
X(WORN, "Walls being dug ??" ) \
X(SMOOTH, "Walls and floors." )
//end TILESPECIAL_MACRO
//special enum
#define X(name,comment) TILE_##name,
enum TileSpecial {
tilespecial_invalid=-1,
TILESPECIAL_MACRO
tilespecial_count,
}; };
#undef X
DFHACK_EXPORT extern const char *TileSpecialString[];
// variants are used for tiles, where there are multiple variants of the same - like grass floors // variants are used for tiles, where there are multiple variants of the same - like grass floors
enum TileVariant enum TileVariant
{ {
VAR_1, tilevariant_invalid=-1,
VAR_1, //Yes, the value of VAR_1 is 0. It's legacy. Deal with it.
VAR_2, VAR_2,
VAR_3, VAR_3,
VAR_4 VAR_4,
};
//Mainly walls and rivers
//Byte values are used because walls can have either 1 or 2 in any given direction.
const int TileDirectionCount = 4;
union TileDirection
{
uint32_t whole;
unsigned char b[TileDirectionCount];
struct
{
//Maybe should add 'up' and 'down' for Z-levels?
unsigned char north,south,west,east;
};
inline TileDirection()
{
whole = 0;
}
TileDirection( uint32_t whole_bits)
{
whole = whole_bits;
}
TileDirection( unsigned char North, unsigned char South, unsigned char West, unsigned char East )
{
north=North; south=South; east=East; west=West;
}
TileDirection( const char *dir )
{
//This one just made for fun.
//Supports N S E W
const char *p = dir;
unsigned char *l=0;
north=south=east=west=0;
if(!dir) return;
for( ;*p;++p)
{
switch(*p)
{
case 'N': //North / Up
case 'n':
++north; l=&north; break;
case 'S': //South / Down
case 's':
++south; l=&south; break;
case 'E': //East / Right
case 'e':
++east; l=&east; break;
case 'W': //West / Left
case 'w':
++west; l=&west; break;
case '-':
case ' ':
//Explicitly ensure dash and space are ignored.
//Other characters/symbols may be assigned in the future.
break;
default:
if( l && '0' <= *p && '9' >= *p )
*l += *p - '0';
break;
}
}
}
//may be useful for some situations
inline uint32_t sum() const
{
return 0L + north + south + east + west;
}
//Gives a string that represents the direction.
//This is a static string, overwritten with every call!
//Support values > 2 even though they should never happen.
//Copy string if it will be used.
inline char * getStr() const
{
static char str[16];
//type punning trick
*( (uint64_t *)str ) = *( (uint64_t *)"--------" );
str[8]=0;
#define DIRECTION(x,i,c) \
if(x){ \
str[i]=c; \
if(1==x) ; \
else if(2==x) str[i+1]=c; \
else str[i+1]='0'+x; \
}
DIRECTION(north,0,'N')
DIRECTION(south,2,'S')
DIRECTION(west,4,'W')
DIRECTION(east,6,'E')
#undef DIRECTION
return str;
}
}; };
struct TileRow struct TileRow
@ -94,16 +244,18 @@ namespace DFHack
TileClass c; TileClass c;
TileMaterial m; TileMaterial m;
TileVariant v; TileVariant v;
TileSpecial s;
TileDirection d;
}; };
#define TILE_TYPE_ARRAY_LENGTH 520 #define TILE_TYPE_ARRAY_LENGTH 520
const TileRow tileTypeTable[TILE_TYPE_ARRAY_LENGTH] = const TileRow tileTypeTable[TILE_TYPE_ARRAY_LENGTH] =
{ {
// 0 // 0
{"void",EMPTY, AIR, VAR_1}, {"void",EMPTY, AIR, VAR_1},
{"ramp top",RAMP_TOP, AIR, VAR_1}, {"ramp top",RAMP_TOP, AIR, VAR_1},
{"pool",FLOOR, SOIL, VAR_1}, {"pool",FLOOR, SOIL, VAR_1, TILE_POOL},
{0, EMPTY, AIR, VAR_1}, {0, EMPTY, AIR, VAR_1},
{0, EMPTY, AIR, VAR_1}, {0, EMPTY, AIR, VAR_1},
{0, EMPTY, AIR, VAR_1}, {0, EMPTY, AIR, VAR_1},
@ -142,7 +294,7 @@ namespace DFHack
{"empty space",EMPTY, AIR, VAR_1}, {"empty space",EMPTY, AIR, VAR_1},
{0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1},
{"shrub",SHRUB_OK, SOIL, VAR_1}, {"shrub",SHRUB_OK, SOIL, VAR_1},
{"chasm",FLOOR, AIR, VAR_1}, {"chasm",FLOOR, AIR, VAR_1, TILE_ENDLESS },
{"obsidian stair up/down",STAIR_UPDOWN, OBSIDIAN, VAR_1}, {"obsidian stair up/down",STAIR_UPDOWN, OBSIDIAN, VAR_1},
{"obsidian stair down",STAIR_DOWN, OBSIDIAN, VAR_1}, {"obsidian stair down",STAIR_DOWN, OBSIDIAN, VAR_1},
{"obsidian stair up",STAIR_UP, OBSIDIAN, VAR_1}, {"obsidian stair up",STAIR_UP, OBSIDIAN, VAR_1},
@ -151,12 +303,12 @@ namespace DFHack
// 40 // 40
{"soil stair down",STAIR_DOWN, SOIL, VAR_1}, {"soil stair down",STAIR_DOWN, SOIL, VAR_1},
{"soil stair up",STAIR_UP, SOIL, VAR_1}, {"soil stair up",STAIR_UP, SOIL, VAR_1},
{"eerie pit",FLOOR, HFS, VAR_1}, {"eerie pit",FLOOR, HFS, VAR_1, TILE_ENDLESS},
{"smooth stone floor",FLOOR, STONE, VAR_1}, {"smooth stone floor",FLOOR, STONE, VAR_1 , TILE_SMOOTH },
{"smooth obsidian floor",FLOOR, OBSIDIAN, VAR_1}, {"smooth obsidian floor",FLOOR, OBSIDIAN, VAR_1 , TILE_SMOOTH },
{"smooth featstone? floor",FLOOR, FEATSTONE, VAR_1}, {"smooth featstone? floor",FLOOR, FEATSTONE, VAR_1 , TILE_SMOOTH },
{"smooth vein floor",FLOOR, VEIN, VAR_1}, {"smooth vein floor",FLOOR, VEIN, VAR_1 , TILE_SMOOTH },
{"smooth ice floor",FLOOR, ICE, VAR_1}, {"smooth ice floor",FLOOR, ICE, VAR_1 , TILE_SMOOTH },
{0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1},
{"grass stair up/down",STAIR_UPDOWN, GRASS, VAR_1}, {"grass stair up/down",STAIR_UPDOWN, GRASS, VAR_1},
@ -206,10 +358,10 @@ namespace DFHack
{0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1},
{0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1},
{0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1},
{"waterfall landing",FLOOR, SOIL, VAR_1}, // verify material {"waterfall landing",FLOOR, SOIL, VAR_1, TILE_WATERFALL }, // verify material
// 90 // 90
{"river source",FLOOR, SOIL, VAR_1}, // verify material {"river source",FLOOR, SOIL, VAR_1, TILE_RIVER_SOURCE }, // verify material
{0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1},
{0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1},
{0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1},
@ -311,9 +463,9 @@ namespace DFHack
{0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1},
{0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1},
{0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1},
{"cracked stone wall" ,WALL, STONE, VAR_1}, {"cracked stone wall" ,WALL, STONE, VAR_1, TILE_CRACKED },
{"damaged stone wall" ,WALL, STONE, VAR_1}, {"damaged stone wall" ,WALL, STONE, VAR_1, TILE_DAMAGED },
{"worn stone wall" ,WALL, STONE, VAR_1}, {"worn stone wall" ,WALL, STONE, VAR_1, TILE_WORN },
{0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1},
// 180 // 180
@ -422,79 +574,79 @@ namespace DFHack
{0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1},
{"glowing floor" ,FLOOR, CYAN_GLOW, VAR_1}, {"glowing floor" ,FLOOR, CYAN_GLOW, VAR_1},
{0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1},
{"smooth obsidian wall RD2",WALL,OBSIDIAN,VAR_1}, {"smooth obsidian wall RD2",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "--SS--E-" },
// 270 // 270
{"smooth obsidian wall R2D",WALL,OBSIDIAN,VAR_1}, {"smooth obsidian wall R2D",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "--S---EE" },
{"smooth obsidian wall R2U",WALL,OBSIDIAN,VAR_1}, {"smooth obsidian wall R2U",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "N-----EE" },
{"smooth obsidian wall RU2",WALL,OBSIDIAN,VAR_1}, {"smooth obsidian wall RU2",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "NN----E-" },
{"smooth obsidian wall L2U",WALL,OBSIDIAN,VAR_1}, {"smooth obsidian wall L2U",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "N---WW--" },
{"smooth obsidian wall LU2",WALL,OBSIDIAN,VAR_1}, {"smooth obsidian wall LU2",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "NN--W---" },
{"smooth obsidian wall L2D",WALL,OBSIDIAN,VAR_1}, {"smooth obsidian wall L2D",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "--S-WW--" },
{"smooth obsidian wall LD2",WALL,OBSIDIAN,VAR_1}, {"smooth obsidian wall LD2",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "--SSW---" },
{"smooth obsidian wall LRUD",WALL,OBSIDIAN,VAR_1}, {"smooth obsidian wall LRUD",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH ,"N-S-W-E-" },
{"smooth obsidian wall RUD",WALL,OBSIDIAN,VAR_1}, {"smooth obsidian wall RUD",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "N-S---E-" },
{"smooth obsidian wall LRD",WALL,OBSIDIAN,VAR_1}, {"smooth obsidian wall LRD",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "--S-W-E-" },
// 280 // 280
{"smooth obsidian wall LRU",WALL,OBSIDIAN,VAR_1}, {"smooth obsidian wall LRU",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "N---W-E-" },
{"smooth obsidian wall LUD",WALL,OBSIDIAN,VAR_1}, {"smooth obsidian wall LUD",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "N-S-W---" },
{"smooth obsidian wall RD",WALL,OBSIDIAN,VAR_1}, {"smooth obsidian wall RD",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "--S---E-" },
{"smooth obsidian wall RU",WALL,OBSIDIAN,VAR_1}, {"smooth obsidian wall RU",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "N-----E-" },
{"smooth obsidian wall LU",WALL,OBSIDIAN,VAR_1}, {"smooth obsidian wall LU",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "N---W---" },
{"smooth obsidian wall LD",WALL,OBSIDIAN,VAR_1}, {"smooth obsidian wall LD",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "--S-W---" },
{"smooth obsidian wall UD",WALL,OBSIDIAN,VAR_1}, {"smooth obsidian wall UD",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "N-S-----" },
{"smooth obsidian wall LR",WALL,OBSIDIAN,VAR_1}, {"smooth obsidian wall LR",WALL,OBSIDIAN,VAR_1 , TILE_SMOOTH , "----W-E-" },
{"smooth featstone wall RD2",WALL,FEATSTONE,VAR_1}, {"smooth featstone wall RD2",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "--SS--E-" },
{"smooth featstone wall R2D",WALL,FEATSTONE,VAR_1}, {"smooth featstone wall R2D",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "--S---EE" },
// 290 // 290
{"smooth featstone wall R2U",WALL,FEATSTONE,VAR_1}, {"smooth featstone wall R2U",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "N-----EE" },
{"smooth featstone wall RU2",WALL,FEATSTONE,VAR_1}, {"smooth featstone wall RU2",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "NN----E-" },
{"smooth featstone wall L2U",WALL,FEATSTONE,VAR_1}, {"smooth featstone wall L2U",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "N---WW--" },
{"smooth featstone wall LU2",WALL,FEATSTONE,VAR_1}, {"smooth featstone wall LU2",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "NN--W---" },
{"smooth featstone wall L2D",WALL,FEATSTONE,VAR_1}, {"smooth featstone wall L2D",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "--S-WW--" },
{"smooth featstone wall LD2",WALL,FEATSTONE,VAR_1}, {"smooth featstone wall LD2",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "--SSW---" },
{"smooth featstone wall LRUD",WALL,FEATSTONE,VAR_1}, {"smooth featstone wall LRUD",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH ,"N-S-W-E-" },
{"smooth featstone wall RUD",WALL,FEATSTONE,VAR_1}, {"smooth featstone wall RUD",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "N-S---E-" },
{"smooth featstone wall LRD",WALL,FEATSTONE,VAR_1}, {"smooth featstone wall LRD",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "--S-W-E-" },
{"smooth featstone wall LRU",WALL,FEATSTONE,VAR_1}, {"smooth featstone wall LRU",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "N---W-E-" },
//300 //300
{"smooth featstone wall LUD",WALL,FEATSTONE,VAR_1}, {"smooth featstone wall LUD",WALL,FEATSTONE,VAR_1, TILE_SMOOTH , "N-S-W---" },
{"smooth featstone wall RD",WALL,FEATSTONE,VAR_1}, {"smooth featstone wall RD",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "--S---E-" },
{"smooth featstone wall RU",WALL,FEATSTONE,VAR_1}, {"smooth featstone wall RU",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "N-----E-" },
{"smooth featstone wall LU",WALL,FEATSTONE,VAR_1}, {"smooth featstone wall LU",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "N---W---" },
{"smooth featstone wall LD",WALL,FEATSTONE,VAR_1}, {"smooth featstone wall LD",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "--S-W---" },
{"smooth featstone wall UD",WALL,FEATSTONE,VAR_1}, {"smooth featstone wall UD",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "N-S-----" },
{"smooth featstone wall LR",WALL,FEATSTONE,VAR_1}, {"smooth featstone wall LR",WALL,FEATSTONE,VAR_1 , TILE_SMOOTH , "----W-E-" },
{"smooth stone wall RD2",WALL,STONE,VAR_1}, {"smooth stone wall RD2",WALL,STONE,VAR_1 , TILE_SMOOTH , "--SS--E-" },
{"smooth stone wall R2D",WALL,STONE,VAR_1}, {"smooth stone wall R2D",WALL,STONE,VAR_1 , TILE_SMOOTH , "--S---EE" },
{"smooth stone wall R2U",WALL,STONE,VAR_1}, {"smooth stone wall R2U",WALL,STONE,VAR_1 , TILE_SMOOTH , "N-----EE" },
//310 //310
{"smooth stone wall RU2",WALL,STONE,VAR_1}, {"smooth stone wall RU2",WALL,STONE,VAR_1 , TILE_SMOOTH , "NN----E-" },
{"smooth stone wall L2U",WALL,STONE,VAR_1}, {"smooth stone wall L2U",WALL,STONE,VAR_1 , TILE_SMOOTH , "N---WW--" },
{"smooth stone wall LU2",WALL,STONE,VAR_1}, {"smooth stone wall LU2",WALL,STONE,VAR_1 , TILE_SMOOTH , "NN--W---" },
{"smooth stone wall L2D",WALL,STONE,VAR_1}, {"smooth stone wall L2D",WALL,STONE,VAR_1 , TILE_SMOOTH , "--S-WW--" },
{"smooth stone wall LD2",WALL,STONE,VAR_1}, {"smooth stone wall LD2",WALL,STONE,VAR_1 , TILE_SMOOTH , "--SSW---" },
{"smooth stone wall LRUD",WALL,STONE,VAR_1}, {"smooth stone wall LRUD",WALL,STONE,VAR_1 , TILE_SMOOTH , "N-S-W-E-" },
{"smooth stone wall RUD",WALL,STONE,VAR_1}, {"smooth stone wall RUD",WALL,STONE,VAR_1 , TILE_SMOOTH , "N-S---E-" },
{"smooth stone wall LRD",WALL,STONE,VAR_1}, {"smooth stone wall LRD",WALL,STONE,VAR_1 , TILE_SMOOTH , "--S-W-E-" },
{"smooth stone wall LRU",WALL,STONE,VAR_1}, {"smooth stone wall LRU",WALL,STONE,VAR_1 , TILE_SMOOTH , "N---W-E-" },
{"smooth stone wall LUD",WALL,STONE,VAR_1}, {"smooth stone wall LUD",WALL,STONE,VAR_1 , TILE_SMOOTH , "N-S-W---" },
//320 //320
{"smooth stone wall RD",WALL,STONE,VAR_1}, {"smooth stone wall RD",WALL,STONE,VAR_1 , TILE_SMOOTH , "--S---E-" },
{"smooth stone wall RU",WALL,STONE,VAR_1}, {"smooth stone wall RU",WALL,STONE,VAR_1 , TILE_SMOOTH , "N-----E-" },
{"smooth stone wall LU",WALL,STONE,VAR_1}, {"smooth stone wall LU",WALL,STONE,VAR_1 , TILE_SMOOTH , "N---W---" },
{"smooth stone wall LD",WALL,STONE,VAR_1}, {"smooth stone wall LD",WALL,STONE,VAR_1 , TILE_SMOOTH , "--S-W---" },
{"smooth stone wall UD",WALL,STONE,VAR_1}, {"smooth stone wall UD",WALL,STONE,VAR_1 , TILE_SMOOTH , "N-S-----" },
{"smooth stone wall LR",WALL,STONE,VAR_1}, {"smooth stone wall LR",WALL,STONE,VAR_1 , TILE_SMOOTH , "----W-E-" },
{"obsidian fortification",FORTIFICATION,OBSIDIAN,VAR_1}, {"obsidian fortification",FORTIFICATION,OBSIDIAN,VAR_1},
{"featstone? fortification",FORTIFICATION,FEATSTONE,VAR_1}, {"featstone? fortification",FORTIFICATION,FEATSTONE,VAR_1},
{"cracked obsidian wall",WALL,OBSIDIAN,VAR_1}, {"cracked obsidian wall",WALL,OBSIDIAN,VAR_1, TILE_CRACKED },
{"damaged obsidian wall",WALL,OBSIDIAN,VAR_1}, {"damaged obsidian wall",WALL,OBSIDIAN,VAR_1, TILE_DAMAGED },
// 330 // 330
{"worn obsidian wall",WALL,OBSIDIAN,VAR_1}, {"worn obsidian wall",WALL,OBSIDIAN,VAR_1},
@ -503,9 +655,9 @@ namespace DFHack
MAPTILE_FEATSTONE_WALL_WORN2, MAPTILE_FEATSTONE_WALL_WORN2,
MAPTILE_FEATSTONE_WALL_WORN3, MAPTILE_FEATSTONE_WALL_WORN3,
MAPTILE_FEATSTONE_WALL,*/ MAPTILE_FEATSTONE_WALL,*/
{"cracked featstone wall",WALL,STONE,VAR_1}, {"cracked featstone wall",WALL,STONE,VAR_1, TILE_CRACKED },
{"damaged featstone wall",WALL,STONE,VAR_1}, {"damaged featstone wall",WALL,STONE,VAR_1, TILE_DAMAGED },
{"worn featstone wall",WALL,STONE,VAR_1}, {"worn featstone wall",WALL,STONE,VAR_1, TILE_WORN },
{"featstone wall",WALL,STONE,VAR_1}, {"featstone wall",WALL,STONE,VAR_1},
{"stone floor",FLOOR,STONE,VAR_1}, {"stone floor",FLOOR,STONE,VAR_1},
{"stone floor",FLOOR,STONE,VAR_2}, {"stone floor",FLOOR,STONE,VAR_2},
@ -538,31 +690,31 @@ namespace DFHack
// 360 // 360
{"ice fortification",FORTIFICATION,ICE,VAR_1}, {"ice fortification",FORTIFICATION,ICE,VAR_1},
{"cracked ice wall",WALL,ICE,VAR_1}, {"cracked ice wall",WALL,ICE,VAR_1, TILE_CRACKED},
{"damaged ice wall",WALL,ICE,VAR_1}, {"damaged ice wall",WALL,ICE,VAR_1, TILE_DAMAGED},
{"worn ice wall",WALL,ICE,VAR_1}, {"worn ice wall",WALL,ICE,VAR_1, TILE_WORN },
{"ice wall",WALL,ICE,VAR_1}, {"ice wall",WALL,ICE,VAR_1},
{"river N",FLOOR,SOIL,VAR_1}, {"river N",FLOOR,SOIL,VAR_1, TILE_RIVER , "N" },
{"river S",FLOOR,SOIL,VAR_1}, {"river S",FLOOR,SOIL,VAR_1, TILE_RIVER , "S" },
{"river E",FLOOR,SOIL,VAR_1}, {"river E",FLOOR,SOIL,VAR_1, TILE_RIVER , "E" },
{"river W",FLOOR,SOIL,VAR_1}, {"river W",FLOOR,SOIL,VAR_1, TILE_RIVER , "W" },
{"river NW",FLOOR,SOIL,VAR_1}, {"river NW",FLOOR,SOIL,VAR_1, TILE_RIVER, "NW"},
//370 //370
{"river NE",FLOOR,SOIL,VAR_1}, {"river NE",FLOOR,SOIL,VAR_1, TILE_RIVER , "NE" },
{"river SW",FLOOR,SOIL,VAR_1}, {"river SW",FLOOR,SOIL,VAR_1, TILE_RIVER , "SW" },
{"river SE",FLOOR,SOIL,VAR_1}, {"river SE",FLOOR,SOIL,VAR_1, TILE_RIVER , "SE" },
{"stream bed N",FLOOR,SOIL,VAR_1}, {"stream bed N",FLOOR,SOIL,VAR_1, TILE_STREAM , "N" },
{"stream bed S",FLOOR,SOIL,VAR_1}, {"stream bed S",FLOOR,SOIL,VAR_1, TILE_STREAM , "S" },
{"stream bed E",FLOOR,SOIL,VAR_1}, {"stream bed E",FLOOR,SOIL,VAR_1, TILE_STREAM , "E" },
{"stream bed W",FLOOR,SOIL,VAR_1}, {"stream bed W",FLOOR,SOIL,VAR_1, TILE_STREAM , "W" },
{"stream bed NW",FLOOR,SOIL,VAR_1}, {"stream bed NW",FLOOR,SOIL,VAR_1, TILE_STREAM, "NW" },
{"stream bed NE",FLOOR,SOIL,VAR_1}, {"stream bed NE",FLOOR,SOIL,VAR_1, TILE_STREAM, "NE" },
{"stream bed SW",FLOOR,SOIL,VAR_1}, {"stream bed SW",FLOOR,SOIL,VAR_1, TILE_STREAM, "SW" },
// 380 // 380
{"stream bed SE",FLOOR,SOIL,VAR_1}, {"stream bed SE",FLOOR,SOIL,VAR_1, TILE_STREAM, "SE" },
{"stream top",FLOOR,SOIL,VAR_1}, {"stream top",FLOOR,SOIL,VAR_1, TILE_STREAM_TOP },
{0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1},
{0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1},
{0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1},
@ -604,33 +756,33 @@ namespace DFHack
{"featstone? pebbles",PEBBLES,FEATSTONE,VAR_2}, {"featstone? pebbles",PEBBLES,FEATSTONE,VAR_2},
{"featstone? pebbles",PEBBLES,FEATSTONE,VAR_3}, {"featstone? pebbles",PEBBLES,FEATSTONE,VAR_3},
{"featstone? pebbles",PEBBLES,FEATSTONE,VAR_4}, {"featstone? pebbles",PEBBLES,FEATSTONE,VAR_4},
{"smooth vein wall",WALL,VEIN,VAR_1}, {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "--SS--E-"},
{"smooth vein wall",WALL,VEIN,VAR_1}, {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "--S---EE"},
{"smooth vein wall",WALL,VEIN,VAR_1}, {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N-----EE" },
// 420 // 420
{"smooth vein wall",WALL,VEIN,VAR_1}, {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "NN----E-"},
{"smooth vein wall",WALL,VEIN,VAR_1}, {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N---WW--"},
{"smooth vein wall",WALL,VEIN,VAR_1}, {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "NN--W---"},
{"smooth vein wall",WALL,VEIN,VAR_1}, {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "--S-WW--" },
{"smooth vein wall",WALL,VEIN,VAR_1}, {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "--SSW---"},
{"smooth vein wall",WALL,VEIN,VAR_1}, {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N-S-W-E-"},
{"smooth vein wall",WALL,VEIN,VAR_1}, {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N-S---E-"},
{"smooth vein wall",WALL,VEIN,VAR_1}, {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "--S-W-E-"},
{"smooth vein wall",WALL,VEIN,VAR_1}, {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N---W-E-"},
{"smooth vein wall",WALL,VEIN,VAR_1}, {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N-S-W---"},
// 430 // 430
{"smooth vein wall",WALL,VEIN,VAR_1}, {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "--S---E-"},
{"smooth vein wall",WALL,VEIN,VAR_1}, {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N-----E-"},
{"smooth vein wall",WALL,VEIN,VAR_1}, {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N---W---"},
{"smooth vein wall",WALL,VEIN,VAR_1}, {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "--S-W---"},
{"smooth vein wall",WALL,VEIN,VAR_1}, {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "N-S-----"},
{"smooth vein wall",WALL,VEIN,VAR_1}, {"smooth vein wall",WALL,VEIN,VAR_1 , TILE_SMOOTH , "----W-E-"},
{"vein fortification",FORTIFICATION,VEIN,VAR_1}, {"vein fortification",FORTIFICATION,VEIN,VAR_1},
{"cracked vein wall",WALL,VEIN,VAR_1}, {"cracked vein wall",WALL,VEIN,VAR_1, TILE_CRACKED },
{"damaged vein wall",WALL,VEIN,VAR_1}, {"damaged vein wall",WALL,VEIN,VAR_1, TILE_DAMAGED },
{"worn vein wall",WALL,VEIN,VAR_1}, {"worn vein wall",WALL,VEIN,VAR_1 , TILE_WORN },
// 440 // 440
{"vein wall",WALL,VEIN,VAR_1}, {"vein wall",WALL,VEIN,VAR_1},
@ -645,27 +797,27 @@ namespace DFHack
{"vein pebbles",PEBBLES,VEIN,VAR_4}, {"vein pebbles",PEBBLES,VEIN,VAR_4},
// 450 // 450
{"smooth ice wall",WALL,ICE,VAR_1}, {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "--SS--E-"},
{"smooth ice wall",WALL,ICE,VAR_1}, {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "--S---EE" },
{"smooth ice wall",WALL,ICE,VAR_1}, {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N-----EE" },
{"smooth ice wall",WALL,ICE,VAR_1}, {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "NN----E-"},
{"smooth ice wall",WALL,ICE,VAR_1}, {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N---WW--" },
{"smooth ice wall",WALL,ICE,VAR_1}, {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "NN--W---" },
{"smooth ice wall",WALL,ICE,VAR_1}, {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "--S-WW--" },
{"smooth ice wall",WALL,ICE,VAR_1}, {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "--SSW---" },
{"smooth ice wall",WALL,ICE,VAR_1}, {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N-S-W-E-"},
{"smooth ice wall",WALL,ICE,VAR_1}, {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N-S---E-" },
// 460 // 460
{"smooth ice wall",WALL,ICE,VAR_1}, {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "--S-W-E-" },
{"smooth ice wall",WALL,ICE,VAR_1}, {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N---W-E-" },
{"smooth ice wall",WALL,ICE,VAR_1}, {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N-S-W---"},
{"smooth ice wall",WALL,ICE,VAR_1}, {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "--S---E-"},
{"smooth ice wall",WALL,ICE,VAR_1}, {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N-----E-" },
{"smooth ice wall",WALL,ICE,VAR_1}, {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N---W---" },
{"smooth ice wall",WALL,ICE,VAR_1}, {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "--S-W---" },
{"smooth ice wall",WALL,ICE,VAR_1}, {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "N-S-----" },
{"smooth ice wall",WALL,ICE,VAR_1}, {"smooth ice wall",WALL,ICE,VAR_1 , TILE_SMOOTH , "----W-E-"},
{0 ,EMPTY, AIR, VAR_1}, {0 ,EMPTY, AIR, VAR_1},
// 470 // 470
@ -699,29 +851,29 @@ namespace DFHack
{"constructed floor",FLOOR,CONSTRUCTED, VAR_1}, {"constructed floor",FLOOR,CONSTRUCTED, VAR_1},
{"constructed fortification",FORTIFICATION,CONSTRUCTED, VAR_1}, {"constructed fortification",FORTIFICATION,CONSTRUCTED, VAR_1},
{"constructed pillar",PILLAR,CONSTRUCTED, VAR_1}, {"constructed pillar",PILLAR,CONSTRUCTED, VAR_1},
{"constructed wall",WALL,CONSTRUCTED, VAR_1}, {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "--SS--E-" },
{"constructed wall",WALL,CONSTRUCTED, VAR_1}, {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "--S---EE" },
{"constructed wall",WALL,CONSTRUCTED, VAR_1}, {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N-----EE" },
{"constructed wall",WALL,CONSTRUCTED, VAR_1}, {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "NN----E-" },
// 500 // 500
{"constructed wall",WALL,CONSTRUCTED, VAR_1}, {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N---WW--" },
{"constructed wall",WALL,CONSTRUCTED, VAR_1}, {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "NN--W---" },
{"constructed wall",WALL,CONSTRUCTED, VAR_1}, {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "--S-WW--" },
{"constructed wall",WALL,CONSTRUCTED, VAR_1}, {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "--SSW---" },
{"constructed wall",WALL,CONSTRUCTED, VAR_1}, {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N-S-W-E-" },
{"constructed wall",WALL,CONSTRUCTED, VAR_1}, {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N-S---E-" },
{"constructed wall",WALL,CONSTRUCTED, VAR_1}, {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "--S-W-E-" },
{"constructed wall",WALL,CONSTRUCTED, VAR_1}, {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N---W-E-" },
{"constructed wall",WALL,CONSTRUCTED, VAR_1}, {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N-S-W---" },
{"constructed wall",WALL,CONSTRUCTED, VAR_1}, {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "--S---E-" },
// 510 // 510
{"constructed wall",WALL,CONSTRUCTED, VAR_1}, {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N-----E-" },
{"constructed wall",WALL,CONSTRUCTED, VAR_1}, {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N---W---" },
{"constructed wall",WALL,CONSTRUCTED, VAR_1}, {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "--S-W---" },
{"constructed wall",WALL,CONSTRUCTED, VAR_1}, {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "N-S-----" },
{"constructed wall",WALL,CONSTRUCTED, VAR_1}, {"constructed wall",WALL,CONSTRUCTED, VAR_1 ,TILE_NORMAL, "----W-E-" },
{"constructed stair up/down",STAIR_UPDOWN,CONSTRUCTED, VAR_1}, {"constructed stair up/down",STAIR_UPDOWN,CONSTRUCTED, VAR_1},
{"constructed stair down",STAIR_DOWN,CONSTRUCTED, VAR_1}, {"constructed stair down",STAIR_DOWN,CONSTRUCTED, VAR_1},
{"constructed stair up",STAIR_UP,CONSTRUCTED, VAR_1}, {"constructed stair up",STAIR_UP,CONSTRUCTED, VAR_1},
@ -764,6 +916,88 @@ namespace DFHack
{ {
return tileTypeTable[in].c; return tileTypeTable[in].c;
} }
//zilpin: for convenience, when you'll be using the tile information a lot.
inline const
TileRow * getTileTypeP(int in)
{
if( in<0 || in>=TILE_TYPE_ARRAY_LENGTH ) return 0;
return ( const TileRow * ) &tileTypeTable[in];
}
//zilpin: Find the first tile entry which matches the given search criteria.
//All parameters are optional.
//To omit, use the 'invalid' enum for that type (e.g. tileclass_invalid, tilematerial_invalid, etc)
//For tile directions, pass NULL to omit.
//Returns matching index in tileTypeTable, or -1 if none found.
inline
int32_t findTileType( const TileClass tclass, const TileMaterial tmat, const TileVariant tvar, const TileSpecial tspecial, const TileDirection tdir )
{
int32_t tt;
for(tt=0;tt<TILE_TYPE_ARRAY_LENGTH; ++tt){
if( tclass>-1 ) if( tclass != tileTypeTable[tt].c ) continue;
if( tmat>-1 ) if( tmat != tileTypeTable[tt].m ) continue;
if( tvar>-1 ) if( tvar != tileTypeTable[tt].v ) continue;
if( tspecial>-1 ) if( tspecial != tileTypeTable[tt].s ) continue;
if( tdir.whole ) if( tdir.whole != tileTypeTable[tt].d.whole ) continue;
//Match!
return tt;
}
return -1;
}
//Convenience version of the above, to pass strings as the direction
inline
int32_t findTileType( const TileClass tclass, const TileMaterial tmat, const TileVariant tvar, const TileSpecial tspecial, const char *tdirStr )
{
if(tdirStr){
TileDirection tdir(tdirStr);
return findTileType(tclass,tmat,tvar,tspecial, tdir );
}else{
return findTileType(tclass,tmat,tvar,tspecial, 0 );
}
}
//zilpin: Find a tile type similar to the one given, but with a different class.
//Useful for tile-editing operations.
//If no match found, returns the sourceType
//Definitely needs improvement for wall directions, etc.
inline
int32_t findSimilarTileType( const int32_t sourceTileType, const TileClass tclass ){
int32_t tt, maybe=0, match=0;
int value=0, matchv=0;
const TileRow *source = &tileTypeTable[sourceTileType];
#ifdef assert
assert( sourceTileType >=0 && sourceTileType < TILE_TYPE_ARRAY_LENGTH );
#endif
for(tt=0;tt<TILE_TYPE_ARRAY_LENGTH; ++tt){
if( tclass == tileTypeTable[tt].c ){
//shortcut null entries
if(!tileTypeTable[tt].name) continue;
//Special flag match is absolutely mandatory!
if( source->s != tileTypeTable[tt].s ) continue;
maybe=tt; value=0;
//Material is high-value match
if( tileTypeTable[tt].m == source->m ) value|=8;
//Direction is medium value match
if( tileTypeTable[tt].d.whole == source->d.whole ) value|=4;
//Variant is low-value match
if( tileTypeTable[tt].v == source->v ) value|=1;
//Check value against last match
if( value>matchv ){
match=tt;
matchv=value;
}
}
}
if( match ) return match;
return sourceTileType;
}
} }

@ -41,6 +41,13 @@ namespace DFHack
class VersionInfoPrivate; class VersionInfoPrivate;
class OffsetGroupPrivate; class OffsetGroupPrivate;
enum INVAL_TYPE
{
NOT_SET,
IS_INVALID,
IS_VALID
};
/* /*
* Offset Group * Offset Group
*/ */
@ -68,31 +75,36 @@ namespace DFHack
std::string getString (const std::string & key); std::string getString (const std::string & key);
OffsetGroup * getGroup ( const std::string & name ); OffsetGroup * getGroup ( const std::string & name );
void setOffset (const std::string & key, const std::string & value); void setOffset (const std::string& key, const std::string& value, const DFHack::INVAL_TYPE inval = IS_VALID);
void setAddress (const std::string & key, const std::string & value); void setOffsetValidity(const std::string& key, const DFHack::INVAL_TYPE inval = IS_VALID);
void setHexValue (const std::string & key, const std::string & value); void setAddress (const std::string& key, const std::string& value, const DFHack::INVAL_TYPE inval = IS_VALID);
void setString (const std::string & key, const std::string & value); void setAddressValidity(const std::string& key, const DFHack::INVAL_TYPE inval = IS_VALID);
void setHexValue (const std::string& key, const std::string& value, const DFHack::INVAL_TYPE inval = IS_VALID);
void setHexValueValidity(const std::string& key, const DFHack::INVAL_TYPE inval = IS_VALID);
void setString (const std::string& key, const std::string& value, const DFHack::INVAL_TYPE inval = IS_VALID);
void setStringValidity(const std::string& key, const DFHack::INVAL_TYPE inval = IS_VALID);
std::string PrintOffsets(int indentation); std::string PrintOffsets(int indentation);
std::string getName(); std::string getName();
std::string getFullName(); std::string getFullName();
OffsetGroup * getParent(); OffsetGroup * getParent();
void setInvalid(INVAL_TYPE arg1);
}; };
/* /*
* Version Info * Version Info
*/ */
enum OSType
{
OS_WINDOWS,
OS_LINUX,
OS_APPLE,
OS_BAD
};
class DFHACK_EXPORT VersionInfo : public OffsetGroup class DFHACK_EXPORT VersionInfo : public OffsetGroup
{ {
private: private:
VersionInfoPrivate * d; VersionInfoPrivate * d;
public: public:
enum OSType
{
OS_WINDOWS,
OS_LINUX,
OS_APPLE,
OS_BAD
};
VersionInfo(); VersionInfo();
VersionInfo(const VersionInfo&); VersionInfo(const VersionInfo&);
void copy(const DFHack::VersionInfo* old); void copy(const DFHack::VersionInfo* old);

@ -1,10 +1,6 @@
#ifndef CL_MOD_ITEMS #ifndef CL_MOD_ITEMS
#define CL_MOD_ITEMS #define CL_MOD_ITEMS
/*
* DEPRECATED, DO NOT USE UNTIL FURTHER NOTICE!
**/
/* /*
* Creatures * Creatures
*/ */

@ -100,6 +100,16 @@ namespace DFHack
uint32_t address_of; uint32_t address_of;
}; };
struct t_grassvein
{
uint32_t vtable;
/// material vector index
uint32_t material;
/// 16x16 array of covering 'intensity'
uint8_t intensity[16][16];
/// this is NOT part of the DF vein, but an address of the vein as seen by DFhack.
uint32_t address_of;
};
enum BiomeOffset enum BiomeOffset
{ {
eNorthWest, eNorthWest,
@ -148,7 +158,15 @@ namespace DFHack
liquid_water, liquid_water,
liquid_magma liquid_magma
}; };
/*
enum e_liquidcharacter
{
liquid_fresh,
liquid_unk1,
liquid_salt,
liquid_unk2,
};
*/
struct naked_designation struct naked_designation
{ {
unsigned int flow_size : 3; // how much liquid is here? unsigned int flow_size : 3; // how much liquid is here?
@ -188,8 +206,9 @@ namespace DFHack
unsigned int feature_local : 1; unsigned int feature_local : 1;
/// this tile is a part of a global feature. can be combined with 'featstone' tiles /// this tile is a part of a global feature. can be combined with 'featstone' tiles
unsigned int feature_global : 1; unsigned int feature_global : 1;
/// those ripples on streams? unsigned int water_stagnant : 1;
unsigned int liquid_character : 2; unsigned int water_salt : 1;
// e_liquidcharacter liquid_character : 2;
}; };
union t_designation union t_designation
@ -417,7 +436,9 @@ namespace DFHack
bool ReadVeins(uint32_t x, uint32_t y, uint32_t z, bool ReadVeins(uint32_t x, uint32_t y, uint32_t z,
std::vector<t_vein>* veins, std::vector<t_vein>* veins,
std::vector<t_frozenliquidvein>* ices = 0, std::vector<t_frozenliquidvein>* ices = 0,
std::vector<t_spattervein>* splatter = 0); std::vector<t_spattervein>* splatter = 0,
std::vector<t_grassvein>* grass = 0
);
private: private:
struct Private; struct Private;

@ -145,7 +145,7 @@ namespace DFHack
void ReadAllMaterials(void); void ReadAllMaterials(void);
std::string getType(t_material & mat); std::string getType(t_material & mat);
std::string getDescription(t_material & mat); std::string getDescription(t_material & mat);
private: private:
class Private; class Private;

@ -25,9 +25,9 @@ distribution.
#ifndef KEYS_H_INCLUDED #ifndef KEYS_H_INCLUDED
#define KEYS_H_INCLUDED #define KEYS_H_INCLUDED
#include "dfhack/DFPragma.h" #include "../DFPragma.h"
#include "dfhack/DFExport.h" #include "../DFExport.h"
#include "dfhack/DFModule.h" #include "../DFModule.h"
namespace DFHack namespace DFHack
{ {

@ -72,24 +72,36 @@ Buildings::Buildings(DFContextShared * d_)
d = new Private; d = new Private;
d->d = d_; d->d = d_;
d->owner = d_->p; d->owner = d_->p;
d->p_bld = NULL;
d->Inited = d->Started = d->hasCustomWorkshops = false; d->Inited = d->Started = d->hasCustomWorkshops = false;
VersionInfo * mem = d->d->offset_descriptor; VersionInfo * mem = d->d->offset_descriptor;
OffsetGroup * OG_build = mem->getGroup("Buildings"); OffsetGroup * OG_build = mem->getGroup("Buildings");
d->buildings_vector = OG_build->getAddress ("buildings_vector"); d->Inited = true;
try try
{ {
d->custom_workshop_vector = OG_build->getAddress("custom_workshop_vector"); d->buildings_vector = OG_build->getAddress ("buildings_vector");
d->building_custom_workshop_type = OG_build->getOffset("building_custom_workshop_type");
d->custom_workshop_type = OG_build->getOffset("custom_workshop_type");
d->custom_workshop_name = OG_build->getOffset("custom_workshop_name");
mem->resolveClassnameToClassID("building_custom_workshop", d->custom_workshop_id);
d->hasCustomWorkshops = true;
} }
catch(DFHack::Error::UnsetMemoryDefinition &e) catch(DFHack::Error::AllMemdef &e)
{ {
cerr << "Custom workshops not available. Unset Memory Definition: " << e.what() << endl; cerr << "Buildings not available... " << e.what() << endl;
d->Inited = false;
}
if(d->Inited)
{
try
{
d->custom_workshop_vector = OG_build->getAddress("custom_workshop_vector");
d->building_custom_workshop_type = OG_build->getOffset("building_custom_workshop_type");
d->custom_workshop_type = OG_build->getOffset("custom_workshop_type");
d->custom_workshop_name = OG_build->getOffset("custom_workshop_name");
mem->resolveClassnameToClassID("building_custom_workshop", d->custom_workshop_id);
d->hasCustomWorkshops = true;
}
catch(DFHack::Error::AllMemdef &e)
{
cerr << "Custom workshops not available. Memory Definition: " << e.what() << endl;
}
} }
d->Inited = true;
} }
Buildings::~Buildings() Buildings::~Buildings()
@ -101,6 +113,8 @@ Buildings::~Buildings()
bool Buildings::Start(uint32_t & numbuildings) bool Buildings::Start(uint32_t & numbuildings)
{ {
if(!d->Inited)
return false;
d->p_bld = new DfVector <uint32_t> (d->owner, d->buildings_vector); d->p_bld = new DfVector <uint32_t> (d->owner, d->buildings_vector);
numbuildings = d->p_bld->size(); numbuildings = d->p_bld->size();
d->Started = true; d->Started = true;

@ -74,7 +74,7 @@ t_customWorkshop* Buildings_ReadCustomWorkshopTypes(DFHackObject* b_Ptr)
if(b_Ptr != NULL) if(b_Ptr != NULL)
{ {
int i; int i;
t_customWorkshop* cw_Ptr; t_customWorkshop* cw_Ptr = NULL;
std::map<uint32_t, string> bTypes; std::map<uint32_t, string> bTypes;
map<uint32_t, string>::iterator bIter; map<uint32_t, string>::iterator bIter;

@ -69,9 +69,10 @@ Creatures::Creatures(DFContextShared* _d)
{ {
d = new Private; d = new Private;
d->d = _d; d->d = _d;
Process * p = d->owner = _d->p; d->owner = _d->p;
d->Inited = false; d->Inited = false;
d->Started = false; d->Started = false;
d->p_cre = NULL;
d->d->InitReadNames(); // throws on error d->d->InitReadNames(); // throws on error
VersionInfo * minfo = d->d->offset_descriptor; VersionInfo * minfo = d->d->offset_descriptor;
OffsetGroup *OG_Creatures = minfo->getGroup("Creatures"); OffsetGroup *OG_Creatures = minfo->getGroup("Creatures");
@ -149,10 +150,14 @@ Creatures::~Creatures()
bool Creatures::Start( uint32_t &numcreatures ) bool Creatures::Start( uint32_t &numcreatures )
{ {
d->p_cre = new DfVector <uint32_t> (d->owner, d->creatures.vector); if(d->Ft_basic)
d->Started = true; {
numcreatures = d->p_cre->size(); d->p_cre = new DfVector <uint32_t> (d->owner, d->creatures.vector);
return true; d->Started = true;
numcreatures = d->p_cre->size();
return true;
}
return false;
} }
bool Creatures::Finish() bool Creatures::Finish()
@ -183,7 +188,6 @@ bool Creatures::ReadCreature (const int32_t index, t_creature & furball)
} }
*/ */
// non-SHM slow path // non-SHM slow path
VersionInfo * minfo = d->d->offset_descriptor;
// read pointer from vector at position // read pointer from vector at position
uint32_t temp = d->p_cre->at (index); uint32_t temp = d->p_cre->at (index);
@ -471,6 +475,8 @@ bool Creatures::WriteSex(const uint32_t index, const uint8_t sex)
uint32_t temp = d->p_cre->at (index); uint32_t temp = d->p_cre->at (index);
Process * p = d->owner; Process * p = d->owner;
p->writeByte (temp + d->creatures.sex_offset, sex); p->writeByte (temp + d->creatures.sex_offset, sex);
return true;
} }
bool Creatures::WriteTraits(const uint32_t index, const t_soul &soul) bool Creatures::WriteTraits(const uint32_t index, const t_soul &soul)
@ -596,7 +602,6 @@ bool Creatures::ReadJob(const t_creature * furball, vector<t_material> & mat)
if(!d->Inited) return false; if(!d->Inited) return false;
if(!furball->current_job.active) return false; if(!furball->current_job.active) return false;
Process * p = d->owner; Process * p = d->owner;
VersionInfo * minfo = d->d->offset_descriptor;
DfVector <uint32_t> cmats(p, furball->current_job.occupationPtr + d->OG_jobs->getOffset("materials_vector")); DfVector <uint32_t> cmats(p, furball->current_job.occupationPtr + d->OG_jobs->getOffset("materials_vector"));
mat.resize(cmats.size()); mat.resize(cmats.size());
@ -614,7 +619,6 @@ bool Creatures::ReadJob(const t_creature * furball, vector<t_material> & mat)
bool Creatures::ReadInventoryIdx(const uint32_t index, std::vector<uint32_t> & item) bool Creatures::ReadInventoryIdx(const uint32_t index, std::vector<uint32_t> & item)
{ {
if(!d->Started) return false; if(!d->Started) return false;
Process * p = d->owner;
uint32_t temp = d->p_cre->at (index); uint32_t temp = d->p_cre->at (index);
return this->ReadInventoryPtr(temp, item); return this->ReadInventoryPtr(temp, item);
} }

@ -84,7 +84,7 @@ t_material* Creatures_ReadJob(DFHackObject* cPtr, const t_creature* furball)
if(mat.size() <= 0) if(mat.size() <= 0)
return NULL; return NULL;
t_material* buf; t_material* buf = NULL;
(*alloc_t_material_buffer_callback)(buf, mat.size()); (*alloc_t_material_buffer_callback)(buf, mat.size());
@ -104,6 +104,64 @@ t_material* Creatures_ReadJob(DFHackObject* cPtr, const t_creature* furball)
return NULL; return NULL;
} }
uint32_t* Creatures_ReadInventoryIdx(DFHackObject* cPtr, const uint32_t index)
{
if(cPtr != NULL)
{
std::vector<uint32_t> item;
if(((DFHack::Creatures*)cPtr)->ReadInventoryIdx(index, item))
{
if(item.size() <= 0)
return NULL;
uint32_t* buf = NULL;
(*alloc_uint_buffer_callback)(buf, item.size());
if(buf != NULL)
{
copy(item.begin(), item.end(), buf);
return buf;
}
else
return NULL;
}
}
return NULL;
}
uint32_t* Creatures_ReadInventoryPtr(DFHackObject* cPtr, const uint32_t index)
{
if(cPtr != NULL)
{
std::vector<uint32_t> item;
if(((DFHack::Creatures*)cPtr)->ReadInventoryPtr(index, item))
{
if(item.size() <= 0)
return NULL;
uint32_t* buf = NULL;
(*alloc_uint_buffer_callback)(buf, item.size());
if(buf != NULL)
{
copy(item.begin(), item.end(), buf);
return buf;
}
else
return NULL;
}
}
return NULL;
}
uint32_t Creatures_GetDwarfRaceIndex(DFHackObject* cPtr) uint32_t Creatures_GetDwarfRaceIndex(DFHackObject* cPtr)
{ {
if(cPtr != NULL) if(cPtr != NULL)

@ -0,0 +1,170 @@
// This is just a graveyard of old 40d code. Things in here COULD be turned into modules, but it requires research.
bool API::InitReadEffects ( uint32_t & numeffects )
{
if(d->effectsInited)
FinishReadEffects();
int effects = 0;
try
{
effects = d->offset_descriptor->getAddress ("effects_vector");
}
catch(Error::AllMemdef)
{
return false;
}
d->effectsInited = true;
d->p_effect = new DfVector (d->p, effects);
numeffects = d->p_effect->getSize();
return true;
}
bool API::ReadEffect(const uint32_t index, t_effect_df40d & effect)
{
if(!d->effectsInited)
return false;
if(index >= d->p_effect->getSize())
return false;
// read pointer from vector at position
uint32_t temp = d->p_effect->at (index);
//read effect from memory
d->p->read (temp, sizeof (t_effect_df40d), (uint8_t *) &effect);
return true;
}
// use with care!
bool API::WriteEffect(const uint32_t index, const t_effect_df40d & effect)
{
if(!d->effectsInited)
return false;
if(index >= d->p_effect->getSize())
return false;
// read pointer from vector at position
uint32_t temp = d->p_effect->at (index);
// write effect to memory
d->p->write(temp,sizeof(t_effect_df40d), (uint8_t *) &effect);
return true;
}
void API::FinishReadEffects()
{
if(d->p_effect)
{
delete d->p_effect;
d->p_effect = NULL;
}
d->effectsInited = false;
}
bool API::InitReadNotes( uint32_t &numnotes )
{
try
{
memory_info * minfo = d->offset_descriptor;
int notes = minfo->getAddress ("notes");
d->note_foreground_offset = minfo->getOffset ("note_foreground");
d->note_background_offset = minfo->getOffset ("note_background");
d->note_name_offset = minfo->getOffset ("note_name");
d->note_xyz_offset = minfo->getOffset ("note_xyz");
d->p_notes = new DfVector (d->p, notes);
d->notesInited = true;
numnotes = d->p_notes->getSize();
return true;
}
catch (Error::AllMemdef&)
{
d->notesInited = false;
numnotes = 0;
throw;
}
}
bool API::ReadNote (const int32_t index, t_note & note)
{
if(!d->notesInited) return false;
// read pointer from vector at position
uint32_t temp = d->p_notes->at (index);
note.symbol = d->p->readByte(temp);
note.foreground = d->p->readWord(temp + d->note_foreground_offset);
note.background = d->p->readWord(temp + d->note_background_offset);
d->p->readSTLString (temp + d->note_name_offset, note.name, 128);
d->p->read (temp + d->note_xyz_offset, 3*sizeof (uint16_t), (uint8_t *) &note.x);
return true;
}
bool API::InitReadSettlements( uint32_t & numsettlements )
{
if(!d->InitReadNames()) return false;
try
{
memory_info * minfo = d->offset_descriptor;
int allSettlements = minfo->getAddress ("settlements");
int currentSettlement = minfo->getAddress("settlement_current");
d->settlement_name_offset = minfo->getOffset ("settlement_name");
d->settlement_world_xy_offset = minfo->getOffset ("settlement_world_xy");
d->settlement_local_xy_offset = minfo->getOffset ("settlement_local_xy");
d->p_settlements = new DfVector (d->p, allSettlements);
d->p_current_settlement = new DfVector(d->p, currentSettlement);
d->settlementsInited = true;
numsettlements = d->p_settlements->getSize();
return true;
}
catch (Error::AllMemdef&)
{
d->settlementsInited = false;
numsettlements = 0;
throw;
}
}
bool API::ReadSettlement(const int32_t index, t_settlement & settlement)
{
if(!d->settlementsInited) return false;
if(!d->p_settlements->getSize()) return false;
// read pointer from vector at position
uint32_t temp = d->p_settlements->at (index);
settlement.origin = temp;
d->readName(settlement.name, temp + d->settlement_name_offset);
d->p->read(temp + d->settlement_world_xy_offset, 2 * sizeof(int16_t), (uint8_t *) &settlement.world_x);
d->p->read(temp + d->settlement_local_xy_offset, 4 * sizeof(int16_t), (uint8_t *) &settlement.local_x1);
return true;
}
bool API::ReadCurrentSettlement(t_settlement & settlement)
{
if(!d->settlementsInited) return false;
if(!d->p_current_settlement->getSize()) return false;
uint32_t temp = d->p_current_settlement->at(0);
settlement.origin = temp;
d->readName(settlement.name, temp + d->settlement_name_offset);
d->p->read(temp + d->settlement_world_xy_offset, 2 * sizeof(int16_t), (uint8_t *) &settlement.world_x);
d->p->read(temp + d->settlement_local_xy_offset, 4 * sizeof(int16_t), (uint8_t *) &settlement.local_x1);
return true;
}
void API::FinishReadSettlements()
{
if(d->p_settlements)
{
delete d->p_settlements;
d->p_settlements = NULL;
}
if(d->p_current_settlement)
{
delete d->p_current_settlement;
d->p_current_settlement = NULL;
}
d->settlementsInited = false;
}
void API::FinishReadNotes()
{
if(d->p_notes)
{
delete d->p_notes;
d->p_notes = 0;
}
d->notesInited = false;
}

@ -58,6 +58,23 @@ int Gui_ReadPauseState(DFHackObject* gui)
return -1; return -1;
} }
int Gui_SetPauseState(DFHackObject* gui, int8_t paused)
{
if(gui != NULL)
{
bool pauseState = false;
if(paused > 0)
pauseState = true;
((DFHack::Gui*)gui)->SetPauseState(pauseState);
return 1;
}
return -1;
}
int Gui_ReadViewScreen(DFHackObject* gui, t_viewscreen* viewscreen) int Gui_ReadViewScreen(DFHackObject* gui, t_viewscreen* viewscreen)
{ {
if(gui != NULL) if(gui != NULL)

@ -116,6 +116,21 @@ Accessor::Accessor(uint32_t function, Process *p)
this->offset1 = (funcText>>24) & 0xffff; this->offset1 = (funcText>>24) & 0xffff;
return; return;
} }
if( (funcText&0x000000FF00FFFFFFLL) == 0x000000C300418B66LL )
{
/* mov ax, [ecx+xx]; ret; (shorter instruction)*/
this->type = ACCESSOR_INDIRECT;
this->offset1 = (funcText>>24) & 0xff;
return;
}
if( (funcText&0x00000000FF00FFFFLL) == 0x00000000C300418BLL )
{
/* mov eax, [ecx+xx]; ret; */
this->type = ACCESSOR_INDIRECT;
this->offset1 = (funcText>>16) & 0xff;
this->dataWidth = 4;
return;
}
if( (funcText&0xFFFFFFFF0000FFFFLL) == 0x8B6600000000818BLL ) if( (funcText&0xFFFFFFFF0000FFFFLL) == 0x8B6600000000818BLL )
{ {
uint64_t funcText2 = p->readQuad(function+8); uint64_t funcText2 = p->readQuad(function+8);
@ -134,6 +149,13 @@ Accessor::Accessor(uint32_t function, Process *p)
this->offset1 = (funcText>>24) & 0xffff; this->offset1 = (funcText>>24) & 0xffff;
return; return;
} }
if( (funcText&0x000000FF00FFFFFFLL) == 0x000000C30041BF0FLL )
{
/* movsx eax, word ptr [ecx+xx]; ret (shorter opcode)*/
this->type = ACCESSOR_INDIRECT;
this->offset1 = (funcText>>24) & 0xff;
return;
}
if( (funcText&0xFFFFFFFF0000FFFFLL) == 0xCCC300000000818BLL ) if( (funcText&0xFFFFFFFF0000FFFFLL) == 0xCCC300000000818BLL )
{ {
/* mov eax, [ecx+xx]; ret; */ /* mov eax, [ecx+xx]; ret; */
@ -240,8 +262,17 @@ Items::Items(DFContextShared * d_)
d->d = d_; d->d = d_;
d->owner = d_->p; d->owner = d_->p;
} }
bool Items::Start(){return true;}
bool Items::Finish(){return true;} bool Items::Start()
{
return true;
}
bool Items::Finish()
{
return true;
}
Items::~Items() Items::~Items()
{ {
Finish(); Finish();
@ -250,6 +281,7 @@ Items::~Items()
while (it != d->descVTable.end()) while (it != d->descVTable.end())
{ {
delete (*it).second; delete (*it).second;
++it;
} }
d->descType.clear(); d->descType.clear();
d->descVTable.clear(); d->descVTable.clear();
@ -262,10 +294,10 @@ bool Items::getItemData(uint32_t itemptr, DFHack::t_item &item)
Process * p = d->owner; Process * p = d->owner;
ItemDesc * desc; ItemDesc * desc;
it = d->descVTable.find(itemptr); uint32_t vtable = p->readDWord(itemptr);
if(it==d->descVTable.end()) it = d->descVTable.find(vtable);
if(it == d->descVTable.end())
{ {
uint32_t vtable = p->readDWord(itemptr);
desc = new ItemDesc(vtable, p); desc = new ItemDesc(vtable, p);
d->descVTable[vtable] = desc; d->descVTable[vtable] = desc;
d->descType[desc->mainType] = desc; d->descType[desc->mainType] = desc;
@ -282,7 +314,7 @@ std::string Items::getItemClass(int32_t index)
std::string out; std::string out;
it = d->descType.find(index); it = d->descType.find(index);
if(it==d->descType.end()) if(it == d->descType.end())
{ {
/* these are dummy values for mood decoding */ /* these are dummy values for mood decoding */
switch(index) switch(index)
@ -325,3 +357,126 @@ std::string Items::getItemDescription(uint32_t itemptr, Materials * Materials)
out.append(this->getItemClass(item.matdesc.itemType)); out.append(this->getItemClass(item.matdesc.itemType));
return out; return out;
} }
// The OLD items code follows (40d era)
// TODO: merge with the current Items module
/*
bool API::InitReadItems(uint32_t & numitems)
{
try
{
int items = d->offset_descriptor->getAddress ("items");
d->item_material_offset = d->offset_descriptor->getOffset ("item_materials");
d->p_itm = new DfVector (d->p, items);
d->itemsInited = true;
numitems = d->p_itm->getSize();
return true;
}
catch (Error::AllMemdef&)
{
d->itemsInited = false;
numitems = 0;
throw;
}
}
bool API::getItemIndexesInBox(vector<uint32_t> &indexes,
const uint16_t x1, const uint16_t y1, const uint16_t z1,
const uint16_t x2, const uint16_t y2, const uint16_t z2)
{
if(!d->itemsInited) return false;
indexes.clear();
uint32_t size = d->p_itm->getSize();
struct temp2{
uint16_t coords[3];
uint32_t flags;
};
temp2 temp2;
for(uint32_t i =0;i<size;i++){
uint32_t temp = d->p_itm->at(i);
d->p->read(temp+sizeof(uint32_t),5 * sizeof(uint16_t), (uint8_t *) &temp2);
if(temp2.flags & (1 << 0)){
if (temp2.coords[0] >= x1 && temp2.coords[0] < x2)
{
if (temp2.coords[1] >= y1 && temp2.coords[1] < y2)
{
if (temp2.coords[2] >= z1 && temp2.coords[2] < z2)
{
indexes.push_back(i);
}
}
}
}
}
return true;
}
bool API::ReadItem (const uint32_t index, t_item & item)
{
if (!d->itemsInited) return false;
t_item_df40d item_40d;
// read pointer from vector at position
uint32_t temp = d->p_itm->at (index);
//read building from memory
d->p->read (temp, sizeof (t_item_df40d), (uint8_t *) &item_40d);
// transform
int32_t type = -1;
d->offset_descriptor->resolveObjectToClassID (temp, type);
item.origin = temp;
item.vtable = item_40d.vtable;
item.x = item_40d.x;
item.y = item_40d.y;
item.z = item_40d.z;
item.type = type;
item.ID = item_40d.ID;
item.flags.whole = item_40d.flags;
//TODO certain item types (creature based, threads, seeds, bags do not have the first matType byte, instead they have the material index only located at 0x68
d->p->read (temp + d->item_material_offset, sizeof (t_matglossPair), (uint8_t *) &item.material);
//for(int i = 0; i < 0xCC; i++){ // used for item research
// uint8_t byte = MreadByte(temp+i);
// item.bytes.push_back(byte);
//}
return true;
}
void API::FinishReadItems()
{
if(d->p_itm)
{
delete d->p_itm;
d->p_itm = NULL;
}
d->itemsInited = false;
}
*/
/*
bool API::ReadItemTypes(vector< vector< t_itemType > > & itemTypes)
{
memory_info * minfo = d->offset_descriptor;
int matgloss_address = minfo->getAddress("matgloss");
int matgloss_skip = minfo->getHexValue("matgloss_skip");
int item_type_name_offset = minfo->getOffset("item_type_name");
for(int i = 8;i<20;i++)
{
DfVector p_temp (d->p, matgloss_address + i*matgloss_skip);
vector< t_itemType > typesForVec;
for(uint32_t j =0; j<p_temp.getSize();j++)
{
t_itemType currType;
uint32_t temp = *(uint32_t *) p_temp[j];
// Mread(temp+40,sizeof(name),(uint8_t *) name);
d->p->readSTLString(temp+4,currType.id,128);
d->p->readSTLString(temp+item_type_name_offset,currType.name,128);
//stringsForVec.push_back(string(name));
typesForVec.push_back(currType);
}
itemTypes.push_back(typesForVec);
}
return true;
}
*/

@ -58,7 +58,7 @@ char* Items_getItemDescription(DFHackObject* items, uint32_t itemptr, DFHackObje
if(desc.size() > 0) if(desc.size() > 0)
{ {
char* buf; char* buf = NULL;
(*alloc_char_buffer_callback)(buf,desc.size()); (*alloc_char_buffer_callback)(buf,desc.size());
if(buf != NULL) if(buf != NULL)
@ -86,7 +86,7 @@ char* Items_getItemClass(DFHackObject* items, int32_t index)
if(iclass.size() > 0) if(iclass.size() > 0)
{ {
char* buf; char* buf = NULL;
(*alloc_char_buffer_callback)(buf, iclass.size()); (*alloc_char_buffer_callback)(buf, iclass.size());
if(buf != NULL) if(buf != NULL)
{ {

@ -57,6 +57,8 @@ struct Maps::Private
OffsetGroup *OG_vector; OffsetGroup *OG_vector;
bool Inited; bool Inited;
bool Started; bool Started;
bool hasGeology;
bool hasFeatures;
// map between feature address and the read object // map between feature address and the read object
map <uint32_t, t_feature> local_feature_store; map <uint32_t, t_feature> local_feature_store;
@ -74,6 +76,7 @@ Maps::Maps(DFContextShared* _d)
DFHack::VersionInfo * mem = p->getDescriptor(); DFHack::VersionInfo * mem = p->getDescriptor();
Server::Maps::maps_offsets &off = d->offsets; Server::Maps::maps_offsets &off = d->offsets;
d->hasFeatures = d->hasGeology = true;
// get the offsets once here // get the offsets once here
OffsetGroup *OG_Maps = mem->getGroup("Maps"); OffsetGroup *OG_Maps = mem->getGroup("Maps");
@ -87,7 +90,6 @@ Maps::Maps(DFContextShared* _d)
off.region_z_offset = OG_Maps->getAddress ("region_z"); off.region_z_offset = OG_Maps->getAddress ("region_z");
off.world_size_x = OG_Maps->getAddress ("world_size_x"); off.world_size_x = OG_Maps->getAddress ("world_size_x");
off.world_size_y = OG_Maps->getAddress ("world_size_y"); off.world_size_y = OG_Maps->getAddress ("world_size_y");
OffsetGroup *OG_MapBlock = OG_Maps->getGroup("block"); OffsetGroup *OG_MapBlock = OG_Maps->getGroup("block");
{ {
off.tile_type_offset = OG_MapBlock->getOffset ("type"); off.tile_type_offset = OG_MapBlock->getOffset ("type");
@ -100,18 +102,31 @@ Maps::Maps(DFContextShared* _d)
off.temperature1_offset = OG_MapBlock->getOffset ("temperature1"); off.temperature1_offset = OG_MapBlock->getOffset ("temperature1");
off.temperature2_offset = OG_MapBlock->getOffset ("temperature2"); off.temperature2_offset = OG_MapBlock->getOffset ("temperature2");
} }
try
OffsetGroup *OG_Geology = OG_Maps->getGroup("geology");
{ {
off.world_regions = OG_Geology->getAddress ("ptr2_region_array"); OffsetGroup *OG_Geology = OG_Maps->getGroup("geology");
off.region_size = OG_Geology->getHexValue ("region_size"); {
off.region_geo_index_offset = OG_Geology->getOffset ("region_geo_index_off"); off.world_regions = OG_Geology->getAddress ("ptr2_region_array");
off.geolayer_geoblock_offset = OG_Geology->getOffset ("geolayer_geoblock_offset"); off.region_size = OG_Geology->getHexValue ("region_size");
off.world_geoblocks_vector = OG_Geology->getAddress ("geoblock_vector"); off.region_geo_index_offset = OG_Geology->getOffset ("region_geo_index_off");
off.type_inside_geolayer = OG_Geology->getOffset ("type_inside_geolayer"); off.geolayer_geoblock_offset = OG_Geology->getOffset ("geolayer_geoblock_offset");
off.world_geoblocks_vector = OG_Geology->getAddress ("geoblock_vector");
off.type_inside_geolayer = OG_Geology->getOffset ("type_inside_geolayer");
}
}
catch(Error::AllMemdef &)
{
d->hasGeology = false;
}
try
{
d->OG_global_features = OG_Maps->getGroup("features")->getGroup("global");
d->OG_local_features = OG_Maps->getGroup("features")->getGroup("local");
}
catch(Error::AllMemdef &)
{
d->hasFeatures = false;
} }
d->OG_global_features = OG_Maps->getGroup("features")->getGroup("global");
d->OG_local_features = OG_Maps->getGroup("features")->getGroup("local");
} }
d->OG_vector = mem->getGroup("vector"); d->OG_vector = mem->getGroup("vector");
@ -121,6 +136,10 @@ Maps::Maps(DFContextShared* _d)
mem->resolveClassnameToVPtr("block_square_event_frozen_liquid", off.vein_ice_vptr); mem->resolveClassnameToVPtr("block_square_event_frozen_liquid", off.vein_ice_vptr);
off.vein_mineral_vptr = 0; off.vein_mineral_vptr = 0;
mem->resolveClassnameToVPtr("block_square_event_mineral",off.vein_mineral_vptr); mem->resolveClassnameToVPtr("block_square_event_mineral",off.vein_mineral_vptr);
off.vein_spatter_vptr = 0;
mem->resolveClassnameToVPtr("block_square_event_material_spatterst",off.vein_spatter_vptr);
off.vein_grass_vptr = 0;
mem->resolveClassnameToVPtr("block_square_event_grassst",off.vein_grass_vptr);
// upload offsets to SHM server if possible // upload offsets to SHM server if possible
d->maps_module = 0; d->maps_module = 0;
@ -517,18 +536,20 @@ bool Maps::WriteGlobalFeature(uint32_t x, uint32_t y, uint32_t z, int16_t global
/* /*
* Block events * Block events
*/ */
bool Maps::ReadVeins(uint32_t x, uint32_t y, uint32_t z, vector <t_vein>* veins, vector <t_frozenliquidvein>* ices, vector <t_spattervein> *splatter) bool Maps::ReadVeins(uint32_t x, uint32_t y, uint32_t z, vector <t_vein>* veins, vector <t_frozenliquidvein>* ices, vector <t_spattervein> *splatter, vector <t_grassvein> *grass)
{ {
MAPS_GUARD MAPS_GUARD
t_vein v; t_vein v;
t_frozenliquidvein fv; t_frozenliquidvein fv;
t_spattervein sv; t_spattervein sv;
t_grassvein gv;
Process* p = d->owner; Process* p = d->owner;
uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z];
if(veins) veins->clear(); if(veins) veins->clear();
if(ices) ices->clear(); if(ices) ices->clear();
if(splatter) splatter->clear(); if(splatter) splatter->clear();
if(grass) splatter->clear();
Server::Maps::maps_offsets &off = d->offsets; Server::Maps::maps_offsets &off = d->offsets;
if (addr) if (addr)
@ -568,6 +589,14 @@ try_again:
// store it in the vector // store it in the vector
splatter->push_back (sv); splatter->push_back (sv);
} }
else if(grass && type == off.vein_grass_vptr)
{
// read the splatter vein data (dereference pointer)
p->read (temp, sizeof(t_grassvein), (uint8_t *) &gv);
gv.address_of = temp;
// store it in the vector
grass->push_back (gv);
}
else else
{ {
string cname = p->readClassName(type); string cname = p->readClassName(type);
@ -586,6 +615,11 @@ try_again:
off.vein_spatter_vptr = type; off.vein_spatter_vptr = type;
goto try_again; goto try_again;
} }
else if(grass && cname=="block_square_event_grassst")
{
off.vein_grass_vptr = type;
goto try_again;
}
#ifdef DEBUG #ifdef DEBUG
else else
{ {
@ -661,7 +695,7 @@ __int16 __userpurge GetGeologicalRegion<ax>(__int16 block_X<cx>, int X<ebx>, __i
bool Maps::ReadGeology (vector < vector <uint16_t> >& assign) bool Maps::ReadGeology (vector < vector <uint16_t> >& assign)
{ {
MAPS_GUARD MAPS_GUARD
VersionInfo * minfo = d->d->offset_descriptor; if(!d->hasGeology) return false;
Process *p = d->owner; Process *p = d->owner;
// get needed addresses and offsets. Now this is what I call crazy. // get needed addresses and offsets. Now this is what I call crazy.
uint16_t worldSizeX, worldSizeY; uint16_t worldSizeX, worldSizeY;
@ -731,12 +765,12 @@ bool Maps::ReadGeology (vector < vector <uint16_t> >& assign)
bool Maps::ReadLocalFeatures( std::map <planecoord, std::vector<t_feature *> > & local_features ) bool Maps::ReadLocalFeatures( std::map <planecoord, std::vector<t_feature *> > & local_features )
{ {
MAPS_GUARD MAPS_GUARD
if(!d->hasFeatures) return false;
// can't be used without a map! // can't be used without a map!
if(!d->block) if(!d->block)
return false; return false;
Process * p = d->owner; Process * p = d->owner;
VersionInfo * mem = p->getDescriptor();
// deref pointer to the humongo-structure // deref pointer to the humongo-structure
uint32_t base = p->readDWord(d->OG_local_features->getAddress("start_ptr")); uint32_t base = p->readDWord(d->OG_local_features->getAddress("start_ptr"));
if(!base) if(!base)
@ -824,6 +858,7 @@ bool Maps::ReadLocalFeatures( std::map <planecoord, std::vector<t_feature *> > &
bool Maps::ReadGlobalFeatures( std::vector <t_feature> & features) bool Maps::ReadGlobalFeatures( std::vector <t_feature> & features)
{ {
MAPS_GUARD MAPS_GUARD
if(!d->hasFeatures) return false;
// can't be used without a map! // can't be used without a map!
if(!d->block) if(!d->block)
return false; return false;

@ -22,6 +22,7 @@ must not be misrepresented as being the original software.
distribution. distribution.
*/ */
#include "dfhack/DFPragma.h"
#include <vector> #include <vector>
#include <algorithm> #include <algorithm>
@ -54,6 +55,48 @@ int Maps_Finish(DFHackObject* maps)
return -1; return -1;
} }
uint16_t* Maps_ReadGeology(DFHackObject* maps)
{
if(maps != NULL)
{
std::vector < std::vector <uint16_t> > geology;
if(((DFHack::Maps*)maps)->ReadGeology(geology))
{
uint16_t* buf = NULL;
uint32_t geoLength = 0;
for(unsigned int i = 0; i < geology.size(); i++)
{
for(unsigned int j = 0; j < geology[i].size(); j++)
{
geoLength += geology[i].size();
}
}
(*alloc_ushort_buffer_callback)(buf, geoLength);
if(buf != NULL)
{
uint16_t* bufCopyPtr = buf;
for(unsigned int i = 0; i < geology.size(); i++)
{
copy(geology[i].begin(), geology[i].end(), bufCopyPtr);
bufCopyPtr += geology[i].size();
}
return buf;
}
else
return NULL;
}
}
return NULL;
}
t_feature* Maps_ReadGlobalFeatures(DFHackObject* maps) t_feature* Maps_ReadGlobalFeatures(DFHackObject* maps)
{ {
if(maps != NULL) if(maps != NULL)
@ -65,7 +108,7 @@ t_feature* Maps_ReadGlobalFeatures(DFHackObject* maps)
if(featureVec.size() <= 0) if(featureVec.size() <= 0)
return NULL; return NULL;
t_feature* buf; t_feature* buf = NULL;
(*alloc_t_feature_buffer_callback)(buf, featureVec.size()); (*alloc_t_feature_buffer_callback)(buf, featureVec.size());
@ -255,6 +298,8 @@ int Maps_WriteEmptyLocalFeature(DFHackObject* maps, uint32_t x, uint32_t y, uint
{ {
return ((DFHack::Maps*)maps)->WriteLocalFeature(x, y, z, -1); return ((DFHack::Maps*)maps)->WriteLocalFeature(x, y, z, -1);
} }
return -1;
} }
int Maps_WriteGlobalFeature(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, int16_t local) int Maps_WriteGlobalFeature(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, int16_t local)
@ -273,6 +318,8 @@ int Maps_WriteEmptyGlobalFeature(DFHackObject* maps, uint32_t x, uint32_t y, uin
{ {
return ((DFHack::Maps*)maps)->WriteGlobalFeature(x, y, z, -1); return ((DFHack::Maps*)maps)->WriteGlobalFeature(x, y, z, -1);
} }
return -1;
} }
int Maps_ReadBlockFlags(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, t_blockflags* blockflags) int Maps_ReadBlockFlags(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, t_blockflags* blockflags)

@ -402,7 +402,7 @@ bool Materials::ReadCreatureTypesEx (void)
p->readSTLString (caste_start + sizeof_string, caste.singular, sizeof(caste.singular)); p->readSTLString (caste_start + sizeof_string, caste.singular, sizeof(caste.singular));
p->readSTLString (caste_start + 2 * sizeof_string, caste.plural, sizeof(caste.plural)); p->readSTLString (caste_start + 2 * sizeof_string, caste.plural, sizeof(caste.plural));
p->readSTLString (caste_start + 3 * sizeof_string, caste.adjective, sizeof(caste.adjective)); p->readSTLString (caste_start + 3 * sizeof_string, caste.adjective, sizeof(caste.adjective));
cout << "Caste " << caste.rawname << " " << caste.singular << ": 0x" << hex << caste_start << endl; //cout << "Caste " << caste.rawname << " " << caste.singular << ": 0x" << hex << caste_start << endl;
if(have_advanced) if(have_advanced)
{ {
/* color mod reading */ /* color mod reading */
@ -459,7 +459,7 @@ void Materials::ReadAllMaterials(void)
this->ReadCreatureTypes(); this->ReadCreatureTypes();
this->ReadCreatureTypesEx(); this->ReadCreatureTypesEx();
this->ReadDescriptorColors(); this->ReadDescriptorColors();
//this->ReadOthers(); this->ReadOthers();
} }
std::string Materials::getDescription(t_material & mat) std::string Materials::getDescription(t_material & mat)
@ -478,6 +478,12 @@ std::string Materials::getDescription(t_material & mat)
{ {
if (mat.subIndex>=this->other.size()) if (mat.subIndex>=this->other.size())
{ {
if (mat.itemType == 0) {
if(mat.subIndex<0)
return "any inorganic";
else
return this->inorganic[mat.subIndex].id;
}
if(mat.subIndex<0) if(mat.subIndex<0)
return "any"; return "any";
if(mat.subIndex>=this->raceEx.size()) if(mat.subIndex>=this->raceEx.size())

@ -232,7 +232,7 @@ t_matgloss* Materials_getInorganic(DFHackObject* mat)
if(materials->inorganic.size() > 0) if(materials->inorganic.size() > 0)
{ {
t_matgloss* buf; t_matgloss* buf = NULL;
((*alloc_matgloss_buffer_callback)(buf, materials->inorganic.size())); ((*alloc_matgloss_buffer_callback)(buf, materials->inorganic.size()));
@ -256,7 +256,7 @@ t_matgloss* Materials_getOrganic(DFHackObject* mat)
if(materials->organic.size() > 0) if(materials->organic.size() > 0)
{ {
t_matgloss* buf; t_matgloss* buf = NULL;
((*alloc_matgloss_buffer_callback)(buf, materials->organic.size())); ((*alloc_matgloss_buffer_callback)(buf, materials->organic.size()));
@ -280,7 +280,7 @@ t_matgloss* Materials_getTree(DFHackObject* mat)
if(materials->tree.size() > 0) if(materials->tree.size() > 0)
{ {
t_matgloss* buf; t_matgloss* buf = NULL;
((*alloc_matgloss_buffer_callback)(buf, materials->tree.size())); ((*alloc_matgloss_buffer_callback)(buf, materials->tree.size()));
@ -304,7 +304,7 @@ t_matgloss* Materials_getPlant(DFHackObject* mat)
if(materials->plant.size() > 0) if(materials->plant.size() > 0)
{ {
t_matgloss* buf; t_matgloss* buf = NULL;
((*alloc_matgloss_buffer_callback)(buf, materials->plant.size())); ((*alloc_matgloss_buffer_callback)(buf, materials->plant.size()));
@ -328,7 +328,7 @@ t_matgloss* Materials_getRace(DFHackObject* mat)
if(materials->race.size() > 0) if(materials->race.size() > 0)
{ {
t_matgloss* buf; t_matgloss* buf = NULL;
((*alloc_matgloss_buffer_callback)(buf, materials->race.size())); ((*alloc_matgloss_buffer_callback)(buf, materials->race.size()));
@ -354,7 +354,7 @@ c_creaturetype* Materials_getRaceEx(DFHackObject* mat)
if(matSize > 0) if(matSize > 0)
{ {
c_creaturetype* buf; c_creaturetype* buf = NULL;
((*alloc_creaturetype_buffer_callback)(buf, matSize)); ((*alloc_creaturetype_buffer_callback)(buf, matSize));
@ -379,7 +379,7 @@ t_descriptor_color* Materials_getColor(DFHackObject* mat)
if(materials->color.size() > 0) if(materials->color.size() > 0)
{ {
t_descriptor_color* buf; t_descriptor_color* buf = NULL;
((*alloc_descriptor_buffer_callback)(buf, materials->color.size())); ((*alloc_descriptor_buffer_callback)(buf, materials->color.size()));
@ -403,7 +403,7 @@ t_matglossOther* Materials_getOther(DFHackObject* mat)
if(materials->other.size() > 0) if(materials->other.size() > 0)
{ {
t_matglossOther* buf; t_matglossOther* buf = NULL;
((*alloc_matgloss_other_buffer_callback)(buf, materials->other.size())); ((*alloc_matgloss_other_buffer_callback)(buf, materials->other.size()));
@ -427,7 +427,7 @@ t_matgloss* Materials_getAllDesc(DFHackObject* mat)
if(materials->alldesc.size() > 0) if(materials->alldesc.size() > 0)
{ {
t_matgloss* buf; t_matgloss* buf = NULL;
((*alloc_matgloss_buffer_callback)(buf, materials->alldesc.size())); ((*alloc_matgloss_buffer_callback)(buf, materials->alldesc.size()));

@ -102,7 +102,7 @@ t_hotkey* Position_ReadHotkeys(DFHackObject* pos)
{ {
if(pos != NULL) if(pos != NULL)
{ {
t_hotkey* buf; t_hotkey* buf = NULL;
(*alloc_t_hotkey_buffer_callback)(buf, NUM_HOTKEYS); (*alloc_t_hotkey_buffer_callback)(buf, NUM_HOTKEYS);
@ -144,7 +144,7 @@ t_screen* Position_getScreenTiles(DFHackObject* pos, int32_t width, int32_t heig
{ {
if(pos != NULL) if(pos != NULL)
{ {
t_screen* buf; t_screen* buf = NULL;
(*alloc_t_screen_buffer_callback)(buf, width * height); (*alloc_t_screen_buffer_callback)(buf, width * height);

@ -124,7 +124,7 @@ char* Translation_TranslateNameEnglish(DFHackObject* trans, const DFHack::t_name
if(nameTrans.size() > 0) if(nameTrans.size() > 0)
{ {
char* buf; char* buf = NULL;
(*alloc_char_buffer_callback)(buf, nameTrans.size()); (*alloc_char_buffer_callback)(buf, nameTrans.size());
@ -155,7 +155,7 @@ char* Translation_TranslateNameNonEnglish(DFHackObject* trans, const DFHack::t_n
if(nameTrans.size() > 0) if(nameTrans.size() > 0)
{ {
char* buf; char* buf = NULL;
(*alloc_char_buffer_callback)(buf, nameTrans.size()); (*alloc_char_buffer_callback)(buf, nameTrans.size());

@ -130,20 +130,19 @@ WindowIO::~WindowIO ()
void WindowIO::TypeStr (const char *input, int delay, bool useShift) void WindowIO::TypeStr (const char *input, int delay, bool useShift)
{ {
//sendmessage needs a window handle HWND, so have to get that from the process HANDLE //sendmessage needs a window handle HWND, so have to get that from the process HANDLE
HWND currentWindow = GetForegroundWindow();
window myWindow; window myWindow;
myWindow.pid = d->p->getPID(); myWindow.pid = d->p->getPID();
EnumWindows (EnumWindowsProc, (LPARAM) &myWindow); EnumWindows (EnumWindowsProc, (LPARAM) &myWindow);
char cChar; char cChar;
DWORD dfProccess = GetWindowThreadProcessId(myWindow.windowHandle,NULL); DWORD dfProcess = GetWindowThreadProcessId(myWindow.windowHandle,NULL);
DWORD currentProccess = GetWindowThreadProcessId(currentWindow,NULL); DWORD currentProcess = GetCurrentThreadId();
AttachThreadInput(currentProccess,dfProccess,TRUE); //The two threads have to have attached input in order to change the keyboard state, which is needed to set the shift state AttachThreadInput(currentProcess,dfProcess,TRUE); //The two threads have to have attached input in order to change the keyboard state, which is needed to set the shift state
while ( (cChar = *input++)) // loops through chars while ( (cChar = *input++)) // loops through chars
{ {
short vk = VkKeyScan (cChar); // keycode of char short vk = VkKeyScan (cChar); // keycode of char
if (useShift || (vk >> 8) &1) // char is capital, so need to hold down shift if (useShift || (vk >> 8) &1) // char is capital, so need to hold down shift
{ {
vk = vk & 0xFF; // remove the shift state from the virtual key code
BYTE keybstate[256] = {0}; BYTE keybstate[256] = {0};
BYTE keybstateOrig[256] = {0}; BYTE keybstateOrig[256] = {0};
GetKeyboardState((LPBYTE)&keybstateOrig); GetKeyboardState((LPBYTE)&keybstateOrig);
@ -160,7 +159,7 @@ void WindowIO::TypeStr (const char *input, int delay, bool useShift)
SendMessage(myWindow.windowHandle,WM_KEYUP,vk,0); SendMessage(myWindow.windowHandle,WM_KEYUP,vk,0);
} }
} }
AttachThreadInput(currentProccess,dfProccess,FALSE); //detach the threads AttachThreadInput(currentProcess,dfProcess,FALSE); //detach the threads
Sleep (delay); Sleep (delay);
} }

@ -81,6 +81,57 @@ using namespace std;
#include <winnt.h> #include <winnt.h>
#include <psapi.h> #include <psapi.h>
#include <tlhelp32.h> #include <tlhelp32.h>
#include <Dbghelp.h>
typedef LONG NTSTATUS;
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
// FIXME: it is uncertain how these map to 64bit
typedef struct _DEBUG_BUFFER
{
HANDLE SectionHandle;
PVOID SectionBase;
PVOID RemoteSectionBase;
ULONG SectionBaseDelta;
HANDLE EventPairHandle;
ULONG Unknown[2];
HANDLE RemoteThreadHandle;
ULONG InfoClassMask;
ULONG SizeOfInfo;
ULONG AllocatedSize;
ULONG SectionSize;
PVOID ModuleInformation;
PVOID BackTraceInformation;
PVOID HeapInformation;
PVOID LockInformation;
PVOID Reserved[8];
} DEBUG_BUFFER, *PDEBUG_BUFFER;
typedef struct _DEBUG_HEAP_INFORMATION
{
ULONG Base; // 0×00
ULONG Flags; // 0×04
USHORT Granularity; // 0×08
USHORT Unknown; // 0x0A
ULONG Allocated; // 0x0C
ULONG Committed; // 0×10
ULONG TagCount; // 0×14
ULONG BlockCount; // 0×18
ULONG Reserved[7]; // 0x1C
PVOID Tags; // 0×38
PVOID Blocks; // 0x3C
} DEBUG_HEAP_INFORMATION, *PDEBUG_HEAP_INFORMATION;
// RtlQueryProcessDebugInformation.DebugInfoClassMask constants
#define PDI_MODULES 0x01
#define PDI_BACKTRACE 0x02
#define PDI_HEAPS 0x04
#define PDI_HEAP_TAGS 0x08
#define PDI_HEAP_BLOCKS 0x10
#define PDI_LOCKS 0x20
extern "C" __declspec(dllimport) NTSTATUS __stdcall RtlQueryProcessDebugInformation( IN ULONG ProcessId, IN ULONG DebugInfoClassMask, IN OUT PDEBUG_BUFFER DebugBuffer);
extern "C" __declspec(dllimport) PDEBUG_BUFFER __stdcall RtlCreateQueryDebugBuffer( IN ULONG Size, IN BOOLEAN EventPair);
extern "C" __declspec(dllimport) NTSTATUS __stdcall RtlDestroyQueryDebugBuffer( IN PDEBUG_BUFFER DebugBuffer);
#endif #endif
// dfhack dependencies // dfhack dependencies

@ -0,0 +1,96 @@
/*
www.sourceforge.net/projects/dfhack
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#ifndef LINUX_PROCESS_H_INCLUDED
#define LINUX_PROCESS_H_INCLUDED
#ifdef LINUX_BUILD
#include "dfhack/DFProcess.h"
namespace DFHack
{
class LinuxProcessBase : public Process
{
protected:
VersionInfo * my_descriptor;
pid_t my_pid;
string memFile;
int memFileHandle;
bool attached;
bool suspended;
bool identified;
public:
LinuxProcessBase(uint32_t pid);
~LinuxProcessBase();
bool attach();
bool detach();
bool suspend();
bool asyncSuspend();
bool resume();
bool forceresume();
void readQuad(const uint32_t address, uint64_t & value);
void writeQuad(const uint32_t address, const uint64_t value);
void readDWord(const uint32_t address, uint32_t & value);
void writeDWord(const uint32_t address, const uint32_t value);
void readFloat(const uint32_t address, float & value);
void readWord(const uint32_t address, uint16_t & value);
void writeWord(const uint32_t address, const uint16_t value);
void readByte(const uint32_t address, uint8_t & value);
void writeByte(const uint32_t address, const uint8_t value);
void read( uint32_t address, uint32_t length, uint8_t* buffer);
void write(uint32_t address, uint32_t length, uint8_t* buffer);
const std::string readCString (uint32_t offset);
bool isSuspended();
bool isAttached();
bool isIdentified();
VersionInfo *getDescriptor();
int getPID();
std::string getPath();
bool getThreadIDs(std::vector<uint32_t> & threads );
void getMemRanges(std::vector<t_memrange> & ranges );
// get module index by name and version. bool 1 = error
bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) { OUTPUT=0; return false;};
// get the SHM start if available
char * getSHMStart (void){return 0;};
// set a SHM command and wait for a response
bool SetAndWait (uint32_t state){return false;};
};
}
#endif
#endif

@ -0,0 +1,46 @@
/*
www.sourceforge.net/projects/dfhack
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#include <string>
namespace DFHack {
class Process;
class MicrosoftSTL
{
private:
uint32_t STLSTR_buf_off;
uint32_t STLSTR_size_off;
uint32_t STLSTR_cap_off;
Process* p;
public:
void init(Process* p);
const std::string readSTLString (uint32_t offset);
size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity);
void writeSTLString(const uint32_t address, const std::string writeString){};
// get class name of an object with rtti/type info
std::string readClassName(uint32_t vptr);
};
}

@ -0,0 +1,38 @@
/*
www.sourceforge.net/projects/dfhack
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#ifndef PROCESS_FACTORY_H_INCLUDED
#define PROCESS_FACTORY_H_INCLUDED
#include "dfhack/DFProcess.h"
namespace DFHack
{
Process* createNormalProcess(uint32_t pid, std::vector <VersionInfo *> & known_versions);
Process* createSHMProcess(uint32_t pid, std::vector <VersionInfo *> & known_versions);
#ifdef LINUX_BUILD
Process* createWineProcess(uint32_t pid, std::vector <VersionInfo *> & known_versions);
#endif
}
#endif

@ -0,0 +1,144 @@
/*
www.sourceforge.net/projects/dfhack
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#ifndef SHM_PROCESS_H_INCLUDED
#define SHM_PROCESS_H_INCLUDED
#include "dfhack/DFProcess.h"
#include "dfhack/DFIntegers.h"
namespace DFHack
{
class DFHACK_EXPORT SHMProcess : public Process
{
private:
class Private;
Private * const d;
public:
SHMProcess(uint32_t PID, std::vector <VersionInfo *> & known_versions);
~SHMProcess();
// Set up stuff so we can read memory
bool attach();
bool detach();
bool suspend();
bool asyncSuspend();
bool resume();
bool forceresume();
void readQuad(const uint32_t address, uint64_t & value);
void writeQuad(const uint32_t address, const uint64_t value);
void readDWord(const uint32_t address, uint32_t & value);
void writeDWord(const uint32_t address, const uint32_t value);
void readFloat(const uint32_t address, float & value);
void readWord(const uint32_t address, uint16_t & value);
void writeWord(const uint32_t address, const uint16_t value);
void readByte(const uint32_t address, uint8_t & value);
void writeByte(const uint32_t address, const uint8_t value);
void read( uint32_t address, uint32_t length, uint8_t* buffer);
void write(uint32_t address, uint32_t length, uint8_t* buffer);
const std::string readSTLString (uint32_t offset);
size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity);
void writeSTLString(const uint32_t address, const std::string writeString);
// get class name of an object with rtti/type info
std::string readClassName(uint32_t vptr);
const std::string readCString (uint32_t offset);
bool isSuspended();
bool isAttached();
bool isIdentified();
bool getThreadIDs(std::vector<uint32_t> & threads );
void getMemRanges(std::vector<t_memrange> & ranges );
VersionInfo *getDescriptor();
int getPID();
std::string getPath();
// get module index by name and version. bool 1 = error
bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT);
// get the SHM start if available
char * getSHMStart (void);
bool SetAndWait (uint32_t state);
private:
bool acquireSuspendLock();
bool releaseSuspendLock();
};
class SHMProcess::Private
{
public:
Private(SHMProcess * self_);
~Private(){}
VersionInfo * memdescriptor;
SHMProcess * self;
char *shm_addr;
int attachmentIdx;
bool attached;
bool locked;
bool identified;
bool useYield;
#ifdef LINUX_BUILD
pid_t process_ID;
int shm_ID;
int server_lock;
int client_lock;
int suspend_lock;
#else
typedef uint32_t pid_t;
uint32_t process_ID;
HANDLE DFSVMutex;
HANDLE DFCLMutex;
HANDLE DFCLSuspendMutex;
#endif
bool validate(std::vector< VersionInfo* >& known_versions);
bool Aux_Core_Attach(bool & versionOK, pid_t& PID);
bool SetAndWait (uint32_t state);
bool GetLocks();
bool AreLocksOk();
void FreeLocks();
};
}
// some helpful macros to keep the code bloat in check
#define SHMCMD ( (uint32_t *) shm_addr)[attachmentIdx]
#define D_SHMCMD ( (uint32_t *) (d->shm_addr))[d->attachmentIdx]
#define SHMHDR ((shm_core_hdr *)shm_addr)
#define D_SHMHDR ((shm_core_hdr *)(d->shm_addr))
#define SHMDATA(type) ((type *)(shm_addr + SHM_HEADER))
#define D_SHMDATA(type) ((type *)(d->shm_addr + SHM_HEADER))
#endif

@ -57,6 +57,7 @@ typedef struct
uint32_t vein_mineral_vptr; uint32_t vein_mineral_vptr;
uint32_t vein_ice_vptr; uint32_t vein_ice_vptr;
uint32_t vein_spatter_vptr; uint32_t vein_spatter_vptr;
uint32_t vein_grass_vptr;
/* /*
GEOLOGY GEOLOGY
*/ */

@ -302,7 +302,15 @@ void printCreature(DFHack::Context * DF, const DFHack::t_creature & creature)
{ {
cout << ", "; cout << ", ";
} }
cout << mem->getSkill(creature.defaultSoul.skills[i].id) << ": " << creature.defaultSoul.skills[i].rating; try
{
cout << mem->getSkill(creature.defaultSoul.skills[i].id) << ": " << creature.defaultSoul.skills[i].rating;
}
catch(DFHack::Error::AllMemdef &e)
{
cout << "Unknown skill! : " << creature.defaultSoul.skills[i].id <<", rating: " << creature.defaultSoul.skills[i].rating << endl;
cout << e.what() << endl;
}
} }
cout << endl; cout << endl;
cout << "Traits" << endl; cout << "Traits" << endl;

@ -2,6 +2,12 @@
* dumps vtables, items types and class name for all items in game * dumps vtables, items types and class name for all items in game
* best used this way : ./dfitemdump | sort -ug * best used this way : ./dfitemdump | sort -ug
*/ */
// THIS IS NOT A GOOD EXAMPLE!
// ... just look at all the magic numbers.
// I'm not fixing it though.
// ~px
#include <stdio.h> #include <stdio.h>
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
@ -41,7 +47,8 @@ int main ()
Materials = DF->getMaterials(); Materials = DF->getMaterials();
Materials->ReadAllMaterials(); Materials->ReadAllMaterials();
p = DF->getProcess(); p = DF->getProcess();
DFHack::DfVector <uint32_t> p_items (p, p->getDescriptor()->getAddress ("items_vector")); DFHack::OffsetGroup* itemGroup = mem->getGroup("Items");
DFHack::DfVector <uint32_t> p_items (p, itemGroup->getAddress("items_vector"));
uint32_t size = p_items.size(); uint32_t size = p_items.size();
Items = DF->getItems(); Items = DF->getItems();
@ -49,6 +56,7 @@ int main ()
printf("type\tvtable\tname\tquality\tdecorate\n"); printf("type\tvtable\tname\tquality\tdecorate\n");
for (i=0;i<size;i++) for (i=0;i<size;i++)
{ {
uint32_t curItem = p_items[i];
uint32_t vtable = p->readDWord(p_items[i]); uint32_t vtable = p->readDWord(p_items[i]);
uint32_t func0 = p->readDWord(vtable); uint32_t func0 = p->readDWord(vtable);
uint64_t funct0 = p->readQuad(func0); uint64_t funct0 = p->readQuad(func0);
@ -84,6 +92,8 @@ int main ()
if (funct1 == 0xC300000092818B66LL) if (funct1 == 0xC300000092818B66LL)
quality = p->readWord(p_items[i]+0x92); quality = p->readWord(p_items[i]+0x92);
if (funct1 == 0xC300000082818B66LL)
quality = p->readWord(p_items[i]+0x82);
else if (funct1 == 0xCCCCCCCCCCC3C033LL) else if (funct1 == 0xCCCCCCCCCCC3C033LL)
quality = 0; quality = 0;
else else
@ -115,6 +125,11 @@ int main ()
uint32_t off1 = (funcBt>>24) & 0xffff; uint32_t off1 = (funcBt>>24) & 0xffff;
typeB = p->readWord(p_items[i] + off1); typeB = p->readWord(p_items[i] + off1);
} }
else if ( (funcBt&0x000000FF00FFFFFFLL) == 0x000000C300418B66LL )
{
uint32_t off1 = (funcBt>>24) & 0xff;
typeB = p->readWord(p_items[i] + off1);
}
else else
printf("bad typeB func @%p\n", (void*) funcB); printf("bad typeB func @%p\n", (void*) funcB);
} }
@ -126,6 +141,16 @@ int main ()
uint32_t off1 = (funcCt>>24)&0xffff; uint32_t off1 = (funcCt>>24)&0xffff;
typeC = p->readWord(p_items[i] + off1); typeC = p->readWord(p_items[i] + off1);
} }
else if ( (funcCt&0x000000FF00FFFFFFLL) == 0x000000C300418B66LL )
{
uint32_t off1 = (funcCt>>24) & 0xff;
typeC = p->readWord(p_items[i] + off1);
}
else if ( (funcCt&0x00000000FF00FFFFLL) == 0x00000000C300418BLL )
{
uint32_t off1 = (funcCt>>16) & 0xff;
typeC = p->readWord(p_items[i] + off1);
}
else else
printf("bad typeC func @%p\n", (void*) funcC); printf("bad typeC func @%p\n", (void*) funcC);
@ -134,12 +159,27 @@ int main ()
else if ( (funcDt&0xFFFFFFFF0000FFFFLL) == 0xCCC300000000818BLL ) else if ( (funcDt&0xFFFFFFFF0000FFFFLL) == 0xCCC300000000818BLL )
{ {
uint32_t off1 = (funcDt>>16) & 0xffff; uint32_t off1 = (funcDt>>16) & 0xffff;
typeD = p->readDWord(p_items[i] + off1); typeD = p->readWord(p_items[i] + off1);
} }
else if ( (funcDt&0xFFFFFF0000FFFFFFLL) == 0xC30000000081BF0FLL ) else if ( (funcDt&0xFFFFFF0000FFFFFFLL) == 0xC30000000081BF0FLL )
{ {
uint32_t off1 = (funcDt>>24) & 0xffff; uint32_t off1 = (funcDt>>24) & 0xffff;
typeD = (int16_t) p->readWord(p_items[i] + off1); typeD = p->readWord(p_items[i] + off1);
}
else if ( (funcDt&0x000000FF00FFFFFFLL) == 0x000000C30041BF0FLL )
{
uint32_t off1 = (funcDt>>24) & 0xff;
typeD = p->readWord(p_items[i] + off1);
}
else if ( (funcDt&0x000000FF00FFFFFFLL) == 0x000000C300418B66LL )
{
uint32_t off1 = (funcDt>>24) & 0xff;
typeD = p->readWord(p_items[i] + off1);
}
else if ( (funcDt&0x00000000FF00FFFFLL) == 0x00000000C300418BLL )
{
uint32_t off1 = (funcDt>>16) & 0xff;
typeD = p->readDWord(p_items[i] + off1);
} }
else else
printf("bad typeD func @%p\n", (void*) funcD); printf("bad typeD func @%p\n", (void*) funcD);
@ -155,8 +195,8 @@ int main ()
{ {
bool sep = false; bool sep = false;
printf("\tdeco=["); printf("\tdeco=[");
uint32_t decStart = p->readDWord(p_items[i] + 0xAC); uint32_t decStart = p->readDWord(p_items[i] + 0x90); // 0xAC pre .13
uint32_t decEnd = p->readDWord(p_items[i] + 0xB0); uint32_t decEnd = p->readDWord(p_items[i] + 0x94); // 0xB0 pre .13
if (decStart != decEnd) if (decStart != decEnd)
{ {
for (j=decStart;j<decEnd;j+=4) for (j=decStart;j<decEnd;j+=4)

@ -24,19 +24,14 @@ TARGET_LINK_LIBRARIES(dfdigger dfhack)
ADD_EXECUTABLE(dfdigger2 digger2.cpp) ADD_EXECUTABLE(dfdigger2 digger2.cpp)
TARGET_LINK_LIBRARIES(dfdigger2 dfhack) TARGET_LINK_LIBRARIES(dfdigger2 dfhack)
ADD_EXECUTABLE(primitives primitives.cpp)
# itemdesignator - change some item designations (dump, forbid, on-fire) for all # itemdesignator - change some item designations (dump, forbid, on-fire) for all
# items of a given type and material # items of a given type and material
# Author: belal # Author: belal
#ADD_EXECUTABLE(dfitemdesignator itemdesignator.cpp) #ADD_EXECUTABLE(dfitemdesignator itemdesignator.cpp)
#TARGET_LINK_LIBRARIES(dfitemdesignator dfhack) #TARGET_LINK_LIBRARIES(dfitemdesignator dfhack)
# incrementalsearch - a bit like cheat engine, only DF-specific, very basic
# and Linux-only
IF(UNIX)
ADD_EXECUTABLE(dfincremental incrementalsearch.cpp)
TARGET_LINK_LIBRARIES(dfincremental dfhack)
ENDIF(UNIX)
# catsplosion - Accelerates pregnancy # catsplosion - Accelerates pregnancy
# Author: Zhentar # Author: Zhentar
ADD_EXECUTABLE(dfcatsplosion catsplosion.cpp) ADD_EXECUTABLE(dfcatsplosion catsplosion.cpp)
@ -60,6 +55,38 @@ TARGET_LINK_LIBRARIES(dfcatsplosion dfhack)
ADD_EXECUTABLE(dfcopypaste copypaste.cpp) ADD_EXECUTABLE(dfcopypaste copypaste.cpp)
TARGET_LINK_LIBRARIES(dfcopypaste dfhack) TARGET_LINK_LIBRARIES(dfcopypaste dfhack)
# paths
# Author: belal
# dumps the current path to the DF exe, as well as the relative paths to the
# current tileset and color files
ADD_EXECUTABLE(dfpaths paths.cpp)
TARGET_LINK_LIBRARIES(dfpaths dfhack)
# deramp
# Author: zilpin
# seeks entire map for 'remove ramp' designation, makes a floor, removes designation.
# intended use is to simulate old 'channel' functionality.
ADD_EXECUTABLE(dfderamp deramp.cpp)
TARGET_LINK_LIBRARIES(dfderamp dfhack)
# printtiletypes
# Author: zilpin
# Prints CSV dump of all tile type information.
# No DF process needed. Intended only for debugging and information purposes.
ADD_EXECUTABLE(dfprinttiletypes printtiletypes.cpp)
TARGET_LINK_LIBRARIES(dfprinttiletypes dfhack)
# hellhole
# Author: zilpin
# Creates a bottomless hole to hell.
# Experimental version hard-codes values.
# Will have many options in the future.
ADD_EXECUTABLE(dfhellhole hellhole.cpp)
TARGET_LINK_LIBRARIES(dfhellhole dfhack)
# this needs the C bindings # this needs the C bindings
IF(BUILD_DFHACK_C_BINDINGS) IF(BUILD_DFHACK_C_BINDINGS)
# for trying out some 'stuff' # for trying out some 'stuff'
@ -76,11 +103,8 @@ dfmoodump
dfdigger dfdigger
dfdigger2 dfdigger2
dfcatsplosion dfcatsplosion
dfderamp
dfprinttiletypes
dfhellhole
RUNTIME DESTINATION bin RUNTIME DESTINATION bin
) )
IF(UNIX)
install(TARGETS
dfincremental
RUNTIME DESTINATION bin
)
ENDIF(UNIX)

@ -0,0 +1,137 @@
// De-ramp. All ramps marked for removal are replaced with given tile (presently, normal floor).
#include <iostream>
#include <vector>
#include <map>
#include <stddef.h>
#include <assert.h>
#include <string.h>
using namespace std;
#include <DFHack.h>
#include <dfhack/DFTileTypes.h>
int main (void)
{
uint32_t x_max,y_max,z_max;
uint32_t num_blocks = 0;
uint32_t bytes_read = 0;
DFHack::designations40d designations;
DFHack::tiletypes40d tiles;
DFHack::tiletypes40d tilesAbove;
//DFHack::TileRow *ptile;
int32_t oldT, newT;
int16_t t;
int dirty=0, count=0;
DFHack::ContextManager DFMgr("Memory.xml");
DFHack::Context *DF = DFMgr.getSingleContext();
//sanity check
assert( sizeof(designations) == (16*16*sizeof(DFHack::t_designation)) );
//Init
try
{
DF->Attach();
}
catch (exception& e)
{
cerr << e.what() << endl;
#ifndef LINUX_BUILD
cin.ignore();
#endif
return 1;
}
DFHack::Maps *Mapz = DF->getMaps();
// init the map
if (!Mapz->Start())
{
cerr << "Can't init map." << endl;
#ifndef LINUX_BUILD
cin.ignore();
#endif
return 1;
}
Mapz->getSize(x_max,y_max,z_max);
uint8_t zeroes [16][16] = {0};
// walk the map
for (uint32_t x = 0; x< x_max;x++)
{
for (uint32_t y = 0; y< y_max;y++)
{
for (uint32_t z = 0; z< z_max;z++)
{
if (Mapz->isValidBlock(x,y,z))
{
dirty=0;
Mapz->ReadDesignations(x,y,z, &designations);
Mapz->ReadTileTypes(x,y,z, &tiles);
if (Mapz->isValidBlock(x,y,z+1))
{
Mapz->ReadTileTypes(x,y,z+1, &tilesAbove);
}
else
{
memset(&tilesAbove,0,sizeof(tilesAbove));
}
for (uint32_t ty=0;ty<16;++ty)
{
for (uint32_t tx=0;tx<16;++tx)
{
//Only the remove ramp designation (ignore channel designation, etc)
oldT = tiles[tx][ty];
if ( DFHack::designation_default == designations[tx][ty].bits.dig
&& DFHack::RAMP==DFHack::tileTypeTable[oldT].c)
{
//Current tile is a ramp.
//Set current tile, as accurately as can be expected
newT = DFHack::findSimilarTileType(oldT,DFHack::FLOOR);
//If no change, skip it (couldn't find a good tile type)
if ( oldT == newT) continue;
//Set new tile type, clear designation
tiles[tx][ty] = newT;
designations[tx][ty].bits.dig = DFHack::designation_no;
//Check the tile above this one, in case a downward slope needs to be removed.
if ( DFHack::RAMP_TOP == DFHack::tileTypeTable[tilesAbove[tx][ty]].c )
{
tilesAbove[tx][ty] = 32;
}
dirty=-1;
++count;
}
}
}
//If anything was changed, write it all.
if (dirty)
{
Mapz->WriteDesignations(x,y,z, &designations);
Mapz->WriteTileTypes(x,y,z, &tiles);
if (Mapz->isValidBlock(x,y,z+1))
{
Mapz->WriteTileTypes(x,y,z+1, &tilesAbove);
}
}
}
}
}
}
DF->Detach();
cout << "Found and changed " << count << " tiles." << endl;
#ifndef LINUX_BUILD
cout << "Done. Press any key to continue" << endl;
cin.ignore();
#endif
return 0;
}

@ -21,7 +21,6 @@
#include <assert.h> #include <assert.h>
using namespace std; using namespace std;
#include <argstream.h>
#include <DFHack.h> #include <DFHack.h>
#include <dfhack/DFTileTypes.h> #include <dfhack/DFTileTypes.h>
#define BLOCK_SIZE 16 #define BLOCK_SIZE 16

File diff suppressed because it is too large Load Diff

@ -0,0 +1,31 @@
#include <iostream>
using namespace std;
#include <DFHack.h>
using namespace DFHack;
int main ()
{
DFHack::ContextManager DFMgr("Memory.xml");
DFHack::Context *DF = DFMgr.getSingleContext();
try
{
DF->Attach();
}
catch (exception& e)
{
cerr << e.what() << endl;
#ifndef LINUX_BUILD
cin.ignore();
#endif
return 1;
}
DFHack::Process * Process = DF->getProcess();
DFHack::Gui * gui = DF->getGui();
cout << Process->getPath() << endl;
#ifndef LINUX_BUILD
cout << "Done. Press any key to continue" << endl;
cin.ignore();
#endif
return 0;
}

@ -0,0 +1,27 @@
#include <iostream>
#include <iomanip>
#include <climits>
#include <vector>
#include <sstream>
#include <ctime>
#include <cstdio>
using namespace std;
std::string teststr1;
std::string * teststr2;
std::string teststr3("test");
int main (int numargs, const char ** args)
{
printf("std::string E : 0x%x\n", &teststr1);
teststr1 = "This is a fairly long string, much longer than the one made by default constructor.";
cin.ignore();
printf("std::string L : 0x%x\n", &teststr1);
teststr1 = "This one is shorter";
cin.ignore();
printf("std::string S : 0x%x\n", &teststr1);
cin.ignore();
teststr2 = new string();
printf("std::string * : 0x%x\n", &teststr2);
printf("std::string(\"test\") : 0x%x\n", &teststr3);
cin.ignore();
return 0;
}

@ -0,0 +1,100 @@
// Prints all the Tile Types known by DFHack.
// File is both fixed-field and CSV parsable.
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <vector>
#include <map>
#include <stddef.h>
#include <assert.h>
using namespace std;
#include <DFHack.h>
#include <dfhack/DFTileTypes.h>
using namespace DFHack;
int main (int argc, char **argv)
{
FILE *f=stdout;
const int Columns = 7;
const char * Headings[Columns] = {"TileTypeID","Class","Material","V","Special","Direction","Description"};
size_t Size[ Columns ] = {};
int i;
//First, figure out column widths.
for(i=0;i<Columns;++i)
{
Size[i]=strlen(Headings[i])+1;
}
//Classes
fprintf(f,"\nTile Type Classes:\n");
for(i=0;i<tileclass_count;++i)
{
Size[1]=max<size_t>(Size[1],strlen(TileClassString[i]));
fprintf(f,"%4i ; %s\n", i, TileClassString[i] ,0 );
}
//Materials
fprintf(f,"\nTile Type Materials:\n");
for(i=0;i<tilematerial_count;++i)
{
Size[2]=max<size_t>(Size[2],strlen(TileMaterialString[i]));
fprintf(f,"%4i ; %s\n", i, TileMaterialString[i] ,0 );
}
//Specials
fprintf(f,"\nTile Type Specials:\n");
for(i=0;i<tilespecial_count;++i)
{
Size[4]=max<size_t>(Size[4],strlen(TileSpecialString[i]));
fprintf(f,"%4i ; %s\n", i, TileSpecialString[i] ,0 );
}
/* - Not needed for now -
//Direction is tricky
for(i=0;i<TILE_TYPE_ARRAY_LENGTH;++i)
Size[5]=max(Size[5], tileTypeTable[i].d.sum()+1 );
*/
//Print the headings first.
fprintf(f,"\nTile Types:\n");
for(i=0;i<Columns;++i)
{
if(i) putc(';',f);
fprintf(f," %-*s ",Size[i],Headings[i],0);
}
fprintf(f,"\n");
//Process the whole array.
//A macro should be used for making the strings safe, but they are left in naked ? blocks
//to illustrate the array references more clearly.
for(i=0;i<TILE_TYPE_ARRAY_LENGTH;++i)
{
fprintf(f," %*i ; %-*s ; %-*s ; %*c ; %-*s ; %-*s ; %s\n",
Size[0], i,
Size[1], ( tileTypeTable[i].name ? TileClassString[ tileTypeTable[i].c ] : "" ),
Size[2], ( tileTypeTable[i].name ? TileMaterialString[ tileTypeTable[i].m ] : "" ),
Size[3], ( tileTypeTable[i].v ? '0'+tileTypeTable[i].v : ' ' ),
Size[4], ( tileTypeTable[i].s ? TileSpecialString[ tileTypeTable[i].s ] : "" ),
Size[5], ( tileTypeTable[i].d.whole ? tileTypeTable[i].d.getStr() : "" ),
( tileTypeTable[i].name ? tileTypeTable[i].name : "" ),
0
);
}
fprintf(f,"\n");
#ifndef LINUX_BUILD
if( 1== argc)
{
cout << "Done. Press any key to continue" << endl;
cin.ignore();
}
#endif
return 0;
}

@ -449,7 +449,7 @@ start:
uint32_t nickname = mem->getOffset("creature_name") + mem->getOffset("name_nickname"); uint32_t nickname = mem->getOffset("creature_name") + mem->getOffset("name_nickname");
p->writeSTLString(toChange.origin+nickname,changeString); p->writeSTLString(toChange.origin+nickname,changeString);
} }
catch (DFHack::Error::MissingMemoryDefinition&) catch (DFHack::Error::AllMemdef&)
{ {
cerr << "Writing creature nicknames unsupported in this version!" << endl; cerr << "Writing creature nicknames unsupported in this version!" << endl;
} }
@ -461,7 +461,7 @@ start:
uint32_t custom_prof = mem->getOffset("creature_custom_profession"); uint32_t custom_prof = mem->getOffset("creature_custom_profession");
p->writeSTLString(toChange.origin+custom_prof,changeString); p->writeSTLString(toChange.origin+custom_prof,changeString);
} }
catch (DFHack::Error::MissingMemoryDefinition&) catch (DFHack::Error::AllMemdef&)
{ {
cerr << "Writing creature custom profession unsupported in this version!" << endl; cerr << "Writing creature custom profession unsupported in this version!" << endl;
} }

@ -9,6 +9,10 @@ ENDIF(UNIX)
ADD_EXECUTABLE(dfreveal reveal.cpp) ADD_EXECUTABLE(dfreveal reveal.cpp)
TARGET_LINK_LIBRARIES(dfreveal dfhack) TARGET_LINK_LIBRARIES(dfreveal dfhack)
# force pause!
ADD_EXECUTABLE(dfpause forcepause.cpp)
TARGET_LINK_LIBRARIES(dfpause dfhack)
# prospector - produces a list of available materials and their quantities # prospector - produces a list of available materials and their quantities
ADD_EXECUTABLE(dfprospector prospector.cpp) ADD_EXECUTABLE(dfprospector prospector.cpp)
TARGET_LINK_LIBRARIES(dfprospector dfhack) TARGET_LINK_LIBRARIES(dfprospector dfhack)
@ -68,6 +72,12 @@ TARGET_LINK_LIBRARIES(dfdoffsets dfhack)
ADD_EXECUTABLE(dfweather weather.cpp) ADD_EXECUTABLE(dfweather weather.cpp)
TARGET_LINK_LIBRARIES(dfweather dfhack) TARGET_LINK_LIBRARIES(dfweather dfhack)
# incrementalsearch - a bit like cheat engine, only DF-specific, very basic
ADD_EXECUTABLE(dfautosearch autosearch.cpp)
TARGET_LINK_LIBRARIES(dfautosearch dfhack)
ADD_EXECUTABLE(dfincremental incrementalsearch.cpp)
TARGET_LINK_LIBRARIES(dfincremental dfhack)
IF(UNIX) IF(UNIX)
SET(VEINLOOK_BUILT "NO") SET(VEINLOOK_BUILT "NO")
@ -113,6 +123,7 @@ dfvdig
dfcleanmap dfcleanmap
dfunstuck dfunstuck
dfprobe dfprobe
dfpause
dfdoffsets dfdoffsets
dfattachtest dfattachtest
dfcleartask dfcleartask
@ -121,5 +132,7 @@ dfsuspend
dfflows dfflows
dfliquids dfliquids
dfweather dfweather
dfautosearch
dfincremental
RUNTIME DESTINATION bin RUNTIME DESTINATION bin
) )

@ -1,5 +1,8 @@
#ifndef SEGMENTED_FINDER_H #ifndef SEGMENTED_FINDER_H
#define SEGMENTED_FINDER_H #define SEGMENTED_FINDER_H
#include <malloc.h>
#include <iosfwd>
#include <iterator>
class SegmentedFinder; class SegmentedFinder;
class SegmentFinder class SegmentFinder
@ -9,18 +12,37 @@ class SegmentFinder
{ {
_DF = DF; _DF = DF;
mr_ = mr; mr_ = mr;
mr_.buffer = (uint8_t *)malloc (mr_.end - mr_.start); if(mr.valid)
DF->ReadRaw(mr_.start,(mr_.end - mr_.start),mr_.buffer); {
_SF = SF; mr_.buffer = (uint8_t *)malloc (mr_.end - mr_.start);
_SF = SF;
try
{
DF->ReadRaw(mr_.start,(mr_.end - mr_.start),mr_.buffer);
valid = true;
}
catch (DFHack::Error::MemoryAccessDenied &)
{
free(mr_.buffer);
valid = false;
mr.valid = false; // mark the range passed in as bad
cout << "Range 0x" << hex << mr_.start << " - 0x" << mr_.end << dec << " not readable." << endl;
}
}
} }
~SegmentFinder() ~SegmentFinder()
{ {
delete mr_.buffer; if(valid)
free(mr_.buffer);
}
bool isValid()
{
return valid;
} }
template <class needleType, class hayType, typename comparator > template <class needleType, class hayType, typename comparator >
bool Find (needleType needle, const uint8_t increment , vector <uint64_t> &newfound, comparator oper) bool Find (needleType needle, const uint8_t increment , vector <uint64_t> &newfound, comparator oper)
{ {
if(!valid) return !newfound.empty();
//loop //loop
for(uint64_t offset = 0; offset < (mr_.end - mr_.start) - sizeof(hayType); offset += increment) for(uint64_t offset = 0; offset < (mr_.end - mr_.start) - sizeof(hayType); offset += increment)
{ {
@ -33,6 +55,7 @@ class SegmentFinder
template < class needleType, class hayType, typename comparator > template < class needleType, class hayType, typename comparator >
uint64_t FindInRange (needleType needle, comparator oper, uint64_t start, uint64_t length) uint64_t FindInRange (needleType needle, comparator oper, uint64_t start, uint64_t length)
{ {
if(!valid) return 0;
uint64_t stopper = min((mr_.end - mr_.start) - sizeof(hayType), (start - mr_.start) - sizeof(hayType) + length); uint64_t stopper = min((mr_.end - mr_.start) - sizeof(hayType), (start - mr_.start) - sizeof(hayType) + length);
//loop //loop
for(uint64_t offset = start - mr_.start; offset < stopper; offset +=1) for(uint64_t offset = start - mr_.start; offset < stopper; offset +=1)
@ -46,6 +69,7 @@ class SegmentFinder
template <class needleType, class hayType, typename comparator > template <class needleType, class hayType, typename comparator >
bool Filter (needleType needle, vector <uint64_t> &found, vector <uint64_t> &newfound, comparator oper) bool Filter (needleType needle, vector <uint64_t> &found, vector <uint64_t> &newfound, comparator oper)
{ {
if(!valid) return !newfound.empty();
for( uint64_t i = 0; i < found.size(); i++) for( uint64_t i = 0; i < found.size(); i++)
{ {
if(mr_.isInRange(found[i])) if(mr_.isInRange(found[i]))
@ -62,6 +86,7 @@ class SegmentFinder
SegmentedFinder * _SF; SegmentedFinder * _SF;
DFHack::Context * _DF; DFHack::Context * _DF;
DFHack::t_memrange mr_; DFHack::t_memrange mr_;
bool valid;
}; };
class SegmentedFinder class SegmentedFinder
@ -286,15 +311,207 @@ bool vectorAll (SegmentedFinder* s, vecTriplet *x, int )
return false; return false;
} }
struct Bytestream class Bytestreamdata
{ {
uint32_t length; public:
void * object; void * object;
uint32_t length;
uint32_t allocated;
uint32_t n_used;
}; };
class Bytestream
{
public:
Bytestream(void * obj, uint32_t len, bool alloc = false)
{
d = new Bytestreamdata();
d->allocated = alloc;
d->object = obj;
d->length = len;
d->n_used = 1;
constant = false;
}
Bytestream()
{
d = new Bytestreamdata();
d->allocated = false;
d->object = 0;
d->length = 0;
d->n_used = 1;
constant = false;
}
Bytestream( Bytestream & bs)
{
d =bs.d;
d->n_used++;
constant = false;
}
Bytestream( const Bytestream & bs)
{
d =bs.d;
d->n_used++;
constant = true;
}
~Bytestream()
{
d->n_used --;
if(d->allocated && d->object && d->n_used == 0)
{
free (d->object);
free (d);
}
}
bool Allocate(size_t bytes)
{
if(constant)
return false;
if(d->allocated)
{
d->object = realloc(d->object, bytes);
}
else
{
d->object = malloc( bytes );
}
if(d->object)
{
d->allocated = bytes;
return true;
}
else
{
d->allocated = 0;
return false;
}
}
template < class T >
bool insert( T what )
{
if(constant)
return false;
if(d->length+sizeof(T) >= d->allocated)
Allocate((d->length+sizeof(T)) * 2);
(*(T *)( (uint64_t)d->object + d->length)) = what;
d->length += sizeof(T);
return true;
}
Bytestreamdata * d;
bool constant;
};
std::ostream& operator<< ( std::ostream& out, Bytestream& bs )
{
if(bs.d->object)
{
out << "bytestream " << dec << bs.d->length << "/" << bs.d->allocated << " bytes" << endl;
for(int i = 0; i < bs.d->length; i++)
{
out << hex << (int) ((uint8_t *) bs.d->object)[i] << " ";
}
out << endl;
}
else
{
out << "empty bytestresm" << endl;
}
return out;
}
std::istream& operator>> ( std::istream& out, Bytestream& bs )
{
string read;
while(!out.eof())
{
string tmp;
out >> tmp;
read.append(tmp);
}
cout << read << endl;
bs.d->length = 0;
size_t first = read.find_first_of("\"");
size_t last = read.find_last_of("\"");
size_t start = first + 1;
if(first == read.npos)
{
std::transform(read.begin(), read.end(), read.begin(), (int(*)(int)) tolower);
bs.Allocate(read.size()); // overkill. size / 2 should be good, but this is safe
int state = 0;
char big = 0;
char small = 0;
string::iterator it = read.begin();
// iterate through string, construct a bytestream out of 00-FF bytes
while(it != read.end())
{
char reads = *it;
if((reads >='0' && reads <= '9'))
{
if(state == 0)
{
big = reads - '0';
state = 1;
}
else if(state == 1)
{
small = reads - '0';
state = 0;
bs.insert<char>(big*16 + small);
}
}
if((reads >= 'a' && reads <= 'f'))
{
if(state == 0)
{
big = reads - 'a' + 10;
state = 1;
}
else if(state == 1)
{
small = reads - 'a' + 10;
state = 0;
bs.insert<char>(big*16 + small);
}
}
it++;
}
// we end in state= 1. should we add or should we trim... or throw errors?
// I decided on adding
if (state == 1)
{
small = 0;
bs.insert<char>(big*16 + small);
}
}
else
{
if(last == first)
{
// only one "
last = read.size();
}
size_t length = last - start;
// construct bytestream out of stuff between ""
bs.d->length = length;
if(length)
{
// todo: Bytestream should be able to handle this without external code
bs.Allocate(length);
bs.d->length = length;
const char* strstart = read.c_str();
memcpy(bs.d->object, strstart + start, length);
}
else
{
bs.d->object = 0;
}
}
cout << bs;
return out;
}
bool findBytestream (SegmentedFinder* s, void *addr, Bytestream compare ) bool findBytestream (SegmentedFinder* s, void *addr, Bytestream compare )
{ {
if(memcmp(addr, compare.object, compare.length) == 0) if(memcmp(addr, compare.d->object, compare.d->length) == 0)
return true; return true;
return false; return false;
} }

@ -0,0 +1,782 @@
// this is an incremental search tool. It only works on Linux.
// here be dragons... and ugly code :P
#include <iostream>
#include <climits>
#include <vector>
#include <map>
#include <set>
#include <list>
#include <ctime>
#include <string.h>
#include <stdio.h>
#include <algorithm>
using namespace std;
#ifndef LINUX_BUILD
#define WINVER 0x0500
// this one prevents windows from infecting the global namespace with filth
#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
#include <DFHack.h>
#include "SegmentedFinder.h"
class Token
{
public:
Token(uint64_t _offset)
{
offset = _offset;
offset_valid = 1;
value_valid = 0;
parent = 0;
}
Token(const std::string & offsetn)
{
full_offset_name = offsetn;
offset_valid = 0;
value_valid = 0;
parent = 0;
}
Token()
{
offset_valid = 0;
value_valid = 0;
parent = 0;
}
virtual ~Token(){};
virtual bool LoadData(SegmentedFinder * s) = 0;
virtual void EmptyData()
{
value_valid = false;
};
virtual bool Match(SegmentedFinder * s, uint64_t offset) = 0;
virtual void EmptyOffset()
{
offset_valid = false;
};
virtual bool AcquireOffset(DFHack::VersionInfo * vinfo)
{
vinfo->getOffset(full_offset_name);
return true;
}
virtual uint32_t Length() = 0;
virtual uint64_t getAbsolute(){if(parent) return parent->getAbsolute() + offset; else return offset;};
void setParent( Token *par )
{
par = parent;
}
protected:
uint64_t offset;// offset from the start of the parent token
std::string full_offset_name;
Token * parent;
bool offset_valid :1;
bool value_valid :1;
};
class Byte: virtual public Token
{
public:
Byte(uint64_t _offset):Token(_offset){};
Byte():Token(){};
~Byte();
virtual bool LoadData(SegmentedFinder * s)
{
if(offset_valid)
{
char * ptr = s->Translate<char>(getAbsolute());
if(ptr)
{
value = *ptr;
value_valid = true;
return true;
}
}
return false;
};
// is the loaded data same as data at offset? yes -> set our offset to that.
virtual bool Match(SegmentedFinder * s, uint64_t offs)
{
if(value_valid && (*s->Translate<char>(parent->getAbsolute() + offset)) == value )
{
if(parent)
offset = offs - parent->getAbsolute();
else
offset = offs;
return true;
}
return false;
};
virtual uint32_t Length()
{
return 1;
};
private:
char value;
};
class Short: virtual public Token
{
public:
Short(uint64_t _offset):Token(_offset){};
Short():Token(){};
~Short();
virtual bool LoadData(SegmentedFinder * s)
{
if(offset_valid)
{
uint16_t * ptr = s->Translate<uint16_t>(getAbsolute());
if(ptr)
{
value = *ptr;
value_valid = true;
return true;
}
}
return false;
};
// is the loaded data same as data at offset? yes -> set our offset to that.
virtual bool Match(SegmentedFinder * s, uint64_t offs)
{
if(value_valid && (*s->Translate<uint16_t>(parent->getAbsolute() + offset)) == value )
{
if(parent)
offset = offs - parent->getAbsolute();
else
offset = offs;
return true;
}
return false;
};
virtual uint32_t Length()
{
return 2;
};
private:
uint16_t value;
};
class Long: virtual public Token
{
public:
Long(uint64_t _offset):Token(_offset){};
Long():Token(){};
~Long();
virtual bool LoadData(SegmentedFinder * s)
{
if(offset_valid)
{
uint32_t * ptr = s->Translate<uint32_t>(getAbsolute());
if(ptr)
{
value = *ptr;
value_valid = true;
return true;
}
}
return false;
};
// is the loaded data same as data at offset? yes -> set our offset to that.
virtual bool Match(SegmentedFinder * s, uint64_t offs)
{
if(value_valid && (*s->Translate<uint32_t>(offs)) == value )
{
if(parent)
offset = offs - parent->getAbsolute();
else
offset = offs;
return true;
}
return false;
};
virtual uint32_t Length(){return 4;};
private:
uint32_t value;
};
class PtrVector : virtual public Token
{
public:
PtrVector(uint64_t _offset):Token(_offset){};
PtrVector():Token(){};
~PtrVector();
virtual uint32_t Length(){return 12;};
private:
vector <uint64_t> value;
};
class Pointer: virtual public Token
{
public:
Pointer(uint64_t _offset):Token(_offset){};
Pointer():Token(){};
~Pointer();
virtual uint32_t Length(){return 4;};
private:
uint64_t value;
};
class String: virtual public Token
{
protected:
string value;
};
class Struct: virtual public Token
{
public:
Struct(uint64_t _offset):Token(_offset){};
Struct():Token(){};
~Struct(){};
void Add( Token * t ){members.push_back(t);};
virtual uint32_t Length(){return 0;}; // FIXME: temporary solution, should be the minimal length of all the contents combined
virtual bool LoadData(SegmentedFinder* s)
{
bool OK = true;
for(int i = 0; i < members.size() && OK; i++)
OK &= members[i]->LoadData(s);
return OK;
};
// TODO: IMPLEMENT!
virtual bool Match(SegmentedFinder* s, uint64_t offset)
{
return false;
}
private:
vector<Token*> members;
};
class LinuxString: virtual public String
{
public:
LinuxString(uint64_t _offset):Token(_offset){};
LinuxString():Token(){};
~LinuxString(){};
virtual uint32_t Length(){return 4;};
virtual bool LoadData(SegmentedFinder* s)
{
return false;
}
virtual bool Match(SegmentedFinder* s, uint64_t offset)
{
return false;
}
/*
// read string pointer, translate to local scheme
char *str = sf->Translate<char>(*offset);
// verify
if(!str)
return false;
uint32_t length = *(uint32_t *)(offset - 12);
uint32_t capacity = *(uint32_t *)(offset - 8);
if(length > capacity)
return false;
//char * temp = new char[length+1];
// read data from inside the string structure
//memcpy(temp, str,length + 1);
output = str;
return true;
*/
};
class WindowsString: virtual public String
{
public:
WindowsString(uint64_t _offset):Token(_offset){};
WindowsString():Token(){};
~WindowsString(){};
virtual uint32_t Length(){return 0x1C;}; // FIXME: pouzivat Memory.xml?
virtual bool LoadData(SegmentedFinder* s)
{
return false;
}
virtual bool Match(SegmentedFinder* s, uint64_t offset)
{
return false;
}
string rdWinString( char * offset, SegmentedFinder & sf )
{
char * start_offset = offset + 4; // FIXME: pouzivat Memory.xml?
uint32_t length = *(uint32_t *)(offset + 20); // FIXME: pouzivat Memory.xml?
uint32_t capacity = *(uint32_t *)(offset + 24); // FIXME: pouzivat Memory.xml?
char * temp = new char[capacity+1];
// read data from inside the string structure
if(capacity < 16)
{
memcpy(temp, start_offset,capacity);
//read(start_offset, capacity, (uint8_t *)temp);
}
else // read data from what the offset + 4 dword points to
{
start_offset = sf.Translate<char>(*(uint32_t*)start_offset);
memcpy(temp, start_offset,capacity);
}
temp[length] = 0;
string ret = temp;
delete temp;
return ret;
}
};
inline void printRange(DFHack::t_memrange * tpr)
{
std::cout << std::hex << tpr->start << " - " << tpr->end << "|" << (tpr->read ? "r" : "-") << (tpr->write ? "w" : "-") << (tpr->execute ? "x" : "-") << "|" << tpr->name << std::endl;
}
bool getRanges(DFHack::Process * p, vector <DFHack::t_memrange>& selected_ranges)
{
vector <DFHack::t_memrange> ranges;
selected_ranges.clear();
p->getMemRanges(ranges);
cout << "Which range to search? (default is 1-4)" << endl;
for(int i = 0; i< ranges.size();i++)
{
cout << dec << "(" << i << ") ";
printRange(&(ranges[i]));
}
int start, end;
while(1)
{
string select;
cout << ">>";
std::getline(cin, select);
if(select.empty())
{
// empty input, assume default. observe the length of the memory range vector
// these are hardcoded values, intended for my convenience only
if(p->getDescriptor()->getOS() == DFHack::OS_WINDOWS)
{
start = min(11, (int)ranges.size());
end = min(14, (int)ranges.size());
}
else if(p->getDescriptor()->getOS() == DFHack::OS_LINUX)
{
start = min(2, (int)ranges.size());
end = min(4, (int)ranges.size());
}
else
{
start = 1;
end = 1;
}
break;
}
// I like the C variants here. much less object clutter
else if(sscanf(select.c_str(), "%d-%d", &start, &end) == 2)
{
start = min(start, (int)ranges.size());
end = min(end, (int)ranges.size());
break;
}
else
{
continue;
}
break;
}
end++;
cout << "selected ranges:" <<endl;
vector <DFHack::t_memrange>::iterator it;
it = ranges.begin() + start;
while (it != ranges.begin() + end)
{
// check if readable
if((*it).read)
{
selected_ranges.push_back(*it);
printRange(&*it);
}
it++;
}
return true;
}
bool getNumber (string prompt, int & output, int def, bool pdef = true)
{
cout << prompt;
if(pdef)
cout << " default=" << def << endl;
while (1)
{
string select;
cout << ">>";
std::getline(cin, select);
if(select.empty())
{
output = def;
break;
}
else if( sscanf(select.c_str(), "%d", &output) == 1 )
{
break;
}
else
{
continue;
}
}
return true;
}
bool getString (string prompt, string & output)
{
cout << prompt;
cout << ">>";
string select;
std::getline(cin, select);
if(select.empty())
{
return false;
}
else
{
output = select;
return true;
}
}
// meh
#pragma pack(1)
struct tilecolors
{
uint16_t fore;
uint16_t back;
uint16_t bright;
};
#pragma pack()
void printFound(vector <uint64_t> &found, const char * what)
{
cout << what << ":" << endl;
for(int i = 0; i < found.size();i++)
{
cout << hex << "0x" << found[i] << endl;
}
}
void printFoundStrVec(vector <uint64_t> &found, const char * what, SegmentedFinder & s)
{
cout << what << ":" << endl;
for(int i = 0; i < found.size();i++)
{
cout << hex << "0x" << found[i] << endl;
cout << "--------------------------" << endl;
vecTriplet * vt = s.Translate<vecTriplet>(found[i]);
if(vt)
{
int j = 0;
for(uint32_t idx = vt->start; idx < vt->finish; idx += sizeof(uint32_t))
{
uint32_t object_ptr;
// deref ptr idx, get ptr to object
if(!s.Read(idx,object_ptr))
{
cout << "BAD!" << endl;
break;
}
// deref ptr to first object, get ptr to string
uint32_t string_ptr;
if(!s.Read(object_ptr,string_ptr))
{
cout << "BAD!" << endl;
break;
}
// get string location in our local cache
char * str = s.Translate<char>(string_ptr);
if(!str)
{
cout << "BAD!" << endl;
break;
}
cout << dec << j << ":" << hex << "0x" << object_ptr << " : " << str << endl;
j++;
}
}
else
{
cout << "BAD!" << endl;
break;
}
cout << "--------------------------" << endl;
}
}
class TokenFactory
{
DFHack::OSType platform;
public:
TokenFactory(DFHack::OSType platform_in)
{
platform = platform_in;
}
template <class T>
T * Build()
{
return new T;
}
template <class T>
T * Build(uint64_t offset)
{
return new T(offset);
}
};
template <>
String * TokenFactory::Build()
{
switch(platform)
{
case DFHack::OS_WINDOWS:
return new WindowsString();
case DFHack::OS_LINUX:
case DFHack::OS_APPLE:
return new LinuxString();
}
return 0;
};
template <>
String * TokenFactory::Build(uint64_t offset)
{
switch(platform)
{
case DFHack::OS_WINDOWS:
return new WindowsString(offset);
case DFHack::OS_LINUX:
case DFHack::OS_APPLE:
return new LinuxString(offset);
}
return 0;
};
void autoSearch(DFHack::Context * DF, vector <DFHack::t_memrange>& ranges, DFHack::OSType platform)
{
cout << "stealing memory..." << endl;
SegmentedFinder sf(ranges, DF);
TokenFactory tf(platform);
cout << "done!" << endl;
Struct maps;
maps.Add(tf.Build<String>());
maps.Add(tf.Build<String>());
/*
vector <uint64_t> allVectors;
vector <uint64_t> filtVectors;
vector <uint64_t> to_filter;
cout << "stealing memory..." << endl;
SegmentedFinder sf(ranges, DF);
cout << "looking for vectors..." << endl;
sf.Find<int ,vecTriplet>(0,4,allVectors, vectorAll);
filtVectors = allVectors;
cout << "-------------------" << endl;
cout << "!!LANGUAGE TABLES!!" << endl;
cout << "-------------------" << endl;
uint64_t kulet_vector;
uint64_t word_table_offset;
uint64_t DWARF_vector;
uint64_t DWARF_object;
// find lang vector (neutral word table)
to_filter = filtVectors;
sf.Filter<const char * ,vecTriplet>("ABBEY",to_filter, vectorStringFirst);
uint64_t lang_addr = to_filter[0];
// find dwarven language word table
to_filter = filtVectors;
sf.Filter<const char * ,vecTriplet>("kulet",to_filter, vectorStringFirst);
kulet_vector = to_filter[0];
// find vector of languages
to_filter = filtVectors;
sf.Filter<const char * ,vecTriplet>("DWARF",to_filter, vectorStringFirst);
// verify
for(int i = 0; i < to_filter.size(); i++)
{
vecTriplet * vec = sf.Translate<vecTriplet>(to_filter[i]);
if(((vec->finish - vec->start) / 4) == 4) // verified
{
DWARF_vector = to_filter[i];
DWARF_object = sf.Read<uint32_t>(vec->start);
// compute word table offset from dwarf word table and dwarf language object addresses
word_table_offset = kulet_vector - DWARF_object;
break;
}
}
cout << "translation vector: " << hex << "0x" << DWARF_vector << endl;
cout << "lang vector: " << hex << "0x" << lang_addr << endl;
cout << "word table offset: " << hex << "0x" << word_table_offset << endl;
cout << "-------------" << endl;
cout << "!!MATERIALS!!" << endl;
cout << "-------------" << endl;
// inorganics vector
to_filter = filtVectors;
//sf.Find<uint32_t,vecTriplet>(257 * 4,4,to_filter,vectorLength<uint32_t>);
sf.Filter<const char * ,vecTriplet>("IRON",to_filter, vectorString);
sf.Filter<const char * ,vecTriplet>("ONYX",to_filter, vectorString);
sf.Filter<const char * ,vecTriplet>("RAW_ADAMANTINE",to_filter, vectorString);
sf.Filter<const char * ,vecTriplet>("BLOODSTONE",to_filter, vectorString);
printFound(to_filter,"inorganics");
// organics vector
to_filter = filtVectors;
sf.Filter<uint32_t,vecTriplet>(52 * 4,to_filter,vectorLength<uint32_t>);
sf.Filter<const char * ,vecTriplet>("MUSHROOM_HELMET_PLUMP",to_filter, vectorStringFirst);
printFound(to_filter,"organics");
// tree vector
to_filter = filtVectors;
sf.Filter<uint32_t,vecTriplet>(31 * 4,to_filter,vectorLength<uint32_t>);
sf.Filter<const char * ,vecTriplet>("MANGROVE",to_filter, vectorStringFirst);
printFound(to_filter,"trees");
// plant vector
to_filter = filtVectors;
sf.Filter<uint32_t,vecTriplet>(21 * 4,to_filter,vectorLength<uint32_t>);
sf.Filter<const char * ,vecTriplet>("MUSHROOM_HELMET_PLUMP",to_filter, vectorStringFirst);
printFound(to_filter,"plants");
// color descriptors
//AMBER, 112
to_filter = filtVectors;
sf.Filter<uint32_t,vecTriplet>(112 * 4,to_filter,vectorLength<uint32_t>);
sf.Filter<const char * ,vecTriplet>("AMBER",to_filter, vectorStringFirst);
printFound(to_filter,"color descriptors");
if(!to_filter.empty())
{
uint64_t vec = to_filter[0];
vecTriplet *vtColors = sf.Translate<vecTriplet>(vec);
uint32_t colorObj = sf.Read<uint32_t>(vtColors->start);
cout << "Amber color:" << hex << "0x" << colorObj << endl;
// TODO: find string 'amber', the floats
}
// all descriptors
//AMBER, 338
to_filter = filtVectors;
sf.Filter<uint32_t,vecTriplet>(338 * 4,to_filter,vectorLength<uint32_t>);
sf.Filter<const char * ,vecTriplet>("AMBER",to_filter, vectorStringFirst);
printFound(to_filter,"all descriptors");
// creature type
//ELEPHANT, ?? (demons abound)
to_filter = filtVectors;
//sf.Find<uint32_t,vecTriplet>(338 * 4,4,to_filter,vectorLength<uint32_t>);
sf.Filter<const char * ,vecTriplet>("ELEPHANT",to_filter, vectorString);
sf.Filter<const char * ,vecTriplet>("CAT",to_filter, vectorString);
sf.Filter<const char * ,vecTriplet>("DWARF",to_filter, vectorString);
sf.Filter<const char * ,vecTriplet>("WAMBLER_FLUFFY",to_filter, vectorString);
sf.Filter<const char * ,vecTriplet>("TOAD",to_filter, vectorString);
sf.Filter<const char * ,vecTriplet>("DEMON_1",to_filter, vectorString);
vector <uint64_t> toad_first = to_filter;
vector <uint64_t> elephant_first = to_filter;
sf.Filter<const char * ,vecTriplet>("TOAD",toad_first, vectorStringFirst);
sf.Filter<const char * ,vecTriplet>("ELEPHANT",elephant_first, vectorStringFirst);
printFoundStrVec(toad_first,"toad-first creature types",sf);
printFound(elephant_first,"elephant-first creature types");
printFound(to_filter,"all creature types");
uint64_t to_use = 0;
if(!elephant_first.empty())
{
to_use = elephant_first[0];
vecTriplet *vtCretypes = sf.Translate<vecTriplet>(to_use);
uint32_t elephant = sf.Read<uint32_t>(vtCretypes->start);
uint64_t Eoffset;
cout << "Elephant: 0x" << hex << elephant << endl;
cout << "Elephant: rawname = 0x0" << endl;
uint8_t letter_E = 'E';
Eoffset = sf.FindInRange<uint8_t,uint8_t> (letter_E,equalityP<uint8_t>, elephant, 0x300 );
if(Eoffset)
{
cout << "Elephant: big E = 0x" << hex << Eoffset - elephant << endl;
}
Eoffset = sf.FindInRange<const char *,vecTriplet> ("FEMALE",vectorStringFirst, elephant, 0x300 );
if(Eoffset)
{
cout << "Elephant: caste vector = 0x" << hex << Eoffset - elephant << endl;
}
Eoffset = sf.FindInRange<const char *,vecTriplet> ("SKIN",vectorStringFirst, elephant, 0x2000 );
if(Eoffset)
{
cout << "Elephant: extract? vector = 0x" << hex << Eoffset - elephant << endl;
}
tilecolors eletc = {7,0,0};
Bytestream bs_eletc(&eletc, sizeof(tilecolors));
cout << bs_eletc;
Eoffset = sf.FindInRange<Bytestream,tilecolors> (bs_eletc, findBytestream, elephant, 0x300 );
if(Eoffset)
{
cout << "Elephant: colors = 0x" << hex << Eoffset - elephant << endl;
}
//cout << "Amber color:" << hex << "0x" << colorObj << endl;
// TODO: find string 'amber', the floats
}
if(!toad_first.empty())
{
to_use = toad_first[0];
vecTriplet *vtCretypes = sf.Translate<vecTriplet>(to_use);
uint32_t toad = sf.Read<uint32_t>(vtCretypes->start);
uint64_t Eoffset;
cout << "Toad: 0x" << hex << toad << endl;
cout << "Toad: rawname = 0x0" << endl;
Eoffset = sf.FindInRange<uint8_t,uint8_t> (0xF9,equalityP<uint8_t>, toad, 0x300 );
if(Eoffset)
{
cout << "Toad: character (not reliable) = 0x" << hex << Eoffset - toad << endl;
}
Eoffset = sf.FindInRange<const char *,vecTriplet> ("FEMALE",vectorStringFirst, toad, 0x300 );
if(Eoffset)
{
cout << "Toad: caste vector = 0x" << hex << Eoffset - toad << endl;
}
Eoffset = sf.FindInRange<const char *,vecTriplet> ("SKIN",vectorStringFirst, toad, 0x2000 );
if(Eoffset)
{
cout << "Toad: extract? vector = 0x" << hex << Eoffset - toad << endl;
}
tilecolors toadtc = {2,0,0};
Bytestream bs_toadc(&toadtc, sizeof(tilecolors));
Eoffset = sf.FindInRange<Bytestream,tilecolors> (bs_toadc, findBytestream, toad, 0x300 );
if(Eoffset)
{
cout << "Toad: colors = 0x" << hex << Eoffset - toad << endl;
}
}*/
}
int main (void)
{
string select;
DFHack::ContextManager DFMgr("Memory.xml");
DFHack::Context * DF = DFMgr.getSingleContext();
try
{
DF->Attach();
}
catch (exception& e)
{
cerr << e.what() << endl;
#ifndef LINUX_BUILD
cin.ignore();
#endif
return 1;
}
DFHack::Process * p = DF->getProcess();
vector <DFHack::t_memrange> selected_ranges;
getRanges(p,selected_ranges);
DFHack::VersionInfo *minfo = DF->getMemoryInfo();
autoSearch(DF,selected_ranges, minfo->getOS());
#ifndef LINUX_BUILD
cout << "Done. Press any key to continue" << endl;
cin.ignore();
#endif
return 0;
}

@ -8,8 +8,19 @@ using namespace std;
#include <DFHack.h> #include <DFHack.h>
int main (void) int main (int argc, char** argv)
{ {
bool quiet = false;
for(int i = 1; i < argc; i++)
{
string test = argv[i];
if(test == "-q")
{
quiet = true;
}
}
uint32_t x_max,y_max,z_max; uint32_t x_max,y_max,z_max;
uint32_t num_blocks = 0; uint32_t num_blocks = 0;
uint32_t bytes_read = 0; uint32_t bytes_read = 0;
@ -44,6 +55,7 @@ int main (void)
Mapz->getSize(x_max,y_max,z_max); Mapz->getSize(x_max,y_max,z_max);
uint8_t zeroes [16][16] = {0}; uint8_t zeroes [16][16] = {0};
DFHack::occupancies40d occ;
// walk the map // walk the map
for(uint32_t x = 0; x< x_max;x++) for(uint32_t x = 0; x< x_max;x++)
@ -55,10 +67,18 @@ int main (void)
if(Mapz->isValidBlock(x,y,z)) if(Mapz->isValidBlock(x,y,z))
{ {
Mapz->ReadVeins(x,y,z,0,0,&splatter); Mapz->ReadVeins(x,y,z,0,0,&splatter);
Mapz->ReadOccupancy(x,y,z,&occ);
for(int i = 0; i < 16; i++)
for(int j = 0; j < 16; j++)
{
occ[i][j].unibits.splatter = 0;
}
Mapz->WriteOccupancy(x,y,z,&occ);
for(uint32_t i = 0; i < splatter.size(); i++) for(uint32_t i = 0; i < splatter.size(); i++)
{ {
DFHack::t_spattervein & vein = splatter[i]; DFHack::t_spattervein & vein = splatter[i];
if(vein.mat1 != 0xC) // filter away snow and mud
if(vein.mat1 != 0xC && vein.mat1 != 0x6)
{ {
uint32_t addr = vein.address_of; uint32_t addr = vein.address_of;
uint32_t offset = offsetof(DFHack::t_spattervein, intensity); uint32_t offset = offsetof(DFHack::t_spattervein, intensity);
@ -71,8 +91,11 @@ int main (void)
} }
DF->Detach(); DF->Detach();
#ifndef LINUX_BUILD #ifndef LINUX_BUILD
cout << "Done. Press any key to continue" << endl; if (!quiet)
cin.ignore(); {
cout << "Done. Press any key to continue" << endl;
cin.ignore();
}
#endif #endif
return 0; return 0;
} }

@ -39,7 +39,7 @@ int main ()
{ {
item_vec_offset = p->getDescriptor()->getAddress ("items_vector"); item_vec_offset = p->getDescriptor()->getAddress ("items_vector");
} }
catch(DFHack::Error::MissingMemoryDefinition & e) catch(DFHack::Error::AllMemdef & e)
{ {
cerr << "missing offset for the item vector, exiting :(" << endl; cerr << "missing offset for the item vector, exiting :(" << endl;
#ifndef LINUX_BUILD #ifndef LINUX_BUILD

@ -0,0 +1,49 @@
// This forces the game to pause.
#include <iostream>
#include <vector>
#include <map>
using namespace std;
#include <DFHack.h>
#include <dfhack/modules/Gui.h>
int main (int argc, char** argv)
{
bool quiet = false;
for(int i = 1; i < argc; i++)
{
string test = argv[i];
if(test == "-q")
{
quiet = true;
}
}
DFHack::ContextManager DFMgr("Memory.xml");
DFHack::Context *DF;
try
{
DF = DFMgr.getSingleContext();
DF->Attach();
}
catch (exception& e)
{
cerr << e.what() << endl;
#ifndef LINUX_BUILD
if(!quiet) cin.ignore();
#endif
return 1;
}
DFHack::Gui *Gui =DF->getGui();
cout << "Pausing..." << endl;
Gui->SetPauseState(true);
DF->Resume();
#ifndef LINUX_BUILD
cout << "Done. The current game frame will have to finish first. This can take some time on bugged maps." << endl;
if (!quiet) cin.ignore();
#endif
return 0;
}

@ -4,6 +4,7 @@
#include <climits> #include <climits>
#include <vector> #include <vector>
#include <map> #include <map>
#include <set>
#include <ctime> #include <ctime>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
@ -20,146 +21,12 @@ using namespace std;
#include <DFHack.h> #include <DFHack.h>
#include "SegmentedFinder.h" #include "SegmentedFinder.h"
template <class T>
class holder
{
public:
vector <T> values;
SegmentedFinder & sf;
holder(SegmentedFinder& sff):sf(sff){};
bool isValid(size_t idx)
{
};
};
class address
{
public:
uint64_t addr_;
unsigned int valid : 1;
virtual void print(SegmentedFinder& sff)
{
cout << hex << "0x" << addr_ << endl;
};
address(const uint64_t addr)
{
addr_ = addr;
valid = false;
}
virtual address & operator=(const uint64_t in)
{
addr_ = in;
valid = false;
return *this;
}
virtual bool isValid(SegmentedFinder& sff)
{
if(valid) return true;
if(sff.getSegmentForAddress(addr_))
{
valid = 1;
}
}
virtual bool equals (SegmentedFinder & sf, address & rhs)
{
return rhs.addr_ == addr_;
}
};
// pointer to a null-terminated byte string
class Cstr: public address
{
void print(SegmentedFinder & sf)
{
cout << hex << "0x" << addr_ << ": \"" << sf.Translate<char>(addr_) << "\"" << endl;
}
bool equals(SegmentedFinder & sf,const char * rhs)
{
uint32_t addr2 = *(sf.Translate<uint32_t>(addr_));
return strcmp(sf.Translate<const char>(addr2), rhs) == 0;
}
template <class Predicate, class inType>
bool equalsP(SegmentedFinder & sf,inType rhs)
{
return Predicate(addr_, sf, rhs);
}
bool isValid(SegmentedFinder& sf)
{
if (address::isValid(sf))
{
// read the pointer
uint32_t addr2 = *(sf.Translate<uint32_t>(addr_));
// is it a real pointer? a pretty weak test, but whatever.
if(sf.getSegmentForAddress(addr2))
return true;
}
return false;
}
};
// STL STRING
#ifdef LINUX_BUILD
class STLstr: public address
{
};
#endif
#ifndef LINUX_BUILD
class STLstr: public address
{
};
#endif
// STL VECTOR
#ifdef LINUX_BUILD
class Vector: public address
{
};
#endif
#ifndef LINUX_BUILD
class Vector: public address
{
};
#endif
class Int64: public address{};
class Int32: public address{};
class Int16: public address{};
class Int8: public address{};
inline void printRange(DFHack::t_memrange * tpr) inline void printRange(DFHack::t_memrange * tpr)
{ {
std::cout << std::hex << tpr->start << " - " << tpr->end << "|" << (tpr->read ? "r" : "-") << (tpr->write ? "w" : "-") << (tpr->execute ? "x" : "-") << "|" << tpr->name << std::endl; std::cout << std::hex << tpr->start << " - " << tpr->end << "|" << (tpr->read ? "r" : "-") << (tpr->write ? "w" : "-") << (tpr->execute ? "x" : "-") << "|" << tpr->name << std::endl;
} }
string rdWinString( char * offset, SegmentedFinder & sf )
{
char * start_offset = offset + 4;
uint32_t length = *(uint32_t *)(offset + 20);
uint32_t capacity = *(uint32_t *)(offset + 24);
char * temp = new char[capacity+1];
// read data from inside the string structure
if(capacity < 16)
{
memcpy(temp, start_offset,capacity);
//read(start_offset, capacity, (uint8_t *)temp);
}
else // read data from what the offset + 4 dword points to
{
start_offset = sf.Translate<char>(*(uint32_t*)start_offset);
memcpy(temp, start_offset,capacity);
}
temp[length] = 0;
string ret = temp;
delete temp;
return ret;
}
bool getRanges(DFHack::Process * p, vector <DFHack::t_memrange>& selected_ranges) bool getRanges(DFHack::Process * p, vector <DFHack::t_memrange>& selected_ranges)
{ {
vector <DFHack::t_memrange> ranges; vector <DFHack::t_memrange> ranges;
@ -181,12 +48,12 @@ bool getRanges(DFHack::Process * p, vector <DFHack::t_memrange>& selected_ranges
{ {
// empty input, assume default. observe the length of the memory range vector // empty input, assume default. observe the length of the memory range vector
// these are hardcoded values, intended for my convenience only // these are hardcoded values, intended for my convenience only
if(p->getDescriptor()->getOS() == DFHack::VersionInfo::OS_WINDOWS) if(p->getDescriptor()->getOS() == DFHack::OS_WINDOWS)
{ {
start = min(11, (int)ranges.size()); start = min(11, (int)ranges.size());
end = min(14, (int)ranges.size()); end = min(14, (int)ranges.size());
} }
else if(p->getDescriptor()->getOS() == DFHack::VersionInfo::OS_LINUX) else if(p->getDescriptor()->getOS() == DFHack::OS_LINUX)
{ {
start = min(2, (int)ranges.size()); start = min(2, (int)ranges.size());
end = min(4, (int)ranges.size()); end = min(4, (int)ranges.size());
@ -225,6 +92,7 @@ bool getRanges(DFHack::Process * p, vector <DFHack::t_memrange>& selected_ranges
} }
it++; it++;
} }
return true;
} }
bool getNumber (string prompt, int & output, int def, bool pdef = true) bool getNumber (string prompt, int & output, int def, bool pdef = true)
@ -273,7 +141,7 @@ bool getString (string prompt, string & output)
template <class T> template <class T>
bool Incremental ( vector <uint64_t> &found, const char * what, T& output, bool Incremental ( vector <uint64_t> &found, const char * what, T& output,
const char *singular = "address", const char *plural = "addresses" ) const char *singular = "address", const char *plural = "addresses", bool numberz = false )
{ {
string select; string select;
if(found.empty()) if(found.empty())
@ -311,26 +179,33 @@ bool Incremental ( vector <uint64_t> &found, const char * what, T& output,
} }
goto incremental_more; goto incremental_more;
} }
else if(select.empty()) else if(select == "q")
{ {
return false; return false;
} }
else if(select.empty())
{
goto incremental_more;
}
else else
{ {
if( sscanf(select.c_str(),"0x%x", &output) == 1 ) if(numberz)
{
//cout << dec << output << endl;
return true;
}
if( sscanf(select.c_str(),"%d", &output) == 1 )
{ {
//cout << dec << output << endl; if( sscanf(select.c_str(),"0x%x", &output) == 1 )
return true; {
//cout << dec << output << endl;
return true;
}
if( sscanf(select.c_str(),"%d", &output) == 1 )
{
//cout << dec << output << endl;
return true;
}
} }
stringstream ss (stringstream::in | stringstream::out); stringstream ss (stringstream::in | stringstream::out);
ss << select; ss << select;
ss >> output; ss >> output;
cout << output;
if(!ss.fail()) if(!ss.fail())
{ {
return true; return true;
@ -358,7 +233,7 @@ void FindIntegers(DFHack::ContextManager & DFMgr, vector <DFHack::t_memrange>& r
uint32_t test1; uint32_t test1;
vector <uint64_t> found; vector <uint64_t> found;
found.reserve(100); found.reserve(100);
while(Incremental(found, "integer",test1)) while(Incremental(found, "integer",test1,"address", "addresses",true))
{ {
DFMgr.Refresh(); DFMgr.Refresh();
DFHack::Context * DF = DFMgr.getSingleContext(); DFHack::Context * DF = DFMgr.getSingleContext();
@ -514,6 +389,220 @@ void FindStrings(DFHack::ContextManager & DFMgr, vector <DFHack::t_memrange>& ra
} }
} }
void FindData(DFHack::ContextManager & DFMgr, vector <DFHack::t_memrange>& ranges)
{
vector <uint64_t> found;
Bytestream select;
while (Incremental(found,"byte stream",select,"byte stream","byte streams"))
{
DFMgr.Refresh();
DFHack::Context * DF = DFMgr.getSingleContext();
DF->Attach();
SegmentedFinder sf(ranges,DF);
sf.Incremental< Bytestream ,uint32_t>(select,1,found, findBytestream);
DF->Detach();
}
}
bool TriggerIncremental ( vector <uint64_t> &found )
{
string select;
if(found.empty())
{
cout << "search ready - position the DF cursor and hit enter when ready" << endl;
}
else if( found.size() == 1 )
{
cout << "Found single coord!" << endl;
cout << hex << "0x" << found[0] << endl;
}
else
{
cout << "Found " << dec << found.size() << " coords." << endl;
}
incremental_more:
cout << ">>";
std::getline(cin, select);
size_t num = 0;
if( sscanf(select.c_str(),"p %d", &num) && num > 0)
{
cout << "Found coords:" << endl;
for(int i = 0; i < min(found.size(), num);i++)
{
cout << hex << "0x" << found[i] << endl;
}
goto incremental_more;
}
else if(select == "p")
{
cout << "Found coords:" << endl;
for(int i = 0; i < found.size();i++)
{
cout << hex << "0x" << found[i] << endl;
}
goto incremental_more;
}
else if(select == "q")
{
return false;
}
else return true;
}
void FindCoords(DFHack::ContextManager & DFMgr, vector <DFHack::t_memrange>& ranges)
{
vector <uint64_t> found;
int size = 4;
do
{
getNumber("Select coord size (2,4 bytes)",size, 4);
} while (size != 2 && size != 4);
while (TriggerIncremental(found))
{
DFMgr.Refresh();
DFHack::Context * DF = DFMgr.getSingleContext();
DF->Attach();
DFHack::Position * pos = DF->getPosition();
pos->Start();
int32_t x, y, z;
pos->getCursorCoords(x,y,z);
cout << "Searching for: " << dec << x << ":" << y << ":" << z << endl;
Bytestream select;
if(size == 2)
{
select.insert<uint16_t>(x);
select.insert<uint16_t>(y);
select.insert<uint16_t>(z);
}
else
{
select.insert<uint32_t>(x);
select.insert<uint32_t>(y);
select.insert<uint32_t>(z);
}
cout << select << endl;
SegmentedFinder sf(ranges,DF);
sf.Incremental< Bytestream ,uint32_t>(select,1,found, findBytestream);
DF->Detach();
}
}
void PtrTrace(DFHack::ContextManager & DFMgr, vector <DFHack::t_memrange>& ranges)
{
int element_size;
do
{
getNumber("Set search granularity",element_size, 4);
} while (element_size < 1);
vector <uint64_t> found;
set <uint64_t> check; // to detect circles
uint32_t select;
while (Incremental(found,"address",select,"addresses","addresses",true))
{
DFMgr.Refresh();
found.clear();
DFHack::Context * DF = DFMgr.getSingleContext();
DF->Attach();
SegmentedFinder sf(ranges,DF);
cout <<"Starting: 0x" << hex << select << endl;
while(sf.getSegmentForAddress(select))
{
sf.Incremental<uint32_t,uint32_t>(select,element_size,found, equalityP<uint32_t>);
if(found.empty())
{
cout << ".";
cout.flush();
select -=element_size;
continue;
}
cout << endl;
cout <<"Object start: 0x" << hex << select << endl;
cout <<"Pointer: 0x" << hex << found[0] << endl;
// make sure we don't go in circles'
if(check.count(select))
{
break;
}
check.insert(select);
// ascend
select = found[0];
found.clear();
}
DF->Detach();
}
}
/*
{
vector <uint64_t> found;
Bytestream select;
while (Incremental(found,"byte stream",select,"byte stream","byte streams"))
{
DFMgr.Refresh();
DFHack::Context * DF = DFMgr.getSingleContext();
DF->Attach();
SegmentedFinder sf(ranges,DF);
sf.Incremental< Bytestream ,uint32_t>(select,1,found, findBytestream);
DF->Detach();
}
}
*/
void DataPtrTrace(DFHack::ContextManager & DFMgr, vector <DFHack::t_memrange>& ranges)
{
int element_size;
do
{
getNumber("Set search granularity",element_size, 4);
} while (element_size < 1);
vector <uint64_t> found;
set <uint64_t> check; // to detect circles
uint32_t select;
Bytestream bs_select;
DFHack::Context * DF = DFMgr.getSingleContext();
DF->Attach();
DFMgr.Refresh();
found.clear();
SegmentedFinder sf(ranges,DF);
while(found.empty())
{
Incremental(found,"byte stream",bs_select,"byte stream","byte streams");
sf.Incremental< Bytestream ,uint32_t>(bs_select,1,found, findBytestream);
}
select = found[0];
cout <<"Starting: 0x" << hex << select << endl;
while(sf.getSegmentForAddress(select))
{
sf.Incremental<uint32_t,uint32_t>(select,element_size,found, equalityP<uint32_t>);
if(found.empty())
{
cout << ".";
cout.flush();
select -=element_size;
continue;
}
cout << endl;
cout <<"Object start: 0x" << hex << select << endl;
cout <<"Pointer: 0x" << hex << found[0] << endl;
// make sure we don't go in circles'
if(check.count(select))
{
break;
}
check.insert(select);
// ascend
select = found[0];
found.clear();
}
DF->Detach();
}
void printFound(vector <uint64_t> &found, const char * what) void printFound(vector <uint64_t> &found, const char * what)
{ {
cout << what << ":" << endl; cout << what << ":" << endl;
@ -580,7 +669,7 @@ struct tilecolors
}; };
#pragma pack() #pragma pack()
void automatedLangtables(DFHack::Context * DF, vector <DFHack::t_memrange>& ranges) void autoSearch(DFHack::Context * DF, vector <DFHack::t_memrange>& ranges)
{ {
vector <uint64_t> allVectors; vector <uint64_t> allVectors;
vector <uint64_t> filtVectors; vector <uint64_t> filtVectors;
@ -664,6 +753,15 @@ void automatedLangtables(DFHack::Context * DF, vector <DFHack::t_memrange>& rang
sf.Filter<const char * ,vecTriplet>("MUSHROOM_HELMET_PLUMP",to_filter, vectorStringFirst); sf.Filter<const char * ,vecTriplet>("MUSHROOM_HELMET_PLUMP",to_filter, vectorStringFirst);
printFound(to_filter,"organics"); printFound(to_filter,"organics");
// new organics vector
to_filter = filtVectors;
sf.Filter<const char * ,vecTriplet>("MUSHROOM_HELMET_PLUMP",to_filter, vectorString);
sf.Filter<const char * ,vecTriplet>("MEADOW-GRASS",to_filter, vectorString);
sf.Filter<const char * ,vecTriplet>("TUNNEL_TUBE",to_filter, vectorString);
sf.Filter<const char * ,vecTriplet>("WEED_BLADE",to_filter, vectorString);
sf.Filter<const char * ,vecTriplet>("EYEBALL",to_filter, vectorString);
printFound(to_filter,"organics 31.19");
// tree vector // tree vector
to_filter = filtVectors; to_filter = filtVectors;
sf.Filter<uint32_t,vecTriplet>(31 * 4,to_filter,vectorLength<uint32_t>); sf.Filter<uint32_t,vecTriplet>(31 * 4,to_filter,vectorLength<uint32_t>);
@ -726,7 +824,8 @@ void automatedLangtables(DFHack::Context * DF, vector <DFHack::t_memrange>& rang
uint64_t Eoffset; uint64_t Eoffset;
cout << "Elephant: 0x" << hex << elephant << endl; cout << "Elephant: 0x" << hex << elephant << endl;
cout << "Elephant: rawname = 0x0" << endl; cout << "Elephant: rawname = 0x0" << endl;
Eoffset = sf.FindInRange<uint8_t,uint8_t> ('E',equalityP<uint8_t>, elephant, 0x300 ); uint8_t letter_E = 'E';
Eoffset = sf.FindInRange<uint8_t,uint8_t> (letter_E,equalityP<uint8_t>, elephant, 0x300 );
if(Eoffset) if(Eoffset)
{ {
cout << "Elephant: big E = 0x" << hex << Eoffset - elephant << endl; cout << "Elephant: big E = 0x" << hex << Eoffset - elephant << endl;
@ -742,7 +841,8 @@ void automatedLangtables(DFHack::Context * DF, vector <DFHack::t_memrange>& rang
cout << "Elephant: extract? vector = 0x" << hex << Eoffset - elephant << endl; cout << "Elephant: extract? vector = 0x" << hex << Eoffset - elephant << endl;
} }
tilecolors eletc = {7,0,0}; tilecolors eletc = {7,0,0};
Bytestream bs_eletc = {sizeof(tilecolors), &eletc}; Bytestream bs_eletc(&eletc, sizeof(tilecolors));
cout << bs_eletc;
Eoffset = sf.FindInRange<Bytestream,tilecolors> (bs_eletc, findBytestream, elephant, 0x300 ); Eoffset = sf.FindInRange<Bytestream,tilecolors> (bs_eletc, findBytestream, elephant, 0x300 );
if(Eoffset) if(Eoffset)
{ {
@ -775,7 +875,7 @@ void automatedLangtables(DFHack::Context * DF, vector <DFHack::t_memrange>& rang
cout << "Toad: extract? vector = 0x" << hex << Eoffset - toad << endl; cout << "Toad: extract? vector = 0x" << hex << Eoffset - toad << endl;
} }
tilecolors toadtc = {2,0,0}; tilecolors toadtc = {2,0,0};
Bytestream bs_toadc = {sizeof(tilecolors), &toadtc}; Bytestream bs_toadc(&toadtc, sizeof(tilecolors));
Eoffset = sf.FindInRange<Bytestream,tilecolors> (bs_toadc, findBytestream, toad, 0x300 ); Eoffset = sf.FindInRange<Bytestream,tilecolors> (bs_toadc, findBytestream, toad, 0x300 );
if(Eoffset) if(Eoffset)
{ {
@ -810,58 +910,80 @@ int main (void)
getRanges(p,selected_ranges); getRanges(p,selected_ranges);
DFHack::VersionInfo *minfo = DF->getMemoryInfo(); DFHack::VersionInfo *minfo = DF->getMemoryInfo();
DFHack::VersionInfo::OSType os = minfo->getOS(); DFHack::OSType os = minfo->getOS();
string prompt = string prompt =
"Select search type: 1=number(default), 2=vector by length, 3=vector>object>string,\n" "Select search type: 1=number(default), 2=vector by length, 3=vector>object>string,\n"
" 4=string, 5=automated offset search, 6=vector by address in its array,\n" " 4=string, 5=automated offset search, 6=vector by address in its array,\n"
" 7=pointer vector by address of an object, 8=vector>first object>string\n" " 7=pointer vector by address of an object, 8=vector>first object>string\n"
" 9=string buffers\n"; " 9=string buffers, 10=known data, 11=backpointers, 12=data+backpointers\n"
" 13=coord lookup\n"
" 0= exit\n";
int mode; int mode;
bool finish = 0;
do do
{ {
getNumber(prompt,mode, 1, false); getNumber(prompt,mode, 1, false);
} while (mode < 1 || mode > 9 ); switch (mode)
switch (mode) {
{ case 0:
case 1: finish = 1;
DF->Detach(); break;
FindIntegers(DFMgr, selected_ranges); case 1:
break; DF->Detach();
case 2: FindIntegers(DFMgr, selected_ranges);
DF->Detach(); break;
FindVectorByLength(DFMgr, selected_ranges); case 2:
break; DF->Detach();
case 3: FindVectorByLength(DFMgr, selected_ranges);
DF->Detach(); break;
FindVectorByObjectRawname(DFMgr, selected_ranges); case 3:
break; DF->Detach();
case 4: FindVectorByObjectRawname(DFMgr, selected_ranges);
DF->Detach(); break;
FindStrings(DFMgr, selected_ranges); case 4:
break; DF->Detach();
case 5: FindStrings(DFMgr, selected_ranges);
automatedLangtables(DF,selected_ranges); break;
break; case 5:
case 6: autoSearch(DF,selected_ranges);
DF->Detach(); break;
FindVectorByBounds(DFMgr,selected_ranges); case 6:
break; DF->Detach();
case 7: FindVectorByBounds(DFMgr,selected_ranges);
DF->Detach(); break;
FindPtrVectorsByObjectAddress(DFMgr,selected_ranges); case 7:
break; DF->Detach();
case 8: FindPtrVectorsByObjectAddress(DFMgr,selected_ranges);
DF->Detach(); break;
FindVectorByFirstObjectRawname(DFMgr, selected_ranges); case 8:
break; DF->Detach();
case 9: FindVectorByFirstObjectRawname(DFMgr, selected_ranges);
DF->Detach(); break;
FindStrBufs(DFMgr, selected_ranges); case 9:
break; DF->Detach();
default: FindStrBufs(DFMgr, selected_ranges);
cout << "not implemented :(" << endl; break;
} case 10:
DF->Detach();
FindData(DFMgr, selected_ranges);
break;
case 11:
DF->Detach();
PtrTrace(DFMgr, selected_ranges);
break;
case 12:
DF->Detach();
DataPtrTrace(DFMgr, selected_ranges);
break;
case 13:
DF->Detach();
FindCoords(DFMgr, selected_ranges);
break;
default:
cout << "Unknown function, try again." << endl;
}
} while ( !finish );
#ifndef LINUX_BUILD #ifndef LINUX_BUILD
cout << "Done. Press any key to continue" << endl; cout << "Done. Press any key to continue" << endl;
cin.ignore(); cin.ignore();

@ -1,16 +1,25 @@
// This will create 7 deep magama on the square the cursor is on. It does not // TO BE DEPRECATED SOON.
// enable magma buildings at this time.
#include <iostream> #include <iostream>
#include <vector> #include <vector>
#include <map> #include <map>
#include <cstdlib>
using namespace std; using namespace std;
#include <DFHack.h> #include <DFHack.h>
#include <dfhack/DFTileTypes.h> #include <dfhack/DFTileTypes.h>
int main (void) int main (int argc, char** argv)
{ {
bool quiet = false;
for(int i = 1; i < argc; i++)
{
string test = argv[i];
if(test == "-q")
{
quiet = true;
}
}
int32_t x,y,z; int32_t x,y,z;
DFHack::designations40d designations; DFHack::designations40d designations;
DFHack::tiletypes40d tiles; DFHack::tiletypes40d tiles;
@ -45,6 +54,8 @@ int main (void)
string flowmode="f+"; string flowmode="f+";
string setmode ="s."; string setmode ="s.";
int amount = 7; int amount = 7;
int width = 1;
int height = 1;
while(!end) while(!end)
{ {
DF->Resume(); DF->Resume();
@ -68,7 +79,8 @@ int main (void)
<< "f- - make the spawned liquid static" << endl << "f- - make the spawned liquid static" << endl
<< "0-7 - set liquid amount" << endl << "0-7 - set liquid amount" << endl
<< "Brush:" << endl << "Brush:" << endl
<< "point - single tile" << endl << "point - single tile [p]" << endl
<< "range - rectangle with cursor at top left [r]" << endl
<< "block - block with cursor in it" << endl << "block - block with cursor in it" << endl
<< "Other:" << endl << "Other:" << endl
<< "q - quit" << endl << "q - quit" << endl
@ -106,10 +118,22 @@ int main (void)
{ {
mode = "flowbits"; mode = "flowbits";
} }
else if(command == "point") else if(command == "point" || command == "p")
{ {
brush = "point"; brush = "point";
} }
else if(command == "range" || command == "r")
{
cout << " :set range width<" << width << "># ";
getline(cin, command);
width = command == "" ? width : atoi (command.c_str());
if(width < 1) width = 1;
cout << " :set range height<" << height << "># ";
getline(cin, command);
height = command == "" ? height : atoi (command.c_str());
if(height < 1) height = 1;
brush = "range";
}
else if(command == "block") else if(command == "block")
{ {
brush = "block"; brush = "block";
@ -214,7 +238,6 @@ int main (void)
cout << "sizeof(tiletypes) = " << sizeof(tiles) << endl; cout << "sizeof(tiletypes) = " << sizeof(tiles) << endl;
for(uint32_t xx = 0; xx < 16; xx++) for(uint32_t yy = 0; yy < 16; yy++) for(uint32_t xx = 0; xx < 16; xx++) for(uint32_t yy = 0; yy < 16; yy++)
{ {
cout<< xx << " " << yy <<": " << tiles[xx][yy] << endl; cout<< xx << " " << yy <<": " << tiles[xx][yy] << endl;
tiles[xx][yy] = 335;// 45 tiles[xx][yy] = 335;// 45
DFHack::naked_designation & des = designations[xx][yy].bits; DFHack::naked_designation & des = designations[xx][yy].bits;
@ -224,10 +247,8 @@ int main (void)
des.skyview = 0; des.skyview = 0;
des.light = 0; des.light = 0;
des.subterranean = 1; des.subterranean = 1;
temp1[xx][yy] = 10015; temp1[xx][yy] = 10015;
temp2[xx][yy] = 10015; temp2[xx][yy] = 10015;
} }
Maps->WriteTemperatures((x/16),(y/16),z, &temp1, &temp2); Maps->WriteTemperatures((x/16),(y/16),z, &temp1, &temp2);
Maps->WriteDesignations((x/16),(y/16),z, &designations); Maps->WriteDesignations((x/16),(y/16),z, &designations);
@ -257,46 +278,18 @@ int main (void)
else else
{ {
// place the magma // place the magma
Maps->ReadDesignations((x/16),(y/16),z, &designations); if(brush != "range")
Maps->ReadTemperatures((x/16),(y/16),z, &temp1, &temp2);
if(brush == "point")
{
if(mode != "flowbits")
{
// fix temperatures so we don't produce lethal heat traps
if(amount == 0 || designations[x%16][y%16].bits.liquid_type == DFHack::liquid_magma && mode == "water")
temp1[x%16][y%16] = temp2[x%16][y%16] = 10015;
DFHack::naked_designation & flow = designations[x%16][y%16].bits;
if(setmode == "s.")
{
flow.flow_size = amount;
}
else if(setmode == "s+")
{
if(flow.flow_size < amount)
flow.flow_size = amount;
}
else if(setmode == "s-")
{
if (flow.flow_size > amount)
flow.flow_size = amount;
}
}
if(mode == "magma")
designations[x%16][y%16].bits.liquid_type = DFHack::liquid_magma;
else if(mode == "water")
designations[x%16][y%16].bits.liquid_type = DFHack::liquid_water;
}
else
{ {
for(uint32_t xx = 0; xx < 16; xx++) for(uint32_t yy = 0; yy < 16; yy++) Maps->ReadDesignations((x/16),(y/16),z, &designations);
Maps->ReadTemperatures((x/16),(y/16),z, &temp1, &temp2);
if(brush == "point")
{ {
if(mode != "flowbits") if(mode != "flowbits")
{ {
// fix temperatures so we don't produce lethal heat traps // fix temperatures so we don't produce lethal heat traps
if(amount == 0 || designations[xx][yy].bits.liquid_type == DFHack::liquid_magma && mode == "water") if(amount == 0 || designations[x%16][y%16].bits.liquid_type == DFHack::liquid_magma && mode == "water")
temp1[xx%16][yy%16] = temp2[xx%16][yy%16] = 10015; temp1[x%16][y%16] = temp2[x%16][y%16] = 10015;
DFHack::naked_designation & flow= designations[xx][yy].bits; DFHack::naked_designation & flow = designations[x%16][y%16].bits;
if(setmode == "s.") if(setmode == "s.")
{ {
flow.flow_size = amount; flow.flow_size = amount;
@ -313,36 +306,162 @@ int main (void)
} }
} }
if(mode == "magma") if(mode == "magma")
designations[xx][yy].bits.liquid_type = DFHack::liquid_magma; designations[x%16][y%16].bits.liquid_type = DFHack::liquid_magma;
else if(mode == "water") else if(mode == "water")
designations[xx][yy].bits.liquid_type = DFHack::liquid_water; designations[x%16][y%16].bits.liquid_type = DFHack::liquid_water;
}
else
{
for(uint32_t xx = 0; xx < 16; xx++) for(uint32_t yy = 0; yy < 16; yy++)
{
if(mode != "flowbits")
{
// fix temperatures so we don't produce lethal heat traps
if(amount == 0 || designations[xx][yy].bits.liquid_type == DFHack::liquid_magma && mode == "water")
temp1[xx%16][yy%16] = temp2[xx%16][yy%16] = 10015;
DFHack::naked_designation & flow= designations[xx][yy].bits;
if(setmode == "s.")
{
flow.flow_size = amount;
}
else if(setmode == "s+")
{
if(flow.flow_size < amount)
flow.flow_size = amount;
}
else if(setmode == "s-")
{
if (flow.flow_size > amount)
flow.flow_size = amount;
}
}
if(mode == "magma")
designations[xx][yy].bits.liquid_type = DFHack::liquid_magma;
else if(mode == "water")
designations[xx][yy].bits.liquid_type = DFHack::liquid_water;
}
}
Maps->WriteTemperatures((x/16),(y/16),z, &temp1, &temp2);
Maps->WriteDesignations(x/16,y/16,z, &designations);
// make the magma flow :)
DFHack::t_blockflags bflags;
Maps->ReadBlockFlags((x/16),(y/16),z,bflags);
// 0x00000001 = job-designated
// 0x0000000C = run flows? - both bit 3 and 4 required for making magma placed on a glacier flow
if(flowmode == "f+")
{
bflags.bits.liquid_1 = true;
bflags.bits.liquid_2 = true;
}
else if(flowmode == "f-")
{
bflags.bits.liquid_1 = false;
bflags.bits.liquid_2 = false;
}
else
{
cout << "flow bit 1 = " << bflags.bits.liquid_1 << endl;
cout << "flow bit 2 = " << bflags.bits.liquid_2 << endl;
}
Maps->WriteBlockFlags((x/16),(y/16),z,bflags);
}
else if (brush == "range")
{
// Crop the range into each block if necessary
int beginxblock = x/16;
int endxblock = (x+width)/16;
int beginyblock = y/16;
int endyblock = (y+height)/16;
for(uint32_t bx = beginxblock; bx < endxblock+1; bx++) for(uint32_t by = beginyblock; by < endyblock+1; by++)
{
if(Maps->isValidBlock(bx,by,z))
{
Maps->ReadDesignations(bx,by,z, &designations);
Maps->ReadTemperatures(bx,by,z, &temp1, &temp2);
// Take original range and crop it into current block
int nx = x;
int ny = y;
int nwidth = width;
int nheight = height;
if(x/16 < bx) //Start point is left of block
{
nx = bx*16;
nwidth -= nx - x;
}
if (nx/16 < (nx+nwidth-1)/16)// End point is right of block
{
nwidth = (bx*16)+16-nx;
}
if(y/16 < by) //Start point is above block
{
ny = by*16;
nheight -= ny - y;
}
if (ny/16 < (ny+nheight-1)/16) // End point is below block
{
nheight = (by*16)+16-ny;
}
cout << " Block:" << bx << "," << by << ":" << endl;
cout << " Start:" << nx << "," << ny << ":" << endl;
cout << " Area: " << nwidth << "," << nheight << ":" << endl;
for(uint32_t xx = nx; xx < nx+nwidth; xx++) for(uint32_t yy = ny; yy < ny+nheight; yy++)
{
if(mode != "flowbits")
{
// fix temperatures so we don't produce lethal heat traps
if(amount == 0 || designations[xx%16][yy%16].bits.liquid_type == DFHack::liquid_magma && mode == "water")
temp1[xx%16][yy%16] = temp2[xx%16][yy%16] = 10015;
DFHack::naked_designation & flow= designations[xx%16][yy%16].bits;
if(setmode == "s.")
{
flow.flow_size = amount;
}
else if(setmode == "s+")
{
if(flow.flow_size < amount)
flow.flow_size = amount;
}
else if(setmode == "s-")
{
if (flow.flow_size > amount)
flow.flow_size = amount;
}
}
if(mode == "magma")
designations[xx%16][yy%16].bits.liquid_type = DFHack::liquid_magma;
else if(mode == "water")
designations[xx%16][yy%16].bits.liquid_type = DFHack::liquid_water;
}
Maps->WriteTemperatures(bx,by,z, &temp1, &temp2);
Maps->WriteDesignations(bx,by,z, &designations);
// make the magma flow :)
DFHack::t_blockflags bflags;
Maps->ReadBlockFlags(bx,by,z,bflags);
// 0x00000001 = job-designated
// 0x0000000C = run flows? - both bit 3 and 4 required for making magma placed on a glacier flow
if(flowmode == "f+")
{
bflags.bits.liquid_1 = true;
bflags.bits.liquid_2 = true;
}
else if(flowmode == "f-")
{
bflags.bits.liquid_1 = false;
bflags.bits.liquid_2 = false;
}
else
{
cout << "flow bit 1 = " << bflags.bits.liquid_1 << endl;
cout << "flow bit 2 = " << bflags.bits.liquid_2 << endl;
}
Maps->WriteBlockFlags(bx,by,z,bflags);
}
} }
} }
Maps->WriteTemperatures((x/16),(y/16),z, &temp1, &temp2);
Maps->WriteDesignations(x/16,y/16,z, &designations);
}
// make the magma flow :)
DFHack::t_blockflags bflags;
Maps->ReadBlockFlags((x/16),(y/16),z,bflags);
// 0x00000001 = job-designated
// 0x0000000C = run flows? - both bit 3 and 4 required for making magma placed on a glacier flow
if(flowmode == "f+")
{
bflags.bits.liquid_1 = true;
bflags.bits.liquid_2 = true;
}
else if(flowmode == "f-")
{
bflags.bits.liquid_1 = false;
bflags.bits.liquid_2 = false;
}
else
{
cout << "flow bit 1 = " << bflags.bits.liquid_1 << endl;
cout << "flow bit 2 = " << bflags.bits.liquid_2 << endl;
} }
Maps->WriteBlockFlags((x/16),(y/16),z,bflags);
cout << "OK" << endl; cout << "OK" << endl;
Maps->Finish(); Maps->Finish();
} while (0); } while (0);
@ -350,8 +469,11 @@ int main (void)
} }
DF->Detach(); DF->Detach();
#ifndef LINUX_BUILD #ifndef LINUX_BUILD
cout << "Done. Press any key to continue" << endl; if(!quiet)
cin.ignore(); {
cout << "Done. Press any key to continue" << endl;
cin.ignore();
}
#endif #endif
return 0; return 0;
} }

@ -8,8 +8,18 @@ using namespace std;
#include <DFHack.h> #include <DFHack.h>
int main (void) int main (int argc, char** argv)
{ {
bool quiet = false;
for(int i = 1; i < argc; i++)
{
string test = argv[i];
if(test == "-q")
{
quiet = true;
}
}
DFHack::Position * Position = 0; DFHack::Position * Position = 0;
DFHack::ContextManager DFMgr("Memory.xml"); DFHack::ContextManager DFMgr("Memory.xml");
DFHack::Context * DF; DFHack::Context * DF;
@ -50,8 +60,11 @@ int main (void)
} }
#ifndef LINUX_BUILD #ifndef LINUX_BUILD
cout << "Done. Press any key to continue" << endl; if(!quiet)
cin.ignore(); {
cout << "Done. Press any key to continue" << endl;
cin.ignore();
}
#endif #endif
return 0; return 0;
} }

@ -8,8 +8,8 @@
#include <ctime> #include <ctime>
#include <cstdio> #include <cstdio>
#define DFHACK_WANT_MISCUTILS #define DFHACK_WANT_MISCUTILS 1
#define DFHACK_WANT_TILETYPES #define DFHACK_WANT_TILETYPES 1
#include <DFHack.h> #include <DFHack.h>
using namespace DFHack; using namespace DFHack;
@ -18,6 +18,7 @@ int main (int numargs, const char ** args)
DFHack::ContextManager DFMgr("Memory.xml"); DFHack::ContextManager DFMgr("Memory.xml");
DFHack::Context *DF = DFMgr.getSingleContext(); DFHack::Context *DF = DFMgr.getSingleContext();
BEGIN_PROBE:
try try
{ {
DF->Attach(); DF->Attach();
@ -31,6 +32,7 @@ int main (int numargs, const char ** args)
return 1; return 1;
} }
DFHack::Position *Pos = DF->getPosition(); DFHack::Position *Pos = DF->getPosition();
DFHack::VersionInfo* mem = DF->getMemoryInfo(); DFHack::VersionInfo* mem = DF->getMemoryInfo();
DFHack::Maps *Maps = DF->getMaps(); DFHack::Maps *Maps = DF->getMaps();
@ -57,6 +59,11 @@ int main (int numargs, const char ** args)
Maps->Start(); Maps->Start();
vector<DFHack::t_feature> global_features;
std::map <DFHack::planecoord, std::vector<DFHack::t_feature *> > local_features;
Maps->ReadLocalFeatures(local_features);
Maps->ReadGlobalFeatures(global_features);
int32_t cursorX, cursorY, cursorZ; int32_t cursorX, cursorY, cursorZ;
Pos->getCursorCoords(cursorX,cursorY,cursorZ); Pos->getCursorCoords(cursorX,cursorY,cursorZ);
if(cursorX != -30000) if(cursorX != -30000)
@ -82,7 +89,15 @@ int main (int numargs, const char ** args)
// tiletype // tiletype
std::cout <<"tiletype: " << tiletype; std::cout <<"tiletype: " << tiletype;
if(tileTypeTable[tiletype].name) if(tileTypeTable[tiletype].name)
std::cout << " = " << tileTypeTable[tiletype].name; std::cout << " = " << tileTypeTable[tiletype].name << std::endl;
printf("%-10s: %4d %s\n","Class",tileTypeTable[tiletype].c,TileClassString[ tileTypeTable[tiletype].c ] , 0);
printf("%-10s: %4d %s\n","Material",tileTypeTable[tiletype].c,TileMaterialString[ tileTypeTable[tiletype].m ] , 0);
printf("%-10s: %4d %s\n","Special",tileTypeTable[tiletype].c,TileSpecialString[ tileTypeTable[tiletype].s ] , 0);
printf("%-10s: %4d\n","Variant",tileTypeTable[tiletype].v , 0);
printf("%-10s: %s\n","Direction",tileTypeTable[tiletype].d.getStr() , 0);
std::cout << std::endl; std::cout << std::endl;
std::cout <<"temperature1: " << tmpb1[tileX][tileY] << " U" << std::endl; std::cout <<"temperature1: " << tmpb1[tileX][tileY] << " U" << std::endl;
std::cout <<"temperature2: " << tmpb2[tileX][tileY] << " U" << std::endl; std::cout <<"temperature2: " << tmpb2[tileX][tileY] << " U" << std::endl;
@ -109,24 +124,45 @@ int main (int numargs, const char ** args)
std::cout << "smooth?" << std::endl; std::cout << "smooth?" << std::endl;
uint32_t designato = block.origin + designatus + (tileX * 16 + tileY) * sizeof(t_designation); uint32_t designato = block.origin + designatus + (tileX * 16 + tileY) * sizeof(t_designation);
printf("designation offset: 0x%x\n", designato); printf("designation offset: 0x%x\n", designato);
if(des.light)
std::cout << "Light "; #define PRINT_FLAG( X ) printf("%-16s= %c\n", #X , ( des.X ? 'Y' : ' ' ) )
else PRINT_FLAG( hidden );
std::cout << " "; PRINT_FLAG( light );
if(des.skyview) PRINT_FLAG( skyview );
std::cout << "SkyView "; PRINT_FLAG( subterranean );
else PRINT_FLAG( water_table );
std::cout << " "; //PRINT_FLAG( rained );
if(des.subterranean)
std::cout << "Underground "; planecoord pc;
else pc.dim.x=blockX; pc.dim.y=blockY;
std::cout << " ";
PRINT_FLAG( feature_local );
if( des.feature_local )
{
printf("%-16s %4d (%2d) %s\n", "",
block.local_feature,
local_features[pc][block.local_feature]->type,
sa_feature[local_features[pc][block.local_feature]->type]
);
}
PRINT_FLAG( feature_global );
if( des.feature_global ){
printf("%-16s %4d (%2d) %s\n", "",
block.global_feature,
global_features[block.global_feature].type,
sa_feature[global_features[block.global_feature].type]
);
}
#undef PRINT_FLAG
std::cout << std::endl; std::cout << std::endl;
} }
} }
DF->Detach();
#ifndef LINUX_BUILD #ifndef LINUX_BUILD
std::cout << "Done. Press any key to continue" << std::endl; std::cout << "Press any key to refresh..." << std::endl;
cin.ignore(); cin.ignore();
goto BEGIN_PROBE;
#endif #endif
return 0; return 0;
} }

@ -41,10 +41,9 @@ struct compare_pair_second
int main (int argc, const char* argv[]) int main (int argc, const char* argv[])
{ {
bool showhidden = false; bool showhidden = false;
bool showbaselayers = false; bool showbaselayers = false;
for(int i = 0; i < argc; i++) for(int i = 1; i < argc; i++)
{ {
string test = argv[i]; string test = argv[i];
if(test == "-a") if(test == "-a")
@ -95,7 +94,6 @@ int main (int argc, const char* argv[])
return 1; return 1;
} }
DFHack::Maps * Maps = DF->getMaps(); DFHack::Maps * Maps = DF->getMaps();
DFHack::Materials * Mats = DF->getMaterials(); DFHack::Materials * Mats = DF->getMaterials();

@ -10,45 +10,44 @@ using namespace std;
#include <DFHack.h> #include <DFHack.h>
#include <dfhack/DFTileTypes.h> #include <dfhack/DFTileTypes.h>
#include <argstream.h> //#include <argstream.h>
#define MAX_DIM 0x300 #define MAX_DIM 0x300
class Point
//TODO: turn into the official coord class for DFHack/DF
class Vertex
{ {
public: public:
Point(uint32_t x, uint32_t y, uint32_t z) Vertex(uint32_t _x, uint32_t _y, uint32_t _z):x(_x),y(_y),z(_z) {}
{ Vertex()
this->x = x;
this->y = y;
this->z = z;
}
Point()
{ {
x = y = z = 0; x = y = z = 0;
} }
bool operator==(const Point &other) const bool operator==(const Vertex &other) const
{ {
return (other.x == x && other.y == y && other.z == z); return (other.x == x && other.y == y && other.z == z);
} }
bool operator<(const Point &other) const // FIXME: <tomprince> peterix_: you could probably get away with not defining operator< if you defined a std::less specialization for Vertex.
bool operator<(const Vertex &other) const
{ {
// FIXME: could be changed to eliminate MAX_DIM and make std::map lookups faster?
return ( (z*MAX_DIM*MAX_DIM + y*MAX_DIM + x) < (other.z*MAX_DIM*MAX_DIM + other.y*MAX_DIM + other.x)); return ( (z*MAX_DIM*MAX_DIM + y*MAX_DIM + x) < (other.z*MAX_DIM*MAX_DIM + other.y*MAX_DIM + other.x));
} }
Point operator/(int number) const Vertex operator/(int number) const
{ {
return Point(x/number, y/number, z); return Vertex(x/number, y/number, z);
} }
Point operator%(int number) const Vertex operator%(int number) const
{ {
return Point(x%number, y%number, z); return Vertex(x%number, y%number, z);
} }
Point operator-(int number) const Vertex operator-(int number) const
{ {
return Point(x,y,z-number); return Vertex(x,y,z-number);
} }
Point operator+(int number) const Vertex operator+(int number) const
{ {
return Point(x,y,z+number); return Vertex(x,y,z+number);
} }
uint32_t x; uint32_t x;
uint32_t y; uint32_t y;
@ -58,7 +57,7 @@ class Point
class Block class Block
{ {
public: public:
Block(DFHack::Maps *_m, Point _bcoord) Block(DFHack::Maps *_m, Vertex _bcoord)
{ {
vector <DFHack::t_vein> veins; vector <DFHack::t_vein> veins;
m = _m; m = _m;
@ -97,23 +96,23 @@ class Block
valid = true; valid = true;
} }
} }
int16_t MaterialAt(Point p) int16_t MaterialAt(Vertex p)
{ {
return materials[p.x][p.y]; return materials[p.x][p.y];
} }
void ClearMaterialAt(Point p) void ClearMaterialAt(Vertex p)
{ {
materials[p.x][p.y] = -1; materials[p.x][p.y] = -1;
} }
int16_t TileTypeAt(Point p) int16_t TileTypeAt(Vertex p)
{ {
return raw.tiletypes[p.x][p.y]; return raw.tiletypes[p.x][p.y];
} }
DFHack::t_designation DesignationAt(Point p) DFHack::t_designation DesignationAt(Vertex p)
{ {
return raw.designation[p.x][p.y]; return raw.designation[p.x][p.y];
} }
bool setDesignationAt(Point p, DFHack::t_designation des) bool setDesignationAt(Vertex p, DFHack::t_designation des)
{ {
if(!valid) return false; if(!valid) return false;
dirty = true; dirty = true;
@ -136,7 +135,7 @@ class Block
volatile bool dirty; volatile bool dirty;
DFHack::Maps * m; DFHack::Maps * m;
DFHack::mapblock40d raw; DFHack::mapblock40d raw;
Point bcoord; Vertex bcoord;
int16_t materials[16][16]; int16_t materials[16][16];
int8_t bitmap[16][16]; int8_t bitmap[16][16];
}; };
@ -153,7 +152,7 @@ class MapCache
}; };
~MapCache() ~MapCache()
{ {
map<Point, Block *>::iterator p; map<Vertex, Block *>::iterator p;
for(p = blocks.begin(); p != blocks.end(); p++) for(p = blocks.begin(); p != blocks.end(); p++)
{ {
delete p->second; delete p->second;
@ -165,11 +164,11 @@ class MapCache
return valid; return valid;
} }
Block * BlockAt (Point blockcoord) Block * BlockAt (Vertex blockcoord)
{ {
if(!valid) return 0; if(!valid) return 0;
map <Point, Block*>::iterator iter = blocks.find(blockcoord); map <Vertex, Block*>::iterator iter = blocks.find(blockcoord);
if(iter != blocks.end()) if(iter != blocks.end())
{ {
return (*iter).second; return (*iter).second;
@ -186,7 +185,7 @@ class MapCache
} }
} }
uint16_t tiletypeAt (Point tilecoord) uint16_t tiletypeAt (Vertex tilecoord)
{ {
Block * b= BlockAt(tilecoord / 16); Block * b= BlockAt(tilecoord / 16);
if(b && b->valid) if(b && b->valid)
@ -196,7 +195,7 @@ class MapCache
return 0; return 0;
} }
int16_t materialAt (Point tilecoord) int16_t materialAt (Vertex tilecoord)
{ {
Block * b= BlockAt(tilecoord / 16); Block * b= BlockAt(tilecoord / 16);
if(b && b->valid) if(b && b->valid)
@ -205,7 +204,7 @@ class MapCache
} }
return 0; return 0;
} }
bool clearMaterialAt (Point tilecoord) bool clearMaterialAt (Vertex tilecoord)
{ {
Block * b= BlockAt(tilecoord / 16); Block * b= BlockAt(tilecoord / 16);
if(b && b->valid) if(b && b->valid)
@ -216,7 +215,7 @@ class MapCache
} }
DFHack::t_designation designationAt (Point tilecoord) DFHack::t_designation designationAt (Vertex tilecoord)
{ {
Block * b= BlockAt(tilecoord / 16); Block * b= BlockAt(tilecoord / 16);
if(b && b->valid) if(b && b->valid)
@ -227,7 +226,7 @@ class MapCache
temp.whole = 0; temp.whole = 0;
return temp; return temp;
} }
bool setDesignationAt (Point tilecoord, DFHack::t_designation des) bool setDesignationAt (Vertex tilecoord, DFHack::t_designation des)
{ {
Block * b= BlockAt(tilecoord / 16); Block * b= BlockAt(tilecoord / 16);
if(b && b->valid) if(b && b->valid)
@ -237,7 +236,7 @@ class MapCache
} }
return false; return false;
} }
bool testCoord (Point tilecoord) bool testCoord (Vertex tilecoord)
{ {
Block * b= BlockAt(tilecoord / 16); Block * b= BlockAt(tilecoord / 16);
if(b && b->valid) if(b && b->valid)
@ -249,7 +248,7 @@ class MapCache
bool WriteAll() bool WriteAll()
{ {
map<Point, Block *>::iterator p; map<Vertex, Block *>::iterator p;
for(p = blocks.begin(); p != blocks.end(); p++) for(p = blocks.begin(); p != blocks.end(); p++)
{ {
p->second->WriteDesignations(); p->second->WriteDesignations();
@ -265,24 +264,29 @@ class MapCache
uint32_t y_tmax; uint32_t y_tmax;
uint32_t z_max; uint32_t z_max;
DFHack::Maps * Maps; DFHack::Maps * Maps;
map<Point, Block *> blocks; map<Vertex, Block *> blocks;
}; };
int main (int argc, char* argv[]) int main (int argc, char* argv[])
{ {
// Command line options // Command line options
bool updown = false; bool updown = false;
/*
argstream as(argc,argv); argstream as(argc,argv);
as >>option('x',"updown",updown,"Dig up and down stairs to reach other z-levels.") as >>option('x',"updown",updown,"Dig up and down stairs to reach other z-levels.")
>>help(); >>help();
// sane check // sane check
if (!as.isOk()) if (!as.isOk())
{ {
cout << as.errorLog(); cout << as.errorLog();
return 1; return 1;
} }
*/
if(argc > 1 && strcmp(argv[1],"-x") == 0)
updown = true;
DFHack::ContextManager DFMgr("Memory.xml"); DFHack::ContextManager DFMgr("Memory.xml");
DFHack::Context * DF; DFHack::Context * DF;
@ -330,7 +334,7 @@ int main (int argc, char* argv[])
DF->Suspend(); DF->Suspend();
Pos->getCursorCoords(cx,cy,cz); Pos->getCursorCoords(cx,cy,cz);
} }
Point xy ((uint32_t)cx,(uint32_t)cy,cz); Vertex xy ((uint32_t)cx,(uint32_t)cy,cz);
if(xy.x == 0 || xy.x == tx_max - 1 || xy.y == 0 || xy.y == ty_max - 1) if(xy.x == 0 || xy.x == tx_max - 1 || xy.y == 0 || xy.y == ty_max - 1)
{ {
cerr << "I won't dig the borders. That would be cheating!" << endl; cerr << "I won't dig the borders. That would be cheating!" << endl;
@ -358,13 +362,13 @@ int main (int argc, char* argv[])
return 1; return 1;
} }
printf("%d/%d/%d tiletype: %d, veinmat: %d, designation: 0x%x ... DIGGING!\n", cx,cy,cz, tt, veinmat, des.whole); printf("%d/%d/%d tiletype: %d, veinmat: %d, designation: 0x%x ... DIGGING!\n", cx,cy,cz, tt, veinmat, des.whole);
stack <Point> flood; stack <Vertex> flood;
flood.push(xy); flood.push(xy);
while( !flood.empty() ) while( !flood.empty() )
{ {
Point current = flood.top(); Vertex current = flood.top();
flood.pop(); flood.pop();
int16_t vmat2 = MCache->materialAt(current); int16_t vmat2 = MCache->materialAt(current);
@ -402,30 +406,30 @@ int main (int argc, char* argv[])
MCache->clearMaterialAt(current); MCache->clearMaterialAt(current);
if(current.x < tx_max - 2) if(current.x < tx_max - 2)
{ {
flood.push(Point(current.x + 1, current.y, current.z)); flood.push(Vertex(current.x + 1, current.y, current.z));
if(current.y < ty_max - 2) if(current.y < ty_max - 2)
{ {
flood.push(Point(current.x + 1, current.y + 1,current.z)); flood.push(Vertex(current.x + 1, current.y + 1,current.z));
flood.push(Point(current.x, current.y + 1,current.z)); flood.push(Vertex(current.x, current.y + 1,current.z));
} }
if(current.y > 1) if(current.y > 1)
{ {
flood.push(Point(current.x + 1, current.y - 1,current.z)); flood.push(Vertex(current.x + 1, current.y - 1,current.z));
flood.push(Point(current.x, current.y - 1,current.z)); flood.push(Vertex(current.x, current.y - 1,current.z));
} }
} }
if(current.x > 1) if(current.x > 1)
{ {
flood.push(Point(current.x - 1, current.y,current.z)); flood.push(Vertex(current.x - 1, current.y,current.z));
if(current.y < ty_max - 2) if(current.y < ty_max - 2)
{ {
flood.push(Point(current.x - 1, current.y + 1,current.z)); flood.push(Vertex(current.x - 1, current.y + 1,current.z));
flood.push(Point(current.x, current.y + 1,current.z)); flood.push(Vertex(current.x, current.y + 1,current.z));
} }
if(current.y > 1) if(current.y > 1)
{ {
flood.push(Point(current.x - 1, current.y - 1,current.z)); flood.push(Vertex(current.x - 1, current.y - 1,current.z));
flood.push(Point(current.x, current.y - 1,current.z)); flood.push(Vertex(current.x, current.y - 1,current.z));
} }
} }
if(updown) if(updown)

@ -536,6 +536,7 @@ main(int argc, char *argv[])
vector<t_vein> veinVector; vector<t_vein> veinVector;
vector<t_frozenliquidvein> IceVeinVector; vector<t_frozenliquidvein> IceVeinVector;
vector<t_spattervein> splatter; vector<t_spattervein> splatter;
vector<t_grassvein> grass;
t_temperatures b_temp1; t_temperatures b_temp1;
t_temperatures b_temp2; t_temperatures b_temp2;
@ -549,7 +550,6 @@ main(int argc, char *argv[])
{ {
pDF = DF = DFMgr.getSingleContext(); pDF = DF = DFMgr.getSingleContext();
DF->Attach(); DF->Attach();
Mats = DF->getMaterials();
Maps = DF->getMaps(); Maps = DF->getMaps();
} }
catch (exception& e) catch (exception& e)
@ -560,6 +560,15 @@ main(int argc, char *argv[])
#endif #endif
finish(0); finish(0);
} }
bool hasmats = true;
try
{
Mats = DF->getMaterials();
}
catch (exception& e)
{
hasmats = false;
}
Process* p = DF->getProcess(); Process* p = DF->getProcess();
// init the map // init the map
@ -574,21 +583,26 @@ main(int argc, char *argv[])
y_max = y_max_a; y_max = y_max_a;
z_max = z_max_a; z_max = z_max_a;
// get stone matgloss mapping bool hasInorgMats = false;
if(!Mats->ReadInorganicMaterials()) bool hasPlantMats = false;
{ bool hasCreatureMats = false;
error = "Can't read stone types.";
pDF = 0; if(hasmats)
finish(0);
}
/*
if(!Mats->ReadCreatureTypes())
{ {
error = "Can't read stone types."; // get stone matgloss mapping
pDF = 0; if(Mats->ReadInorganicMaterials())
finish(0); {
hasInorgMats = true;
}
if(Mats->ReadCreatureTypes())
{
hasCreatureMats = true;
}
if(Mats->ReadOrganicMaterials())
{
hasPlantMats = true;
}
} }
*/
/* /*
// get region geology // get region geology
if(!DF.ReadGeology( layerassign )) if(!DF.ReadGeology( layerassign ))
@ -620,7 +634,9 @@ main(int argc, char *argv[])
{ {
TEMP_NO, TEMP_NO,
TEMP_1, TEMP_1,
TEMP_2 TEMP_2,
WATER_SALT,
WATER_STAGNANT
}; };
e_tempmode temperature = TEMP_NO; e_tempmode temperature = TEMP_NO;
@ -691,6 +707,12 @@ main(int argc, char *argv[])
case 'm': case 'm':
temperature = TEMP_2; temperature = TEMP_2;
break; break;
case 'c':
temperature = WATER_SALT;
break;
case 'v':
temperature = WATER_STAGNANT;
break;
case 27: // escape key case 27: // escape key
DF->Detach(); DF->Detach();
return 0; return 0;
@ -715,15 +737,29 @@ main(int argc, char *argv[])
IceVeinVector.clear(); IceVeinVector.clear();
effects.clear(); effects.clear();
splatter.clear(); splatter.clear();
grass.clear();
dirtybit = 0; dirtybit = 0;
// Supend, read/write data // Supend, read/write data
DF->Suspend(); DF->Suspend();
// restart cleared modules // restart cleared modules
Maps->Start(); Maps->Start();
Mats->Start(); if(hasmats)
Mats->ReadInorganicMaterials(); {
Mats->ReadCreatureTypes(); Mats->Start();
if(hasInorgMats)
{
Mats->ReadInorganicMaterials();
}
if(hasPlantMats)
{
Mats->ReadOrganicMaterials();
}
if(hasCreatureMats)
{
Mats->ReadCreatureTypes();
}
}
uint32_t effectnum; uint32_t effectnum;
/* /*
if(DF.InitReadEffects(effectnum)) if(DF.InitReadEffects(effectnum))
@ -739,17 +775,16 @@ main(int argc, char *argv[])
for(int i = -1; i <= 1; i++) for(int j = -1; j <= 1; j++) for(int i = -1; i <= 1; i++) for(int j = -1; j <= 1; j++)
{ {
mapblock40d * Block = &blocks[i+1][j+1]; mapblock40d * Block = &blocks[i+1][j+1];
if(Maps->isValidBlock(cursorX+i,cursorY+j,cursorZ)) if(Maps->isValidBlock(cursorX+i,cursorY+j,cursorZ))
{ {
Maps->ReadBlock40d(cursorX+i,cursorY+j,cursorZ, Block); Maps->ReadBlock40d(cursorX+i,cursorY+j,cursorZ, Block);
// extra processing of the block in the middle // extra processing of the block in the middle
if(i == 0 && j == 0) if(i == 0 && j == 0)
{ {
do_features(DF, Block, cursorX, cursorY, 50,10, Mats->inorganic); if(hasInorgMats)
do_features(DF, Block, cursorX, cursorY, 50,10, Mats->inorganic);
// read veins // read veins
Maps->ReadVeins(cursorX+i,cursorY+j,cursorZ,&veinVector,&IceVeinVector,&splatter); Maps->ReadVeins(cursorX+i,cursorY+j,cursorZ,&veinVector,&IceVeinVector,&splatter,&grass);
// get pointer to block // get pointer to block
blockaddr = Maps->getBlockPtr(cursorX+i,cursorY+j,cursorZ); blockaddr = Maps->getBlockPtr(cursorX+i,cursorY+j,cursorZ);
@ -849,11 +884,12 @@ main(int argc, char *argv[])
uint32_t mineralsize = veinVector.size(); uint32_t mineralsize = veinVector.size();
uint32_t icesize = IceVeinVector.size(); uint32_t icesize = IceVeinVector.size();
uint32_t splattersize = splatter.size(); uint32_t splattersize = splatter.size();
uint32_t totalVeinSize = mineralsize+ icesize + splattersize; uint32_t grasssize = grass.size();
uint32_t totalVeinSize = mineralsize+ icesize + splattersize + grasssize;
if(vein == totalVeinSize) vein = totalVeinSize - 1; if(vein == totalVeinSize) vein = totalVeinSize - 1;
if(vein < -1) vein = -1; if(vein < -1) vein = -1;
cprintf("X %d/%d, Y %d/%d, Z %d/%d. Vein %d of %d",cursorX+1,x_max,cursorY+1,y_max,cursorZ,z_max,vein+1,totalVeinSize); cprintf("X %d/%d, Y %d/%d, Z %d/%d. Vein %d of %d",cursorX+1,x_max,cursorY+1,y_max,cursorZ,z_max,vein+1,totalVeinSize);
if(!veinVector.empty() || !IceVeinVector.empty() || !splatter.empty()) if(!veinVector.empty() || !IceVeinVector.empty() || !splatter.empty() || !grass.empty())
{ {
if(vein != -1 && vein < totalVeinSize) if(vein != -1 && vein < totalVeinSize)
{ {
@ -883,8 +919,11 @@ main(int argc, char *argv[])
} }
} }
} }
gotoxy(50,3); if(hasInorgMats)
cprintf("Mineral: %s",Mats->inorganic[veinVector[vein].type].id); {
gotoxy(50,3);
cprintf("Mineral: %s",Mats->inorganic[veinVector[vein].type].id);
}
} }
else if (vein < mineralsize + icesize) else if (vein < mineralsize + icesize)
{ {
@ -906,7 +945,7 @@ main(int argc, char *argv[])
gotoxy(50,3); gotoxy(50,3);
cprintf("ICE"); cprintf("ICE");
} }
else else if(vein < mineralsize + icesize + splattersize)
{ {
realvein = vein - mineralsize - icesize; realvein = vein - mineralsize - icesize;
t_spattervein &bloodmud = splatter[realvein]; t_spattervein &bloodmud = splatter[realvein];
@ -923,8 +962,31 @@ main(int argc, char *argv[])
} }
} }
} }
if(hasCreatureMats)
{
gotoxy(50,3);
cprintf("Spatter: %s",PrintSplatterType(splatter[realvein].mat1,splatter[realvein].mat2,Mats->race).c_str());
}
}
else
{
realvein = vein - mineralsize - icesize - splattersize;
t_grassvein & grassy =grass[realvein];
for(uint32_t yyy = 0; yyy < 16; yyy++)
{
for(uint32_t xxx = 0; xxx < 16; xxx++)
{
uint8_t intensity = grassy.intensity[xxx][yyy];
if(intensity)
{
attron(A_STANDOUT);
putch(xxx+16,yyy+16,'X', COLOR_RED);
attroff(A_STANDOUT);
}
}
}
gotoxy(50,3); gotoxy(50,3);
cprintf("Spatter: %s",PrintSplatterType(splatter[realvein].mat1,splatter[realvein].mat2,Mats->race).c_str()); cprintf("Grass: 0x%x, %s",grassy.address_of, Mats->organic[grassy.material].id);
} }
} }
} }
@ -940,6 +1002,30 @@ main(int argc, char *argv[])
} }
} }
} }
else if(temperature == WATER_SALT)
{
for(int x = 0; x < 16; x++) for(int y = 0; y < 16; y++)
{
if(Block->designation[x][y].bits.water_salt)
{
putch(x + 16,y + 16,'@',COLOR_WHITE);
}
}
gotoxy (50,8);
cprintf ("Salt water");
}
else if(temperature == WATER_STAGNANT)
{
for(int x = 0; x < 16; x++) for(int y = 0; y < 16; y++)
{
if(Block->designation[x][y].bits.water_stagnant)
{
putch(x + 16,y + 16,'@',COLOR_WHITE);
}
}
gotoxy (50,8);
cprintf ("Stagnant water");
}
else else
{ {
if(temperature == TEMP_1) if(temperature == TEMP_1)

@ -43,8 +43,25 @@ void printWeather(DFHack::WeatherType current)
} }
using namespace DFHack; using namespace DFHack;
int main (int numargs, const char ** args) int main (int argc, char** argv)
{ {
string command = "";
bool quiet = false;
bool cmdarg = false;
for(int i = 1; i < argc; i++)
{
string test = argv[i];
if(test == "-q")
{
quiet = true;
}
else
{
command = test;
cmdarg = true;
}
}
DFHack::ContextManager DFMgr("Memory.xml"); DFHack::ContextManager DFMgr("Memory.xml");
DFHack::Context *DF = DFMgr.getSingleContext(); DFHack::Context *DF = DFMgr.getSingleContext();
@ -68,9 +85,8 @@ int main (int numargs, const char ** args)
{ {
WeatherType current = (WeatherType) W->ReadCurrentWeather(); WeatherType current = (WeatherType) W->ReadCurrentWeather();
DF->Resume(); DF->Resume();
string command = "";
printWeather(current); printWeather(current);
getline(cin, command); if (command == "") getline(cin, command); // only read from stdin if command hasn't been passed on the console
DF->Suspend(); DF->Suspend();
if(command == "c") if(command == "c")
{ {
@ -88,11 +104,17 @@ int main (int numargs, const char ** args)
{ {
end = true; end = true;
} }
command = "";
if(cmdarg) end = true; // exit the loop when a cmd line arg has been passed.
} }
#ifndef LINUX_BUILD #ifndef LINUX_BUILD
std::cout << "Done. Press any key to continue" << std::endl; if (!quiet)
cin.ignore(); {
std::cout << "Done. Press any key to continue" << std::endl;
cin.ignore();
}
#endif #endif
DF->Resume();
DF->Detach(); DF->Detach();
return 0; return 0;
} }