From b218552cc41d8166cb2212245e3269c6cdafe56a Mon Sep 17 00:00:00 2001 From: Alpyne Date: Wed, 4 Nov 2020 14:59:50 -0800 Subject: [PATCH] Block mutability for aligned bitfields (1.16 style) TODO: "In versions prior to 1.16, the full range of bits is used, where the remaining bits of a block index continue on the next long value." --- src/DedicatedServer.cpp | 13 +++++++-- src/Lockable.h | 8 ++++++ src/data/IDMapper.h | 7 ++++- src/world/Chunk.cpp | 43 ++++++++++++++++++++++++---- src/world/Chunk.h | 13 +++++++-- src/world/PalettedContainer.h | 53 +++++++++++++++++++++++++++++++---- 6 files changed, 121 insertions(+), 16 deletions(-) diff --git a/src/DedicatedServer.cpp b/src/DedicatedServer.cpp index 2e823d1..5160fe4 100644 --- a/src/DedicatedServer.cpp +++ b/src/DedicatedServer.cpp @@ -246,10 +246,17 @@ namespace Feather sections.WriteVarInt(sect.blockStates.palette.ByID(j)); } + // Block State Data + sections.WriteVarInt(dataLength); - // Can't just copy because endian-ness! - for (size_t i = 0; i < dataLength; i++) - sections.Write(sect.blockStates.data[i]); + + { + auto [data, lock] = sect.blockStates.data.borrow(); + + // Can't just copy because endian-ness! + for (size_t i = 0; i < dataLength; i++) + sections.Write(data[i]); + } } //Log::Trace("Section bits: {:#b}", sectionsBits); diff --git a/src/Lockable.h b/src/Lockable.h index 1d7e9e6..ed8f4dd 100644 --- a/src/Lockable.h +++ b/src/Lockable.h @@ -3,6 +3,8 @@ #include #include #include +#include +#include namespace Feather { @@ -25,4 +27,10 @@ namespace Feather template using LockableList = Lockable>; + + template + using LockableMap = Lockable>; + + template + using LockableArray = Lockable>; } diff --git a/src/data/IDMapper.h b/src/data/IDMapper.h index ebfb2c8..fcb16d5 100644 --- a/src/data/IDMapper.h +++ b/src/data/IDMapper.h @@ -46,6 +46,11 @@ namespace Feather return m_IDtoValue.at(id); } + inline bool HasValue(const T& value) const + { + return m_ValueToID.contains(value); + } + inline size_t Size() const { return m_IDtoValue.size(); @@ -53,4 +58,4 @@ namespace Feather }; -} \ No newline at end of file +} diff --git a/src/world/Chunk.cpp b/src/world/Chunk.cpp index d6f2db4..c6eac24 100644 --- a/src/world/Chunk.cpp +++ b/src/world/Chunk.cpp @@ -96,8 +96,12 @@ namespace Feather Assert(blockStates.GetLength() < section->blockStates.GetNumLongs()); - for (size_t i = 0; i < blockStates.GetLength(); i++) - section->blockStates.data[i] = blockStates[i]; + { + auto [data, lock] = section->blockStates.data.borrow(); + + for (size_t i = 0; i < blockStates.GetLength(); i++) + data[i] = blockStates[i]; + } section->blockStates.SetBits(Math::CeilDiv(blockStates.GetLength() * bitsizeof(int64), ChunkSection::NUM_BLOCKS)); @@ -108,11 +112,40 @@ namespace Feather } - bool Chunk::SetBlock(BlockPos& pos, BlockState& state) + bool Chunk::SetBlock(const BlockPos& pos, const BlockState& state) { - ChunkSection& section = sections[GetSection(pos)]; + int i = GetSection(pos); + ChunkSection& section = sections[i]; + + Log::Debug("Chunk::SetBlock: ({}, {}, {}) -> ({}, {}, {}) Chunk Local", + pos.x, pos.y, pos.z, + pos.x & 0xF, pos.y & 0xF, pos.z & 0xF + ); + int index = GetSectionIndex(pos); + + Log::Debug("Chunk::SetBlock -> section {}, index {}", i, index); + + //if (!section.blockStates.palette.HasValue(state)) - return false; + // TODO: temp code. use BlockState instead of global ID + { + int id = World::GLOBAL_PALETTE.GetID(state); + + if (!section.blockStates.palette.HasValue(id)) { + Log::Warn("Chunk::SetBlock for block that is not in section's local palette. NYI"); + return false; + } + + int localId = section.blockStates.palette.GetID(id); + + uint prev = section.blockStates.GetAndSet(index, localId); + + Log::Debug("Chunk::SetBlock changed block from {} to {}", prev, localId); + } + + //section.blockStates.GetAndSet(GetSectionIndex(pos), ) + + return true; } } diff --git a/src/world/Chunk.h b/src/world/Chunk.h index d4c9ed0..a431a2c 100644 --- a/src/world/Chunk.h +++ b/src/world/Chunk.h @@ -44,8 +44,17 @@ namespace Feather Chunk(ChunkPos& pos, std::unique_ptr tag); - inline int GetSection(BlockPos& pos) { return pos.y >> 4; } + inline int GetSection(const BlockPos& pos) { return pos.y >> 4; } - bool SetBlock(BlockPos& pos, BlockState& state); + inline int GetSectionIndex(const BlockPos& pos) + { + int x = pos.x & 0xF; + int y = pos.y & 0xF; + int z = pos.z & 0xF; + + return y << 8 | z << 4 | x; + } + + bool SetBlock(const BlockPos& pos, const BlockState& state); }; }; diff --git a/src/world/PalettedContainer.h b/src/world/PalettedContainer.h index 422f6c8..743bf6a 100644 --- a/src/world/PalettedContainer.h +++ b/src/world/PalettedContainer.h @@ -2,8 +2,7 @@ #include "Common.h" #include "Palette.h" - -#include +#include "Lockable.h" namespace Feather { @@ -15,7 +14,9 @@ namespace Feather static constexpr size_t NUM_LONGS = Math::CeilDiv(MaxSize * MaxBits, bitsizeof(uint64)); - std::array data; + static constexpr size_t BITS_PER_CELL = bitsizeof(uint64); + + LockableArray data; // TODO: this could eventually be Palette to avoid double lookup // Palette of local indexs to indexs in the global palette @@ -23,11 +24,53 @@ namespace Feather uint size = MaxSize; uint8 bits = MaxBits; + uint64 mask = 0; + uint valuesPerCell = 0; public: - PalettedContainer(uint size, uint8 bits) : size(size), bits(bits), data() {} + PalettedContainer(uint size, uint8 bits) : size(size), data() { SetBits(bits); } - inline void SetBits(uint8 nbits) { bits = nbits; } + inline void SetBits(uint8 nbits) + { + bits = nbits; + mask = (1 << bits) - 1; + valuesPerCell = BITS_PER_CELL / bits; + + Log::Debug("PalettedContainer::SetBits: {}, mask = {:#b}, valuesPerCell = {}", bits, mask, valuesPerCell); + } + + // TODO: optimize all math here + + inline int CellIndex(int index) + { + return index / valuesPerCell; + } + + // Update value, returns previous value + // TODO: change from uint to const T& + inline uint GetAndSet(int index, uint value) + { + auto [d, lock] = data.borrow(); + + int id = value; // palette.GetID(value); + int cellIndex = CellIndex(index); + uint64 shift = (index - cellIndex * valuesPerCell) * bits;//(index % valuesPerCell) * bits; + + Log::Debug("PalettedContainer::GetAndSet: index {} -> cell {}, [{}:{}]", index, cellIndex, shift, shift + bits); + + uint64 cell = d[cellIndex]; + int prev = (cell >> shift) & mask; + + //d[cellIndex] = ((cell & (mask << shift ^ 0xFFFFFFFFFFFFFFFFL)) | (uint64(id) & mask)) << shift; + + d[cellIndex] &= ~(mask << shift); // clear target bits + d[cellIndex] |= ((uint64)id & mask) << shift; // set target bits + + //Log::Debug("Changed from {:#b} to {:#b}", cell, d[cellIndex]); + Log::Debug("Changed from {} (g: {}) to {} (g: {})", prev, palette.ByID(prev), value, palette.ByID(value)); + + return (uint)prev; // palette.ByID(prev); + } inline constexpr size_t GetNumLongs() { return NUM_LONGS; } };