diff --git a/dfhack/python/c api/dfhack_api_ctypes.py b/dfhack/python/c api/dfhack_api_ctypes.py new file mode 100644 index 000000000..e3781b90a --- /dev/null +++ b/dfhack/python/c api/dfhack_api_ctypes.py @@ -0,0 +1,273 @@ +from ctypes import * +from pydftypes import * + +int_ptr = POINTER(c_int) +uint_ptr = POINTER(c_uint) + +libdfhack = cdll.libdfhack +libdfhack.API_Alloc.restype = c_void_p +libdfhack.API_Free.argtypes = [ c_void_p ] + +libdfhack.API_getMemoryInfo.restype = c_void_p +libdfhack.API_getProcess.restype = c_void_p +libdfhack.API_getWindow.restype = c_void_p + +libdfhack.API_getCreatures.restype = c_void_p +libdfhack.API_getMaps.restype = c_void_p +libdfhack.API_getGui.restype = c_void_p +libdfhack.API_getPosition.restype = c_void_p +libdfhack.API_getMaterials.restype = c_void_p +libdfhack.API_getTranslation.restype = c_void_p +libdfhack.API_getVegetation.restype = c_void_p +libdfhack.API_getBuildings.restype = c_void_p +libdfhack.API_getConstructions.restype = c_void_p + +class API(object): + def __init__(self, memory_path): + self._api_ptr = libdfhack.API_Alloc(create_string_buffer(memory_path)) + + self._pos_obj = None + self._mat_obj = None + + def __del__(self): + libdfhack.API_Free(self._api_ptr) + + def attach(self): + return libdfhack.API_Attach(self._api_ptr) > 0 + + def detach(self): + return libdfhack.API_Detach(self._api_ptr) > 0 + + def suspend(self): + return libdfhack.API_Suspend(self._api_ptr) > 0 + + def resume(self): + return libdfhack.API_Resume(self._api_ptr) > 0 + + def force_resume(self): + return libdfhack.API_ForceResume(self._api_ptr) > 0 + + def async_suspend(self): + return libdfhack.API_AsyncSuspend(self._api_ptr) > 0 + + @property + def is_attached(self): + return libdfhack.API_isAttached(self._api_ptr) > 0 + + @property + def is_suspended(self): + return libdfhack.API_isSuspended(self._api_ptr) > 0 + + @property + def position(self): + if self._pos_obj is None: + ptr = libdfhack.API_getPosition(self._api_ptr) + + if ptr is not None: + return Position(ptr) + else: + return None + else: + return self._pos_obj + + @property + def materials(self): + if self._mat_obj is None: + ptr = libdfhack.API_getMaterials(self._api_ptr) + + if ptr is not None: + return Materials(ptr) + else: + return None + else: + return self._mat_obj + +class Position(object): + def __init__(self, ptr): + self._pos_ptr = ptr + + self._vx, self._vy, self._vz = c_int(), c_int(), c_int() + self._cx, self._cy, self._cz = c_int(), c_int(), c_int() + self._ww, self._wh = c_int(), c_int() + + def get_view_coords(self): + if libdfhack.Position_getViewCoords(self._pos_ptr, byref(self._vx), byref(self._vy), byref(self._vz)) > 0: + return (self._vx.value, self._vy.value, self._vz.value) + else: + return (-1, -1, -1) + + def set_view_coords(self, v_coords): + self._vx.value, self._vy.value, self._vz.value = v_coords + + libdfhack.Position_setViewCoords(self._pos_ptr, self._vx, self._vy, self._vz) + + view_coords = property(get_view_coords, set_view_coords) + + def get_cursor_coords(self): + if libdfhack.Position_getCursorCoords(self._pos_ptr, byref(self._cx), byref(self._cy), byref(self._cz)) > 0: + return (self._cx.value, self._cy.value, self._cz.value) + else: + return (-1, -1, -1) + + def set_cursor_coords(self, c_coords): + self._cx.value, self._cy.value, self_cz.value = c_coords + + libdfhack.Position_setCursorCoords(self._pos_ptr, self._cx, self._cy, self._cz) + + cursor_coords = property(get_cursor_coords, set_cursor_coords) + + @property + def window_size(self): + if libdfhack.Position_getWindowSize(self._pos_ptr, byref(self._ww), byref(self._wh)) > 0: + return (self._ww.value, self._wh.value) + else: + return (-1, -1) + +libdfhack.Gui_ReadViewScreen.argtypes = [ c_void_p, c_void_p ] + +class Gui(object): + def __init__(self, ptr): + self._gui_ptr = ptr + + def start(self): + return libdfhack.Gui_Start(self._gui_ptr) + + def finish(self): + return libdfhack.Gui_Finish(self._gui_ptr) + + def read_pause_state(self): + return libdfhack.Gui_ReadPauseState(self._pos_ptr) > 0 + + def read_view_screen(self): + s = ViewScreen() + + if libdfhack.Gui_ReadViewScreen(self._gui_ptr, byref(s)) > 0: + return s + else: + return None + +arr_create_func = CFUNCTYPE(c_void_p, c_int) + +get_arg_types = [ c_void_p, arr_create_func ] + +libdfhack.Materials_getInorganic.argtypes = get_arg_types +libdfhack.Materials_getOrganic.argtypes = get_arg_types +libdfhack.Materials_getTree.argtypes = get_arg_types +libdfhack.Materials_getPlant.argtypes = get_arg_types +libdfhack.Materials_getRace.argtypes = get_arg_types +libdfhack.Materials_getRaceEx.argtypes = get_arg_types +libdfhack.Materials_getColor.argtypes = get_arg_types +libdfhack.Materials_getOther.argtypes = get_arg_types + +class Materials(object): + def __init__(self, ptr): + self._mat_ptr = ptr + + self.inorganic = None + self.organic = None + self.tree = None + self.plant = None + self.race = None + self.race_ex = None + self.color = None + self.other = None + + def read_inorganic(self): + return libdfhack.Materials_ReadInorganicMaterials(self._mat_ptr) + + def read_organic(self): + return libdfhack.Materials_ReadOrganicMaterials(self._mat_ptr) + + def read_wood(self): + return libdfhack.Materials_ReadWoodMaterials(self._mat_ptr) + + def read_plant(self): + return libdfhack.Materials_ReadPlantMaterials(self._mat_ptr) + + def read_creature_types(self): + return libdfhack.Materials_ReadCreatureTypes(self._mat_ptr) + + def read_creature_types_ex(self): + return libdfhack.Materials_ReadCreatureTypesEx(self._mat_ptr) + + def read_descriptor_colors(self): + return libdfhack.Materials_ReadDescriptorColors(self._mat_ptr) + + def read_others(self): + return libdfhack.Materials_ReadOthers(self._mat_ptr) + + def read_all(self): + libdfhack.Materials_ReadAllMaterials(self._mat_ptr) + + def get_description(self, material): + return libdfhack.Materials_getDescription(self._mat_ptr, byref(material)) + + def _allocate_matgloss_array(self, count): + arr_type = Matgloss * count + + arr = arr_type() + + ptr = c_void_p() + ptr = addressof(arr) + + return (arr, ptr) + + def update_inorganic_cache(self): + def update_callback(count): + allocated = self._allocate_matgloss_array(count) + + self.inorganic = allocated[0] + + return allocated[1] + + callback = arr_create_func(update_callback) + + return libdfhack.Materials_getInorganic(self._mat_ptr, callback) + + def update_organic_cache(self): + def update_callback(count): + allocated = self._allocate_matgloss_array(count) + + self.organic = allocated[0] + + return allocated[1] + + callback = arr_create_func(update_callback) + + return libdfhack.Materials_getOrganic(self._mat_ptr, callback) + + def update_tree_cache(self): + def update_callback(count): + allocated = self._allocate_matgloss_array(count) + + self.tree = allocated[0] + + return allocated[1] + + callback = arr_create_func(update_callback) + + return libdfhack.Materials_getTree(self._mat_ptr, callback) + + def update_plant_cache(self): + def update_callback(count): + allocated = self._allocate_matgloss_array(count) + + self.plant = allocated[0] + + return allocated[1] + + callback = arr_create_func(update_callback) + + return libdfhack.Materials_getPlant(self._mat_ptr, callback) + + def update_race_cache(self): + def update_callback(count): + allocated = self._allocate_matgloss_array(count) + + self.race = allocated[0] + + return allocated[1] + + callback = arr_create_func(update_callback) + + return libdfhack.Materials_getRace(self._mat_ptr, callback) diff --git a/dfhack/python/c api/enum.py b/dfhack/python/c api/enum.py new file mode 100644 index 000000000..f9124fe2a --- /dev/null +++ b/dfhack/python/c api/enum.py @@ -0,0 +1,97 @@ +#found this in the cookbook: http://code.activestate.com/recipes/576415/ + +from ctypes import c_uint + +class C_EnumerationType(type(c_uint)): + def __new__(metacls, name, bases, dictionary): + if not "_members_" in dictionary: + _members_ = {} + + for key, value in dictionary.iteritems(): + if not key.startswith("_"): + _members_[key] = value + + dictionary["_members_"] = _members_ + + cls = type(c_uint).__new__(metacls, name, bases, dictionary) + + for key, value in cls._members_.iteritems(): + globals()[key] = value + + return cls + + def __contains__(self, value): + return value in self._members_.values() + + def __repr__(self): + return "" % self.__name__ + +class C_Enumeration(c_uint): + __metaclass__ = C_EnumerationType + _members_ = {} + + def __init__(self, value): + for key, value in self._members_.iteritems(): + if v == value: + self.name = key + break + else: + raise ValueError("No enumeration member with value %r" % value) + + c_uint.__init__(self, value) + + def __repr__(self): + return "" % (self.name, self.value, self.__class__) + + @classmethod + def from_param(cls, param): + if isinstance(param, C_Enumeration): + if param.__class__ != cls: + raise ValueError("Cannot mix enumeration members") + else: + return param + else: + return cls(param) + +FeatureType = C_EnumerationType("FeatureType", + (c_uint,), + {"Other" : 0, + "Adamantine_Tube" : 1, + "Underworld" : 2, + "Hell_Temple" : 3}) + +BiomeOffset = C_EnumerationType("BiomeOffset", + (c_uint,), + {"NorthWest" : 0, + "North" : 1, + "NorthEast" : 2, + "West" : 3, + "Here" : 4, + "East" : 5, + "SouthWest" : 6, + "South" : 7, + "SouthEast" : 8, + "BiomeCount" : 9}) + +TrafficType = C_EnumerationType("TrafficType", + (c_uint,), + {"Normal" : 0, + "Low" : 1, + "High" : 2, + "Restricted" : 3}) + +DesignationType = C_EnumerationType("DesignationType", + (c_uint,), + {"No" : 0, + "Default" : 1, + "UD_Stair" : 2, + "Channel" : 3, + "Ramp" : 4, + "D_Stair" : 5, + "U_Stair" : 6, + "Whatever" : 7}) + +LiquidType = C_EnumerationType("LiquidType", + (c_uint,), + {"Water" : 0, + "Magma" : 1}) diff --git a/dfhack/python/c api/pydfhackflags.py b/dfhack/python/c api/pydfhackflags.py new file mode 100644 index 000000000..645bba659 --- /dev/null +++ b/dfhack/python/c api/pydfhackflags.py @@ -0,0 +1,200 @@ +# -*- coding: utf-8 -*- +from ctypes import Structure, Union, c_uint +from enum import * + +class DesignationStruct(Structure): + _fields_ = [("flow_size", c_uint, 3), + ("pile", c_uint, 1), + ("dig", DesignationType, 3), + ("smooth", c_uint, 2), + ("hidden", c_uint, 1), + ("geolayer_index", c_uint, 4), + ("light", c_uint, 1), + ("subterranean", c_uint, 1), + ("skyview", c_uint, 1), + ("biome", c_uint, 4), + ("liquid_type", c_uint, 1), + ("water_table", c_uint, 1), + ("rained", c_uint, 1), + ("traffic", c_uint, 2), + ("flow_forbid", c_uint, 1), + ("liquid_static", c_uint, 1), + ("feature_local", c_uint, 1), + ("feature_global", c_uint, 1), + ("liquid_character", c_uint, 2)] + +class DesignationFlags(Union): + _fields_ = [("whole", c_uint, 32), + ("bits", DesignationStruct)] + + def __init__(self, initial = 0): + self.whole = initial + + def __int__(self): + return self.whole + +class OccupancyStruct(Structure): + _fields_ = [("building", c_uint, 3), + ("unit", c_uint, 1), + ("unit_grounded", c_uint, 1), + ("item", c_uint, 1), + ("splatter", c_uint, 26)] + +class OccupancyFlags(Union): + _fields_ = [("whole", c_uint, 32), + ("bits", OccupancyStruct)] + + def __init__(self, initial = 0): + self.whole = initial + + def __int__(self): + return self.whole + +class CreatureStruct1(Structure): + _fields_ = [("move_state", c_uint, 1), + ("dead", c_uint, 1), + ("has_mood", c_uint, 1), + ("had_mood", c_uint, 1), + ("marauder", c_uint, 1), + ("drowning", c_uint, 1), + ("merchant", c_uint, 1), + ("forest", c_uint, 1), + ("left", c_uint, 1), + ("rider", c_uint, 1), + ("incoming", c_uint, 1), + ("diplomat", c_uint, 1), + ("zombie", c_uint, 1), + ("skeleton", c_uint, 1), + ("can_swap", c_uint, 1), + ("on_ground", c_uint, 1), + ("projectile", c_uint, 1), + ("active_invader", c_uint, 1), + ("hidden_in_ambush", c_uint, 1), + ("invader_origin", c_uint, 1), + ("coward", c_uint, 1), + ("hidden_ambusher", c_uint, 1), + ("invades", c_uint, 1), + ("check_flows", c_uint, 1), + ("ridden", c_uint, 1), + ("caged", c_uint, 1), + ("tame", c_uint, 1), + ("chained", c_uint, 1), + ("royal_guard", c_uint, 1), + ("fortress_guard", c_uint, 1), + ("suppress_wield", c_uint, 1), + ("important_historical_figure", c_uint, 1)] + +class CreatureFlags1(Union): + _fields_ = [("whole", c_uint, 32), + ("bits", CreatureStruct1)] + + def __init__(self, initial = 0): + self.whole = initial + + def __int__(self): + return self.whole + +class CreatureStruct2(Structure): + _fields_ = [("swimming", c_uint, 1), + ("sparring", c_uint, 1), + ("no_notify", c_uint, 1), + ("unused", c_uint, 1), + ("calculated_nerves", c_uint, 1), + ("calculated_bodyparts", c_uint, 1), + ("important_historical_figure", c_uint, 1), + ("killed", c_uint, 1), + ("cleanup_1", c_uint, 1), + ("cleanup_2", c_uint, 1), + ("cleanup_3", c_uint, 1), + ("for_trade", c_uint, 1), + ("trade_resolved", c_uint, 1), + ("has_breaks", c_uint, 1), + ("gutted", c_uint, 1), + ("circulatory_spray", c_uint, 1), + ("locked_in_for_trading", c_uint, 1), + ("slaughter", c_uint, 1), + ("underworld", c_uint, 1), + ("resident", c_uint, 1), + ("cleanup_4", c_uint, 1), + ("calculated_insulation", c_uint, 1), + ("visitor_uninvited", c_uint, 1), + ("visitor", c_uint, 1), + ("calculated_inventory", c_uint, 1), + ("vision_good", c_uint, 1), + ("vision_damaged", c_uint, 1), + ("vision_missing", c_uint, 1), + ("breathing_good", c_uint, 1), + ("breathing_problem", c_uint, 1), + ("roaming_wilderness_population_source", c_uint, 1), + ("roaming_wilderness_population_source_not_a_map_feature", c_uint, 1)] + +class CreatureFlags2(Union): + _fields_ = [("whole", c_uint, 32), + ("bits", CreatureStruct2)] + + def __init__(self, initial = 0): + self.whole = initial + + def __int__(self): + return self.whole + +class ItemStruct(Structure): + _fields_ = [("on_ground", c_uint, 1), + ("in_job", c_uint, 1), + ("in_inventory", c_uint, 1), + ("u_ngrd1", c_uint, 1), + ("in_workshop", c_uint, 1), + ("u_ngrd2", c_uint, 1), + ("u_ngrd3", c_uint, 1), + ("rotten", c_uint, 1), + ("unk1", c_uint, 1), + ("u_ngrd4", c_uint, 1), + ("unk2", c_uint, 1), + ("u_ngrd5", c_uint, 1), + ("unk3", c_uint, 1), + ("u_ngrd6", c_uint, 1), + ("narrow", c_uint, 1), + ("u_ngrd7", c_uint, 1), + ("worn", c_uint, 1), + ("unk4", c_uint, 1), + ("u_ngrd8", c_uint, 1), + ("forbid", c_uint, 1), + ("unk5", c_uint, 1), + ("dump", c_uint, 1), + ("on_fire", c_uint, 1), + ("melt", c_uint, 1), + ("hidden", c_uint, 1), + ("u_ngrd9", c_uint, 1), + ("unk6", c_uint, 1), + ("unk7", c_uint, 1), + ("unk8", c_uint, 1), + ("unk9", c_uint, 1), + ("unk10", c_uint, 1), + ("unk11", c_uint, 1)] + +class ItemFlags(Union): + _fields_ = [("whole", c_uint, 32), + ("bits", ItemStruct)] + + def __init__(self, initial = 0): + self.whole = initial + + def __int__(self): + return self.whole + +class BlockFlagStruct(Structure): + _fields_ = [("designated", c_uint, 1), + ("unk_1", c_uint, 1), + ("liquid_1", c_uint, 1), + ("liquid_2", c_uint, 1), + ("unk_2", c_uint, 28)] + +class BlockFlags(Union): + _fields_ = [("whole", c_uint, 32), + ("bits", BlockFlagStruct)] + + def __init__(self, inital = 0): + self.whole = initial + + def __int__(self): + return self.whole diff --git a/dfhack/python/c api/pydftypes.py b/dfhack/python/c api/pydftypes.py new file mode 100644 index 000000000..67e29b895 --- /dev/null +++ b/dfhack/python/c api/pydftypes.py @@ -0,0 +1,134 @@ +from ctypes import * +from collections import namedtuple +from pydfhackflags import * +from enum import * + +Position3D = namedtuple("Position3D", "x, y, z") +Rectangle = namedtuple("Rectangle", "x1, y1, x2, y2") +Note = namedtuple("Note", "symbol, foreground, background, name, position") +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") +CreatureTypeEx = namedtuple("CreatureTypeEx", "rawname, castes, tile_character, tilecolor") +TileColor = namedtuple("TileColor", "fore, back, bright") +Name = namedtuple("Name", "first_name, nickname, language, has_name, words, parts_of_speech") + +TileTypes40d = ((c_int * 16) * 16) +BiomeIndices40d = c_ubyte * 16 +Temperatures = ((c_ushort * 16) * 16) +Designations40d = ((DesignationFlags * 16) * 16) +Occupancies40d = ((OccupancyFlags * 16) * 16) + +class Position2D(Structure): + _fields_ = [("x", c_ushort), + ("y", c_ushort)] + +class PlaneCoord(Union): + _fields_ = [("xy", c_uint), + ("dim", Position2D)] + + def __cmp__(self, other): + if isinstance(other, PlaneCoord): + return self.xy - other.xy + else: + raise TypeError("argument must be of type %s" % type(self)) + +class Feature(Structure): + _fields_ = [("type", FeatureType), + ("main_material", c_short), + ("sub_material", c_short), + ("discovered", c_byte), + ("origin", c_uint)] + +class Vein(Structure): + _fields_ = [("vtable", c_uint), + ("type", c_int), + ("assignment", c_short * 16), + ("flags", c_uint), + ("address_of", c_uint)] + +class FrozenLiquidVein(Structure): + _fields_ = [("vtable", c_uint), + ("tiles", TileTypes40d), + ("address_of", c_uint)] + +class SpatterVein(Structure): + _fields_ = [("vtable", c_uint), + ("mat1", c_ushort), + ("unk1", c_ushort), + ("mat2", c_uint), + ("mat3", c_ushort), + ("intensity", ((c_ubyte * 16) * 16)), + ("address_of", c_uint)] + +class Soul(object): + def __init__(self, *args, **kwds): + if kwds: + for k, v in kwds.iteritems(): + self.__dict__[k] = v + +class MapBlock40d(Structure): + _fields_ = [("tiletypes", TileTypes40d), + ("designation", Designations40d), + ("occupancy", Occupancies40d), + ("biome_indices", BiomeIndices40d), + ("origin", c_uint), + ("blockflags", BlockFlags), + ("global_feature", c_short), + ("local_feature", c_short)] + + +class ViewScreen(Structure): + _fields_ = [("type", c_int)] + +class Matgloss(Structure): + _fields_ = [("id", c_char * 128), + ("fore", c_byte), + ("back", c_byte), + ("bright", c_byte), + ("name", c_char * 128)] + +class MatglossPair(Structure): + _fields_ [("type", c_short), + ("index", c_int)] + +class Descriptor_Color(Structure): + _fields_ = [("id", c_char * 128), + ("r", c_float), + ("v", c_float), + ("b", c_float), + ("name", c_char * 128)] + +class MatglossOther(Structure): + _fields_ = [("rawname", c_char * 128)] + +class Building(Structure): + _fields_ = [("origin", c_uint), + ("vtable", c_uint), + ("x1", c_uint), + ("y1", c_uint), + ("x2", c_uint), + ("y2", c_uint), + ("z", c_uint), + ("material", MatglossPair), + ("type", c_uint)] + +class CustomWorkshop(Structure): + _fields_ = [("index", c_uint), + ("name", c_char * 256)] + +class Construction(Structure): + _fields_ = [("x", c_ushort), + ("y", c_ushort), + ("z", c_ushort), + ("form", c_ushort), + ("unk_8", c_ushort), + ("mat_type", c_ushort), + ("mat_idx", c_ushort), + ("unk3", c_ushort), + ("unk4", c_ushort), + ("unk5", c_ushort), + ("unk6", c_uint), + ("origin", c_uint)]