clean up buildorder.create interface
parent
9f6237edf1
commit
0947d91ae8
4
Makefile
4
Makefile
|
@ -6,7 +6,7 @@ test:
|
|||
lua ./unittest/run.lua
|
||||
|
||||
doc:
|
||||
ldoc -f markdown -a mods/vxl/
|
||||
ldoc -f markdown -a mods/stm/
|
||||
|
||||
check:
|
||||
luacheck mods/vxl/
|
||||
luacheck mods/stm/
|
||||
|
|
|
@ -14,24 +14,41 @@ end)
|
|||
local TASK_TIMEOUT = 3 * stm.TIME_SCALE
|
||||
|
||||
--- Creates a build order from a schematic function.
|
||||
-- @param min vector for the bounding rectangle's min point
|
||||
-- @param max vector for the bounding rectangle's max point
|
||||
-- @param fn callback function taking arguments `(x,y,z)` and returning a
|
||||
-- string such as "default:dirt" or "air"
|
||||
-- @param bounding rectangle's min point
|
||||
-- @param rectangle's max point
|
||||
-- @param spec function, table, or string describing the nodes to be set
|
||||
-- during construction.
|
||||
-- If `spec` is a string it must be a filename relative to /schematics/.
|
||||
-- If the file ends in .lua, the file is evaluated with dofile and its result
|
||||
-- is expected to be one of the other supported spec types (a function or
|
||||
-- table).
|
||||
--
|
||||
-- If `spec` is a table it is assumed to have values of the following form,
|
||||
-- specifying positions and node names for the build order:
|
||||
--
|
||||
-- { pos = <vector>, name = <string> }
|
||||
--
|
||||
-- If `spec` is a function, it must take arguments of the form `(min, max)`, where:
|
||||
--
|
||||
-- - `min` is the minimum position of the build order in world coords
|
||||
-- - `max` is the maximum position of the build order in world coords
|
||||
-- - the function is expected to return a table as described above
|
||||
-- @return the newly created BuildOrder
|
||||
function BuildOrder.create(min, max, fn)
|
||||
function BuildOrder.create(min, max, spec)
|
||||
local result = BuildOrder.new()
|
||||
if type(spec) == 'string' then
|
||||
spec = dofile(stm.base_path .. "/schematics/" .. spec)
|
||||
end
|
||||
|
||||
if type(spec) == 'function' then
|
||||
spec = spec(min,max)
|
||||
end
|
||||
|
||||
result.min = min
|
||||
result.max = max
|
||||
for x = min.x,max.x do
|
||||
for y = min.y,max.y do
|
||||
for z = min.z,max.z do
|
||||
local name = fn(x,y,z)
|
||||
if name then
|
||||
result:push(vector.new(x,y,z), name)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- TODO: truncate spec to given min/max extents?
|
||||
for k,v in pairs(spec) do
|
||||
result:push(v.pos, v.name)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
|
|
@ -51,6 +51,7 @@ function Character:simulate(dt)
|
|||
if not ok then
|
||||
print('error performing task', err)
|
||||
stm.dump(self.tasks)
|
||||
assert(false)
|
||||
end
|
||||
self:update_physics(dt)
|
||||
end
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
return function(min,max)
|
||||
local build_fn = function(x,y,z)
|
||||
if y >= min.y then return 'air' end
|
||||
return 'default:dirt'
|
||||
end
|
||||
|
||||
return stm.walk_aabb(min, max, build_fn)
|
||||
end
|
|
@ -0,0 +1,23 @@
|
|||
return function(min,max)
|
||||
local build_fn = function(x,y,z)
|
||||
if x == min.x or x == max.x or
|
||||
y == max.y or
|
||||
z == min.z or z == max.z
|
||||
then
|
||||
return "air"
|
||||
elseif
|
||||
x == min.x+1 or x == max.x-1 or
|
||||
y == max.y-1 or
|
||||
z == min.z+1 or z == max.z-1
|
||||
then
|
||||
local midx = math.floor(min.x + (max.x - min.x)*.5)
|
||||
local midz = math.floor(min.z + (max.z - min.z)*.5)
|
||||
if x == midx and z > midz and y <= min.y + 1 then
|
||||
return "air"
|
||||
end
|
||||
return "default:stone"
|
||||
end
|
||||
return "air"
|
||||
end
|
||||
return stm.walk_aabb(min, max, build_fn)
|
||||
end
|
|
@ -32,18 +32,13 @@ return {
|
|||
|
||||
-- found a good spot
|
||||
local loc = Location.new({ type = Location.TYPE_MUNICIPALITY })
|
||||
loc.pos = MapData.get_surface_pos(pos)
|
||||
loc.pos = vector.new(pos.x, y_min, pos.z)
|
||||
loc.min = vector.new(pos.x - size, y_min, pos.z - size)
|
||||
loc.max = vector.new(pos.x + size, y_max, pos.z + size)
|
||||
Location.register(loc)
|
||||
|
||||
local build_fn = function(x,y,z)
|
||||
if y >= loc.pos.y then return 'air' end
|
||||
return 'default:dirt'
|
||||
end
|
||||
|
||||
-- create initial build orders for this location
|
||||
local order = BuildOrder.create(loc.min, loc.max, build_fn)
|
||||
local order = BuildOrder.create(loc.min, loc.max, 'flatland.lua')
|
||||
BuildOrder.register(order)
|
||||
loc:add_order(order)
|
||||
|
||||
|
|
|
@ -23,10 +23,6 @@ return {
|
|||
end
|
||||
|
||||
char.municipality = loc.id
|
||||
char:push_task('move', { dest = loc:get_position(), distance = 5 })
|
||||
state.state = MOVE
|
||||
|
||||
elseif state.state == MOVE then
|
||||
state.state = REQUEST_LOCATION
|
||||
|
||||
elseif state.state == REQUEST_LOCATION then
|
||||
|
@ -43,29 +39,11 @@ return {
|
|||
if not residence then return false end
|
||||
residence.type = Location.TYPE_RESIDENCE
|
||||
char.residence = residence.id
|
||||
char:push_task('move', { dest = residence:get_position() })
|
||||
state.state = ENQUEUE_RESIDENCE
|
||||
|
||||
elseif state.state == ENQUEUE_RESIDENCE then
|
||||
local residence = Location.get(char.residence)
|
||||
local order = BuildOrder.create(residence.min, residence.max, function(x,y,z)
|
||||
if x == residence.min.x or x == residence.max.x or
|
||||
y == residence.max.y or
|
||||
z == residence.min.z or z == residence.max.z
|
||||
then
|
||||
return "air"
|
||||
elseif
|
||||
x == residence.min.x+1 or x == residence.max.x-1 or
|
||||
y == residence.max.y-1 or
|
||||
z == residence.min.z+1 or z == residence.max.z-1
|
||||
then
|
||||
if x == residence.pos.x and z > residence.pos.z and y <= residence.min.y + 1 then
|
||||
return "air"
|
||||
end
|
||||
return "default:stone"
|
||||
end
|
||||
return "air"
|
||||
end)
|
||||
local order = BuildOrder.create(residence.min, residence.max, 'house.lua')
|
||||
|
||||
BuildOrder.register(order)
|
||||
char:push_task("build_lazily", { order = order.id })
|
||||
|
|
|
@ -126,4 +126,30 @@ function stm.count_pairs(t)
|
|||
return result
|
||||
end
|
||||
|
||||
--- Iterates over all integer positions between `a` and `b`, applying `fn`
|
||||
-- @param a min extents of the aabb
|
||||
-- @param b max extents of the aabb
|
||||
-- @param fn callback function taking arguments `(x,y,z)` and returning a string
|
||||
-- @return an array of tables where each element has the form `{ pos = <vector>, name = <result for that position> }`
|
||||
function stm.walk_aabb(a,b,fn)
|
||||
local result = { }
|
||||
for x = math.min(a.x,b.x),math.max(a.x,b.x),1 do
|
||||
for y = math.min(a.y,b.y),math.max(a.y,b.y),1 do
|
||||
for z = math.min(a.z,b.z),math.max(a.z,b.z),1 do
|
||||
local name = fn(x,y,z)
|
||||
if name then
|
||||
table.insert(result, { pos = vector.new(x,y,z), name = name })
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
if minetest then
|
||||
stm.base_path = minetest.get_modpath('stm')
|
||||
else
|
||||
stm.base_path = './mods/stm/'
|
||||
end
|
||||
|
||||
math.randomseed(os.time())
|
|
@ -101,5 +101,5 @@ function TestCharacter:testGravity()
|
|||
c:simulate(step)
|
||||
end
|
||||
|
||||
assert(math.abs(c.pos.y - 0.5) < 0.0001)
|
||||
assert(math.abs(c.pos.y - 0.5) < 0.015)
|
||||
end
|
Loading…
Reference in New Issue