diff --git a/dfhack/DFHackAPI.cpp b/dfhack/DFHackAPI.cpp index b023ccbd6..995a7326c 100644 --- a/dfhack/DFHackAPI.cpp +++ b/dfhack/DFHackAPI.cpp @@ -66,6 +66,10 @@ API::~API() bool API::Attach() { + if(d->p != NULL) + { + return d->p->suspend(); + } // detach all processes, destroy manager if (d->pm == 0) { diff --git a/dfhack/DFMemInfo.cpp b/dfhack/DFMemInfo.cpp index 7f0d9ef0a..549842c4b 100644 --- a/dfhack/DFMemInfo.cpp +++ b/dfhack/DFMemInfo.cpp @@ -227,7 +227,7 @@ void memory_info::setProfession (const string & key, const string & value) uint32_t keyInt = strtol(key.c_str(), NULL, 10); if(d->professions.size() <= keyInt) { - d->professions.resize(keyInt+1); + d->professions.resize(keyInt+1,""); } d->professions[keyInt] = value; } diff --git a/dfhack/include/DFError.h b/dfhack/include/DFError.h index 15086b9bb..34cd69839 100644 --- a/dfhack/include/DFError.h +++ b/dfhack/include/DFError.h @@ -78,14 +78,22 @@ namespace DFHack class DFHACK_EXPORT MissingMemoryDefinition : public std::exception { public: - MissingMemoryDefinition(const char* _type, const char* _key) : type(_type), key(_key) {} + MissingMemoryDefinition(const char* _type, const char* _key) : type(_type), key(_key) + { + std::stringstream s; + s << "memory definition missing: type " << type << " key " << key; + full = s.str(); + } // Used by functios using integer keys, such as getTrait MissingMemoryDefinition(const char* _type, uint32_t _key) : type(_type) { - // FIXME fancy hex printer goes here + std::stringstream s1; + s1 << _key; + key = s1.str(); + std::stringstream s; - s << _key; - key = s.str(); + s << "memory definition missing: type " << type << " key " << key; + full = s.str(); } virtual ~MissingMemoryDefinition() throw(){}; @@ -102,14 +110,13 @@ namespace DFHack // trait // traitname // labor + std::string full; const std::string type; std::string key; virtual const char* what() const throw() { - std::stringstream s; - s << "memory definition missing: type " << type << " key " << key; - return s.str().c_str(); + return full.c_str(); } }; @@ -117,9 +124,16 @@ namespace DFHack class DFHACK_EXPORT MemoryXmlParse : public std::exception { public: - MemoryXmlParse(const char* _desc, int _id, int _row, int _col) : - desc(_desc), id(_id), row(_row), col(_col) {} + MemoryXmlParse(const char* _desc, int _id, int _row, int _col) + :desc(_desc), id(_id), row(_row), col(_col) + { + std::stringstream s; + s << "error " << id << ": " << desc << ", at row " << row << " col " << col; + full = s.str(); + } + + std::string full; const std::string desc; const int id; const int row; @@ -129,26 +143,27 @@ namespace DFHack virtual const char* what() const throw() { - std::stringstream s; - s << "error " << id << ": " << desc << ", at row " << row << " col " << col; - return s.str().c_str(); + return full.c_str(); } }; class DFHACK_EXPORT MemoryXmlBadAttribute : public std::exception { public: - MemoryXmlBadAttribute(const char* _attr) : attr(_attr) {} - + MemoryXmlBadAttribute(const char* _attr) : attr(_attr) + { + std::stringstream s; + s << "attribute is either missing or invalid: " << attr; + full = s.str(); + } + std::string full; std::string attr; virtual ~MemoryXmlBadAttribute() throw(){}; virtual const char* what() const throw() { - std::stringstream s; - s << "attribute is either missing or invalid: " << attr; - return s.str().c_str(); + return full.c_str(); } }; @@ -168,46 +183,58 @@ namespace DFHack class DFHACK_EXPORT MemoryXmlNoDFExtractor : public std::exception { public: - MemoryXmlNoDFExtractor(const char* _name) : name(_name) {} + MemoryXmlNoDFExtractor(const char* _name) : name(_name) + { + std::stringstream s; + s << "DFExtractor != " << name; + full = s.str(); + } virtual ~MemoryXmlNoDFExtractor() throw(){}; std::string name; + std::string full; virtual const char* what() const throw() { - std::stringstream s; - s << "DFExtractor != " << name; - return s.str().c_str(); + return full.c_str(); } }; class DFHACK_EXPORT MemoryXmlUnderspecifiedEntry : public std::exception { public: - MemoryXmlUnderspecifiedEntry(const char * _where) : where(_where) {} + MemoryXmlUnderspecifiedEntry(const char * _where) : where(_where) + { + std::stringstream s; + s << "underspecified MemInfo entry, each entry needs to set both the name attribute and have a value. parent: " << where; + full = s.str(); + } virtual ~MemoryXmlUnderspecifiedEntry() throw(){}; std::string where; + std::string full; virtual const char* what() const throw() { - std::stringstream s; - s << "underspecified MemInfo entry, each entry needs to set both the name attribute and have a value. parent: " << where; - return s.str().c_str(); + return full.c_str(); } }; class DFHACK_EXPORT MemoryXmlUnknownType : public std::exception { public: - MemoryXmlUnknownType(const char* _type) : type(_type) {} + MemoryXmlUnknownType(const char* _type) : type(_type) + { + std::stringstream s; + s << "unknown MemInfo type: " << type; + full = s.str(); + } virtual ~MemoryXmlUnknownType() throw(){}; std::string type; + std::string full; virtual const char* what() const throw() { - std::stringstream s; - s << "unknown MemInfo type: " << type; - return s.str().c_str(); + return full.c_str(); } }; @@ -224,16 +251,20 @@ namespace DFHack class DFHACK_EXPORT SHMLockingError : public std::exception { public: - SHMLockingError(const char* _type) : type(_type) {} + SHMLockingError(const char* _type) : type(_type) + { + std::stringstream s; + s << "SHM locking error: " << type; + full = s.str(); + } virtual ~SHMLockingError() throw(){}; std::string type; + std::string full; virtual const char* what() const throw() { - std::stringstream s; - s << "SHM locking error: " << type; - return s.str().c_str(); + return full.c_str(); } }; class DFHACK_EXPORT MemoryAccessDenied : public std::exception @@ -241,9 +272,6 @@ namespace DFHack public: MemoryAccessDenied() {} virtual ~MemoryAccessDenied() throw(){}; - - std::string type; - virtual const char* what() const throw() { return "SHM ACCESS DENIED"; @@ -254,9 +282,6 @@ namespace DFHack public: SHMVersionMismatch() {} virtual ~SHMVersionMismatch() throw(){}; - - std::string type; - virtual const char* what() const throw() { return "SHM VERSION MISMATCH"; @@ -267,9 +292,6 @@ namespace DFHack public: SHMAttachFailure() {} virtual ~SHMAttachFailure() throw(){}; - - std::string type; - virtual const char* what() const throw() { return "SHM ATTACH FAILURE"; diff --git a/dfhack/include/modules/Maps.h b/dfhack/include/modules/Maps.h index 883fa61ae..ddeac55de 100644 --- a/dfhack/include/modules/Maps.h +++ b/dfhack/include/modules/Maps.h @@ -11,7 +11,37 @@ namespace DFHack /*************************************************************************** T Y P E S ***************************************************************************/ - + + enum e_feature + { + feature_Adamantine_Tube, + feature_Underworld, + // add stuff here, don't reorder or delete + feature_Other = 10000, + }; + union planecoord + { + uint32_t xy; + struct + { + uint16_t x; + uint16_t y; + } dim; + bool operator<(const planecoord &other) const + { + if(other.xy < xy) return true; + return false; + } + }; + struct t_feature + { + e_feature type; + int16_t main_material; + int32_t sub_material; + bool discovered; // placeholder. + uint32_t origin; + }; + struct t_vein { uint32_t vtable; @@ -52,7 +82,7 @@ namespace DFHack eSouthEast, eBiomeCount }; - + enum e_traffic { traffic_normal, @@ -210,6 +240,8 @@ namespace DFHack biome_indices40d biome_indices; uint32_t origin; // the address where it came from t_blockflags blockflags; + int16_t global_feature; + int16_t local_feature; } mapblock40d; /*************************************************************************** @@ -259,7 +291,14 @@ namespace DFHack } */ bool ReadGeology( std::vector < std::vector >& assign ); - + vector global_features; + // map between feature address and the read object + map local_feature_store; + // map between mangled coords and pointer to feature + + + bool ReadGlobalFeatures( std::vector & features); + bool ReadLocalFeatures( std::map > & local_features ); /* * BLOCK DATA */ diff --git a/dfhack/modules/Maps.cpp b/dfhack/modules/Maps.cpp index b562ed655..f2e6df197 100644 --- a/dfhack/modules/Maps.cpp +++ b/dfhack/modules/Maps.cpp @@ -54,6 +54,10 @@ struct Maps::Private Process * owner; bool Inited; bool Started; + + // map between feature address and the read object + map local_feature_store; + vector v_geology[eBiomeCount]; }; @@ -77,9 +81,29 @@ Maps::Maps(APIPrivate* _d) off.occupancy_offset = mem->getOffset("map_data_occupancy"); off.biome_stuffs = mem->getOffset ("map_data_biome_stuffs"); off.veinvector = mem->getOffset ("map_data_vein_vector"); + off.local_feature_offset = mem->getOffset ("map_data_feature_local"); + off.global_feature_offset = mem->getOffset ("map_data_feature_global"); + off.temperature1_offset = mem->getOffset ("map_data_temperature1_offset"); off.temperature2_offset = mem->getOffset ("map_data_temperature2_offset"); - + off.region_x_offset = mem->getAddress ("region_x"); + off.region_y_offset = mem->getAddress ("region_y"); + off.region_z_offset = mem->getAddress ("region_z"); + + + off.world_regions = mem->getAddress ("ptr2_region_array"); + off.region_size = mem->getHexValue ("region_size"); + off.region_geo_index_offset = mem->getOffset ("region_geo_index_off"); + off.geolayer_geoblock_offset = mem->getOffset ("geolayer_geoblock_offset"); + off.world_geoblocks_vector = mem->getAddress ("geoblock_vector"); + off.type_inside_geolayer = mem->getOffset ("type_inside_geolayer"); + + off.world_size_x = mem->getAddress ("world_size_x"); + off.world_size_y = mem->getAddress ("world_size_y"); + + + + // these can fail and will be found when looking at the actual veins later // basically a cache off.vein_ice_vptr = 0; @@ -138,6 +162,11 @@ bool Maps::Start() //return false; } + // read position of the region inside DF world + p->readDWord (off.region_x_offset, d->regionX); + p->readDWord (off.region_y_offset, d->regionY); + p->readDWord (off.region_z_offset, d->regionZ); + // alloc array for pointers to all blocks d->block = new uint32_t[mx*my*mz]; uint32_t *temp_x = new uint32_t[mx]; @@ -157,6 +186,7 @@ bool Maps::Start() } delete [] temp_x; delete [] temp_y; + d->Started = true; return true; } @@ -168,8 +198,10 @@ void Maps::getSize (uint32_t& x, uint32_t& y, uint32_t& z) z = d->z_block_count; } +// invalidates local and global features! bool Maps::Finish() { + d->local_feature_store.clear(); if (d->block != NULL) { delete [] d->block; @@ -219,6 +251,8 @@ bool Maps::ReadBlock40d(uint32_t x, uint32_t y, uint32_t z, mapblock40d * buffer p->read (addr + d->offsets.designation_offset, sizeof (buffer->designation), (uint8_t *) buffer->designation); p->read (addr + d->offsets.occupancy_offset, sizeof (buffer->occupancy), (uint8_t *) buffer->occupancy); p->read (addr + d->offsets.biome_stuffs, sizeof (biome_indices40d), (uint8_t *) buffer->biome_indices); + p->readWord(addr + d->offsets.global_feature_offset, (uint16_t&) buffer->global_feature); + p->readWord(addr + d->offsets.local_feature_offset, (uint16_t&)buffer->local_feature); buffer->origin = addr; uint32_t addr_of_struct = p->readDWord(addr); buffer->blockflags.whole = p->readDWord(addr_of_struct); @@ -557,45 +591,26 @@ bool Maps::ReadGeology (vector < vector >& assign) memory_info * minfo = d->d->offset_descriptor; Process *p = d->owner; // get needed addresses and offsets. Now this is what I call crazy. - int region_x_offset = minfo->getAddress ("region_x"); - int region_y_offset = minfo->getAddress ("region_y"); - int region_z_offset = minfo->getAddress ("region_z"); - int world_regions = minfo->getAddress ("ptr2_region_array"); - int region_size = minfo->getHexValue ("region_size"); - int region_geo_index_offset = minfo->getOffset ("region_geo_index_off"); - int world_geoblocks_vector = minfo->getAddress ("geoblock_vector"); - int world_size_x = minfo->getAddress ("world_size_x"); - int world_size_y = minfo->getAddress ("world_size_y"); - int geolayer_geoblock_offset = minfo->getOffset ("geolayer_geoblock_offset"); - - int type_inside_geolayer = minfo->getOffset ("type_inside_geolayer"); - - uint32_t regionX, regionY, regionZ; uint16_t worldSizeX, worldSizeY; - - // read position of the region inside DF world - p->readDWord (region_x_offset, regionX); - p->readDWord (region_y_offset, regionY); - p->readDWord (region_z_offset, regionZ); - + Server::Maps::maps_offsets &off = d->offsets; // get world size - p->readWord (world_size_x, worldSizeX); - p->readWord (world_size_y, worldSizeY); + p->readWord (off.world_size_x, worldSizeX); + p->readWord (off.world_size_y, worldSizeY); // get pointer to first part of 2d array of regions - uint32_t regions = p->readDWord (world_regions); + uint32_t regions = p->readDWord (off.world_regions); // read the geoblock vector - DfVector geoblocks (d->d->p, world_geoblocks_vector); + DfVector geoblocks (d->d->p, off.world_geoblocks_vector); // iterate over 8 surrounding regions + local region for (int i = eNorthWest; i < eBiomeCount; i++) { // check against worldmap boundaries, fix if needed - int bioRX = regionX / 16 + (i % 3) - 1; + int bioRX = d->regionX / 16 + (i % 3) - 1; if (bioRX < 0) bioRX = 0; if (bioRX >= worldSizeX) bioRX = worldSizeX - 1; - int bioRY = regionY / 16 + (i / 3) - 1; + int bioRY = d->regionY / 16 + (i / 3) - 1; if (bioRY < 0) bioRY = 0; if (bioRY >= worldSizeY) bioRY = worldSizeY - 1; @@ -607,7 +622,7 @@ bool Maps::ReadGeology (vector < vector >& assign) // get index into geoblock vector uint16_t geoindex; - p->readWord (geoX + bioRY*region_size + region_geo_index_offset, geoindex); + p->readWord (geoX + bioRY*off.region_size + off.region_geo_index_offset, geoindex); /// geology blocks are assigned to regions from a vector // get the geoblock from the geoblock vector using the geoindex @@ -616,7 +631,7 @@ bool Maps::ReadGeology (vector < vector >& assign) /// geology blocks have a vector of layer descriptors // get the vector with pointer to layers - DfVector geolayers (p, geoblock_off + geolayer_geoblock_offset); // let's hope + DfVector geolayers (p, geoblock_off + off.geolayer_geoblock_offset); // let's hope // make sure we don't load crap assert (geolayers.size() > 0 && geolayers.size() <= 16); @@ -628,7 +643,7 @@ bool Maps::ReadGeology (vector < vector >& assign) // read pointer to a layer uint32_t geol_offset = geolayers[j]; // read word at pointer + 2, store in our geology vectors - d->v_geology[i].push_back (p->readWord (geol_offset + type_inside_geolayer)); + d->v_geology[i].push_back (p->readWord (geol_offset + off.type_inside_geolayer)); } } assign.clear(); @@ -639,3 +654,138 @@ bool Maps::ReadGeology (vector < vector >& assign) } return true; } + +bool Maps::ReadLocalFeatures( std::map > & local_features ) +{ + // can't be used without a map! + if(!d->block) + return false; + + Process * p = d->owner; + memory_info * mem = p->getDescriptor(); + // deref pointer to the humongo-structure + uint32_t base = p->readDWord(mem->getAddress("local_feature_start_ptr")); + uint32_t sizeof_vec = mem->getHexValue("sizeof_vector"); + const uint32_t sizeof_elem = 16; + const uint32_t offset_elem = 4; + const uint32_t main_mat_offset = 0x30; + const uint32_t sub_mat_offset = 0x34; + + local_features.clear(); + + for(uint32_t blockX = 0; blockX < d->x_block_count; blockX ++) + for(uint32_t blockY = 0; blockY < d->x_block_count; blockY ++) + { + //uint64_t block48_x = blockX / 3 + d->regionX; + //uint16_t region_x_plus8 = ( block48_x + 8 ) / 16; + + // region X coord offset by 8 big blocks (48x48 tiles) + uint16_t region_x_plus8 = ( (blockX / 3 ) + d->regionX /*+ 8*/ ) / 16; + //((BYTE4(region_x_local) & 0xF) + (_DWORD)region_x_local) >> 4; + //int16_t region_x_local = (blockX / 3) + d->regionX; + //int16_t region_x_plus8 = ((region_x_local & 0xF) + region_x_local) >> 4; + // plain region Y coord + uint64_t region_y_local = ( (blockY / 3) + d->regionY ) / 16; + + // this is just a few pointers to arrays of 16B (4 DWORD) structs + uint32_t array_elem = p->readDWord(base + (region_x_plus8 / 16) * 4); + + // 16B structs, second DWORD of the struct is a pointer + uint32_t wtf = p->readDWord(array_elem + ( sizeof_elem * (region_y_local/16)) + offset_elem); + if(wtf) + { + // wtf + sizeof(vector) * crap; + uint32_t feat_vector = wtf + sizeof_vec * (16 * (region_x_plus8 % 16) + (region_y_local % 16)); + DfVector p_features(p, feat_vector); + uint32_t size = p_features.size(); + planecoord pc; + pc.dim.x = blockX; + pc.dim.y = blockY; + std::vector tempvec; + for(uint32_t i = 0; i < size; i++) + { + uint32_t cur_ptr = p_features[i]; + + map ::iterator it; + it = d->local_feature_store.find(cur_ptr); + // do we already have the feature? + if(it != d->local_feature_store.end()) + { + // push pointer to existing feature + tempvec.push_back(&((*it).second)); + } + // no? + else + { + // create, add to store + t_feature tftemp; + tftemp.discovered = false; //= p->readDWord(cur_ptr + 4); + tftemp.origin = cur_ptr; + string name = p->readClassName(p->readDWord( cur_ptr )); + if(name == "feature_init_deep_special_tubest") + { + tftemp.main_material = p->readWord( cur_ptr + main_mat_offset ); + tftemp.sub_material = p->readDWord( cur_ptr + sub_mat_offset ); + tftemp.type = feature_Adamantine_Tube; + } + else + { + tftemp.main_material = -1; + tftemp.sub_material = -1; + tftemp.type = feature_Other; + } + d->local_feature_store[cur_ptr] = tftemp; + // push pointer + tempvec.push_back(&(d->local_feature_store[cur_ptr])); + } + } + local_features[pc] = tempvec; + } + } + return true; +} + +bool Maps::ReadGlobalFeatures( std::vector & features) +{ + // can't be used without a map! + if(!d->block) + return false; + + Process * p = d->owner; + memory_info * mem = p->getDescriptor(); + + uint32_t global_feature_vector = mem->getAddress("global_feature_vector"); + uint32_t global_feature_funcptr = mem->getOffset("global_feature_funcptr_"); + const uint32_t main_mat_offset = 0x34; + const uint32_t sub_mat_offset = 0x38; + DfVector p_features (p,global_feature_vector); + + features.clear(); + uint32_t size = p_features.size(); + features.reserve(size); + for(uint32_t i = 0; i < size; i++) + { + t_feature temp; + uint32_t feat_ptr = p->readDWord(p_features[i] + global_feature_funcptr ); + temp.origin = feat_ptr; + //temp.discovered = p->readDWord( feat_ptr + 4 ); // maybe, placeholder + temp.discovered = false; + + // FIXME: use the memory_info cache mechanisms + string name = p->readClassName(p->readDWord( feat_ptr)); + if(name == "feature_init_underworld_from_layerst") + { + temp.main_material = p->readWord( feat_ptr + main_mat_offset ); + temp.sub_material = p->readDWord( feat_ptr + sub_mat_offset ); + temp.type = feature_Underworld; + } + else + { + temp.main_material = -1; + temp.sub_material = -1; + temp.type = feature_Other; + } + features.push_back(temp); + } + return true; +} \ No newline at end of file diff --git a/dfhack/python/DF_API.cpp b/dfhack/python/DF_API.cpp index 0f227f55f..f80534353 100644 --- a/dfhack/python/DF_API.cpp +++ b/dfhack/python/DF_API.cpp @@ -29,6 +29,7 @@ distribution. #include #include "DFTypes.h" #include "DFHackAPI.h" +#include "DF_Imports.cpp" #include "DF_MemInfo.cpp" #include "DF_Position.cpp" #include "DF_Material.cpp" @@ -54,6 +55,11 @@ struct DF_API PyObject* construction; PyObject* vegetation; PyObject* gui; + + PyObject* map_type; + PyObject* vegetation_type; + PyObject* gui_type; + DFHack::API* api_Ptr; }; @@ -87,6 +93,10 @@ static int DF_API_init(DF_API* self, PyObject* args, PyObject* kwds) self->vegetation = NULL; self->gui = NULL; + self->map_type = (PyObject*)&DF_Map_type; + self->vegetation_type = (PyObject*)&DF_Vegetation_type; + self->gui_type = (PyObject*)&DF_GUI_type; + if(!PyArg_ParseTuple(args, "s", &memFileString)) return -1; @@ -310,7 +320,7 @@ static PyObject* DF_API_getMap(DF_API* self, void* closure) { if(self->api_Ptr != NULL) { - self->map = PyObject_Call((PyObject*)&DF_Map_type, NULL, NULL); + self->map = PyObject_CallObject(self->map_type, NULL); if(self->map != NULL) { @@ -397,7 +407,7 @@ static PyObject* DF_API_getVegetation(DF_API* self, void* closure) { if(self->api_Ptr != NULL) { - self->vegetation = PyObject_Call((PyObject*)&DF_Vegetation_type, NULL, NULL); + self->vegetation = PyObject_CallObject(self->vegetation_type, NULL); if(self->vegetation != NULL) { @@ -426,7 +436,7 @@ static PyObject* DF_API_getGUI(DF_API* self, void* closure) { if(self->api_Ptr != NULL) { - self->gui = PyObject_Call((PyObject*)&DF_GUI_type, NULL, NULL); + self->gui = PyObject_CallObject(self->gui_type, NULL); if(self->gui != NULL) { @@ -446,6 +456,81 @@ static PyObject* DF_API_getGUI(DF_API* self, void* closure) Py_RETURN_NONE; } +static PyObject* DF_API_getMapType(DF_API* self, void* closure) +{ + return self->map_type; +} + +static int DF_API_setMapType(DF_API* self, PyObject* value) +{ + if(PyType_Check(value) <= 0) + { + PySys_WriteStdout("failed type check"); + PyErr_SetString(PyExc_TypeError, "value must be a type object"); + return -1; + } + if(PyObject_IsSubclass(value, (PyObject*)&DF_Map_type) <= 0) + { + PySys_WriteStdout("failed subclass check"); + PyErr_SetString(PyExc_TypeError, "value must be descended from pydfhack._MapManager"); + return -1; + } + + self->map_type = value; + + return 0; +} + +static PyObject* DF_API_getVegetationType(DF_API* self, void* closure) +{ + return self->vegetation_type; +} + +static int DF_API_setVegetationType(DF_API* self, PyObject* value) +{ + if(PyType_Check(value) <= 0) + { + PySys_WriteStdout("failed type check"); + PyErr_SetString(PyExc_TypeError, "value must be a type object"); + return -1; + } + if(PyObject_IsSubclass(value, (PyObject*)&DF_Vegetation_type) <= 0) + { + PySys_WriteStdout("failed subclass check"); + PyErr_SetString(PyExc_TypeError, "value must be descended from pydfhack._VegetationManager"); + return -1; + } + + self->vegetation_type = value; + + return 0; +} + +static PyObject* DF_API_getGUIType(DF_API* self, void* closure) +{ + return self->gui_type; +} + +static int DF_API_setGUIType(DF_API* self, PyObject* value) +{ + if(PyType_Check(value) <= 0) + { + PySys_WriteStdout("failed type check"); + PyErr_SetString(PyExc_TypeError, "value must be a type object"); + return -1; + } + if(PyObject_IsSubclass(value, (PyObject*)&DF_GUI_type) <= 0) + { + PySys_WriteStdout("failed subclass check"); + PyErr_SetString(PyExc_TypeError, "value must be descended from pydfhack._GUIManager"); + return -1; + } + + self->gui_type = value; + + return 0; +} + static PyGetSetDef DF_API_getterSetters[] = { {"is_attached", (getter)DF_API_getIsAttached, NULL, "is_attached", NULL}, @@ -459,6 +544,9 @@ static PyGetSetDef DF_API_getterSetters[] = {"constructions", (getter)DF_API_getConstruction, NULL, "constructions", NULL}, {"vegetation", (getter)DF_API_getVegetation, NULL, "vegetation", NULL}, {"gui", (getter)DF_API_getGUI, NULL, "gui", NULL}, + {"_map_mgr_type", (getter)DF_API_getMapType, (setter)DF_API_setMapType, "_map_mgr_type", NULL}, + {"_vegetation_mgr_type", (getter)DF_API_getVegetationType, (setter)DF_API_setVegetationType, "_vegetation_mgr_type", NULL}, + {"_gui_mgr_type", (getter)DF_API_getGUIType, (setter)DF_API_setGUIType, "_gui_mgr_type", NULL}, {NULL} // Sentinel }; @@ -565,7 +653,7 @@ static PyTypeObject DF_API_type = { PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ - "pydfhack.API", /*tp_name*/ + "pydfhack._API", /*tp_name*/ sizeof(DF_API), /*tp_basicsize*/ 0, /*tp_itemsize*/ (destructor)DF_API_dealloc, /*tp_dealloc*/ @@ -584,7 +672,7 @@ static PyTypeObject DF_API_type = 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ - "pydfhack API objects", /* tp_doc */ + "pydfhack _API objects", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ diff --git a/dfhack/python/DF_Buildings.cpp b/dfhack/python/DF_Buildings.cpp index 1028074f2..00bfe146e 100644 --- a/dfhack/python/DF_Buildings.cpp +++ b/dfhack/python/DF_Buildings.cpp @@ -26,6 +26,12 @@ distribution. #define __DFBUILDINGS__ #include "Python.h" +#include +#include + +using namespace std; + +#include "DFTypes.h" #include "modules/Buildings.h" #include "DF_Helpers.cpp" @@ -38,22 +44,40 @@ static PyObject* BuildBuilding(DFHack::t_building& building) t_dict = PyDict_New(); - temp = PyInt_FromLong(building.origin); - DICTADD(t_dict, "origin", temp); + temp = Py_BuildValue("(si)(si)(si)(sO)(s((ii)(ii)i))", \ + "origin", building.origin, \ + "vtable", building.vtable, \ + "type", building.type, \ + "material", BuildMatglossPair(building.material), \ + "bounds", Py_BuildValue("(ii)(ii)i", building.x1, building.y1, building.x2, building.y2, building.z)); - temp = PyInt_FromLong(building.vtable); - DICTADD(t_dict, "vtable", temp); + PyDict_MergeFromSeq2(t_dict, temp, 0); - temp = PyInt_FromLong(building.type); - DICTADD(t_dict, "type", temp); + return t_dict; +} + +static DFHack::t_building ReverseBuildBuilding(PyObject* bDict) +{ + PyObject* temp; + uint32_t x1, y1, x2, y2, z; + DFHack::t_building building; - temp = BuildMatglossPair(building.material); - DICTADD(t_dict, "material", temp); + building.origin = (uint32_t)PyInt_AsLong(PyDict_GetItemString(bDict, "origin")); + building.vtable = (uint32_t)PyInt_AsLong(PyDict_GetItemString(bDict, "vtable")); + building.material = ReverseBuildMatglossPair(PyDict_GetItemString(bDict, "material")); + building.type = (uint32_t)PyInt_AsLong(PyDict_GetItemString(bDict, "type")); - temp = PyTuple_Pack(2, PyTuple_Pack(2, building.x1, building.y1), PyTuple_Pack(2, building.x2, building.y2)); - DICTADD(t_dict, "bounds", temp); + temp = PyDict_GetItemString(bDict, "bounds"); - return t_dict; + PyArg_ParseTuple(temp, "(ii)(ii)i", &x1, &y1, &x2, &y2, &z); + + building.x1 = x1; + building.y1 = y1; + building.x2 = x2; + building.y2 = y2; + building.z = z; + + return building; } struct DF_Building @@ -151,11 +175,53 @@ static PyObject* DF_Building_Read(DF_Building* self, PyObject* args) Py_RETURN_NONE; } +static PyObject* DF_Building_ReadCustomWorkshopTypes(DF_Building* self, PyObject* args) +{ + PyObject* bDict; + std::map bTypes; + std::map::iterator bIter; + + if(self->b_Ptr != NULL) + { + if(self->b_Ptr->ReadCustomWorkshopTypes(bTypes)) + { + bDict = PyDict_New(); + + for(bIter = bTypes.begin(); bIter != bTypes.end(); bIter++) + { + PyObject* temp = Py_BuildValue("is", (*bIter).first, (*bIter).second.c_str()); + + PyDict_MergeFromSeq2(bDict, temp, 1); + } + + return bDict; + } + } + + Py_RETURN_NONE; +} + +static PyObject* DF_Building_GetCustomWorkshopType(DF_Building* self, PyObject* args) +{ + DFHack::t_building building; + + if(self->b_Ptr != NULL) + { + building = ReverseBuildBuilding(args); + + return PyInt_FromLong(self->b_Ptr->GetCustomWorkshopType(building)); + } + + Py_RETURN_NONE; +} + static PyMethodDef DF_Building_methods[] = { {"Start", (PyCFunction)DF_Building_Start, METH_NOARGS, ""}, {"Finish", (PyCFunction)DF_Building_Finish, METH_NOARGS, ""}, {"Read", (PyCFunction)DF_Building_Read, METH_VARARGS, ""}, + {"Read_Custom_Workshop_Types", (PyCFunction)DF_Building_ReadCustomWorkshopTypes, METH_NOARGS, ""}, + {"Get_Custom_Workshop_Type", (PyCFunction)DF_Building_GetCustomWorkshopType, METH_VARARGS, ""}, {NULL} // Sentinel }; diff --git a/dfhack/python/DF_Constructions.cpp b/dfhack/python/DF_Constructions.cpp index 237efb479..0bfe99320 100644 --- a/dfhack/python/DF_Constructions.cpp +++ b/dfhack/python/DF_Constructions.cpp @@ -178,7 +178,7 @@ static PyTypeObject DF_Construction_type = { PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ - "pydfhack.Construction", /*tp_name*/ + "pydfhack._ConstructionManager", /*tp_name*/ sizeof(DF_Construction), /*tp_basicsize*/ 0, /*tp_itemsize*/ (destructor)DF_Construction_dealloc, /*tp_dealloc*/ @@ -197,7 +197,7 @@ static PyTypeObject DF_Construction_type = 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ - "pydfhack Construction objects", /* tp_doc */ + "pydfhack ConstructionManager object", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ diff --git a/dfhack/python/DF_CreatureManager.cpp b/dfhack/python/DF_CreatureManager.cpp index 43e08f230..c9b4136c8 100644 --- a/dfhack/python/DF_CreatureManager.cpp +++ b/dfhack/python/DF_CreatureManager.cpp @@ -26,6 +26,7 @@ distribution. #define __DFCREATURES__ #include "Python.h" +#include "stdio.h" #include "DFTypes.h" #include "modules/Creatures.h" #include "DF_CreatureType.cpp" @@ -155,12 +156,76 @@ static PyObject* DF_CreatureManager_ReadCreatureInBox(DF_CreatureManager* self, Py_RETURN_NONE; } +static PyObject* DF_CreatureManager_GetDwarfRaceIndex(DF_CreatureManager* self, PyObject* args) +{ + if(self->creature_Ptr != NULL) + { + return PyInt_FromLong(self->creature_Ptr->GetDwarfRaceIndex()); + } + + Py_RETURN_NONE; +} + +static PyObject* DF_CreatureManager_GetDwarfCivId(DF_CreatureManager* self, PyObject* args) +{ + if(self->creature_Ptr != NULL) + { + return PyInt_FromLong(self->creature_Ptr->GetDwarfCivId()); + } + + Py_RETURN_NONE; +} + +static PyObject* DF_CreatureManager_WriteLabors(DF_CreatureManager* self, PyObject* args) +{ + int32_t index; + PyObject* laborList; + + + if(self->creature_Ptr != NULL) + { + uint8_t laborArray[NUM_CREATURE_LABORS]; + + if(!PyArg_ParseTuple(args, "iO", &index, &laborList)) + return NULL; + + if(!PyList_Check(laborList)) + { + PyErr_SetString(PyExc_TypeError, "argument 2 must be a list"); + return NULL; + } + + if(PyList_Size(laborList) < NUM_CREATURE_LABORS) + { + char errBuff[50]; + + sprintf(errBuff, "list must contain at least %u entries", NUM_CREATURE_LABORS); + + PyErr_SetString(PyExc_StandardError, errBuff); + return NULL; + } + + for(int i = 0; i < NUM_CREATURE_LABORS; i++) + laborArray[i] = (uint8_t)PyInt_AsLong(PyList_GET_ITEM(laborList, i)); + + if(self->creature_Ptr->WriteLabors(index, laborArray)) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; + } + + Py_RETURN_NONE; +} + static PyMethodDef DF_CreatureManager_methods[] = { {"Start", (PyCFunction)DF_CreatureManager_Start, METH_NOARGS, ""}, {"Finish", (PyCFunction)DF_CreatureManager_Finish, METH_NOARGS, ""}, {"Read_Creature", (PyCFunction)DF_CreatureManager_ReadCreature, METH_VARARGS, ""}, {"Read_Creature_In_Box", (PyCFunction)DF_CreatureManager_ReadCreatureInBox, METH_VARARGS, ""}, + {"Write_Labors", (PyCFunction)DF_CreatureManager_WriteLabors, METH_VARARGS, ""}, + {"Get_Dwarf_Race_Index", (PyCFunction)DF_CreatureManager_GetDwarfRaceIndex, METH_NOARGS, ""}, + {"Get_Dwarf_Civ_id", (PyCFunction)DF_CreatureManager_GetDwarfCivId, METH_NOARGS, ""}, {NULL} // Sentinel }; diff --git a/dfhack/python/DF_GUI.cpp b/dfhack/python/DF_GUI.cpp index 015d115b9..5e9d064de 100644 --- a/dfhack/python/DF_GUI.cpp +++ b/dfhack/python/DF_GUI.cpp @@ -26,6 +26,7 @@ distribution. #define __DFGUI__ #include "Python.h" +#include "DFTypes.h" #include "modules/Gui.h" using namespace DFHack; @@ -163,7 +164,7 @@ static PyTypeObject DF_GUI_type = { PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ - "pydfhack.GUI", /*tp_name*/ + "pydfhack._GUIManager", /*tp_name*/ sizeof(DF_GUI), /*tp_basicsize*/ 0, /*tp_itemsize*/ (destructor)DF_GUI_dealloc, /*tp_dealloc*/ @@ -182,7 +183,7 @@ static PyTypeObject DF_GUI_type = 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ - "pydfhack GUI objects", /* tp_doc */ + "pydfhack GUIManager object", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ diff --git a/dfhack/python/DF_Helpers.cpp b/dfhack/python/DF_Helpers.cpp index 9dce8c737..6c4b580cd 100644 --- a/dfhack/python/DF_Helpers.cpp +++ b/dfhack/python/DF_Helpers.cpp @@ -28,24 +28,86 @@ distribution. #include "Python.h" #include #include +#include + +using namespace std; + #include "DFTypes.h" #include "DF_Imports.cpp" using namespace DFHack; #include "modules/Creatures.h" +#include "modules/Materials.h" #define DICTADD(d, name, item) PyDict_SetItemString(d, name, item); Py_DECREF(item) #define OBJSET(o, name, item) PyObject_SetAttrString(o, name, item); Py_DECREF(item) +static PyObject* BuildTileColor(uint16_t fore, uint16_t back, uint16_t bright) +{ + PyObject *tObj, *args; + + args = Py_BuildValue("iii", fore, back, bright); + + tObj = PyObject_CallObject(TileColor_type, args); + + Py_DECREF(args); + + return tObj; +} + +static PyObject* BuildPosition2D(uint16_t x, uint16_t y) +{ + PyObject *posObj, *args; + + args = Py_BuildValue("ii", x, y); + + posObj = PyObject_CallObject(Position2D_type, args); + + Py_DECREF(args); + + return posObj; +} + +static PyObject* BuildPosition3D(uint16_t x, uint16_t y, uint16_t z) +{ + PyObject *posObj, *args; + + args = Py_BuildValue("iii", x, y, z); + + posObj = PyObject_CallObject(Position3D_type, args); + + Py_DECREF(args); + + return posObj; +} + static PyObject* BuildMatglossPair(DFHack::t_matglossPair& matgloss) { return Py_BuildValue("ii", matgloss.type, matgloss.index); } +static DFHack::t_matglossPair ReverseBuildMatglossPair(PyObject* mObj) +{ + DFHack::t_matglossPair mPair; + + mPair.type = (int16_t)PyInt_AsLong(PyTuple_GetItem(mObj, 0)); + mPair.index = (int32_t)PyInt_AsLong(PyTuple_GetItem(mObj, 1)); + + return mPair; +} + static PyObject* BuildSkill(DFHack::t_skill& skill) { - return Py_BuildValue("III", skill.id, skill.experience, skill.rating); + PyObject *args, *skillObj; + + args = Py_BuildValue("III", skill.id, skill.experience, skill.rating); + + skillObj = PyObject_CallObject(Skill_type, args); + + Py_DECREF(args); + + return skillObj; } static PyObject* BuildSkillList(DFHack::t_skill (&skills)[256], uint8_t numSkills) @@ -65,24 +127,20 @@ static PyObject* BuildJob(DFHack::t_job& job) static PyObject* BuildAttribute(DFHack::t_attrib& at) { - return Py_BuildValue("IIIIIII", at.level, at.field_4, at.field_8, at.field_C, at.leveldiff, at.field_14, at.field_18); + PyObject *args, *attrObj; + + args = Py_BuildValue("IIIIIII", at.level, at.field_4, at.field_8, at.field_C, at.leveldiff, at.field_14, at.field_18); + + attrObj = PyObject_CallObject(Attribute_type, args); + + Py_DECREF(args); + + return attrObj; } static PyObject* BuildItemType(DFHack::t_itemType& item) { - PyObject *id, *name; - - if(item.id[0]) - id = PyString_FromString(item.id); - else - id = PyString_FromString(""); - - if(item.name[0]) - name = PyString_FromString(item.name); - else - name = PyString_FromString(""); - - return Py_BuildValue("OO", id, name); + return Py_BuildValue("ss", item.id, item.name); } static PyObject* BuildLike(DFHack::t_like& like) @@ -97,19 +155,20 @@ static PyObject* BuildLike(DFHack::t_like& like) static PyObject* BuildNote(DFHack::t_note& note) { PyObject* noteObj; - PyObject *args, *name, *position; + PyObject *args, *position; - if(note.name[0]) - name = PyString_FromString(note.name); - else - name = PyString_FromString(""); + args = Py_BuildValue("III", note.x, note.y, note.z); - position = Py_BuildValue("III", note.x, note.y, note.z); + position = PyObject_CallObject(Position3D_type, args); - args = Py_BuildValue("cIIsO", note.symbol, note.foreground, note.background, name, position); + Py_DECREF(args); + + args = Py_BuildValue("cIIsO", note.symbol, note.foreground, note.background, note.name, position); noteObj = PyObject_CallObject(Note_type, args); + Py_DECREF(args); + return noteObj; } @@ -235,33 +294,36 @@ static DFHack::t_name ReverseBuildName(PyObject* nameObj) static PyObject* BuildSettlement(DFHack::t_settlement& settlement) { - PyObject* setDict; - PyObject *local_pos1, *local_pos2; - PyObject* temp; + PyObject* setObj; + PyObject *world_pos, *local_pos, *args; - setDict = PyDict_New(); + args = Py_BuildValue("ii", settlement.world_x, settlement.world_y); - temp = PyInt_FromLong(settlement.origin); - DICTADD(setDict, "origin", temp); + world_pos = PyObject_CallObject(Position2D_type, args); - temp = BuildName(settlement.name); - DICTADD(setDict, "name", temp); + Py_DECREF(args); - temp = Py_BuildValue("ii", settlement.world_x, settlement.world_y); - DICTADD(setDict, "world_pos", temp); + args = Py_BuildValue("iiii", settlement.local_x1, settlement.local_y1, settlement.local_x2, settlement.local_y2); - local_pos1 = Py_BuildValue("ii", settlement.local_x1, settlement.local_y1); - local_pos2 = Py_BuildValue("ii", settlement.local_x2, settlement.local_y2); + local_pos = PyObject_CallObject(Rectangle_type, args); - temp = Py_BuildValue("OO", local_pos1, local_pos2); - DICTADD(setDict, "local_pos", temp); + Py_DECREF(args); - return setDict; + args = Py_BuildValue("iOOO", settlement.origin, BuildName(settlement.name), world_pos, local_pos); + + setObj = PyObject_CallObject(Settlement_type, args); + + Py_DECREF(args); + + return setObj; } static PyObject* BuildSoul(DFHack::t_soul& soul) { - PyObject *soulDict, *skillList, *temp; + PyObject *soulDict, *skillList, *temp, *emptyArgs; + PyObject* soulObj; + + emptyArgs = Py_BuildValue("()"); soulDict = PyDict_New(); @@ -307,7 +369,11 @@ static PyObject* BuildSoul(DFHack::t_soul& soul) temp = BuildAttribute(soul.social_awareness); DICTADD(soulDict, "social_awareness", temp); - return soulDict; + soulObj = PyObject_Call(Soul_type, emptyArgs, soulDict); + + Py_DECREF(emptyArgs); + + return soulObj; } #endif \ No newline at end of file diff --git a/dfhack/python/DF_Imports.cpp b/dfhack/python/DF_Imports.cpp index 15e93d2b3..b163a8822 100644 --- a/dfhack/python/DF_Imports.cpp +++ b/dfhack/python/DF_Imports.cpp @@ -43,10 +43,23 @@ static PyObject* MapBlock40d_type = NULL; static PyObject* Vein_type = NULL; static PyObject* FrozenLiquidVein_type = NULL; static PyObject* SpatterVein_type = NULL; +static PyObject* Position2D_type = NULL; +static PyObject* Position3D_type = NULL; +static PyObject* Rectangle_type = NULL; +static PyObject* Settlement_type = NULL; +static PyObject* Attribute_type = NULL; +static PyObject* Skill_type = NULL; +static PyObject* Soul_type = NULL; +static PyObject* Tree_type = NULL; +static PyObject* CreatureCaste_type = NULL; +static PyObject* Matgloss_type = NULL; +static PyObject* DescriptorColor_type = NULL; +static PyObject* CreatureTypeEx_type = NULL; +static PyObject* TileColor_type = NULL; static void DoImports() { - if(TypesModule == NULL) + if(FlagsModule == NULL) { FlagsModule = PyImport_ImportModule("pydfhackflags"); @@ -56,7 +69,9 @@ static void DoImports() OccupancyFlags_type = PyObject_GetAttrString(FlagsModule, "OccupancyFlags"); ItemFlags_type = PyObject_GetAttrString(FlagsModule, "ItemFlags"); BlockFlags_type = PyObject_GetAttrString(FlagsModule, "BlockFlags"); - + } + if(TypesModule == NULL) + { TypesModule = PyImport_ImportModule("pydftypes"); Note_type = PyObject_GetAttrString(TypesModule, "Note"); @@ -66,6 +81,19 @@ static void DoImports() Vein_type = PyObject_GetAttrString(TypesModule, "Vein"); FrozenLiquidVein_type = PyObject_GetAttrString(TypesModule, "FrozenLiquidVein"); SpatterVein_type = PyObject_GetAttrString(TypesModule, "SpatterVein"); + Position2D_type = PyObject_GetAttrString(TypesModule, "Position2D"); + Position3D_type = PyObject_GetAttrString(TypesModule, "Position3D"); + Rectangle_type = PyObject_GetAttrString(TypesModule, "Rectangle"); + Settlement_type = PyObject_GetAttrString(TypesModule, "Settlement"); + Attribute_type = PyObject_GetAttrString(TypesModule, "Attribute"); + Skill_type = PyObject_GetAttrString(TypesModule, "Skill"); + Soul_type = PyObject_GetAttrString(TypesModule, "Soul"); + Tree_type = PyObject_GetAttrString(TypesModule, "Tree"); + CreatureCaste_type = PyObject_GetAttrString(TypesModule, "CreatureCaste"); + Matgloss_type = PyObject_GetAttrString(TypesModule, "Matgloss"); + DescriptorColor_type = PyObject_GetAttrString(TypesModule, "DescriptorColor"); + CreatureTypeEx_type = PyObject_GetAttrString(TypesModule, "CreatureTypeEx"); + TileColor_type = PyObject_GetAttrString(TypesModule, "TileColor"); } } diff --git a/dfhack/python/DF_Maps.cpp b/dfhack/python/DF_Maps.cpp index 788130444..e7d4297e6 100644 --- a/dfhack/python/DF_Maps.cpp +++ b/dfhack/python/DF_Maps.cpp @@ -31,6 +31,7 @@ distribution. using namespace std; +#include "DFTypes.h" #include "modules/Maps.h" #include "DF_Imports.cpp" #include "DF_Helpers.cpp" @@ -301,10 +302,10 @@ static void ReverseBuildDesignations40d(PyObject* list, DFHack::designations40d& for(int i = 0; i < 16; i++) { - innerList = PyList_GetItem(list, i); + innerList = PyList_GET_ITEM(list, i); for(int j = 0; j < 16; j++) - des[i][j].whole = (uint32_t)PyInt_AsLong(PyList_GET_ITEM(innerList, j)); + des[i][j].whole = (uint32_t)PyInt_AS_LONG(PyList_GET_ITEM(innerList, j)); } } @@ -591,11 +592,11 @@ static PyObject* DF_Map_WriteDesignations(DF_Map* self, PyObject* args) if(!PyArg_ParseTuple(args, "IIIO", &x, &y, &z, &desList)) return NULL; - designations40d des; + DFHack::designations40d writeDes; - ReverseBuildDesignations40d(desList, des); + ReverseBuildDesignations40d(desList, writeDes); - if(self->m_Ptr->WriteDesignations(x, y, z, &des)) + if(self->m_Ptr->WriteDesignations(x, y, z, &writeDes)) Py_RETURN_TRUE; else Py_RETURN_FALSE; @@ -817,7 +818,7 @@ static PyTypeObject DF_Map_type = { PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ - "pydfhack.Map", /*tp_name*/ + "pydfhack._MapManager", /*tp_name*/ sizeof(DF_Map), /*tp_basicsize*/ 0, /*tp_itemsize*/ (destructor)DF_Map_dealloc, /*tp_dealloc*/ @@ -836,7 +837,7 @@ static PyTypeObject DF_Map_type = 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ - "pydfhack Map objects", /* tp_doc */ + "pydfhack MapManager object", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ diff --git a/dfhack/python/DF_Material.cpp b/dfhack/python/DF_Material.cpp index 6cc02cd18..56813c5d9 100644 --- a/dfhack/python/DF_Material.cpp +++ b/dfhack/python/DF_Material.cpp @@ -31,6 +31,8 @@ distribution. using namespace std; #include "modules/Materials.h" +#include "DF_Imports.cpp" +#include "DF_Helpers.cpp" using namespace DFHack; @@ -44,48 +46,16 @@ struct DF_Material static PyObject* BuildMatgloss(t_matgloss& matgloss) { - PyObject* matDict; - PyObject* temp; - - matDict = PyDict_New(); - - if(matgloss.id[0]) - temp = PyString_FromString(matgloss.id); - else - temp = PyString_FromString(""); - - PyDict_SetItemString(matDict, "id", temp); - - Py_DECREF(temp); - - temp = PyInt_FromLong(matgloss.fore); - - PyDict_SetItemString(matDict, "fore", temp); - - Py_DECREF(temp); - - temp = PyInt_FromLong(matgloss.back); + PyObject* matObj; + PyObject* args; - PyDict_SetItemString(matDict, "back", temp); + args = Py_BuildValue("siiis", matgloss.id, matgloss.fore, matgloss.back, matgloss.bright, matgloss.name); - Py_DECREF(temp); + matObj = PyObject_CallObject(Matgloss_type, args); - temp = PyInt_FromLong(matgloss.bright); + Py_DECREF(args); - PyDict_SetItemString(matDict, "bright", temp); - - Py_DECREF(temp); - - if(matgloss.name[0]) - temp = PyString_FromString(matgloss.name); - else - temp = PyString_FromString(""); - - PyDict_SetItemString(matDict, "name", temp); - - Py_DECREF(temp); - - return matDict; + return matObj; } static PyObject* BuildMatglossPlant(t_matglossPlant& matgloss) @@ -145,6 +115,106 @@ static PyObject* BuildMatglossList(std::vector & matVec) return matList; } +static PyObject* BuildDescriptorColor(t_descriptor_color& color) +{ + PyObject* descObj; + PyObject* args; + + args = Py_BuildValue("sfffs", color.id, color.r, color.v, color.b, color.name); + + descObj = PyObject_CallObject(DescriptorColor_type, args); + + Py_DECREF(args); + + return descObj; +} + +static PyObject* BuildDescriptorColorList(std::vector& colors) +{ + PyObject* colorList; + std::vector::iterator colorIter; + + colorList = PyList_New(0); + + for(colorIter = colors.begin(); colorIter != colors.end(); colorIter++) + { + PyObject* color = BuildDescriptorColor(*colorIter); + + PyList_Append(colorList, color); + + Py_DECREF(colorList); + } + + return colorList; +} + +static PyObject* BuildCreatureCaste(t_creaturecaste& caste) +{ + PyObject* casteObj; + PyObject* args; + + args = Py_BuildValue("ssss", caste.rawname, caste.singular, caste.plural, caste.adjective); + + casteObj = PyObject_CallObject(CreatureCaste_type, args); + + Py_DECREF(args); + + return casteObj; +} + +static PyObject* BuildCreatureCasteList(std::vector& castes) +{ + PyObject* casteList; + std::vector::iterator casteIter; + + casteList = PyList_New(0); + + for(casteIter = castes.begin(); casteIter != castes.end(); casteIter++) + { + PyObject* caste = BuildCreatureCaste(*casteIter); + + PyList_Append(casteList, caste); + + Py_DECREF(caste); + } + + return casteList; +} + +static PyObject* BuildCreatureTypeEx(t_creaturetype& creature) +{ + PyObject* cObj; + PyObject* args; + + args = Py_BuildValue("sOiO", creature.rawname, BuildCreatureCasteList(creature.castes), creature.tile_character, \ + BuildTileColor(creature.tilecolor.fore, creature.tilecolor.back, creature.tilecolor.bright)); + + cObj = PyObject_CallObject(CreatureTypeEx_type, args); + + Py_DECREF(args); + + return cObj; +} + +static PyObject* BuildCreatureTypeExList(std::vector& creatures) +{ + PyObject* creatureList; + std::vector::iterator creatureIter; + + creatureList = PyList_New(0); + + for(creatureIter = creatures.begin(); creatureIter != creatures.end(); creatureIter++) + { + PyObject* creature = BuildCreatureTypeEx(*creatureIter); + + PyList_Append(creatureList, creature); + + Py_DECREF(creature); + } + + return creatureList; +} + // API type Allocation, Deallocation, and Initialization static PyObject* DF_Material_new(PyTypeObject* type, PyObject* args, PyObject* kwds) @@ -266,6 +336,36 @@ static PyObject* DF_Material_ReadCreatureTypes(DF_Material* self, PyObject* args Py_RETURN_NONE; } +static PyObject* DF_Material_ReadCreatureTypesEx(DF_Material* self, PyObject* args) +{ + if(self->mat_Ptr != NULL) + { + std::vector creatureVec; + + if(self->mat_Ptr->ReadCreatureTypesEx(creatureVec)) + { + return BuildCreatureTypeExList(creatureVec); + } + } + + Py_RETURN_NONE; +} + +static PyObject* DF_Material_ReadDescriptorColors(DF_Material* self, PyObject* args) +{ + if(self->mat_Ptr != NULL) + { + std::vector colorVec; + + if(self->mat_Ptr->ReadDescriptorColors(colorVec)) + { + return BuildDescriptorColorList(colorVec); + } + } + + Py_RETURN_NONE; +} + static PyMethodDef DF_Material_methods[] = { {"Read_Inorganic_Materials", (PyCFunction)DF_Material_ReadInorganicMaterials, METH_NOARGS, ""}, @@ -273,6 +373,8 @@ static PyMethodDef DF_Material_methods[] = {"Read_Wood_Materials", (PyCFunction)DF_Material_ReadWoodMaterials, METH_NOARGS, ""}, {"Read_Plant_Materials", (PyCFunction)DF_Material_ReadPlantMaterials, METH_NOARGS, ""}, {"Read_Creature_Types", (PyCFunction)DF_Material_ReadCreatureTypes, METH_NOARGS, ""}, + {"Read_Creature_Types_Ex", (PyCFunction)DF_Material_ReadCreatureTypesEx, METH_NOARGS, ""}, + {"Read_Descriptor_Colors", (PyCFunction)DF_Material_ReadDescriptorColors, METH_NOARGS, ""}, {NULL} //Sentinel }; diff --git a/dfhack/python/DF_Translate.cpp b/dfhack/python/DF_Translate.cpp index 274e5ccdd..1ce635f5c 100644 --- a/dfhack/python/DF_Translate.cpp +++ b/dfhack/python/DF_Translate.cpp @@ -31,7 +31,9 @@ distribution. using namespace std; +#include "DFTypes.h" #include "modules/Translation.h" +#include "DF_Helpers.cpp" using namespace DFHack; @@ -237,7 +239,7 @@ static PyTypeObject DF_Translate_type = { PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ - "pydfhack.Translate", /*tp_name*/ + "pydfhack._TranslationManager", /*tp_name*/ sizeof(DF_Translate), /*tp_basicsize*/ 0, /*tp_itemsize*/ (destructor)DF_Translate_dealloc, /*tp_dealloc*/ @@ -256,7 +258,7 @@ static PyTypeObject DF_Translate_type = 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ - "pydfhack Translate objects", /* tp_doc */ + "pydfhack TranslationManager object", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ diff --git a/dfhack/python/DF_Vegetation.cpp b/dfhack/python/DF_Vegetation.cpp index 93ba687dd..f549b55c0 100644 --- a/dfhack/python/DF_Vegetation.cpp +++ b/dfhack/python/DF_Vegetation.cpp @@ -33,24 +33,16 @@ using namespace DFHack; static PyObject* BuildTree(DFHack::t_tree& tree) { - PyObject* t_dict; - PyObject* temp; + PyObject* t_Obj; + PyObject* args; - t_dict = PyDict_New(); + args = Py_BuildValue("iiOi", tree.type, tree.material, BuildPosition3D(tree.x, tree.y, tree.z), tree.address); - temp = PyInt_FromLong(tree.type); - DICTADD(t_dict, "type", temp); + t_Obj = PyObject_CallObject(Tree_type, args); - temp = PyInt_FromLong(tree.material); - DICTADD(t_dict, "material", temp); + Py_DECREF(args); - temp = PyTuple_Pack(3, tree.x, tree.y, tree.z); - DICTADD(t_dict, "position", temp); - - temp = PyInt_FromLong(tree.address); - DICTADD(t_dict, "address", temp); - - return t_dict; + return t_Obj; } struct DF_Vegetation diff --git a/dfhack/python/examples/attachtest.py b/dfhack/python/examples/attachtest.py new file mode 100644 index 000000000..2f04437bc --- /dev/null +++ b/dfhack/python/examples/attachtest.py @@ -0,0 +1,43 @@ +import time +import math +import pydfapi + +df = pydfapi.API("Memory.xml") + +def test_attach(): + if not df.Attach(): + print "Unable to attach!" + return False + elif not df.Detach(): + print "Unable to detach!" + return False + else: + return True + +def suspend_test(): + print "Testing suspend/resume" + + df.Attach() + + t1 = time.time() + + for i in xrange(1000): + df.Suspend() + + if i % 10 == 0: + print "%i%%" % (i / 10,) + + df.Resume() + + t2 = time.time() + + df.Detach() + + print "suspend tests done in %0.9f seconds" % (t2 - t1,) + +if __name__ == "__main__": + if test_attach(): + suspend_test() + + print "Done. Press any key to continue" + raw_input() \ No newline at end of file diff --git a/dfhack/python/examples/miscutils.py b/dfhack/python/examples/miscutils.py new file mode 100644 index 000000000..64ccf9031 --- /dev/null +++ b/dfhack/python/examples/miscutils.py @@ -0,0 +1,36 @@ +_splatter_dict = { 0 : "Rock", + 1 : "Amber", + 2 : "Coral", + 3 : "Green Glass", + 4 : "Clear Glass", + 5 : "Crystal Glass", + 6 : "Ice", + 7 : "Coal", + 8 : "Potash", + 9 : "Ash", + 10 : "Pearlash", + 11 : "Lye", + 12 : "Mud", + 13 : "Vomit", + 14 : "Salt", + 15 : "Filth", + 16 : "Frozen? Filth", + 18 : "Grime", + 0xF2 : "Very Specific Blood (references a named creature)" } + +def get_splatter_type(mat1, mat2, creature_types): + from cStringIO import StringIO + + if mat1 in _splatter_dict: + return _splatter_dict[mat1] + elif mat1 == 0x2A or mat1 == 0x2B: + splatter = StringIO() + + if mat2 != -1: + splatter.write(creature_types[mat2]["id"] + " ") + + splatter.write("Blood") + + return splatter.getvalue() + else: + return "Unknown" diff --git a/dfhack/python/examples/position.py b/dfhack/python/examples/position.py new file mode 100644 index 000000000..82aae5b01 --- /dev/null +++ b/dfhack/python/examples/position.py @@ -0,0 +1,22 @@ +import sys +import pydfapi + +df = pydfapi.API("Memory.xml") + +if not df.Attach(): + print "Unable to attach!" + print "Press any key to continue" + raw_input() + sys.exit(1) + +pos = df.position + +print "view coords: %s" % (pos.view_coords,) +print "cursor coords: %s" % (pos.cursor_coords,) +print "window size: %s" % (pos.window_size,) + +if not df.Detach(): + print "Unable to detach!" + +print "Done. Press any key to continue" +raw_input() diff --git a/dfhack/python/examples/settlementdump.py b/dfhack/python/examples/settlementdump.py new file mode 100644 index 000000000..b30538ac9 --- /dev/null +++ b/dfhack/python/examples/settlementdump.py @@ -0,0 +1,8 @@ +import sys +from cStringIO import StringIO +import pydfapi + +df = pydfapi.API("Memory.xml") + +def print_settlement(settlement, english_words, foreign_words): + s = StringIO() diff --git a/dfhack/python/examples/suspendtest.py b/dfhack/python/examples/suspendtest.py new file mode 100644 index 000000000..65f11bf53 --- /dev/null +++ b/dfhack/python/examples/suspendtest.py @@ -0,0 +1,38 @@ +import pydfapi + +if __name__ == "__main__": + df = pydfapi.API("Memory.xml") + + if not df.Attach(): + print "Unable to attach!" + return False + + print "Attached, DF should be suspended now" + raw_input() + + df.Resume() + + print "Resumed, DF should be running" + raw_input() + + df.Suspend() + + print "Suspended, DF should be suspended now" + raw_input() + + df.Resume() + + print "Resumed, testing ForceResume. Suspend using SysInternals Process Explorer" + raw_input() + + df.Force_Resume() + + print "ForceResumed. DF should be running." + raw_input() + + if not df.Detach(): + print "Can't detach from DF" + return False + + print "Detached, DF should be running again" + raw_input() \ No newline at end of file diff --git a/dfhack/python/examples/treedump.py b/dfhack/python/examples/treedump.py new file mode 100644 index 000000000..7b62dfe91 --- /dev/null +++ b/dfhack/python/examples/treedump.py @@ -0,0 +1,66 @@ +import sys +from cStringIO import StringIO +import pydfapi + +df = pydfapi.API("Memory.xml") + +if not df.Attach(): + print "Unable to attach!\nPress any key to continue" + raw_input() + sys.exit(1) + +pos = df.position +veg = df.vegetation +mat = df.materials + +organics = mat.Read_Organic_Materials() + +x, y, z = pos.cursor_coords + +num_vegs = veg.Start() + +if x == -30000: + print "----==== Trees ====----" + + for i in xrange(num_vegs): + tree = veg.Read(i) + + t_x, t_y, t_z = tree["position"] + + print "%f/%f/%f, %f:%f" % (t_x, t_y, t_z, tree["type"], tree["material"]) +else: + print "----==== Tree at %i/%i/%i" % (x, y, z) + + for i in xrange(num_vegs): + tree = veg.Read(i) + + t_x, t_y, t_z = tree["position"] + t_type = tree["address"] + + if t_x == x and t_y == y and t_z == z: + s = StringIO() + + s.write("%f:%f = " % (tree["type"], tree["material"])) + + if t_type in (1, 3): + s.write("near-water ") + + s.write("%i " % (organics[tree["material"]]["id"]),) + + if t_type in (0, 1): + s.write("tree\n") + elif t_type in (2, 3): + s.write("shrub\n") + + print s.getvalue() + print "Address: 0x%x" % (tree["address"],) + + break + +veg.Finish() + +if not df.Detach(): + print "Unable to detach!" + +print "Done. Press any key to continue" +raw_input() diff --git a/dfhack/python/pydfapi.py b/dfhack/python/pydfapi.py new file mode 100644 index 000000000..76aea332c --- /dev/null +++ b/dfhack/python/pydfapi.py @@ -0,0 +1,21 @@ +from pydfhack import * + +class API(_API): + def __init__(self, *args, **kwds): + _API.__init__(self, args, kwds) + + self._map_mgr_type = Map + self._vegetation_mgr_type = Vegetation + self._gui_mgr_type = GUI + +class Map(_MapManager): + def __init__(self, *args, **kwds): + _MapManager.__init__(self, args, kwds) + +class Vegetation(_VegetationManager): + def __init__(self, *args, **kwds): + _VegetationManager.__init__(self, args, kwds) + +class GUI(_GUIManager): + def __init__(self, *args, **kwds): + _GUIManager.__init__(self, args, kwds) \ No newline at end of file diff --git a/dfhack/python/pydfhack.cpp b/dfhack/python/pydfhack.cpp index 323c2ad70..b01adad1c 100644 --- a/dfhack/python/pydfhack.cpp +++ b/dfhack/python/pydfhack.cpp @@ -117,18 +117,18 @@ PyMODINIT_FUNC initpydfhack(void) Py_INCREF(&DF_Map_type); Py_INCREF(&DF_GUI_type); - PyModule_AddObject(module, "API", (PyObject*)&DF_API_type); - PyModule_AddObject(module, "MemInfo", (PyObject*)&DF_MemInfo_type); - PyModule_AddObject(module, "Position", (PyObject*)&DF_Position_type); - PyModule_AddObject(module, "Materials", (PyObject*)&DF_Material_type); - PyModule_AddObject(module, "Creature_Base", (PyObject*)&DF_Creature_Base_type); - PyModule_AddObject(module, "CreatureManager", (PyObject*)&DF_CreatureManager_type); - PyModule_AddObject(module, "Translate", (PyObject*)&DF_Translate_type); - PyModule_AddObject(module, "Vegetation", (PyObject*)&DF_Vegetation_type); - PyModule_AddObject(module, "Building", (PyObject*)&DF_Building_type); - PyModule_AddObject(module, "ConstructionManager", (PyObject*)&DF_Construction_type); - PyModule_AddObject(module, "Map", (PyObject*)&DF_Map_type); - PyModule_AddObject(module, "GUI", (PyObject*)&DF_GUI_type); + PyModule_AddObject(module, "_API", (PyObject*)&DF_API_type); + PyModule_AddObject(module, "_MemInfo", (PyObject*)&DF_MemInfo_type); + PyModule_AddObject(module, "_PositionManager", (PyObject*)&DF_Position_type); + PyModule_AddObject(module, "_MaterialsManager", (PyObject*)&DF_Material_type); + PyModule_AddObject(module, "_Creature_Base", (PyObject*)&DF_Creature_Base_type); + PyModule_AddObject(module, "_CreatureManager", (PyObject*)&DF_CreatureManager_type); + PyModule_AddObject(module, "_TranslationManager", (PyObject*)&DF_Translate_type); + PyModule_AddObject(module, "_VegetationManager", (PyObject*)&DF_Vegetation_type); + PyModule_AddObject(module, "_BuildingManager", (PyObject*)&DF_Building_type); + PyModule_AddObject(module, "_ConstructionManager", (PyObject*)&DF_Construction_type); + PyModule_AddObject(module, "_MapManager", (PyObject*)&DF_Map_type); + PyModule_AddObject(module, "_GUIManager", (PyObject*)&DF_GUI_type); DoImports(); diff --git a/dfhack/python/pydfhackflags.py b/dfhack/python/pydfhackflags.py index ee0399d1c..f8c15bef7 100644 --- a/dfhack/python/pydfhackflags.py +++ b/dfhack/python/pydfhackflags.py @@ -18,8 +18,8 @@ class DesignationStruct(Structure): ("traffic", c_uint, 2), ("flow_forbid", c_uint, 1), ("liquid_static", c_uint, 1), - ("moss", c_uint, 1), - ("feature_present", c_uint, 1), + ("feature_local", c_uint, 1), + ("feature_global", c_uint, 1), ("liquid_character", c_uint, 2)] class DesignationFlags(Union): @@ -28,6 +28,9 @@ class DesignationFlags(Union): def __init__(self, initial = 0): self.whole = initial + + def __int__(self): + return self.whole class OccupancyStruct(Structure): _fields_ = [("building", c_uint, 3), @@ -42,6 +45,9 @@ class OccupancyFlags(Union): def __init__(self, initial = 0): self.whole = initial + + def __int__(self): + return self.whole class CreatureStruct1(Structure): _fields_ = [("move_state", c_uint, 1), @@ -83,6 +89,9 @@ class CreatureFlags1(Union): def __init__(self, initial = 0): self.whole = initial + + def __int__(self): + return self.whole class CreatureStruct2(Structure): _fields_ = [("swimming", c_uint, 1), @@ -124,6 +133,9 @@ class CreatureFlags2(Union): def __init__(self, initial = 0): self.whole = initial + + def __int__(self): + return self.whole class ItemStruct(Structure): _fields_ = [("on_ground", c_uint, 1), @@ -165,6 +177,9 @@ class ItemFlags(Union): def __init__(self, initial = 0): self.whole = initial + + def __int__(self): + return self.whole dig_types = { "no" : 0, "default" : 1, @@ -193,3 +208,6 @@ class BlockFlags(Union): def __init__(self, inital = 0): self.whole = initial + + def __int__(self): + return self.whole diff --git a/dfhack/python/pydftypes.py b/dfhack/python/pydftypes.py index 4e77a2b1b..5ff79d7ea 100644 --- a/dfhack/python/pydftypes.py +++ b/dfhack/python/pydftypes.py @@ -1,16 +1,31 @@ from collections import namedtuple +Position2D = namedtuple("Position2D", "x, y") +Position3D = namedtuple("Position3D", "x, y, z") +Rectangle = namedtuple("Rectangle", "x1, y1, x2, y2") Note = namedtuple("Note", "symbol, foreground, background, name, position") Construction = namedtuple("Construction", "position, form, unk_8, mat_type, mat_idx, unk3, unk4, unk5, unk6, origin") Vein = namedtuple("Vein", "vtable, type, flags, address, assignment") FrozenLiquidVein = namedtuple("FrozenLiquidVein", "vtable, address, tiles") SpatterVein = namedtuple("SpatterVein", "vtable, address, mat1, unk1, mat2, mat3, intensity") +Settlement = namedtuple("Settlement", "origin, name, world_pos, local_pos") +Attribute = namedtuple("Attribute", "level, field_4, field_8, field_C, leveldiff, field_14, field_18"); +Skill = namedtuple("Skill", "id, experience, rating") +Tree = namedtuple("Tree", "type, material, position, address") +CreatureCaste = namedtuple("CreatureCaste", "rawname, singular, plural, adjective") +Matgloss = namedtuple("Matgloss", "id, fore, back, bright, name") +DescriptorColor = namedtuple("DescriptorColor", "id, r, v, b, name") +CreatureTypeEx = namedtuple("CreatureTypeEx", "rawname, castes, tile_character, tilecolor") +TileColor = namedtuple("TileColor", "fore, back, bright") class Name(object): __slots__ = ["first_name", "nickname", "language", "has_name", "words", "parts_of_speech"] class Soul(object): - pass + def __init__(self, *args, **kwds): + if kwds: + for k, v in kwds.iteritems(): + self.__dict__[k] = v class MapBlock40d(object): pass \ No newline at end of file diff --git a/dfhack/python/setup.py b/dfhack/python/setup.py index f42072986..a115d1003 100644 --- a/dfhack/python/setup.py +++ b/dfhack/python/setup.py @@ -2,9 +2,10 @@ from distutils.core import setup, Extension e = Extension("pydfhack", - sources=["DF_MemInfo.cpp", "DF_API.cpp", "pydfhack.cpp"], + sources=["DF_API.cpp", "DF_Buildings.cpp", "DF_Constructions.cpp", "DF_CreatureManager.cpp", "DF_GUI.cpp", "DF_Maps.cpp", "DF_Material.cpp", "DF_Position.cpp", "DF_Translate.cpp", "DF_Vegetation.cpp", "pydfhack.cpp"], include_dirs=["..\\", "..\\include", "..\\depends\\md5", "..\\depends\\tinyxml"], library_dirs=["..\\..\\output"], + #extra_compile_args=["-w"], libraries=["libdfhack"], export_symbols=["initpydfhack", "ReadRaw", "WriteRaw"]) diff --git a/dfhack/shm/mod-maps.h b/dfhack/shm/mod-maps.h index 832c4e8c8..de3a9812f 100644 --- a/dfhack/shm/mod-maps.h +++ b/dfhack/shm/mod-maps.h @@ -42,6 +42,9 @@ typedef struct uint32_t x_count_offset;// = d->offset_descriptor->getAddress ("x_count"); uint32_t y_count_offset;// = d->offset_descriptor->getAddress ("y_count"); uint32_t z_count_offset;// = d->offset_descriptor->getAddress ("z_count"); + /* + Block + */ uint32_t tile_type_offset;// = d->offset_descriptor->getOffset ("type"); uint32_t designation_offset;// = d->offset_descriptor->getOffset ("designation"); uint32_t occupancy_offset;// = d->offset_descriptor->getOffset ("occupancy"); @@ -49,23 +52,27 @@ typedef struct uint32_t veinvector;// = d->offset_descriptor->getOffset ("v_vein"); uint32_t temperature1_offset; uint32_t temperature2_offset; + uint32_t global_feature_offset; + uint32_t local_feature_offset; + uint32_t vein_mineral_vptr; uint32_t vein_ice_vptr; uint32_t vein_spatter_vptr; /* GEOLOGY + */ uint32_t region_x_offset;// = minfo->getAddress ("region_x"); uint32_t region_y_offset;// = minfo->getAddress ("region_y"); uint32_t region_z_offset;// = minfo->getAddress ("region_z"); - uint32_t world_offset;// = minfo->getAddress ("world"); - uint32_t world_regions_offset;// = minfo->getOffset ("w_regions_arr"); + + uint32_t world_regions;// mem->getAddress ("ptr2_region_array"); uint32_t region_size;// = minfo->getHexValue ("region_size"); uint32_t region_geo_index_offset;// = minfo->getOffset ("region_geo_index_off"); - uint32_t world_geoblocks_offset;// = minfo->getOffset ("w_geoblocks"); + uint32_t world_geoblocks_vector;// = minfo->getOffset ("geoblock_vector"); uint32_t world_size_x;// = minfo->getOffset ("world_size_x"); uint32_t world_size_y;// = minfo->getOffset ("world_size_y"); uint32_t geolayer_geoblock_offset;// = minfo->getOffset ("geolayer_geoblock_offset"); - */ + uint32_t type_inside_geolayer;// = mem->getOffset ("type_inside_geolayer"); } maps_offsets; typedef struct diff --git a/examples/veinlook.cpp b/examples/veinlook.cpp index 5c084e211..7dfd992dd 100644 --- a/examples/veinlook.cpp +++ b/examples/veinlook.cpp @@ -281,6 +281,7 @@ void hexdump (DFHack::API& DF, uint32_t address, uint32_t length, int filenum) // blockaddr = address of the block // blockX, blockY = local map X and Y coords in 16x16 of the block // printX, printX = where to print stuff on the screen +/* void do_features(Process* p, uint32_t blockaddr, uint32_t blockX, uint32_t blockY, int printX, int printY, vector &stonetypes) { memory_info* mem = p->getDescriptor(); @@ -337,19 +338,11 @@ void do_features(Process* p, uint32_t blockaddr, uint32_t blockX, uint32_t block gotoxy(printX,printY+6); cprintf("local feature vector: 0x%x\n", feat_vector); DfVector p_features(p, feat_vector); - /* - for(int k = 0 ; k < p_features.size();k++) - { - printf("feature %d addr: 0x%x\n", k, p_features[k]); - string name = p->readClassName(p->readDWord( p_features[k] )); - cout << name << endl; - } - */ - gotoxy(printX,printY+7); + gotoxy(printX,printY + 7); cprintf("feature %d addr: 0x%x\n", idx, p_features[idx]); if(idx >= p_features.size()) { - gotoxy(printX,printY+8); + gotoxy(printX,printY + 8); cprintf("ERROR, out of vector bounds."); } else @@ -418,8 +411,91 @@ void do_features(Process* p, uint32_t blockaddr, uint32_t blockX, uint32_t block } } } - - +*/ +void do_features(API& DF, mapblock40d * block, uint32_t blockX, uint32_t blockY, int printX, int printY, vector &stonetypes) +{ + Maps * Maps = DF.getMaps(); + Process * p = DF.getProcess(); + if(!Maps) + return; + vector global_features; + std::map > local_features; + if(!Maps->ReadGlobalFeatures(global_features)) + return; + if(!Maps->ReadLocalFeatures(local_features)) + return; + + planecoord pc; + pc.dim.x = blockX; + pc.dim.y = blockY; + int16_t idx =block->global_feature; + if(idx != -1) + { + t_feature &ftr =global_features[idx]; + gotoxy(printX,printY); + cprintf( "global feature present: %d @ 0x%x\n", idx, ftr.origin); + if(ftr.discovered ) + { + gotoxy(printX,printY+1); + cprintf("You've discovered it already!"); + } + if(ftr.type == feature_Underworld) + { + char * matname = "unknown"; + // is stone? + if(ftr.main_material == 0) + { + matname = stonetypes[ftr.sub_material].id; + } + gotoxy(printX,printY+2); + cprintf("Underworld, material %d/%d : %s", ftr.main_material, ftr.sub_material, matname); + } + else + { + gotoxy(printX,printY+2); + string name = p->readClassName(p->readDWord( ftr.origin )); + cprintf("%s", name.c_str()); + } + } + idx =block->local_feature; + if(idx != -1) + { + vector &ftrv = local_features[pc]; + if(idx < ftrv.size()) + { + t_feature & ftr = *ftrv[idx]; + gotoxy(printX,printY + 4); + cprintf( "local feature present: %d @ 0x%x\n", idx, ftr.origin); + if(ftr.discovered ) + { + gotoxy(printX,printY+ 5); + cprintf("You've discovered it already!"); + } + if(ftr.type == feature_Adamantine_Tube) + { + char * matname = "unknown"; + // is stone? + if(ftr.main_material == 0) + { + matname = stonetypes[ftr.sub_material].id; + } + gotoxy(printX,printY+6); + cprintf("Underworld, material %d/%d : %s", ftr.main_material, ftr.sub_material, matname); + } + else + { + gotoxy(printX,printY+6); + string name = p->readClassName(p->readDWord( ftr.origin )); + cprintf("%s", name.c_str()); + } + } + else + { + gotoxy(printX,printY + 4); + cprintf( "local feature vector overflow: %d", idx); + } + } +} main(int argc, char *argv[]) { @@ -677,7 +753,7 @@ main(int argc, char *argv[]) // extra processing of the block in the middle if(i == 0 && j == 0) { - do_features(p, Block->origin, cursorX, cursorY, 50,10, stonetypes); + do_features(DF, Block, cursorX, cursorY, 50,10, stonetypes); // read veins Maps->ReadVeins(cursorX+i,cursorY+j,cursorZ,&veinVector,&IceVeinVector,&splatter); diff --git a/tools/prospector.cpp b/tools/prospector.cpp index b64790793..73ac9bcd2 100644 --- a/tools/prospector.cpp +++ b/tools/prospector.cpp @@ -49,12 +49,18 @@ int main (int argc, const char* argv[]) showhidden = true; #endif uint32_t x_max,y_max,z_max; + /* DFHack::tiletypes40d tiletypes; DFHack::designations40d designations; DFHack::biome_indices40d regionoffsets; + */ + DFHack::mapblock40d Block; map materials; materials.clear(); vector stonetypes; + vector global_features; + std::map > local_features; + vector< vector > layerassign; DFHack::API DF("Memory.xml"); @@ -86,6 +92,23 @@ int main (int argc, const char* argv[]) } Maps->getSize(x_max,y_max,z_max); + if(!Maps->ReadGlobalFeatures(global_features)) + { + cerr << "Can't get global features." << endl; + #ifndef LINUX_BUILD + cin.ignore(); + #endif + return 1; + } + + if(!Maps->ReadLocalFeatures(local_features)) + { + cerr << "Can't get local features." << endl; + #ifndef LINUX_BUILD + cin.ignore(); + #endif + return 1; + } // get stone matgloss mapping if(!Mats->ReadInorganicMaterials(stonetypes)) { @@ -122,8 +145,9 @@ int main (int argc, const char* argv[]) continue; // read data - Maps->ReadTileTypes(x,y,z, &tiletypes); - Maps->ReadDesignations(x,y,z, &designations); + Maps->ReadBlock40d(x,y,z, &Block); + //Maps->ReadTileTypes(x,y,z, &tiletypes); + //Maps->ReadDesignations(x,y,z, &designations); memset(tempvein, -1, sizeof(tempvein)); veins.clear(); @@ -131,24 +155,24 @@ int main (int argc, const char* argv[]) if(showbaselayers) { - Maps->ReadRegionOffsets(x,y,z, ®ionoffsets); + //Maps->ReadRegionOffsets(x,y,z, ®ionoffsets); // get the layer materials for(uint32_t xx = 0;xx<16;xx++) { for (uint32_t yy = 0; yy< 16;yy++) { - uint8_t test = designations[xx][yy].bits.biome; + uint8_t test = Block.designation[xx][yy].bits.biome; if(test > maximum_regionoffset) maximum_regionoffset = test; - if( test >= sizeof(regionoffsets)) + if( test >= sizeof(Block.biome_indices)) { num_overflows++; continue; } tempvein[xx][yy] = layerassign - [regionoffsets[test]] - [designations[xx][yy].bits.geolayer_index]; + [Block.biome_indices[test]] + [Block.designation[xx][yy].bits.geolayer_index]; } } } @@ -172,6 +196,56 @@ int main (int argc, const char* argv[]) } } } + + // global feature overrides + int16_t idx = Block.global_feature; + if( idx != -1 && uint16_t(idx) < global_features.size() && global_features[idx].type == DFHack::feature_Underworld) + { + for(uint32_t xi = 0 ; xi< 16 ; xi++) for(uint32_t yi = 0 ; yi< 16 ; yi++) + { + if(Block.designation[xi][yi].bits.feature_global) + { + if(global_features[idx].main_material == 0) // stone + { + tempvein[xi][yi] = global_features[idx].sub_material; + } + else + { + tempvein[xi][yi] = -1; + } + } + } + } + + idx = Block.local_feature; + if( idx != -1 ) + { + DFHack::planecoord pc; + pc.dim.x = x; + pc.dim.y = y; + std::map >::iterator it; + it = local_features.find(pc); + if(it != local_features.end()) + { + std::vector& vectr = (*it).second; + if(uint16_t(idx) < vectr.size() && vectr[idx]->type == DFHack::feature_Adamantine_Tube) + for(uint32_t xi = 0 ; xi< 16 ; xi++) for(uint32_t yi = 0 ; yi< 16 ; yi++) + { + if(Block.designation[xi][yi].bits.feature_local && DFHack::isWallTerrain(Block.tiletypes[xi][yi])) + { + if(vectr[idx]->main_material == 0) // stone + { + tempvein[xi][yi] = vectr[idx]->sub_material; + } + else + { + tempvein[xi][yi] = -1; + } + } + } + } + } + // count the material types for(uint32_t xi = 0 ; xi< 16 ; xi++) { @@ -179,7 +253,7 @@ int main (int argc, const char* argv[]) { // hidden tiles are ignored unless '-a' is provided on the command line // non-wall tiles are ignored - if( (designations[xi][yi].bits.hidden && !showhidden) || !DFHack::isWallTerrain(tiletypes[xi][yi])) + if( (Block.designation[xi][yi].bits.hidden && !showhidden) || !DFHack::isWallTerrain(Block.tiletypes[xi][yi])) continue; if(tempvein[xi][yi] < 0) continue; @@ -199,7 +273,7 @@ int main (int argc, const char* argv[]) } // print report cout << "Maximal regionoffset seen: " << maximum_regionoffset << "."; - if(maximum_regionoffset >= sizeof(regionoffsets) ) + if(maximum_regionoffset >= sizeof(Block.biome_indices) ) { cout << " This is above the regionoffsets array size!" << endl; cout << "Number of overflows: " << num_overflows; @@ -209,7 +283,14 @@ int main (int argc, const char* argv[]) map::iterator p; for(p = materials.begin(); p != materials.end(); p++) { - cout << stonetypes[p->first].id << " : " << p->second << endl; + if(p->first == -1) + { + cout << "Non-stone" << " : " << p->second << endl; + } + else + { + cout << stonetypes[p->first].id << " : " << p->second << endl; + } } DF.Detach(); #ifndef LINUX_BUILD