Initial work on sending multiple chunks

This commit is contained in:
Joshua Ashton 2020-08-13 18:06:28 +01:00
parent 4e1a4c92b3
commit 5d1257456f
7 changed files with 151 additions and 113 deletions

View File

@ -191,92 +191,99 @@ namespace Feather
// SEND CHUNKS
NetworkMessage chunkData(5KB);
// Packet ID
chunkData.WriteVarInt(0x22);
// Chunk X, Z
//chunkData.Write<int32_t>(-10);
//chunkData.Write<int32_t>(-12);
chunkData.Write<int32_t>(0);
chunkData.Write<int32_t>(0);
// Full chunk
chunkData.Write<bool>(true);
Chunk* chunk = m_worldManager.GetOverworld()->m_chunk;
NBT::CompoundTag* chunkNBT = m_worldManager.GetOverworld()->m_chunkNBT;
int32_t sectionsBits = 0;
NetworkMessage sections(3KB);
for (int i = 0; i < Chunk::NUM_SECTIONS; i++)
auto levelData = m_worldManager.GetOverworld()->GetLevelData();
ChunkPos spawnChunk = BlockPos(levelData.spawnX, levelData.spawnY, levelData.spawnZ);
int32_t viewDistance = m_properties->viewDistance;
for (int32_t x = spawnChunk.x - viewDistance; x < spawnChunk.x + viewDistance; x++)
{
const ChunkSection& sect = chunk->sections[i];
Log::Trace("Chunk: Got Section {} with local palette size {}", i, sect.localPalette.Size());
sectionsBits |= 1 << i;
// Block Count: fudge
sections.Write<int16_t>(1024);
const uint8_t bitsPerBlock = sect.bitsPerBlock;
sections.Write<uint8_t>(bitsPerBlock);
const size_t dataLength = (16 * 16 * 16) * bitsPerBlock / 64;
if (bitsPerBlock <= 8)
for (int32_t z = spawnChunk.z - viewDistance; z < spawnChunk.z + viewDistance; z++)
{
// Palette
sections.WriteVarInt(sect.localPalette.Size());
NetworkMessage chunkData(5KB);
// Packet ID
chunkData.WriteVarInt(0x22);
for (size_t j = 0; j < sect.localPalette.Size(); j++)
sections.WriteVarInt(sect.localPalette.ByID(j));
// Chunk X, Z
chunkData.Write<int32_t>(x);
chunkData.Write<int32_t>(z);
// Full chunk
chunkData.Write<bool>(true);
Chunk* chunk = m_worldManager.GetOverworld()->GetChunk({ x, z });
if (!chunk)
continue;
NBT::CompoundTag* chunkNBT = chunk->nbt.get();
int32_t sectionsBits = 0;
NetworkMessage sections(3KB);
for (int i = 0; i < Chunk::NUM_SECTIONS; i++)
{
const ChunkSection& sect = chunk->sections[i];
Log::Trace("Chunk: Got Section {} with local palette size {}", i, sect.localPalette.Size());
sectionsBits |= 1 << i;
// Block Count: fudge
sections.Write<int16_t>(1024);
const uint8_t bitsPerBlock = sect.bitsPerBlock;
sections.Write<uint8_t>(bitsPerBlock);
const size_t dataLength = (16 * 16 * 16) * bitsPerBlock / 64;
if (bitsPerBlock <= 8)
{
// Palette
sections.WriteVarInt(sect.localPalette.Size());
for (size_t j = 0; j < sect.localPalette.Size(); j++)
sections.WriteVarInt(sect.localPalette.ByID(j));
}
sections.WriteVarInt(dataLength);
// Can't just copy because endian-ness!
for (size_t i = 0; i < dataLength; i++)
sections.Write<uint64_t>(sect.blockStates[i]);
}
Log::Trace("Section bits: {:#b}", sectionsBits);
chunkData.WriteVarInt(sectionsBits);
// Heightmaps
// TODO: Use chunk->heightmaps
NBT::DataBuffer buf = chunkNBT->Get<NBT::CompoundTag>("Heightmaps").GetData();
chunkData.WriteData(buf.data, buf.length);
// Biomes
NBT::IntArrayTag biomes = chunkNBT->Get<NBT::IntArrayTag>("Biomes");
for (uint32_t i = 0; i < 1024; i++)
chunkData.Write<int32_t>(biomes[i]);
sections.Finalize();
chunkData.WriteSubMessage(sections);
// Block Ents
chunkData.WriteVarInt(0);
chunkData.Finalize();
client.SendMessage(chunkData);
}
sections.WriteVarInt(dataLength);
// Can't just copy because endian-ness!
for (size_t i = 0; i < dataLength; i++)
sections.Write<uint64_t>(sect.blockStates[i]);
}
Log::Trace("Section bits: {:#b}", sectionsBits);
chunkData.WriteVarInt(sectionsBits);
// Heightmaps
// TODO: Use chunk->heightmaps
NBT::DataBuffer buf = chunkNBT->Get<NBT::CompoundTag>("Heightmaps").GetData();
chunkData.WriteData(buf.data, buf.length);
// Biomes
NBT::IntArrayTag biomes = chunkNBT->Get<NBT::IntArrayTag>("Biomes");
for (uint32_t i = 0; i < 1024; i++)
chunkData.Write<int32_t>(biomes[i]);
sections.Finalize();
chunkData.WriteSubMessage(sections);
// Block Ents
chunkData.WriteVarInt(0);
chunkData.Finalize();
client.SendMessage(chunkData);
// UPDATE POSITION
using RelativeFlags = Play::ClientboundPlayerPositionAndLook::RelativeFlags;
Play::ClientboundPlayerPositionAndLook playerPos =
{
.x = 0,
.y = 87,
.z = 0,
.x = double(levelData.spawnX),
.y = double(levelData.spawnY),
.z = double(levelData.spawnZ),
.xRot = 0,
.yRot = 0,
.flags = RelativeFlags(0),

View File

@ -4,6 +4,7 @@
#include "ServerStatus.h"
#include "protocol/Protocol.h"
#include "PacketReader.h"
#include "JobManager.h"
#include "world/WorldManager.h"
@ -38,6 +39,6 @@ namespace Feather
LockableList<MinecraftClient> m_clients;
WorldManager m_worldManager;
JobRunner m_jobRunner;
};
}

