From 2865e1373aaa366b1121806408726a9b8c087fa6 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Thu, 11 Oct 2012 17:34:34 +0400 Subject: [PATCH] Experimental API for associating tile bitmasks with persistent data. Use block_square_event_world_constructionst objects with the same bogus negative id as the matching historical figure object. --- Lua API.html | 27 ++++++++ Lua API.rst | 34 ++++++++++ library/LuaApi.cpp | 52 ++++++++++++++- .../df/custom/tile_bitmask.methods.inc | 6 +- library/include/modules/World.h | 9 +++ library/modules/World.cpp | 65 +++++++++++++++++++ library/xml | 2 +- 7 files changed, 189 insertions(+), 6 deletions(-) diff --git a/Lua API.html b/Lua API.html index 06fa5418e..125687110 100644 --- a/Lua API.html +++ b/Lua API.html @@ -932,6 +932,21 @@ Returns entry, did_create_new

and automatically stored in the save game, these save and retrieval functions can just copy values in memory without doing any actual I/O. However, currently every entry has a 180+-byte dead-weight overhead.

+

It is also possible to associate one bit per map tile with an entry, +using these two methods:

+ +

Note that these masks are only saved in fortress mode, and also that deleting +the persistent entry will NOT delete the associated masks.

Material info lookup

@@ -1286,6 +1301,18 @@ tools like liquids or tiletypes are used. It also cannot possibly take into account anything that depends on the actual units, like burrows, or the presence of invaders.

