diff --git a/doc/lua_api.md b/doc/lua_api.md index 449309493..c4c74d884 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -6588,6 +6588,9 @@ Environment access on-the-fly * `core.spawn_tree (pos, {treedef})` * spawns L-system tree at given `pos` with definition in `treedef` table +* `core.spawn_tree_on_vmanip(vmanip, pos, treedef)` + * analogous to `core.spawn_tree`, but spawns a L-system tree onto the specified + VoxelManip object `vmanip` instead of the map. * `core.transforming_liquid_add(pos)` * add node to liquid flow update queue * `core.get_node_max_level(pos)` diff --git a/games/devtest/mods/testitems/init.lua b/games/devtest/mods/testitems/init.lua index 12da2ad1c..71a85ef6d 100644 --- a/games/devtest/mods/testitems/init.lua +++ b/games/devtest/mods/testitems/init.lua @@ -105,3 +105,68 @@ core.register_craftitem("testitems:telescope_stick", { return itemstack end, }) + + +-- Tree spawners + +local tree_def={ + axiom="Af", + rules_a="TT[&GB][&+GB][&++GB][&+++GB]A", + rules_b="[+GB]fB", + trunk="basenodes:tree", + leaves="basenodes:leaves", + angle=90, + iterations=4, + trunk_type="single", + thin_branches=true, +} + +core.register_craftitem("testitems:tree_spawner", { + description = S("Tree Spawner"), + inventory_image = "testitems_tree_spawner.png", + on_place = function(itemstack, placer, pointed_thing) + if (not pointed_thing or pointed_thing.type ~= "node") then + return + end + core.spawn_tree(pointed_thing.above, tree_def) + end, +}) + +local vmanip_for_trees = {} -- per player +core.register_craftitem("testitems:tree_spawner_vmanip", { + description = S("Tree Spawner using VoxelManip"), + inventory_image = "testitems_tree_spawner_vmanip.png", + on_place = function(itemstack, placer, pointed_thing) + if (not pointed_thing or pointed_thing.type ~= "node" or + not core.is_player(placer)) then + return + end + local name = placer:get_player_name() + local vm = vmanip_for_trees[name] + if not vm then + vm = VoxelManip(vector.add(pointed_thing.above, 20), + vector.subtract(pointed_thing.above, 20)) + vmanip_for_trees[name] = vm + core.chat_send_player(name, + "Tree in new VoxelManip spawned, left click to apply to map, ".. + "or right click to add more trees.") + end + core.spawn_tree_on_vmanip(vm, pointed_thing.above, tree_def) + end, + on_use = function(itemstack, user, pointed_thing) + if not core.is_player(user) then + return + end + local name = user:get_player_name() + local vm = vmanip_for_trees[name] + if vm then + vm:write_to_map() + vmanip_for_trees[name] = nil + core.chat_send_player(name, "VoxelManip written to map.") + end + end, +}) + +core.register_on_leaveplayer(function(player, timed_out) + vmanip_for_trees[player:get_player_name()] = nil +end) diff --git a/games/devtest/mods/testitems/textures/testitems_tree_spawner.png b/games/devtest/mods/testitems/textures/testitems_tree_spawner.png new file mode 100644 index 000000000..aa7430677 Binary files /dev/null and b/games/devtest/mods/testitems/textures/testitems_tree_spawner.png differ diff --git a/games/devtest/mods/testitems/textures/testitems_tree_spawner_vmanip.png b/games/devtest/mods/testitems/textures/testitems_tree_spawner_vmanip.png new file mode 100644 index 000000000..2d8e0311f Binary files /dev/null and b/games/devtest/mods/testitems/textures/testitems_tree_spawner_vmanip.png differ diff --git a/src/mapgen/treegen.cpp b/src/mapgen/treegen.cpp index e03f41482..688833fa2 100644 --- a/src/mapgen/treegen.cpp +++ b/src/mapgen/treegen.cpp @@ -875,4 +875,15 @@ void make_pine_tree(MMVManip &vmanip, v3s16 p0, const NodeDefManager *ndef, } } +std::string error_to_string(error e) +{ + switch (e) { + case SUCCESS: + return "success"; + case UNBALANCED_BRACKETS: + return "closing ']' has no matching opening bracket"; + } + return "unknown error"; +} + }; // namespace treegen diff --git a/src/mapgen/treegen.h b/src/mapgen/treegen.h index 159063eb3..dba7ea047 100644 --- a/src/mapgen/treegen.h +++ b/src/mapgen/treegen.h @@ -68,4 +68,7 @@ namespace treegen { treegen::error make_ltree(MMVManip &vmanip, v3s16 p0, const TreeDef &def); // Helper to spawn it directly on map treegen::error spawn_ltree(ServerMap *map, v3s16 p0, const TreeDef &def); + + // Helper to get a string from the error message + std::string error_to_string(error e); }; // namespace treegen diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp index 666dee712..5ebb2c3e4 100644 --- a/src/script/lua_api/l_env.cpp +++ b/src/script/lua_api/l_env.cpp @@ -1307,11 +1307,7 @@ int ModApiEnv::l_spawn_tree(lua_State *L) ServerMap *map = &env->getServerMap(); treegen::error e; if ((e = treegen::spawn_ltree (map, p0, tree_def)) != treegen::SUCCESS) { - if (e == treegen::UNBALANCED_BRACKETS) { - luaL_error(L, "spawn_tree(): closing ']' has no matching opening bracket"); - } else { - luaL_error(L, "spawn_tree(): unknown error"); - } + throw LuaError("spawn_tree(): " + treegen::error_to_string(e)); } lua_pushboolean(L, true); @@ -1614,11 +1610,7 @@ int ModApiEnvVM::l_spawn_tree(lua_State *L) treegen::error e; if ((e = treegen::make_ltree(*vm, p0, tree_def)) != treegen::SUCCESS) { - if (e == treegen::UNBALANCED_BRACKETS) { - throw LuaError("spawn_tree(): closing ']' has no matching opening bracket"); - } else { - throw LuaError("spawn_tree(): unknown error"); - } + throw LuaError("spawn_tree(): " + treegen::error_to_string(e)); } lua_pushboolean(L, true); diff --git a/src/script/lua_api/l_mapgen.cpp b/src/script/lua_api/l_mapgen.cpp index 89323b2f6..d102b357f 100644 --- a/src/script/lua_api/l_mapgen.cpp +++ b/src/script/lua_api/l_mapgen.cpp @@ -1773,6 +1773,27 @@ int ModApiMapgen::l_place_schematic_on_vmanip(lua_State *L) return 1; } +// spawn_tree_on_vmanip(vmanip, pos, treedef) +int ModApiMapgen::l_spawn_tree_on_vmanip(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + MMVManip *vm = checkObject(L, 1)->vm; + v3s16 p0 = read_v3s16(L, 2); + treegen::TreeDef tree_def; + const NodeDefManager *ndef = getGameDef(L)->ndef(); + if (!read_tree_def(L, 3, ndef, tree_def)) + return 0; + + treegen::error e = treegen::make_ltree(*vm, p0, tree_def); + if (e != treegen::SUCCESS) { + throw LuaError("spawn_tree_on_vmanip(): " + treegen::error_to_string(e)); + } + + lua_pushboolean(L, true); + return 1; +} + // serialize_schematic(schematic, format, options={...}) int ModApiMapgen::l_serialize_schematic(lua_State *L) @@ -2023,6 +2044,7 @@ void ModApiMapgen::Initialize(lua_State *L, int top) API_FCT(create_schematic); API_FCT(place_schematic); API_FCT(place_schematic_on_vmanip); + API_FCT(spawn_tree_on_vmanip); API_FCT(serialize_schematic); API_FCT(read_schematic); } @@ -2049,6 +2071,7 @@ void ModApiMapgen::InitializeEmerge(lua_State *L, int top) API_FCT(generate_ores); API_FCT(generate_decorations); API_FCT(place_schematic_on_vmanip); + API_FCT(spawn_tree_on_vmanip); API_FCT(serialize_schematic); API_FCT(read_schematic); } diff --git a/src/script/lua_api/l_mapgen.h b/src/script/lua_api/l_mapgen.h index d72cbcbad..860daa7e8 100644 --- a/src/script/lua_api/l_mapgen.h +++ b/src/script/lua_api/l_mapgen.h @@ -131,6 +131,9 @@ private: // replacements, force_placement, flagstring) static int l_place_schematic_on_vmanip(lua_State *L); + // spawn_tree_on_vmanip(vmanip, pos, treedef) + static int l_spawn_tree_on_vmanip(lua_State *L); + // serialize_schematic(schematic, format, options={...}) static int l_serialize_schematic(lua_State *L);