2020-08-07 05:48:54 +01:00
|
|
|
#include "Common.h"
|
|
|
|
#include "Types.h"
|
|
|
|
#include "World.h"
|
|
|
|
#include "nbt/NBT.h"
|
|
|
|
#include "RegionFile.h"
|
2020-08-13 04:10:44 +01:00
|
|
|
#include "data/Registry.h"
|
2020-08-07 05:48:54 +01:00
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
#include <fstream>
|
|
|
|
#include <filesystem>
|
|
|
|
#include <sstream>
|
|
|
|
|
|
|
|
namespace fs = std::filesystem;
|
|
|
|
using std::string;
|
|
|
|
using std::stringstream;
|
|
|
|
|
|
|
|
namespace Feather
|
|
|
|
{
|
2020-08-13 04:10:44 +01:00
|
|
|
const GlobalPalette<BlockState> World::GLOBAL_PALETTE = GlobalPalette<BlockState>(
|
|
|
|
Registry::BLOCK_STATES,
|
|
|
|
new BlockState("minecraft:air") // temp
|
|
|
|
);
|
|
|
|
|
2020-08-07 05:48:54 +01:00
|
|
|
static bool CheckPath(fs::path path, bool dir = false)
|
|
|
|
{
|
|
|
|
if (!fs::exists(path) || (dir && !fs::is_directory(path)))
|
|
|
|
{
|
2020-08-07 06:25:10 +01:00
|
|
|
if (dir) Log::Error("Cannot find folder \"{}\"", path.string().c_str());
|
|
|
|
else Log::Error("Cannot find file \"{}\"", path.string().c_str());
|
2020-08-07 05:48:54 +01:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
World::World(string name)
|
2020-08-13 18:06:28 +01:00
|
|
|
: m_name(name)
|
2020-08-07 05:48:54 +01:00
|
|
|
{
|
|
|
|
fs::path worldPath = fs::path(name);
|
|
|
|
if (!CheckPath(worldPath)) return;
|
|
|
|
|
|
|
|
fs::path levelDatPath = worldPath/"level.dat";
|
|
|
|
if (!CheckPath(levelDatPath)) return;
|
|
|
|
|
|
|
|
|
2020-08-07 06:25:10 +01:00
|
|
|
Log::Info("Loading world \"{}\"", name.c_str());
|
2020-08-07 05:48:54 +01:00
|
|
|
|
|
|
|
NBT::CompoundTag levelDat = NBT::CompoundTag(levelDatPath.string().c_str());
|
|
|
|
|
|
|
|
//std::cout << levelDat << "\n";
|
|
|
|
|
|
|
|
m_levelData.spawnX = levelDat.Get<int32_t>("SpawnX");
|
|
|
|
m_levelData.spawnY = levelDat.Get<int32_t>("SpawnY");
|
|
|
|
m_levelData.spawnZ = levelDat.Get<int32_t>("SpawnZ");
|
2020-08-13 18:06:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2020-08-07 05:48:54 +01:00
|
|
|
|
2020-08-13 18:06:28 +01:00
|
|
|
fs::path regionsPath = worldPath / "region";
|
|
|
|
if (!CheckPath(regionsPath)) return nullptr;
|
|
|
|
|
|
|
|
RegionPos regionPos(pos);
|
|
|
|
RegionLocalPos regionChunkPos(pos);
|
2020-08-07 05:48:54 +01:00
|
|
|
|
|
|
|
stringstream regionFile;
|
|
|
|
regionFile << "r." << regionPos.x << "." << regionPos.z << ".mca";
|
|
|
|
|
|
|
|
fs::path mcaFile = regionsPath / regionFile.str();
|
2020-08-13 18:06:28 +01:00
|
|
|
if (!CheckPath(mcaFile)) return nullptr;
|
2020-08-07 05:48:54 +01:00
|
|
|
|
2020-08-13 04:15:51 +01:00
|
|
|
//Log_Info("Spawn Chunk Region File: %s", mcaFile.string().c_str());
|
2020-08-07 05:48:54 +01:00
|
|
|
RegionFile region(mcaFile.string());
|
2020-08-13 04:15:51 +01:00
|
|
|
|
|
|
|
//int regionOffset = region.GetOffset(regionChunkPos);
|
|
|
|
|
|
|
|
//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);
|
|
|
|
|
2020-08-13 18:06:28 +01:00
|
|
|
auto nbt = std::make_unique<NBT::CompoundTag>(chunkData, length);
|
|
|
|
if (!*nbt) return nullptr;
|
2020-08-07 05:48:54 +01:00
|
|
|
|
2020-08-13 18:06:28 +01:00
|
|
|
std::cout << *nbt << "\n";
|
2020-08-07 05:48:54 +01:00
|
|
|
|
2020-08-13 18:06:28 +01:00
|
|
|
return std::make_unique<Chunk>(pos, std::move(nbt));
|
2020-08-07 05:48:54 +01:00
|
|
|
}
|
|
|
|
};
|