Files
minecraft-pe-0.6.1/src/world/level/chunk/ChunkCache.h
Shredder e346df682c Another Huge Commit my bad - shredder
Restored Java's Debug Screen using partial unused code and ported code, avaliable in options menu as a style

Slight Water texture is now overlayed when in water

Vignette function has been fixed and can now be toggled in options

World Generation now includes Tall Grass and Ferns both

Broken Frame Chart Graph found in the source has now been fixed and enabled when debug screen is turned on

Pie Chart works now and will appear when debug screen is opened

Most changes have not been tested on anything besides windows, will test it
2026-05-04 01:28:27 +05:00

266 lines
8.4 KiB
C++
Executable File

#ifndef NET_MINECRAFT_WORLD_LEVEL_CHUNK__ChunkCache_H__
#define NET_MINECRAFT_WORLD_LEVEL_CHUNK__ChunkCache_H__
//package net.minecraft.world.level.chunk;
#include "ChunkSource.h"
#include "storage/ChunkStorage.h"
#include "EmptyLevelChunk.h"
#include "../Level.h"
#include "../LevelConstants.h"
class ChunkCache: public ChunkSource {
//static const int CHUNK_CACHE_WIDTH = CHUNK_CACHE_WIDTH; // WAS 32;
static const int MAX_SAVES = 2;
public:
ChunkCache(Level* level_, ChunkStorage* storage_, ChunkSource* source_)
: xLast(-999999999),
zLast(-999999999),
last(NULL),
level(level_),
storage(storage_),
source(source_)
{
isChunkCache = true;
//emptyChunk = new EmptyLevelChunk(level_, emptyChunkBlocks, 0, 0);
emptyChunk = new EmptyLevelChunk(level_, NULL, 0, 0);
memset(chunks, 0, sizeof(LevelChunk*) * CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH);
}
~ChunkCache() {
delete source;
delete emptyChunk;
for (int i = 0; i < CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH; i++)
{
if (chunks[i])
{
chunks[i]->deleteBlockData();
delete chunks[i];
}
}
}
bool fits(int x, int z) {
return (x >= 0 && z >= 0 && x < CHUNK_CACHE_WIDTH && z < CHUNK_CACHE_WIDTH);
}
bool hasChunk(int x, int z) {
// with a fixed world size, chunks outside the fitting area are always available (emptyChunks)
if (!fits(x, z)) return true;
if (x == xLast && z == zLast && last != NULL) {
return true;
}
int xs = x & (CHUNK_CACHE_WIDTH - 1);
int zs = z & (CHUNK_CACHE_WIDTH - 1);
int slot = xs + zs * CHUNK_CACHE_WIDTH;
return chunks[slot] != NULL && (chunks[slot] == emptyChunk || chunks[slot]->isAt(x, z));
}
LevelChunk* create(int x, int z) {
return getChunk(x, z);
}
LevelChunk* getChunk(int x, int z) {
//static Stopwatch sw;
//sw.start();
if (x == xLast && z == zLast && last != NULL) {
return last;
}
if (!fits(x, z)) return emptyChunk;
//if (!level->isFindingSpawn && !fits(x, z)) return emptyChunk;
int xs = x & (CHUNK_CACHE_WIDTH - 1);
int zs = z & (CHUNK_CACHE_WIDTH - 1);
int slot = xs + zs * CHUNK_CACHE_WIDTH;
if (!hasChunk(x, z)) {
if (chunks[slot] != NULL) {
chunks[slot]->unload();
save(chunks[slot]);
saveEntities(chunks[slot]);
}
LevelChunk* newChunk = load(x, z);
bool updateLights = false;
if (newChunk == NULL) {
if (source == NULL) {
newChunk = emptyChunk;
} else {
newChunk = source->getChunk(x, z);
}
} else {
//return emptyChunk;
updateLights = true;
}
chunks[slot] = newChunk;
newChunk->lightLava();
if (updateLights)
{
for (int cx = 0; cx < 16; cx++)
{
for (int cz = 0; cz < 16; cz++)
{
int height = level->getHeightmap(cx + x * 16, cz + z * 16);
for (int cy = height; cy >= 0; cy--)
{
level->updateLight(LightLayer::Sky, cx + x * 16, cy, cz + z * 16, cx + x * 16, cy, cz + z * 16);
level->updateLight(LightLayer::Block, cx + x * 16 - 1, cy, cz + z * 16 - 1, cx + x * 16 + 1, cy, cz + z * 16 + 1);
}
}
}
//level->updateLight(LightLayer::Sky, x * 16, 0, z * 16, x * 16 + 15, 128, z * 16 + 15);
//level->updateLight(LightLayer::Block, x * 16, 0, z * 16, x * 16 + 15, 128, z * 16 + 15);
}
if (chunks[slot] != NULL) {
chunks[slot]->load();
}
if (!chunks[slot]->terrainPopulated && hasChunk(x + 1, z + 1) && hasChunk(x, z + 1) && hasChunk(x + 1, z)) postProcess(this, x, z);
if (hasChunk(x - 1, z) && !getChunk(x - 1, z)->terrainPopulated && 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)->terrainPopulated && hasChunk(x + 1, z - 1) && hasChunk(x, z - 1) && hasChunk(x + 1, z)) postProcess(this, x, z - 1);
if (hasChunk(x - 1, z - 1) && !getChunk(x - 1, z - 1)->terrainPopulated && hasChunk(x - 1, z - 1) && hasChunk(x, z - 1) && hasChunk(x - 1, z)) postProcess(this, x - 1, z - 1);
}
xLast = x;
zLast = z;
last = chunks[slot];
//sw.stop();
//sw.printEvery(500000, "ChunkCache::load: ");
return chunks[slot];
}
Biome::MobList getMobsAt(const MobCategory& mobCategory, int x, int y, int z) {
return source->getMobsAt(mobCategory, x, y, z);
}
void postProcess(ChunkSource* parent, int x, int z) {
if (!fits(x, z)) return;
LevelChunk* chunk = getChunk(x, z);
if (!chunk->terrainPopulated) {
chunk->terrainPopulated = true;
if (source != NULL) {
source->postProcess(parent, x, z);
chunk->clearUpdateMap();
}
}
}
//bool save(bool force, ProgressListener progressListener) {
// int saves = 0;
// int count = 0;
// if (progressListener != NULL) {
// for (int i = 0; i < chunks.length; i++) {
// if (chunks[i] != NULL && chunks[i].shouldSave(force)) {
// count++;
// }
// }
// }
// int cc = 0;
// for (int i = 0; i < chunks.length; i++) {
// if (chunks[i] != NULL) {
// if (force && !chunks[i].dontSave) saveEntities(chunks[i]);
// if (chunks[i].shouldSave(force)) {
// save(chunks[i]);
// chunks[i].unsaved = false;
// if (++saves == MAX_SAVES && !force) return false;
// if (progressListener != NULL) {
// if (++cc % 10 == 0) {
// progressListener.progressStagePercentage(cc * 100 / count);
// }
// }
// }
// }
// }
// if (force) {
// if (storage == NULL) return true;
// storage.flush();
// }
// return true;
//}
bool tick() {
if (storage != NULL) storage->tick();
return source->tick();
}
bool shouldSave() {
return true;
}
std::string gatherStats() {
// return "ChunkCache: 1024";
return ("ChunkCache: " + std::to_string(CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH));
}
void saveAll(bool onlyUnsaved) {
if (storage != NULL) {
std::vector<LevelChunk*> chunks;
for (int z = 0; z < CHUNK_CACHE_WIDTH; ++z)
for (int x = 0; x < CHUNK_CACHE_WIDTH; ++x) {
LevelChunk* chunk = level->getChunk(x, z);
if (!onlyUnsaved || chunk->shouldSave(false))
chunks.push_back( chunk );
}
storage->saveAll(level, chunks);
}
}
private:
LevelChunk* load(int x, int z) {
if (storage == NULL) return emptyChunk;
if (x < 0 || x >= CHUNK_CACHE_WIDTH || z < 0 || z >= CHUNK_CACHE_WIDTH)
{
return emptyChunk;
}
//try {
LevelChunk* levelChunk = storage->load(level, x, z);
if (levelChunk != NULL) {
levelChunk->lastSaveTime = level->getTime();
}
return levelChunk;
//} catch (Exception e) {
// e.printStackTrace();
// return emptyChunk;
//}
}
void saveEntities(LevelChunk* levelChunk) {
if (storage == NULL) return;
//try {
storage->saveEntities(level, levelChunk);
//} catch (Error e) {
// e.printStackTrace();
//}
}
void save(LevelChunk* levelChunk) {
if (storage == NULL) return;
//try {
levelChunk->lastSaveTime = level->getTime();
storage->save(level, levelChunk);
//} catch (IOException e) {
// e.printStackTrace();
//}
}
public:
int xLast;
int zLast;
private:
//unsigned char emptyChunkBlocks[LevelChunk::ChunkBlockCount];
LevelChunk* emptyChunk;
ChunkSource* source;
ChunkStorage* storage;
LevelChunk* chunks[CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH];
Level* level;
LevelChunk* last;
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_CHUNK__ChunkCache_H__*/