godot_voxel/storage/voxel_metadata.h

136 lines
4.0 KiB
C++

#ifndef VOXEL_METADATA_H
#define VOXEL_METADATA_H
#include "../util/memory.h"
//#include "../util/non_copyable.h"
#include "../util/span.h"
#include <cstdint>
namespace zylann::voxel {
// Voxel metadata is arbitrary, sparse data that can be attached to particular voxels.
// It is not intented at being an efficient or fast storage method, but rather a versatile one for special cases.
// For example, it can be used to store text, tags, inventory contents, or other complex states attached to a voxel.
// If you need to store smaller data much more frequently, you may rely on a data channel instead.
// Base interface for custom data types.
class ICustomVoxelMetadata {
public:
virtual ~ICustomVoxelMetadata() {}
// Gets how many bytes this metadata will occupy when serialized.
virtual size_t get_serialized_size() const = 0;
// Serializes this metadata into `dst`. The size of `dst` will be equal or greater than the size returned by
// `get_serialized_size()`. Returns how many bytes were written.
virtual size_t serialize(Span<uint8_t> dst) const = 0;
// Deserializes this metadata from the given bytes.
// Returns `true` on success, `false` otherwise. `out_read_size` must be assigned to the number of bytes read.
virtual bool deserialize(Span<const uint8_t> src, uint64_t &out_read_size) = 0;
virtual ICustomVoxelMetadata *duplicate() = 0;
};
// Container for one metadata instance. It owns the data.
class VoxelMetadata {
public:
enum Type : uint8_t { //
TYPE_EMPTY = 0,
TYPE_U64 = 1,
// Reserved predefined types.
TYPE_CUSTOM_BEGIN = 32,
// Types equal or greater will implement `ICustomVoxelMetadata`.
TYPE_APP_SPECIFIC_BEGIN = 40
// Nothing prevents registering custom types lower than this index, but for convenience, it should be used for
// application-specific types (aka game-specific). Lower indices can be used for engine-specific integrations.
};
static const unsigned int CUSTOM_TYPES_MAX_COUNT = 256 - TYPE_CUSTOM_BEGIN;
VoxelMetadata() {}
VoxelMetadata(VoxelMetadata &&other) {
_type = other._type;
_data = other._data;
other._type = TYPE_EMPTY;
}
~VoxelMetadata() {
clear();
}
inline void operator=(VoxelMetadata &&other) {
clear();
_type = other._type;
_data = other._data;
other._type = TYPE_EMPTY;
}
void clear();
inline Type get_type() const {
return Type(_type);
}
void set_u64(const uint64_t &v);
uint64_t get_u64() const;
void set_custom(uint8_t type, ICustomVoxelMetadata *custom_data);
ICustomVoxelMetadata &get_custom();
const ICustomVoxelMetadata &get_custom() const;
// Clears this metadata and makes it a duplicate of the given one.
void copy_from(const VoxelMetadata &src);
private:
union Data {
uint64_t u64_data;
ICustomVoxelMetadata *custom_data;
};
uint8_t _type = TYPE_EMPTY;
Data _data;
};
// Registry of custom metadata types, used to deserialize them from saved data.
class VoxelMetadataFactory {
public:
typedef ICustomVoxelMetadata *(*ConstructorFunc)();
static VoxelMetadataFactory &get_singleton();
VoxelMetadataFactory();
// Registers a custom metadata type.
// The `type` you choose should remain the same over time.
// It will be used in save files, so changing it could break old saves.
// `type` must be greater or equal to `VoxelMetadata::TYPE_CUSTOM_BEGIN`.
void add_constructor(uint8_t type, ConstructorFunc ctor);
template <typename T>
void add_constructor_by_type(uint8_t type) {
add_constructor(type, []() { //
// Doesn't compile if I directly return the newed instance
ICustomVoxelMetadata *c = ZN_NEW(T);
return c;
});
}
void remove_constructor(uint8_t type);
// Constructs a custom metadata type from the given type ID.
// The `type` must be greater or equal to `VoxelMetadata::TYPE_CUSTOM_BEGIN`.
// Returns `nullptr` if the type could not be constructed.
ICustomVoxelMetadata *try_construct(uint8_t type) const;
private:
FixedArray<ConstructorFunc, VoxelMetadata::CUSTOM_TYPES_MAX_COUNT> _constructors;
};
} //namespace zylann::voxel
#endif // VOXEL_METADATA_H