Begin implementation of chunk loading
This commit is contained in:
parent
9689e7996f
commit
dc6677672a
|
@ -20,6 +20,7 @@ feather_src = [
|
|||
'config/Properties.cpp',
|
||||
'config/ServerProperties.cpp',
|
||||
|
||||
'world/Chunk.cpp',
|
||||
'world/World.cpp',
|
||||
'world/WorldManager.cpp',
|
||||
'world/RegionFile.cpp',
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
#include "Chunk.h"
|
||||
#include "World.h"
|
||||
|
||||
namespace Feather
|
||||
{
|
||||
Chunk::Chunk(ChunkPos& pos, NBT::CompoundTag& tag) :
|
||||
pos(pos)
|
||||
{
|
||||
using namespace NBT;
|
||||
CompoundTag level = tag.GetCompound("Level");
|
||||
|
||||
Log::Trace("Loading chunk ({}, {}) from NBT", pos.x, pos.z);
|
||||
|
||||
if (pos.x != level.Get<int>("xPos") || pos.z != level.Get<int>("zPos"))
|
||||
{
|
||||
Log::Error("Tried to load chunk ({}, {}) from NBT but NBT says chunk pos is ({}, {})",
|
||||
pos.x, pos.z,
|
||||
level.Get<int>("xPos"), level.Get<int>("zPos")
|
||||
);
|
||||
}
|
||||
|
||||
CompoundTag hmTag = level.GetCompound("Heightmaps");
|
||||
heightmaps = &hmTag;
|
||||
|
||||
ListTag<CompoundTag> sectionsList = level.GetList<CompoundTag>("Sections");
|
||||
|
||||
int n = 0;
|
||||
for (CompoundTag& sectData : sectionsList)
|
||||
{
|
||||
|
||||
//std::cout << sectData << "\n";
|
||||
|
||||
|
||||
int8_t y = sectData.Get<int8_t>("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;
|
||||
}
|
||||
|
||||
// Palette
|
||||
|
||||
ListTag<CompoundTag> palette = sectData.GetList<CompoundTag>("Palette");
|
||||
|
||||
for (int i = 0; i < palette.GetLength(); i++)
|
||||
{
|
||||
CompoundTag state = palette[i];
|
||||
const char* name = state.Get<StringTag>("Name").GetValue();
|
||||
|
||||
BlockState stateLookup(name);
|
||||
int id;
|
||||
|
||||
// TODO: handle this in IdMapper
|
||||
try {
|
||||
id = World::GLOBAL_PALETTE.GetID(stateLookup);
|
||||
}
|
||||
catch (std::out_of_range& err) {
|
||||
(void)err;
|
||||
Log::Warn("Chunk Section Palette maps id {} to invalid block state with name '{}'", i, name);
|
||||
continue;
|
||||
}
|
||||
|
||||
Log::Trace(" {} -> {} {}", i, id, name);
|
||||
}
|
||||
|
||||
// Block States
|
||||
|
||||
LongArrayTag blockStates = sectData.Get<LongArrayTag>("BlockStates");
|
||||
|
||||
if (!blockStates) {
|
||||
Log::Warn("Skipping section with no block states.");
|
||||
continue;
|
||||
}
|
||||
|
||||
int len = blockStates.GetLength();
|
||||
if (len != ChunkSection::NUM_LONGS) {
|
||||
Log::Warn("Section {} has {} longs, expected {}", y, len, ChunkSection::NUM_LONGS);
|
||||
}
|
||||
|
||||
ChunkSection section = Sections[y];
|
||||
|
||||
for (int i = 0; i < blockStates.GetLength() && i < ChunkSection::NUM_LONGS; i++)
|
||||
{
|
||||
section.blockStates[i] = blockStates[i];
|
||||
}
|
||||
|
||||
n++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
#pragma once
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
#include "nbt/NBT.h"
|
||||
#include "PalettedContainer.h"
|
||||
#include "block/state/BlockState.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
|
||||
namespace Feather
|
||||
{
|
||||
// 16x16x16 sections of a chunk
|
||||
class ChunkSection
|
||||
{
|
||||
public:
|
||||
// 4 bits per block
|
||||
// 16^3 = 4096 blocks total
|
||||
// 4096 * 4 = 16384 bits = 256x int64
|
||||
// 16 blocks per int64
|
||||
static constexpr int NUM_LONGS = 256;
|
||||
|
||||
int64_t blockStates[NUM_LONGS];
|
||||
};
|
||||
|
||||
// Chunk: 16x256x16 world chunk
|
||||
class Chunk
|
||||
{
|
||||
static constexpr int NUM_SECTIONS = 16;
|
||||
|
||||
// Each chunk is made of up 16 ChunkSections
|
||||
ChunkSection Sections[NUM_SECTIONS];
|
||||
|
||||
ChunkPos pos;
|
||||
|
||||
// UNSERIALIZED
|
||||
const NBT::CompoundTag* heightmaps;
|
||||
|
||||
public:
|
||||
Chunk(ChunkPos& pos, NBT::CompoundTag& tag);
|
||||
};
|
||||
};
|
|
@ -8,15 +8,16 @@ using std::string;
|
|||
namespace Feather
|
||||
{
|
||||
RegionFile::RegionFile(string path)
|
||||
: m_path(path)
|
||||
{
|
||||
std::ifstream stream(path, std::ifstream::binary);
|
||||
stream.read(m_header, 8KB);
|
||||
m_stream = new std::ifstream(path, std::ifstream::binary);
|
||||
m_stream->read(m_header, 8KB);
|
||||
|
||||
// Populate m_offsets
|
||||
for (int i = 0; i < 1024; i++)
|
||||
{
|
||||
int32_t readInt = 0;
|
||||
std::memcpy(&readInt, &m_header[i * 4], sizeof(int32_t));
|
||||
std::memcpy(&readInt, &m_header[i * sizeof(int32_t)], sizeof(int32_t));
|
||||
|
||||
// Read big endian ints.
|
||||
readInt = ReverseBytes(readInt);
|
||||
|
@ -26,6 +27,7 @@ namespace Feather
|
|||
|
||||
//int sector = GetSectorNumber(readInt);
|
||||
//int sectorCount = GetSectorCount(readInt);
|
||||
//Log::Trace("{}: Sector [{:x}] Count:{} Num:{}", i, readInt, sectorCount, sector);
|
||||
// We can record which sectors are used by this region here
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
#pragma once
|
||||
#include "Common.h"
|
||||
#include "Types.h"
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
namespace Feather
|
||||
{
|
||||
|
@ -10,6 +13,11 @@ namespace Feather
|
|||
char m_header[8KB];
|
||||
int32_t m_offsets[1KB];
|
||||
|
||||
// TEMP
|
||||
std::ifstream* m_stream;
|
||||
|
||||
std::string m_path;
|
||||
|
||||
inline int GetOffsetIndex(RegionLocalPos pos) { return pos.x + pos.z * 32; }
|
||||
public:
|
||||
RegionFile(std::string path);
|
||||
|
@ -20,8 +28,14 @@ namespace Feather
|
|||
// Contains data for this chunk?
|
||||
inline bool HasChunk(ChunkPos pos) { return GetOffset(RegionLocalPos(pos)) != 0; }
|
||||
|
||||
// TEMP
|
||||
std::ifstream* GetChunkStream(RegionLocalPos pos) {
|
||||
m_stream->seekg(GetSectorNumber(GetOffset(pos)));
|
||||
return m_stream;
|
||||
}
|
||||
|
||||
// Unpack sector num from result of GetOffset()
|
||||
static int GetSectorNumber(int packedOffset) { return packedOffset >> 8; }
|
||||
static int GetSectorNumber(int packedOffset) { return (packedOffset >> 8) * 4096; }
|
||||
|
||||
// Unpack sector count from result of GetOffset()
|
||||
static int GetSectorCount(int packedOffset) { return packedOffset & 0xFF; }
|
||||
|
|
|
@ -56,19 +56,55 @@ namespace Feather
|
|||
m_levelData.spawnY = levelDat.Get<int32_t>("SpawnY");
|
||||
m_levelData.spawnZ = levelDat.Get<int32_t>("SpawnZ");
|
||||
|
||||
ChunkPos spawnChunk(BlockPos(m_levelData.spawnX, m_levelData.spawnY, m_levelData.spawnZ));
|
||||
BlockPos spawnPos(m_levelData.spawnX, m_levelData.spawnY, m_levelData.spawnZ);
|
||||
ChunkPos spawnChunk(spawnPos);
|
||||
RegionPos regionPos(spawnChunk);
|
||||
RegionLocalPos regionChunkPos(spawnChunk);
|
||||
|
||||
stringstream regionFile;
|
||||
regionFile << "r." << regionPos.x << "." << regionPos.z << ".mca";
|
||||
|
||||
fs::path mcaFile = regionsPath / regionFile.str();
|
||||
if (!CheckPath(mcaFile)) return;
|
||||
Log::Trace("Spawn Chunk: Block({} {} {}) -> Chunk({} {}) -> Region({} {}) -> RegionChunk({} {})",
|
||||
spawnPos.x, spawnPos.y, spawnPos.z,
|
||||
spawnChunk.x, spawnChunk.z,
|
||||
regionPos.x, regionPos.z,
|
||||
regionChunkPos.x, regionChunkPos.z
|
||||
);
|
||||
|
||||
|
||||
//Log_Info("Spawn Chunk Region File: %s", mcaFile.string().c_str());
|
||||
|
||||
RegionFile region(mcaFile.string());
|
||||
|
||||
//int regionOffset = region.GetOffset(regionChunkPos);
|
||||
|
||||
//std::cout << region << "\n";
|
||||
//int sectorNum = RegionFile::GetSectorNumber(regionOffset);
|
||||
//Log::Trace("Loading chunk from offset: [{}] = {}", regionChunkPos.x + regionChunkPos.z * 32, sectorNum);
|
||||
|
||||
std::ifstream* chunkStream = region.GetChunkStream(regionChunkPos);
|
||||
|
||||
Log::Trace("{}", chunkStream->good());
|
||||
|
||||
char lengthBytes[5];
|
||||
chunkStream->read(lengthBytes, 5);
|
||||
|
||||
int32_t length = 0;
|
||||
std::memcpy(&length, lengthBytes, sizeof(int32_t));
|
||||
length = ReverseBytes(length);
|
||||
|
||||
int8_t compressionType = lengthBytes[4];
|
||||
|
||||
Log::Trace("Loading chunk: Length: {}. Compression: {}", length, compressionType);
|
||||
|
||||
char* chunkData = new char[length + 1];
|
||||
chunkStream->read(chunkData, length);
|
||||
|
||||
m_chunkNBT = new NBT::CompoundTag(chunkData, length);
|
||||
|
||||
std::cout << *m_chunkNBT << "\n";
|
||||
|
||||
m_chunk = new Chunk(spawnChunk, *m_chunkNBT);
|
||||
|
||||
/*for (auto& f : fs::directory_iterator(regionsPath))
|
||||
{
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "Common.h"
|
||||
#include "nbt/NBT.h"
|
||||
#include "Chunk.h"
|
||||
#include "Palette.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
@ -13,6 +15,11 @@ namespace Feather
|
|||
public:
|
||||
// global palette of all block states
|
||||
static const GlobalPalette<BlockState> GLOBAL_PALETTE;
|
||||
|
||||
// TEMP
|
||||
NBT::CompoundTag* m_chunkNBT;
|
||||
Chunk* m_chunk;
|
||||
|
||||
struct LevelData
|
||||
{
|
||||
int32_t spawnX, spawnY, spawnZ;
|
||||
|
|
Loading…
Reference in New Issue