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>
|
template<class T, typename TCoord=int>
|
||||||
class AreaMap2D {
|
class AreaMap2D {
|
||||||
public:
|
public:
|
||||||
using OutCallback = std::function<void(const T&)>;
|
using OutCallback = std::function<void(TCoord, TCoord, const T&)>;
|
||||||
private:
|
private:
|
||||||
TCoord offsetX, offsetY;
|
TCoord offsetX = 0, offsetY = 0;
|
||||||
TCoord sizeX, sizeY;
|
TCoord sizeX, sizeY;
|
||||||
std::vector<T> firstBuffer;
|
std::vector<T> firstBuffer;
|
||||||
std::vector<T> secondBuffer;
|
std::vector<T> secondBuffer;
|
||||||
@ -35,7 +35,7 @@ namespace util {
|
|||||||
}
|
}
|
||||||
if (nx < 0 || ny < 0 || nx >= sizeX || ny >= sizeY) {
|
if (nx < 0 || ny < 0 || nx >= sizeX || ny >= sizeY) {
|
||||||
if (outCallback) {
|
if (outCallback) {
|
||||||
outCallback(value);
|
outCallback(x + offsetX, y + offsetY, value);
|
||||||
}
|
}
|
||||||
valuesCount--;
|
valuesCount--;
|
||||||
continue;
|
continue;
|
||||||
@ -71,6 +71,23 @@ namespace util {
|
|||||||
return firstBuffer[ly * sizeX + lx];
|
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 {
|
const T& require(TCoord x, TCoord y) const {
|
||||||
auto lx = x - offsetX;
|
auto lx = x - offsetX;
|
||||||
auto ly = y - offsetY;
|
auto ly = y - offsetY;
|
||||||
@ -134,11 +151,14 @@ namespace util {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void clear() {
|
void clear() {
|
||||||
for (TCoord i = 0; i < sizeX * sizeY; i++) {
|
for (TCoord y = 0; y < sizeY; y++) {
|
||||||
auto value = firstBuffer[i];
|
for (TCoord x = 0; x < sizeX; x++) {
|
||||||
firstBuffer[i] = {};
|
auto i = y * sizeX + x;
|
||||||
if (outCallback) {
|
auto value = firstBuffer[i];
|
||||||
outCallback(value);
|
firstBuffer[i] = {};
|
||||||
|
if (outCallback) {
|
||||||
|
outCallback(x + offsetX, y + offsetY, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
valuesCount = 0;
|
valuesCount = 0;
|
||||||
|
|||||||
@ -35,7 +35,7 @@ Chunks::Chunks(
|
|||||||
areaMap(w, d),
|
areaMap(w, d),
|
||||||
worldFiles(wfile) {
|
worldFiles(wfile) {
|
||||||
areaMap.setCenter(ox-w/2, oz-d/2);
|
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());
|
save(chunk.get());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,25 +4,63 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
SurroundMap::SurroundMap(int loadDistance, ubyte maxLevel)
|
SurroundMap::SurroundMap(int loadDistance, int8_t maxLevel)
|
||||||
: areaMap((loadDistance + maxLevel) * 2 + 1,
|
: areaMap((loadDistance + maxLevel) * 2 + 1,
|
||||||
(loadDistance + maxLevel) * 2 + 1),
|
(loadDistance + maxLevel) * 2 + 1),
|
||||||
levelCallbacks(maxLevel),
|
levelCallbacks(maxLevel),
|
||||||
maxLevel(maxLevel)
|
maxLevel(maxLevel)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void SurroundMap::setLevelCallback(int level, LevelCallback callback) {
|
void SurroundMap::setLevelCallback(int8_t level, LevelCallback callback) {
|
||||||
levelCallbacks.at(level) = 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);
|
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) {
|
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) {
|
void SurroundMap::setCenter(int x, int y) {
|
||||||
areaMap.setCenter(x, 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
|
#pragma once
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
#define GLM_ENABLE_EXPERIMENTAL
|
#define GLM_ENABLE_EXPERIMENTAL
|
||||||
#include <glm/gtx/hash.hpp>
|
#include <glm/gtx/hash.hpp>
|
||||||
@ -10,18 +11,34 @@
|
|||||||
|
|
||||||
class SurroundMap {
|
class SurroundMap {
|
||||||
public:
|
public:
|
||||||
using LevelCallback = std::function<void(ubyte)>;
|
using LevelCallback = std::function<void(int, int)>;
|
||||||
|
struct LevelCallbackWrapper {
|
||||||
|
LevelCallback callback;
|
||||||
|
bool active;
|
||||||
|
};
|
||||||
private:
|
private:
|
||||||
util::AreaMap2D<ubyte> areaMap;
|
util::AreaMap2D<int8_t> areaMap;
|
||||||
std::vector<LevelCallback> levelCallbacks;
|
std::vector<LevelCallbackWrapper> levelCallbacks;
|
||||||
ubyte maxLevel;
|
int8_t maxLevel;
|
||||||
|
|
||||||
|
void upgrade(int x, int y, int8_t level);
|
||||||
public:
|
public:
|
||||||
SurroundMap(int loadDistance, ubyte maxLevel);
|
SurroundMap(int loadDistance, int8_t maxLevel);
|
||||||
|
|
||||||
void setLevelCallback(int level, LevelCallback callback);
|
/// @brief Callback called on point level increments
|
||||||
void setOutCallback(util::AreaMap2D<ubyte>::OutCallback callback);
|
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);
|
void completeAt(int x, int y);
|
||||||
|
|
||||||
|
/// @brief Set map area center
|
||||||
void setCenter(int x, int y);
|
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"
|
#include "world/generator/SurroundMap.hpp"
|
||||||
|
|
||||||
TEST(SurroundMap, InitTest) {
|
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