implement more simple job programming using coroutines

master
theFox6 2018-05-19 13:36:14 +02:00
parent 26c0584257
commit 5a1c067843
4 changed files with 79 additions and 18 deletions

61
api.lua
View File

@ -405,6 +405,13 @@ function working_villages.villager:pickup_item()
end
end
-- working_villages.villager.is_active check if the villager is paused.
function working_villages.villager:is_active()
return self.pause == "active"
end
dofile(working_villages.modpath.."/async_actions.lua") --load states
---------------------------------------------------------------------
function working_villages.villager.get_state(id)
@ -431,7 +438,8 @@ function working_villages.register_state(id,def)
--minetest.log("debug","registered state: "..id)
end
dofile(working_villages.modpath.."/actions.lua") --load states
dofile(working_villages.modpath.."/states.lua") --load states
--TODO: move states to async_actions
---------------------------------------------------------------------
@ -548,7 +556,6 @@ function working_villages.register_egg(egg_name, def)
)
new_villager:get_luaentity().owner_name = user:get_player_name()
new_villager:get_luaentity():update_infotext()
new_villager:setvelocity{x =0, y = 5, z = 0}
itemstack:take_item()
return itemstack
@ -575,7 +582,11 @@ function working_villages.register_villager(product_name, def)
if listname == "job" then
local job_name = stack:get_name()
local job = working_villages.registered_jobs[job_name]
job.on_start(self)
if type(job.on_start)=="function" then
job.on_start(self)
elseif type(job.jobfunc)=="function" then
self.job_thread = coroutine.create(job.jobfunc)
end
self:set_state("job")
self:update_infotext()
end
@ -599,8 +610,13 @@ function working_villages.register_villager(product_name, def)
local job = working_villages.registered_jobs[job_name]
self:set_state("idle")
self.time_counters = {}
job.on_stop(self)
if job then
if type(job.on_stop)=="function" then
job.on_stop(self)
elseif type(job.jobfunc)=="function" then
self.job_thread = false
end
end
self:update_infotext()
end
end,
@ -619,11 +635,19 @@ function working_villages.register_villager(product_name, def)
local job = working_villages.registered_jobs[job_name]
if to_list == "job" then
job.on_start(self)
if type(job.on_start)=="function" then
job.on_start(self)
elseif type(job.jobfunc)=="function" then
self.job_thread = coroutine.create(job.jobfunc)
end
self:set_state("job")
elseif from_list == "job" then
self:set_state("idle")
job.on_stop(self)
if type(job.on_stop)=="function" then
job.on_stop(self)
elseif type(job.jobfunc)=="function" then
self.job_thread = false
end
end
self:update_infotext()
@ -686,17 +710,23 @@ function working_villages.register_villager(product_name, def)
text = self.nametag
}
self.object:setvelocity{x = 0, y = 0, z = 0}
self.object:setacceleration{x = 0, y = -10, z = 0}
local job = self:get_job()
if job ~= nil then
job.on_start(self)
if type(job.on_start)=="function" then
job.on_start(self)
elseif type(job.jobfunc)=="function" then
self.job_thread = coroutine.create(job.jobfunc)
end
self:set_state("job")
if self.pause == "resting" then
self:set_state("idle")
job.on_pause(self)
if type(job.on_pause)=="function" then
job.on_pause(self)
end
end
else
self.object:setvelocity{x = 0, y = 0, z = 0}
self.object:setacceleration{x = 0, y = -10, z = 0}
end
end
@ -777,7 +807,7 @@ function working_villages.register_villager(product_name, def)
physical = true,
visual = "mesh",
visual_size = {x = 1, y = 1},
collisionbox = {-0.25, -1, -0.25, 0.25, 0.75, 0.25},
collisionbox = {-0.25, 0, -0.25, 0.25, 1.75, 0.25},
is_visible = true,
makes_footstep_sound = true,
infotext = "",
@ -786,6 +816,7 @@ function working_villages.register_villager(product_name, def)
-- extra initial properties
pause = "active",
state = "job",
job_thread = false,
product_name = "",
manufacturing_number = -1,
owner_name = "",
@ -807,6 +838,9 @@ function working_villages.register_villager(product_name, def)
get_state = working_villages.villager.get_state,
set_state = working_villages.villager.set_state,
-- async methods.
goto = working_villages.villager.goto,
-- extra methods.
get_inventory = working_villages.villager.get_inventory,
get_job = working_villages.villager.get_job,
@ -826,6 +860,7 @@ function working_villages.register_villager(product_name, def)
move_main_to_wield = working_villages.villager.move_main_to_wield,
is_named = working_villages.villager.is_named,
is_near = working_villages.villager.is_near,
is_active = working_villages.villager.is_active,
has_item_in_main = working_villages.villager.has_item_in_main,
change_direction = working_villages.villager.change_direction,
change_direction_randomly = working_villages.villager.change_direction_randomly,

5
async_actions.lua Normal file
View File

@ -0,0 +1,5 @@
function working_villages.villager:goto(pos)
self.destination = pos
self:set_state("goto_dest")
coroutine.yield()
end

View File

@ -16,14 +16,18 @@ minetest.register_tool("working_villages:commanding_sceptre", {
if job ~= nil then
if luaentity.state == "idle" then
luaentity.pause = "active"
job.on_resume(luaentity)
if type(job.on_resume)=="function" then
job.on_resume(luaentity)
end
luaentity:set_state("job")
luaentity:update_infotext()
else
luaentity:set_state("idle")
luaentity.pause = "resting"
job.on_pause(luaentity)
if type(job.on_pause)=="function" then
job.on_pause(luaentity)
end
luaentity:update_infotext()
end
end

View File

@ -7,10 +7,15 @@ working_villages.register_state("job",{
return
end--]]
local job = self:get_job()
if job then
local job = self:get_job()
if not job then return end
if type(job.on_step)=="function" then
job.on_step(self, dtime)
elseif self.job_thread then
if coroutine.status(self.job_thread) == "suspended" then
coroutine.resume(self.job_thread, self)
end
end
end
})
@ -22,9 +27,11 @@ working_villages.register_state("goto_dest",{
self.destination=working_villages.pathfinder.get_ground_level(vector.round(self.destination))
end
local val_pos = working_villages.func.validate_pos(self.object:getpos())
--FIXME: doesn't seem to be right if villager is right below a roof
self.path = working_villages.pathfinder.get_reachable(val_pos,self.destination,self)
self:set_timer("goto_dest:find_path",0) -- find path interval
self:set_timer("goto_dest:change_dir",0)
self:set_timer("goto_dest:give_up",0)
if self.path == nil then
self.path = {self.destination}
end
@ -38,7 +45,17 @@ working_villages.register_state("goto_dest",{
if self:timer_exceeded("goto_dest:find_path",100) then
local val_pos = working_villages.func.validate_pos(self.object:getpos())
local path = working_villages.pathfinder.get_reachable(val_pos,self.destination,self)
if path ~= nil then
if path == nil then
self:count_timer("goto_dest:give_up")
if self:timer_exceeded("goto_dest:give_up",3) then
self.destination=vector.round(self.destination)
if working_villages.func.walkable_pos(self.destination) then
self.destination=working_villages.pathfinder.get_ground_level(vector.round(self.destination))
end
print("villager can't find path")
--FIXME: we ought to give up at this point
end
else
self.path = path
end
end