mirror of
https://github.com/celisej567/mcpe.git
synced 2026-09-11 20:11:18 +03:00
* Start work on ExternalFileLevelStorage
This commit is contained in:
@@ -41,4 +41,7 @@
|
||||
// Toggle Demo Mode
|
||||
//#define DEMO
|
||||
|
||||
// Enable Debug Mode
|
||||
#define MC_DEBUG
|
||||
|
||||
#endif
|
||||
|
||||
@@ -11,17 +11,40 @@
|
||||
#include "Utils.hpp"
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <Windows.h>
|
||||
#include <io.h>
|
||||
#include <direct.h>
|
||||
|
||||
// XPL means "Cross PLatform"
|
||||
#define XPL_ACCESS _access
|
||||
#define XPL_MKDIR(path, mode) _mkdir(path)
|
||||
|
||||
// Why are we not using GetTickCount64()? It's simple -- getTimeMs has the exact same problem as using regular old GetTickCount.
|
||||
#pragma warning(disable : 28159)
|
||||
|
||||
#else
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define XPL_ACCESS access
|
||||
#define XPL_MKDIR(path, mode) mkdir(path, mode)
|
||||
#endif
|
||||
|
||||
#include "compat/GL.hpp"
|
||||
|
||||
int g_TimeSecondsOnInit = 0;
|
||||
|
||||
bool createFolderIfNotExists(const char* pDir)
|
||||
{
|
||||
if (!XPL_ACCESS(pDir, 0))
|
||||
return true;
|
||||
|
||||
return XPL_MKDIR(pDir, 0755) == 0;
|
||||
}
|
||||
|
||||
const char* GetTerrainName()
|
||||
{
|
||||
return "terrain.png";
|
||||
|
||||
@@ -504,6 +504,7 @@ constexpr float Lerp(float a, float b, float progress)
|
||||
return a + progress * (b - a);
|
||||
}
|
||||
|
||||
bool createFolderIfNotExists(const char* pDir);
|
||||
|
||||
// things that we added:
|
||||
#ifndef ORIGINAL_CODE
|
||||
@@ -537,3 +538,23 @@ void SetHWND(HWND hwnd);
|
||||
#define LogMsgNoCR(...)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef MC_DEBUG
|
||||
|
||||
#ifdef PLATFORM_ANDROID
|
||||
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, "MinecraftPE", __VA_ARGS__)
|
||||
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, "MinecraftPE", __VA_ARGS__)
|
||||
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, "MinecraftPE", __VA_ARGS__)
|
||||
#else
|
||||
#define LOGI(...) printf("Info: " __VA_ARGS__)
|
||||
#define LOGW(...) printf("WARN: " __VA_ARGS__)
|
||||
#define LOGE(...) printf("ERROR: " __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#define LOGI(...) printf(__VA_ARGS__)
|
||||
#define LOGW(...) printf(__VA_ARGS__)
|
||||
#define LOGE(...) printf(__VA_ARGS__)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -19,6 +19,36 @@ LevelData::LevelData(TLong seed, const std::string& name, int x)
|
||||
field_78 = name;
|
||||
}
|
||||
|
||||
void LevelData::read(RakNet::BitStream& bs, int version)
|
||||
{
|
||||
field_20 = version;
|
||||
bs.Read(m_seed);
|
||||
bs.Read(m_spawnPos.x);
|
||||
bs.Read(m_spawnPos.y);
|
||||
bs.Read(m_spawnPos.z);
|
||||
bs.Read(field_10);
|
||||
bs.Read(field_18);
|
||||
bs.Read(field_14);
|
||||
|
||||
RakNet::RakString rs;
|
||||
bs.Read(rs);
|
||||
field_78 = std::string(rs.C_String());
|
||||
}
|
||||
|
||||
void LevelData::write(RakNet::BitStream& bs, int d)
|
||||
{
|
||||
bs.Write(m_seed);
|
||||
bs.Write(m_spawnPos.x);
|
||||
bs.Write(m_spawnPos.y);
|
||||
bs.Write(m_spawnPos.z);
|
||||
bs.Write(field_10);
|
||||
bs.Write(field_18);
|
||||
bs.Write(int(getEpochTimeS()));
|
||||
|
||||
RakNet::RakString rs(field_78.c_str());
|
||||
bs.Write(rs);
|
||||
}
|
||||
|
||||
void PlayerData::loadPlayer(Player* player)
|
||||
{
|
||||
player->setPos(0.0f, 0.0f, 0.0f);
|
||||
@@ -43,3 +73,18 @@ void PlayerData::loadPlayer(Player* player)
|
||||
for (int i = 0; i < C_MAX_HOTBAR_ITEMS; i++)
|
||||
player->m_pInventory->setSelectionSlotItemId(i, m_hotbar[i]);
|
||||
}
|
||||
|
||||
void PlayerData::savePlayer(Player* player)
|
||||
{
|
||||
m_pos = player->m_pos;
|
||||
m_vel = player->m_vel;
|
||||
m_pitch = player->m_pitch;
|
||||
m_yaw = player->m_yaw;
|
||||
m_distanceFallen = player->m_distanceFallen;
|
||||
field_24 = player->field_C0;
|
||||
field_26 = player->field_BC;
|
||||
field_28 = player->field_7C;
|
||||
|
||||
for (int i = 0; i < C_MAX_HOTBAR_ITEMS; i++)
|
||||
m_hotbar[i] = player->m_pInventory->getSelectionSlotItemId(i);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "Utils.hpp"
|
||||
#include "Vec3.hpp"
|
||||
#include "Inventory.hpp"
|
||||
#include "BitStream.h"
|
||||
|
||||
struct PlayerData
|
||||
{
|
||||
@@ -27,6 +28,7 @@ struct PlayerData
|
||||
int m_hotbar[C_MAX_HOTBAR_ITEMS];
|
||||
|
||||
void loadPlayer(Player* player);
|
||||
void savePlayer(Player* player);
|
||||
};
|
||||
|
||||
struct LevelData
|
||||
@@ -34,15 +36,24 @@ struct LevelData
|
||||
LevelData();
|
||||
LevelData(TLong seed, const std::string&, int);
|
||||
|
||||
void read(RakNet::BitStream& bs, int d);
|
||||
void write(RakNet::BitStream& bs, int d);
|
||||
|
||||
TLong m_seed = 0;
|
||||
Pos m_spawnPos;
|
||||
TLong field_10 = 0;
|
||||
int field_14 = 0;
|
||||
int field_18 = 0;
|
||||
TLong field_18 = 0;
|
||||
int field_1C = 0;
|
||||
int field_20 = 0;
|
||||
PlayerData m_LocalPlayerData;
|
||||
int m_nPlayers = -1;
|
||||
std::string field_78;
|
||||
|
||||
// inlined in 0.1.0 demo
|
||||
int getVersion() const
|
||||
{
|
||||
return field_20;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
225
source/World/Storage/ExternalFileLevelStorage.cpp
Normal file
225
source/World/Storage/ExternalFileLevelStorage.cpp
Normal file
@@ -0,0 +1,225 @@
|
||||
#include "ExternalFileLevelStorage.hpp"
|
||||
#include "LevelChunk.hpp"
|
||||
|
||||
ExternalFileLevelStorage::ExternalFileLevelStorage(const std::string& a, const std::string& path) :
|
||||
field_8(a),
|
||||
m_levelDirPath(path)
|
||||
{
|
||||
createFolderIfNotExists(m_levelDirPath.c_str());
|
||||
|
||||
std::string datLevel = m_levelDirPath + "/" + "level.dat";
|
||||
std::string datPlayer = m_levelDirPath + "/" + "player.dat";
|
||||
|
||||
m_pLevelData = new LevelData;
|
||||
if (!readLevelData(datLevel, m_pLevelData))
|
||||
{
|
||||
delete m_pLevelData;
|
||||
m_pLevelData = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
readPlayerData(datPlayer, m_pLevelData);
|
||||
}
|
||||
|
||||
LevelData* ExternalFileLevelStorage::prepareLevel(Level* level)
|
||||
{
|
||||
m_pLevel = level;
|
||||
return m_pLevelData;
|
||||
}
|
||||
|
||||
ChunkStorage* ExternalFileLevelStorage::createChunkStorage(Dimension* pDim)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
void ExternalFileLevelStorage::saveLevelData(LevelData* levelData, std::vector<Player*>& players)
|
||||
{
|
||||
writeLevelData(m_levelDirPath + "/" + "level.dat", levelData);
|
||||
savePlayerData(levelData, players);
|
||||
|
||||
SAFE_DELETE(m_pLevelData);
|
||||
|
||||
m_pLevelData = new LevelData(*levelData);
|
||||
}
|
||||
|
||||
void ExternalFileLevelStorage::savePlayerData(LevelData* levelData, std::vector<Player*>& players)
|
||||
{
|
||||
if (players.empty())
|
||||
return;
|
||||
|
||||
FILE* pFile = fopen((m_levelDirPath + "/" + "player.dat").c_str(), "wb");
|
||||
if (!pFile)
|
||||
{
|
||||
LogMsg("Not saving player data");
|
||||
return;
|
||||
}
|
||||
|
||||
levelData->m_LocalPlayerData.savePlayer(players[0]);
|
||||
|
||||
int nPlayers = 1;
|
||||
fwrite(&nPlayers, sizeof nPlayers, 1, pFile);
|
||||
|
||||
int nSizePD = 80;
|
||||
fwrite(&nSizePD, sizeof nSizePD, 1, pFile);
|
||||
|
||||
// @NOTE: No reason to swap elementCount and elementSize here. I understood it the
|
||||
// last time - to check whether the data loaded all the way. However, no checks are
|
||||
// done here.
|
||||
fwrite(&levelData->m_LocalPlayerData, 1, nSizePD, pFile);
|
||||
|
||||
fclose(pFile);
|
||||
}
|
||||
|
||||
void ExternalFileLevelStorage::closeAll()
|
||||
{
|
||||
}
|
||||
|
||||
void ExternalFileLevelStorage::tick()
|
||||
{
|
||||
}
|
||||
|
||||
void ExternalFileLevelStorage::flush()
|
||||
{
|
||||
}
|
||||
|
||||
LevelChunk* ExternalFileLevelStorage::load(Level* level, int x, int z)
|
||||
{
|
||||
if (!m_pRegionFile)
|
||||
{
|
||||
m_pRegionFile = new RegionFile(m_levelDirPath);
|
||||
|
||||
if (!m_pRegionFile->open())
|
||||
{
|
||||
SAFE_DELETE(m_pRegionFile);
|
||||
m_pRegionFile = nullptr;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
RakNet::BitStream* pBitStream = nullptr;
|
||||
if (!m_pRegionFile->readChunk(x, z, &pBitStream))
|
||||
return nullptr;
|
||||
|
||||
pBitStream->ResetReadPointer();
|
||||
|
||||
TileID* pData = new TileID[16 * 16 * 128];
|
||||
pBitStream->Read((char*)pData, 16 * 16 * 128 * sizeof(TileID));
|
||||
|
||||
LevelChunk* pChunk = new LevelChunk(level, pData, x, z);
|
||||
pBitStream->Read((char*)pChunk->m_tileData, 16 * 16 * 128 / 2);
|
||||
|
||||
if (m_pLevelData->getVersion() == 1)
|
||||
{
|
||||
pBitStream->Read((char*)pChunk->m_lightSky, 16 * 16 * 128 / 2);
|
||||
pBitStream->Read((char*)pChunk->m_lightBlk, 16 * 16 * 128 / 2);
|
||||
}
|
||||
|
||||
pBitStream->Read((char*)pChunk->m_updateMap, sizeof pChunk->m_updateMap);
|
||||
|
||||
delete pBitStream->GetData();
|
||||
delete pBitStream;
|
||||
|
||||
pChunk->recalcHeightmap();
|
||||
pChunk->m_bUnsaved = false;
|
||||
pChunk->field_234 = true;
|
||||
pChunk->field_237 = true;
|
||||
|
||||
return pChunk;
|
||||
}
|
||||
|
||||
void ExternalFileLevelStorage::save(Level* level, LevelChunk* chunk)
|
||||
{
|
||||
if (!m_pRegionFile)
|
||||
m_pRegionFile = new RegionFile(m_levelDirPath);
|
||||
|
||||
if (!m_pRegionFile->open())
|
||||
{
|
||||
SAFE_DELETE(m_pRegionFile);
|
||||
m_pRegionFile = nullptr;
|
||||
|
||||
LogMsg("Not saving :( (x: %d z: %d)", chunk->m_chunkX, chunk->m_chunkZ);
|
||||
return;
|
||||
}
|
||||
|
||||
RakNet::BitStream bs;
|
||||
bs.Write((const char*)chunk->m_pBlockData, 16 * 16 * 128 * sizeof(TileID));
|
||||
bs.Write((const char*)chunk->m_tileData, 16 * 16 * 128 / 2);
|
||||
|
||||
if (m_pLevelData->field_20 == 1)
|
||||
{
|
||||
bs.Write((const char*)chunk->m_lightSky, 16 * 16 * 128 / 2);
|
||||
bs.Write((const char*)chunk->m_lightBlk, 16 * 16 * 128 / 2);
|
||||
}
|
||||
|
||||
bs.Write((const char*)chunk->m_updateMap, sizeof chunk->m_updateMap);
|
||||
|
||||
m_pRegionFile->writeChunk(chunk->m_chunkX, chunk->m_chunkZ, bs);
|
||||
}
|
||||
|
||||
void ExternalFileLevelStorage::saveEntities(Level* level, LevelChunk* chunk)
|
||||
{
|
||||
// no op
|
||||
}
|
||||
|
||||
bool ExternalFileLevelStorage::readLevelData(const std::string& path, LevelData* pLevelData)
|
||||
{
|
||||
FILE* pFile = fopen(path.c_str(), "rb");
|
||||
if (!pFile)
|
||||
return false;
|
||||
|
||||
int version = 0, length = 0;
|
||||
if (fread(&version, sizeof(int), 1, pFile) != 1)
|
||||
{
|
||||
_cleanup:
|
||||
fclose(pFile);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fread(&length, sizeof(int), 1, pFile) != 1)
|
||||
goto _cleanup;
|
||||
|
||||
uint8_t* data = new uint8_t[length];
|
||||
|
||||
if (fread(data, sizeof(uint8_t), length, pFile) != length)
|
||||
{
|
||||
SAFE_DELETE(data);
|
||||
goto _cleanup;
|
||||
}
|
||||
|
||||
RakNet::BitStream bs(data, length, false);
|
||||
pLevelData->read(bs, version);
|
||||
|
||||
SAFE_DELETE_ARRAY(data);
|
||||
fclose(pFile);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ExternalFileLevelStorage::readPlayerData(const std::string& path, LevelData* pLevelData)
|
||||
{
|
||||
FILE* pFile = fopen(path.c_str(), "rb");
|
||||
if (!pFile)
|
||||
return false;
|
||||
|
||||
// don't know if it's actually nPlayers or version
|
||||
int nPlayers = 0, size = 0;
|
||||
if (fread(&nPlayers, sizeof(int), 1, pFile) != 1)
|
||||
goto _cleanup;
|
||||
|
||||
if (fread(&size, sizeof(int), 1, pFile) != 1)
|
||||
goto _cleanup;
|
||||
|
||||
if (nPlayers != 1)
|
||||
goto _cleanup;
|
||||
|
||||
if (fread(&pLevelData->m_LocalPlayerData, 1, sizeof pLevelData->m_LocalPlayerData, pFile) == size)
|
||||
pLevelData->m_nPlayers = nPlayers;
|
||||
|
||||
fclose(pFile);
|
||||
return true;
|
||||
|
||||
_cleanup:
|
||||
fclose(pFile);
|
||||
return false;
|
||||
}
|
||||
41
source/World/Storage/ExternalFileLevelStorage.hpp
Normal file
41
source/World/Storage/ExternalFileLevelStorage.hpp
Normal file
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include "LevelStorage.hpp"
|
||||
#include "ChunkStorage.hpp"
|
||||
#include "RegionFile.hpp"
|
||||
|
||||
#ifndef DEMO
|
||||
|
||||
class ExternalFileLevelStorage : public LevelStorage, ChunkStorage
|
||||
{
|
||||
public:
|
||||
ExternalFileLevelStorage(const std::string& a, const std::string& path);
|
||||
|
||||
// LevelStorage
|
||||
LevelData* prepareLevel(Level* level) override;
|
||||
ChunkStorage* createChunkStorage(Dimension*) override;
|
||||
void saveLevelData(LevelData* levelData, std::vector<Player*>& players) override;
|
||||
void savePlayerData(LevelData* levelData, std::vector<Player*>& players) override;
|
||||
void closeAll() override;
|
||||
void tick() override;
|
||||
void flush() override;
|
||||
|
||||
// ChunkStorage
|
||||
LevelChunk* load(Level* level, int x, int z) override;
|
||||
void save(Level* level, LevelChunk* chunk) override;
|
||||
void saveEntities(Level* level, LevelChunk* chunk) override;
|
||||
|
||||
static bool readLevelData(const std::string& path, LevelData* pLevelData);
|
||||
static bool readPlayerData(const std::string& path, LevelData* pLevelData);
|
||||
|
||||
public:
|
||||
std::string field_8;
|
||||
std::string m_levelDirPath;
|
||||
LevelData* m_pLevelData = nullptr;
|
||||
RegionFile* m_pRegionFile = nullptr;
|
||||
Level* m_pLevel = nullptr;
|
||||
std::list<UnsavedLevelChunk> m_unsavedLevelChunks;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -154,6 +154,7 @@
|
||||
<ClInclude Include="..\source\World\Renderer\TntRenderer.hpp" />
|
||||
<ClInclude Include="..\source\World\Renderer\TripodCameraRenderer.hpp" />
|
||||
<ClInclude Include="..\source\World\Storage\ChunkStorage.hpp" />
|
||||
<ClInclude Include="..\source\World\Storage\ExternalFileLevelStorage.hpp" />
|
||||
<ClInclude Include="..\source\World\Storage\LevelSource.hpp" />
|
||||
<ClInclude Include="..\source\World\Storage\LevelStorage.hpp" />
|
||||
<ClInclude Include="..\source\World\Storage\LevelStorageSource.hpp" />
|
||||
@@ -472,6 +473,7 @@
|
||||
<ClCompile Include="..\source\World\Renderer\TntRenderer.cpp" />
|
||||
<ClCompile Include="..\source\World\Renderer\TripodCameraRenderer.cpp" />
|
||||
<ClCompile Include="..\source\World\Storage\ChunkStorage.cpp" />
|
||||
<ClCompile Include="..\source\World\Storage\ExternalFileLevelStorage.cpp" />
|
||||
<ClCompile Include="..\source\World\Storage\LevelSource.cpp" />
|
||||
<ClCompile Include="..\source\World\Storage\LevelStorage.cpp" />
|
||||
<ClCompile Include="..\source\World\Storage\LevelStorageSource.cpp" />
|
||||
|
||||
@@ -1062,6 +1062,9 @@
|
||||
<ClCompile Include="..\source\World\RegionFile.cpp">
|
||||
<Filter>Source Files\World</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\source\World\Storage\ExternalFileLevelStorage.cpp">
|
||||
<Filter>Source Files\World\Storage</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\source\Options.hpp">
|
||||
@@ -1931,6 +1934,9 @@
|
||||
<ClInclude Include="..\source\World\RegionFile.hpp">
|
||||
<Filter>Header Files\World</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\source\World\Storage\ExternalFileLevelStorage.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="..\thirdparty\raknet\CMakeLists.txt">
|
||||
|
||||
Reference in New Issue
Block a user