Basic layout for world loading

This commit is contained in:
DankParrot 2020-08-06 21:48:54 -07:00
parent f0043ded2a
commit d4256e9e32
10 changed files with 234 additions and 2 deletions

View File

@ -4,6 +4,7 @@
#include "PacketReader.h"
#include <chrono>
#include <string>
namespace Feather
{
@ -13,7 +14,9 @@ namespace Feather
m_status()
{
m_status.descriptionText = properties->motd.GetValue();
m_status.maxPlayers = properties->maxPlayers.GetValue();
m_status.maxPlayers = properties->maxPlayers;
m_worldManager.LoadWorld(m_properties->levelName);
while (1)
{

View File

@ -5,8 +5,11 @@
#include "protocol/Protocol.h"
#include "PacketReader.h"
#include "world/WorldManager.h"
#include "network/IListenerInterface.h"
namespace Feather
{
class ServerProperties;
@ -33,5 +36,8 @@ namespace Feather
ServerStatus m_status;
LockableList<MinecraftClient> m_clients;
WorldManager m_worldManager;
};
}

View File

@ -23,7 +23,7 @@ namespace Feather
struct BlockPos
{
int32_t x, y, z;
const int32_t x, y, z;
BlockPos(int32_t x, int32_t y, int32_t z) : x(x), y(y), z(z) {}
@ -52,4 +52,37 @@ namespace Feather
static const int Z_OFFSET = PACKED_Y_LENGTH;
static const int X_OFFSET = PACKED_Y_LENGTH + PACKED_Z_LENGTH;
};
struct ChunkPos
{
const int32_t x, z;
ChunkPos(int32_t x, int32_t z) : x(x), z(z) {}
// Coordinate of the 16x16 chunk containing this block
ChunkPos(BlockPos pos) : x(pos.x >> 4), z(pos.z >> 4) {}
// Decode from packed int64
ChunkPos(int64_t packed) : x(packed), z(packed >> 32) {}
// Pack into one int64
inline int64_t Encode()
{
return ((int64_t)x & 0xFFFFFFFF) | (((int64_t)z & 0xFFFFFFFF) << 32);
}
};
// Which 32x32 chunk region file (r.<x>.<z>.mca) the chunk is stored in
struct RegionPos
{
const int32_t x, z;
RegionPos(ChunkPos pos) : x(pos.x >> 5), z(pos.z >> 5) {}
};
// Position of chunk relative to its region
struct RegionLocalPos
{
const int32_t x, z;
RegionLocalPos(ChunkPos pos) : x(pos.x & 0x1F), z(pos.z & 0x1F) {}
};
}

View File

@ -17,6 +17,10 @@ feather_src = [
'config/Properties.cpp',
'config/ServerProperties.cpp',
'world/World.cpp',
'world/WorldManager.cpp',
'world/RegionFile.cpp',
]
subdir('protocol')

32
src/world/RegionFile.cpp Normal file
View File

@ -0,0 +1,32 @@
#include "RegionFile.h"
#include "util/ByteUtil.h"
#include <fstream>
using std::string;
namespace Feather
{
RegionFile::RegionFile(string path)
{
std::ifstream stream(path);
stream.read(m_header, 8KB);
// Populate m_offsets
for (int i = 0; i < 1KB; i++)
{
int32_t readInt = 0;
std::memcpy(&readInt, &m_header[i * 4], sizeof(int32_t));
// Read big endian ints.
readInt = ReverseBytes(readInt);
m_offsets[i] = readInt;
if (readInt == 0) continue;
//int sector = GetSectorNumber(readInt);
//int sectorCount = GetSectorCount(readInt);
// We can record which sectors are used by this region here
}
}
}

29
src/world/RegionFile.h Normal file
View File

@ -0,0 +1,29 @@
#pragma once
#include "Common.h"
#include "Types.h"
#include <string>
namespace Feather
{
class RegionFile
{
char m_header[8KB];
int32_t m_offsets[1KB];
inline int GetOffsetIndex(RegionLocalPos pos) { return pos.x + pos.z * 32; }
public:
RegionFile(std::string path);
// Packed data about the offset into the region file to parse chunk data from
inline int GetOffset(RegionLocalPos pos) { return m_offsets[GetOffsetIndex(pos)]; }
// Contains data for this chunk?
inline bool HasChunk(ChunkPos pos) { return GetOffset(RegionLocalPos(pos)) != 0; }
// Unpack sector num from result of GetOffset()
static int GetSectorNumber(int packedOffset) { return packedOffset >> 8; }
// Unpack sector count from result of GetOffset()
static int GetSectorCount(int packedOffset) { return packedOffset & 0xFF; }
};
}

72
src/world/World.cpp Normal file
View File

@ -0,0 +1,72 @@
#include "Common.h"
#include "Types.h"
#include "World.h"
#include "nbt/NBT.h"
#include "RegionFile.h"
#include <iostream>
#include <fstream>
#include <filesystem>
#include <sstream>
namespace fs = std::filesystem;
using std::string;
using std::stringstream;
namespace Feather
{
static bool CheckPath(fs::path path, bool dir = false)
{
if (!fs::exists(path) || (dir && !fs::is_directory(path)))
{
if (dir) Log_Error("Cannot find folder \"%s\"", path.string().c_str());
else Log_Error("Cannot find file \"%s\"", path.string().c_str());
return false;
}
return true;
}
World::World(string 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;
Log_Info("Loading world \"%s\"", name.c_str());
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");
ChunkPos spawnChunk(BlockPos(m_levelData.spawnX, m_levelData.spawnY, m_levelData.spawnZ));
RegionPos regionPos(spawnChunk);
stringstream regionFile;
regionFile << "r." << regionPos.x << "." << regionPos.z << ".mca";
fs::path mcaFile = regionsPath / regionFile.str();
if (!CheckPath(mcaFile)) return;
//Log_Info("Spawn Chunk Region File: %s", mcaFile.string().c_str());
RegionFile region(mcaFile.string());
//std::cout << region << "\n";
/*for (auto& f : fs::directory_iterator(regionsPath))
{
std::cout << f.path() << "\n";
}*/
}
};

19
src/world/World.h Normal file
View File

@ -0,0 +1,19 @@
#pragma once
#include "Common.h"
#include <cstdint>
#include <string>
namespace Feather
{
class World
{
public:
struct LevelData
{
int32_t spawnX, spawnY, spawnZ;
} m_levelData;
World(std::string name);
};
}

View File

@ -0,0 +1,16 @@
#include "Common.h"
#include "WorldManager.h"
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
namespace Feather
{
void WorldManager::LoadWorld(string name)
{
world = new World(name);
}
}

18
src/world/WorldManager.h Normal file
View File

@ -0,0 +1,18 @@
#pragma once
#include "World.h"
#include <string>
using std::string;
namespace Feather
{
// TODO: this will manage different dimensions and worlds
class WorldManager
{
World* world;
public:
void LoadWorld(string name);
};
}