diff --git a/build/generate-MSVC-all.bat b/build/generate-MSVC-all.bat old mode 100644 new mode 100755 index 686ec3bcf..b16f9dce1 --- a/build/generate-MSVC-all.bat +++ b/build/generate-MSVC-all.bat @@ -3,4 +3,4 @@ IF NOT EXIST DF_PATH.txt SET _DF_PATH=%CD%\DF mkdir VC2010 cd VC2010 echo generating a build folder -cmake ..\.. -G"Visual Studio 10" -DCMAKE_INSTALL_PREFIX=%_DF_PATH% -DBUILD_DEVEL=1 -DBUILD_DEV_PLUGINS=1 -DBUILD_DF2MC=1 -DBUILD_DFUSION=1 -DBUILD_STONESENSE=1 -DBUILD_SERVER=1 +cmake ..\.. -G"Visual Studio 10" -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=1 -DBUILD_DEV_PLUGINS=1 -DBUILD_DF2MC=1 -DBUILD_DFUSION=1 -DBUILD_STONESENSE=1 -DBUILD_SERVER=1 diff --git a/build/generate-MSVC-gui.bat b/build/generate-MSVC-gui.bat old mode 100644 new mode 100755 index f86a3894d..98f1acddb --- a/build/generate-MSVC-gui.bat +++ b/build/generate-MSVC-gui.bat @@ -3,5 +3,5 @@ IF NOT EXIST DF_PATH.txt SET _DF_PATH=%CD%\DF mkdir VC2010 cd VC2010 echo Pre-generating a build folder -cmake ..\.. -G"Visual Studio 10" -DCMAKE_INSTALL_PREFIX=%_DF_PATH% -cmake-gui . \ No newline at end of file +cmake ..\.. -G"Visual Studio 10" -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" +cmake-gui . diff --git a/build/generate-MSVC-minimal.bat b/build/generate-MSVC-minimal.bat old mode 100644 new mode 100755 index d1b96a282..19ca75c5f --- a/build/generate-MSVC-minimal.bat +++ b/build/generate-MSVC-minimal.bat @@ -3,4 +3,4 @@ IF NOT EXIST DF_PATH.txt SET _DF_PATH=%CD%\DF mkdir VC2010 cd VC2010 echo generating a build folder -cmake ..\.. -G"Visual Studio 10" -DCMAKE_INSTALL_PREFIX=%_DF_PATH% -DBUILD_DEVEL=0 -DBUILD_DEV_PLUGINS=0 -DBUILD_DF2MC=0 -DBUILD_DFUSION=0 -DBUILD_STONESENSE=0 -DBUILD_SERVER=0 +cmake ..\.. -G"Visual Studio 10" -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=0 -DBUILD_DEV_PLUGINS=0 -DBUILD_DF2MC=0 -DBUILD_DFUSION=0 -DBUILD_STONESENSE=0 -DBUILD_SERVER=0 diff --git a/depends/lua/include/luaconf.h b/depends/lua/include/luaconf.h index 25f08c0c4..ffa33a0de 100644 --- a/depends/lua/include/luaconf.h +++ b/depends/lua/include/luaconf.h @@ -152,7 +152,7 @@ ** LUA_BUILD_AS_DLL to get it). */ #ifdef __cplusplus - #define LUA_API_EXTERN extern "C" + #define LUA_API_EXTERN extern #else #define LUA_API_EXTERN extern #endif diff --git a/library/DataDefs.cpp b/library/DataDefs.cpp index 712d4563f..755477d47 100644 --- a/library/DataDefs.cpp +++ b/library/DataDefs.cpp @@ -51,6 +51,11 @@ void type_identity::do_copy_pod(void *tgt, const void *src) { memmove(tgt, src, size); }; +bool type_identity::do_destroy_pod(void *obj) { + free(obj); + return true; +} + void *type_identity::allocate() { if (can_allocate()) return do_allocate(); @@ -65,6 +70,13 @@ bool type_identity::copy(void *tgt, const void *src) { return false; } +bool type_identity::destroy(void *obj) { + if (can_allocate() && obj) + return do_destroy(obj); + else + return false; +} + void *enum_identity::do_allocate() { void *p = malloc(byte_size()); memcpy(p, &first_item_value, std::min(byte_size(), sizeof(int64_t))); @@ -137,10 +149,11 @@ enum_identity::enum_identity(size_t size, compound_identity *scope_parent, const char *dfhack_name, type_identity *base_type, int64_t first_item_value, int64_t last_item_value, - const char *const *keys) + const char *const *keys, + const void *attrs, struct_identity *attr_type) : compound_identity(size, NULL, scope_parent, dfhack_name), first_item_value(first_item_value), last_item_value(last_item_value), - keys(keys), base_type(base_type) + keys(keys), base_type(base_type), attrs(attrs), attr_type(attr_type) { } diff --git a/library/DataStaticsFields.cpp b/library/DataStaticsFields.cpp index 89736369f..29816bbc5 100644 --- a/library/DataStaticsFields.cpp +++ b/library/DataStaticsFields.cpp @@ -8,6 +8,7 @@ #include "df/ui.h" #include "DataIdentity.h" +#include "DataFuncs.h" #include @@ -30,6 +31,8 @@ namespace df { bool_identity identity_traits::identity; stl_string_identity identity_traits::identity; + ptr_string_identity identity_traits::identity; + ptr_string_identity identity_traits::identity; pointer_identity identity_traits::identity; stl_ptr_vector_identity identity_traits >::identity; stl_bit_vector_identity identity_traits >::identity; @@ -43,6 +46,7 @@ namespace df { #define FLD(mode, name) struct_field_info::mode, #name, offsetof(CUR_STRUCT, name) #define GFLD(mode, name) struct_field_info::mode, #name, (size_t)&df::global::name +#define METHOD(mode, name) struct_field_info::mode, #name, 0, wrap_function(&CUR_STRUCT::name) #define FLD_END struct_field_info::END // Field definitions diff --git a/library/LuaTypes.cpp b/library/LuaTypes.cpp index 25cdfa354..536bcd72a 100644 --- a/library/LuaTypes.cpp +++ b/library/LuaTypes.cpp @@ -36,6 +36,7 @@ distribution. #include "DataDefs.h" #include "DataIdentity.h" #include "LuaWrapper.h" +#include "DataFuncs.h" #include "MiscUtils.h" @@ -49,6 +50,16 @@ using namespace DFHack::LuaWrapper; * Identity object read/write methods * **************************************/ +void function_identity_base::lua_read(lua_State *state, int fname_idx, void *ptr) +{ + field_error(state, fname_idx, "executable code", "read"); +} + +void function_identity_base::lua_write(lua_State *state, int fname_idx, void *ptr, int val_index) +{ + field_error(state, fname_idx, "executable code", "write"); +} + void constructed_identity::lua_read(lua_State *state, int fname_idx, void *ptr) { push_object_internal(state, this, ptr); @@ -99,6 +110,20 @@ void df::bool_identity::lua_write(lua_State *state, int fname_idx, void *ptr, in field_error(state, fname_idx, "boolean or number expected", "write"); } +void df::ptr_string_identity::lua_read(lua_State *state, int fname_idx, void *ptr) +{ + auto pstr = (char**)ptr; + if (*pstr) + lua_pushstring(state, *pstr); + else + lua_pushnil(state); +} + +void df::ptr_string_identity::lua_write(lua_State *state, int fname_idx, void *ptr, int val_index) +{ + field_error(state, fname_idx, "raw pointer string", "write"); +} + void df::stl_string_identity::lua_read(lua_State *state, int fname_idx, void *ptr) { auto pstr = (std::string*)ptr; @@ -264,12 +289,31 @@ static void lookup_field(lua_State *state, int index, const char *mode) field_error(state, index, "not found", mode); } +// Resolve the field in the metatable and return +static int get_metafield(lua_State *state) +{ + lua_rawget(state, UPVAL_METATABLE); + return 1; +} + static void *find_field(lua_State *state, int index, const char *mode) { lookup_field(state, index, mode); + // Methods + if (lua_isfunction(state, -1)) + return NULL; + + // Otherwise must be a pointer + if (!lua_isuserdata(state, -1)) + field_error(state, index, "corrupted field table", mode); + void *p = lua_touserdata(state, -1); lua_pop(state, 1); + + // NULL => metafield + if (!p) + get_metafield(state); return p; } @@ -295,6 +339,10 @@ static void read_field(lua_State *state, const struct_field_info *field, void *p return; } + case struct_field_info::OBJ_METHOD: + case struct_field_info::CLASS_METHOD: + // error + case struct_field_info::PRIMITIVE: case struct_field_info::SUBSTRUCT: field->type->lua_read(state, 2, ptr); @@ -339,6 +387,10 @@ static void field_reference(lua_State *state, const struct_field_info *field, vo push_adhoc_pointer(state, ptr, field->type); return; + case struct_field_info::OBJ_METHOD: + case struct_field_info::CLASS_METHOD: + // error + case struct_field_info::CONTAINER: read_field(state, field, ptr); return; @@ -371,6 +423,10 @@ static void write_field(lua_State *state, const struct_field_info *field, void * return; } + case struct_field_info::OBJ_METHOD: + case struct_field_info::CLASS_METHOD: + // error + case struct_field_info::PRIMITIVE: case struct_field_info::SUBSTRUCT: case struct_field_info::CONTAINER: @@ -418,13 +474,6 @@ static int meta_ptr_tostring(lua_State *state) return 1; } -// Resolve the field in the metatable and return -static int get_metafield(lua_State *state) -{ - lua_rawget(state, UPVAL_METATABLE); - return 1; -} - /** * Metamethod: __index for structures. */ @@ -433,7 +482,7 @@ static int meta_struct_index(lua_State *state) uint8_t *ptr = get_object_addr(state, 1, 2, "read"); auto field = (struct_field_info*)find_field(state, 2, "read"); if (!field) - return get_metafield(state); + return 1; read_field(state, field, ptr + field->offset); return 1; } @@ -448,7 +497,7 @@ static int meta_struct_field_reference(lua_State *state) uint8_t *ptr = get_object_addr(state, 1, 2, "reference"); auto field = (struct_field_info*)find_field(state, 2, "reference"); if (!field) - field_error(state, 2, "builtin property", "reference"); + field_error(state, 2, "builtin property or method", "reference"); field_reference(state, field, ptr + field->offset); return 1; } @@ -461,7 +510,7 @@ static int meta_struct_newindex(lua_State *state) uint8_t *ptr = get_object_addr(state, 1, 2, "write"); auto field = (struct_field_info*)find_field(state, 2, "write"); if (!field) - field_error(state, 2, "builtin property", "write"); + field_error(state, 2, "builtin property or method", "write"); write_field(state, field, ptr + field->offset, 3); return 0; } @@ -475,7 +524,7 @@ static int meta_primitive_index(lua_State *state) uint8_t *ptr = get_object_addr(state, 1, 2, "read"); auto type = (type_identity*)find_field(state, 2, "read"); if (!type) - return get_metafield(state); + return 1; type->lua_read(state, 2, ptr); return 1; } @@ -488,7 +537,7 @@ static int meta_primitive_newindex(lua_State *state) uint8_t *ptr = get_object_addr(state, 1, 2, "write"); auto type = (type_identity*)find_field(state, 2, "write"); if (!type) - field_error(state, 2, "builtin property", "write"); + field_error(state, 2, "builtin property or method", "write"); type->lua_write(state, 2, ptr, 3); return 0; } @@ -521,7 +570,7 @@ static int lookup_container_field(lua_State *state, int field, const char *mode if (lua_isuserdata(state, -1) && !lua_touserdata(state, -1)) { if (mode) - field_error(state, field, "builtin property", mode); + field_error(state, field, "builtin property or method", mode); lua_pop(state, 1); get_metafield(state); @@ -727,7 +776,7 @@ static int meta_global_index(lua_State *state) { auto field = (struct_field_info*)find_field(state, 2, "read"); if (!field) - return get_metafield(state); + return 1; void *ptr = *(void**)field->offset; if (!ptr) field_error(state, 2, "global address not known", "read"); @@ -742,7 +791,7 @@ static int meta_global_newindex(lua_State *state) { auto field = (struct_field_info*)find_field(state, 2, "write"); if (!field) - field_error(state, 2, "builtin property", "write"); + field_error(state, 2, "builtin property or method", "write"); void *ptr = *(void**)field->offset; if (!ptr) field_error(state, 2, "global address not known", "write"); @@ -750,27 +799,92 @@ static int meta_global_newindex(lua_State *state) return 0; } +/** + * Wrapper for c++ methods and functions. + */ +static int meta_call_function(lua_State *state) +{ + auto id = (function_identity_base*)lua_touserdata(state, UPVAL_CONTAINER_ID); + if (lua_gettop(state) != id->getNumArgs()) + field_error(state, UPVAL_METHOD_NAME, "invalid argument count", "invoke"); + id->invoke(state, 1); + return 1; +} + +/** + * Create a closure invoking the given function, and add it to the field table. + */ +static void AddMethodWrapper(lua_State *state, int meta_idx, int field_idx, + const char *name, function_identity_base *fun) +{ + lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_TYPETABLE_NAME); + lua_pushvalue(state, meta_idx); + lua_pushfstring(state, "%s()", name); + lua_pushlightuserdata(state, fun); + lua_pushcclosure(state, meta_call_function, 4); + + lua_setfield(state, field_idx, name); +} + /** * Add fields in the array to the UPVAL_FIELDTABLE candidates on the stack. */ static void IndexFields(lua_State *state, struct_identity *pstruct) { - // stack: fieldtable + // stack: metatable fieldtable - int base = lua_gettop(state); + int base = lua_gettop(state) - 2; + + for (struct_identity *p = pstruct; p; p = p->getParent()) + { + auto fields = p->getFields(); + if (!fields) + continue; + + for (int i = 0; fields[i].mode != struct_field_info::END; ++i) + { + switch (fields[i].mode) + { + case struct_field_info::OBJ_METHOD: + AddMethodWrapper(state, base+1, base+2, fields[i].name, + (function_identity_base*)fields[i].type); + break; + + case struct_field_info::CLASS_METHOD: + break; + + default: + lua_pushstring(state,fields[i].name); + lua_pushlightuserdata(state,(void*)&fields[i]); + lua_rawset(state,base+2); + break; + } + } + } +} + +void LuaWrapper::IndexStatics(lua_State *state, int meta_idx, int ftable_idx, struct_identity *pstruct) +{ + // stack: metatable fieldtable for (struct_identity *p = pstruct; p; p = p->getParent()) { auto fields = p->getFields(); + if (!fields) + continue; - for (; fields; ++fields) + for (int i = 0; fields[i].mode != struct_field_info::END; ++i) { - if (fields->mode == struct_field_info::END) + switch (fields[i].mode) + { + case struct_field_info::CLASS_METHOD: + AddMethodWrapper(state, meta_idx, ftable_idx, fields[i].name, + (function_identity_base*)fields[i].type); break; - lua_pushstring(state,fields->name); - lua_pushlightuserdata(state,(void*)fields); - lua_rawset(state,base); + default: + break; + } } } } diff --git a/library/LuaWrapper.cpp b/library/LuaWrapper.cpp index 7a871e4be..4758f04f1 100644 --- a/library/LuaWrapper.cpp +++ b/library/LuaWrapper.cpp @@ -593,10 +593,7 @@ static int meta_new(lua_State *state) void *ptr = id->allocate(); if (!ptr) - { - lua_pushnil(state); - return 1; - } + luaL_error(state, "Cannot allocate %s", id->getFullName().c_str()); if (lua_isuserdata(state, 1)) { @@ -630,6 +627,30 @@ static int meta_assign(lua_State *state) return 0; } +/** + * Method: deallocation for DF object references. + */ +static int meta_delete(lua_State *state) +{ + int argc = lua_gettop(state); + + if (argc != 1) + luaL_error(state, "Usage: object:delete() or df.delete(object)"); + + if (lua_isnil(state, 1)) + { + lua_pushboolean(state, true); + return 1; + } + + type_identity *id = get_object_identity(state, 1, "df.delete()", false); + + bool ok = id->destroy(get_object_ref(state, 1)); + + lua_pushboolean(state, ok); + return 1; +} + /** * Verify that the object is a DF ref with UPVAL_METATABLE. * If everything ok, extract the address. @@ -677,6 +698,30 @@ static int meta_ptr_tostring(lua_State *state) return 1; } +/** + * Metamethod: __index for enum.attrs + */ +static int meta_enum_attr_index(lua_State *state) +{ + if (!lua_isnumber(state, 2)) + lua_rawget(state, UPVAL_FIELDTABLE); + if (!lua_isnumber(state, 2)) + luaL_error(state, "Invalid index in enum.attrs[]"); + + auto id = (enum_identity*)lua_touserdata(state, lua_upvalueindex(2)); + + int64_t idx = lua_tonumber(state, 2); + if (idx < id->getFirstItem() || idx > id->getLastItem()) + idx = id->getLastItem()+1; + idx -= id->getFirstItem(); + + uint8_t *ptr = (uint8_t*)id->getAttrs(); + auto atype = id->getAttrType(); + + push_object_internal(state, atype, ptr + unsigned(atype->byte_size()*idx)); + return 1; +} + /** * Make a metatable with most common fields, and an empty table for UPVAL_FIELDTABLE. */ @@ -741,6 +786,10 @@ void LuaWrapper::SetPtrMethods(lua_State *state, int meta_idx, int read_idx) lua_setfield(state, meta_idx, "new"); EnableMetaField(state, read_idx, "new"); + lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_DELETE_NAME); + lua_setfield(state, meta_idx, "delete"); + EnableMetaField(state, read_idx, "delete"); + lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_ASSIGN_NAME); lua_setfield(state, meta_idx, "assign"); EnableMetaField(state, read_idx, "assign"); @@ -835,82 +884,152 @@ static void AssociateId(lua_State *state, int table, int val, const char *name) lua_rawset(state, table); } +static void FillEnumKeys(lua_State *state, int ftable, enum_identity *eid) +{ + const char *const *keys = eid->getKeys(); + + // Create a new table attached to ftable as __index + lua_newtable(state); + + lua_dup(state); + lua_setmetatable(state, ftable); + + int base = lua_gettop(state); + + lua_newtable(state); + + // For enums, set mapping between keys and values + for (int64_t i = eid->getFirstItem(), j = 0; i <= eid->getLastItem(); i++, j++) + { + if (keys[j]) + AssociateId(state, base+1, i, keys[j]); + } + + if (eid->getFirstItem() <= eid->getLastItem()) + { + lua_pushinteger(state, eid->getFirstItem()); + lua_setfield(state, base+1, "_first_item"); + + lua_pushinteger(state, eid->getLastItem()); + lua_setfield(state, base+1, "_last_item"); + } + + SaveInTable(state, eid, DFHACK_ENUM_TABLE_NAME); + + // Add an attribute table if any + if (eid->getAttrs()) + { + lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_TYPETABLE_NAME); + lua_pushlightuserdata(state, eid); + lua_pushvalue(state, base+1); + lua_pushcclosure(state, meta_enum_attr_index, 3); + + freeze_table(state, false, (eid->getFullName()+".attrs").c_str()); + lua_setfield(state, ftable, "attrs"); + } + + lua_setfield(state, base, "__index"); + lua_pop(state, 1); +} + +static void FillBitfieldKeys(lua_State *state, int ftable, bitfield_identity *eid) +{ + auto bits = eid->getBits(); + + for (int i = 0; i < eid->getNumBits(); i++) + { + if (bits[i].name) + AssociateId(state, ftable, i, bits[i].name); + if (bits[i].size > 1) + i += bits[i].size-1; + } + + lua_pushinteger(state, 0); + lua_setfield(state, ftable, "_first_item"); + + lua_pushinteger(state, eid->getNumBits()-1); + lua_setfield(state, ftable, "_last_item"); + + SaveInTable(state, eid, DFHACK_ENUM_TABLE_NAME); +} + static void RenderType(lua_State *state, compound_identity *node) { assert(node->getName()); std::string name = node->getFullName(); + int base = lua_gettop(state); + lua_newtable(state); if (!lua_checkstack(state, 20)) return; - int base = lua_gettop(state); + SaveInTable(state, node, DFHACK_TYPEID_TABLE_NAME); + + // metatable + lua_newtable(state); + + lua_dup(state); + lua_setmetatable(state, base+1); + + lua_pushstring(state, name.c_str()); + lua_setfield(state, base+2, "__metatable"); + + lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_TYPE_TOSTRING_NAME); + lua_setfield(state, base+2, "__tostring"); + + lua_pushlightuserdata(state, node); + lua_setfield(state, base+2, "_identity"); + + // inner table + lua_newtable(state); + + lua_dup(state); + lua_setfield(state, base+2, "__index"); + + int ftable = base+3; switch (node->type()) { case IDTYPE_STRUCT: lua_pushstring(state, "struct-type"); - lua_setfield(state, base, "_kind"); + lua_setfield(state, ftable, "_kind"); + IndexStatics(state, base+2, base+3, (struct_identity*)node); break; case IDTYPE_CLASS: lua_pushstring(state, "class-type"); - lua_setfield(state, base, "_kind"); + lua_setfield(state, ftable, "_kind"); + IndexStatics(state, base+2, base+3, (struct_identity*)node); break; case IDTYPE_ENUM: - { - lua_pushstring(state, "enum-type"); - lua_setfield(state, base, "_kind"); - - enum_identity *eid = (enum_identity*)node; - const char *const *keys = eid->getKeys(); - - // For enums, set mapping between keys and values - for (int64_t i = eid->getFirstItem(), j = 0; i <= eid->getLastItem(); i++, j++) - { - if (keys[j]) - AssociateId(state, base, i, keys[j]); - } - - if (eid->getFirstItem() <= eid->getLastItem()) - { - lua_pushinteger(state, eid->getFirstItem()); - lua_setfield(state, base, "_first_item"); - - lua_pushinteger(state, eid->getLastItem()); - lua_setfield(state, base, "_last_item"); - } - - SaveInTable(state, node, DFHACK_ENUM_TABLE_NAME); - } + lua_pushstring(state, "enum-type"); + lua_setfield(state, ftable, "_kind"); + FillEnumKeys(state, ftable, (enum_identity*)node); break; case IDTYPE_BITFIELD: - { - lua_pushstring(state, "bitfield-type"); - lua_setfield(state, base, "_kind"); + lua_pushstring(state, "bitfield-type"); + lua_setfield(state, ftable, "_kind"); + FillBitfieldKeys(state, ftable, (bitfield_identity*)node); + break; - bitfield_identity *eid = (bitfield_identity*)node; - auto bits = eid->getBits(); + case IDTYPE_GLOBAL: + { + RenderTypeChildren(state, node->getScopeChildren()); - for (int i = 0; i < eid->getNumBits(); i++) - { - if (bits[i].name) - AssociateId(state, base, i, bits[i].name); - if (bits[i].size > 1) - i += bits[i].size-1; - } + BuildTypeMetatable(state, node); - lua_pushinteger(state, 0); - lua_setfield(state, base, "_first_item"); + lua_dup(state); + lua_setmetatable(state, base+3); - lua_pushinteger(state, eid->getNumBits()-1); - lua_setfield(state, base, "_last_item"); + lua_getfield(state, -1, "__newindex"); + lua_setfield(state, base+2, "__newindex"); - SaveInTable(state, node, DFHACK_ENUM_TABLE_NAME); + lua_pop(state, 3); + return; } - break; default: break; @@ -918,44 +1037,13 @@ static void RenderType(lua_State *state, compound_identity *node) RenderTypeChildren(state, node->getScopeChildren()); - assert(base == lua_gettop(state)); - lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_SIZEOF_NAME); - lua_setfield(state, base, "sizeof"); - lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_NEW_NAME); - lua_setfield(state, base, "new"); - - if (node->type() == IDTYPE_GLOBAL) - { - BuildTypeMetatable(state, node); - - // Set metatable for the inner table - lua_dup(state); - lua_setmetatable(state, base); - lua_swap(state); // -> meta curtable + lua_setfield(state, ftable, "sizeof"); - freeze_table(state, true, "global"); - - // Copy __newindex to the outer metatable - lua_getfield(state, base, "__newindex"); - lua_setfield(state, -2, "__newindex"); - - lua_remove(state, base); - } - else - { - freeze_table(state, true, name.c_str()); - } - - lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_TYPE_TOSTRING_NAME); - lua_setfield(state, -2, "__tostring"); - - lua_pushlightuserdata(state, node); - lua_setfield(state, -2, "_identity"); - - lua_pop(state, 1); + lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_NEW_NAME); + lua_setfield(state, ftable, "new"); - SaveInTable(state, node, DFHACK_TYPEID_TABLE_NAME); + lua_pop(state, 2); } static void RenderTypeChildren(lua_State *state, const std::vector &children) @@ -1007,6 +1095,10 @@ static void DoAttach(lua_State *state) lua_pushcclosure(state, meta_assign, 1); lua_setfield(state, LUA_REGISTRYINDEX, DFHACK_ASSIGN_NAME); + lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_TYPETABLE_NAME); + lua_pushcclosure(state, meta_delete, 1); + lua_setfield(state, LUA_REGISTRYINDEX, DFHACK_DELETE_NAME); + luaL_register(state, "df", no_functions); { @@ -1020,6 +1112,8 @@ static void DoAttach(lua_State *state) lua_setfield(state, -2, "sizeof"); lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_NEW_NAME); lua_setfield(state, -2, "new"); + lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_DELETE_NAME); + lua_setfield(state, -2, "delete"); lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_DISPLACE_NAME); lua_setfield(state, -2, "_displace"); lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_ASSIGN_NAME); diff --git a/library/include/DataDefs.h b/library/include/DataDefs.h index 48b79721b..b2c86ec11 100644 --- a/library/include/DataDefs.h +++ b/library/include/DataDefs.h @@ -49,6 +49,7 @@ namespace DFHack enum identity_type { IDTYPE_GLOBAL, + IDTYPE_FUNCTION, IDTYPE_PRIMITIVE, IDTYPE_POINTER, IDTYPE_CONTAINER, @@ -72,10 +73,12 @@ namespace DFHack void *do_allocate_pod(); void do_copy_pod(void *tgt, const void *src); + bool do_destroy_pod(void *obj); virtual bool can_allocate() { return true; } virtual void *do_allocate() { return do_allocate_pod(); } virtual void do_copy(void *tgt, const void *src) { do_copy_pod(tgt, src); } + virtual bool do_destroy(void *obj) { return do_destroy_pod(obj); } public: virtual ~type_identity() {} @@ -100,6 +103,7 @@ namespace DFHack void *allocate(); bool copy(void *tgt, const void *src); + bool destroy(void *obj); }; class DFHACK_EXPORT constructed_identity : public type_identity { @@ -109,12 +113,13 @@ namespace DFHack constructed_identity(size_t size, TAllocateFn alloc) : type_identity(size), allocator(alloc) {}; - virtual bool isPrimitive() { return false; } - virtual bool isConstructed() { return true; } - virtual bool can_allocate() { return (allocator != NULL); } virtual void *do_allocate() { return allocator(NULL,NULL); } virtual void do_copy(void *tgt, const void *src) { allocator(tgt,src); } + virtual bool do_destroy(void *obj) { return allocator(NULL,obj) == obj; } + public: + virtual bool isPrimitive() { return false; } + virtual bool isConstructed() { return true; } virtual void lua_read(lua_State *state, int fname_idx, void *ptr); virtual void lua_write(lua_State *state, int fname_idx, void *ptr, int val_index); @@ -161,6 +166,7 @@ namespace DFHack virtual bool can_allocate() { return true; } virtual void *do_allocate() { return do_allocate_pod(); } virtual void do_copy(void *tgt, const void *src) { do_copy_pod(tgt, src); } + virtual bool do_destroy(void *obj) { return do_destroy_pod(obj); } public: bitfield_identity(size_t size, @@ -177,6 +183,8 @@ namespace DFHack virtual void build_metatable(lua_State *state); }; + class struct_identity; + class DFHACK_EXPORT enum_identity : public compound_identity { const char *const *keys; int64_t first_item_value; @@ -184,17 +192,22 @@ namespace DFHack type_identity *base_type; + const void *attrs; + struct_identity *attr_type; + protected: virtual bool can_allocate() { return true; } virtual void *do_allocate(); virtual void do_copy(void *tgt, const void *src) { do_copy_pod(tgt, src); } + virtual bool do_destroy(void *obj) { return do_destroy_pod(obj); } public: enum_identity(size_t size, compound_identity *scope_parent, const char *dfhack_name, type_identity *base_type, int64_t first_item_value, int64_t last_item_value, - const char *const *keys); + const char *const *keys, + const void *attrs, struct_identity *attr_type); virtual identity_type type() { return IDTYPE_ENUM; } @@ -204,6 +217,8 @@ namespace DFHack const char *const *getKeys() { return keys; } type_identity *getBaseType() { return base_type; } + const void *getAttrs() { return attrs; } + struct_identity *getAttrType() { return attr_type; } virtual bool isPrimitive() { return true; } virtual bool isConstructed() { return false; } @@ -221,7 +236,9 @@ namespace DFHack STATIC_ARRAY, SUBSTRUCT, CONTAINER, - STL_VECTOR_PTR + STL_VECTOR_PTR, + OBJ_METHOD, + CLASS_METHOD }; Mode mode; const char *name; @@ -409,6 +426,14 @@ namespace df template void *allocator_fn(void *out, const void *in) { if (out) { *(T*)out = *(const T*)in; return out; } + else if (in) { delete (T*)in; return (T*)in; } + else return new T(); + } + + template + void *allocator_nodel_fn(void *out, const void *in) { + if (out) { *(T*)out = *(const T*)in; return out; } + else if (in) { return NULL; } else return new T(); } diff --git a/library/include/DataFuncs.h b/library/include/DataFuncs.h new file mode 100644 index 000000000..a3769af55 --- /dev/null +++ b/library/include/DataFuncs.h @@ -0,0 +1,129 @@ +/* +https://github.com/peterix/dfhack +Copyright (c) 2009-2011 Petr Mrázek (peterix@gmail.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#pragma once + +#include +#include +#include +#include + +#include "DataIdentity.h" +#include "LuaWrapper.h" + +namespace df { + template struct function_wrapper {}; + + /* + * Since templates can't match variable arg count, + * a separate specialization is needed for every + * supported count value... + * + * The FW_TARGS ugliness is needed because of + * commas not wrapped in () + */ + +#define INVOKE_VOID(call) \ + call; lua_pushnil(state); +#define INVOKE_RV(call) \ + RT rv = call; df::identity_traits::get()->lua_read(state, UPVAL_METHOD_NAME, &rv); +#define LOAD_CLASS() \ + CT *self = (CT*)DFHack::LuaWrapper::get_object_addr(state, base++, UPVAL_METHOD_NAME, "invoke"); +#define LOAD_ARG(type) \ + type v##type; df::identity_traits::get()->lua_write(state, UPVAL_METHOD_NAME, &v##type, base++); + +#define INSTANTIATE_WRAPPERS(Count, FArgs, Args, Loads) \ + template struct function_wrapper { \ + static const bool is_method = false; \ + static const int num_args = Count; \ + static void execute(lua_State *state, int base, void (*cb) FArgs) { Loads; INVOKE_VOID(cb Args); } \ + }; \ + template struct function_wrapper { \ + static const bool is_method = false; \ + static const int num_args = Count; \ + static void execute(lua_State *state, int base, RT (*cb) FArgs) { Loads; INVOKE_RV(cb Args); } \ + }; \ + template struct function_wrapper { \ + static const bool is_method = true; \ + static const int num_args = Count+1; \ + static void execute(lua_State *state, int base, void (CT::*cb) FArgs) { \ + LOAD_CLASS() Loads; INVOKE_VOID((self->*cb) Args); } \ + }; \ + template struct function_wrapper { \ + static const bool is_method = true; \ + static const int num_args = Count+1; \ + static void execute(lua_State *state, int base, RT (CT::*cb) FArgs) { \ + LOAD_CLASS(); Loads; INVOKE_RV((self->*cb) Args); } \ + }; + +#define FW_TARGSC +#define FW_TARGS +INSTANTIATE_WRAPPERS(0, (), (), ;) +#undef FW_TARGS + +#undef FW_TARGSC +#define FW_TARGSC FW_TARGS, +#define FW_TARGS class A1 +INSTANTIATE_WRAPPERS(1, (A1), (vA1), LOAD_ARG(A1);) +#undef FW_TARGS + +#define FW_TARGS class A1, class A2 +INSTANTIATE_WRAPPERS(2, (A1,A2), (vA1,vA2), LOAD_ARG(A1); LOAD_ARG(A2);) +#undef FW_TARGS + +#define FW_TARGS class A1, class A2, class A3 +INSTANTIATE_WRAPPERS(3, (A1,A2,A3), (vA1,vA2,vA3), LOAD_ARG(A1); LOAD_ARG(A2); LOAD_ARG(A3);) +#undef FW_TARGS + +#define FW_TARGS class A1, class A2, class A3, class A4 +INSTANTIATE_WRAPPERS(4, (A1,A2,A3,A4), (vA1,vA2,vA3,vA4), + LOAD_ARG(A1); LOAD_ARG(A2); LOAD_ARG(A3); LOAD_ARG(A4);) +#undef FW_TARGS + +#undef FW_TARGSC +#undef INSTANTIATE_WRAPPERS +#undef INVOKE_VOID +#undef INVOKE_RV +#undef LOAD_CLASS +#undef LOAD_ARG + + template + class function_identity : public function_identity_base { + T ptr; + + public: + typedef function_wrapper wrapper; + + function_identity(T ptr) + : function_identity_base(wrapper::num_args), ptr(ptr) {}; + + virtual void invoke(lua_State *state, int base) { wrapper::execute(state, base, ptr); } + }; + + template + inline function_identity_base *wrap_function(T ptr) { + // bah, but didn't have any idea how to allocate statically + return new function_identity(ptr); + } +} \ No newline at end of file diff --git a/library/include/DataIdentity.h b/library/include/DataIdentity.h index e0f864225..840c9688f 100644 --- a/library/include/DataIdentity.h +++ b/library/include/DataIdentity.h @@ -37,6 +37,23 @@ distribution. namespace DFHack { + class DFHACK_EXPORT function_identity_base : public type_identity { + int num_args; + + public: + function_identity_base(int num_args) : type_identity(0), num_args(num_args) {}; + + virtual identity_type type() { return IDTYPE_FUNCTION; } + + int getNumArgs() { return num_args; } + std::string getFullName() { return "function"; } + + virtual void invoke(lua_State *state, int base) = 0; + + virtual void lua_read(lua_State *state, int fname_idx, void *ptr); + virtual void lua_write(lua_State *state, int fname_idx, void *ptr, int val_index); + }; + class DFHACK_EXPORT primitive_identity : public type_identity { public: primitive_identity(size_t size) : type_identity(size) {}; @@ -145,6 +162,7 @@ namespace DFHack namespace df { + using DFHack::function_identity_base; using DFHack::primitive_identity; using DFHack::pointer_identity; using DFHack::container_identity; @@ -187,6 +205,16 @@ namespace df virtual void lua_write(lua_State *state, int fname_idx, void *ptr, int val_index); }; + class ptr_string_identity : public primitive_identity { + public: + ptr_string_identity() : primitive_identity(sizeof(char*)) {}; + + std::string getFullName() { return "char*"; } + + virtual void lua_read(lua_State *state, int fname_idx, void *ptr); + virtual void lua_write(lua_State *state, int fname_idx, void *ptr, int val_index); + }; + class stl_string_identity : public DFHack::constructed_identity { public: stl_string_identity() @@ -370,6 +398,28 @@ namespace df } }; + template + class enum_list_attr_identity : public container_identity { + public: + typedef enum_list_attr container; + + enum_list_attr_identity(type_identity *item) + : container_identity(sizeof(container), NULL, item, NULL) + {} + + std::string getFullName(type_identity *item) { + return "enum_list_attr" + container_identity::getFullName(item); + } + + protected: + virtual int item_count(void *ptr, CountMode cm) { + return cm == COUNT_WRITE ? 0 : ((container*)ptr)->size; + } + virtual void *item_pointer(type_identity *item, void *ptr, int idx) { + return (void*)&((container*)ptr)->items[idx]; + } + }; + #define NUMBER_IDENTITY_TRAITS(type) \ template<> struct identity_traits { \ static number_identity identity; \ @@ -397,6 +447,16 @@ namespace df static stl_string_identity *get() { return &identity; } }; + template<> struct identity_traits { + static ptr_string_identity identity; + static ptr_string_identity *get() { return &identity; } + }; + + template<> struct identity_traits { + static ptr_string_identity identity; + static ptr_string_identity *get() { return &identity; } + }; + template<> struct identity_traits { static pointer_identity identity; static pointer_identity *get() { return &identity; } @@ -448,47 +508,51 @@ namespace df static container_identity *get(); }; + template struct identity_traits > { + static container_identity *get(); + }; + // Container definitions template - primitive_identity *identity_traits >::get() { + inline primitive_identity *identity_traits >::get() { return identity_traits::get(); } template - pointer_identity *identity_traits::get() { + inline pointer_identity *identity_traits::get() { static pointer_identity identity(identity_traits::get()); return &identity; } template - container_identity *identity_traits::get() { + inline container_identity *identity_traits::get() { static buffer_container_identity identity(sz, identity_traits::get()); return &identity; } template - container_identity *identity_traits >::get() { + inline container_identity *identity_traits >::get() { typedef std::vector container; static stl_container_identity identity("vector", identity_traits::get()); return &identity; } template - stl_ptr_vector_identity *identity_traits >::get() { + inline stl_ptr_vector_identity *identity_traits >::get() { static stl_ptr_vector_identity identity(identity_traits::get()); return &identity; } template - container_identity *identity_traits >::get() { + inline container_identity *identity_traits >::get() { typedef std::deque container; static stl_container_identity identity("deque", identity_traits::get()); return &identity; } template - bit_container_identity *identity_traits >::get() { + inline bit_container_identity *identity_traits >::get() { static type_identity *eid = identity_traits::get(); static enum_identity *reid = eid->type() == DFHack::IDTYPE_ENUM ? (enum_identity*)eid : NULL; static bit_array_identity identity(reid); @@ -496,10 +560,16 @@ namespace df } template - container_identity *identity_traits >::get() { + inline container_identity *identity_traits >::get() { typedef DfArray container; static stl_container_identity identity("DfArray", identity_traits::get()); return &identity; } + + template + inline container_identity *identity_traits >::get() { + static enum_list_attr_identity identity(identity_traits::get()); + return &identity; + } } diff --git a/library/include/LuaWrapper.h b/library/include/LuaWrapper.h index 2d98aeda6..d043d96f7 100644 --- a/library/include/LuaWrapper.h +++ b/library/include/LuaWrapper.h @@ -68,6 +68,7 @@ namespace DFHack { namespace LuaWrapper { #define DFHACK_DISPLACE_NAME "DFHack::Displace" #define DFHACK_NEW_NAME "DFHack::New" #define DFHACK_ASSIGN_NAME "DFHack::Assign" +#define DFHACK_DELETE_NAME "DFHack::Delete" /* * Upvalue: contents of DFHACK_TYPETABLE_NAME @@ -186,5 +187,7 @@ namespace DFHack { namespace LuaWrapper { * and the enum itself to the _enum metafield. */ void AttachEnumKeys(lua_State *state, int meta_idx, int ftable_idx, type_identity *ienum); + + void IndexStatics(lua_State *state, int meta_idx, int ftable_idx, struct_identity *pstruct); }} diff --git a/library/xml b/library/xml index 55a120d5b..f7c535a64 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 55a120d5bc823b783aeb8b6931ccaa31402fd850 +Subproject commit f7c535a64b0858acbb56d38f13dde0c820e2c4bc diff --git a/plugins/Dfusion/luafiles/init.lua b/plugins/Dfusion/luafiles/init.lua index 27f0571fd..aaf2677fc 100644 --- a/plugins/Dfusion/luafiles/init.lua +++ b/plugins/Dfusion/luafiles/init.lua @@ -61,7 +61,7 @@ dofile("dfusion/editor.lua") unlockDF() plugins={} table.insert(plugins,{"simple_embark","A simple embark dwarf count editor"}) ---table.insert(plugins,{"tools","some misc tools"}) +table.insert(plugins,{"tools","some misc tools"}) table.insert(plugins,{"embark","Multi race embark"}) table.insert(plugins,{"friendship","Multi race fort enabler"}) --[=[table.insert(plugins,{"items","A collection of item hacking tools"}) diff --git a/plugins/Dfusion/luafiles/tools/init.lua b/plugins/Dfusion/luafiles/tools/init.lua index ebaf63719..6f1384baa 100644 --- a/plugins/Dfusion/luafiles/tools/init.lua +++ b/plugins/Dfusion/luafiles/tools/init.lua @@ -272,23 +272,42 @@ function tools.empregnate(unit) if unit==nil then error("Failed to empregnate. Unit not selected/valide") end + print(string.format("%x %x",df.sizeof(unit))) + local arr1=unit.appearance.unk_51c local arr2=unit.appearance.unk_51c local created=false if unit.relations.pregnancy_ptr == nil then print("creating preg ptr.") - unit.relations.pregnancy_ptr=unit.relations:_field("pregnancy_ptr"):new()--=df.new(unit.relations.pregnancy_ptr._kind) + if false then + print(string.format("%x %x",df.sizeof(unit.relations:_field("pregnancy_ptr")))) + return + end + local size,offset=df.sizeof(unit.relations:_field("pregnancy_ptr")) + local s1=df.sizeof(arr1) + local s2=df.sizeof(arr2) + engine.poked(offset,engine.alloc(s1+s2)) created=true end - local tarr1=unit.relations.pregnancy_ptr:deref().anon_1 - local tarr2=unit.relations.pregnancy_ptr:deref().anon_2 - if created or tarr1.size~= arr1.size then + local tarr1=unit.relations.pregnancy_ptr.anon_1 + local tarr2=unit.relations.pregnancy_ptr.anon_2 + if created or #tarr1~= #arr1 then + print(string.format("Before: %d vs %d",#tarr1,#arr1)) print("Setting up arr1") - initType(tarr1,arr1.size) + print(string.format("%x %x",df.sizeof(tarr1))) + --tarr1=arr1:new() + local size,offset=df.sizeof(tarr1) + engine.poked(offset,engine.alloc(#arr1)) + engine.poked(offset+4,#arr1) + print(string.format("after: %d vs %d",#tarr1,#arr1)) end - if created or tarr2.size~= arr2.size then - print("Setting up arr1") - initType(tarr2,arr2.size) + if created or #tarr2~= #arr2 then + print("Setting up arr2") + --tarr2=arr2:new() + local size,offset=df.sizeof(tarr2) + + engine.poked(offset,engine.alloc(#arr2*2)) + engine.poked(offset+4,#arr2) end print("Setting preg timer.") unit.relations.pregnancy_timer=10 diff --git a/plugins/stonesense b/plugins/stonesense index 7525c0030..a0f680825 160000 --- a/plugins/stonesense +++ b/plugins/stonesense @@ -1 +1 @@ -Subproject commit 7525c003089367823183eaf5093a90271a5eb9b4 +Subproject commit a0f6808254168063449b4f7e93afbd879bd1fafd