Initial work on sending multiple chunks
This commit is contained in:
parent
4e1a4c92b3
commit
5d1257456f
|
@ -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),
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
|
12
src/Types.h
12
src/Types.h
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
};
|
|
@ -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));
|
||||
}
|
||||
};
|
|
@ -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;
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue