From 3ba984c22c83946c2e52627ee2acd8c7db9597fe Mon Sep 17 00:00:00 2001 From: myk002 Date: Wed, 16 Dec 2020 11:10:47 -0800 Subject: [PATCH] only reset extents if they are unusable this allows callers of Buildings::setSize() to "pre-initialize" the extents to declare non-rectangular structures. this allows quickfort to create non-rectangular stockpiles, farm plots, zones, etc. the extents are still reset as before if the size of the building doesn't match the caller's expectations. this commit also fixes a memory leak when setSize() allocates memory for extents, but the memory is not deallocated if the building is ultimately invalid for some reason. --- docs/Lua API.rst | 10 ++++++++-- library/include/modules/Buildings.h | 2 ++ library/lua/dfhack/buildings.lua | 5 +++++ library/modules/Buildings.cpp | 15 ++++++++------- 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/docs/Lua API.rst b/docs/Lua API.rst index ffce7fd4e..1fe403034 100644 --- a/docs/Lua API.rst +++ b/docs/Lua API.rst @@ -1679,7 +1679,11 @@ Low-level building creation functions: Returns *false* if the building cannot be placed, or *true, width, height, rect_area, true_area*. Returned width and height are the final values used by the building; true_area is less than rect_area - if any tiles were removed from designation. + if any tiles were removed from designation. You can specify a non-rectangular + designation for building types that support extents by setting the + ``room.extents`` bitmap before calling this function. The extents will be + reset, however, if the size returned by this function doesn't match the + input size parameter. * ``dfhack.buildings.constructAbstract(building)`` @@ -1768,7 +1772,9 @@ Among them are: - ``fields = { ... }`` - Initializes fields of the building object after creation with ``df.assign``. + Initializes fields of the building object after creation with + ``df.assign``. If ``room.extents`` is assigned this way and this function + returns with error, the memory allocated for the extents is freed. - ``width = ..., height = ..., direction = ...`` diff --git a/library/include/modules/Buildings.h b/library/include/modules/Buildings.h index 94bf75499..aa539c02a 100644 --- a/library/include/modules/Buildings.h +++ b/library/include/modules/Buildings.h @@ -162,6 +162,8 @@ DFHACK_EXPORT bool hasSupport(df::coord pos, df::coord2d size); /** * Sets the size of the building, using size and direction as guidance. + * Any custom extents set for the building will be cleared if the size passed in + * as guidance cannot be applied to the building. * Returns true if the building can be created at its position, using that size. */ DFHACK_EXPORT bool setSize(df::building *bld, df::coord2d size, int direction = 0); diff --git a/library/lua/dfhack/buildings.lua b/library/lua/dfhack/buildings.lua index 5bb84b1d1..26a28aa2a 100644 --- a/library/lua/dfhack/buildings.lua +++ b/library/lua/dfhack/buildings.lua @@ -485,6 +485,11 @@ function buildings.constructBuilding(info) local to_delete = instance return dfhack.with_finalize( function() + -- ensure we don't leak extents created by Buildings::checkFreeTiles + if to_delete and to_delete.room.extents then + df.delete(to_delete.room.extents) + to_delete.room.extents = nil + end df.delete(to_delete) end, function() diff --git a/library/modules/Buildings.cpp b/library/modules/Buildings.cpp index 8fd2b77a1..5a0cd37dc 100644 --- a/library/modules/Buildings.cpp +++ b/library/modules/Buildings.cpp @@ -758,18 +758,19 @@ bool Buildings::setSize(df::building *bld, df::coord2d size, int direction) CHECK_NULL_POINTER(bld); CHECK_INVALID_ARGUMENT(bld->id == -1); - // Delete old extents - if (bld->room.extents) - { - delete[] bld->room.extents; - bld->room.extents = NULL; - } - // Compute correct size and apply it + df::coord2d old_size = size; df::coord2d center; getCorrectSize(size, center, bld->getType(), bld->getSubtype(), bld->getCustomType(), direction); + // Delete old extents if size has changed. + if (old_size != size && bld->room.extents) + { + delete[] bld->room.extents; + bld->room.extents = NULL; + } + bld->x2 = bld->x1 + size.x - 1; bld->y2 = bld->y1 + size.y - 1; bld->centerx = bld->x1 + center.x;