Files
factory-hole-core/include/Core/Chunk.h
2026-02-20 22:50:05 +09:00

184 lines
5.4 KiB
C++

#pragma once
#include <stdint.h>
#include <array>
#include <memory>
#include <vector>
#include <unordered_map>
#include "Util/Span.h"
#include "config.h"
#include "Types/Tile.h"
#include "Components/Misc.hpp"
struct Chunk
{
public:
typedef uint8_t CoordinateType;
static constexpr int ChunkSizePowerOfTwo = 6;
static constexpr int ChunkSize = 1 << ChunkSizePowerOfTwo;
static constexpr int TotalChunkTiles = ChunkSize * ChunkSize;
static constexpr int ChunkMask = (1 << ChunkSizePowerOfTwo) - 1;
static_assert(sizeof(CoordinateType) * 8 >= ChunkSizePowerOfTwo, "CoordinateType is too small to support chunk size");
static constexpr uint8_t WorldToLocal(int world) { return world & ChunkMask; }
std::array<Tile, TotalChunkTiles> Tiles;
public:
static void Assert(int x, int y) { DEV_ASSERT(x < ChunkSize && x >= 0 && y < ChunkSize && y >= 0); }
public:
Tile GetTile(int x, int y) const { Assert(x, y); return Tiles[y * ChunkSize + x]; }
Tile GetTile(Vector2 pos) const { return GetTile(pos.X, pos.Y); }
const Tile& GetTileRef(int x, int y) const { Assert(x, y); return Tiles[y * ChunkSize + x]; }
Tile& GetTile(int x, int y) { Assert(x, y); return Tiles[y * ChunkSize + x]; }
Tile& GetTile(Vector2 pos) { return GetTile(pos.X, pos.Y); }
};
struct ChunkCoordinate
{
ChunkCoordinate() = default;
ChunkCoordinate(int x, int y) : X{ static_cast<uint8_t>(x) }, Y{ static_cast<uint8_t>(y) } { DEV_ASSERT(x >= 0 && x < Chunk::ChunkSize && y >= 0 && y < Chunk::ChunkSize); }
ChunkCoordinate(Vector2 pos) : ChunkCoordinate{pos.X, pos.Y} {}
uint8_t X{};
uint8_t Y{};
operator Vector2() const { return Vector2(X, Y); }
};
static_assert(sizeof(ChunkCoordinate) / 2 >= Chunk::ChunkSizePowerOfTwo / 8);
struct EntityTile final
{
public:
EntityTile() = default;
EntityTile(flecs::entity entity, int worldX, int worldY)
: Entity{ entity }
, ChunkX{ Chunk::WorldToLocal(worldX) }
, ChunkY{ Chunk::WorldToLocal(worldY) }
{}
public:
flecs::entity Entity{};
Chunk::CoordinateType ChunkX{};
Chunk::CoordinateType ChunkY{};
};
struct ChunkKey
{
public:
static constexpr int16_t WorldToChunk(int pos) { return static_cast<int16_t>(pos >> Chunk::ChunkSizePowerOfTwo); }
static constexpr int32_t ChunkToWorld(int16_t pos) { return pos << Chunk::ChunkSizePowerOfTwo; }
public:
int16_t X{}, Y{};
public:
ChunkKey() = default;
ChunkKey(int WorldX, int WorldY) : X{ WorldToChunk(WorldX) }, Y{ WorldToChunk(WorldY) } {}
public:
uint64_t hash64() const { static_assert(sizeof(uint32_t) == sizeof(ChunkKey)); return std::hash<uint32_t>{}(*reinterpret_cast<const uint32_t*>(this)); }
uint32_t hash() const { return static_cast<uint32_t>(hash64()); }
static uint32_t hash(ChunkKey key) { return key.hash(); }
Bounds GetBounds() const { return Bounds{Vector2{ChunkToWorld(X), ChunkToWorld(Y)}, Vector2{ChunkToWorld(X + 1), ChunkToWorld(Y + 1)}}; }
public:
bool operator==(const ChunkKey& rhs) const { return hash() == rhs.hash(); }
};
static_assert(sizeof(ChunkKey) == 4);
struct ChunkData
{
public:
void MarkAsPersistant(flecs::entity entity);
void RemovePersistance(flecs::entity entity);
void Clear()
{
TileData = {};
Entities.resize(0);
}
public:
std::unique_ptr<Chunk> TileData{};
std::vector<EntityTile> Entities{};
std::vector<EntityTile> PersistantEntities{};
};
struct ChunkCollection
{
public:
const Chunk& GetChunk(int x, int y);
const Chunk& GetChunk(ChunkKey key);
Chunk const* TryGetChunk(int x, int y) const;
Chunk const* TryGetChunk(ChunkKey key) const;
ChunkData& GetChunkData(int x, int y);
ChunkData& GetChunkData(ChunkKey key);
Tile GetTile(int x, int y);
Tile const* TryGetTile(int x, int y) const;
flecs::entity GetEntity(int x, int y) const;
void SetChunkTiles(int x, int y, std::unique_ptr<Chunk>&& chunk);
void SetChunkTiles(ChunkKey key, std::unique_ptr<Chunk>&& chunk);
void AddEntity(flecs::entity entity, tcb::span<Vector2> claimedPositions);
void AddPersistantEntity(flecs::entity entity, tcb::span<Vector2> claimedPositions);
void MarkAsPersistant(flecs::entity entity);
void RemovePersistance(flecs::entity entity);
void RemoveEntity(flecs::entity entity);
void RemoveChunk(int x, int y);
void RemoveChunk(ChunkKey key);
private:
int GetChunkIndex(int x, int y);
int GetChunkIndex(ChunkKey key);
int TryGetChunkIndex(int x, int y) const;
int TryGetChunkIndex(ChunkKey key) const;
Chunk& GetChunkInternal(int x, int y);
Chunk& GetChunkInternal(ChunkKey key);
Tile& GetTileInternal(int x, int y);
void SetTile(Tile tile, int x, int y);
void InvalidateCachedChunk();
private:
std::vector<ChunkData> ChunkDatas;
std::unordered_map<ChunkKey, int, ChunkKey> ChunkMap{};
ChunkKey CachedChunkKey{};
int CachedChunk{-1};
};
// struct LightValue
// {
// constexpr static uint8_t LightLevelBits = 5;
// constexpr static uint8_t PenetrationBits = 8 - LightLevelBits;
// constexpr static uint8_t MaxLightVal = (1 << LightLevelBits) - 1;
// constexpr static uint8_t MaxPenetration = (1 << PenetrationBits) - 1;
// uint8_t Penetration : PenetrationBits;
// uint8_t Val : LightLevelBits;
// LightValue()
// {
// Penetration = 1;
// Val = 0;
// }
// };
//static_assert(sizeof(LightValue) == 1);
// struct LightChunk
// {
// std::array<LightValue, Chunk::TotalChunkTiles> Tiles;
// public:
// LightValue GetTile(int x, int y) const { Chunk::Assert(x, y); return Tiles[y * Chunk::ChunkSize + x]; }
// LightValue& GetTile(int x, int y) { Chunk::Assert(x, y); return Tiles[y * Chunk::ChunkSize + x]; }
// };