Compare commits

...

10 Commits

Author SHA1 Message Date
Wuzzy
b34a5a0f30 Translate new dir delim error message 2024-07-27 11:16:20 +02:00
Wuzzy
751ed074f1 Forbid slash and backslash in schematic name 2024-07-27 11:12:57 +02:00
Wuzzy
0a93d0a7f2 Add translation of mod title and description 2024-07-26 11:53:19 +02:00
Wuzzy
0317451cbb Version 1.8.0 2023-12-24 01:19:49 +01:00
Wuzzy
8a132c5d02 Clear area with -c properly 2023-12-23 23:39:40 +01:00
Wuzzy
a3d561ddf8 Add new flags for /placeschem: -r and -f 2023-12-23 23:26:02 +01:00
Wuzzy
28ede3cc26 Highlight the Northern border by default 2023-12-23 21:08:37 +01:00
Wuzzy
f5beb59b54 Add initial_properties to entity 2023-12-23 20:30:58 +01:00
Wuzzy
314eae8754 Improve README 2023-12-23 20:27:00 +01:00
Wuzzy
85efb7d371 Add quick start instructions in README 2023-12-23 20:24:26 +01:00
5 changed files with 208 additions and 53 deletions

View File

@ -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; youll 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
View File

@ -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

View File

@ -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.

View File

@ -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.=

View File

@ -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