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."
This commit is contained in:
Alpyne 2020-11-04 14:59:50 -08:00
parent b15e039d61
commit b218552cc4
6 changed files with 121 additions and 16 deletions

View File

@ -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<uint64_t>(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<uint64_t>(data[i]);
}
}
//Log::Trace("Section bits: {:#b}", sectionsBits);

View File

@ -3,6 +3,8 @@
#include <mutex>
#include <vector>
#include <list>
#include <map>
#include <array>
namespace Feather
{
@ -25,4 +27,10 @@ namespace Feather
template <typename T>
using LockableList = Lockable<std::list<T>>;
template <typename Key, typename T>
using LockableMap = Lockable<std::map<Key, T>>;
template <typename T, size_t Size>
using LockableArray = Lockable<std::array<T, Size>>;
}

View File

@ -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
};
}
}

View File

@ -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;
}
}

View File

@ -44,8 +44,17 @@ namespace Feather
Chunk(ChunkPos& pos, std::unique_ptr<NBT::CompoundTag> 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);
};
};

View File

@ -2,8 +2,7 @@
#include "Common.h"
#include "Palette.h"
#include <array>
#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<uint64, NUM_LONGS> data;
static constexpr size_t BITS_PER_CELL = bitsizeof(uint64);
LockableArray<uint64, NUM_LONGS> data;
// TODO: this could eventually be Palette<BlockState> 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; }
};