diff --git a/Makefile b/Makefile index a1c4f67..ac96b22 100644 --- a/Makefile +++ b/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/ diff --git a/mods/stm/build_order.lua b/mods/stm/build_order.lua index 0ac7fc1..561b4be 100644 --- a/mods/stm/build_order.lua +++ b/mods/stm/build_order.lua @@ -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 = , name = } +-- +-- 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 diff --git a/mods/stm/character.lua b/mods/stm/character.lua index c973b94..14ecc70 100644 --- a/mods/stm/character.lua +++ b/mods/stm/character.lua @@ -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 diff --git a/mods/stm/schematics/flatland.lua b/mods/stm/schematics/flatland.lua new file mode 100644 index 0000000..877936c --- /dev/null +++ b/mods/stm/schematics/flatland.lua @@ -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 \ No newline at end of file diff --git a/mods/stm/schematics/house.lua b/mods/stm/schematics/house.lua new file mode 100644 index 0000000..6de25ca --- /dev/null +++ b/mods/stm/schematics/house.lua @@ -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 diff --git a/mods/stm/tasks/establish_municipality.lua b/mods/stm/tasks/establish_municipality.lua index d4c0870..94ad47d 100644 --- a/mods/stm/tasks/establish_municipality.lua +++ b/mods/stm/tasks/establish_municipality.lua @@ -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) diff --git a/mods/stm/tasks/find_residence.lua b/mods/stm/tasks/find_residence.lua index fac92c1..72c7720 100644 --- a/mods/stm/tasks/find_residence.lua +++ b/mods/stm/tasks/find_residence.lua @@ -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 }) diff --git a/mods/stm/util.lua b/mods/stm/util.lua index d53a7e9..cd70d8b 100644 --- a/mods/stm/util.lua +++ b/mods/stm/util.lua @@ -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 = , name = }` +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()) \ No newline at end of file diff --git a/unittest/test_character.lua b/unittest/test_character.lua index 7249ec6..0ba2c6e 100644 --- a/unittest/test_character.lua +++ b/unittest/test_character.lua @@ -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 \ No newline at end of file