diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 57940a5dd..b337be1f0 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -2294,6 +2294,15 @@ These functions return the leftover itemstack. * `replacements` = `{["old_name"] = "convert_to", ...}` * `force_placement` is a boolean indicating whether nodes other than `air` and `ignore` are replaced by the schematic + * Returns nil if the schematic could not be loaded. + +* `minetest.place_schematic_on_vmanip(vmanip, pos, schematic, rotation, replacement, force_placement)`: + * This function is analagous to minetest.place_schematic, but places a schematic onto the + specified VoxelManip object `vmanip` instead of the whole map. + * Returns false if any part of the schematic was cut-off due to the VoxelManip not + containing the full area required, and true if the whole schematic was able to fit. + * Returns nil if the schematic could not be loaded. + * After execution, any external copies of the VoxelManip contents are invalidated. * `minetest.serialize_schematic(schematic, format, options)` * Return the serialized schematic specified by schematic (see: Schematic specifier) diff --git a/src/mg_decoration.cpp b/src/mg_decoration.cpp index 1e080fd6a..846d6130b 100644 --- a/src/mg_decoration.cpp +++ b/src/mg_decoration.cpp @@ -351,7 +351,7 @@ size_t DecoSchematic::generate(MMVManip *vm, PseudoRandom *pr, v3s16 p) bool force_placement = (flags & DECO_FORCE_PLACEMENT); - schematic->blitToVManip(p, vm, rot, force_placement); + schematic->blitToVManip(vm, p, rot, force_placement); return 1; } diff --git a/src/mg_schematic.cpp b/src/mg_schematic.cpp index a5ffb20b8..019ed4dee 100644 --- a/src/mg_schematic.cpp +++ b/src/mg_schematic.cpp @@ -94,7 +94,7 @@ void Schematic::resolveNodeNames() } -void Schematic::blitToVManip(v3s16 p, MMVManip *vm, Rotation rot, bool force_place) +void Schematic::blitToVManip(MMVManip *vm, v3s16 p, Rotation rot, bool force_place) { sanity_check(m_ndef != NULL); @@ -175,20 +175,21 @@ void Schematic::blitToVManip(v3s16 p, MMVManip *vm, Rotation rot, bool force_pla } -void Schematic::placeStructure(Map *map, v3s16 p, u32 flags, +bool Schematic::placeOnVManip(MMVManip *vm, v3s16 p, u32 flags, Rotation rot, bool force_place) { - assert(schemdata != NULL); // Pre-condition + assert(vm != NULL); + assert(schemdata != NULL); sanity_check(m_ndef != NULL); - MMVManip *vm = new MMVManip(map); - + //// Determine effective rotation and effective schematic dimensions if (rot == ROTATE_RAND) rot = (Rotation)myrand_range(ROTATE_0, ROTATE_270); v3s16 s = (rot == ROTATE_90 || rot == ROTATE_270) ? - v3s16(size.Z, size.Y, size.X) : size; + v3s16(size.Z, size.Y, size.X) : size; + //// Adjust placement position if necessary if (flags & DECO_PLACE_CENTER_X) p.X -= (s.X + 1) / 2; if (flags & DECO_PLACE_CENTER_Y) @@ -196,25 +197,60 @@ void Schematic::placeStructure(Map *map, v3s16 p, u32 flags, if (flags & DECO_PLACE_CENTER_Z) p.Z -= (s.Z + 1) / 2; - v3s16 bp1 = getNodeBlockPos(p); - v3s16 bp2 = getNodeBlockPos(p + s - v3s16(1,1,1)); - vm->initialEmerge(bp1, bp2); + blitToVManip(vm, p, rot, force_place); - blitToVManip(p, vm, rot, force_place); + return vm->m_area.contains(VoxelArea(p, p + s - v3s16(1,1,1))); +} +void Schematic::placeOnMap(Map *map, v3s16 p, u32 flags, + Rotation rot, bool force_place) +{ std::map lighting_modified_blocks; std::map modified_blocks; - vm->blitBackAll(&modified_blocks); + std::map::iterator it; + assert(map != NULL); + assert(schemdata != NULL); + sanity_check(m_ndef != NULL); + + //// Determine effective rotation and effective schematic dimensions + if (rot == ROTATE_RAND) + rot = (Rotation)myrand_range(ROTATE_0, ROTATE_270); + + v3s16 s = (rot == ROTATE_90 || rot == ROTATE_270) ? + v3s16(size.Z, size.Y, size.X) : size; + + //// Adjust placement position if necessary + if (flags & DECO_PLACE_CENTER_X) + p.X -= (s.X + 1) / 2; + if (flags & DECO_PLACE_CENTER_Y) + p.Y -= (s.Y + 1) / 2; + if (flags & DECO_PLACE_CENTER_Z) + p.Z -= (s.Z + 1) / 2; + + //// Create VManip for effected area, emerge our area, modify area + //// inside VManip, then blit back. + v3s16 bp1 = getNodeBlockPos(p); + v3s16 bp2 = getNodeBlockPos(p + s - v3s16(1,1,1)); + + MMVManip vm(map); + vm.initialEmerge(bp1, bp2); + + blitToVManip(&vm, p, rot, force_place); + + vm.blitBackAll(&modified_blocks); + + //// Carry out post-map-modification actions + + //// Update lighting // TODO: Optimize this by using Mapgen::calcLighting() instead lighting_modified_blocks.insert(modified_blocks.begin(), modified_blocks.end()); map->updateLighting(lighting_modified_blocks, modified_blocks); + //// Create & dispatch map modification events to observers MapEditEvent event; event.type = MEET_OTHER; - for (std::map::iterator - it = modified_blocks.begin(); - it != modified_blocks.end(); ++it) + for (it = modified_blocks.begin(); it != modified_blocks.end(); ++it) event.modified_blocks.insert(it->first); map->dispatchEvent(&event); diff --git a/src/mg_schematic.h b/src/mg_schematic.h index 5c732648e..da8859540 100644 --- a/src/mg_schematic.h +++ b/src/mg_schematic.h @@ -106,8 +106,9 @@ public: bool serializeToLua(std::ostream *os, const std::vector &names, bool use_comments, u32 indent_spaces); - void blitToVManip(v3s16 p, MMVManip *vm, Rotation rot, bool force_place); - void placeStructure(Map *map, v3s16 p, u32 flags, Rotation rot, bool force_place); + void blitToVManip(MMVManip *vm, v3s16 p, Rotation rot, bool force_place); + bool placeOnVManip(MMVManip *vm, v3s16 p, u32 flags, Rotation rot, bool force_place); + void placeOnMap(Map *map, v3s16 p, u32 flags, Rotation rot, bool force_place); void applyProbabilities(v3s16 p0, std::vector > *plist, diff --git a/src/script/lua_api/l_mapgen.cpp b/src/script/lua_api/l_mapgen.cpp index 7adb6a534..d5cf54f24 100644 --- a/src/script/lua_api/l_mapgen.cpp +++ b/src/script/lua_api/l_mapgen.cpp @@ -1271,12 +1271,54 @@ int ModApiMapgen::l_place_schematic(lua_State *L) return 0; } - schem->placeStructure(map, p, 0, (Rotation)rot, force_placement); + schem->placeOnMap(map, p, 0, (Rotation)rot, force_placement); lua_pushboolean(L, true); return 1; } +int ModApiMapgen::l_place_schematic_on_vmanip(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr; + + //// Read VoxelManip object + MMVManip *vm = LuaVoxelManip::checkobject(L, 1)->vm; + + //// Read position + v3s16 p = check_v3s16(L, 2); + + //// Read rotation + int rot = ROTATE_0; + const char *enumstr = lua_tostring(L, 4); + if (enumstr) + string_to_enum(es_Rotation, rot, std::string(enumstr)); + + //// Read force placement + bool force_placement = true; + if (lua_isboolean(L, 6)) + force_placement = lua_toboolean(L, 6); + + //// Read node replacements + StringMap replace_names; + if (lua_istable(L, 5)) + read_schematic_replacements(L, 5, &replace_names); + + //// Read schematic + Schematic *schem = get_or_load_schematic(L, 3, schemmgr, &replace_names); + if (!schem) { + errorstream << "place_schematic: failed to get schematic" << std::endl; + return 0; + } + + bool schematic_did_fit = schem->placeOnVManip( + vm, p, 0, (Rotation)rot, force_placement); + + lua_pushboolean(L, schematic_did_fit); + return 1; +} + // serialize_schematic(schematic, format, options={...}) int ModApiMapgen::l_serialize_schematic(lua_State *L) { @@ -1355,5 +1397,6 @@ void ModApiMapgen::Initialize(lua_State *L, int top) API_FCT(generate_decorations); API_FCT(create_schematic); API_FCT(place_schematic); + API_FCT(place_schematic_on_vmanip); API_FCT(serialize_schematic); } diff --git a/src/script/lua_api/l_mapgen.h b/src/script/lua_api/l_mapgen.h index 4768f934d..9751c0db6 100644 --- a/src/script/lua_api/l_mapgen.h +++ b/src/script/lua_api/l_mapgen.h @@ -85,9 +85,13 @@ private: // create_schematic(p1, p2, probability_list, filename) static int l_create_schematic(lua_State *L); - // place_schematic(p, schematic, rotation, replacement) + // place_schematic(p, schematic, rotation, replacements, force_placement) static int l_place_schematic(lua_State *L); + // place_schematic_on_vmanip(vm, p, schematic, + // rotation, replacements, force_placement) + static int l_place_schematic_on_vmanip(lua_State *L); + // serialize_schematic(schematic, format, options={...}) static int l_serialize_schematic(lua_State *L);