added support for newer WorldEdit file format

- develpoed/tested with format version 5
- applying metadata, stored in newer WorldEdit format. So the direction of objects is right now
- more robust. unknown nodes ignored
- differentiation of nodes to place and items as payment. Sample: lrfurn:coffeetable_front is node to place, but lrfurn:coffeetable is item to pay
  (determinated by drop, if the node is masked in creative)
- nodes masked in creative and without drop are placed for free. So doors:hidden, lrfurn:coffeetable_back and other "multiblocks"/helpers will be placed as expected
  (but not in the right order because there is no relation to the door or the right coffeetable in data)
- Now you can just save a building using worldedit and move the file to the towntest_chest/buildings and it should work! I do not provide my sample because ist not pretty :(
master
Alexander Weber 2016-09-17 23:54:04 +02:00
parent 7a8c7fc5cd
commit ff7743ec27
1 changed files with 74 additions and 17 deletions

View File

@ -61,14 +61,62 @@ towntest_chest.load = function(filename)
return towntest_chest.get_string(building)
end
local function mapname(name)
local node = minetest.registered_items[name]
if not node then
minetest.log("info", "unknown node in building: "..name)
return nil
else
-- known node. Check for price or if it is free
if (node.groups.not_in_creative_inventory and not (node.groups.not_in_creative_inventory == 0)) or
(not node.description or node.description == "") then
if node.drop then
return mapname(node.drop) --use the drop as payment
else --something not supported, but known
return "free" -- will be build for free. they are something like doors:hidden or second part of coffee lrfurn:coffeetable_back
end
else
return node.name
end
end
end
-- get_table - convert building table to string
-- building_string - string containing pos and nodes to build
-- return - table containing pos and nodes to build
towntest_chest.get_table = function(building_string)
local building = {}
for x, y, z, name, param1, param2 in building_string:gmatch("([+-]?%d+)%s+([+-]?%d+)%s+([+-]?%d+)%s+([^%s]+)%s+(%d+)%s+(%d+)[^\r\n]*[\r\n]*") do
if tonumber(x)~=0 or tonumber(y)~=0 or tonumber(z)~=0 then
table.insert(building, {x=x,y=y,z=z,name=name,param1=param1,param2=param2})
local wefile = {}
local idx, def
local retpos = string.find(string.sub(building_string,0,10), "return")
if retpos then
local exe, err, ok
exe,err = loadstring(string.sub(building_string,retpos))
if exe then
ok, wefile = pcall(exe)
end
for idx,def in pairs(wefile) do
if tonumber(def.x)~=0 or tonumber(def.y)~=0 or tonumber(def.z)~=0 then
if not def.matname then
def.matname = mapname(def.name)
end
if def.matname then -- found
table.insert(building, {x=def.x,y=def.y,z=def.z,name=def.name,param1=def.param1,param2=def.param2,meta=def.meta,matname=def.matname})
end
end
end
else
for x, y, z, name, param1, param2 in building_string:gmatch("([+-]?%d+)%s+([+-]?%d+)%s+([+-]?%d+)%s+([^%s]+)%s+(%d+)%s+(%d+)[^\r\n]*[\r\n]*") do
if tonumber(x)~=0 or tonumber(y)~=0 or tonumber(z)~=0 then
local matname = mapname(name)
if def.matname then
table.insert(building, {x=x,y=y,z=z,name=name,param1=param1,param2=param2,matname=matname})
end
end
end
end
return building
@ -79,8 +127,8 @@ end
-- return - string containing pos and nodes to build
towntest_chest.get_string = function(building)
local building_string = ""
for i,v in ipairs(building) do
building_string = building_string..v.x.." "..v.y.." "..v.z.." "..v.name.." "..v.param1.." "..v.param2.."\n"
if building_string then
building_string = "return "..dump(building)
end
return building_string
end
@ -94,10 +142,12 @@ towntest_chest.update_needed = function(inv,building)
end
local materials = {}
for i,v in ipairs(building) do
if not materials[v.name] then
materials[v.name] = 1
else
materials[v.name] = materials[v.name]+1
if v.matname ~= "free" then --free materials will be built for free
if not materials[v.matname] then
materials[v.matname] = 1
else
materials[v.matname] = materials[v.matname]+1
end
end
end
for k,v in pairs(materials) do
@ -158,16 +208,23 @@ towntest_chest.build = function(chestpos)
for i,v in ipairs(building_plan) do
local pos = {x=v.x+chestpos.x,y=v.y+chestpos.y,z=v.z+chestpos.z}
-- check if the builder has the node
if inv:contains_item("builder", v.name) then
if inv:contains_item("builder", v.matname) or -- is payed or
-- for free and the item is at the end of building plan (all next items already built, to avoid all free items are placed at the first)
( v.matname == "free" and i == #building_plan )
then
-- check if npc is already moving
if npc and not npc.target then
table.remove(building_plan,i)
-- move the npc to the build area
npc:moveto({x=pos.x, y=pos.y+1.5, z=pos.z}, 2, 2, 0, function(self,after_param)
-- take from the inv
after_param.inv:remove_item("builder", after_param.v.name.." 1")
after_param.inv:remove_item("builder", after_param.v.matname.." 1")
-- add the node to the world
minetest.env:add_node(after_param.pos, {name=after_param.v.name,param1=after_param.v.param1,param2=after_param.v.param2})
if v.meta then
minetest.env:get_meta(after_param.pos):from_table(after_param.v.meta)
end
-- update the chest building_plan
meta:set_string("building_plan", towntest_chest.get_string(building_plan))
end, {pos=pos, v=v, inv=inv, meta=meta})
@ -180,7 +237,7 @@ towntest_chest.build = function(chestpos)
local items_needed = true
for i,v in ipairs(building_plan) do
-- check if the chest has the node
if inv:contains_item("main", v.name) then
if inv:contains_item("main", v.matname) then
items_needed = false
-- check if npc is already moving
if npc and not npc.target then
@ -195,11 +252,11 @@ towntest_chest.build = function(chestpos)
local stack = inv:get_stack("main", i)
if not stack:is_empty() then
local node = minetest.registered_nodes[stack:get_name()]
if node.name == "default:apple" then
if node and node.name == "default:apple" then
local quality = 1
npc.food = npc.food + (stack:get_count() * quality * 4)
inv:set_stack("main", i, nil)
elseif node.groups.food ~= nil then
elseif node and node.groups.food ~= nil then
local quality = 4 - node.groups.food
npc.food = npc.food + (stack:get_count() * quality * 4)
inv:set_stack("main", i, nil)
@ -209,9 +266,9 @@ towntest_chest.build = function(chestpos)
end
-- take from the inv
for i,v in ipairs(building_plan) do
if inv:contains_item("main",v.name.." 1") and inv:room_for_item("builder",v.name.." 1") then
inv:add_item("builder",inv:remove_item("main",v.name.." 1"))
inv:remove_item("needed", v.name.." 1")
if inv:contains_item("main",v.matname.." 1") and inv:room_for_item("builder",v.matname.." 1") then
inv:add_item("builder",inv:remove_item("main",v.matname.." 1"))
inv:remove_item("needed", v.matname.." 1")
end
end
end, {inv=inv,building_plan=building_plan})