+
  • dfhack.maps.hasTileAssignment(tilemask)

    +

    Checks if the tile_bitmask object is not nil and contains any set bits; returns true or false.

    +
  • +
  • dfhack.maps.getTileAssignment(tilemask,x,y)

    +

    Checks if the tile_bitmask object is not nil and has the relevant bit set; returns true or false.

    +
  • +
  • dfhack.maps.setTileAssignment(tilemask,x,y,enable)

    +

    Sets the relevant bit in the tile_bitmask object to the enable argument.

    +
  • +
  • dfhack.maps.resetTileAssignment(tilemask[,enable])

    +

    Sets all bits in the mask to the enable argument.

    +
  • diff --git a/Lua API.rst b/Lua API.rst index fbb4b7d82..7ad6aec23 100644 --- a/Lua API.rst +++ b/Lua API.rst @@ -646,6 +646,24 @@ and automatically stored in the save game, these save and retrieval functions can just copy values in memory without doing any actual I/O. However, currently every entry has a 180+-byte dead-weight overhead. +It is also possible to associate one bit per map tile with an entry, +using these two methods: + +* ``entry:getTilemask(block[, create])`` + + Retrieves the tile bitmask associated with this entry in the given map + block. If ``create`` is *true*, an empty mask is created if none exists; + otherwise the function returns *nil*, which must be assumed to be the same + as an all-zero mask. + +* ``entry:deleteTilemask(block)`` + + Deletes the associated tile mask from the given map block. + +Note that these masks are only saved in fortress mode, and also that deleting +the persistent entry will **NOT** delete the associated masks. + + Material info lookup -------------------- @@ -1079,6 +1097,22 @@ Maps module take into account anything that depends on the actual units, like burrows, or the presence of invaders. +* ``dfhack.maps.hasTileAssignment(tilemask)`` + + Checks if the tile_bitmask object is not *nil* and contains any set bits; returns *true* or *false*. + +* ``dfhack.maps.getTileAssignment(tilemask,x,y)`` + + Checks if the tile_bitmask object is not *nil* and has the relevant bit set; returns *true* or *false*. + +* ``dfhack.maps.setTileAssignment(tilemask,x,y,enable)`` + + Sets the relevant bit in the tile_bitmask object to the *enable* argument. + +* ``dfhack.maps.resetTileAssignment(tilemask[,enable])`` + + Sets all bits in the mask to the *enable* argument. + Burrows module -------------- diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 0df96f066..ef571bcb7 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -30,6 +30,7 @@ distribution. #include "MemAccess.h" #include "Core.h" +#include "Error.h" #include "VersionInfo.h" #include "tinythread.h" // must be last due to MS stupidity @@ -311,12 +312,12 @@ static PersistentDataItem get_persistent(lua_State *state) if (lua_istable(state, 1)) { + Lua::StackUnwinder frame(state); + if (!lua_getmetatable(state, 1) || !lua_rawequal(state, -1, lua_upvalueindex(1))) luaL_argerror(state, 1, "invalid table type"); - lua_settop(state, 1); - return persistent_by_struct(state, 1); } else @@ -446,11 +447,38 @@ static int dfhack_persistent_save(lua_State *state) return 2; } +static int dfhack_persistent_getTilemask(lua_State *state) +{ + CoreSuspender suspend; + + lua_settop(state, 3); + auto ref = get_persistent(state); + auto block = Lua::CheckDFObject(state, 2); + bool create = lua_toboolean(state, 3); + + Lua::PushDFObject(state, World::getPersistentTilemask(ref, block, create)); + return 1; +} + +static int dfhack_persistent_deleteTilemask(lua_State *state) +{ + CoreSuspender suspend; + + lua_settop(state, 2); + auto ref = get_persistent(state); + auto block = Lua::CheckDFObject(state, 2); + + lua_pushboolean(state, World::deletePersistentTilemask(ref, block)); + return 1; +} + static const luaL_Reg dfhack_persistent_funcs[] = { { "get", dfhack_persistent_get }, { "delete", dfhack_persistent_delete }, { "get_all", dfhack_persistent_get_all }, { "save", dfhack_persistent_save }, + { "getTilemask", dfhack_persistent_getTilemask }, + { "deleteTilemask", dfhack_persistent_deleteTilemask }, { NULL, NULL } }; @@ -937,6 +965,22 @@ static const luaL_Reg dfhack_items_funcs[] = { /***** Maps module *****/ +static bool hasTileAssignment(df::tile_bitmask *bm) { + return bm && bm->has_assignments(); +} +static bool getTileAssignment(df::tile_bitmask *bm, int x, int y) { + return bm && bm->getassignment(x,y); +} +static void setTileAssignment(df::tile_bitmask *bm, int x, int y, bool val) { + CHECK_NULL_POINTER(bm); + bm->setassignment(x,y,val); +} +static void resetTileAssignment(df::tile_bitmask *bm, bool val) { + CHECK_NULL_POINTER(bm); + if (val) bm->set_all(); + else bm->clear(); +} + static const LuaWrapper::FunctionReg dfhack_maps_module[] = { WRAPN(getBlock, (df::map_block* (*)(int32_t,int32_t,int32_t))Maps::getBlock), WRAPM(Maps, enableBlockUpdates), @@ -944,6 +988,10 @@ static const LuaWrapper::FunctionReg dfhack_maps_module[] = { WRAPM(Maps, getLocalInitFeature), WRAPM(Maps, canWalkBetween), WRAPM(Maps, spawnFlow), + WRAPN(hasTileAssignment, hasTileAssignment), + WRAPN(getTileAssignment, getTileAssignment), + WRAPN(setTileAssignment, setTileAssignment), + WRAPN(resetTileAssignment, resetTileAssignment), { NULL, NULL } }; diff --git a/library/include/df/custom/tile_bitmask.methods.inc b/library/include/df/custom/tile_bitmask.methods.inc index 18b312a08..e3414e334 100644 --- a/library/include/df/custom/tile_bitmask.methods.inc +++ b/library/include/df/custom/tile_bitmask.methods.inc @@ -16,7 +16,7 @@ inline bool getassignment( const df::coord2d &xy ) } inline bool getassignment( int x, int y ) { - return (bits[y] & (1 << x)); + return (bits[(y&15)] & (1 << (x&15))); } inline void setassignment( const df::coord2d &xy, bool bit ) { @@ -25,9 +25,9 @@ inline void setassignment( const df::coord2d &xy, bool bit ) inline void setassignment( int x, int y, bool bit ) { if(bit) - bits[y] |= (1 << x); + bits[(y&15)] |= (1 << (x&15)); else - bits[y] &= ~(1 << x); + bits[(y&15)] &= ~(1 << (x&15)); } bool has_assignments() { diff --git a/library/include/modules/World.h b/library/include/modules/World.h index f4c31dcf3..a945c4e72 100644 --- a/library/include/modules/World.h +++ b/library/include/modules/World.h @@ -37,6 +37,12 @@ distribution. #include "DataDefs.h" +namespace df +{ + struct tile_bitmask; + struct map_block; +} + namespace DFHack { typedef df::game_mode GameMode; @@ -120,6 +126,9 @@ namespace DFHack DFHACK_EXPORT bool DeletePersistentData(const PersistentDataItem &item); DFHACK_EXPORT void ClearPersistentCache(); + + DFHACK_EXPORT df::tile_bitmask *getPersistentTilemask(const PersistentDataItem &item, df::map_block *block, bool create = false); + DFHACK_EXPORT bool deletePersistentTilemask(const PersistentDataItem &item, df::map_block *block); } } #endif diff --git a/library/modules/World.cpp b/library/modules/World.cpp index 65d0c7cb8..f3283c3a3 100644 --- a/library/modules/World.cpp +++ b/library/modules/World.cpp @@ -38,13 +38,18 @@ using namespace std; #include "ModuleFactory.h" #include "Core.h" +#include "modules/Maps.h" + #include "MiscUtils.h" #include "DataDefs.h" #include "df/world.h" #include "df/historical_figure.h" +#include "df/map_block.h" +#include "df/block_square_event_world_constructionst.h" using namespace DFHack; +using namespace df::enums; using df::global::world; @@ -312,3 +317,63 @@ bool World::DeletePersistentData(const PersistentDataItem &item) return false; } + +df::tile_bitmask *World::getPersistentTilemask(const PersistentDataItem &item, df::map_block *block, bool create) +{ + if (!block) + return NULL; + + int id = item.raw_id(); + if (id > -100) + return NULL; + + for (size_t i = 0; i < block->block_events.size(); i++) + { + auto ev = block->block_events[i]; + if (ev->getType() != block_square_event_type::world_construction) + continue; + auto wcsev = strict_virtual_cast(ev); + if (!wcsev || wcsev->construction_id != id) + continue; + return &wcsev->tile_bitmask; + } + + if (!create) + return NULL; + + auto ev = df::allocate(); + if (!ev) + return NULL; + + ev->construction_id = id; + ev->tile_bitmask.clear(); + vector_insert_at(block->block_events, 0, (df::block_square_event*)ev); + + return &ev->tile_bitmask; +} + +bool World::deletePersistentTilemask(const PersistentDataItem &item, df::map_block *block) +{ + if (!block) + return false; + int id = item.raw_id(); + if (id > -100) + return false; + + bool found = false; + for (int i = block->block_events.size()-1; i >= 0; i--) + { + auto ev = block->block_events[i]; + if (ev->getType() != block_square_event_type::world_construction) + continue; + auto wcsev = strict_virtual_cast(ev); + if (!wcsev || wcsev->construction_id != id) + continue; + + delete wcsev; + vector_erase_at(block->block_events, i); + found = true; + } + + return found; +} diff --git a/library/xml b/library/xml index 20c6d9c74..aec106cdc 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 20c6d9c743f1c5a20bb288f427b101e9b2a138d7 +Subproject commit aec106cdc32083bbcc6d6dd27d9e069f5525ea92