Compare commits
10 Commits
70eeedf85c
...
b34a5a0f30
Author | SHA1 | Date | |
---|---|---|---|
|
b34a5a0f30 | ||
|
751ed074f1 | ||
|
0a93d0a7f2 | ||
|
0317451cbb | ||
|
8a132c5d02 | ||
|
a3d561ddf8 | ||
|
28ede3cc26 | ||
|
f5beb59b54 | ||
|
314eae8754 | ||
|
85efb7d371 |
53
README.md
53
README.md
@ -1,7 +1,7 @@
|
||||
# Schematic Editor [`schemedit`]
|
||||
|
||||
## Version
|
||||
1.7.1
|
||||
1.8.0
|
||||
|
||||
## Description
|
||||
This is a mod which allows you to edit and export schematics (`.mts` files).
|
||||
@ -26,14 +26,57 @@ It also adds these server commands:
|
||||
|
||||
There's also a setting `schemedit_export_lua` to enable automatic export to .lua files.
|
||||
|
||||
## Usage help
|
||||
This mod assumes you already have a basic understanding about how schematics in Minetest work.
|
||||
If not, refer to the Minetest Lua API documentation to understand more about schematics.
|
||||
## Quick Start
|
||||
|
||||
To learn how to use all the items in this mod, read `USAGE.md`.
|
||||
### Creating a schematic
|
||||
|
||||
To create a schematic file:
|
||||
|
||||
1. Choose a cuboid area you like to used for a schematic
|
||||
2. Place a schematic creator in front of one of the bottom 4 corners of that area
|
||||
3. Use (rightclick) the schematic creator
|
||||
4. Enter a size and click on “Save size”
|
||||
5. Enter a schematic name and click on “Export schematic”
|
||||
|
||||
The schematic will be saved in your world directory; you’ll see the exact location in chat.
|
||||
|
||||
### Importing a schematic
|
||||
|
||||
You can import a schematic file for editing if it already exists in your world directory
|
||||
under `schems`. To import it:
|
||||
|
||||
1. Place a schematic creator on the ground
|
||||
2. Enter the schematic file name
|
||||
3. Click on “Import schematic”
|
||||
|
||||
This will put the schematic in the world and import advanced information like
|
||||
probabilities, force-placement, schematic voids.
|
||||
|
||||
### Placing a schematic
|
||||
|
||||
Use the `/placeschem` chat command to place a schematic as if it were placed by the game.
|
||||
This is useful to test a schematic to see the end result.
|
||||
|
||||
Use `/help placeschem` to get a list of parameters.
|
||||
|
||||
## Advanced usage
|
||||
|
||||
By default, if you export a schematic and then place it, every node will be placed,
|
||||
including air. This is because the air is exported, too. This is by design.
|
||||
|
||||
But you can place a special Schematic Void to mark positions that should not be overridden
|
||||
when the schematic is placed. This is very useful for trees.
|
||||
|
||||
You can also set probabilities for certain nodes to be placed, or tell the game to
|
||||
force-place nodes.
|
||||
|
||||
For detailed information read `USAGE.md`.
|
||||
|
||||
You can also find the same help texts in-game if you if you use the optional Help modpack
|
||||
(mods `doc` and `doc_items`).
|
||||
|
||||
For general information on how schematics work, please refer to the Minetest Lua API
|
||||
documentation.
|
||||
|
||||
## License of everything
|
||||
MIT License
|
||||
|
181
init.lua
181
init.lua
@ -353,6 +353,18 @@ local function set_item_metadata(itemstack, prob, force_place)
|
||||
return itemstack
|
||||
end
|
||||
|
||||
-- Forbid dir delimiters in schematic name,
|
||||
-- to avoid player accessing files outside of schems dir
|
||||
local function check_schem_name(schem_name)
|
||||
if string.match(schem_name, DIR_DELIM) or
|
||||
string.match(schem_name, "\\") or
|
||||
string.match(schem_name, "/") then
|
||||
return false
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
---
|
||||
--- Formspec Tabs
|
||||
---
|
||||
@ -453,6 +465,13 @@ schemedit.add_form("main", {
|
||||
meta.schem_name = fields.name
|
||||
end
|
||||
|
||||
-- Check schematic name for forbidden characters
|
||||
if not check_schem_name(meta.schem_name or "") then
|
||||
minetest.chat_send_player(name, minetest.colorize(TEXT_COLOR_ERROR,
|
||||
S("Schematic name contains a forbidden slash or backslash!")))
|
||||
meta.schem_name = nil
|
||||
end
|
||||
|
||||
-- Node conversion
|
||||
if (fields.air2void) then
|
||||
local pos1, pos2 = schemedit.size(pos)
|
||||
@ -937,7 +956,7 @@ function schemedit.mark(pos)
|
||||
local offset
|
||||
|
||||
-- XY plane markers
|
||||
for _, z in ipairs({pos1.z - 0.5, pos2.z + 0.5}) do
|
||||
for i, z in ipairs({pos1.z - 0.5, pos2.z + 0.5}) do
|
||||
if low then
|
||||
offset = -0.01
|
||||
else
|
||||
@ -945,8 +964,17 @@ function schemedit.mark(pos)
|
||||
end
|
||||
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
|
||||
local textures
|
||||
if i == 2 then
|
||||
if minetest.settings:get_bool("schemedit_highlight_north", true) then
|
||||
-- Highlight Northern side
|
||||
textures = marker:get_properties().textures
|
||||
textures[1] = "("..textures[1] .. ")^[brighten"
|
||||
end
|
||||
end
|
||||
marker:set_properties({
|
||||
visual_size={x=(sizex+0.01) * 2, y=(sizey+0.01) * 2},
|
||||
textures=textures,
|
||||
})
|
||||
marker:get_luaentity().id = id
|
||||
marker:get_luaentity().owner = owner
|
||||
@ -963,7 +991,6 @@ function schemedit.mark(pos)
|
||||
else
|
||||
offset = 0.01
|
||||
end
|
||||
|
||||
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({
|
||||
@ -1353,6 +1380,7 @@ minetest.register_node("schemedit:void", {
|
||||
|
||||
-- [entity] Visible schematic border
|
||||
minetest.register_entity("schemedit:display", {
|
||||
initial_properties = {
|
||||
visual = "upright_sprite",
|
||||
textures = {get_border_texture()},
|
||||
visual_size = {x=10, y=10},
|
||||
@ -1360,6 +1388,7 @@ minetest.register_entity("schemedit:display", {
|
||||
physical = false,
|
||||
static_save = false,
|
||||
glow = minetest.LIGHT_MAX,
|
||||
},
|
||||
|
||||
on_step = function(self, dtime)
|
||||
if not self.id then
|
||||
@ -1397,43 +1426,106 @@ local function add_suffix(schem)
|
||||
return schem_full, schem_lua
|
||||
end
|
||||
|
||||
-- [chatcommand] Place schematic
|
||||
minetest.register_chatcommand("placeschem", {
|
||||
description = S("Place schematic at the position specified or the current player position (loaded from @1). “-c” will clear the area first", export_path_trunc),
|
||||
privs = {server = true},
|
||||
params = S("<schematic name>[.mts] [-c] [<x> <y> <z>]"),
|
||||
func = function(name, param)
|
||||
local schem, clear, p = string.match(param, "^([^ ]+) +(%-c) *(.*)$")
|
||||
if not schem then
|
||||
schem, p = string.match(param, "^([^ ]+) *(.*)$")
|
||||
parse_command_arguments = function(arguments, relative_pos)
|
||||
if not relative_pos then
|
||||
relative_pos = vector.zero()
|
||||
end
|
||||
clear = clear == "-c"
|
||||
|
||||
local ppos = minetest.get_player_by_name(name):get_pos()
|
||||
|
||||
local pos
|
||||
if p and p ~= "" then
|
||||
local pp = string.split(p, " ")
|
||||
local nums = {}
|
||||
local arglist = string.split(arguments, " ")
|
||||
local flags = {
|
||||
clear = false,
|
||||
force_placement = false,
|
||||
rotate = "0",
|
||||
}
|
||||
local coords = {}
|
||||
local axes = { "x", "y", "z" }
|
||||
for a=1, #axes do
|
||||
local axis = axes[a]
|
||||
local parsed
|
||||
if minetest.parse_relative_number then
|
||||
parsed = minetest.parse_relative_number(pp[a], ppos[axis])
|
||||
else
|
||||
parsed = tonumber(ppos[axis])
|
||||
local coord_index = 1
|
||||
local previous_arg = nil
|
||||
local parsing_flags = true
|
||||
for a=1, #arglist do
|
||||
local arg = arglist[a]
|
||||
local relnum
|
||||
if coord_index <= 4 then
|
||||
relnum = minetest.parse_relative_number(arg, relative_pos[axes[coord_index]])
|
||||
end
|
||||
if not parsed then
|
||||
if previous_arg == "-r" then
|
||||
if arg == "0" or arg == "90" or arg == "180" or arg == "270" or arg == "random" then
|
||||
flags.rotate = arg
|
||||
else
|
||||
return false, S("Incorrect angle after “-r” flag. Allowed are “0”, “90”, “180”, “270” or “random”.")
|
||||
end
|
||||
elseif relnum then
|
||||
if coord_index > 3 then
|
||||
-- Too many coordinates!
|
||||
return false
|
||||
end
|
||||
table.insert(nums, parsed)
|
||||
end
|
||||
pos = vector.new(nums[1], nums[2], nums[3])
|
||||
parsing_flags = false
|
||||
table.insert(coords, relnum)
|
||||
coord_index = coord_index + 1
|
||||
else
|
||||
pos = ppos
|
||||
if parsing_flags then
|
||||
if previous_arg == "-r" then
|
||||
-- Error: Flag after "-r"
|
||||
return false
|
||||
end
|
||||
if arg == "-c" then
|
||||
flags.clear = true
|
||||
elseif arg == "-f" then
|
||||
flags.force_placement = true
|
||||
elseif arg == "-r" then
|
||||
flags.rotate = "pending"
|
||||
else
|
||||
-- Error: Unknown flag
|
||||
return false, S("Unknown flag “@1”. Use “/help placeschem” for a list of flags.", arg)
|
||||
end
|
||||
else
|
||||
-- Error: Something non-coordinate like-found in coordinate section
|
||||
return false
|
||||
end
|
||||
end
|
||||
previous_arg = arg
|
||||
end
|
||||
if #coords == 0 then
|
||||
coords = nil
|
||||
elseif #coords == 3 then
|
||||
coords = { x = coords[1], y = coords[2], z = coords[3] }
|
||||
else
|
||||
return false
|
||||
end
|
||||
if flags.rotate == "pending" then
|
||||
return false, S("No angle specified after “-r” flag.")
|
||||
end
|
||||
return flags, coords
|
||||
end
|
||||
|
||||
local flag_info = S("“-c”: clear area before placing; “-r <angle>”: set rotation to 0, 90, 180, 270 or random; “-f”: also replace nodes other than air and ignore")
|
||||
|
||||
-- [chatcommand] Place schematic
|
||||
minetest.register_chatcommand("placeschem", {
|
||||
description = S("Place schematic at the position specified or the current player position (loaded from @1). Available flags: @2.",
|
||||
export_path_trunc,
|
||||
flag_info),
|
||||
privs = {server = true},
|
||||
params = S("<schematic name>[.mts] [<flags>] [<x> <y> <z>]"),
|
||||
func = function(name, param)
|
||||
local schem, arguments = string.match(param, "^([^ ]+) *(.*)$")
|
||||
if not schem then
|
||||
return false
|
||||
end
|
||||
local ppos
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if player and player:is_player() then
|
||||
ppos = player:get_pos()
|
||||
end
|
||||
local flags, extra_info = parse_command_arguments(arguments, ppos)
|
||||
|
||||
if flags == false then
|
||||
return false, extra_info
|
||||
end
|
||||
|
||||
local pos = extra_info
|
||||
if not pos then
|
||||
pos = table.copy(ppos)
|
||||
end
|
||||
pos = vector.round(pos)
|
||||
|
||||
if not schem then
|
||||
@ -1449,14 +1541,25 @@ minetest.register_chatcommand("placeschem", {
|
||||
-- files when we reload. minetest.read_schematic circumvents that.
|
||||
local schematic = minetest.read_schematic(schem_path, {})
|
||||
if schematic then
|
||||
if clear then
|
||||
-- Clear same size for X and Z because
|
||||
-- because schematic is randomly rotated
|
||||
local max_xz = math.max(schematic.size.x, schematic.size.z)
|
||||
if flags.clear then
|
||||
local max_x, max_z
|
||||
if flags.rotate == "0" or flags.rotate == "180" then
|
||||
max_x = schematic.size.x
|
||||
max_z = schematic.size.z
|
||||
elseif flags.rotate == "90" or flags.rotate == "270" then
|
||||
max_x = schematic.size.z
|
||||
max_z = schematic.size.x
|
||||
elseif flags.rotate == "random" then
|
||||
-- Pick the maximum of both axes because we want
|
||||
-- to clear the *potential* area in which the
|
||||
-- randomly-rotated schematic might spawn.
|
||||
max_x = math.max(schematic.size.x, schematic.size.z)
|
||||
max_z = max_x
|
||||
end
|
||||
local posses = {}
|
||||
for z=pos.z, pos.z+max_xz-1 do
|
||||
for z=pos.z, pos.z+max_z-1 do
|
||||
for y=pos.y, pos.y+schematic.size.y-1 do
|
||||
for x=pos.x, pos.x+max_xz-1 do
|
||||
for x=pos.x, pos.x+max_x-1 do
|
||||
table.insert(posses, {x=x,y=y,z=z})
|
||||
end
|
||||
end
|
||||
@ -1464,13 +1567,13 @@ minetest.register_chatcommand("placeschem", {
|
||||
minetest.bulk_set_node(posses, {name="air"})
|
||||
end
|
||||
minetest.log("action", "[schemedit] Placing schematic '"..schem.."' at: "..minetest.pos_to_string(pos))
|
||||
success = minetest.place_schematic(pos, schematic, "random", nil, false)
|
||||
success = minetest.place_schematic(pos, schematic, flags.rotate, nil, flags.force_placement)
|
||||
end
|
||||
else
|
||||
-- Legacy support for Minetest versions that do not have minetest.read_schematic.
|
||||
-- Note: "-c" is ignored here.
|
||||
minetest.log("action", "[schemedit] Placing schematic '"..schem.."' at: "..minetest.pos_to_string(pos))
|
||||
success = minetest.place_schematic(schem_path, schematic, "random", nil, false)
|
||||
success = minetest.place_schematic(schem_path, schematic, flags.rotate, nil, flags.force_placement)
|
||||
end
|
||||
|
||||
if success == nil then
|
||||
|
@ -1,4 +1,6 @@
|
||||
# textdomain: schemedit
|
||||
Schematic Editor=Schematic-Editor
|
||||
Advanced tool for modders and advanced users to create and edit schematics.=Fortgeschrittenes Werkzeug für Modder und fortgeschrittene Benutzer, um Schematics zu erstellen und zu bearbeiten.
|
||||
<world path>=<Weltpfad>
|
||||
Insufficient privileges! You need the “@1” privilege to use this.=Unzureichende Privilegien! Sie benötigen das „@1“-Privileg, um dies benutzen zu können.
|
||||
Exported schematic to @1=Schematic nach @1 exportiert
|
||||
@ -29,6 +31,7 @@ Y size:=Y-Größe:
|
||||
Z size:=Z-Größe:
|
||||
Save size=Größe speichern
|
||||
Help=Hilfe
|
||||
Schematic name contains a forbidden slash or backslash!=Schematic-Name enthält einen verbotenen Schrägstrich oder Backslash!
|
||||
Could not emerge area from @1 to @2: Emerging was cancelled. Nothing was exported.=Gebiet von @1 zu @2 konnte nicht emergt werden: Emergen wurde abgebrochen. Nichts wurde exportiert.
|
||||
Could not emerge area from @1 to @2: Error while emerging. Nothing was exported.=Gebiet von @1 zu @2 konnte nicht emergt werden: Fehler beim Emergen. Nichts wurde exportiert.
|
||||
Could not emerge area from @1 to @2: Unknown action in emerge callback. Nothing was exported.=Gebiet von @1 zu @2 konnte nicht emergt werden: Unbekannte Aktion im Emerge-Callback. Nichts wurde exportiert.
|
||||
|
@ -1,4 +1,6 @@
|
||||
# textdomain: schemedit
|
||||
Schematic Editor=
|
||||
Advanced tool for modders and advanced users to create and edit schematics.=
|
||||
<world path>=
|
||||
Insufficient privileges! You need the “@1” privilege to use this.=
|
||||
Exported schematic to @1=
|
||||
@ -29,6 +31,7 @@ Y size:=
|
||||
Z size:=
|
||||
Save size=
|
||||
Help=
|
||||
Schematic name contains a forbidden slash or backslash!=
|
||||
Could not emerge area from @1 to @2: Emerging was cancelled. Nothing was exported.=
|
||||
Could not emerge area from @1 to @2: Error while emerging. Nothing was exported.=
|
||||
Could not emerge area from @1 to @2: Unknown action in emerge callback. Nothing was exported.=
|
||||
|
@ -6,3 +6,6 @@ schemedit_export_lua (.lua file schematic export) bool false
|
||||
# * edges: Show borders at the edges
|
||||
# * checkers: Checker pattern at the sides
|
||||
schemedit_border_style (Border style) enum edges edges,checkers
|
||||
|
||||
# If enabled, the Northern border marker will be brighter.
|
||||
schemedit_highlight_north (Highlight Northern border) bool true
|
||||
|
Loading…
x
Reference in New Issue
Block a user