]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/mapgen/mg_decoration.cpp
Revert "Replace MyEventReceiver KeyList with std::unordered_set" (#10622)
[dragonfireclient.git] / src / mapgen / mg_decoration.cpp
index 2c2fbc6473eabdcb15290fc700e4b88f55dbc7f8..a4cada396d078ac6d7725401329dee80a2451196 100644 (file)
@@ -1,7 +1,7 @@
 /*
 Minetest
-Copyright (C) 2014-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
-Copyright (C) 2015-2017 paramat
+Copyright (C) 2014-2018 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+Copyright (C) 2015-2018 paramat
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License as published by
@@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "log.h"
 #include "util/numeric.h"
 #include <algorithm>
+#include <vector>
 
 
 FlagDesc flagdesc_deco[] = {
@@ -66,6 +67,13 @@ size_t DecorationManager::placeAllDecos(Mapgen *mg, u32 blockseed,
        return nplaced;
 }
 
+DecorationManager *DecorationManager::clone() const
+{
+       auto mgr = new DecorationManager();
+       ObjDefManager::cloneTo(mgr);
+       return mgr;
+}
+
 
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -154,23 +162,43 @@ size_t Decoration::placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
                        nmin.Z + sidelen + sidelen * z0 - 1
                );
 
+               bool cover = false;
                // Amount of decorations
                float nval = (flags & DECO_USE_NOISE) ?
                        NoisePerlin2D(&np, p2d_center.X, p2d_center.Y, mapseed) :
                        fill_ratio;
                u32 deco_count = 0;
-               float deco_count_f = (float)area * nval;
-               if (deco_count_f >= 1.f) {
-                       deco_count = deco_count_f;
-               } else if (deco_count_f > 0.f) {
-                       // For low density decorations calculate a chance for 1 decoration
-                       if (ps.range(1000) <= deco_count_f * 1000.f)
-                               deco_count = 1;
+
+               if (nval >= 10.0f) {
+                       // Complete coverage. Disable random placement to avoid
+                       // redundant multiple placements at one position.
+                       cover = true;
+                       deco_count = area;
+               } else {
+                       float deco_count_f = (float)area * nval;
+                       if (deco_count_f >= 1.0f) {
+                               deco_count = deco_count_f;
+                       } else if (deco_count_f > 0.0f) {
+                               // For very low density calculate a chance for 1 decoration
+                               if (ps.range(1000) <= deco_count_f * 1000.0f)
+                                       deco_count = 1;
+                       }
                }
 
+               s16 x = p2d_min.X - 1;
+               s16 z = p2d_min.Y;
+
                for (u32 i = 0; i < deco_count; i++) {
-                       s16 x = ps.range(p2d_min.X, p2d_max.X);
-                       s16 z = ps.range(p2d_min.Y, p2d_max.Y);
+                       if (!cover) {
+                               x = ps.range(p2d_min.X, p2d_max.X);
+                               z = ps.range(p2d_min.Y, p2d_max.Y);
+                       } else {
+                               x++;
+                               if (x == p2d_max.X + 1) {
+                                       z++;
+                                       x = p2d_min.X;
+                               }
+                       }
                        int mapindex = carea_size * (z - nmin.Z) + (x - nmin.X);
 
                        if ((flags & DECO_ALL_FLOORS) ||
@@ -178,26 +206,23 @@ size_t Decoration::placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
                                // All-surfaces decorations
                                // Check biome of column
                                if (mg->biomemap && !biomes.empty()) {
-                                       std::unordered_set<u8>::const_iterator iter =
-                                               biomes.find(mg->biomemap[mapindex]);
+                                       auto iter = biomes.find(mg->biomemap[mapindex]);
                                        if (iter == biomes.end())
                                                continue;
                                }
 
                                // Get all floors and ceilings in node column
                                u16 size = (nmax.Y - nmin.Y + 1) / 2;
-                               s16 floors[size];
-                               s16 ceilings[size];
-                               u16 num_floors = 0;
-                               u16 num_ceilings = 0;
+                               std::vector<s16> floors;
+                               std::vector<s16> ceilings;
+                               floors.reserve(size);
+                               ceilings.reserve(size);
 
-                               mg->getSurfaces(v2s16(x, z), nmin.Y, nmax.Y,
-                                       floors, ceilings, &num_floors, &num_ceilings);
+                               mg->getSurfaces(v2s16(x, z), nmin.Y, nmax.Y, floors, ceilings);
 
-                               if ((flags & DECO_ALL_FLOORS) && num_floors > 0) {
+                               if (flags & DECO_ALL_FLOORS) {
                                        // Floor decorations
-                                       for (u16 fi = 0; fi < num_floors; fi++) {
-                                               s16 y = floors[fi];
+                                       for (const s16 y : floors) {
                                                if (y < y_min || y > y_max)
                                                        continue;
 
@@ -208,10 +233,9 @@ size_t Decoration::placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
                                        }
                                }
 
-                               if ((flags & DECO_ALL_CEILINGS) && num_ceilings > 0) {
+                               if (flags & DECO_ALL_CEILINGS) {
                                        // Ceiling decorations
-                                       for (u16 ci = 0; ci < num_ceilings; ci++) {
-                                               s16 y = ceilings[ci];
+                                       for (const s16 y : ceilings) {
                                                if (y < y_min || y > y_max)
                                                        continue;
 
@@ -234,8 +258,7 @@ size_t Decoration::placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
                                        continue;
 
                                if (mg->biomemap && !biomes.empty()) {
-                                       std::unordered_set<u8>::const_iterator iter =
-                                               biomes.find(mg->biomemap[mapindex]);
+                                       auto iter = biomes.find(mg->biomemap[mapindex]);
                                        if (iter == biomes.end())
                                                continue;
                                }
@@ -251,9 +274,42 @@ size_t Decoration::placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
 }
 
 
+void Decoration::cloneTo(Decoration *def) const
+{
+       ObjDef::cloneTo(def);
+       def->flags = flags;
+       def->mapseed = mapseed;
+       def->c_place_on = c_place_on;
+       def->sidelen = sidelen;
+       def->y_min = y_min;
+       def->y_max = y_max;
+       def->fill_ratio = fill_ratio;
+       def->np = np;
+       def->c_spawnby = c_spawnby;
+       def->nspawnby = nspawnby;
+       def->place_offset_y = place_offset_y;
+       def->biomes = biomes;
+}
+
+
 ///////////////////////////////////////////////////////////////////////////////
 
 
+ObjDef *DecoSimple::clone() const
+{
+       auto def = new DecoSimple();
+       Decoration::cloneTo(def);
+
+       def->c_decos = c_decos;
+       def->deco_height = deco_height;
+       def->deco_height_max = deco_height_max;
+       def->deco_param2 = deco_param2;
+       def->deco_param2_max = deco_param2_max;
+
+       return def;
+}
+
+
 void DecoSimple::resolveNodeNames()
 {
        Decoration::resolveNodeNames();
@@ -303,10 +359,10 @@ size_t DecoSimple::generate(MMVManip *vm, PcgRandom *pr, v3s16 p, bool ceiling)
        if (ceiling) {
                // Ceiling decorations
                // 'place offset y' is inverted
-               vm->m_area.add_y(em, vi, -place_offset_y);
+               VoxelArea::add_y(em, vi, -place_offset_y);
 
                for (int i = 0; i < height; i++) {
-                       vm->m_area.add_y(em, vi, -1);
+                       VoxelArea::add_y(em, vi, -1);
                        content_t c = vm->m_data[vi].getContent();
                        if (c != CONTENT_AIR && c != CONTENT_IGNORE && !force_placement)
                                break;
@@ -314,10 +370,10 @@ size_t DecoSimple::generate(MMVManip *vm, PcgRandom *pr, v3s16 p, bool ceiling)
                        vm->m_data[vi] = MapNode(c_place, 0, param2);
                }
        } else { // Heightmap and floor decorations
-               vm->m_area.add_y(em, vi, place_offset_y);
+               VoxelArea::add_y(em, vi, place_offset_y);
 
                for (int i = 0; i < height; i++) {
-                       vm->m_area.add_y(em, vi, 1);
+                       VoxelArea::add_y(em, vi, 1);
                        content_t c = vm->m_data[vi].getContent();
                        if (c != CONTENT_AIR && c != CONTENT_IGNORE && !force_placement)
                                break;
@@ -333,6 +389,31 @@ size_t DecoSimple::generate(MMVManip *vm, PcgRandom *pr, v3s16 p, bool ceiling)
 ///////////////////////////////////////////////////////////////////////////////
 
 
+DecoSchematic::~DecoSchematic()
+{
+       if (was_cloned)
+               delete schematic;
+}
+
+
+ObjDef *DecoSchematic::clone() const
+{
+       auto def = new DecoSchematic();
+       Decoration::cloneTo(def);
+       NodeResolver::cloneTo(def);
+
+       def->rotation = rotation;
+       /* FIXME: We do not own this schematic, yet we only have a pointer to it
+        * and not a handle. We are left with no option but to clone it ourselves.
+        * This is a waste of memory and should be replaced with an alternative
+        * approach sometime. */
+       def->schematic = dynamic_cast<Schematic*>(schematic->clone());
+       def->was_cloned = true;
+
+       return def;
+}
+
+
 size_t DecoSchematic::generate(MMVManip *vm, PcgRandom *pr, v3s16 p, bool ceiling)
 {
        // Schematic could have been unloaded but not the decoration
@@ -362,13 +443,22 @@ size_t DecoSchematic::generate(MMVManip *vm, PcgRandom *pr, v3s16 p, bool ceilin
        if (p.Y < vm->m_area.MinEdge.Y)
                return 0;
 
-       if (flags & DECO_PLACE_CENTER_X)
-               p.X -= (schematic->size.X - 1) / 2;
-       if (flags & DECO_PLACE_CENTER_Z)
-               p.Z -= (schematic->size.Z - 1) / 2;
-
        Rotation rot = (rotation == ROTATE_RAND) ?
                (Rotation)pr->range(ROTATE_0, ROTATE_270) : rotation;
+
+       if (flags & DECO_PLACE_CENTER_X) {
+               if (rot == ROTATE_0 || rot == ROTATE_180)
+                       p.X -= (schematic->size.X - 1) / 2;
+               else
+                       p.Z -= (schematic->size.X - 1) / 2;
+       }
+       if (flags & DECO_PLACE_CENTER_Z) {
+               if (rot == ROTATE_0 || rot == ROTATE_180)
+                       p.Z -= (schematic->size.Z - 1) / 2;
+               else
+                       p.X -= (schematic->size.Z - 1) / 2;
+       }
+
        bool force_placement = (flags & DECO_FORCE_PLACEMENT);
 
        schematic->blitToVManip(vm, p, rot, force_placement);