#pragma once #include #include #include #include #include #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 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(x) }, Y{ static_cast(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(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{}(*reinterpret_cast(this)); } uint32_t hash() const { return static_cast(hash64()); } static uint32_t hash(ChunkKey key) { return key.hash(); } Bounds SetBounds() 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() { Chunk = {}; Entities.resize(0); } public: std::unique_ptr Chunk{}; std::vector Entities{}; std::vector 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); void SetChunkTiles(ChunkKey key, std::unique_ptr&& chunk); void AddEntity(flecs::entity entity, tcb::span claimedPositions); void AddPersistantEntity(flecs::entity entity, tcb::span 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 ChunkDatas; std::unordered_map 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 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]; } // };