schemlib update. Use schemlib plan persistance manager

This commit is contained in:
Alexander Weber 2018-07-30 22:29:45 +02:00
parent 2a1bf33851
commit 63cacc2e5b

177
init.lua
View File

@ -2,6 +2,7 @@
local dprint = function() return end
local modpath = minetest.get_modpath(minetest.get_current_modname())
local filepath = modpath.."/buildings/"
local plan_manager = schemlib.plan_manager
local BUILD_DISTANCE = 3
@ -11,110 +12,17 @@ schemlib_builder_npcf = {
walk_around_rarity = 3, -- Rarity for direction change in walk around without job
walk_around_duration = 10, -- Rarity for direction change in walk around without job
plan_max_distance = 100, -- Maximal distance to the next plan
check_anchor_rarity = 10, -- Rarity of check for anchor call --10
--buildings = {} -- list with buildings {name=, filename=}
check_anchor_rarity = 2, -- Rarity of check for anchor call --10
}
local func = {} -- different functions
local building_checktable = {}
local tmp_next_plan
--------------------------------------
-- Plan manager singleton
--------------------------------------
local plan_manager = {
plan_list = {}
}
schemlib_builder_npcf.plan_manager = plan_manager
--------------------------------------
-- Restore active WIP plan's
--------------------------------------
function plan_manager:restore()
self.stored_list = schemlib.save_restore.restore_data("/schemlib_builder_npcf.store")
for plan_id, entry in pairs(self.stored_list) do
local filename = building_checktable[entry.filename]
if filename then
local plan = func.get_plan_from_file(entry.filename, modpath.."/buildings/"..entry.filename, plan_id, entry.anchor_pos)
if entry.facedir ~= nil then
plan.facedir = entry.facedir
end
if entry.mirrored ~= nil then
plan.mirrored = entry.mirrored
end
end
end
end
--------------------------------------
-- Save active WIP plan's
--------------------------------------
function plan_manager:save()
self.stored_list = {}
for plan_id, plan in pairs(self.plan_list) do
if plan.schemlib_builder_npcf_building_filename then
local entry = {
anchor_pos = plan.anchor_pos,
filename = plan.schemlib_builder_npcf_building_filename,
facedir = plan.facedir,
mirrored = plan.mirrored,
}
self.stored_list[plan_id] = entry
end
end
schemlib.save_restore.save_data("/schemlib_builder_npcf.store", self.stored_list)
end
--------------------------------------
-- Get known plan
--------------------------------------
function plan_manager:get(plan_id)
local plan = self.plan_list[plan_id]
if plan and plan:get_status() == "finished" then
dprint(self.npc_id, "plan finished, remove from npc plan manager")
self:set_finished(plan)
return nil
else
return plan
end
end
--------------------------------------
-- Set the plan finished
--------------------------------------
function plan_manager:set_finished(plan)
self.plan_list[plan.plan_id] = nil
plan_manager:save()
end
--------------------------------------
-- Add new plan to the list
--------------------------------------
function plan_manager:add(plan)
self.plan_list[plan.plan_id] = plan
end
--------------------------------------
-- set anchor and rename to get active
--------------------------------------
function plan_manager:activate_by_anchor(anchor_pos)
local plan = tmp_next_plan
tmp_next_plan = nil
local new_plan_id = minetest.pos_to_string(anchor_pos)
plan.plan_id = new_plan_id
plan.anchor_pos = anchor_pos
plan:set_status("build")
self.plan_list[new_plan_id] = plan
self:save()
return plan
end
--------------------------------------
-- Functions
--------------------------------------
-- Get buildings list
--------------------------------------
function func.get_buildings_list()
local function get_buildings_list()
local list = {}
local building_files = minetest.get_dir_list(modpath.."/buildings/", false)
for _, file in ipairs(building_files) do
@ -127,16 +35,10 @@ end
--------------------------------------
-- Load plan from file and configure them
--------------------------------------
function func.get_plan_from_file(name, filename, plan_id, anchor_pos)
plan_id = plan_id or name
local plan = schemlib.plan.new(plan_id, anchor_pos)
plan.schemlib_builder_npcf_building_filename = name
local function get_plan_from_file(filename)
local plan = schemlib.plan.new()
plan:read_from_schem_file(filename)
plan:apply_flood_with_air()
if anchor_pos then
plan:set_status("build")
plan_manager:add(plan)
end
return plan
end
@ -144,16 +46,19 @@ end
-- NPC Enhancements
--------------------------------------
-- Get exsisting plan prefering the already assigned
function func.get_existing_plan(self)
local function get_existing_plan(self)
local mv_obj = npcf.movement.getControl(self)
if self.metadata.build_plan_id and (not tmp_next_plan or self.build_plan ~= tmp_next_plan) then
-- check if current plan is still valid / get them
dprint(self.npc_id,"check existing plan", self.metadata.build_plan_id )
self.build_plan = plan_manager:get(self.metadata.build_plan_id)
self.build_plan = plan_manager:get_plan(self.metadata.build_plan_id)
if not self.build_plan then
self.metadata.build_plan_id = nil
end
end
-- The NPC is not a workaholic
if self.build_plan == nil and schemlib_builder_npcf.max_pause_duration > 0 then
if not self.build_plan and schemlib_builder_npcf.max_pause_duration > 0 then
dprint(self.npc_id,"check for pause")
if not self.metadata.schemlib_pause then
self.metadata.schemlib_pause = math.random(schemlib_builder_npcf.max_pause_duration)
@ -174,18 +79,19 @@ function func.get_existing_plan(self)
-- no plan assigned, check for neighboar plans / select existing plan
dprint(self.npc_id,"select existing plan")
local selected_plan = {}
for plan_id, _ in pairs(plan_manager.plan_list) do
local plan = plan_manager:get(plan_id)
if plan then
local distance = vector.distance(plan.anchor_pos, mv_obj.pos)
dprint(self.npc_id,"plan exists:", plan_id, plan.anchor_pos, distance)
for plan_id, meta in pairs(plan_manager.plan_meta_list) do
if meta.npc_build and meta.anchor_pos then
local distance = vector.distance(meta.anchor_pos, mv_obj.pos)
dprint(self.npc_id,"plan exists:", plan_id, meta.anchor_pos, distance)
if distance < schemlib_builder_npcf.plan_max_distance and (not selected_plan.distance or selected_plan.distance > distance) then
selected_plan.distance = distance
selected_plan.plan = plan
selected_plan.plan_id = plan_id
end
end
end
self.build_plan = selected_plan.plan or self.build_plan
if selected_plan.plan_id then
self.build_plan = plan_manager.get_plan(selected_plan.plan_id)
end
if self.build_plan then
self.metadata.build_plan_id = self.build_plan.plan_id
dprint(self.npc_id,"Existing plan selected", selected_plan.plan_id)
@ -194,28 +100,29 @@ function func.get_existing_plan(self)
end
function func.create_new_plan(self)
local function create_new_plan(self)
local mv_obj = npcf.movement.getControl(self)
if not tmp_next_plan then
-- no plan in list - and no plan temporary loaded - load them (maybe)
local building = schemlib_builder_npcf.buildings[math.random(#schemlib_builder_npcf.buildings)]
dprint(self.npc_id,"File selected for build", building.filename)
tmp_next_plan = func.get_plan_from_file(building.name, building.filename)
tmp_next_plan.facedir = math.random(4)-1
tmp_next_plan.mirrored = (math.random(2) == 1)
tmp_next_plan = get_plan_from_file(building.filename)
tmp_next_plan.data.facedir = math.random(4)-1
tmp_next_plan.data.mirrored = (math.random(2) == 1)
dprint(self.npc_id,"building loaded. Nodes:", tmp_next_plan.data.nodecount)
return
end
if math.random(schemlib_builder_npcf.check_anchor_rarity) == 1 then
-- dummy plan exists, search for anchor, but do not penetrate the map by propose_anchor()
dprint(self.npc_id,"Check anchor")
local chk_pos = vector.round(mv_obj.pos)
local anchor_pos, error_pos
-- check for possible overlaps with other plans
for plan_id, _ in pairs(plan_manager.plan_list) do
local plan = plan_manager:get(plan_id)
if tmp_next_plan:check_overlap(plan:get_world_minp(), plan:get_world_maxp(), 3, chk_pos) then
error_pos = plan:get_world_pos(plan:get_random_plan_pos())
for plan_id, meta in pairs(plan_manager.plan_meta_list) do
local plan_meta = plan_manager.get_plan_meta(plan_id)
error_pos = tmp_next_plan:check_overlap(plan_meta:get_world_minp(), plan_meta:get_world_maxp(), 3, chk_pos)
if error_pos then
break
end
end
@ -234,8 +141,14 @@ function func.create_new_plan(self)
dprint(self.npc_id,"proposed anchor", minetest.pos_to_string(anchor_pos), "nearly", minetest.pos_to_string(mv_obj.pos))
-- Prepare building plan to be build
self.build_plan = plan_manager:activate_by_anchor(anchor_pos)
self.build_plan = tmp_next_plan
self.build_plan.plan_id = "builder:"..minetest.pos_to_string(anchor_pos)
self.build_plan.data.managed_by_schemlib_builder = true
self.metadata.build_plan_id = self.build_plan.plan_id
self.build_plan.data.anchor_pos = anchor_pos
self.build_plan.data.npc_build = true
tmp_next_plan = nil
plan_manager.set_plan(self.build_plan)
dprint(self.npc_id,"building ready to build at:", self.metadata.build_plan_id)
end
end
@ -256,17 +169,26 @@ npcf:register_npc("schemlib_builder_npcf:builder" ,{
mv_obj:mine_stop()
-- check plan
func.get_existing_plan(self)
get_existing_plan(self)
if self.build_plan then
dprint(self.npc_id,"plan ready for build, get the next node")
if self.build_plan.data.nodecount == 0 then
if self.build_plan.data.managed_by_schemlib_builder then
plan_manager.delete_plan(self.build_plan.plan_id)
end
self.build_plan = nil
self.metadata.build_plan_id = nil
dprint(self.npc_id, "plan finished")
return
end
dprint(self.npc_id,"plan ready for build, get the next node")
if not self.build_npc_ai or self.build_npc_ai.plan ~= self.build_plan then
self.build_npc_ai = schemlib.npc_ai.new(self.build_plan, BUILD_DISTANCE)
end
self.target_node = self.build_npc_ai:plan_target_get(mv_obj.pos)
end
if not self.build_plan and schemlib_builder_npcf.architect_rarity > 0 and
if (not self.build_plan) and schemlib_builder_npcf.architect_rarity > 0 and
math.random(schemlib_builder_npcf.architect_rarity) == 1 then
func.create_new_plan(self)
create_new_plan(self)
self.target_node = nil
end
@ -376,6 +298,5 @@ npcf:register_npc("schemlib_builder_npcf:builder" ,{
})
-- Restore data at init
schemlib_builder_npcf.buildings = func.get_buildings_list() -- at init!
plan_manager:restore()
schemlib_builder_npcf.buildings = get_buildings_list() -- at init!