From fdefbda49fe3fe17aa5deb981b32a1e0de622ea3 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 10 Sep 2024 20:34:26 +0300 Subject: [PATCH] implement SurroundMap & update AreaMap2D --- src/util/AreaMap2D.hpp | 36 ++++++++++++++++----- src/voxels/Chunks.cpp | 2 +- src/world/generator/SurroundMap.cpp | 48 +++++++++++++++++++++++++--- src/world/generator/SurroundMap.hpp | 31 ++++++++++++++---- test/world/generator/SurroundMap.cpp | 5 ++- 5 files changed, 100 insertions(+), 22 deletions(-) diff --git a/src/util/AreaMap2D.hpp b/src/util/AreaMap2D.hpp index 1c3041be..54c10657 100644 --- a/src/util/AreaMap2D.hpp +++ b/src/util/AreaMap2D.hpp @@ -10,9 +10,9 @@ namespace util { template class AreaMap2D { public: - using OutCallback = std::function; + using OutCallback = std::function; private: - TCoord offsetX, offsetY; + TCoord offsetX = 0, offsetY = 0; TCoord sizeX, sizeY; std::vector firstBuffer; std::vector secondBuffer; @@ -35,7 +35,7 @@ namespace util { } if (nx < 0 || ny < 0 || nx >= sizeX || ny >= sizeY) { if (outCallback) { - outCallback(value); + outCallback(x + offsetX, y + offsetY, value); } valuesCount--; continue; @@ -71,6 +71,23 @@ namespace util { return firstBuffer[ly * sizeX + lx]; } + T get(TCoord x, TCoord y, const T& def) const { + if (auto ptr = getIf(x, y)) { + const auto& value = *ptr; + if (value == T{}) { + return def; + } + return value; + } + return def; + } + + bool isInside(TCoord x, TCoord y) const { + auto lx = x - offsetX; + auto ly = y - offsetY; + return !(lx < 0 || ly < 0 || lx >= sizeX || ly >= sizeY); + } + const T& require(TCoord x, TCoord y) const { auto lx = x - offsetX; auto ly = y - offsetY; @@ -134,11 +151,14 @@ namespace util { } void clear() { - for (TCoord i = 0; i < sizeX * sizeY; i++) { - auto value = firstBuffer[i]; - firstBuffer[i] = {}; - if (outCallback) { - outCallback(value); + for (TCoord y = 0; y < sizeY; y++) { + for (TCoord x = 0; x < sizeX; x++) { + auto i = y * sizeX + x; + auto value = firstBuffer[i]; + firstBuffer[i] = {}; + if (outCallback) { + outCallback(x + offsetX, y + offsetY, value); + } } } valuesCount = 0; diff --git a/src/voxels/Chunks.cpp b/src/voxels/Chunks.cpp index ae8eee1a..c408190b 100644 --- a/src/voxels/Chunks.cpp +++ b/src/voxels/Chunks.cpp @@ -35,7 +35,7 @@ Chunks::Chunks( areaMap(w, d), worldFiles(wfile) { areaMap.setCenter(ox-w/2, oz-d/2); - areaMap.setOutCallback([this](const auto& chunk) { + areaMap.setOutCallback([this](int, int, const auto& chunk) { save(chunk.get()); }); } diff --git a/src/world/generator/SurroundMap.cpp b/src/world/generator/SurroundMap.cpp index fd31d3e7..8017758f 100644 --- a/src/world/generator/SurroundMap.cpp +++ b/src/world/generator/SurroundMap.cpp @@ -4,25 +4,63 @@ #include #include -SurroundMap::SurroundMap(int loadDistance, ubyte maxLevel) +SurroundMap::SurroundMap(int loadDistance, int8_t maxLevel) : areaMap((loadDistance + maxLevel) * 2 + 1, (loadDistance + maxLevel) * 2 + 1), levelCallbacks(maxLevel), maxLevel(maxLevel) {} -void SurroundMap::setLevelCallback(int level, LevelCallback callback) { - levelCallbacks.at(level) = callback; +void SurroundMap::setLevelCallback(int8_t level, LevelCallback callback) { + auto& wrapper = levelCallbacks.at(level); + wrapper.callback = callback; + wrapper.active = callback != nullptr; } -void SurroundMap::setOutCallback(util::AreaMap2D::OutCallback callback) { +void SurroundMap::setOutCallback(util::AreaMap2D::OutCallback callback) { areaMap.setOutCallback(callback); } +void SurroundMap::upgrade(int x, int y, int8_t level) { + auto& callback = levelCallbacks[level]; + int size = maxLevel - level + 1; + for (int ly = -size+1; ly < size; ly++) { + for (int lx = -size+1; lx < size; lx++) { + int posX = lx + x; + int posY = ly + y; + int8_t sourceLevel = areaMap.get(posX, posY, 0); + if (sourceLevel < level-1) { + throw std::runtime_error("invalid map state"); + } + if (sourceLevel >= level) { + continue; + } + areaMap.set(posX, posY, level); + if (callback.active) { + callback.callback(posX, posY); + } + } + } +} + void SurroundMap::completeAt(int x, int y) { - // TODO + if (!areaMap.isInside(x - maxLevel + 1, y - maxLevel + 1) || + !areaMap.isInside(x + maxLevel - 1, y + maxLevel - 1)) { + throw std::invalid_argument( + "upgrade square is not fully inside of area"); + } + for (int8_t level = 1; level <= maxLevel; level++) { + upgrade(x, y, level); + } } void SurroundMap::setCenter(int x, int y) { areaMap.setCenter(x, y); } + +int8_t SurroundMap::at(int x, int y) { + if (auto ptr = areaMap.getIf(x, y)) { + return *ptr; + } + throw std::invalid_argument("position is out of area"); +} diff --git a/src/world/generator/SurroundMap.hpp b/src/world/generator/SurroundMap.hpp index 3a99817e..a7af02dd 100644 --- a/src/world/generator/SurroundMap.hpp +++ b/src/world/generator/SurroundMap.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #define GLM_ENABLE_EXPERIMENTAL #include @@ -10,18 +11,34 @@ class SurroundMap { public: - using LevelCallback = std::function; + using LevelCallback = std::function; + struct LevelCallbackWrapper { + LevelCallback callback; + bool active; + }; private: - util::AreaMap2D areaMap; - std::vector levelCallbacks; - ubyte maxLevel; + util::AreaMap2D areaMap; + std::vector levelCallbacks; + int8_t maxLevel; + + void upgrade(int x, int y, int8_t level); public: - SurroundMap(int loadDistance, ubyte maxLevel); + SurroundMap(int loadDistance, int8_t maxLevel); - void setLevelCallback(int level, LevelCallback callback); - void setOutCallback(util::AreaMap2D::OutCallback callback); + /// @brief Callback called on point level increments + void setLevelCallback(int8_t level, LevelCallback callback); + /// @brief Callback called when non-zero value moves out of area + void setOutCallback(util::AreaMap2D::OutCallback callback); + + /// @brief Upgrade point to maxLevel + /// @throws std::invalid_argument - upgrade square is not fully inside void completeAt(int x, int y); + /// @brief Set map area center void setCenter(int x, int y); + + /// @brief Get level at position + /// @throws std::invalid_argument - position is out of area + int8_t at(int x, int y); }; diff --git a/test/world/generator/SurroundMap.cpp b/test/world/generator/SurroundMap.cpp index dc29ea03..d9ce8542 100644 --- a/test/world/generator/SurroundMap.cpp +++ b/test/world/generator/SurroundMap.cpp @@ -3,5 +3,8 @@ #include "world/generator/SurroundMap.hpp" TEST(SurroundMap, InitTest) { - SurroundMap map(50, 8); + int8_t maxLevel = 2; + SurroundMap map(50, maxLevel); + map.completeAt(25, 25); + EXPECT_EQ(map.at(25, 25), maxLevel); }