implement SurroundMap & update AreaMap2D
This commit is contained in:
parent
dc79c150da
commit
fdefbda49f
@ -10,9 +10,9 @@ namespace util {
|
||||
template<class T, typename TCoord=int>
|
||||
class AreaMap2D {
|
||||
public:
|
||||
using OutCallback = std::function<void(const T&)>;
|
||||
using OutCallback = std::function<void(TCoord, TCoord, const T&)>;
|
||||
private:
|
||||
TCoord offsetX, offsetY;
|
||||
TCoord offsetX = 0, offsetY = 0;
|
||||
TCoord sizeX, sizeY;
|
||||
std::vector<T> firstBuffer;
|
||||
std::vector<T> 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;
|
||||
|
||||
@ -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());
|
||||
});
|
||||
}
|
||||
|
||||
@ -4,25 +4,63 @@
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
|
||||
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<ubyte>::OutCallback callback) {
|
||||
void SurroundMap::setOutCallback(util::AreaMap2D<int8_t>::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");
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
|
||||
#define GLM_ENABLE_EXPERIMENTAL
|
||||
#include <glm/gtx/hash.hpp>
|
||||
@ -10,18 +11,34 @@
|
||||
|
||||
class SurroundMap {
|
||||
public:
|
||||
using LevelCallback = std::function<void(ubyte)>;
|
||||
using LevelCallback = std::function<void(int, int)>;
|
||||
struct LevelCallbackWrapper {
|
||||
LevelCallback callback;
|
||||
bool active;
|
||||
};
|
||||
private:
|
||||
util::AreaMap2D<ubyte> areaMap;
|
||||
std::vector<LevelCallback> levelCallbacks;
|
||||
ubyte maxLevel;
|
||||
util::AreaMap2D<int8_t> areaMap;
|
||||
std::vector<LevelCallbackWrapper> 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<ubyte>::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<int8_t>::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);
|
||||
};
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user