#include "Chunk.h" #include "World.h" namespace Feather { Chunk::Chunk(ChunkPos& pos, std::unique_ptr tag) : pos(pos), nbt(std::move(tag)) { using namespace NBT; CompoundTag level = nbt->GetCompound("Level"); //Log::Trace("Loading chunk ({}, {}) from NBT", pos.x, pos.z); if (pos.x != level.Get("xPos") || pos.z != level.Get("zPos")) { Log::Error("Tried to load chunk ({}, {}) from NBT but NBT says chunk pos is ({}, {})", pos.x, pos.z, level.Get("xPos"), level.Get("zPos") ); } // TODO: Heightmaps ListTag sectionsList = level.GetList("Sections"); int n = 0; for (CompoundTag& sectData : sectionsList) { //std::cout << sectData << "\n"; int8_t y = sectData.Get("Y"); if (y < 0 || y >= NUM_SECTIONS) { //Log::Trace("Skipping section {}", y); continue; } //Log::Trace("Loading section {}/{} at Y {}", n + 1, NUM_SECTIONS, y); if (n >= NUM_SECTIONS) { Log::Error("Chunk ({}, {}) has more than {} sections!", pos.x, pos.z, NUM_SECTIONS); break; } ChunkSection* section = §ions[y]; // Section Palette ListTag palette = sectData.GetList("Palette"); for (size_t i = 0; i < palette.GetLength(); i++) { CompoundTag state = palette[i]; const char* name = state.Get("Name").GetValue(); BlockState stateLookup(name); CompoundTag properties = state.GetCompound("Properties"); if (properties) { for (auto& prop : properties) { stateLookup.AddProperty(prop.GetName(), prop.GetValueString()); } } int id; // TODO: handle this in IdMapper try { id = World::GLOBAL_PALETTE.GetID(stateLookup); } catch (std::out_of_range& err) { (void)err; int defaultId = World::GLOBAL_PALETTE.GetDefaultID(); section->blockStates.palette.AddMapping(i, defaultId); Log::Warn("Chunk Section Palette maps id {} to invalid block state with name '{}'", i, name); continue; } // TODO: could use Add() section->blockStates.palette.AddMapping(i, id); //Log::Trace(" {} -> {} {}", i, id, name); } // Block States LongArrayTag blockStates = sectData.Get("BlockStates"); if (!blockStates) { Log::Warn("Skipping section with no block states."); continue; } Assert(blockStates.GetLength() < section->blockStates.GetNumLongs()); { 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)); n++; } } bool Chunk::SetBlock(const BlockPos& pos, const BlockState& state) { 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)) // 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; } }