Diggler/src/Chunk.hpp

253 lines
6.0 KiB
C++

#ifndef CHUNK_HPP
#define CHUNK_HPP
#include <memory>
#include <mutex>
#include <glm/glm.hpp>
#include "Texture.hpp"
#include "content/Content.hpp"
#include "network/Network.hpp"
#define CHUNK_INMEM_COMPRESS 1
#define CHUNK_INMEM_COMPRESS_DELAY 2000 /* ms */
namespace Diggler {
class CaveGenerator;
class Game;
class World;
using WorldRef = std::shared_ptr<World>;
namespace Render {
class WorldRenderer;
}
namespace Net {
namespace MsgTypes {
struct BlockUpdateNotify;
}
}
class Chunk {
private:
friend World;
friend CaveGenerator;
friend class Render::WorldRenderer;
uintptr_t rendererData;
public:
constexpr static int
CX = 16, /**< Chunk size along X axis, in blocks. */
CY = 16, /**< Chunk size along Y axis, in blocks. */
CZ = 16; /**< Chunk size along Z axis, in blocks. */
constexpr static float CullSphereRadius =
(CZ > (CX > CY ? CX : CY) ? CZ : (CX > CY ? CX : CY));
// * 1.4142135623f; but we're already at 2x the radius (i.e. diameter)
constexpr static float MidX = CX/2.f, MidY = CY/2.f, MidZ = CZ/2.f;
const int wcx, wcy, wcz;
/**
* @brief Struct holding the Chunk's block contents.
* @note This structure must be a Plain Old Data struct.
*/
struct Data {
static constexpr FourCC MagicMarker = MakeFourCC("CKDT");
FourCC magic; /**< Magic marker. Used for Chunk eviction checking. */
BlockId id[CX*CY*CZ]; /**< Block IDs. */
BlockData data[CX*CY*CZ]; /**< Block data. */
LightData light[CX*CY*CZ]; /**< Block light info. */
void clear();
};
constexpr static int AllocaSize = sizeof(Data);
enum class State : uint8 {
Unavailable, /**< The Chunk is unavailable right now. */
Generating, /**< The Chunk is generating. */
Loading, /**< The Chunk is loading from storage or network. */
Ready, /**< The Chunk is loaded properly and ready to use. */
Evicted /**< The Chunk has been evicted from memory. */
};
struct Vertex {
float x, y, z;
uint16 tx, ty;
float r, g, b;
};
Game *const G;
const WorldRef W;
private:
Data *data;
//std::map<uint16, msgpack::object> extdataStore;
State state;
bool dirty;
std::mutex mut;
public:
void calcMemUsage();
#if CHUNK_INMEM_COMPRESS
union {
uint imcSize;
uint64 imcUnusedSince;
};
void *imcData;
void imcCompress();
void imcUncompress();
#endif
uint blkMem;
State getState();
class ChangeHelper {
private:
Chunk &C;
std::vector<glm::ivec3> m_changes;
public:
bool enabled;
ChangeHelper(Chunk &C);
void add(int x, int y, int z);
bool empty() const;
int count() const;
void flush(Net::MsgTypes::BlockUpdateNotify&);
void discard();
} CH;
Chunk(Game *G, WorldRef W, int X, int Y, int Z);
~Chunk();
/* ============ Events ============ */
void onRenderPropertiesChanged();
/* ============ Getters ============ */
/**
* @brief Get the World in which this Chunk resides.
* @return Reference to belonging World.
*/
inline WorldRef getWorld() const {
return W;
}
/**
* @brief Get this Chunk's position in the World.
* @return Chunk's position in the World.
*/
inline glm::ivec3 getWorldChunkPos() const {
return glm::ivec3(wcx, wcy, wcz);
}
/**
* @brief Get the block ID at specified location.
* @param x X block coordinate within the Chunk.
* @param y Y block coordinate within the Chunk.
* @param z Z block coordinate within the Chunk.
* @return The block ID at specified location.
*/
BlockId getBlockId(int x, int y, int z);
/**
* @brief Get the block data at specified location.
* @param x X block coordinate within the Chunk.
* @param y Y block coordinate within the Chunk.
* @param z Z block coordinate within the Chunk.
* @return Block's data integer.
*/
BlockData getBlockData(int x, int y, int z);
/**
* @brief Get if the block has extdata.
* @param x X block coordinate within the Chunk.
* @param y Y block coordinate within the Chunk.
* @param z Z block coordinate within the Chunk.
* @return `true` if block has extdata, `false` otherwise.
*/
bool blockHasExtdata(int x, int y, int z);
#if 0
/**
* @brief Gets a block's extdata.
* Gets a block's extdata store, to save advanced state values.
* @param x
* @param y
* @param z
* @return Block's extdata.
* @throws NoExtdataOnBlock if the targeted block doesn't have extdata
*/
goodform::object& getBlockExtdata(int x, int y, int z);
#endif
bool isDirty() const {
return dirty;
}
/* ============ Setters ============ */
/**
* @brief Set the block at specified location, replacing its ID and data.
* @param x X block coordinate within the Chunk.
* @param y Y block coordinate within the Chunk.
* @param z Z block coordinate within the Chunk.
* @param id Block ID to set.
* @param data Block data to set.
*/
void setBlock(int x, int y, int z, BlockId id, BlockData data = 0);
/**
* @brief Set the block ID at specified location, keeping its (meta)data.
* @param x X block coordinate within the Chunk.
* @param y Y block coordinate within the Chunk.
* @param z Z block coordinate within the Chunk.
* @param id Block ID to set.
*/
void setBlockId(int x, int y, int z, BlockId id);
/**
* @brief Set the block data at specified location, keeping its ID.
* @param x X block coordinate within the Chunk.
* @param y Y block coordinate within the Chunk.
* @param z Z block coordinate within the Chunk.
* @param data Block data to set.
*/
void setBlockData(int x, int y, int z, BlockData data);
// Copies extdata tree
// TODO void setExtdata(const msgpack::object &meta);
/* ============ Updates ============ */
void notifyChange(int x, int y, int z);
/**
* @brief Marks chunk as dirty.
* Marks chunk as dirty so it is re-rendered.
*/
void markAsDirty();
void updateClient();
void updateServer();
/* ============ Serialization ============ */
void write(IO::OutStream&) const;
void read(IO::InStream&);
};
using ChunkRef = std::shared_ptr<Chunk>;
using ChunkWeakRef = std::weak_ptr<Chunk>;
}
#endif