View File

@ -55,7 +55,7 @@ namespace Feather
struct ChunkPos
{
const int32_t x, z;
int32_t x, z;
ChunkPos(int32_t x, int32_t z) : x(x), z(z) {}
@ -70,6 +70,16 @@ namespace Feather
{
return ((int64_t)x & 0xFFFFFFFF) | (((int64_t)z & 0xFFFFFFFF) << 32);
}
bool operator==(const ChunkPos& o) const
{
return x == o.x && z == o.z;
}
bool operator<(const ChunkPos& o) const
{
return x < o.x || (x == o.x && z < o.z);
}
};
// Which 32x32 chunk region file (r.<x>.<z>.mca) the chunk is stored in

View File

@ -3,11 +3,11 @@
namespace Feather
{
Chunk::Chunk(ChunkPos& pos, NBT::CompoundTag& tag) :
pos(pos)
Chunk::Chunk(ChunkPos& pos, std::unique_ptr<NBT::CompoundTag> tag)
: pos(pos), nbt(std::move(tag))
{
using namespace NBT;
CompoundTag level = tag.GetCompound("Level");
CompoundTag level = nbt->GetCompound("Level");
Log::Trace("Loading chunk ({}, {}) from NBT", pos.x, pos.z);

View File

@ -8,7 +8,6 @@
#include <cstdint>
namespace Feather
{
// 16x16x16 sections of a chunk
@ -36,10 +35,13 @@ namespace Feather
ChunkPos pos;
// TODO: Nuke this shit!
std::unique_ptr<NBT::CompoundTag> nbt;
// TODO: save heightmaps here
// UNSERIALIZED
//const NBT::CompoundTag* heightmaps;
Chunk(ChunkPos& pos, NBT::CompoundTag& tag);
Chunk(ChunkPos& pos, std::unique_ptr<NBT::CompoundTag> tag);
};
};

View File

@ -35,13 +35,11 @@ namespace Feather
}
World::World(string name)
: m_name(name)
{
fs::path worldPath = fs::path(name);
if (!CheckPath(worldPath)) return;
fs::path regionsPath = worldPath/"region";
if (!CheckPath(regionsPath)) return;
fs::path levelDatPath = worldPath/"level.dat";
if (!CheckPath(levelDatPath)) return;
@ -55,24 +53,36 @@ namespace Feather
m_levelData.spawnX = levelDat.Get<int32_t>("SpawnX");
m_levelData.spawnY = levelDat.Get<int32_t>("SpawnY");
m_levelData.spawnZ = levelDat.Get<int32_t>("SpawnZ");
}
BlockPos spawnPos(m_levelData.spawnX, m_levelData.spawnY, m_levelData.spawnZ);
ChunkPos spawnChunk(spawnPos);
RegionPos regionPos(spawnChunk);
RegionLocalPos regionChunkPos(spawnChunk);
Chunk* World::GetChunk(ChunkPos pos)
{
auto [chunks, lock] = m_chunks.borrow();
if (chunks.find(pos) == chunks.end())
{
if (auto chunk = LoadChunk(pos))
chunks[pos] = std::move(chunk);
}
return chunks[pos].get();
}
std::unique_ptr<Chunk> World::LoadChunk(ChunkPos pos)
{
fs::path worldPath = fs::path(m_name);
if (!CheckPath(worldPath)) return nullptr;
fs::path regionsPath = worldPath / "region";
if (!CheckPath(regionsPath)) return nullptr;
RegionPos regionPos(pos);
RegionLocalPos regionChunkPos(pos);
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
);
if (!CheckPath(mcaFile)) return nullptr;
//Log_Info("Spawn Chunk Region File: %s", mcaFile.string().c_str());
RegionFile region(mcaFile.string());
@ -100,15 +110,11 @@ namespace Feather
char* chunkData = new char[length + 1];
chunkStream->read(chunkData, length);
m_chunkNBT = new NBT::CompoundTag(chunkData, length);
auto nbt = std::make_unique<NBT::CompoundTag>(chunkData, length);
if (!*nbt) return nullptr;
std::cout << *m_chunkNBT << "\n";
std::cout << *nbt << "\n";
m_chunk = new Chunk(spawnChunk, *m_chunkNBT);
/*for (auto& f : fs::directory_iterator(regionsPath))
{
std::cout << f.path() << "\n";
}*/
return std::make_unique<Chunk>(pos, std::move(nbt));
}
};

View File

@ -4,27 +4,39 @@
#include "nbt/NBT.h"
#include "Chunk.h"
#include "Palette.h"
#include "../Lockable.h"
#include <cstdint>
#include <string>
#include <map>
namespace Feather
{
struct LevelData
{
int32_t spawnX, spawnY, spawnZ;
};
class World
{
public:
World(std::string name);
// global palette of all block states
static const GlobalPalette<BlockState> GLOBAL_PALETTE;
// TEMP
NBT::CompoundTag* m_chunkNBT;
Chunk* m_chunk;
Chunk* GetChunk(ChunkPos pos);
struct LevelData
{
int32_t spawnX, spawnY, spawnZ;
} m_levelData;
LevelData GetLevelData() const { return m_levelData; }
World(std::string name);
private:
std::unique_ptr<Chunk> LoadChunk(ChunkPos pos);
Lockable<std::map<ChunkPos, std::unique_ptr<Chunk>>> m_chunks;
LevelData m_levelData;
// TODO nuke this shit
std::string m_name;
};
}