ported mts reading to minetest.serialize_schematic. Moved the new small code to the plan methods
This commit is contained in:
parent
a1f8911e71
commit
9d1a40d632
1
init.lua
1
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")
|
||||
|
||||
|
46
plan.lua
46
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
|
||||
|
184
schematics.lua
184
schematics.lua
@ -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
|
Loading…
x
Reference in New Issue
Block a user