FeatherMC/src/world/World.cpp

155 lines
3.9 KiB
C++
Raw Normal View History

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-11-07 01:51:08 +00:00
// TODO: move this to ChunkSection
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)
: 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-14 02:41:05 +01:00
void World::PrepareSpawn()
{
Log::Info("Loading spawn area...");
BlockPos spawnPos(m_levelData.spawnX, m_levelData.spawnY, m_levelData.spawnZ);
ChunkPos spawnChunk(spawnPos);
for (int x = -10; x <= 10; x++) {
for (int z = -10; z <= 10; z++) {
GetChunk(ChunkPos(spawnChunk.x + x, spawnChunk.z + z));
}
}
Log::Info("Finished loading spawn area.");
}
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();
}
2020-11-05 00:32:44 +00:00
bool World::SetBlock(const BlockPos& pos, const BlockState& state)
{
if (IsOutsideBuildHeight(pos)) return false;
Chunk* chunk = GetChunk(ChunkPos(pos));
Log::Debug("World::SetBlock at BlockPos({}, {}, {}) -> ChunkPos({}, {})",
pos.x, pos.y, pos.z,
chunk->pos.x, chunk->pos.z
);
return chunk->SetBlock(pos, state);
}
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
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();
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);
2020-08-14 02:41:05 +01:00
if (!chunkStream->good()) {
Log::Error("Failed to find chunk ({}, {}) on disk.", pos.x, pos.z);
return nullptr;
}
2020-08-13 04:15:51 +01:00
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];
2020-08-14 02:42:21 +01:00
//Log::Trace("Loading chunk: Length: {}. Compression: {}", length, compressionType);
2020-08-13 04:15:51 +01:00
char* chunkData = new char[length + 1];
chunkStream->read(chunkData, length);
auto nbt = std::make_unique<NBT::CompoundTag>(chunkData, length);
if (!*nbt) return nullptr;
2020-08-07 05:48:54 +01:00
2020-08-14 02:42:21 +01:00
//std::cout << *nbt << "\n";
2020-08-07 05:48:54 +01:00
return std::make_unique<Chunk>(pos, std::move(nbt));
2020-08-07 05:48:54 +01:00
}
2020-11-05 00:32:44 +00:00
};