mirror of
https://github.com/celisej567/mcpe.git
synced 2026-01-08 06:09:54 +03:00
295 lines
6.2 KiB
C++
295 lines
6.2 KiB
C++
/********************************************************************
|
|
Minecraft: Pocket Edition - Decompilation Project
|
|
Copyright (C) 2023 iProgramInCpp
|
|
|
|
The following code is licensed under the BSD 1 clause license.
|
|
SPDX-License-Identifier: BSD-1-Clause
|
|
********************************************************************/
|
|
|
|
#include "LevelChunk.hpp"
|
|
#include "ChunkCache.hpp"
|
|
#include "world/level/Level.hpp"
|
|
|
|
ChunkCache::ChunkCache(Level* pLevel, ChunkStorage* pStor, ChunkSource* pSrc)
|
|
{
|
|
field_4 = true;
|
|
m_pLevel = nullptr;
|
|
m_pLastChunk = nullptr;
|
|
m_LastChunkX = -999999999;
|
|
m_LastChunkZ = -999999999;
|
|
|
|
m_pChunkSource = pSrc;
|
|
m_pChunkStorage = pStor;
|
|
m_pLevel = pLevel;
|
|
|
|
m_pEmptyChunk = new EmptyLevelChunk(pLevel, nullptr, 0, 0);
|
|
m_pEmptyChunk->field_236 = true;
|
|
|
|
memset(m_chunkMap, 0, sizeof(m_chunkMap));
|
|
}
|
|
|
|
LevelChunk* ChunkCache::create(int x, int z)
|
|
{
|
|
return getChunk(x, z);
|
|
}
|
|
|
|
LevelChunk* ChunkCache::getChunk(int x, int z)
|
|
{
|
|
// get the last chunk quickly if needed
|
|
if (m_LastChunkX == x && m_LastChunkZ == z)
|
|
{
|
|
if (m_pLastChunk)
|
|
return m_pLastChunk;
|
|
}
|
|
|
|
if (x < 0 || z < 0 || x >= C_MAX_CHUNKS_Z || z >= C_MAX_CHUNKS_X)
|
|
return m_pEmptyChunk;
|
|
|
|
if (!hasChunk(x, z))
|
|
{
|
|
LevelChunk* pOldChunk = m_chunkMap[z][x];
|
|
if (pOldChunk)
|
|
{
|
|
pOldChunk->unload();
|
|
save(pOldChunk);
|
|
if (m_pChunkStorage)
|
|
m_pChunkStorage->saveEntities(m_pLevel, pOldChunk);
|
|
}
|
|
|
|
LevelChunk* pChunk = load(x, z);
|
|
if (pChunk)
|
|
{
|
|
m_chunkMap[z][x] = pChunk;
|
|
pChunk->lightLava();
|
|
|
|
int globalX = x * 16, globalZ = z * 16;
|
|
for (int i = globalX, m = 0; m < 16; i++, m++)
|
|
{
|
|
for (int j = globalZ, n = 0; n < 16; j++, n++)
|
|
{
|
|
int height = m_pLevel->getHeightmap(i, j);
|
|
if (height >= 0)
|
|
{
|
|
for (int k = height; k > 0; k--)
|
|
{
|
|
m_pLevel->updateLight(LightLayer::Sky, globalX, k, globalZ, globalX, k, globalZ);
|
|
m_pLevel->updateLight(LightLayer::Block, globalX-1, k, globalZ-1, globalX+1, k, globalZ+1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pChunk = m_pEmptyChunk;
|
|
if (m_pChunkSource)
|
|
pChunk = m_pChunkSource->getChunk(x, z);
|
|
|
|
if (!pChunk)
|
|
return nullptr;
|
|
m_chunkMap[z][x] = pChunk;
|
|
pChunk->lightLava();
|
|
}
|
|
|
|
pChunk = m_chunkMap[z][x];
|
|
if (pChunk)
|
|
pChunk->load();
|
|
else
|
|
return nullptr;
|
|
|
|
if (!pChunk->field_234 && hasChunk(x + 1, z + 1) && hasChunk(x, z + 1) && hasChunk(x + 1, z))
|
|
postProcess(this, x, z);
|
|
|
|
//@OVERSIGHT: redundant call twice to hasChunk(x-1, z), hasChunk(x,z-1), and hasChunk(x-1,z-1)
|
|
if (hasChunk(x - 1, z) && !getChunk(x - 1, z)->field_234 && hasChunk(x - 1, z + 1) && hasChunk(x, z + 1) && hasChunk(x - 1, z))
|
|
postProcess(this, x - 1, z);
|
|
|
|
if (hasChunk(x, z - 1) && !getChunk(x, z - 1)->field_234 && hasChunk(x + 1, z - 1) && hasChunk(x + 1, z) && hasChunk(x, z - 1))
|
|
postProcess(this, x, z - 1);
|
|
|
|
if (hasChunk(x - 1, z - 1) && !getChunk(x - 1, z - 1)->field_234 && hasChunk(x - 1, z - 1) && hasChunk(x, z - 1) && hasChunk(x - 1, z))
|
|
postProcess(this, x - 1, z - 1);
|
|
}
|
|
|
|
m_LastChunkX = x;
|
|
m_LastChunkZ = z;
|
|
m_pLastChunk = m_chunkMap[z][x];
|
|
return m_chunkMap[z][x];
|
|
}
|
|
|
|
LevelChunk* ChunkCache::getChunkDontCreate(int x, int z)
|
|
{
|
|
// get the last chunk quickly if needed
|
|
if (m_LastChunkX == x && m_LastChunkZ == z)
|
|
{
|
|
if (m_pLastChunk)
|
|
return m_pLastChunk;
|
|
}
|
|
|
|
if (x < 0 || z < 0 || x >= C_MAX_CHUNKS_Z || z >= C_MAX_CHUNKS_X)
|
|
return m_pEmptyChunk;
|
|
|
|
if (!hasChunk(x, z))
|
|
{
|
|
LevelChunk* pOldChunk = m_chunkMap[z][x];
|
|
if (pOldChunk)
|
|
{
|
|
pOldChunk->unload();
|
|
save(pOldChunk);
|
|
if (m_pChunkStorage)
|
|
m_pChunkStorage->saveEntities(m_pLevel, pOldChunk);
|
|
}
|
|
|
|
// create an empty chunk
|
|
LevelChunk* pChunk = m_pEmptyChunk;
|
|
if (m_pChunkSource)
|
|
pChunk = m_pChunkSource->getChunkDontCreate(x, z);
|
|
|
|
m_chunkMap[z][x] = pChunk;
|
|
}
|
|
|
|
m_LastChunkX = x;
|
|
m_LastChunkZ = z;
|
|
m_pLastChunk = m_chunkMap[z][x];
|
|
return m_chunkMap[z][x];
|
|
}
|
|
|
|
bool ChunkCache::hasChunk(int x, int z)
|
|
{
|
|
if (x < 0 || z < 0)
|
|
return true;
|
|
|
|
if (x >= C_MAX_CHUNKS_X || z >= C_MAX_CHUNKS_Z)
|
|
return true;
|
|
|
|
if (m_LastChunkX == x && m_LastChunkZ == z)
|
|
return true;
|
|
|
|
LevelChunk* pChunk = m_chunkMap[z][x];
|
|
if (!pChunk)
|
|
return false;
|
|
|
|
if (pChunk == m_pEmptyChunk)
|
|
return true;
|
|
|
|
return pChunk->isAt(x, z);
|
|
}
|
|
|
|
int ChunkCache::tick()
|
|
{
|
|
if (m_pChunkStorage)
|
|
m_pChunkStorage->tick();
|
|
|
|
return m_pChunkSource->tick();
|
|
}
|
|
|
|
void ChunkCache::postProcess(ChunkSource* pChkSrc, int x, int z)
|
|
{
|
|
if (x < 0 || z < 0 || x >= C_MAX_CHUNKS_X || z >= C_MAX_CHUNKS_Z)
|
|
return;
|
|
|
|
LevelChunk* pChunk = getChunk(x, z);
|
|
if (!pChunk->field_234)
|
|
{
|
|
pChunk->field_234 = 1;
|
|
if (m_pChunkSource)
|
|
{
|
|
m_pChunkSource->postProcess(m_pChunkSource, x, z);
|
|
pChunk->clearUpdateMap();
|
|
}
|
|
}
|
|
}
|
|
|
|
void ChunkCache::save(LevelChunk* pChunk)
|
|
{
|
|
if (m_pChunkStorage)
|
|
{
|
|
pChunk->field_23C = m_pLevel->getTime();
|
|
m_pChunkStorage->save(m_pLevel, pChunk);
|
|
}
|
|
}
|
|
|
|
void ChunkCache::saveAll()
|
|
{
|
|
if (!m_pChunkStorage) return;
|
|
|
|
std::vector<LevelChunk*> chunksToSave;
|
|
|
|
for (int i = 0; i < C_MAX_CHUNKS_Z; i++)
|
|
{
|
|
for (int j = 0; j < C_MAX_CHUNKS_X; j++)
|
|
{
|
|
chunksToSave.push_back(m_pLevel->getChunk(j, i));
|
|
}
|
|
}
|
|
|
|
m_pChunkStorage->saveAll(m_pLevel, chunksToSave);
|
|
}
|
|
|
|
#ifdef ENH_IMPROVED_SAVING
|
|
|
|
void ChunkCache::saveUnsaved()
|
|
{
|
|
if (!m_pChunkStorage) return;
|
|
|
|
std::vector<LevelChunk*> chunksToSave;
|
|
|
|
for (int i = 0; i < C_MAX_CHUNKS_Z; i++)
|
|
{
|
|
for (int j = 0; j < C_MAX_CHUNKS_X; j++)
|
|
{
|
|
LevelChunk* pChunk = m_pLevel->getChunk(j, i);
|
|
if (!pChunk->m_bUnsaved)
|
|
continue;
|
|
|
|
chunksToSave.push_back(pChunk);
|
|
}
|
|
}
|
|
|
|
m_pChunkStorage->saveAll(m_pLevel, chunksToSave);
|
|
}
|
|
|
|
#endif
|
|
|
|
bool ChunkCache::shouldSave()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
std::string ChunkCache::gatherStats()
|
|
{
|
|
return "ChunkCache: 1024";
|
|
}
|
|
|
|
ChunkCache::~ChunkCache()
|
|
{
|
|
SAFE_DELETE(m_pChunkSource);
|
|
SAFE_DELETE(m_pEmptyChunk);
|
|
|
|
for (int i = 0; i < 16; i++)
|
|
for (int j = 0; j < 16; j++)
|
|
{
|
|
LevelChunk* pChk = m_chunkMap[i][j];
|
|
if (pChk)
|
|
{
|
|
pChk->deleteBlockData();
|
|
SAFE_DELETE(pChk);
|
|
}
|
|
}
|
|
}
|
|
|
|
LevelChunk* ChunkCache::load(int x, int z)
|
|
{
|
|
if (!m_pChunkStorage)
|
|
return m_pEmptyChunk;
|
|
|
|
if (x < 0 || z < 0 || x >= C_MAX_CHUNKS_X || z >= C_MAX_CHUNKS_Z)
|
|
return m_pEmptyChunk;
|
|
|
|
LevelChunk* pChk = m_pChunkStorage->load(m_pLevel, x, z);
|
|
if (pChk)
|
|
pChk->field_23C = m_pLevel->getTime();
|
|
|
|
return pChk;
|
|
}
|