buildingplan: construct buildings from lua

Replace C++ building construction code with lua constructBuilding so we can get the proper job_item filters set. these filters will be used when we replace the core buildingplan algorithm in the next PR.
develop
Myk Taylor 2020-10-16 14:03:05 -07:00
parent 82013c0c5e
commit 1368fb4003
7 changed files with 117 additions and 45 deletions

@ -126,7 +126,7 @@ if(BUILD_SUPPORTED)
dfhack_plugin(flows flows.cpp) dfhack_plugin(flows flows.cpp)
dfhack_plugin(follow follow.cpp) dfhack_plugin(follow follow.cpp)
dfhack_plugin(forceequip forceequip.cpp) dfhack_plugin(forceequip forceequip.cpp)
dfhack_plugin(fortplan fortplan.cpp LINK_LIBRARIES buildingplan-lib) dfhack_plugin(fortplan fortplan.cpp LINK_LIBRARIES buildingplan-lib lua)
dfhack_plugin(generated-creature-renamer generated-creature-renamer.cpp) dfhack_plugin(generated-creature-renamer generated-creature-renamer.cpp)
dfhack_plugin(getplants getplants.cpp) dfhack_plugin(getplants getplants.cpp)
dfhack_plugin(hotkeys hotkeys.cpp) dfhack_plugin(hotkeys hotkeys.cpp)

