2020-05-08 22:10:49 +02:00
|
|
|
#pragma once
|
2014-03-05 21:41:27 +01:00
|
|
|
|
2020-05-08 22:10:49 +02:00
|
|
|
#include <cstdint>
|
2014-03-05 21:41:27 +01:00
|
|
|
#include <list>
|
2014-04-19 08:13:34 +02:00
|
|
|
#include <vector>
|
2014-03-09 12:32:13 +01:00
|
|
|
#include <utility>
|
2014-04-19 08:13:34 +02:00
|
|
|
#include "types.h"
|
|
|
|
|
|
|
|
|
2020-03-26 23:07:27 +01:00
|
|
|
struct BlockPos {
|
2014-04-19 08:13:34 +02:00
|
|
|
int16_t x;
|
|
|
|
int16_t y;
|
|
|
|
int16_t z;
|
|
|
|
|
2016-09-18 14:33:13 +02:00
|
|
|
BlockPos() : x(0), y(0), z(0) {}
|
|
|
|
BlockPos(int16_t x, int16_t y, int16_t z) : x(x), y(y), z(z) {}
|
2020-03-27 16:12:26 +01:00
|
|
|
|
|
|
|
// Implements the inverse ordering so that (2,2,2) < (1,1,1)
|
2014-04-19 08:13:34 +02:00
|
|
|
bool operator < (const BlockPos &p) const
|
|
|
|
{
|
2018-10-20 23:01:03 +02:00
|
|
|
if (z > p.z)
|
2014-04-19 08:13:34 +02:00
|
|
|
return true;
|
2018-10-20 23:01:03 +02:00
|
|
|
if (z < p.z)
|
2014-04-19 08:13:34 +02:00
|
|
|
return false;
|
2018-10-20 23:01:03 +02:00
|
|
|
if (y > p.y)
|
2014-04-19 08:13:34 +02:00
|
|
|
return true;
|
2018-10-20 23:01:03 +02:00
|
|
|
if (y < p.y)
|
2014-04-19 08:13:34 +02:00
|
|
|
return false;
|
2018-10-20 23:01:03 +02:00
|
|
|
if (x > p.x)
|
2014-04-19 08:13:34 +02:00
|
|
|
return true;
|
2018-10-20 23:01:03 +02:00
|
|
|
if (x < p.x)
|
2014-04-19 08:13:34 +02:00
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
typedef std::pair<BlockPos, ustring> Block;
|
|
|
|
typedef std::list<Block> BlockList;
|
2014-03-05 21:41:27 +01:00
|
|
|
|
|
|
|
|
|
|
|
class DB {
|
2014-04-19 08:13:34 +02:00
|
|
|
protected:
|
2020-03-27 16:12:26 +01:00
|
|
|
// Helpers that implement the hashed positions used by most backends
|
2014-04-19 08:13:34 +02:00
|
|
|
inline int64_t encodeBlockPos(const BlockPos pos) const;
|
|
|
|
inline BlockPos decodeBlockPos(int64_t hash) const;
|
|
|
|
|
2014-03-05 21:41:27 +01:00
|
|
|
public:
|
2020-03-27 16:12:26 +01:00
|
|
|
/* Return all block positions inside the range given by min and max,
|
|
|
|
* so that min.x <= x < max.x, ...
|
|
|
|
*/
|
|
|
|
virtual std::vector<BlockPos> getBlockPos(BlockPos min, BlockPos max) = 0;
|
2020-03-27 21:10:00 +01:00
|
|
|
/* Read all blocks in column given by x and z
|
|
|
|
* and inside the given Y range (min_y <= y < max_y) into list
|
2020-03-27 16:12:26 +01:00
|
|
|
*/
|
|
|
|
virtual void getBlocksOnXZ(BlockList &blocks, int16_t x, int16_t z,
|
|
|
|
int16_t min_y, int16_t max_y) = 0;
|
2020-03-27 21:10:00 +01:00
|
|
|
/* Read blocks at given positions into list
|
|
|
|
*/
|
|
|
|
virtual void getBlocksByPos(BlockList &blocks,
|
|
|
|
const std::vector<BlockPos> &positions) = 0;
|
|
|
|
/* Can this database efficiently do range queries?
|
|
|
|
* (for large data sets, more efficient that brute force)
|
|
|
|
*/
|
|
|
|
virtual bool preferRangeQueries() const = 0;
|
|
|
|
|
|
|
|
|
2020-03-27 16:12:26 +01:00
|
|
|
virtual ~DB() {}
|
2014-03-05 21:41:27 +01:00
|
|
|
};
|
|
|
|
|
2014-04-19 08:13:34 +02:00
|
|
|
|
|
|
|
|
|
|
|
/****************
|
|
|
|
* Black magic! *
|
|
|
|
****************
|
|
|
|
* The position hashing is seriously messed up,
|
|
|
|
* and is a lot more complicated than it looks.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static inline int16_t unsigned_to_signed(uint16_t i, uint16_t max_positive)
|
|
|
|
{
|
|
|
|
if (i < max_positive) {
|
|
|
|
return i;
|
|
|
|
} else {
|
|
|
|
return i - (max_positive * 2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Modulo of a negative number does not work consistently in C
|
|
|
|
static inline int64_t pythonmodulo(int64_t i, int64_t mod)
|
|
|
|
{
|
|
|
|
if (i >= 0) {
|
|
|
|
return i % mod;
|
|
|
|
}
|
|
|
|
return mod - ((-i) % mod);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
inline int64_t DB::encodeBlockPos(const BlockPos pos) const
|
|
|
|
{
|
|
|
|
return (uint64_t) pos.z * 0x1000000 +
|
|
|
|
(uint64_t) pos.y * 0x1000 +
|
|
|
|
(uint64_t) pos.x;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
inline BlockPos DB::decodeBlockPos(int64_t hash) const
|
|
|
|
{
|
|
|
|
BlockPos pos;
|
|
|
|
pos.x = unsigned_to_signed(pythonmodulo(hash, 4096), 2048);
|
|
|
|
hash = (hash - pos.x) / 4096;
|
|
|
|
pos.y = unsigned_to_signed(pythonmodulo(hash, 4096), 2048);
|
|
|
|
hash = (hash - pos.y) / 4096;
|
|
|
|
pos.z = unsigned_to_signed(pythonmodulo(hash, 4096), 2048);
|
|
|
|
return pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*******************
|
|
|
|
* End black magic *
|
|
|
|
*******************/
|
|
|
|
|