Basic layout for world loading
This commit is contained in:
parent
f0043ded2a
commit
d4256e9e32
|
@ -4,6 +4,7 @@
|
||||||
#include "PacketReader.h"
|
#include "PacketReader.h"
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace Feather
|
namespace Feather
|
||||||
{
|
{
|
||||||
|
@ -13,7 +14,9 @@ namespace Feather
|
||||||
m_status()
|
m_status()
|
||||||
{
|
{
|
||||||
m_status.descriptionText = properties->motd.GetValue();
|
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)
|
while (1)
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,8 +5,11 @@
|
||||||
#include "protocol/Protocol.h"
|
#include "protocol/Protocol.h"
|
||||||
#include "PacketReader.h"
|
#include "PacketReader.h"
|
||||||
|
|
||||||
|
#include "world/WorldManager.h"
|
||||||
|
|
||||||
#include "network/IListenerInterface.h"
|
#include "network/IListenerInterface.h"
|
||||||
|
|
||||||
|
|
||||||
namespace Feather
|
namespace Feather
|
||||||
{
|
{
|
||||||
class ServerProperties;
|
class ServerProperties;
|
||||||
|
@ -33,5 +36,8 @@ namespace Feather
|
||||||
ServerStatus m_status;
|
ServerStatus m_status;
|
||||||
|
|
||||||
LockableList<MinecraftClient> m_clients;
|
LockableList<MinecraftClient> m_clients;
|
||||||
|
|
||||||
|
WorldManager m_worldManager;
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
35
src/Types.h
35
src/Types.h
|
@ -23,7 +23,7 @@ namespace Feather
|
||||||
|
|
||||||
struct BlockPos
|
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) {}
|
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 Z_OFFSET = PACKED_Y_LENGTH;
|
||||||
static const int X_OFFSET = PACKED_Y_LENGTH + PACKED_Z_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) {}
|
||||||
|
};
|
||||||
}
|
}
|
|
@ -17,6 +17,10 @@ feather_src = [
|
||||||
|
|
||||||
'config/Properties.cpp',
|
'config/Properties.cpp',
|
||||||
'config/ServerProperties.cpp',
|
'config/ServerProperties.cpp',
|
||||||
|
|
||||||
|
'world/World.cpp',
|
||||||
|
'world/WorldManager.cpp',
|
||||||
|
'world/RegionFile.cpp',
|
||||||
]
|
]
|
||||||
|
|
||||||
subdir('protocol')
|
subdir('protocol')
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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; }
|
||||||
|
};
|
||||||
|
}
|
|
@ -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";
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
};
|
|
@ -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);
|
||||||
|
};
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in New Issue