From 91ab69fdcbe631ddce1ee607f934dfda94a1e0bc Mon Sep 17 00:00:00 2001 From: root Date: Mon, 3 May 2010 13:29:17 +1100 Subject: [PATCH 01/36] Ignore .pyc --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 71d983519..c250df176 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,7 @@ build*/ #fake curses header examples/fake-curses.h + +# Python binding binaries +\.pyc + From b644c86dc44a92d0953dc4f5976270fef843c343 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 3 May 2010 13:29:50 +1100 Subject: [PATCH 02/36] Ignore .pyc --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index c250df176..144415db0 100644 --- a/.gitignore +++ b/.gitignore @@ -23,5 +23,5 @@ build*/ examples/fake-curses.h # Python binding binaries -\.pyc +.pyc From e578cafe8fa21ac01da2c6e42d5443c8502636e8 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 3 May 2010 13:36:29 +1100 Subject: [PATCH 03/36] Ignore pydfhack.so --- .gitignore | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 144415db0..e32a8290c 100644 --- a/.gitignore +++ b/.gitignore @@ -23,5 +23,5 @@ build*/ examples/fake-curses.h # Python binding binaries -.pyc - +*.pyc +dfhack/python/pydfhack.so From fcc2cbfa09a7344ef267e92a50adb5ebe918809f Mon Sep 17 00:00:00 2001 From: root Date: Mon, 3 May 2010 13:37:13 +1100 Subject: [PATCH 04/36] IPython shell for easy lib using --- dfhack/python/shell.py | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100755 dfhack/python/shell.py diff --git a/dfhack/python/shell.py b/dfhack/python/shell.py new file mode 100755 index 000000000..1967ba4c2 --- /dev/null +++ b/dfhack/python/shell.py @@ -0,0 +1,38 @@ +#!/usr/bin/python +import sys +import pydfhack +import pydfapi +from smarthttp.lib.containers import SmartDict +DF = pydfapi.API("Memory.xml") + +DF.Attach() + +pos = DF.position +maps = DF.maps +maps.Start() +cursor = pos.cursor_coords +msize = maps.size +block = SmartDict() +if cursor: + block.coords = (cursor[0]/16, cursor[1]/16, cursor[2]) + block.tiles = maps.Read_Tile_Types(block.coords[0], block.coords[1], block.coords[2]) +maps.Finish() +DF.Resume() + +locs = dict(pydfhack=pydfhack, API=pydfhack._API, DF=DF, pos=pos, maps=maps, msize=msize, cursor=cursor, block=block) + +banner = """DFHack Shell\n\n"""\ + """\tpydfhack = {pydfhack}\n"""\ + """\tAPI = {API}\n"""\ + """\tDF = {DF}\n"""\ + """\tpos = {pos}\n"""\ + """\tmaps = {maps}\n"""\ + """\tmsize = {msize}\n"""\ + """\tcursor = {cursor}\n"""\ + """\tblock = {block}\n""".format(**locs) + +from IPython.Shell import IPShellEmbed +shell = IPShellEmbed() +shell.set_banner(shell.IP.BANNER + '\n\n' + banner) +shell(local_ns=locs, global_ns={}) + From 2a095cdc525c05f080ab56a655d156773892ee6e Mon Sep 17 00:00:00 2001 From: RusAnon Date: Mon, 3 May 2010 13:49:51 +1100 Subject: [PATCH 05/36] Classes for coords and blocks --- dfhack/python/blocks.py | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 dfhack/python/blocks.py diff --git a/dfhack/python/blocks.py b/dfhack/python/blocks.py new file mode 100644 index 000000000..91b2277ba --- /dev/null +++ b/dfhack/python/blocks.py @@ -0,0 +1,40 @@ +class Point(object): + x = None + y = None + z = None + block = False + def __init__(self, x, y, z, block=False): + self.x = x + self.y = y + self.z = z + self.block = block + + def get_block(self): + return Point(self.x/16, self.y/16, self.z, True) + +class Block(object): + """ + 16x16 tiles block + """ + api = None + tiles = None + coords = None + def __init__(self, api, coords): + """ + api is instance of API, which is used for read/write operations + coords is Point object + """ + self.api = api + if not isinstance(Point, coords): + raise Exception(u"coords parameter should be Point") + + if not coords.block: + coords = coords.get_block() + self.coords = coords + + def reload(self): + pass + + def save(self): + pass + From ec514c303b9867f7b6723521bc3b4babcbd3f961 Mon Sep 17 00:00:00 2001 From: RusAnon Date: Mon, 3 May 2010 13:51:08 +1100 Subject: [PATCH 06/36] Added __init__.py to make it package --- dfhack/python/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 dfhack/python/__init__.py diff --git a/dfhack/python/__init__.py b/dfhack/python/__init__.py new file mode 100644 index 000000000..e69de29bb From 021480ca9a0882a084be8f62335de0f9e1e965e5 Mon Sep 17 00:00:00 2001 From: RusAnon Date: Mon, 3 May 2010 14:06:46 +1100 Subject: [PATCH 07/36] Made proper egg package --- .gitignore | 3 ++- dfhack/python/__init__.py | 0 dfhack/python/{ => pydfhack}/blocks.py | 0 dfhack/python/{ => pydfhack}/pydfapi.py | 0 dfhack/python/{ => pydfhack}/pydfhackflags.py | 0 dfhack/python/{ => pydfhack}/pydftypes.py | 0 dfhack/python/setup.py | 19 +++++++++++++++++-- 7 files changed, 19 insertions(+), 3 deletions(-) delete mode 100644 dfhack/python/__init__.py rename dfhack/python/{ => pydfhack}/blocks.py (100%) rename dfhack/python/{ => pydfhack}/pydfapi.py (100%) rename dfhack/python/{ => pydfhack}/pydfhackflags.py (100%) rename dfhack/python/{ => pydfhack}/pydftypes.py (100%) diff --git a/.gitignore b/.gitignore index e32a8290c..0facefd9a 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,5 @@ examples/fake-curses.h # Python binding binaries *.pyc -dfhack/python/pydfhack.so +dfhack/python/pydfhack/_pydfhack.so +dfhack/python/PyDFHack.egg-info diff --git a/dfhack/python/__init__.py b/dfhack/python/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/dfhack/python/blocks.py b/dfhack/python/pydfhack/blocks.py similarity index 100% rename from dfhack/python/blocks.py rename to dfhack/python/pydfhack/blocks.py diff --git a/dfhack/python/pydfapi.py b/dfhack/python/pydfhack/pydfapi.py similarity index 100% rename from dfhack/python/pydfapi.py rename to dfhack/python/pydfhack/pydfapi.py diff --git a/dfhack/python/pydfhackflags.py b/dfhack/python/pydfhack/pydfhackflags.py similarity index 100% rename from dfhack/python/pydfhackflags.py rename to dfhack/python/pydfhack/pydfhackflags.py diff --git a/dfhack/python/pydftypes.py b/dfhack/python/pydfhack/pydftypes.py similarity index 100% rename from dfhack/python/pydftypes.py rename to dfhack/python/pydfhack/pydftypes.py diff --git a/dfhack/python/setup.py b/dfhack/python/setup.py index 5c60e8379..6421ff17d 100644 --- a/dfhack/python/setup.py +++ b/dfhack/python/setup.py @@ -1,5 +1,11 @@ # -*- coding: utf-8 -*- -from distutils.core import setup, Extension +try: + from setuptools import setup, find_packages +except ImportError: + from ez_setup import use_setuptools + use_setuptools() + from setuptools import setup, find_packages +from distutils.core import Extension e = Extension("pydfhack", 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"], @@ -9,4 +15,13 @@ e = Extension("pydfhack", libraries=["libdfhack"], export_symbols=["initpydfhack", "ReadRaw", "WriteRaw"]) -setup(name="PyDFHack", version="1.0", ext_modules=[e]) +setup( + name="PyDFHack", + description="Python wrapper and bindings for DFHack library", + version="1.0", + packages=find_packages(exclude=['ez_setup']), + include_package_data=True, + test_suite='nose.collector', + zip_safe=False, + ext_modules=[e], + ) From 34a8424afd13b230cad7bc2ca42ef4367591bddd Mon Sep 17 00:00:00 2001 From: RusAnon Date: Mon, 3 May 2010 14:12:31 +1100 Subject: [PATCH 08/36] Some fixes for compiling, setup and importing --- .gitignore | 1 + dfhack/python/pydfhack.cpp | 2 +- dfhack/python/pydfhack/__init__.py | 1 + dfhack/python/pydfhack/pydfapi.py | 19 +++++++++---------- dfhack/python/setup.py | 4 ++-- 5 files changed, 14 insertions(+), 13 deletions(-) create mode 100644 dfhack/python/pydfhack/__init__.py diff --git a/.gitignore b/.gitignore index 0facefd9a..78db0d39d 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,4 @@ examples/fake-curses.h *.pyc dfhack/python/pydfhack/_pydfhack.so dfhack/python/PyDFHack.egg-info +dfhack/python/build diff --git a/dfhack/python/pydfhack.cpp b/dfhack/python/pydfhack.cpp index 3ce0634c2..80b2c3571 100644 --- a/dfhack/python/pydfhack.cpp +++ b/dfhack/python/pydfhack.cpp @@ -62,7 +62,7 @@ static PyMethodDef module_methods[] = {NULL} //Sentinel }; -PyMODINIT_FUNC initpydfhack(void) +PyMODINIT_FUNC init_pydfhack(void) { PyObject* module; diff --git a/dfhack/python/pydfhack/__init__.py b/dfhack/python/pydfhack/__init__.py new file mode 100644 index 000000000..1f17c8569 --- /dev/null +++ b/dfhack/python/pydfhack/__init__.py @@ -0,0 +1 @@ +from .pydfapi import API diff --git a/dfhack/python/pydfhack/pydfapi.py b/dfhack/python/pydfhack/pydfapi.py index 0cb4c5be3..5b7f7ae97 100644 --- a/dfhack/python/pydfhack/pydfapi.py +++ b/dfhack/python/pydfhack/pydfapi.py @@ -1,6 +1,5 @@ -import pydfhack, os - -class API(pydfhack._API): +import _pydfhack, os +class API(_pydfhack._API): for file in ["Memory.xml", os.path.join("..","..","output","Memory.xml")]: if os.path.isfile(file): datafile = file @@ -9,20 +8,20 @@ class API(pydfhack._API): raise ImportError, "Memory.xml not found." def __init__(self, *args, **kwds): - pydfhack._API.__init__(self, API.datafile) + _pydfhack._API.__init__(self, API.datafile) self._map_mgr_type = Map self._vegetation_mgr_type = Vegetation self._gui_mgr_type = GUI -class Map(pydfhack._MapManager): +class Map(_pydfhack._MapManager): def __init__(self, *args, **kwds): - pydfhack._MapManager.__init__(self, args, kwds) + _pydfhack._MapManager.__init__(self, args, kwds) -class Vegetation(pydfhack._VegetationManager): +class Vegetation(_pydfhack._VegetationManager): def __init__(self, *args, **kwds): - pydfhack._VegetationManager.__init__(self, args, kwds) + _pydfhack._VegetationManager.__init__(self, args, kwds) -class GUI(pydfhack._GUIManager): +class GUI(_pydfhack._GUIManager): def __init__(self, *args, **kwds): - pydfhack._GUIManager.__init__(self, args, kwds) + _pydfhack._GUIManager.__init__(self, args, kwds) diff --git a/dfhack/python/setup.py b/dfhack/python/setup.py index 6421ff17d..226681478 100644 --- a/dfhack/python/setup.py +++ b/dfhack/python/setup.py @@ -7,13 +7,13 @@ except ImportError: from setuptools import setup, find_packages from distutils.core import Extension -e = Extension("pydfhack", +e = Extension("_pydfhack", 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"]) + export_symbols=["init_pydfhack", "ReadRaw", "WriteRaw"]) setup( name="PyDFHack", From f2fd748fc6b03097e0c5047f8754955c3dc3a2fc Mon Sep 17 00:00:00 2001 From: RusAnon Date: Mon, 3 May 2010 14:26:13 +1100 Subject: [PATCH 09/36] Some more fixes for setup and the binding --- dfhack/python/pydfhack.cpp | 2 +- dfhack/python/setup.py | 13 +++++++------ dfhack/python/shell.py | 5 ++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/dfhack/python/pydfhack.cpp b/dfhack/python/pydfhack.cpp index 80b2c3571..8d1fded04 100644 --- a/dfhack/python/pydfhack.cpp +++ b/dfhack/python/pydfhack.cpp @@ -102,7 +102,7 @@ PyMODINIT_FUNC init_pydfhack(void) if(PyType_Ready(&DF_GUI_type) < 0) return; - module = Py_InitModule3("pydfhack", module_methods, "pydfhack extension module"); + module = Py_InitModule3("_pydfhack", module_methods, "pydfhack extension module"); Py_INCREF(&DF_API_type); Py_INCREF(&DF_MemInfo_type); diff --git a/dfhack/python/setup.py b/dfhack/python/setup.py index 226681478..1f95d9238 100644 --- a/dfhack/python/setup.py +++ b/dfhack/python/setup.py @@ -6,14 +6,15 @@ except ImportError: use_setuptools() from setuptools import setup, find_packages from distutils.core import Extension +from os import path e = Extension("_pydfhack", - 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=["init_pydfhack", "ReadRaw", "WriteRaw"]) + 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=["../", path.join("..", "include"), path.join("..","depends","md5"), path.join("..","depends","tinyxml")], + library_dirs=[path.join("..","..","output")], + extra_compile_args=["-DLINUX_BUILD", "-w"], + libraries=["dfhack"], + export_symbols=["init_pydfhack", "ReadRaw", "WriteRaw"]) setup( name="PyDFHack", diff --git a/dfhack/python/shell.py b/dfhack/python/shell.py index 1967ba4c2..0ed37b52a 100755 --- a/dfhack/python/shell.py +++ b/dfhack/python/shell.py @@ -1,9 +1,8 @@ #!/usr/bin/python import sys import pydfhack -import pydfapi from smarthttp.lib.containers import SmartDict -DF = pydfapi.API("Memory.xml") +DF = pydfhack.API("Memory.xml") DF.Attach() @@ -19,7 +18,7 @@ if cursor: maps.Finish() DF.Resume() -locs = dict(pydfhack=pydfhack, API=pydfhack._API, DF=DF, pos=pos, maps=maps, msize=msize, cursor=cursor, block=block) +locs = dict(pydfhack=pydfhack, API=pydfhack.API, DF=DF, pos=pos, maps=maps, msize=msize, cursor=cursor, block=block) banner = """DFHack Shell\n\n"""\ """\tpydfhack = {pydfhack}\n"""\ From ff52803eff7fa887b65ac7ce84a89a06f16ecfcb Mon Sep 17 00:00:00 2001 From: RusAnon Date: Mon, 3 May 2010 15:00:18 +1100 Subject: [PATCH 10/36] Import from package; Check for import errors and handle them --- dfhack/python/DF_Imports.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/dfhack/python/DF_Imports.cpp b/dfhack/python/DF_Imports.cpp index 6bc07e546..249b53587 100644 --- a/dfhack/python/DF_Imports.cpp +++ b/dfhack/python/DF_Imports.cpp @@ -61,7 +61,12 @@ static void DoImports() { if(FlagsModule == NULL) { - FlagsModule = PyImport_ImportModule("pydfhackflags"); + FlagsModule = PyImport_ImportModule("pydfhack.pydfhackflags"); + if (PyErr_Occurred()) + { + PyErr_Print(); + return ; + } CreatureFlags1_type = PyObject_GetAttrString(FlagsModule, "CreatureFlags1"); CreatureFlags2_type = PyObject_GetAttrString(FlagsModule, "CreatureFlags2"); @@ -72,7 +77,12 @@ static void DoImports() } if(TypesModule == NULL) { - TypesModule = PyImport_ImportModule("pydftypes"); + TypesModule = PyImport_ImportModule("pydfhack.pydftypes"); + if (PyErr_Occurred()) + { + PyErr_Print(); + return ; + } Note_type = PyObject_GetAttrString(TypesModule, "Note"); Construction_type = PyObject_GetAttrString(TypesModule, "Construction"); From 1d2f085ef351fdfa86abe65557ba3fb8bf34dcd8 Mon Sep 17 00:00:00 2001 From: RusAnon Date: Mon, 3 May 2010 16:31:17 +1100 Subject: [PATCH 11/36] Added subclassing for all managers --- dfhack/python/DF_API.cpp | 205 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 196 insertions(+), 9 deletions(-) diff --git a/dfhack/python/DF_API.cpp b/dfhack/python/DF_API.cpp index b705ef627..0965823dd 100644 --- a/dfhack/python/DF_API.cpp +++ b/dfhack/python/DF_API.cpp @@ -58,7 +58,13 @@ struct DF_API PyObject* vegetation; PyObject* gui; + PyObject* mem_info_type; + PyObject* position_type; + PyObject* material_type; + PyObject* creature_type; PyObject* map_type; + PyObject* translate_type; + PyObject* construction_type; PyObject* vegetation_type; PyObject* gui_type; @@ -95,6 +101,7 @@ static int DF_API_init(DF_API* self, PyObject* args, PyObject* kwds) self->vegetation = NULL; self->gui = NULL; + self->position_type = (PyObject*)&DF_Position_type; self->map_type = (PyObject*)&DF_Map_type; self->vegetation_type = (PyObject*)&DF_Vegetation_type; self->gui_type = (PyObject*)&DF_GUI_type; @@ -206,7 +213,10 @@ static PyObject* DF_API_getMemoryInfo(DF_API* self, void* closure) { if(self->api_Ptr != NULL) { - self->mem_info = PyObject_Call((PyObject*)&DF_MemInfo_type, NULL, NULL); + PyObject *apiarg; + apiarg = PyTuple_New(1); + PyTuple_SetItem(apiarg, 0, (PyObject*)self); + self->mem_info = PyObject_CallObject(self->mem_info_type, apiarg); if(self->mem_info != NULL) { @@ -235,7 +245,10 @@ static PyObject* DF_API_getPosition(DF_API* self, void* closure) { if(self->api_Ptr != NULL) { - self->position = PyObject_Call((PyObject*)&DF_Position_type, NULL, NULL); + PyObject *apiarg; + apiarg = PyTuple_New(1); + PyTuple_SetItem(apiarg, 0, (PyObject*)self); + self->position = PyObject_CallObject(self->position_type, apiarg); if(self->position != NULL) { @@ -264,7 +277,10 @@ static PyObject* DF_API_getMaterial(DF_API* self, void* closure) { if(self->api_Ptr != NULL) { - self->material = PyObject_Call((PyObject*)&DF_Material_type, NULL, NULL); + PyObject *apiarg; + apiarg = PyTuple_New(1); + PyTuple_SetItem(apiarg, 0, (PyObject*)self); + self->material = PyObject_CallObject(self->material_type, apiarg); if(self->material != NULL) { @@ -293,7 +309,10 @@ static PyObject* DF_API_getCreature(DF_API* self, void* closure) { if(self->api_Ptr != NULL) { - self->creature = PyObject_Call((PyObject*)&DF_CreatureManager_type, NULL, NULL); + PyObject *apiarg; + apiarg = PyTuple_New(1); + PyTuple_SetItem(apiarg, 0, (PyObject*)self); + self->creature = PyObject_CallObject(self->creature_type, apiarg); if(self->creature != NULL) { @@ -322,7 +341,10 @@ static PyObject* DF_API_getMap(DF_API* self, void* closure) { if(self->api_Ptr != NULL) { - self->map = PyObject_CallObject(self->map_type, NULL); + PyObject *apiarg; + apiarg = PyTuple_New(1); + PyTuple_SetItem(apiarg, 0, (PyObject*)self); + self->map = PyObject_CallObject(self->map_type, apiarg); if(self->map != NULL) { @@ -351,7 +373,10 @@ static PyObject* DF_API_getTranslation(DF_API* self, void* closure) { if(self->api_Ptr != NULL) { - self->translate = PyObject_Call((PyObject*)&DF_Translate_type, NULL, NULL); + PyObject *apiarg; + apiarg = PyTuple_New(1); + PyTuple_SetItem(apiarg, 0, (PyObject*)self); + self->translate = PyObject_CallObject(self->translate_type, apiarg); if(self->translate != NULL) { @@ -380,7 +405,10 @@ static PyObject* DF_API_getConstruction(DF_API* self, void* closure) { if(self->api_Ptr != NULL) { - self->construction = PyObject_Call((PyObject*)&DF_Construction_type, NULL, NULL); + PyObject *apiarg; + apiarg = PyTuple_New(1); + PyTuple_SetItem(apiarg, 0, (PyObject*)self); + self->construction = PyObject_CallObject(self->construction_type, apiarg); if(self->construction != NULL) { @@ -409,7 +437,10 @@ static PyObject* DF_API_getVegetation(DF_API* self, void* closure) { if(self->api_Ptr != NULL) { - self->vegetation = PyObject_CallObject(self->vegetation_type, NULL); + PyObject *apiarg; + apiarg = PyTuple_New(1); + PyTuple_SetItem(apiarg, 0, (PyObject*)self); + self->vegetation = PyObject_CallObject(self->vegetation_type, apiarg); if(self->vegetation != NULL) { @@ -438,7 +469,10 @@ static PyObject* DF_API_getGUI(DF_API* self, void* closure) { if(self->api_Ptr != NULL) { - self->gui = PyObject_CallObject(self->gui_type, NULL); + PyObject *apiarg; + apiarg = PyTuple_New(1); + PyTuple_SetItem(apiarg, 0, (PyObject*)self); + self->gui = PyObject_CallObject(self->gui_type, apiarg); if(self->gui != NULL) { @@ -457,6 +491,105 @@ static PyObject* DF_API_getGUI(DF_API* self, void* closure) Py_RETURN_NONE; } +static PyObject* DF_API_getMemInfoType(DF_API* self, void* closure) +{ + return self->mem_info_type; +} + +static int DF_API_setMemInfoType(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_MemInfo_type) <= 0) + { + PySys_WriteStdout("failed subclass check"); + PyErr_SetString(PyExc_TypeError, "value must be descended from _pydfhack._MemInfo"); + return -1; + } + + self->mem_info_type = value; + + return 0; +} + +static PyObject* DF_API_getPositionType(DF_API* self, void* closure) +{ + return self->position_type; +} + +static int DF_API_setPositionType(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_Position_type) <= 0) + { + PySys_WriteStdout("failed subclass check"); + PyErr_SetString(PyExc_TypeError, "value must be descended from _pydfhack._PositionManager"); + return -1; + } + + self->position_type = value; + + return 0; +} + +static PyObject* DF_API_getMaterialType(DF_API* self, void* closure) +{ + return self->material_type; +} + +static int DF_API_setMaterialType(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_Material_type) <= 0) + { + PySys_WriteStdout("failed subclass check"); + PyErr_SetString(PyExc_TypeError, "value must be descended from pydfhack._MaterialManager"); + return -1; + } + + self->material_type = value; + + return 0; +} + +static PyObject* DF_API_getCreatureType(DF_API* self, void* closure) +{ + return self->creature_type; +} + +static int DF_API_setCreatureType(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_CreatureManager_type) <= 0) + { + PySys_WriteStdout("failed subclass check"); + PyErr_SetString(PyExc_TypeError, "value must be descended from pydfhack._CreatureManager"); + return -1; + } + + self->creature_type = value; + + return 0; +} static PyObject* DF_API_getMapType(DF_API* self, void* closure) { @@ -482,6 +615,54 @@ static int DF_API_setMapType(DF_API* self, PyObject* value) return 0; } +static PyObject* DF_API_getTranslateType(DF_API* self, void* closure) +{ + return self->translate_type; +} + +static int DF_API_setTranslateType(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_Translate_type) <= 0) + { + PySys_WriteStdout("failed subclass check"); + PyErr_SetString(PyExc_TypeError, "value must be descended from pydfhack._TranslateManager"); + return -1; + } + + self->translate_type = value; + + return 0; +} +static PyObject* DF_API_getConstructionType(DF_API* self, void* closure) +{ + return self->construction_type; +} + +static int DF_API_setConstructionType(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_Construction_type) <= 0) + { + PySys_WriteStdout("failed subclass check"); + PyErr_SetString(PyExc_TypeError, "value must be descended from pydfhack._ConstructionManager"); + return -1; + } + + self->construction_type = value; + + return 0; +} static PyObject* DF_API_getVegetationType(DF_API* self, void* closure) { @@ -546,7 +727,13 @@ 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}, + {"_mem_info_mgr_type", (getter)DF_API_getMemInfoType, (setter)DF_API_setMemInfoType, "_mem_info_mgr_type", NULL}, + {"_position_mgr_type", (getter)DF_API_getPositionType, (setter)DF_API_setPositionType, "_position_mgr_type", NULL}, + {"_material_mgr_type", (getter)DF_API_getMaterialType, (setter)DF_API_setMaterialType, "_material_mgr_type", NULL}, + {"_creature_mgr_type", (getter)DF_API_getCreatureType, (setter)DF_API_setCreatureType, "_creature_mgr_type", NULL}, {"_map_mgr_type", (getter)DF_API_getMapType, (setter)DF_API_setMapType, "_map_mgr_type", NULL}, + {"_translate_mgr_type", (getter)DF_API_getTranslateType, (setter)DF_API_setTranslateType, "_translate_mgr_type", NULL}, + {"_construction_mgr_type", (getter)DF_API_getConstructionType, (setter)DF_API_setConstructionType, "_construction_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 From 3ccb7783c90e0c23b1fef52ab74f02df9a710fd6 Mon Sep 17 00:00:00 2001 From: RusAnon Date: Mon, 3 May 2010 17:13:35 +1100 Subject: [PATCH 12/36] Added subclasses for all exported classes, and linked them to API --- dfhack/python/pydfhack/blocks.py | 6 ++++ dfhack/python/pydfhack/construction.py | 25 ++++++++++++++++ dfhack/python/pydfhack/creature.py | 25 ++++++++++++++++ dfhack/python/pydfhack/gui.py | 25 ++++++++++++++++ dfhack/python/pydfhack/map.py | 25 ++++++++++++++++ dfhack/python/pydfhack/materials.py | 25 ++++++++++++++++ dfhack/python/pydfhack/meminfo.py | 25 ++++++++++++++++ dfhack/python/pydfhack/position.py | 23 +++++++++++++++ dfhack/python/pydfhack/pydfapi.py | 41 ++++++++++++++++++-------- dfhack/python/pydfhack/translation.py | 25 ++++++++++++++++ dfhack/python/pydfhack/vegetation.py | 25 ++++++++++++++++ 11 files changed, 257 insertions(+), 13 deletions(-) create mode 100644 dfhack/python/pydfhack/construction.py create mode 100644 dfhack/python/pydfhack/creature.py create mode 100644 dfhack/python/pydfhack/gui.py create mode 100644 dfhack/python/pydfhack/map.py create mode 100644 dfhack/python/pydfhack/materials.py create mode 100644 dfhack/python/pydfhack/meminfo.py create mode 100644 dfhack/python/pydfhack/position.py create mode 100644 dfhack/python/pydfhack/translation.py create mode 100644 dfhack/python/pydfhack/vegetation.py diff --git a/dfhack/python/pydfhack/blocks.py b/dfhack/python/pydfhack/blocks.py index 91b2277ba..6e02d3066 100644 --- a/dfhack/python/pydfhack/blocks.py +++ b/dfhack/python/pydfhack/blocks.py @@ -11,6 +11,12 @@ class Point(object): def get_block(self): return Point(self.x/16, self.y/16, self.z, True) + + def __repr__(self): + b = '' + if self.block: + b = ', Block' + return "".format(self, b) class Block(object): """ diff --git a/dfhack/python/pydfhack/construction.py b/dfhack/python/pydfhack/construction.py new file mode 100644 index 000000000..d0876c5d9 --- /dev/null +++ b/dfhack/python/pydfhack/construction.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +""" +Python class for DF_Hack::Construction +""" +from ._pydfhack import _ConstructionManager +class Construction(_ConstructionManager): + api = None + started = False + def __init__(self, api, *args, **kwds): + _ConstructionManager.__init__(self, args, kwds) + self.api = api + + def prepare(self): + """ + Enforce Suspend/Start + """ + if self.api.prepare(): + if not self.started: + self.started = self.Start() + return self.started + else: + return False + + + diff --git a/dfhack/python/pydfhack/creature.py b/dfhack/python/pydfhack/creature.py new file mode 100644 index 000000000..8857e9ef1 --- /dev/null +++ b/dfhack/python/pydfhack/creature.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +""" +Python class for DF_Hack::Creature +""" +from ._pydfhack import _CreatureManager +class Creature(_CreatureManager): + api = None + started = False + def __init__(self, api, *args, **kwds): + _CreatureManager.__init__(self, args, kwds) + self.api = api + + def prepare(self): + """ + Enforce Suspend/Start + """ + if self.api.prepare(): + if not self.started: + self.started = self.Start() + return self.started + else: + return False + + + diff --git a/dfhack/python/pydfhack/gui.py b/dfhack/python/pydfhack/gui.py new file mode 100644 index 000000000..07192f67c --- /dev/null +++ b/dfhack/python/pydfhack/gui.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +""" +Python class for DF_Hack::GUI +""" +from ._pydfhack import _GUIManager +class GUI(_GUIManager): + api = None + started = False + def __init__(self, api, *args, **kwds): + _GUIManager.__init__(self, args, kwds) + self.api = api + + def prepare(self): + """ + Enforce Suspend/Start + """ + if self.api.prepare(): + if not self.started: + self.started = self.Start() + return self.started + else: + return False + + + diff --git a/dfhack/python/pydfhack/map.py b/dfhack/python/pydfhack/map.py new file mode 100644 index 000000000..944aa1fe0 --- /dev/null +++ b/dfhack/python/pydfhack/map.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +""" +Python class for DF_Hack::Maps +""" +from ._pydfhack import _MapManager +class Map(_MapManager): + api = None + started = False + def __init__(self, api, *args, **kwds): + _MapManager.__init__(self, args, kwds) + self.api = api + + def prepare(self): + """ + Enforce Suspend/Start + """ + if self.api.prepare(): + if not self.started: + self.started = self.Start() + return self.started + else: + return False + + + diff --git a/dfhack/python/pydfhack/materials.py b/dfhack/python/pydfhack/materials.py new file mode 100644 index 000000000..5cd3de191 --- /dev/null +++ b/dfhack/python/pydfhack/materials.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +""" +Python class for DF_Hack::Materials +""" +from ._pydfhack import _MaterialsManager +class Materials(_MaterialsManager): + api = None + started = False + def __init__(self, api, *args, **kwds): + _MaterialsManager.__init__(self, args, kwds) + self.api = api + + def prepare(self): + """ + Enforce Suspend/Start + """ + if self.api.prepare(): + if not self.started: + self.started = self.Start() + return self.started + else: + return False + + + diff --git a/dfhack/python/pydfhack/meminfo.py b/dfhack/python/pydfhack/meminfo.py new file mode 100644 index 000000000..2a4b155aa --- /dev/null +++ b/dfhack/python/pydfhack/meminfo.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +""" +Python class for DF_Hack::MemInfo +""" +from ._pydfhack import _MemInfo +class MemInfo(_MemInfo): + api = None + started = False + def __init__(self, api, *args, **kwds): + _MemInfo.__init__(self, args, kwds) + self.api = api + + def prepare(self): + """ + Enforce Suspend/Start + """ + if self.api.prepare(): + if not self.started: + self.started = self.Start() + return self.started + else: + return False + + + diff --git a/dfhack/python/pydfhack/position.py b/dfhack/python/pydfhack/position.py new file mode 100644 index 000000000..f46f5cf80 --- /dev/null +++ b/dfhack/python/pydfhack/position.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +""" +Python class for DF_Hack::Position +""" +from ._pydfhack import _PositionManager +from .blocks import Point, Block +class Position(_PositionManager): + api = None + def __init__(self, api, *args, **kwds): + _PositionManager.__init__(self, args, kwds) + self.api = api + + def prepare(self): + """ + Enforce Suspend/Start + """ + return self.api.prepare() + + def get_cursor(self): + self.prepare() + coords = self.cursor_coords + return Point(*coords) + diff --git a/dfhack/python/pydfhack/pydfapi.py b/dfhack/python/pydfhack/pydfapi.py index 5b7f7ae97..c172bc05f 100644 --- a/dfhack/python/pydfhack/pydfapi.py +++ b/dfhack/python/pydfhack/pydfapi.py @@ -1,4 +1,14 @@ import _pydfhack, os +from .blocks import Point, Block +from .meminfo import MemInfo +from .position import Position +from .materials import Materials +from .creature import Creature +from .map import Map +from .translation import Translation +from .construction import Construction +from .vegetation import Vegetation +from .gui import GUI class API(_pydfhack._API): for file in ["Memory.xml", os.path.join("..","..","output","Memory.xml")]: if os.path.isfile(file): @@ -7,21 +17,26 @@ class API(_pydfhack._API): else: raise ImportError, "Memory.xml not found." + def prepare(self): + """ + Enforce Attach/Suspend behavior. + Return True if succeeded, else False + """ + r = True + if not self.is_attached: + r = self.Attach() + if r and not self.is_suspended: + r = self.Suspend() + return r + def __init__(self, *args, **kwds): _pydfhack._API.__init__(self, API.datafile) - + self._mem_info_mgr_type = MemInfo + self._position_mgr_type = Position + self._material_mgr_type = Materials + self._creature_mgr_type = Creature self._map_mgr_type = Map + self._translate_mgr_type = Translation + self._construction_mgr_type = Construction self._vegetation_mgr_type = Vegetation self._gui_mgr_type = GUI - -class Map(_pydfhack._MapManager): - def __init__(self, *args, **kwds): - _pydfhack._MapManager.__init__(self, args, kwds) - -class Vegetation(_pydfhack._VegetationManager): - def __init__(self, *args, **kwds): - _pydfhack._VegetationManager.__init__(self, args, kwds) - -class GUI(_pydfhack._GUIManager): - def __init__(self, *args, **kwds): - _pydfhack._GUIManager.__init__(self, args, kwds) diff --git a/dfhack/python/pydfhack/translation.py b/dfhack/python/pydfhack/translation.py new file mode 100644 index 000000000..0179e9db0 --- /dev/null +++ b/dfhack/python/pydfhack/translation.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +""" +Python class for DF_Hack::Translation +""" +from ._pydfhack import _TranslationManager +class Translation(_TranslationManager): + api = None + started = False + def __init__(self, api, *args, **kwds): + _TranslationManager.__init__(self, args, kwds) + self.api = api + + def prepare(self): + """ + Enforce Suspend/Start + """ + if self.api.prepare(): + if not self.started: + self.started = self.Start() + return self.started + else: + return False + + + diff --git a/dfhack/python/pydfhack/vegetation.py b/dfhack/python/pydfhack/vegetation.py new file mode 100644 index 000000000..b80291d66 --- /dev/null +++ b/dfhack/python/pydfhack/vegetation.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +""" +Python class for DF_Hack::Vegetation +""" +from ._pydfhack import _VegetationManager +class Vegetation(_VegetationManager): + api = None + started = False + def __init__(self, api, *args, **kwds): + _VegetationManager.__init__(self, args, kwds) + self.api = api + + def prepare(self): + """ + Enforce Suspend/Start + """ + if self.api.prepare(): + if not self.started: + self.started = self.Start() + return self.started + else: + return False + + + From 7ac5b9a1fe88847b5de9a6a1ba2b17385a56e3de Mon Sep 17 00:00:00 2001 From: RusAnon Date: Mon, 3 May 2010 18:02:16 +1100 Subject: [PATCH 13/36] Mix-ins for Start/Finish handling --- dfhack/python/pydfhack/mixins.py | 56 ++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 dfhack/python/pydfhack/mixins.py diff --git a/dfhack/python/pydfhack/mixins.py b/dfhack/python/pydfhack/mixins.py new file mode 100644 index 000000000..67e069b70 --- /dev/null +++ b/dfhack/python/pydfhack/mixins.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- +""" +Mix-ins for bound classes +""" + +class NeedsStart(object): + """ + This mixin enforces Start/Finish routines + """ + started = False + def prepare(self): + """ + Enforce Suspend/Start + """ + if self.api.prepare(): + if not self.started: + self.Start() + return self.started + else: + return False + + def Start(self): + if self.api.prepare(): + self.started = self.cls.Start(self) + return self.started + else: + return False + + start = Start + + def Finish(self): + if self.started: + self.cls.Finish(self) + self.started = False + + finish = Finish + +class NoStart(object): + """ + This mixin enforces Suspend, and disables Start/Finish + """ + def prepare(self): + """ + Enforce Suspend + """ + return self.api.prepare() + + def Start(self): + raise Exception("{0.cls} does not need Start()".format(self)) + + start = Start + + def Finish(self): + raise Exception("{0.cls} does not need Finish()".format(self)) + + finish = Finish From e4210ad4445c3b016eefd781a2ae8c438b3271c7 Mon Sep 17 00:00:00 2001 From: RusAnon Date: Mon, 3 May 2010 18:02:33 +1100 Subject: [PATCH 14/36] Decorator to enforce suspend --- dfhack/python/pydfhack/decorators.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 dfhack/python/pydfhack/decorators.py diff --git a/dfhack/python/pydfhack/decorators.py b/dfhack/python/pydfhack/decorators.py new file mode 100644 index 000000000..702cf18f9 --- /dev/null +++ b/dfhack/python/pydfhack/decorators.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +""" +Decorators for bound classes +""" +from decorator import decorator + +@decorator +def suspend(func, self, *args, **kw): + """ + This decorator will try to suspend DF and start needed module before running func + """ + if self.prepare(): + return func(self, *args, **kw) + else: + raise Exception(u"Could not suspend/start") From 2fd787cc8ab007a97f787f7e89c248aca5c0b794 Mon Sep 17 00:00:00 2001 From: RusAnon Date: Mon, 3 May 2010 18:03:06 +1100 Subject: [PATCH 15/36] Some tweaks for Point --- dfhack/python/pydfhack/blocks.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/dfhack/python/pydfhack/blocks.py b/dfhack/python/pydfhack/blocks.py index 6e02d3066..e62d8c4cf 100644 --- a/dfhack/python/pydfhack/blocks.py +++ b/dfhack/python/pydfhack/blocks.py @@ -10,7 +10,14 @@ class Point(object): self.block = block def get_block(self): - return Point(self.x/16, self.y/16, self.z, True) + if not self.block: + return Point(self.x/16, self.y/16, self.z, True) + else: + return self + + @property + def xyz(self): + return (self.x, self.y, self.z) def __repr__(self): b = '' From 3c9abeff07ad70fc5a7d9e5b6afd7a21d0ff1d98 Mon Sep 17 00:00:00 2001 From: RusAnon Date: Mon, 3 May 2010 18:03:32 +1100 Subject: [PATCH 16/36] Use mix-ins and decorators for Map --- dfhack/python/pydfhack/map.py | 85 +++++++++++++++++++++++++++++------ 1 file changed, 72 insertions(+), 13 deletions(-) diff --git a/dfhack/python/pydfhack/map.py b/dfhack/python/pydfhack/map.py index 944aa1fe0..41953882c 100644 --- a/dfhack/python/pydfhack/map.py +++ b/dfhack/python/pydfhack/map.py @@ -3,23 +3,82 @@ Python class for DF_Hack::Maps """ from ._pydfhack import _MapManager -class Map(_MapManager): +from .mixins import NeedsStart +from .decorators import suspend + +class Map(NeedsStart, _MapManager): api = None - started = False + cls = _MapManager def __init__(self, api, *args, **kwds): - _MapManager.__init__(self, args, kwds) + self.cls.__init__(self, args, kwds) self.api = api - def prepare(self): + @suspend + def Write_Tile_Types(self, x=0, y=0, z=0, tiles=None, point=None): + if point: + point = point.get_block() + x, y, z = point.xyz + return self.cls.Write_Tile_Types(self, x, y, z, tiles) + + @suspend + def Write_Occupancy(self, *args, **kw): + return self.cls.Write_Occupancy(self, *args, **kw) + + @suspend + def Read_Tile_Types(self, x=0, y=0, z=0, point=None): """ - Enforce Suspend/Start + Returns 16x16 block in form of list of lists. + Should be called either by point or x,y,z coords. Coords are in block form. """ - if self.api.prepare(): - if not self.started: - self.started = self.Start() - return self.started - else: - return False - - + if point: + point = point.get_block() + x, y, z = point.xyz + return self.cls.Read_Tile_Types(self, x, y, z) + + @suspend + def Is_Valid_Block(self, *args, **kw): + return self.cls.Is_Valid_Block(self, *args, **kw) + + @suspend + def Write_Dirty_Bit(self, *args, **kw): + return self.cls.Write_Dirty_Bit(self, *args, **kw) + + @suspend + def Read_Designations(self, *args, **kw): + return self.cls.Read_Designations(self, *args, **kw) + + @suspend + def Write_Block_Flags(self, *args, **kw): + return self.cls.Write_Block_Flags(self, *args, **kw) + + @suspend + def Write_Designations(self, *args, **kw): + return self.cls.Write_Designations(self, *args, **kw) + + @suspend + def Read_Region_Offsets(self, *args, **kw): + return self.cls.Read_Region_Offsets(self, *args, **kw) + + @suspend + def Read_Dirty_Bit(self, *args, **kw): + return self.cls.Read_Dirty_Bit(self, *args, **kw) + + @suspend + def Read_Occupancy(self, *args, **kw): + return self.cls.Read_Occupancy(self, *args, **kw) + + @suspend + def Read_Block_Flags(self, *args, **kw): + return self.cls.Read_Block_Flags(self, *args, **kw) + + @suspend + def Read_Geology(self, *args, **kw): + return self.cls.Read_Geology(self, *args, **kw) + + @suspend + def Read_Block_40d(self, *args, **kw): + return self.cls.Read_Block_40d(self, *args, **kw) + @suspend + def get_size(self): + return self.size From 5908e1ca71243f78fdd8b0e8f3c95ecfdd0d4a2c Mon Sep 17 00:00:00 2001 From: RusAnon Date: Mon, 3 May 2010 18:10:00 +1100 Subject: [PATCH 17/36] Updated Position for mix-ins and decorators --- dfhack/python/pydfhack/position.py | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/dfhack/python/pydfhack/position.py b/dfhack/python/pydfhack/position.py index f46f5cf80..8b39aa7d5 100644 --- a/dfhack/python/pydfhack/position.py +++ b/dfhack/python/pydfhack/position.py @@ -4,20 +4,27 @@ Python class for DF_Hack::Position """ from ._pydfhack import _PositionManager from .blocks import Point, Block -class Position(_PositionManager): +from .mixins import NoStart +from .decorators import suspend + +class Position(NoStart, _PositionManager): api = None + cls = _PositionManager def __init__(self, api, *args, **kwds): - _PositionManager.__init__(self, args, kwds) + self.cls.__init__(self, args, kwds) self.api = api - def prepare(self): - """ - Enforce Suspend/Start - """ - return self.api.prepare() - + @suspend def get_cursor(self): - self.prepare() coords = self.cursor_coords return Point(*coords) + @suspend + def get_window_size(self): + wsize = self.window_size + return wsize + + @suspend + def get_view_coords(self): + coords = self.view_coords + return Point(*coords) From d507974e8e8f93f21119fee38755aab6479e0acd Mon Sep 17 00:00:00 2001 From: RusAnon Date: Mon, 3 May 2010 18:18:41 +1100 Subject: [PATCH 18/36] MemInfo exported funcs --- dfhack/python/pydfhack/meminfo.py | 103 +++++++++++++++++++++++++----- 1 file changed, 88 insertions(+), 15 deletions(-) diff --git a/dfhack/python/pydfhack/meminfo.py b/dfhack/python/pydfhack/meminfo.py index 2a4b155aa..819623a9e 100644 --- a/dfhack/python/pydfhack/meminfo.py +++ b/dfhack/python/pydfhack/meminfo.py @@ -3,23 +3,96 @@ Python class for DF_Hack::MemInfo """ from ._pydfhack import _MemInfo -class MemInfo(_MemInfo): +from .mixins import NoStart +from .decorators import suspend + +class MemInfo(NoStart, _MemInfo): api = None - started = False + cls = _MemInfo def __init__(self, api, *args, **kwds): - _MemInfo.__init__(self, args, kwds) + self.cls.__init__(self, args, kwds) self.api = api - def prepare(self): - """ - Enforce Suspend/Start - """ - if self.api.prepare(): - if not self.started: - self.started = self.Start() - return self.started - else: - return False - - + ## Properties: + # version + # base + ## No idea if these should work only on suspend. To check later. + + def Rebase_All(self, *args, **kw): + return self.cls.Rebase_All(self, *args, **kw) + + def Set_String(self, *args, **kw): + return self.cls.Set_String(self, *args, **kw) + + def Resolve_Object_To_Class_ID(self, *args, **kw): + return self.cls.Resolve_Object_To_Class_ID(self, *args, **kw) + + def Get_Trait(self, *args, **kw): + return self.cls.Get_Trait(self, *args, **kw) + + def Get_Job(self, *args, **kw): + return self.cls.Get_Job(self, *args, **kw) + + def Rebase_VTable(self, *args, **kw): + return self.cls.Rebase_VTable(self, *args, **kw) + + def Get_String(self, *args, **kw): + return self.cls.Get_String(self, *args, **kw) + + def Get_Trait_Name(self, *args, **kw): + return self.cls.Get_Trait_Name(self, *args, **kw) + + def Set_Job(self, *args, **kw): + return self.cls.Set_Job(self, *args, **kw) + + def Set_Offset(self, *args, **kw): + return self.cls.Set_Offset(self, *args, **kw) + + def Rebase_Addresses(self, *args, **kw): + return self.cls.Rebase_Addresses(self, *args, **kw) + + def Resolve_Classname_To_Class_ID(self, *args, **kw): + return self.cls.Resolve_Classname_To_Class_ID(self, *args, **kw) + + def Set_Labor(self, *args, **kw): + return self.cls.Set_Labor(self, *args, **kw) + + def Get_Skill(self, *args, **kw): + return self.cls.Get_Skill(self, *args, **kw) + + def Set_Profession(self, *args, **kw): + return self.cls.Set_Profession(self, *args, **kw) + + def Get_Profession(self, *args, **kw): + return self.cls.Get_Profession(self, *args, **kw) + + def Get_Offset(self, *args, **kw): + return self.cls.Get_Offset(self, *args, **kw) + + def Get_HexValue(self, *args, **kw): + return self.cls.Get_HexValue(self, *args, **kw) + + def Set_Address(self, *args, **kw): + return self.cls.Set_Address(self, *args, **kw) + + def Set_HexValue(self, *args, **kw): + return self.cls.Set_HexValue(self, *args, **kw) + + def Get_Address(self, *args, **kw): + return self.cls.Get_Address(self, *args, **kw) + + def Set_Trait(self, *args, **kw): + return self.cls.Set_Trait(self, *args, **kw) + + def Resolve_Classname_To_VPtr(self, *args, **kw): + return self.cls.Resolve_Classname_To_VPtr(self, *args, **kw) + + def Get_Labor(self, *args, **kw): + return self.cls.Get_Labor(self, *args, **kw) + + def Set_Skill(self, *args, **kw): + return self.cls.Set_Skill(self, *args, **kw) + + def Resolve_Class_ID_To_Classname(self, *args, **kw): + return self.cls.Resolve_Class_ID_To_Classname(self, *args, **kw) From 9f5220235a619c92cbaf2034df2148d56ebc98b7 Mon Sep 17 00:00:00 2001 From: RusAnon Date: Mon, 3 May 2010 18:21:55 +1100 Subject: [PATCH 19/36] Materials exported funcs --- dfhack/python/pydfhack/materials.py | 47 ++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/dfhack/python/pydfhack/materials.py b/dfhack/python/pydfhack/materials.py index 5cd3de191..13e02c682 100644 --- a/dfhack/python/pydfhack/materials.py +++ b/dfhack/python/pydfhack/materials.py @@ -3,23 +3,40 @@ Python class for DF_Hack::Materials """ from ._pydfhack import _MaterialsManager -class Materials(_MaterialsManager): +from .mixins import NoStart +from .decorators import suspend + +class Materials(NoStart, _MaterialsManager): api = None - started = False + cls = _MaterialsManager def __init__(self, api, *args, **kwds): - _MaterialsManager.__init__(self, args, kwds) + cls.__init__(self, args, kwds) self.api = api - def prepare(self): - """ - Enforce Suspend/Start - """ - if self.api.prepare(): - if not self.started: - self.started = self.Start() - return self.started - else: - return False - - + @suspend + def Read_Wood_Materials(self, *args, **kw): + return self.cls.Read_Wood_Materials(self, *args, **kw) + + @suspend + def Read_Plant_Materials(self, *args, **kw): + return self.cls.Read_Plant_Materials(self, *args, **kw) + + @suspend + def Read_Inorganic_Materials(self, *args, **kw): + return self.cls.Read_Inorganic_Materials(self, *args, **kw) + + @suspend + def Read_Descriptor_Colors(self, *args, **kw): + return self.cls.Read_Descriptor_Colors(self, *args, **kw) + + @suspend + def Read_Creature_Types(self, *args, **kw): + return self.cls.Read_Creature_Types(self, *args, **kw) + + @suspend + def Read_Organic_Materials(self, *args, **kw): + return self.cls.Read_Organic_Materials(self, *args, **kw) + @suspend + def Read_Creature_Types_Ex(self, *args, **kw): + return self.cls.Read_Creature_Types_Ex(self, *args, **kw) From 9d770b9b767ae63765e8f1911690f555f16149ce Mon Sep 17 00:00:00 2001 From: RusAnon Date: Mon, 3 May 2010 18:25:23 +1100 Subject: [PATCH 20/36] Creature exported funcs --- dfhack/python/pydfhack/creature.py | 41 ++++++++++++++++++------------ 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/dfhack/python/pydfhack/creature.py b/dfhack/python/pydfhack/creature.py index 8857e9ef1..3234d563f 100644 --- a/dfhack/python/pydfhack/creature.py +++ b/dfhack/python/pydfhack/creature.py @@ -3,23 +3,32 @@ Python class for DF_Hack::Creature """ from ._pydfhack import _CreatureManager -class Creature(_CreatureManager): +from .mixins import NeedsStart +from .decorators import suspend + +class Creature(NeedsStart, _CreatureManager): api = None - started = False + cls = _CreatureManager def __init__(self, api, *args, **kwds): - _CreatureManager.__init__(self, args, kwds) + cls.__init__(self, args, kwds) self.api = api - def prepare(self): - """ - Enforce Suspend/Start - """ - if self.api.prepare(): - if not self.started: - self.started = self.Start() - return self.started - else: - return False - - - + @suspend + def Read_Creature(self, *args, **kw): + return self.cls.Read_Creature(self, *args, **kw) + + @suspend + def Get_Dwarf_Race_Index(self, *args, **kw): + return self.cls.Get_Dwarf_Race_Index(self, *args, **kw) + + @suspend + def Write_Labors(self, *args, **kw): + return self.cls.Write_Labors(self, *args, **kw) + + @suspend + def Read_Creature_In_Box(self, *args, **kw): + return self.cls.Read_Creature_In_Box(self, *args, **kw) + + @suspend + def Get_Dwarf_Civ_id(self, *args, **kw): + return self.cls.Get_Dwarf_Civ_id(self, *args, **kw) From 9d9e7a4f2417bf7b72d79f542a9160a9ee937726 Mon Sep 17 00:00:00 2001 From: RusAnon Date: Mon, 3 May 2010 18:28:14 +1100 Subject: [PATCH 21/36] Translation exports, creature fix --- dfhack/python/pydfhack/creature.py | 2 +- dfhack/python/pydfhack/translation.py | 25 ++++++++++--------------- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/dfhack/python/pydfhack/creature.py b/dfhack/python/pydfhack/creature.py index 3234d563f..676b10d40 100644 --- a/dfhack/python/pydfhack/creature.py +++ b/dfhack/python/pydfhack/creature.py @@ -10,7 +10,7 @@ class Creature(NeedsStart, _CreatureManager): api = None cls = _CreatureManager def __init__(self, api, *args, **kwds): - cls.__init__(self, args, kwds) + self.cls.__init__(self, args, kwds) self.api = api @suspend diff --git a/dfhack/python/pydfhack/translation.py b/dfhack/python/pydfhack/translation.py index 0179e9db0..6f7116217 100644 --- a/dfhack/python/pydfhack/translation.py +++ b/dfhack/python/pydfhack/translation.py @@ -3,23 +3,18 @@ Python class for DF_Hack::Translation """ from ._pydfhack import _TranslationManager -class Translation(_TranslationManager): +from .mixins import NeedsStart +from .decorators import suspend + +class Translation(NeedsStart, _TranslationManager): api = None - started = False + cls = _TranslationManager def __init__(self, api, *args, **kwds): - _TranslationManager.__init__(self, args, kwds) + self.cls.__init__(self, args, kwds) self.api = api - def prepare(self): - """ - Enforce Suspend/Start - """ - if self.api.prepare(): - if not self.started: - self.started = self.Start() - return self.started - else: - return False - - + def get_dictionaries(self): + return self.dictionaries + def Translate_Name(self, *args, **kw): + return self.cls.Translate_Name(self, *args, **kw) From f678b344d2897e3abccff816b9619bb1000444cc Mon Sep 17 00:00:00 2001 From: RusAnon Date: Mon, 3 May 2010 18:31:20 +1100 Subject: [PATCH 22/36] Construction and Vegetation exports --- dfhack/python/pydfhack/construction.py | 25 +++++++++---------------- dfhack/python/pydfhack/vegetation.py | 25 +++++++++---------------- 2 files changed, 18 insertions(+), 32 deletions(-) diff --git a/dfhack/python/pydfhack/construction.py b/dfhack/python/pydfhack/construction.py index d0876c5d9..c19be2fc1 100644 --- a/dfhack/python/pydfhack/construction.py +++ b/dfhack/python/pydfhack/construction.py @@ -3,23 +3,16 @@ Python class for DF_Hack::Construction """ from ._pydfhack import _ConstructionManager -class Construction(_ConstructionManager): +from .mixins import NeedsStart +from .decorators import suspend + +class Construction(NeedsStart, _ConstructionManager): api = None - started = False + cls = _ConstructionManager def __init__(self, api, *args, **kwds): - _ConstructionManager.__init__(self, args, kwds) + self.cls.__init__(self, args, kwds) self.api = api - def prepare(self): - """ - Enforce Suspend/Start - """ - if self.api.prepare(): - if not self.started: - self.started = self.Start() - return self.started - else: - return False - - - + @suspend + def Read(self, *args, **kw): + return self.cls.Read(self, *args, **kw) diff --git a/dfhack/python/pydfhack/vegetation.py b/dfhack/python/pydfhack/vegetation.py index b80291d66..ce1262a13 100644 --- a/dfhack/python/pydfhack/vegetation.py +++ b/dfhack/python/pydfhack/vegetation.py @@ -3,23 +3,16 @@ Python class for DF_Hack::Vegetation """ from ._pydfhack import _VegetationManager -class Vegetation(_VegetationManager): +from .mixins import NeedsStart +from .decorators import suspend + +class Vegetation(NeedsStart, _VegetationManager): api = None - started = False + cls = _VegetationManager def __init__(self, api, *args, **kwds): - _VegetationManager.__init__(self, args, kwds) + self.cls.__init__(self, args, kwds) self.api = api - - def prepare(self): - """ - Enforce Suspend/Start - """ - if self.api.prepare(): - if not self.started: - self.started = self.Start() - return self.started - else: - return False - - + @suspend + def Read(self, *args, **kw): + return self.cls.Read(self, *args, **kw) From add3288333d089aa399d312f7f0f689ed710fa9a Mon Sep 17 00:00:00 2001 From: RusAnon Date: Mon, 3 May 2010 18:45:25 +1100 Subject: [PATCH 23/36] Automatically handle Suspend/Resume Start/Finish --- dfhack/python/pydfhack/decorators.py | 9 +++- dfhack/python/pydfhack/mixins.py | 7 +++ dfhack/python/pydfhack/pydfapi.py | 66 ++++++++++++++++------------ 3 files changed, 52 insertions(+), 30 deletions(-) diff --git a/dfhack/python/pydfhack/decorators.py b/dfhack/python/pydfhack/decorators.py index 702cf18f9..db0f565fd 100644 --- a/dfhack/python/pydfhack/decorators.py +++ b/dfhack/python/pydfhack/decorators.py @@ -7,9 +7,14 @@ from decorator import decorator @decorator def suspend(func, self, *args, **kw): """ - This decorator will try to suspend DF and start needed module before running func + This decorator will try to suspend DF and start needed module before running func. + If DF was resumed when decorator was run, it will try to resume back after executing func """ + susp = not self.api.is_attached or self.api.is_suspended if self.prepare(): - return func(self, *args, **kw) + res = func(self, *args, **kw) + if not susp: + self.api.Resume() + return res else: raise Exception(u"Could not suspend/start") diff --git a/dfhack/python/pydfhack/mixins.py b/dfhack/python/pydfhack/mixins.py index 67e069b70..29ef213d0 100644 --- a/dfhack/python/pydfhack/mixins.py +++ b/dfhack/python/pydfhack/mixins.py @@ -20,8 +20,13 @@ class NeedsStart(object): return False def Start(self): + if self.started: + return True + if self.api.prepare(): self.started = self.cls.Start(self) + if self.started: + self.api.started.append(self) return self.started else: return False @@ -32,6 +37,8 @@ class NeedsStart(object): if self.started: self.cls.Finish(self) self.started = False + if self in self.api.started: + self.api.started.remove(self) finish = Finish diff --git a/dfhack/python/pydfhack/pydfapi.py b/dfhack/python/pydfhack/pydfapi.py index c172bc05f..94efb5f9a 100644 --- a/dfhack/python/pydfhack/pydfapi.py +++ b/dfhack/python/pydfhack/pydfapi.py @@ -10,33 +10,43 @@ from .construction import Construction from .vegetation import Vegetation from .gui import GUI class API(_pydfhack._API): - for file in ["Memory.xml", os.path.join("..","..","output","Memory.xml")]: - if os.path.isfile(file): - datafile = file - break - else: - raise ImportError, "Memory.xml not found." + started = None + + for file in ["Memory.xml", os.path.join("..","..","output","Memory.xml")]: + if os.path.isfile(file): + datafile = file + break + else: + raise ImportError, "Memory.xml not found." - def prepare(self): - """ - Enforce Attach/Suspend behavior. - Return True if succeeded, else False - """ - r = True - if not self.is_attached: - r = self.Attach() - if r and not self.is_suspended: - r = self.Suspend() - return r + def prepare(self): + """ + Enforce Attach/Suspend behavior. + Return True if succeeded, else False + """ + r = True + if not self.is_attached: + r = self.Attach() + if r and not self.is_suspended: + r = self.Suspend() + return r - def __init__(self, *args, **kwds): - _pydfhack._API.__init__(self, API.datafile) - self._mem_info_mgr_type = MemInfo - self._position_mgr_type = Position - self._material_mgr_type = Materials - self._creature_mgr_type = Creature - self._map_mgr_type = Map - self._translate_mgr_type = Translation - self._construction_mgr_type = Construction - self._vegetation_mgr_type = Vegetation - self._gui_mgr_type = GUI + def __init__(self, *args, **kwds): + _pydfhack._API.__init__(self, API.datafile) + self._mem_info_mgr_type = MemInfo + self._position_mgr_type = Position + self._material_mgr_type = Materials + self._creature_mgr_type = Creature + self._map_mgr_type = Map + self._translate_mgr_type = Translation + self._construction_mgr_type = Construction + self._vegetation_mgr_type = Vegetation + self._gui_mgr_type = GUI + self.started = [] + + def Resume(self): + # Explicitly Finish() all started modules + for m in self.started[:]: + m.Finish() + self.started = [] + _pydfhack._API.Resume(self) From 394002f688b88008b676a22b9c889905758af428 Mon Sep 17 00:00:00 2001 From: RusAnon Date: Mon, 3 May 2010 21:19:40 +1100 Subject: [PATCH 24/36] Some work on blocks access --- dfhack/python/pydfhack/blocks.py | 102 ++++++++++++++++++++++++++--- dfhack/python/pydfhack/map.py | 66 ++++++++++++++----- dfhack/python/pydfhack/position.py | 14 +++- dfhack/python/pydfhack/pydfapi.py | 31 +++++++-- dfhack/python/shell.py | 23 +++---- 5 files changed, 193 insertions(+), 43 deletions(-) diff --git a/dfhack/python/pydfhack/blocks.py b/dfhack/python/pydfhack/blocks.py index e62d8c4cf..ac04ef8ab 100644 --- a/dfhack/python/pydfhack/blocks.py +++ b/dfhack/python/pydfhack/blocks.py @@ -1,3 +1,12 @@ +# -*- coding: utf-8 -*- +""" +Module for high-level abstraction of tiles +""" +from collections import namedtuple +from .pydftypes import Rectangle +from .mixins import NoStart +from .decorators import suspend + class Point(object): x = None y = None @@ -18,36 +27,113 @@ class Point(object): @property def xyz(self): return (self.x, self.y, self.z) + + @property + def rect(self): + """ + Return block coords in form (x1, y1, x2, y2) + """ + block = self.get_block() + x1 = block.x * 16 + y1 = block.y * 16 + return Rectangle(x1, y1, x1+15, y1+15) + def __repr__(self): b = '' if self.block: b = ', Block' - return "".format(self, b) + return "".format(self, b) -class Block(object): +class Block(NoStart): """ 16x16 tiles block """ api = None tiles = None coords = None + x1 = None + y1 = None def __init__(self, api, coords): """ api is instance of API, which is used for read/write operations coords is Point object """ self.api = api - if not isinstance(Point, coords): + if not isinstance(coords, Point): raise Exception(u"coords parameter should be Point") - if not coords.block: - coords = coords.get_block() + coords = coords.get_block() self.coords = coords + self.rect = self.coords.rect + self.reload() + @suspend def reload(self): - pass + tile_types = self.api.maps.Read_Tile_Types(point=self.coords) + tile_flags = self.api.maps.Read_Designations(point=self.coords) + if self.tiles: + for x in range(16): + for y in range(16): + self.tiles[x][y].update(ttype=tile_types[x][y], flags=tile_flags[x][y]) + else: + self.tiles = [] + for x in range(16): + row = [] + for y in range(16): + row.append(Tile(self, tile_types[x][y], tile_flags[x][y], self.rect.x1 + x, self.rect.y1 + y, self.coords.z)) + self.tiles.append(row) + + @suspend + def save(self): + tile_types = map(lambda x:range(16), range(16)) + tile_flags = map(lambda x:range(16), range(16)) + for x in range(16): + for y in range(16): + tile_types[x][y] = self.tiles[x][y].ttype + tile_flags[x][y] = self.tiles[x][y].flags + self.api.maps.Write_Tile_Types(point=self.coords, tiles=tile_types) + # Designations are bugged + + #self.api.maps.Write_Designations(point=self.coords, tiles=tile_flags) + + def get_tile(self, x=0, y=0, z=0, point=None): + if point: + x, y, z = point.xyz + + if z == self.coords.z and (self.rect.y1 <= y <= self.rect.y2) and (self.rect.x1 <= x <= self.rect.x2): + return self.tiles[x%16][y%16] + else: + raise Exception("This tile does not belong to this block") + def __repr__(self): + return "".format(self, self.coords, *self.coords.rect) + + + +class Tile(object): + coords = None + block = None + ttype = None + temperature = None + flags = None + def __init__(self, block, ttype, flags, x=0, y=0, z=0, point=None): + self.ttype = ttype + self.flags = flags + if not point: + point = Point(x, y, z) + self.coords = point + self.block = block + + def update(self, ttype, flags): + self.ttype = ttype + self.flags = flags + + def reload(self): + self.block.reload() + def save(self): - pass - + self.block.save() + + def __repr__(self): + return "".format(self, self.coords) diff --git a/dfhack/python/pydfhack/map.py b/dfhack/python/pydfhack/map.py index 41953882c..7eab175f0 100644 --- a/dfhack/python/pydfhack/map.py +++ b/dfhack/python/pydfhack/map.py @@ -5,6 +5,7 @@ Python class for DF_Hack::Maps from ._pydfhack import _MapManager from .mixins import NeedsStart from .decorators import suspend +from .blocks import Block, Point class Map(NeedsStart, _MapManager): api = None @@ -14,15 +15,18 @@ class Map(NeedsStart, _MapManager): self.api = api @suspend - def Write_Tile_Types(self, x=0, y=0, z=0, tiles=None, point=None): + def get_size(self): + return self.size + + @suspend + def Is_Valid_Block(self, x=0, y=0, z=0, point=None): + """ + Checks if coords are valid + """ if point: point = point.get_block() x, y, z = point.xyz - return self.cls.Write_Tile_Types(self, x, y, z, tiles) - - @suspend - def Write_Occupancy(self, *args, **kw): - return self.cls.Write_Occupancy(self, *args, **kw) + return self.cls.Is_Valid_Block(self, x, y, z) @suspend def Read_Tile_Types(self, x=0, y=0, z=0, point=None): @@ -36,25 +40,42 @@ class Map(NeedsStart, _MapManager): return self.cls.Read_Tile_Types(self, x, y, z) @suspend - def Is_Valid_Block(self, *args, **kw): - return self.cls.Is_Valid_Block(self, *args, **kw) + def Write_Tile_Types(self, x=0, y=0, z=0, tiles=None, point=None): + if point: + point = point.get_block() + x, y, z = point.xyz + return self.cls.Write_Tile_Types(self, x, y, z, tiles) + + @suspend + def Read_Designations(self, x=0, y=0, z=0, point=None): + """ + Returns 16x16 block in form of list of lists. + """ + if point: + point = point.get_block() + x, y, z = point.xyz + return self.cls.Read_Designations(self, x, y, z) + + @suspend + def Write_Designations(self, x=0, y=0, z=0, tiles=None, point=None): + if point: + point = point.get_block() + x, y, z = point.xyz + return self.cls.Write_Designations(self, x, y, z, tiles) + + @suspend + def Write_Occupancy(self, *args, **kw): + return self.cls.Write_Occupancy(self, *args, **kw) @suspend def Write_Dirty_Bit(self, *args, **kw): return self.cls.Write_Dirty_Bit(self, *args, **kw) - @suspend - def Read_Designations(self, *args, **kw): - return self.cls.Read_Designations(self, *args, **kw) @suspend def Write_Block_Flags(self, *args, **kw): return self.cls.Write_Block_Flags(self, *args, **kw) - @suspend - def Write_Designations(self, *args, **kw): - return self.cls.Write_Designations(self, *args, **kw) - @suspend def Read_Region_Offsets(self, *args, **kw): return self.cls.Read_Region_Offsets(self, *args, **kw) @@ -80,5 +101,16 @@ class Map(NeedsStart, _MapManager): return self.cls.Read_Block_40d(self, *args, **kw) @suspend - def get_size(self): - return self.size + def get_block(self, point): + point = point.get_block() + block = Block(api=self.api, coords=point) + return block + + @suspend + def get_tile(self, x=0, y=0, z=0, point=None): + if not point: + point = Point(x, y, z) + block = Block(api=self.api, coords=point.get_block()) + return block.get_tile(point=point) + + diff --git a/dfhack/python/pydfhack/position.py b/dfhack/python/pydfhack/position.py index 8b39aa7d5..7956ea812 100644 --- a/dfhack/python/pydfhack/position.py +++ b/dfhack/python/pydfhack/position.py @@ -17,7 +17,10 @@ class Position(NoStart, _PositionManager): @suspend def get_cursor(self): coords = self.cursor_coords - return Point(*coords) + if coords: + return Point(*coords) + else: + return None @suspend def get_window_size(self): @@ -28,3 +31,12 @@ class Position(NoStart, _PositionManager): def get_view_coords(self): coords = self.view_coords return Point(*coords) + + @suspend + def get_cursor_tile(self): + point = self.get_cursor() + if point: + tile = self.api.maps.get_tile(point=point) + return tile + else: + return None diff --git a/dfhack/python/pydfhack/pydfapi.py b/dfhack/python/pydfhack/pydfapi.py index 94efb5f9a..10b0976d4 100644 --- a/dfhack/python/pydfhack/pydfapi.py +++ b/dfhack/python/pydfhack/pydfapi.py @@ -1,4 +1,4 @@ -import _pydfhack, os +import _pydfhack, os, copy from .blocks import Point, Block from .meminfo import MemInfo from .position import Position @@ -44,9 +44,28 @@ class API(_pydfhack._API): self._gui_mgr_type = GUI self.started = [] + def Attach(self, *args, **kw): + print "API.Attach()" + return _pydfhack._API.Attach(self, *args, **kw) + + def Detach(self, *args, **kw): + print "API.Detach()" + return _pydfhack._API.Detach(self, *args, **kw) + + def Suspend(self, *args, **kw): + print "API.Suspend()" + return _pydfhack._API.Suspend(self, *args, **kw) + def Resume(self): - # Explicitly Finish() all started modules - for m in self.started[:]: - m.Finish() - self.started = [] - _pydfhack._API.Resume(self) + print "API.Resume()" + # Reference counting is fcked, so leave it alone for now + + ## Explicitly Finish() all started modules + #print self.started + #started = copy.copy(self.started) + #print started + #for m in started: + # print m + # m.Finish() + #self.started = [] + return _pydfhack._API.Resume(self) diff --git a/dfhack/python/shell.py b/dfhack/python/shell.py index 0ed37b52a..41c43cdc5 100755 --- a/dfhack/python/shell.py +++ b/dfhack/python/shell.py @@ -1,24 +1,24 @@ #!/usr/bin/python import sys import pydfhack -from smarthttp.lib.containers import SmartDict DF = pydfhack.API("Memory.xml") DF.Attach() pos = DF.position maps = DF.maps -maps.Start() -cursor = pos.cursor_coords -msize = maps.size -block = SmartDict() +refc = dict(pydfhack=pydfhack, API=pydfhack.API, DF=DF, pos=pos, maps=maps) +cursor = pos.get_cursor() +msize = maps.get_size() +block = None +tile = None if cursor: - block.coords = (cursor[0]/16, cursor[1]/16, cursor[2]) - block.tiles = maps.Read_Tile_Types(block.coords[0], block.coords[1], block.coords[2]) -maps.Finish() + block = maps.get_block(point=cursor) + if block: + tile = block.get_tile(point=cursor) DF.Resume() -locs = dict(pydfhack=pydfhack, API=pydfhack.API, DF=DF, pos=pos, maps=maps, msize=msize, cursor=cursor, block=block) +locs = dict(pydfhack=pydfhack, API=pydfhack.API, DF=DF, pos=pos, maps=maps, msize=msize, cursor=cursor, block=block, tile=tile) banner = """DFHack Shell\n\n"""\ """\tpydfhack = {pydfhack}\n"""\ @@ -28,10 +28,11 @@ banner = """DFHack Shell\n\n"""\ """\tmaps = {maps}\n"""\ """\tmsize = {msize}\n"""\ """\tcursor = {cursor}\n"""\ - """\tblock = {block}\n""".format(**locs) + """\tblock = {block}\n"""\ + """\ttile = {tile}\n""".format(**locs) from IPython.Shell import IPShellEmbed shell = IPShellEmbed() shell.set_banner(shell.IP.BANNER + '\n\n' + banner) shell(local_ns=locs, global_ns={}) - +DF.Detach() From 8eeb9296c30e750d249cee45d38723f1fc2e0637 Mon Sep 17 00:00:00 2001 From: RusAnon Date: Mon, 3 May 2010 21:36:21 +1100 Subject: [PATCH 25/36] Fixed compiling and installing of so and xml --- dfhack/python/pydfhack/pydfapi.py | 9 +++------ dfhack/python/setup.py | 11 ++++++++++- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/dfhack/python/pydfhack/pydfapi.py b/dfhack/python/pydfhack/pydfapi.py index 10b0976d4..27f1ef3cc 100644 --- a/dfhack/python/pydfhack/pydfapi.py +++ b/dfhack/python/pydfhack/pydfapi.py @@ -11,12 +11,9 @@ from .vegetation import Vegetation from .gui import GUI class API(_pydfhack._API): started = None - - for file in ["Memory.xml", os.path.join("..","..","output","Memory.xml")]: - if os.path.isfile(file): - datafile = file - break - else: + path = os.path.dirname(os.path.abspath(__file__)) + datafile = os.path.join(path, "Memory.xml") + if not os.path.isfile(datafile): raise ImportError, "Memory.xml not found." def prepare(self): diff --git a/dfhack/python/setup.py b/dfhack/python/setup.py index 1f95d9238..352eb1e59 100644 --- a/dfhack/python/setup.py +++ b/dfhack/python/setup.py @@ -8,7 +8,7 @@ except ImportError: from distutils.core import Extension from os import path -e = Extension("_pydfhack", +e = Extension("pydfhack._pydfhack", 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=["../", path.join("..", "include"), path.join("..","depends","md5"), path.join("..","depends","tinyxml")], library_dirs=[path.join("..","..","output")], @@ -16,11 +16,20 @@ e = Extension("_pydfhack", libraries=["dfhack"], export_symbols=["init_pydfhack", "ReadRaw", "WriteRaw"]) +for file in ["Memory.xml", path.join("..","..","output","Memory.xml")]: + if path.isfile(file): + datafile = file + break +else: + raise Exception("Memory.xml not found.") + + setup( name="PyDFHack", description="Python wrapper and bindings for DFHack library", version="1.0", packages=find_packages(exclude=['ez_setup']), + data_files=[('pydfhack', [datafile])], include_package_data=True, test_suite='nose.collector', zip_safe=False, From e5d280518488978d6a5032cfea2657b79045b01b Mon Sep 17 00:00:00 2001 From: RusAnon Date: Mon, 3 May 2010 21:36:59 +1100 Subject: [PATCH 26/36] Ignore ./dist --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 78db0d39d..5abcc3138 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,4 @@ examples/fake-curses.h dfhack/python/pydfhack/_pydfhack.so dfhack/python/PyDFHack.egg-info dfhack/python/build +dfhack/python/dist From 2b04c0f66290888569d8b8d58b5ebb5c9f89196c Mon Sep 17 00:00:00 2001 From: RusAnon Date: Mon, 3 May 2010 22:03:28 +1100 Subject: [PATCH 27/36] Hack to bypass MEMXML_DATA_PATH xml path restriction --- dfhack/python/pydfhack/pydfapi.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dfhack/python/pydfhack/pydfapi.py b/dfhack/python/pydfhack/pydfapi.py index 27f1ef3cc..7f7943625 100644 --- a/dfhack/python/pydfhack/pydfapi.py +++ b/dfhack/python/pydfhack/pydfapi.py @@ -15,6 +15,9 @@ class API(_pydfhack._API): datafile = os.path.join(path, "Memory.xml") if not os.path.isfile(datafile): raise ImportError, "Memory.xml not found." + + # Rude hack to bypass xml location restrictions + datafile = "./" + "../"*20 + datafile def prepare(self): """ From ada8da84224c1e84ca37014c1fce47e5fb674768 Mon Sep 17 00:00:00 2001 From: doomchild Date: Tue, 4 May 2010 04:50:43 +0800 Subject: [PATCH 28/36] fixed void pointer delete bug --- dfhack/DFHackAPI_C.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dfhack/DFHackAPI_C.cpp b/dfhack/DFHackAPI_C.cpp index b9ebb76a9..e7bf624b0 100644 --- a/dfhack/DFHackAPI_C.cpp +++ b/dfhack/DFHackAPI_C.cpp @@ -49,11 +49,14 @@ DFHackObject* API_Alloc(const char* path_to_xml) } //FIXME: X:\dfhack\DFHackAPI_C.cpp:56: warning: deleting `DFHackObject* ' is undefined +//DC: Yeah, I forgot that trying to delete a void pointer might be a bad idea. This works now. void API_Free(DFHackObject* api) { if(api != NULL) { - delete api; + DFHack::API* a = (DFHack::API*)api; + delete a; + api = NULL; } } From 3d0a1299acf87be50bc6f43cd31ff248cd974dc3 Mon Sep 17 00:00:00 2001 From: doomchild Date: Tue, 4 May 2010 04:54:13 +0800 Subject: [PATCH 29/36] first commit, attaching/detaching/suspending/resuming works --- dfhack/python/dfhack_api_ctypes.py | 41 ++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 dfhack/python/dfhack_api_ctypes.py diff --git a/dfhack/python/dfhack_api_ctypes.py b/dfhack/python/dfhack_api_ctypes.py new file mode 100644 index 000000000..d9f460ba8 --- /dev/null +++ b/dfhack/python/dfhack_api_ctypes.py @@ -0,0 +1,41 @@ +from ctypes 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 ] + +class API(object): + def __init__(self, memory_path): + self._api_ptr = libdfhack.API_Alloc(create_string_buffer(memory_path)) + + 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 From 07ddc54e76d9a3c1f423c1c1c6e46d442a490fc3 Mon Sep 17 00:00:00 2001 From: RusAnon Date: Tue, 4 May 2010 13:47:06 +1100 Subject: [PATCH 30/36] Utility to count flows and liquids --- examples/CMakeLists.txt | 4 ++ examples/flows.cpp | 83 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 examples/flows.cpp diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 64615906e..1276e4b38 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -74,6 +74,10 @@ TARGET_LINK_LIBRARIES(dfspatterdump dfhack) ADD_EXECUTABLE(dfcatsplosion catsplosion.cpp) TARGET_LINK_LIBRARIES(dfcatsplosion dfhack) +# flows - check flows impact on fps +ADD_EXECUTABLE(dfflows flows.cpp) +TARGET_LINK_LIBRARIES(dfflows dfhack) + IF(UNIX) SET(CURSES_NEED_WIDE "YES") SET(CURSES_NEED_NCURSES "NO") diff --git a/examples/flows.cpp b/examples/flows.cpp new file mode 100644 index 000000000..352a16da2 --- /dev/null +++ b/examples/flows.cpp @@ -0,0 +1,83 @@ +// This is a reveal program. It reveals the map. + +#include +#include +#include +using namespace std; + +#include +#include +#include + +int main (void) +{ + uint32_t x_max,y_max,z_max; + DFHack::designations40d designations; + + DFHack::API DF("Memory.xml"); + try + { + DF.Attach(); + } + catch (exception& e) + { + cerr << e.what() << endl; + #ifndef LINUX_BUILD + cin.ignore(); + #endif + return 1; + } + + DFHack::Maps *Maps =DF.getMaps(); + // init the map + if(!Maps->Start()) + { + cerr << "Can't init map." << endl; + #ifndef LINUX_BUILD + cin.ignore(); + #endif + return 1; + } + DFHack::t_blockflags bflags; + Maps->getSize(x_max,y_max,z_max); + // walk the map, count flowing tiles, magma, water + uint32_t flow1=0, flow2=0, flowboth=0, water=0, magma=0; + cout << "Counting flows and liquids ."; + 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(Maps->isValidBlock(x,y,z)) + { + Maps->ReadBlockFlags(x, y, z, bflags); + Maps->ReadDesignations(x, y, z, &designations); + if (bflags.bits.liquid_1) + flow1++; + if (bflags.bits.liquid_2) + flow2++; + if (bflags.bits.liquid_1 && bflags.bits.liquid_2) + flowboth++; + for (uint32_t i = 0; i < 16;i++) for (uint32_t j = 0; j < 16;j++) + { + if (designations[i][j].bits.liquid_type == DFHack::liquid_magma) + magma++; + if (designations[i][j].bits.liquid_type == DFHack::liquid_water) + water++; + } + // Maps->WriteDesignations(x, y, z, &designations); + // Maps->WriteBlockFlags(x, y, z, bflags); + cout << "."; + } + } + } + } + cout << endl << "Done." << endl; + cout << "Blocks with liquid_1=true: " << flow1 << endl; + cout << "Blocks with liquid_2=true: " << flow2 << endl; + cout << "Blocks with both: " << flowboth << endl; + cout << "Water tiles: " << water << endl; + cout << "Magma tiles: " << magma << endl; + return 0; +} From 722e2e746ef3f28061098d4473408e2fb4aafad3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Tue, 4 May 2010 21:33:40 +0200 Subject: [PATCH 31/36] Add a trace script --- build/build-MinGW32-release-trace.bat | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 build/build-MinGW32-release-trace.bat diff --git a/build/build-MinGW32-release-trace.bat b/build/build-MinGW32-release-trace.bat new file mode 100644 index 000000000..f75da5ff8 --- /dev/null +++ b/build/build-MinGW32-release-trace.bat @@ -0,0 +1,6 @@ +mkdir build-real +cd build-real +cmake ..\.. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE:string=Release --trace > trace-stdout.txt 2> trace-stderr.txt +mingw32-make 2> log.txt +pause +dir file.xxx \ No newline at end of file From 382c8b4261458776213796d3e5901fd41675e069 Mon Sep 17 00:00:00 2001 From: RusAnon Date: Wed, 5 May 2010 11:38:34 +1100 Subject: [PATCH 32/36] Added setuptools bootstrap file --- dfhack/python/ez_setup.py | 284 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 284 insertions(+) create mode 100644 dfhack/python/ez_setup.py diff --git a/dfhack/python/ez_setup.py b/dfhack/python/ez_setup.py new file mode 100644 index 000000000..1ff1d3e7a --- /dev/null +++ b/dfhack/python/ez_setup.py @@ -0,0 +1,284 @@ +#!python +"""Bootstrap setuptools installation + +If you want to use setuptools in your package's setup.py, just include this +file in the same directory with it, and add this to the top of your setup.py:: + + from ez_setup import use_setuptools + use_setuptools() + +If you want to require a specific version of setuptools, set a download +mirror, or use an alternate download directory, you can do so by supplying +the appropriate options to ``use_setuptools()``. + +This file can also be run as a script to install or upgrade setuptools. +""" +import sys +DEFAULT_VERSION = "0.6c11" +DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3] + +md5_data = { + 'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca', + 'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb', + 'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b', + 'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a', + 'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618', + 'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac', + 'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5', + 'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4', + 'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c', + 'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b', + 'setuptools-0.6c10-py2.3.egg': 'ce1e2ab5d3a0256456d9fc13800a7090', + 'setuptools-0.6c10-py2.4.egg': '57d6d9d6e9b80772c59a53a8433a5dd4', + 'setuptools-0.6c10-py2.5.egg': 'de46ac8b1c97c895572e5e8596aeb8c7', + 'setuptools-0.6c10-py2.6.egg': '58ea40aef06da02ce641495523a0b7f5', + 'setuptools-0.6c11-py2.3.egg': '2baeac6e13d414a9d28e7ba5b5a596de', + 'setuptools-0.6c11-py2.4.egg': 'bd639f9b0eac4c42497034dec2ec0c2b', + 'setuptools-0.6c11-py2.5.egg': '64c94f3bf7a72a13ec83e0b24f2749b2', + 'setuptools-0.6c11-py2.6.egg': 'bfa92100bd772d5a213eedd356d64086', + 'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27', + 'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277', + 'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa', + 'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e', + 'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e', + 'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f', + 'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2', + 'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc', + 'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167', + 'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64', + 'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d', + 'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20', + 'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab', + 'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53', + 'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2', + 'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e', + 'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372', + 'setuptools-0.6c8-py2.3.egg': '50759d29b349db8cfd807ba8303f1902', + 'setuptools-0.6c8-py2.4.egg': 'cba38d74f7d483c06e9daa6070cce6de', + 'setuptools-0.6c8-py2.5.egg': '1721747ee329dc150590a58b3e1ac95b', + 'setuptools-0.6c9-py2.3.egg': 'a83c4020414807b496e4cfbe08507c03', + 'setuptools-0.6c9-py2.4.egg': '260a2be2e5388d66bdaee06abec6342a', + 'setuptools-0.6c9-py2.5.egg': 'fe67c3e5a17b12c0e7c541b7ea43a8e6', + 'setuptools-0.6c9-py2.6.egg': 'ca37b1ff16fa2ede6e19383e7b59245a', +} + +import sys, os +try: from hashlib import md5 +except ImportError: from md5 import md5 + +def _validate_md5(egg_name, data): + if egg_name in md5_data: + digest = md5(data).hexdigest() + if digest != md5_data[egg_name]: + print >>sys.stderr, ( + "md5 validation of %s failed! (Possible download problem?)" + % egg_name + ) + sys.exit(2) + return data + +def use_setuptools( + version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, + download_delay=15 +): + """Automatically find/download setuptools and make it available on sys.path + + `version` should be a valid setuptools version number that is available + as an egg for download under the `download_base` URL (which should end with + a '/'). `to_dir` is the directory where setuptools will be downloaded, if + it is not already available. If `download_delay` is specified, it should + be the number of seconds that will be paused before initiating a download, + should one be required. If an older version of setuptools is installed, + this routine will print a message to ``sys.stderr`` and raise SystemExit in + an attempt to abort the calling script. + """ + was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules + def do_download(): + egg = download_setuptools(version, download_base, to_dir, download_delay) + sys.path.insert(0, egg) + import setuptools; setuptools.bootstrap_install_from = egg + try: + import pkg_resources + except ImportError: + return do_download() + try: + pkg_resources.require("setuptools>="+version); return + except pkg_resources.VersionConflict, e: + if was_imported: + print >>sys.stderr, ( + "The required version of setuptools (>=%s) is not available, and\n" + "can't be installed while this script is running. Please install\n" + " a more recent version first, using 'easy_install -U setuptools'." + "\n\n(Currently using %r)" + ) % (version, e.args[0]) + sys.exit(2) + else: + del pkg_resources, sys.modules['pkg_resources'] # reload ok + return do_download() + except pkg_resources.DistributionNotFound: + return do_download() + +def download_setuptools( + version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, + delay = 15 +): + """Download setuptools from a specified location and return its filename + + `version` should be a valid setuptools version number that is available + as an egg for download under the `download_base` URL (which should end + with a '/'). `to_dir` is the directory where the egg will be downloaded. + `delay` is the number of seconds to pause before an actual download attempt. + """ + import urllib2, shutil + egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3]) + url = download_base + egg_name + saveto = os.path.join(to_dir, egg_name) + src = dst = None + if not os.path.exists(saveto): # Avoid repeated downloads + try: + from distutils import log + if delay: + log.warn(""" +--------------------------------------------------------------------------- +This script requires setuptools version %s to run (even to display +help). I will attempt to download it for you (from +%s), but +you may need to enable firewall access for this script first. +I will start the download in %d seconds. + +(Note: if this machine does not have network access, please obtain the file + + %s + +and place it in this directory before rerunning this script.) +---------------------------------------------------------------------------""", + version, download_base, delay, url + ); from time import sleep; sleep(delay) + log.warn("Downloading %s", url) + src = urllib2.urlopen(url) + # Read/write all in one block, so we don't create a corrupt file + # if the download is interrupted. + data = _validate_md5(egg_name, src.read()) + dst = open(saveto,"wb"); dst.write(data) + finally: + if src: src.close() + if dst: dst.close() + return os.path.realpath(saveto) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +def main(argv, version=DEFAULT_VERSION): + """Install or upgrade setuptools and EasyInstall""" + try: + import setuptools + except ImportError: + egg = None + try: + egg = download_setuptools(version, delay=0) + sys.path.insert(0,egg) + from setuptools.command.easy_install import main + return main(list(argv)+[egg]) # we're done here + finally: + if egg and os.path.exists(egg): + os.unlink(egg) + else: + if setuptools.__version__ == '0.0.1': + print >>sys.stderr, ( + "You have an obsolete version of setuptools installed. Please\n" + "remove it from your system entirely before rerunning this script." + ) + sys.exit(2) + + req = "setuptools>="+version + import pkg_resources + try: + pkg_resources.require(req) + except pkg_resources.VersionConflict: + try: + from setuptools.command.easy_install import main + except ImportError: + from easy_install import main + main(list(argv)+[download_setuptools(delay=0)]) + sys.exit(0) # try to force an exit + else: + if argv: + from setuptools.command.easy_install import main + main(argv) + else: + print "Setuptools version",version,"or greater has been installed." + print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)' + +def update_md5(filenames): + """Update our built-in md5 registry""" + + import re + + for name in filenames: + base = os.path.basename(name) + f = open(name,'rb') + md5_data[base] = md5(f.read()).hexdigest() + f.close() + + data = [" %r: %r,\n" % it for it in md5_data.items()] + data.sort() + repl = "".join(data) + + import inspect + srcfile = inspect.getsourcefile(sys.modules[__name__]) + f = open(srcfile, 'rb'); src = f.read(); f.close() + + match = re.search("\nmd5_data = {\n([^}]+)}", src) + if not match: + print >>sys.stderr, "Internal error!" + sys.exit(2) + + src = src[:match.start(1)] + repl + src[match.end(1):] + f = open(srcfile,'w') + f.write(src) + f.close() + + +if __name__=='__main__': + if len(sys.argv)>2 and sys.argv[1]=='--md5update': + update_md5(sys.argv[2:]) + else: + main(sys.argv[1:]) + + + + + + From 8978637786ac10bee41ea67b00fc6c30b9d62fb9 Mon Sep 17 00:00:00 2001 From: RusAnon Date: Wed, 5 May 2010 15:28:10 +1100 Subject: [PATCH 33/36] Moved shell.py and trees.py to tools/ --- dfhack/python/{ => tools}/shell.py | 0 dfhack/python/tools/trees.py | 45 ++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) rename dfhack/python/{ => tools}/shell.py (100%) create mode 100755 dfhack/python/tools/trees.py diff --git a/dfhack/python/shell.py b/dfhack/python/tools/shell.py similarity index 100% rename from dfhack/python/shell.py rename to dfhack/python/tools/shell.py diff --git a/dfhack/python/tools/trees.py b/dfhack/python/tools/trees.py new file mode 100755 index 000000000..4b458fb19 --- /dev/null +++ b/dfhack/python/tools/trees.py @@ -0,0 +1,45 @@ +#!/usr/bin/python +import sys +import pydfhack +from pydfhack.blocks import Point +DF = pydfhack.API("Memory.xml") + +DF.Attach() + +pos = DF.position +maps = DF.maps +cursor = pos.get_cursor() +refc = dict(pydfhack=pydfhack, API=pydfhack.API, DF=DF, pos=pos, maps=maps) +msize = maps.get_size() +print msize +locs = dict(pydfhack=pydfhack, API=pydfhack.API, DF=DF, pos=pos, maps=maps, msize=msize, cursor=cursor) +for z in range(msize[2]): + trees = 0 + saplings = 0 + dead_saplings = 0 + for x in range(msize[0]): + for y in range(msize[1]): + p = Point(x, y, z, True) + block = maps.get_block(point=p) + changed = False + if not block.tiles: + break + for tx in range(16): + for ty in range(16): + tile = block.tiles[tx][ty] + if tile.ttype == 24: + trees += 1 + elif tile.ttype == 231: + saplings += 1 + tile.ttype = 24 + changed = True + elif tile.ttype == 392: + dead_saplings += 1 + tile.ttype = 24 + changed = True + if changed: + block.save() + print "Saved block {0}".format(block) + print "Z-Level {0}: Trees {1}, Saplings {2}, Dead saplings {3}".format(z, trees, saplings, dead_saplings) +DF.Resume() +DF.Detach() From 3d5121dfc91f313fe13a7f9a877ab76b8467f2c2 Mon Sep 17 00:00:00 2001 From: RusAnon Date: Wed, 5 May 2010 15:28:34 +1100 Subject: [PATCH 34/36] Should fix windows compilation --- dfhack/python/setup.py | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/dfhack/python/setup.py b/dfhack/python/setup.py index 352eb1e59..8a5c9297b 100644 --- a/dfhack/python/setup.py +++ b/dfhack/python/setup.py @@ -7,21 +7,37 @@ except ImportError: from setuptools import setup, find_packages from distutils.core import Extension from os import path +import platform + +if platform.system() == 'Windows': + # dfhack.lib location can differ, search for it + for libdir in ["..", path.join("..",".."), path.join("..", "..", "output"), path.join("..", "..", "output", "Release")]: + if path.isfile(path.join(libdir, "dfhack.lib")): + lib_dirs = libdir + break + else: + raise Exception("dfhack.lib is not found") + osspec = dict(library_dirs=lib_dirs) + +elif platform.system() == 'Linux': + osspec = dict(extra_compile_args=["-DLINUX_BUILD", "-w"], + library_dirs=[path.join("..","..","output")]) e = Extension("pydfhack._pydfhack", - 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=["../", path.join("..", "include"), path.join("..","depends","md5"), path.join("..","depends","tinyxml")], - library_dirs=[path.join("..","..","output")], - extra_compile_args=["-DLINUX_BUILD", "-w"], - libraries=["dfhack"], - export_symbols=["init_pydfhack", "ReadRaw", "WriteRaw"]) + 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=["../", path.join("..", "include"), path.join("..","depends","md5"), path.join("..","depends","tinyxml")], + libraries=["dfhack"], + export_symbols=["init_pydfhack", "ReadRaw", "WriteRaw"], + **osspec) for file in ["Memory.xml", path.join("..","..","output","Memory.xml")]: if path.isfile(file): datafile = file break else: - raise Exception("Memory.xml not found.") + raise Exception("Memory.xml is not found.") setup( From 1da629fc5c2239046985e244fa3522a599db2014 Mon Sep 17 00:00:00 2001 From: RusAnon Date: Wed, 5 May 2010 15:34:54 +1100 Subject: [PATCH 35/36] Fix for libpath bug --- dfhack/python/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dfhack/python/setup.py b/dfhack/python/setup.py index 8a5c9297b..bd570e913 100644 --- a/dfhack/python/setup.py +++ b/dfhack/python/setup.py @@ -17,7 +17,7 @@ if platform.system() == 'Windows': break else: raise Exception("dfhack.lib is not found") - osspec = dict(library_dirs=lib_dirs) + osspec = dict(library_dirs=[lib_dirs]) elif platform.system() == 'Linux': osspec = dict(extra_compile_args=["-DLINUX_BUILD", "-w"], From 735b49e77606b8d69ab5a4b12f0cf0b2ccd30857 Mon Sep 17 00:00:00 2001 From: RusAnon Date: Wed, 5 May 2010 20:33:44 +1100 Subject: [PATCH 36/36] Some changes for mingw --- dfhack/python/setup.py | 12 +++++++++--- output/stones.py | 4 ++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/dfhack/python/setup.py b/dfhack/python/setup.py index bd570e913..fe36c0fdd 100644 --- a/dfhack/python/setup.py +++ b/dfhack/python/setup.py @@ -14,21 +14,27 @@ if platform.system() == 'Windows': for libdir in ["..", path.join("..",".."), path.join("..", "..", "output"), path.join("..", "..", "output", "Release")]: if path.isfile(path.join(libdir, "dfhack.lib")): lib_dirs = libdir + libraries=["dfhack"] + break + if path.isfile(path.join(libdir, "libdfhack.dll")): + lib_dirs = libdir + libraries = ["libdfhack"] break else: raise Exception("dfhack.lib is not found") - osspec = dict(library_dirs=[lib_dirs]) + osspec = dict(library_dirs=[lib_dirs], + libraries=libraries) elif platform.system() == 'Linux': osspec = dict(extra_compile_args=["-DLINUX_BUILD", "-w"], - library_dirs=[path.join("..","..","output")]) + library_dirs=[path.join("..","..","output")], + libraries=["dfhack"]) e = Extension("pydfhack._pydfhack", 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=["../", path.join("..", "include"), path.join("..","depends","md5"), path.join("..","depends","tinyxml")], - libraries=["dfhack"], export_symbols=["init_pydfhack", "ReadRaw", "WriteRaw"], **osspec) diff --git a/output/stones.py b/output/stones.py index 4db1b3361..2cc7a2d7f 100644 --- a/output/stones.py +++ b/output/stones.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -import pydfhack -DF = pydfhack._API("Memory.xml") +from pydfhack import API +DF = API("Memory.xml") if DF.Attach(): Mats = DF.materials