|
|
|
@ -1,3 +1,6 @@
|
|
|
|
|
local S = minetest.get_translator("schemedit")
|
|
|
|
|
local F = minetest.formspec_escape
|
|
|
|
|
|
|
|
|
|
local schemedit = {}
|
|
|
|
|
|
|
|
|
|
-- Directory delimeter fallback (normally comes from builtin)
|
|
|
|
@ -6,9 +9,14 @@ if not DIR_DELIM then
|
|
|
|
|
end
|
|
|
|
|
local export_path_full = table.concat({minetest.get_worldpath(), "schems"}, DIR_DELIM)
|
|
|
|
|
|
|
|
|
|
-- truncated export path so the server directory structure is not exposed publicly
|
|
|
|
|
local export_path_trunc = table.concat({S("<world path>"), "schems"}, DIR_DELIM)
|
|
|
|
|
|
|
|
|
|
local text_color = "#D79E9E"
|
|
|
|
|
local text_color_number = 0xD79E9E
|
|
|
|
|
|
|
|
|
|
local can_import = minetest.read_schematic ~= nil
|
|
|
|
|
|
|
|
|
|
schemedit.markers = {}
|
|
|
|
|
|
|
|
|
|
-- [local function] Renumber table
|
|
|
|
@ -175,8 +183,8 @@ end
|
|
|
|
|
-- The itemstack is updated in-place.
|
|
|
|
|
local function set_item_metadata(itemstack, prob, force_place)
|
|
|
|
|
local smeta = itemstack:get_meta()
|
|
|
|
|
local prob_desc = "\nProbability: "..(prob) or
|
|
|
|
|
smeta:get_string("schemedit_prob") or "Not Set"
|
|
|
|
|
local prob_desc = "\n"..S("Probability: @1", prob or
|
|
|
|
|
smeta:get_string("schemedit_prob") or S("Not Set"))
|
|
|
|
|
-- Update probability
|
|
|
|
|
if prob and prob >= 0 and prob < 255 then
|
|
|
|
|
smeta:set_string("schemedit_prob", tostring(prob))
|
|
|
|
@ -185,8 +193,8 @@ local function set_item_metadata(itemstack, prob, force_place)
|
|
|
|
|
prob_desc = ""
|
|
|
|
|
smeta:set_string("schemedit_prob", nil)
|
|
|
|
|
else
|
|
|
|
|
prob_desc = "\nProbability: "..(smeta:get_string("schemedit_prob") or
|
|
|
|
|
"Not Set")
|
|
|
|
|
prob_desc = "\n"..S("Probability: @1", smeta:get_string("schemedit_prob") or
|
|
|
|
|
S("Not Set"))
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- Update force place
|
|
|
|
@ -212,7 +220,7 @@ local function set_item_metadata(itemstack, prob, force_place)
|
|
|
|
|
|
|
|
|
|
local force_desc = ""
|
|
|
|
|
if smeta:get_string("schemedit_force_place") == "true" then
|
|
|
|
|
force_desc = "\n".."Force placement"
|
|
|
|
|
force_desc = "\n"..S("Force placement")
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
desc = desc..minetest.colorize(text_color, prob_desc..force_desc)
|
|
|
|
@ -225,10 +233,13 @@ end
|
|
|
|
|
---
|
|
|
|
|
--- Formspec Tabs
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
local import_btn = ""
|
|
|
|
|
if can_import then
|
|
|
|
|
import_btn = "button[0.5,2.5;6,1;import;"..F(S("Import schematic")).."]"
|
|
|
|
|
end
|
|
|
|
|
schemedit.add_form("main", {
|
|
|
|
|
tab = true,
|
|
|
|
|
caption = "Main",
|
|
|
|
|
caption = S("Main"),
|
|
|
|
|
get = function(self, pos, name)
|
|
|
|
|
local meta = minetest.get_meta(pos):to_table().fields
|
|
|
|
|
local strpos = minetest.pos_to_string(pos)
|
|
|
|
@ -236,38 +247,43 @@ schemedit.add_form("main", {
|
|
|
|
|
|
|
|
|
|
local border_button
|
|
|
|
|
if meta.schem_border == "true" and schemedit.markers[hashpos] then
|
|
|
|
|
border_button = "button[3.5,7.5;3,1;border;Hide border]"
|
|
|
|
|
border_button = "button[3.5,7.5;3,1;border;"..F(S("Hide border")).."]"
|
|
|
|
|
else
|
|
|
|
|
border_button = "button[3.5,7.5;3,1;border;Show border]"
|
|
|
|
|
border_button = "button[3.5,7.5;3,1;border;"..F(S("Show border")).."]"
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- TODO: Show information regarding volume, pos1, pos2, etc... in formspec
|
|
|
|
|
local xs, ys, zs = meta.x_size or 1, meta.y_size or 1, meta.z_size or 1
|
|
|
|
|
local size = {x=xs, y=ys, z=zs}
|
|
|
|
|
|
|
|
|
|
local form = [[
|
|
|
|
|
size[7,8]
|
|
|
|
|
label[0.5,-0.1;Position: ]]..strpos..[[]
|
|
|
|
|
label[3,-0.1;Owner: ]]..name..[[]
|
|
|
|
|
label[0.5,-0.1;]]..F(S("Position: @1", strpos))..[[]
|
|
|
|
|
label[3,-0.1;]]..F(S("Owner: @1", name))..[[]
|
|
|
|
|
label[0.5,0.4;]]..F(S("Schematic name: @1", meta.schem_name))..[[]
|
|
|
|
|
label[0.5,0.9;]]..F(S("Size: @1", minetest.pos_to_string(size)))..[[]
|
|
|
|
|
|
|
|
|
|
field[0.8,1;5,1;name;Schematic name:;]]..minetest.formspec_escape(meta.schem_name or "")..[[]
|
|
|
|
|
button[5.3,0.69;1.2,1;save_name;Save]
|
|
|
|
|
tooltip[save_name;Save schematic name]
|
|
|
|
|
field[0.8,2;5,1;name;]]..F(S("Schematic name:"))..[[;]]..F(meta.schem_name or "")..[[]
|
|
|
|
|
button[5.3,1.69;1.2,1;save_name;]]..F(S("OK"))..[[]
|
|
|
|
|
tooltip[save_name;]]..F(S("Save schematic name"))..[[]
|
|
|
|
|
field_close_on_enter[name;false]
|
|
|
|
|
|
|
|
|
|
button[0.5,1.5;6,1;export;Export schematic]
|
|
|
|
|
textarea[0.8,2.5;6.2,5;;The schematic will be exported as a .mts file and stored in]]..
|
|
|
|
|
"\n" .. export_path_full .. DIR_DELIM .. [[<name>.mts.;]
|
|
|
|
|
field[0.8,7;2,1;x;X size:;]]..meta.x_size..[[]
|
|
|
|
|
field[2.8,7;2,1;y;Y size:;]]..meta.y_size..[[]
|
|
|
|
|
field[4.8,7;2,1;z;Z size:;]]..meta.z_size..[[]
|
|
|
|
|
button[0.5,3.5;6,1;export;]]..F(S("Export schematic")).."]"..
|
|
|
|
|
import_btn..[[
|
|
|
|
|
textarea[0.8,4.5;6.2,5;;]]..F(S("Export/import path:\n@1",
|
|
|
|
|
export_path_trunc .. DIR_DELIM .. F(S("<name>"))..".mts"))..[[;]
|
|
|
|
|
field[0.8,7;2,1;x;]]..F(S("X size:"))..[[;]]..xs..[[]
|
|
|
|
|
field[2.8,7;2,1;y;]]..F(S("Y size:"))..[[;]]..ys..[[]
|
|
|
|
|
field[4.8,7;2,1;z;]]..F(S("Z size:"))..[[;]]..zs..[[]
|
|
|
|
|
field_close_on_enter[x;false]
|
|
|
|
|
field_close_on_enter[y;false]
|
|
|
|
|
field_close_on_enter[z;false]
|
|
|
|
|
|
|
|
|
|
button[0.5,7.5;3,1;save;Save size]
|
|
|
|
|
button[0.5,7.5;3,1;save;]]..F(S("Save size"))..[[]
|
|
|
|
|
]]..
|
|
|
|
|
border_button
|
|
|
|
|
if minetest.get_modpath("doc") then
|
|
|
|
|
form = form .. "image_button[6.4,-0.2;0.8,0.8;doc_button_icon_lores.png;doc;]" ..
|
|
|
|
|
"tooltip[doc;Help]"
|
|
|
|
|
"tooltip[doc;"..F(S("Help")).."]"
|
|
|
|
|
end
|
|
|
|
|
return form
|
|
|
|
|
end,
|
|
|
|
@ -276,6 +292,31 @@ schemedit.add_form("main", {
|
|
|
|
|
local meta = realmeta:to_table().fields
|
|
|
|
|
local hashpos = minetest.hash_node_position(pos)
|
|
|
|
|
|
|
|
|
|
-- Save size vector values
|
|
|
|
|
if (fields.x and fields.x ~= "") then
|
|
|
|
|
local x = tonumber(fields.x)
|
|
|
|
|
if x then
|
|
|
|
|
meta.x_size = math.max(x, 1)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
if (fields.y and fields.y ~= "") then
|
|
|
|
|
local y = tonumber(fields.y)
|
|
|
|
|
if y then
|
|
|
|
|
meta.y_size = math.max(y, 1)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
if (fields.z and fields.z ~= "") then
|
|
|
|
|
local z = tonumber(fields.z)
|
|
|
|
|
if z then
|
|
|
|
|
meta.z_size = math.max(z, 1)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- Save schematic name
|
|
|
|
|
if fields.name then
|
|
|
|
|
meta.schem_name = fields.name
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if fields.doc then
|
|
|
|
|
doc.show_entry(name, "nodes", "schemedit:creator", true)
|
|
|
|
|
return
|
|
|
|
@ -292,30 +333,6 @@ schemedit.add_form("main", {
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- Save size vector values
|
|
|
|
|
if (fields.save or fields.key_enter_field == "x" or
|
|
|
|
|
fields.key_enter_field == "y" or fields.key_enter_field == "z")
|
|
|
|
|
and (fields.x and fields.y and fields.z and fields.x ~= ""
|
|
|
|
|
and fields.y ~= "" and fields.z ~= "") then
|
|
|
|
|
local x, y, z = tonumber(fields.x), tonumber(fields.y), tonumber(fields.z)
|
|
|
|
|
|
|
|
|
|
if x then
|
|
|
|
|
meta.x_size = math.max(x, 1)
|
|
|
|
|
end
|
|
|
|
|
if y then
|
|
|
|
|
meta.y_size = math.max(y, 1)
|
|
|
|
|
end
|
|
|
|
|
if z then
|
|
|
|
|
meta.z_size = math.max(z, 1)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- Save schematic name
|
|
|
|
|
if fields.save_name or fields.key_enter_field == "name" and fields.name and
|
|
|
|
|
fields.name ~= "" then
|
|
|
|
|
meta.schem_name = fields.name
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- Export schematic
|
|
|
|
|
if fields.export and meta.schem_name and meta.schem_name ~= "" then
|
|
|
|
|
local pos1, pos2 = schemedit.size(pos)
|
|
|
|
@ -351,13 +368,98 @@ schemedit.add_form("main", {
|
|
|
|
|
|
|
|
|
|
if res then
|
|
|
|
|
minetest.chat_send_player(name, minetest.colorize("#00ff00",
|
|
|
|
|
"Exported schematic to "..filepath))
|
|
|
|
|
S("Exported schematic to @1", filepath)))
|
|
|
|
|
else
|
|
|
|
|
minetest.chat_send_player(name, minetest.colorize("red",
|
|
|
|
|
"Failed to export schematic to "..filepath))
|
|
|
|
|
S("Failed to export schematic to @1", filepath)))
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- Import schematic
|
|
|
|
|
if fields.import and meta.schem_name and meta.schem_name ~= "" then
|
|
|
|
|
if not minetest.get_player_privs(name).debug then
|
|
|
|
|
minetest.chat_send_player(name, minetest.colorize("red",
|
|
|
|
|
S("Insufficient privileges! You need the “debug” privilege to do this.")))
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if not can_import then
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
local pos1
|
|
|
|
|
local node = minetest.get_node(pos)
|
|
|
|
|
local path = export_path_full .. DIR_DELIM
|
|
|
|
|
|
|
|
|
|
local filepath = path..meta.schem_name..".mts"
|
|
|
|
|
local schematic = minetest.read_schematic(filepath, {write_yslice_prob="low"})
|
|
|
|
|
local success = false
|
|
|
|
|
|
|
|
|
|
if schematic then
|
|
|
|
|
meta.x_size = schematic.size.x
|
|
|
|
|
meta.y_size = schematic.size.y
|
|
|
|
|
meta.z_size = schematic.size.z
|
|
|
|
|
meta.slices = minetest.serialize(schematic.yslice_prob)
|
|
|
|
|
|
|
|
|
|
if node.param2 == 1 then
|
|
|
|
|
pos1 = vector.add(pos, {x=1,y=0,z=-meta.z_size+1})
|
|
|
|
|
elseif node.param2 == 2 then
|
|
|
|
|
pos1 = vector.add(pos, {x=-meta.x_size+1,y=0,z=-meta.z_size})
|
|
|
|
|
elseif node.param2 == 3 then
|
|
|
|
|
pos1 = vector.add(pos, {x=-meta.x_size,y=0,z=0})
|
|
|
|
|
else
|
|
|
|
|
pos1 = vector.add(pos, {x=0,y=0,z=1})
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local schematic_for_meta = table.copy(schematic)
|
|
|
|
|
-- Strip probability data for placement
|
|
|
|
|
schematic.yslice_prob = {}
|
|
|
|
|
for d=1, #schematic.data do
|
|
|
|
|
schematic.data[d].prob = nil
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- Place schematic
|
|
|
|
|
success = minetest.place_schematic(pos1, schematic, "0", nil, true)
|
|
|
|
|
|
|
|
|
|
-- Add special schematic data to nodes
|
|
|
|
|
if success then
|
|
|
|
|
local d = 1
|
|
|
|
|
for z=0, meta.z_size-1 do
|
|
|
|
|
for y=0, meta.y_size-1 do
|
|
|
|
|
for x=0, meta.x_size-1 do
|
|
|
|
|
local data = schematic_for_meta.data[d]
|
|
|
|
|
local pp = {x=pos1.x+x, y=pos1.y+y, z=pos1.z+z}
|
|
|
|
|
if data.prob == 0 then
|
|
|
|
|
minetest.set_node(pp, {name="schemedit:void"})
|
|
|
|
|
else
|
|
|
|
|
local meta = minetest.get_meta(pp)
|
|
|
|
|
if data.prob and data.prob ~= 255 and data.prob ~= 254 then
|
|
|
|
|
meta:set_string("schemedit_prob", tostring(data.prob))
|
|
|
|
|
else
|
|
|
|
|
meta:set_string("schemedit_prob", "")
|
|
|
|
|
end
|
|
|
|
|
if data.force_place then
|
|
|
|
|
meta:set_string("schemedit_force_place", "true")
|
|
|
|
|
else
|
|
|
|
|
meta:set_string("schemedit_force_place", "")
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
d = d + 1
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
if success then
|
|
|
|
|
minetest.chat_send_player(name, minetest.colorize("#00ff00",
|
|
|
|
|
S("Imported schematic from @1", filepath)))
|
|
|
|
|
else
|
|
|
|
|
minetest.chat_send_player(name, minetest.colorize("red",
|
|
|
|
|
S("Failed to import schematic from @1", filepath)))
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- Save meta before updating visuals
|
|
|
|
|
local inv = realmeta:get_inventory():get_lists()
|
|
|
|
|
realmeta:from_table({fields = meta, inventory = inv})
|
|
|
|
@ -375,7 +477,7 @@ schemedit.add_form("main", {
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
schemedit.add_form("slice", {
|
|
|
|
|
caption = "Y Slices",
|
|
|
|
|
caption = S("Y Slices"),
|
|
|
|
|
tab = true,
|
|
|
|
|
get = function(self, pos, name, visible_panel)
|
|
|
|
|
local meta = minetest.get_meta(pos):to_table().fields
|
|
|
|
@ -385,8 +487,8 @@ schemedit.add_form("slice", {
|
|
|
|
|
local slice_list = minetest.deserialize(meta.slices)
|
|
|
|
|
local slices = ""
|
|
|
|
|
for _, i in pairs(slice_list) do
|
|
|
|
|
local insert = "Y = "..tostring(i.ypos).."; Probability = "..tostring(i.prob)
|
|
|
|
|
slices = slices..minetest.formspec_escape(insert)..","
|
|
|
|
|
local insert = F(S("Y = @1; Probability = @2", tostring(i.ypos), tostring(i.prob)))
|
|
|
|
|
slices = slices..insert..","
|
|
|
|
|
end
|
|
|
|
|
slices = slices:sub(1, -2) -- Remove final comma
|
|
|
|
|
|
|
|
|
@ -397,9 +499,9 @@ schemedit.add_form("slice", {
|
|
|
|
|
|
|
|
|
|
if self.panel_add or self.panel_edit then
|
|
|
|
|
local ypos_default, prob_default = "", ""
|
|
|
|
|
local done_button = "button[5,7.18;2,1;done_add;Done]"
|
|
|
|
|
local done_button = "button[5,7.18;2,1;done_add;"..F(S("Done")).."]"
|
|
|
|
|
if self.panel_edit then
|
|
|
|
|
done_button = "button[5,7.18;2,1;done_edit;Done]"
|
|
|
|
|
done_button = "button[5,7.18;2,1;done_edit;"..F(S("Done")).."]"
|
|
|
|
|
if slice_list[self.selected] then
|
|
|
|
|
ypos_default = slice_list[self.selected].ypos
|
|
|
|
|
prob_default = slice_list[self.selected].prob
|
|
|
|
@ -407,27 +509,27 @@ schemedit.add_form("slice", {
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
form = form..[[
|
|
|
|
|
field[0.3,7.5;2.5,1;ypos;Y position (max. ]]..(meta.y_size - 1)..[[):;]]..ypos_default..[[]
|
|
|
|
|
field[2.8,7.5;2.5,1;prob;Probability (0-255):;]]..prob_default..[[]
|
|
|
|
|
field[0.3,7.5;2.5,1;ypos;]]..F(S("Y position (max. @1):", (meta.y_size - 1)))..[[;]]..ypos_default..[[]
|
|
|
|
|
field[2.8,7.5;2.5,1;prob;]]..F(S("Probability (0-255):"))..[[;]]..prob_default..[[]
|
|
|
|
|
field_close_on_enter[ypos;false]
|
|
|
|
|
field_close_on_enter[prob;false]
|
|
|
|
|
]]..done_button
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if not self.panel_edit then
|
|
|
|
|
form = form.."button[0,6;2,1;add;+ Add slice]"
|
|
|
|
|
form = form.."button[0,6;2.4,1;add;"..F(S("+ Add slice")).."]"
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if slices ~= "" and self.selected and not self.panel_add then
|
|
|
|
|
if not self.panel_edit then
|
|
|
|
|
form = form..[[
|
|
|
|
|
button[2,6;2,1;remove;- Remove slice]
|
|
|
|
|
button[4,6;2,1;edit;+/- Edit slice]
|
|
|
|
|
button[2.4,6;2.4,1;remove;]]..F(S("- Remove slice"))..[[]
|
|
|
|
|
button[4.8,6;2.4,1;edit;]]..F(S("+/- Edit slice"))..[[]
|
|
|
|
|
]]
|
|
|
|
|
else
|
|
|
|
|
form = form..[[
|
|
|
|
|
button[2,6;2,1;remove;- Remove slice]
|
|
|
|
|
button[4,6;2,1;edit;+/- Edit slice]
|
|
|
|
|
button[2.4,6;2.4,1;remove;]]..F(S("- Remove slice"))..[[]
|
|
|
|
|
button[4.8,6;2.4,1;edit;]]..F(S("+/- Edit slice"))..[[]
|
|
|
|
|
]]
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
@ -497,7 +599,7 @@ schemedit.add_form("slice", {
|
|
|
|
|
|
|
|
|
|
schemedit.add_form("probtool", {
|
|
|
|
|
cache_name = false,
|
|
|
|
|
caption = "Schematic Node Probability Tool",
|
|
|
|
|
caption = S("Schematic Node Probability Tool"),
|
|
|
|
|
get = function(self, pos, name)
|
|
|
|
|
local player = minetest.get_player_by_name(name)
|
|
|
|
|
if not player then
|
|
|
|
@ -519,13 +621,13 @@ schemedit.add_form("probtool", {
|
|
|
|
|
force_place = "false"
|
|
|
|
|
end
|
|
|
|
|
local form = "size[5,4]"..
|
|
|
|
|
"label[0,0;Schematic Node Probability Tool]"..
|
|
|
|
|
"field[0.75,1;4,1;prob;Probability (0-255);"..prob.."]"..
|
|
|
|
|
"checkbox[0.60,1.5;force_place;Force placement;" .. force_place .. "]" ..
|
|
|
|
|
"button_exit[0.25,3;2,1;cancel;Cancel]"..
|
|
|
|
|
"button_exit[2.75,3;2,1;submit;Apply]"..
|
|
|
|
|
"tooltip[prob;Probability that the node will be placed]"..
|
|
|
|
|
"tooltip[force_place;If enabled, the node will replace nodes other than air and ignore]"..
|
|
|
|
|
"label[0,0;"..F(S("Schematic Node Probability Tool")).."]"..
|
|
|
|
|
"field[0.75,1;4,1;prob;"..F(S("Probability (0-255)"))..";"..prob.."]"..
|
|
|
|
|
"checkbox[0.60,1.5;force_place;"..F(S("Force placement"))..";" .. force_place .. "]" ..
|
|
|
|
|
"button_exit[0.25,3;2,1;cancel;"..F(S("Cancel")).."]"..
|
|
|
|
|
"button_exit[2.75,3;2,1;submit;"..F(S("Apply")).."]"..
|
|
|
|
|
"tooltip[prob;"..F(S("Probability that the node will be placed")).."]"..
|
|
|
|
|
"tooltip[force_place;"..F(S("If enabled, the node will replace nodes other than air and ignore")).."]"..
|
|
|
|
|
"field_close_on_enter[prob;false]"
|
|
|
|
|
return form
|
|
|
|
|
end,
|
|
|
|
@ -546,6 +648,9 @@ schemedit.add_form("probtool", {
|
|
|
|
|
|
|
|
|
|
set_item_metadata(probtool, prob, force_place)
|
|
|
|
|
|
|
|
|
|
-- Repurpose the tool's wear bar to display the set probability
|
|
|
|
|
probtool:set_wear(math.floor(((255-prob)/255)*65535))
|
|
|
|
|
|
|
|
|
|
player:set_wielded_item(probtool)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
@ -642,7 +747,7 @@ function schemedit.mark(pos)
|
|
|
|
|
local marker = minetest.add_entity({x = pos1.x + sizex - 0.5, y = pos1.y + sizey - 0.5, z = z + offset}, "schemedit:display")
|
|
|
|
|
if marker ~= nil then
|
|
|
|
|
marker:set_properties({
|
|
|
|
|
visual_size={x=(sizex+0.01) * 2, y=sizey * 2},
|
|
|
|
|
visual_size={x=(sizex+0.01) * 2, y=(sizey+0.01) * 2},
|
|
|
|
|
})
|
|
|
|
|
marker:get_luaentity().id = id
|
|
|
|
|
marker:get_luaentity().owner = owner
|
|
|
|
@ -663,9 +768,9 @@ function schemedit.mark(pos)
|
|
|
|
|
local marker = minetest.add_entity({x = x + offset, y = pos1.y + sizey - 0.5, z = pos1.z + sizez - 0.5}, "schemedit:display")
|
|
|
|
|
if marker ~= nil then
|
|
|
|
|
marker:set_properties({
|
|
|
|
|
visual_size={x=(sizez+0.01) * 2, y=sizey * 2},
|
|
|
|
|
visual_size={x=(sizez+0.01) * 2, y=(sizey+0.01) * 2},
|
|
|
|
|
})
|
|
|
|
|
marker:set_yaw(math.pi / 2)
|
|
|
|
|
marker:set_rotation({x=0, y=math.pi / 2, z=0})
|
|
|
|
|
marker:get_luaentity().id = id
|
|
|
|
|
marker:get_luaentity().owner = owner
|
|
|
|
|
table.insert(m, marker)
|
|
|
|
@ -673,6 +778,30 @@ function schemedit.mark(pos)
|
|
|
|
|
low = false
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
low = true
|
|
|
|
|
-- XZ plane markers
|
|
|
|
|
for _, y in ipairs({pos1.y - 0.5, pos2.y + 0.5}) do
|
|
|
|
|
if low then
|
|
|
|
|
offset = -0.01
|
|
|
|
|
else
|
|
|
|
|
offset = 0.01
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local marker = minetest.add_entity({x = pos1.x + sizex - 0.5, y = y + offset, z = pos1.z + sizez - 0.5}, "schemedit:display")
|
|
|
|
|
if marker ~= nil then
|
|
|
|
|
marker:set_properties({
|
|
|
|
|
visual_size={x=(sizex+0.01) * 2, y=(sizez+0.01) * 2},
|
|
|
|
|
})
|
|
|
|
|
marker:set_rotation({x=math.pi/2, y=0, z=0})
|
|
|
|
|
marker:get_luaentity().id = id
|
|
|
|
|
marker:get_luaentity().owner = owner
|
|
|
|
|
table.insert(m, marker)
|
|
|
|
|
end
|
|
|
|
|
low = false
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
schemedit.markers[id] = m
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
@ -697,12 +826,12 @@ end
|
|
|
|
|
-- Show probability and force_place status of a particular position for player in HUD.
|
|
|
|
|
-- Probability is shown as a number followed by “[F]” if the node is force-placed.
|
|
|
|
|
-- The distance to the node is also displayed below that. This can't be avoided and is
|
|
|
|
|
-- and artifact of the waypoint HUD element. TODO: Hide displayed distance.
|
|
|
|
|
-- and artifact of the waypoint HUD element.
|
|
|
|
|
function schemedit.display_node_prob(player, pos, prob, force_place)
|
|
|
|
|
local wpstring
|
|
|
|
|
if prob and force_place == true then
|
|
|
|
|
wpstring = string.format("%d [F]", prob)
|
|
|
|
|
elseif prob then
|
|
|
|
|
wpstring = string.format("%s [F]", prob)
|
|
|
|
|
elseif prob and type(tonumber(prob)) == "number" then
|
|
|
|
|
wpstring = prob
|
|
|
|
|
elseif force_place == true then
|
|
|
|
|
wpstring = "[F]"
|
|
|
|
@ -711,6 +840,7 @@ function schemedit.display_node_prob(player, pos, prob, force_place)
|
|
|
|
|
return player:hud_add({
|
|
|
|
|
hud_elem_type = "waypoint",
|
|
|
|
|
name = wpstring,
|
|
|
|
|
precision = 0,
|
|
|
|
|
text = "m", -- For the distance artifact
|
|
|
|
|
number = text_color_number,
|
|
|
|
|
world_pos = pos,
|
|
|
|
@ -723,7 +853,7 @@ end
|
|
|
|
|
-- But the boundaries can optionally be set explicitly with pos1 and pos2.
|
|
|
|
|
function schemedit.display_node_probs_region(player, pos1, pos2)
|
|
|
|
|
local playername = player:get_player_name()
|
|
|
|
|
local pos = vector.round(player:getpos())
|
|
|
|
|
local pos = vector.round(player:get_pos())
|
|
|
|
|
|
|
|
|
|
local dist = 5
|
|
|
|
|
-- Default: 5 nodes away from player in any direction
|
|
|
|
@ -747,7 +877,7 @@ function schemedit.display_node_probs_region(player, pos1, pos2)
|
|
|
|
|
|
|
|
|
|
local prob, force_place
|
|
|
|
|
local meta = minetest.get_meta(checkpos)
|
|
|
|
|
prob = tonumber(meta:get_string("schemedit_prob"))
|
|
|
|
|
prob = meta:get_string("schemedit_prob")
|
|
|
|
|
force_place = meta:get_string("schemedit_force_place") == "true"
|
|
|
|
|
local hud_id = schemedit.display_node_prob(player, checkpos, prob, force_place)
|
|
|
|
|
if hud_id then
|
|
|
|
@ -809,19 +939,25 @@ end)
|
|
|
|
|
|
|
|
|
|
-- [priv] schematic_override
|
|
|
|
|
minetest.register_privilege("schematic_override", {
|
|
|
|
|
description = "Allows you to access schemedit nodes not owned by you",
|
|
|
|
|
description = S("Allows you to access schemedit nodes not owned by you"),
|
|
|
|
|
give_to_singleplayer = false,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
local help_import = ""
|
|
|
|
|
if can_import then
|
|
|
|
|
help_import = S("Importing a schematic will load a schematic from the world directory, place it in front of the schematic creator and sets probability and force-place data accordingly.").."\n"
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- [node] Schematic creator
|
|
|
|
|
minetest.register_node("schemedit:creator", {
|
|
|
|
|
description = "Schematic Creator",
|
|
|
|
|
_doc_items_longdesc = "The schematic creator is used to save a region of the world into a schematic file (.mts).",
|
|
|
|
|
_doc_items_usagehelp = "To get started, place the block facing directly in front of any bottom left corner of the structure you want to save. This block can only be accessed by the placer or by anyone with the “schematic_override” privilege.".."\n"..
|
|
|
|
|
"To save a region, rightclick the block, enter the size, a schematic name and hit “Export schematic”. The file will always be saved in the world directory. Note you can use this name in the /placeschem command to place the schematic again.".."\n\n"..
|
|
|
|
|
"The other features of the schematic creator are optional and are used to allow to add randomness and fine-tuning.".."\n\n"..
|
|
|
|
|
"Y slices are used to remove entire slices based on chance. For each slice of the schematic region along the Y axis, you can specify that it occours only with a certain chance. In the Y slice tab, you have to specify the Y slice height (0 = bottom) and a probability from 0 to 255 (255 is for 100%). By default, all Y slices occour always.".."\n\n"..
|
|
|
|
|
"With a schematic node probability tool, you can set a probability for each node and enable them to overwrite all nodes when placed as schematic. This tool must be used prior to the file export.",
|
|
|
|
|
description = S("Schematic Creator"),
|
|
|
|
|
_doc_items_longdesc = S("The schematic creator is used to save a region of the world into a schematic file (.mts)."),
|
|
|
|
|
_doc_items_usagehelp = S("To get started, place the block facing directly in front of any bottom left corner of the structure you want to save. This block can only be accessed by the placer or by anyone with the “schematic_override” privilege.").."\n"..
|
|
|
|
|
S("To save a region, use the block, enter the size and a schematic name and hit “Export schematic”. The file will always be saved in the world directory. Note you can use this name in the /placeschem command to place the schematic again.").."\n\n"..
|
|
|
|
|
help_import..
|
|
|
|
|
S("The other features of the schematic creator are optional and are used to allow to add randomness and fine-tuning.").."\n\n"..
|
|
|
|
|
S("Y slices are used to remove entire slices based on chance. For each slice of the schematic region along the Y axis, you can specify that it occurs only with a certain chance. In the Y slice tab, you have to specify the Y slice height (0 = bottom) and a probability from 0 to 255 (255 is for 100%). By default, all Y slices occur always.").."\n\n"..
|
|
|
|
|
S("With a schematic node probability tool, you can set a probability for each node and enable them to overwrite all nodes when placed as schematic. This tool must be used prior to the file export."),
|
|
|
|
|
tiles = {"schemedit_creator_top.png", "schemedit_creator_bottom.png",
|
|
|
|
|
"schemedit_creator_sides.png"},
|
|
|
|
|
groups = { dig_immediate = 2},
|
|
|
|
@ -833,7 +969,7 @@ minetest.register_node("schemedit:creator", {
|
|
|
|
|
local meta = minetest.get_meta(pos)
|
|
|
|
|
|
|
|
|
|
meta:set_string("owner", name)
|
|
|
|
|
meta:set_string("infotext", "Schematic Creator\n(owned by "..name..")")
|
|
|
|
|
meta:set_string("infotext", S("Schematic Creator").."\n"..S("(owned by @1)", name))
|
|
|
|
|
meta:set_string("prob_list", minetest.serialize({}))
|
|
|
|
|
meta:set_string("slices", minetest.serialize({}))
|
|
|
|
|
|
|
|
|
@ -874,33 +1010,37 @@ minetest.register_node("schemedit:creator", {
|
|
|
|
|
after_destruct = function(pos)
|
|
|
|
|
schemedit.unmark(pos)
|
|
|
|
|
end,
|
|
|
|
|
|
|
|
|
|
-- No support for Minetest Game's screwdriver
|
|
|
|
|
on_rotate = false,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
minetest.register_tool("schemedit:probtool", {
|
|
|
|
|
description = "Schematic Node Probability Tool",
|
|
|
|
|
description = S("Schematic Node Probability Tool"),
|
|
|
|
|
_doc_items_longdesc =
|
|
|
|
|
"This is an advanced tool which only makes sense when used together with a schematic creator. It is used to finetune the way how nodes from a schematic are placed.".."\n"..
|
|
|
|
|
"It allows you to set two things:".."\n"..
|
|
|
|
|
"1) Set probability: Chance for any particular node to be actually placed (default: always placed)".."\n"..
|
|
|
|
|
"2) Enable force placement: These nodes replace node other than air and ignored when placed in a schematic (default: off)",
|
|
|
|
|
S("This is an advanced tool which only makes sense when used together with a schematic creator. It is used to finetune the way how nodes from a schematic are placed.").."\n"..
|
|
|
|
|
S("It allows you to set two things:").."\n"..
|
|
|
|
|
S("1) Set probability: Chance for any particular node to be actually placed (default: always placed)").."\n"..
|
|
|
|
|
S("2) Enable force placement: These nodes replace node other than air and ignore when placed in a schematic (default: off)"),
|
|
|
|
|
_doc_items_usagehelp = "\n"..
|
|
|
|
|
"BASIC USAGE:".."\n"..
|
|
|
|
|
"Punch to configure the tool. Select a probability (0-255; 255 is for 100%) and enable or disable force placement. Now place the tool on any node to apply these values to the node. This information is preserved in the node until it is destroyed or changed by the tool again. This tool has no effect on schematic voids.".."\n"..
|
|
|
|
|
"Now you can use a schematic creator to save a region as usual, the nodes will now be saved with the special node settings applied.".."\n\n"..
|
|
|
|
|
"NODE HUD:".."\n"..
|
|
|
|
|
"To help you remember the node values, the nodes with special values are labelled in the HUD. The first line shows probability and force placement (with “[F]”). The second line is the current distance to the node. Nodes with default settings and schematic voids are not labelled.".."\n"..
|
|
|
|
|
"To disable the node HUD, unselect the tool or hit “place” while not pointing anything.".."\n\n"..
|
|
|
|
|
"UPDATING THE NODE HUD:".."\n"..
|
|
|
|
|
"The node HUD is not updated automatically any may be outdated. The node HUD only updates the HUD for nodes close to you whenever you place the tool or press the punch and sneak keys simutanously. If you sneak-punch a schematic creator, then the node HUd is updated for all nodes within the schematic creator's region, even if this region is very big.",
|
|
|
|
|
S("BASIC USAGE:").."\n"..
|
|
|
|
|
S("Punch to configure the tool. Select a probability (0-255; 255 is for 100%) and enable or disable force placement. Now place the tool on any node to apply these values to the node. This information is preserved in the node until it is destroyed or changed by the tool again. This tool has no effect on schematic voids.").."\n"..
|
|
|
|
|
S("Now you can use a schematic creator to save a region as usual, the nodes will now be saved with the special node settings applied.").."\n\n"..
|
|
|
|
|
S("NODE HUD:").."\n"..
|
|
|
|
|
S("To help you remember the node values, the nodes with special values are labelled in the HUD. The first line shows probability and force placement (with “[F]”). The second line is the current distance to the node. Nodes with default settings and schematic voids are not labelled.").."\n"..
|
|
|
|
|
S("To disable the node HUD, unselect the tool or hit “place” while not pointing anything.").."\n\n"..
|
|
|
|
|
S("UPDATING THE NODE HUD:").."\n"..
|
|
|
|
|
S("The node HUD is not updated automatically and may be outdated. The node HUD only updates the HUD for nodes close to you whenever you place the tool or press the punch and sneak keys simutanously. If you sneak-punch a schematic creator, then the node HUD is updated for all nodes within the schematic creator's region, even if this region is very big."),
|
|
|
|
|
wield_image = "schemedit_probtool.png",
|
|
|
|
|
inventory_image = "schemedit_probtool.png",
|
|
|
|
|
liquids_pointable = true,
|
|
|
|
|
groups = { disable_repair = 1 },
|
|
|
|
|
on_use = function(itemstack, user, pointed_thing)
|
|
|
|
|
local ctrl = user:get_player_control()
|
|
|
|
|
-- Simple use
|
|
|
|
|
if not ctrl.sneak then
|
|
|
|
|
-- Open dialog to change the probability to apply to nodes
|
|
|
|
|
schemedit.show_formspec(user:getpos(), user, "probtool", true)
|
|
|
|
|
schemedit.show_formspec(user:get_pos(), user, "probtool", true)
|
|
|
|
|
|
|
|
|
|
-- Use + sneak
|
|
|
|
|
else
|
|
|
|
@ -910,7 +1050,7 @@ minetest.register_tool("schemedit:probtool", {
|
|
|
|
|
-- within the creator's region.
|
|
|
|
|
local use_creator_region = false
|
|
|
|
|
if pointed_thing and pointed_thing.type == "node" and pointed_thing.under then
|
|
|
|
|
punchpos = pointed_thing.under
|
|
|
|
|
local punchpos = pointed_thing.under
|
|
|
|
|
local node = minetest.get_node(punchpos)
|
|
|
|
|
if node.name == "schemedit:creator" then
|
|
|
|
|
local pos1, pos2 = schemedit.size(punchpos)
|
|
|
|
@ -969,9 +1109,9 @@ minetest.register_tool("schemedit:probtool", {
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
minetest.register_node("schemedit:void", {
|
|
|
|
|
description = "Schematic Void",
|
|
|
|
|
_doc_items_longdesc = "This is an utility block used in the creation of schematic files. It should be used together with a schematic creator. When saving a schematic, all nodes with a schematic void will be left unchanged when the schematic is placed again. Technically, this is equivalent to a block with the node probability set to 0.",
|
|
|
|
|
_doc_items_usagehelp = "Just place the schematic void like any other block and use the schematic creator to save a portion of the world.",
|
|
|
|
|
description = S("Schematic Void"),
|
|
|
|
|
_doc_items_longdesc = S("This is an utility block used in the creation of schematic files. It should be used together with a schematic creator. When saving a schematic, all nodes with a schematic void will be left unchanged when the schematic is placed again. Technically, this is equivalent to a block with the node probability set to 0."),
|
|
|
|
|
_doc_items_usagehelp = S("Just place the schematic void like any other block and use the schematic creator to save a portion of the world."),
|
|
|
|
|
tiles = { "schemedit_void.png" },
|
|
|
|
|
drawtype = "nodebox",
|
|
|
|
|
is_ground_content = false,
|
|
|
|
@ -992,8 +1132,10 @@ minetest.register_entity("schemedit:display", {
|
|
|
|
|
visual = "upright_sprite",
|
|
|
|
|
textures = {"schemedit_border.png"},
|
|
|
|
|
visual_size = {x=10, y=10},
|
|
|
|
|
collisionbox = {0,0,0,0,0,0},
|
|
|
|
|
pointable = false,
|
|
|
|
|
physical = false,
|
|
|
|
|
static_save = false,
|
|
|
|
|
glow = minetest.LIGHT_MAX,
|
|
|
|
|
|
|
|
|
|
on_step = function(self, dtime)
|
|
|
|
|
if not self.id then
|
|
|
|
@ -1007,25 +1149,35 @@ minetest.register_entity("schemedit:display", {
|
|
|
|
|
end,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
minetest.register_lbm({
|
|
|
|
|
label = "Reset schematic creator border entities",
|
|
|
|
|
name = "schemedit:reset_border",
|
|
|
|
|
nodenames = "schemedit:creator",
|
|
|
|
|
run_at_every_load = true,
|
|
|
|
|
action = function(pos, node)
|
|
|
|
|
local meta = minetest.get_meta(pos)
|
|
|
|
|
meta:set_string("schem_border", "false")
|
|
|
|
|
end,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
-- [chatcommand] Place schematic
|
|
|
|
|
minetest.register_chatcommand("placeschem", {
|
|
|
|
|
description = "Place schematic at the position specified or the current "..
|
|
|
|
|
"player position (loaded from "..export_path_full..".",
|
|
|
|
|
description = S("Place schematic at the position specified or the current player position (loaded from @1)", export_path_trunc),
|
|
|
|
|
privs = {debug = true},
|
|
|
|
|
params = "<schematic name>[.mts] [<x> <y> <z>]",
|
|
|
|
|
params = S("<schematic name>[.mts] [<x> <y> <z>]"),
|
|
|
|
|
func = function(name, param)
|
|
|
|
|
local schem, p = string.match(param, "^([^ ]+) *(.*)$")
|
|
|
|
|
local pos = minetest.string_to_pos(p)
|
|
|
|
|
|
|
|
|
|
if not schem then
|
|
|
|
|
return false, "No schematic file specified."
|
|
|
|
|
return false, S("No schematic file specified.")
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if not pos then
|
|
|
|
|
pos = minetest.get_player_by_name(name):get_pos()
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- Automatiically add file name suffix if omitted
|
|
|
|
|
-- Automatically add file name suffix if omitted
|
|
|
|
|
local schem_full
|
|
|
|
|
if string.sub(schem, string.len(schem)-3, string.len(schem)) == ".mts" then
|
|
|
|
|
schem_full = schem
|
|
|
|
@ -1033,10 +1185,23 @@ minetest.register_chatcommand("placeschem", {
|
|
|
|
|
schem_full = schem .. ".mts"
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local success = minetest.place_schematic(pos, export_path_full .. DIR_DELIM .. schem_full, "random", nil, false)
|
|
|
|
|
local success = false
|
|
|
|
|
local schem_path = export_path_full .. DIR_DELIM .. schem_full
|
|
|
|
|
if minetest.read_schematic then
|
|
|
|
|
-- We don't call minetest.place_schematic with the path name directly because
|
|
|
|
|
-- this would trigger the caching and we wouldn't get any updates to the schematic
|
|
|
|
|
-- files when we reload. minetest.read_schematic circumvents that.
|
|
|
|
|
local schematic = minetest.read_schematic(schem_path, {})
|
|
|
|
|
if schematic then
|
|
|
|
|
success = minetest.place_schematic(pos, schematic, "random", nil, false)
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
-- Legacy support for Minetest versions that do not have minetest.read_schematic
|
|
|
|
|
success = minetest.place_schematic(schem_path, schematic, "random", nil, false)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if success == nil then
|
|
|
|
|
return false, "Schematic file could not be loaded!"
|
|
|
|
|
return false, S("Schematic file could not be loaded!")
|
|
|
|
|
else
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|