@ -522,42 +522,6 @@ bool Planner::isPlannableBuilding(BuildingTypeKey key)
return item_for_building_type.count(std::get<0>(key)) > 0; return item_for_building_type.count(std::get<0>(key)) > 0;
} }
bool Planner::allocatePlannedBuilding(BuildingTypeKey key)
{
coord32_t cursor;
if (!DFHack::Gui::getCursorCoords(cursor.x, cursor.y, cursor.z))
return false;
auto type = std::get<0>(key);
auto newinst = Buildings::allocInstance(cursor.get_coord16(), type);
if (!newinst)
return false;
df::job_item *filter = new df::job_item();
filter->item_type = item_type::NONE;
filter->mat_index = 0;
filter->flags2.bits.building_material = true;
std::vector<df::job_item*> filters;
filters.push_back(filter);
if (!Buildings::constructWithFilters(newinst, filters))
{
delete newinst;
return false;
}
if (type == building_type::Door)
{
auto door = virtual_cast<df::building_doorst>(newinst);
if (door)
door->door_flags.bits.pet_passable = true;
}
addPlannedBuilding(newinst);
return true;
}
Planner::ItemFiltersWrapper Planner::getItemFilters(BuildingTypeKey key) Planner::ItemFiltersWrapper Planner::getItemFilters(BuildingTypeKey key)
{ {
static std::vector<ItemFilter> empty_vector; static std::vector<ItemFilter> empty_vector;

@ -106,7 +106,6 @@ public:
void initialize(); void initialize();
void reset(); void reset();
bool allocatePlannedBuilding(BuildingTypeKey key);
void addPlannedBuilding(df::building *bld); void addPlannedBuilding(df::building *bld);
PlannedBuilding *getPlannedBuilding(df::building *bld); PlannedBuilding *getPlannedBuilding(df::building *bld);

@ -287,6 +287,33 @@ static bool is_planmode_enabled(BuildingTypeKey key)
return planmode_enabled[key] || quickfort_mode; return planmode_enabled[key] || quickfort_mode;
} }
static bool construct_planned_building()
{
auto L = Lua::Core::State;
color_ostream_proxy out(Core::getInstance().getConsole());
CoreSuspendClaimer suspend;
Lua::StackUnwinder top(L);
if (!(lua_checkstack(L, 1) &&
Lua::PushModulePublic(out, L, "plugins.buildingplan",
"construct_building_from_ui_state") &&
Lua::SafeCall(out, L, 0, 1)))
{
return false;
}
auto bld = static_cast<df::building *>(LuaWrapper::get_object_ref(L, -1));
lua_pop(L, 1);
if (!bld)
return false;
planner.addPlannedBuilding(bld);
return true;
}
struct buildingplan_query_hook : public df::viewscreen_dwarfmodest struct buildingplan_query_hook : public df::viewscreen_dwarfmodest
{ {
typedef df::viewscreen_dwarfmodest interpose_base; typedef df::viewscreen_dwarfmodest interpose_base;
@ -417,7 +444,7 @@ struct buildingplan_place_hook : public df::viewscreen_dwarfmodest
if (input->count(interface_key::SELECT)) if (input->count(interface_key::SELECT))
{ {
if (ui_build_selector->errors.size() == 0 && planner.allocatePlannedBuilding(key)) if (ui_build_selector->errors.size() == 0 && construct_planned_building())
{ {
Gui::refreshSidebar(); Gui::refreshSidebar();
if (quickfort_mode) if (quickfort_mode)

@ -1,14 +1,17 @@
#include <fstream> #include <fstream>
#include <vector> #include <vector>
#include "df/world.h" #include "df/job_item.h"
#include "df/trap_type.h" #include "df/trap_type.h"
#include "df/world.h"
#include "modules/Buildings.h"
#include "modules/Filesystem.h" #include "modules/Filesystem.h"
#include "modules/Gui.h" #include "modules/Gui.h"
#include "modules/Maps.h" #include "modules/Maps.h"
#include "modules/World.h" #include "modules/World.h"
#include "LuaTools.h"
#include "PluginManager.h" #include "PluginManager.h"
#include "buildingplan-lib.h" #include "buildingplan-lib.h"
@ -47,8 +50,38 @@ struct BuildingInfo {
hasCustomOptions = false; hasCustomOptions = false;
} }
bool allocate() { bool allocate(coord32_t cursor) {
return planner.allocatePlannedBuilding(toBuildingTypeKey(type, -1, -1)); auto L = Lua::Core::State;
color_ostream_proxy out(Core::getInstance().getConsole());
CoreSuspendClaimer suspend;
Lua::StackUnwinder top(L);
if (!lua_checkstack(L, 5) ||
!Lua::PushModulePublic(out, L, "plugins.fortplan",
"construct_building_from_params"))
{
return false;
}
Lua::Push(L, type);
Lua::Push(L, cursor.x);
Lua::Push(L, cursor.y);
Lua::Push(L, cursor.z);
if (!Lua::SafeCall(out, L, 4, 1))
return false;
auto bld =
static_cast<df::building *>(LuaWrapper::get_object_ref(L, -1));
lua_pop(L, 1);
if (!bld)
return false;
planner.addPlannedBuilding(bld);
return true;
} }
}; };
@ -347,13 +380,13 @@ command_result fortplan(color_ostream &out, vector<string> & params) {
offsetCursor.x -= xOffset; offsetCursor.x -= xOffset;
offsetCursor.y -= yOffset; offsetCursor.y -= yOffset;
DFHack::Gui::setCursorCoords(offsetCursor.x, offsetCursor.y, offsetCursor.z); DFHack::Gui::setCursorCoords(offsetCursor.x, offsetCursor.y, offsetCursor.z);
if (!buildingInfo.allocate()) { if (!buildingInfo.allocate(offsetCursor)) {
con.print("*** There was an error placing building with code '%s' centered at (%zu,%zu).\n",curCode.c_str(),x,y); con.print("*** There was an error placing building with code '%s' centered at (%zu,%zu).\n",curCode.c_str(),x,y);
} }
DFHack::Gui::setCursorCoords(cursor.x, cursor.y, cursor.z); DFHack::Gui::setCursorCoords(cursor.x, cursor.y, cursor.z);
} else if (block) { } else if (block) {
//con.print("Placing a building with code '%s' with corner at (%d,%d) and default size %dx%d.\n",curCode.c_str(),x,y,buildingInfo.defaultWidth,buildingInfo.defaultHeight); //con.print("Placing a building with code '%s' with corner at (%d,%d) and default size %dx%d.\n",curCode.c_str(),x,y,buildingInfo.defaultWidth,buildingInfo.defaultHeight);
if (!buildingInfo.allocate()) { if (!buildingInfo.allocate(cursor)) {
con.print("*** There was an error placing building with code '%s' with corner at (%zu,%zu).\n",curCode.c_str(),x,y); con.print("*** There was an error placing building with code '%s' with corner at (%zu,%zu).\n",curCode.c_str(),x,y);
} }
} else { } else {
@ -366,7 +399,7 @@ command_result fortplan(color_ostream &out, vector<string> & params) {
} }
} else { } else {
//con.print("Building a(n) %s.\n",buildingInfo.name.c_str()); //con.print("Building a(n) %s.\n",buildingInfo.name.c_str());
if (!buildingInfo.allocate()) { if (!buildingInfo.allocate(cursor)) {
con.print("*** There was an error placing the %s at (%zu,%zu).\n",buildingInfo.name.c_str(),x,y); con.print("*** There was an error placing the %s at (%zu,%zu).\n",buildingInfo.name.c_str(),x,y);
} }
} }

@ -11,4 +11,40 @@ local _ENV = mkmodule('plugins.buildingplan')
--]] --]]
local guidm = require('gui.dwarfmode')
require('dfhack.buildings')
-- needs the core suspended
function construct_building_from_ui_state()
local uibs = df.global.ui_build_selector
local world = df.global.world
local direction = world.selected_direction
local _, width, height = dfhack.buildings.getCorrectSize(
world.building_width, world.building_height, uibs.building_type,
uibs.building_subtype, uibs.custom_type, direction)
-- the cursor is at the center of the building; we need the upper-left
-- corner of the building
local pos = guidm.getCursorPos()
pos.x = pos.x - math.floor(width/2)
pos.y = pos.y - math.floor(height/2)
local bld, err = dfhack.buildings.constructBuilding{
type=uibs.building_type, subtype=uibs.building_subtype,
custom=uibs.custom_type, pos=pos, width=width, height=height,
direction=direction}
if err then error(err) end
-- TODO: assign fields for the types that need them. we can't pass them all
-- in to the call to constructBuilding since the unneeded fields will cause
-- errors
--local fields = {
-- friction=uibs.friction,
-- use_dump=uibs.use_dump,
-- dump_x_shift=uibs.dump_x_shift,
-- dump_y_shift=uibs.dump_y_shift,
-- speed=uibs.speed
--}
-- TODO: use quickfort's post_construction_fns? maybe move those functions
-- into the library so they get applied automatically
return bld
end
return _ENV return _ENV

@ -0,0 +1,13 @@
local _ENV = mkmodule('plugins.fortplan')
require('dfhack.buildings')
function construct_building_from_params(building_type, x, y, z)
local pos = xyz2pos(x, y, z)
local bld, err =
dfhack.buildings.constructBuilding{type=building_type, pos=pos}
if err then error(err) end
return bld
end
return _ENV