diff --git a/source/World/LevelData.cpp b/source/World/LevelData.cpp index e23aa18..7725d50 100644 --- a/source/World/LevelData.cpp +++ b/source/World/LevelData.cpp @@ -35,7 +35,7 @@ void LevelData::read(RakNet::BitStream& bs, int version) field_78 = std::string(rs.C_String()); } -void LevelData::write(RakNet::BitStream& bs, int d) +void LevelData::write(RakNet::BitStream& bs) { bs.Write(m_seed); bs.Write(m_spawnPos.x); diff --git a/source/World/LevelData.hpp b/source/World/LevelData.hpp index 5e6d3d2..4b382ad 100644 --- a/source/World/LevelData.hpp +++ b/source/World/LevelData.hpp @@ -37,7 +37,7 @@ struct LevelData LevelData(TLong seed, const std::string&, int); void read(RakNet::BitStream& bs, int d); - void write(RakNet::BitStream& bs, int d); + void write(RakNet::BitStream& bs); TLong m_seed = 0; Pos m_spawnPos; diff --git a/source/World/Storage/ExternalFileLevelStorage.cpp b/source/World/Storage/ExternalFileLevelStorage.cpp index 838df4d..abf0c6c 100644 --- a/source/World/Storage/ExternalFileLevelStorage.cpp +++ b/source/World/Storage/ExternalFileLevelStorage.cpp @@ -1,5 +1,8 @@ #include "ExternalFileLevelStorage.hpp" -#include "LevelChunk.hpp" +#include "Level.hpp" +#include "GetTime.h" + +#define C_CHUNKS_TO_SAVE_PER_TICK (2) ExternalFileLevelStorage::ExternalFileLevelStorage(const std::string& a, const std::string& path) : field_8(a), @@ -76,6 +79,57 @@ void ExternalFileLevelStorage::closeAll() void ExternalFileLevelStorage::tick() { + m_timer++; + if (m_timer % 50 != 0 || !m_pLevel) + return; + + for (int z = 0; z < C_MAX_CHUNKS_Z; z++) + { + for (int x = 0; x < C_MAX_CHUNKS_X; x++) + { + LevelChunk* pChunk = m_pLevel->getChunk(x, z); + if (!pChunk || !pChunk->m_bUnsaved) + continue; + + int index = x + z * 16; + + auto iter = m_unsavedLevelChunks.begin(); + for (; iter != m_unsavedLevelChunks.end(); ++iter) + { + if (iter->m_index == index) + { + iter->m_foundTime = RakNet::GetTimeMS(); + break; + } + } + + if (iter == m_unsavedLevelChunks.end()) + { + UnsavedLevelChunk ulc = { index, RakNet::GetTimeMS(), pChunk }; + m_unsavedLevelChunks.push_back(ulc); + } + + pChunk->m_bUnsaved = false; + } + } + + int count = 0; + while (count < C_CHUNKS_TO_SAVE_PER_TICK && !m_unsavedLevelChunks.empty()) + { + count++; + + auto iter = m_unsavedLevelChunks.begin(); + for (auto it2 = m_unsavedLevelChunks.begin(); it2 != m_unsavedLevelChunks.end(); ++it2) + { + if (iter->m_foundTime > it2->m_foundTime) + iter = it2; + } + + LevelChunk* pChunk = iter->m_pChunk; + m_unsavedLevelChunks.erase(iter); + + save(m_pLevel, pChunk); + } } void ExternalFileLevelStorage::flush() @@ -223,3 +277,22 @@ _cleanup: fclose(pFile); return false; } + +bool ExternalFileLevelStorage::writeLevelData(const std::string& path, LevelData* pLevelData) +{ + FILE* pFile = fopen(path.c_str(), "wb"); + if (!pFile) + return false; + + RakNet::BitStream bs; + pLevelData->write(bs); + + fwrite(&pLevelData->field_20, sizeof(int), 1, pFile); + + int length = bs.GetNumberOfBytesUsed(); + fwrite(&length, sizeof(int), 1, pFile); + fwrite(bs.GetData(), 1, length, pFile); + fclose(pFile); + + return true; +} diff --git a/source/World/Storage/ExternalFileLevelStorage.hpp b/source/World/Storage/ExternalFileLevelStorage.hpp index 88736b7..95664d6 100644 --- a/source/World/Storage/ExternalFileLevelStorage.hpp +++ b/source/World/Storage/ExternalFileLevelStorage.hpp @@ -7,6 +7,13 @@ #ifndef DEMO +struct UnsavedLevelChunk +{ + int m_index; + int m_foundTime; + LevelChunk* m_pChunk; +}; + class ExternalFileLevelStorage : public LevelStorage, ChunkStorage { public: @@ -28,6 +35,7 @@ public: static bool readLevelData(const std::string& path, LevelData* pLevelData); static bool readPlayerData(const std::string& path, LevelData* pLevelData); + static bool writeLevelData(const std::string& path, LevelData* pLevelData); public: std::string field_8; @@ -35,6 +43,7 @@ public: LevelData* m_pLevelData = nullptr; RegionFile* m_pRegionFile = nullptr; Level* m_pLevel = nullptr; + int m_timer = 0; std::list m_unsavedLevelChunks; };