From b88595050f3af5ccac06aac331ead4ebdcb9deb9 Mon Sep 17 00:00:00 2001 From: paramat Date: Sun, 11 Sep 2016 23:34:43 +0100 Subject: [PATCH] Decorations: Generalise 'spawn by' to be used by all decoration types In lua_api.txt, make clear that 'place on' and 'spawn by' can be lists. --- doc/lua_api.txt | 16 ++--- src/mg_decoration.cpp | 123 ++++++++++++++++---------------- src/mg_decoration.h | 9 ++- src/script/lua_api/l_mapgen.cpp | 21 +++--- 4 files changed, 82 insertions(+), 87 deletions(-) diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 74d4b90d5..aa4f129f0 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -3909,7 +3909,7 @@ The Biome API is still in an experimental phase and subject to change. { deco_type = "simple", -- See "Decoration types" place_on = "default:dirt_with_grass", - -- ^ Node that decoration can be placed on + -- ^ Node (or list of nodes) that the decoration can be placed on sidelen = 8, -- ^ Size of divisions made in the chunk being generated. -- ^ If the chunk size is not evenly divisible by sidelen, sidelen is made equal to the chunk size. @@ -3928,6 +3928,13 @@ The Biome API is still in an experimental phase and subject to change. -- ^ Minimum and maximum `y` positions these decorations can be generated at. -- ^ This parameter refers to the `y` position of the decoration base, so -- the actual maximum height would be `height_max + size.Y`. + spawn_by = "default:water", + -- ^ Node (or list of nodes) that the decoration only spawns next to. + -- ^ Checks two horizontal planes of neighbouring nodes (including diagonal neighbours), + -- ^ one plane at Y = surface and one plane at Y = surface = + 1. + num_spawn_by = 1, + -- ^ Number of spawn_by nodes that must be surrounding the decoration position to occur. + -- ^ If absent or -1, decorations occur next to any nodes. flags = "liquid_surface, force_placement", -- ^ Flags for all decoration types. -- ^ "liquid_surface": Instead of placement on the highest solid surface @@ -3945,13 +3952,6 @@ The Biome API is still in an experimental phase and subject to change. height_max = 0, -- ^ Number of nodes the decoration can be at maximum. -- ^ If absent, the parameter 'height' is used as a constant. - spawn_by = "default:water", - -- ^ Node that the decoration only spawns next to. - -- ^ The neighbours checked are the 8 nodes horizontally surrounding the lowest node of the - -- ^ decoration, and the 8 nodes horizontally surrounding the ground node below the decoration. - num_spawn_by = 1, - -- ^ Number of spawn_by nodes that must be surrounding the decoration position to occur. - -- ^ If absent or -1, decorations occur next to any nodes. ----- Schematic-type parameters schematic = "foobar.mts", diff --git a/src/mg_decoration.cpp b/src/mg_decoration.cpp index 127915b51..92483abc3 100644 --- a/src/mg_decoration.cpp +++ b/src/mg_decoration.cpp @@ -26,12 +26,12 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "util/numeric.h" FlagDesc flagdesc_deco[] = { - {"place_center_x", DECO_PLACE_CENTER_X}, - {"place_center_y", DECO_PLACE_CENTER_Y}, - {"place_center_z", DECO_PLACE_CENTER_Z}, + {"place_center_x", DECO_PLACE_CENTER_X}, + {"place_center_y", DECO_PLACE_CENTER_Y}, + {"place_center_z", DECO_PLACE_CENTER_Z}, {"force_placement", DECO_FORCE_PLACEMENT}, - {"liquid_surface", DECO_LIQUID_SURFACE}, - {NULL, 0} + {"liquid_surface", DECO_LIQUID_SURFACE}, + {NULL, 0} }; @@ -82,6 +82,56 @@ Decoration::~Decoration() void Decoration::resolveNodeNames() { getIdsFromNrBacklog(&c_place_on); + getIdsFromNrBacklog(&c_spawnby); +} + + +bool Decoration::canPlaceDecoration(MMVManip *vm, v3s16 p) +{ + // Check if the decoration can be placed on this node + u32 vi = vm->m_area.index(p); + if (!CONTAINS(c_place_on, vm->m_data[vi].getContent())) + return false; + + // Don't continue if there are no spawnby constraints + if (nspawnby == -1) + return true; + + int nneighs = 0; + static const v3s16 dirs[16] = { + v3s16( 0, 0, 1), + v3s16( 0, 0, -1), + v3s16( 1, 0, 0), + v3s16(-1, 0, 0), + v3s16( 1, 0, 1), + v3s16(-1, 0, 1), + v3s16(-1, 0, -1), + v3s16( 1, 0, -1), + + v3s16( 0, 1, 1), + v3s16( 0, 1, -1), + v3s16( 1, 1, 0), + v3s16(-1, 1, 0), + v3s16( 1, 1, 1), + v3s16(-1, 1, 1), + v3s16(-1, 1, -1), + v3s16( 1, 1, -1) + }; + + // Check these 16 neighbouring nodes for enough spawnby nodes + for (size_t i = 0; i != ARRLEN(dirs); i++) { + u32 index = vm->m_area.index(p + dirs[i]); + if (!vm->m_area.contains(index)) + continue; + + if (CONTAINS(c_spawnby, vm->m_data[index].getContent())) + nneighs++; + } + + if (nneighs < nspawnby) + return false; + + return true; } @@ -236,66 +286,15 @@ void DecoSimple::resolveNodeNames() { Decoration::resolveNodeNames(); getIdsFromNrBacklog(&c_decos); - getIdsFromNrBacklog(&c_spawnby); -} - - -bool DecoSimple::canPlaceDecoration(MMVManip *vm, v3s16 p) -{ - // Don't bother if there aren't any decorations to place - if (c_decos.size() == 0) - return false; - - u32 vi = vm->m_area.index(p); - - // Check if the decoration can be placed on this node - if (!CONTAINS(c_place_on, vm->m_data[vi].getContent())) - return false; - - // Don't continue if there are no spawnby constraints - if (nspawnby == -1) - return true; - - int nneighs = 0; - v3s16 dirs[16] = { - v3s16( 0, 0, 1), - v3s16( 0, 0, -1), - v3s16( 1, 0, 0), - v3s16(-1, 0, 0), - v3s16( 1, 0, 1), - v3s16(-1, 0, 1), - v3s16(-1, 0, -1), - v3s16( 1, 0, -1), - - v3s16( 0, 1, 1), - v3s16( 0, 1, -1), - v3s16( 1, 1, 0), - v3s16(-1, 1, 0), - v3s16( 1, 1, 1), - v3s16(-1, 1, 1), - v3s16(-1, 1, -1), - v3s16( 1, 1, -1) - }; - - // Check a Moore neighborhood if there are enough spawnby nodes - for (size_t i = 0; i != ARRLEN(dirs); i++) { - u32 index = vm->m_area.index(p + dirs[i]); - if (!vm->m_area.contains(index)) - continue; - - if (CONTAINS(c_spawnby, vm->m_data[index].getContent())) - nneighs++; - } - - if (nneighs < nspawnby) - return false; - - return true; } size_t DecoSimple::generate(MMVManip *vm, PcgRandom *pr, v3s16 p) { + // Don't bother if there aren't any decorations to place + if (c_decos.size() == 0) + return 0; + if (!canPlaceDecoration(vm, p)) return 0; @@ -345,9 +344,7 @@ size_t DecoSchematic::generate(MMVManip *vm, PcgRandom *pr, v3s16 p) if (schematic == NULL) return 0; - u32 vi = vm->m_area.index(p); - content_t c = vm->m_data[vi].getContent(); - if (!CONTAINS(c_place_on, c)) + if (!canPlaceDecoration(vm, p)) return 0; if (flags & DECO_PLACE_CENTER_X) diff --git a/src/mg_decoration.h b/src/mg_decoration.h index da98fd482..be0ba44d7 100644 --- a/src/mg_decoration.h +++ b/src/mg_decoration.h @@ -68,6 +68,7 @@ public: virtual void resolveNodeNames(); + bool canPlaceDecoration(MMVManip *vm, v3s16 p); size_t placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax); //size_t placeCutoffs(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax); @@ -82,6 +83,8 @@ public: s16 y_max; float fill_ratio; NoiseParams np; + std::vector c_spawnby; + s16 nspawnby; UNORDERED_SET biomes; //std::list cutoffs; @@ -90,17 +93,13 @@ public: class DecoSimple : public Decoration { public: + virtual void resolveNodeNames(); virtual size_t generate(MMVManip *vm, PcgRandom *pr, v3s16 p); - bool canPlaceDecoration(MMVManip *vm, v3s16 p); virtual int getHeight(); - virtual void resolveNodeNames(); - std::vector c_decos; - std::vector c_spawnby; s16 deco_height; s16 deco_height_max; - s16 nspawnby; }; class DecoSchematic : public Decoration { diff --git a/src/script/lua_api/l_mapgen.cpp b/src/script/lua_api/l_mapgen.cpp index 9f28231eb..a176f4f52 100644 --- a/src/script/lua_api/l_mapgen.cpp +++ b/src/script/lua_api/l_mapgen.cpp @@ -902,6 +902,7 @@ int ModApiMapgen::l_register_decoration(lua_State *L) deco->fill_ratio = getfloatfield_default(L, index, "fill_ratio", 0.02); deco->y_min = getintfield_default(L, index, "y_min", -31000); deco->y_max = getintfield_default(L, index, "y_max", 31000); + deco->nspawnby = getintfield_default(L, index, "num_spawn_by", -1); deco->sidelen = getintfield_default(L, index, "sidelen", 8); if (deco->sidelen <= 0) { errorstream << "register_decoration: sidelen must be " @@ -929,6 +930,14 @@ int ModApiMapgen::l_register_decoration(lua_State *L) errorstream << "register_decoration: couldn't get all biomes " << std::endl; lua_pop(L, 1); + //// Get node name(s) to 'spawn by' + size_t nnames = getstringlistfield(L, index, "spawn_by", &deco->m_nodenames); + deco->m_nnlistsizes.push_back(nnames); + if (nnames == 0 && deco->nspawnby != -1) { + errorstream << "register_decoration: no spawn_by nodes defined," + " but num_spawn_by specified" << std::endl; + } + //// Handle decoration type-specific parameters bool success = false; switch (decotype) { @@ -962,12 +971,10 @@ int ModApiMapgen::l_register_decoration(lua_State *L) bool read_deco_simple(lua_State *L, DecoSimple *deco) { - size_t nnames; int index = 1; deco->deco_height = getintfield_default(L, index, "height", 1); deco->deco_height_max = getintfield_default(L, index, "height_max", 0); - deco->nspawnby = getintfield_default(L, index, "num_spawn_by", -1); if (deco->deco_height <= 0) { errorstream << "register_decoration: simple decoration height" @@ -975,7 +982,7 @@ bool read_deco_simple(lua_State *L, DecoSimple *deco) return false; } - nnames = getstringlistfield(L, index, "decoration", &deco->m_nodenames); + size_t nnames = getstringlistfield(L, index, "decoration", &deco->m_nodenames); deco->m_nnlistsizes.push_back(nnames); if (nnames == 0) { errorstream << "register_decoration: no decoration nodes " @@ -983,14 +990,6 @@ bool read_deco_simple(lua_State *L, DecoSimple *deco) return false; } - nnames = getstringlistfield(L, index, "spawn_by", &deco->m_nodenames); - deco->m_nnlistsizes.push_back(nnames); - if (nnames == 0 && deco->nspawnby != -1) { - errorstream << "register_decoration: no spawn_by nodes defined," - " but num_spawn_by specified" << std::endl; - return false; - } - return true; }