diff --git a/init.lua b/init.lua index 385d3a1..459e63f 100644 --- a/init.lua +++ b/init.lua @@ -8,7 +8,6 @@ schemlib.node = dofile(modpath.."/node.lua") schemlib.mapping = dofile(modpath.."/mapping.lua") schemlib.worldedit_file = dofile(modpath.."/worldedit_file.lua") schemlib.save_restore = dofile(modpath.."/save_restore.lua") -schemlib.schematics = dofile(modpath.."/schematics.lua") schemlib.plan = dofile(modpath.."/plan.lua") schemlib.npc_ai = dofile(modpath.."/npc_ai.lua") diff --git a/plan.lua b/plan.lua index f58cd52..3424581 100644 --- a/plan.lua +++ b/plan.lua @@ -6,7 +6,7 @@ local dprint = print local mapping = schemlib.mapping local save_restore = schemlib.save_restore local modpath = schemlib.modpath -local schematics = schemlib.schematics +local node = schemlib.node -------------------------------------- -- Plan class @@ -321,18 +321,40 @@ end -- Generate a plan from schematics file -------------------------------------- function plan_class:read_from_schem_file(filename) - local file = save_restore.file_access(filename, "r") - if file == nil then - dprint("error: could not open file \"" .. filename .. "\"") - self.data = nil - else - -- different file types - if string.find(filename, '.mts', -4) then - self.data = schematics.analyze_mts_file(file) + + -- Minetest Schematics + if string.find(filename, '.mts', -4) then + local str = minetest.serialize_schematic(filename, "lua", {}) + if not str then + dprint("error: could not open file \"" .. filename .. "\"") + return end - if string.find(filename, '.we', -3) or string.find(filename, '.wem', -4) then - local newplan = schematics.analyze_we_file(file) - self.data = newplan.data + local schematic = loadstring(str.." return(schematic)")() + --[[ schematic.yslice_prob = {{ypos = 0,prob = 254},..} + schematic.size = { y = 18,x = 10, z = 18}, + schematic.data = {{param2 = 2,name = "default:tree",prob = 254},..} + ]] + + -- analyze the file + for i, ent in ipairs( schematic.data ) do + if ent.name ~= "air" then + ent.z = math.floor((i-1)/schematic.size.y/schematic.size.x) + ent.y = math.floor((i-1)/schematic.size.x) % schematic.size.y + ent.x = (i-1) % schematic.size.x + self:add_node(node.new(ent), true) + end + end + -- WorldEdit files + elseif string.find(filename, '.we', -3) or string.find(filename, '.wem', -4) then + local file = save_restore.file_access(filename, "r") + if not file then + dprint("error: could not open file \"" .. filename .. "\"") + return + end + local nodes = schemlib.worldedit_file.load_schematic(file:read("*a")) + -- analyze the file + for i, ent in ipairs( nodes ) do + self:add_node(node.new(ent), true) end end end diff --git a/schematics.lua b/schematics.lua deleted file mode 100644 index e12049c..0000000 --- a/schematics.lua +++ /dev/null @@ -1,184 +0,0 @@ - -local schematics = {} - -schematics.analyze_mts_file = function(file) ---[[ taken from src/mg_schematic.cpp: - Minetest Schematic File Format - - All values are stored in big-endian byte order. - [u32] signature: 'MTSM' - [u16] version: 3 - [u16] size X - [u16] size Y - [u16] size Z - For each Y: - [u8] slice probability value - [Name-ID table] Name ID Mapping Table - [u16] name-id count - For each name-id mapping: - [u16] name length - [u8[] ] name - ZLib deflated { - For each node in schematic: (for z, y, x) - [u16] content - For each node in schematic: - [u8] probability of occurance (param1) - For each node in schematic: - [u8] param2 - } - - Version changes: - 1 - Initial version - 2 - Fixed messy never/always place; 0 probability is now never, 0xFF is always - 3 - Added y-slice probabilities; this allows for variable height structures ---]] - --- taken from https://github.com/MirceaKitsune/minetest_mods_structures/blob/master/structures_io.lua (Taokis Sructures I/O mod) --- gets the size of a structure file --- nodeinfos: contains all the node names that are used in the schematic with count of occurence ({name_orig="abc:dcg",count=1}) - - local size = { x = 0, y = 0, z = 0, version = 0 } - local version = 0; - - -- thanks to sfan5 for this advanced code that reads the size from schematic files - local read_s16 = function(fi) - return string.byte(fi:read(1)) * 256 + string.byte(fi:read(1)) - end - - local function get_schematic_size(f) - -- make sure those are the first 4 characters, otherwise this might be a corrupt file - if f:read(4) ~= "MTSM" then - return nil - end - -- advance 2 more characters - local version = read_s16(f); --f:read(2) - -- the next characters here are our size, read them - return read_s16(f), read_s16(f), read_s16(f), version - end - - size.x, size.y, size.z, size.version = get_schematic_size(file) - - -- read the slice probability for each y value that was introduced in version 3 - if( size.version >= 3 ) then - -- the probability is not very intresting for buildings so we just skip it - file:read( size.y ) - end - - -- this list is not yet used for anything - local nodeinfos = {} - local ground_id = {} - local is_air = 0 - - -- after that: read_s16 (2 bytes) to find out how many diffrent nodenames (node_name_count) are present in the file - local node_name_count = read_s16( file ) - - for i = 1, node_name_count do - -- the length of the next name - local name_length = read_s16( file ) - -- the text of the next name - local name_text = file:read( name_length ) - nodeinfos[i] = { name_orig = name_text, count = 0 } - if string.sub(name_text, 1, 18) == "default:dirt_with_" or - name_text == "farming:soil_wet" then - ground_id[i] = true - elseif( name_text == 'air' ) then - is_air = i; - end - end - - -- decompression was recently added; if it is not yet present, we need to use normal place_schematic - if( minetest.decompress == nil) then - file.close(file); - return nil; -- normal place_schematic is no longer supported as minetest.decompress is now part of the release version of minetest - end - - local compressed_data = file:read( "*all" ); - local data_string = minetest.decompress(compressed_data, "deflate" ); - file.close(file) - - local p2offset = (size.x*size.y*size.z)*3; - local i = 1; - - local scm = {}; - local min_pos = {} - local max_pos = {} - local nodecount = 0 - local ground_y = -1 --if nothing defined, it is under the building - local groundnode_count = 0 - - for z = 1, size.z do - for y = 1, size.y do - for x = 1, size.x do - local id = string.byte( data_string, i ) * 256 + string.byte( data_string, i+1 ); - i = i + 2; - local p2 = string.byte( data_string, p2offset + math.floor(i/2)); - id = id+1; - if( id ~= is_air ) then - -- use node - if( not( scm[y] )) then - scm[y] = {}; - end - if( not( scm[y][x] )) then - scm[y][x] = {}; - end - scm[y][x][z] = {name_id = id, param2 = p2}; - nodecount = nodecount + 1 - nodeinfos[id].count = nodeinfos[id].count + 1 - - -- adjust position information - if not max_pos.x or x > max_pos.x then - max_pos.x = x - end - if not max_pos.y or y > max_pos.y then - max_pos.y = y - end - if not max_pos.z or z > max_pos.z then - max_pos.z = z - end - if not min_pos.x or x < min_pos.x then - min_pos.x = x - end - if not min_pos.y or y < min_pos.y then - min_pos.y = y - end - if not min_pos.z or z < min_pos.z then - min_pos.z = z - end - - -- calculate ground_y value - if ground_id[id] then - groundnode_count = groundnode_count + 1 - if groundnode_count == 1 then - ground_y = y - else - ground_y = ground_y + (y - ground_y) / groundnode_count - end - end - end - end - end - end - - return { min_pos = min_pos, -- minimal {x,y,z} vector - max_pos = max_pos, -- maximal {x,y,z} vector - nodeinfos = nodeinfos, -- nodeinfos[1] = {name_orig="abc:dcg",count=1} - scm_data_cache = scm, -- scm[y][x][z] = { name_id, ent.param2 } - nodecount = nodecount, -- integer, count - ground_y = ground_y } -- average ground high -end - - -schematics.analyze_we_file = function(file) - local node = schemlib.node - local plan = schemlib.plan - - local nodes = schemlib.worldedit_file.load_schematic(file:read("*a")) - -- analyze the file - local plan_obj = plan.new() - for i, ent in ipairs( nodes ) do - plan_obj:add_node(node.new(ent), true) - end - return plan_obj -end - -return schematics