Modify Chunk Loading to Support Significantly Larger World Sizes

This commit is contained in:
Digitalfear117 2026-03-01 15:05:15 -05:00
parent 5037420311
commit 8356781868
6 changed files with 126 additions and 41 deletions

View file

@ -78,6 +78,7 @@ void Chunk::setPos(int x, int y, int z)
clipChunk->zm = zm;
clipChunk->globalIdx = LevelRenderer::getGlobalIndexForChunk(x, y, z, level);
int globalIdx = clipChunk->globalIdx;
#if 1
// 4J - we're not using offsetted renderlists anymore, so just set the full position of this chunk into x/y/zRenderOffs where
@ -126,6 +127,11 @@ void Chunk::setPos(int x, int y, int z)
// If we're the first thing to be referencing this, mark it up as dirty to get rebuilt
if( refCount == 1 )
{
int listBase = levelRenderer->allocateListBaseForGlobalIdx(globalIdx);
if (listBase < 0)
{
__debugbreak();
}
// printf("Setting %d %d %d dirty [%d]\n",x,y,z, idx);
// Chunks being made dirty in this way can be very numerous (eg the full visible area of the world at start up, or a whole edge of the world when moving).
// On account of this, don't want to stick them into our lock free queue that we would normally use for letting the render update thread know about this chunk.
@ -211,8 +217,14 @@ void Chunk::rebuild()
int r = 1;
int lists = levelRenderer->getGlobalIndexForChunk(this->x,this->y,this->z,level) * 2;
lists += levelRenderer->chunkLists;
int globalIdx = levelRenderer->getGlobalIndexForChunk(this->x, this->y, this->z, level);
int listBase = levelRenderer->getListBaseForGlobalIdx(globalIdx);
if (listBase < 0)
{
__debugbreak();
PIXEndNamedEvent();
return;
}
PIXEndNamedEvent();
@ -324,7 +336,7 @@ void Chunk::rebuild()
for (int currentLayer = 0; currentLayer < 2; currentLayer++)
{
levelRenderer->setGlobalChunkFlag(this->x, this->y, this->z, level, LevelRenderer::CHUNK_FLAG_EMPTY0, currentLayer);
RenderManager.CBuffClear(lists + currentLayer);
RenderManager.CBuffClear(listBase + currentLayer);
}
delete region;
@ -381,7 +393,7 @@ void Chunk::rebuild()
started = true;
MemSect(31);
glNewList(lists + currentLayer, GL_COMPILE);
glNewList(listBase + currentLayer, GL_COMPILE);
MemSect(0);
glPushMatrix();
glDepthMask(true); // 4J added
@ -459,12 +471,12 @@ void Chunk::rebuild()
{
// 4J - added - clear any renderer data associated with this unused list
levelRenderer->setGlobalChunkFlag(this->x, this->y, this->z, level, LevelRenderer::CHUNK_FLAG_EMPTY0, currentLayer);
RenderManager.CBuffClear(lists + currentLayer);
RenderManager.CBuffClear(listBase + currentLayer);
}
if((currentLayer==0)&&(!renderNextLayer))
{
levelRenderer->setGlobalChunkFlag(this->x, this->y, this->z, level, LevelRenderer::CHUNK_FLAG_EMPTY1);
RenderManager.CBuffClear(lists + 1);
RenderManager.CBuffClear(listBase + 1);
break;
}
}
@ -670,8 +682,12 @@ void Chunk::rebuild_SPU()
Region region(level, x0 - r, y0 - r, z0 - r, x1 + r, y1 + r, z1 + r);
TileRenderer tileRenderer(&region);
int lists = levelRenderer->getGlobalIndexForChunk(this->x,this->y,this->z,level) * 2;
lists += levelRenderer->chunkLists;
int globalIdx = levelRenderer->getGlobalIndexForChunk(this->x, this->y, this->z, level);
int listBase = levelRenderer->getListBaseForGlobalIdx(globalIdx);
if (listBase < 0)
{
return;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 4J - optimisation begins.
@ -700,7 +716,7 @@ void Chunk::rebuild_SPU()
bool rendered = false;
{
glNewList(lists + currentLayer, GL_COMPILE);
glNewList(listBase + currentLayer, GL_COMPILE);
MemSect(0);
glPushMatrix();
glDepthMask(true); // 4J added
@ -796,7 +812,7 @@ void Chunk::rebuild_SPU()
{
// 4J - added - clear any renderer data associated with this unused list
levelRenderer->setGlobalChunkFlag(this->x, this->y, this->z, level, LevelRenderer::CHUNK_FLAG_EMPTY0, currentLayer);
RenderManager.CBuffClear(lists + currentLayer);
RenderManager.CBuffClear(listBase + currentLayer);
}
}
@ -965,18 +981,13 @@ void Chunk::reset()
unsigned char refCount = levelRenderer->decGlobalChunkRefCount(x, y, z, level);
assigned = false;
// printf("\t\t [dec] refcount %d at %d, %d, %d\n",refCount,x,y,z);
if( refCount == 0 )
if (refCount == 0)
{
int lists = levelRenderer->getGlobalIndexForChunk(x, y, z, level) * 2;
if(lists >= 0)
int globalIdx = levelRenderer->getGlobalIndexForChunk(x, y, z, level);
if (globalIdx >= 0)
{
lists += levelRenderer->chunkLists;
for (int i = 0; i < 2; i++)
{
// 4J - added - clear any renderer data associated with this unused list
RenderManager.CBuffClear(lists + i);
}
levelRenderer->setGlobalChunkFlags(x, y, z, level, 0);
levelRenderer->freeListBaseForGlobalIdx(globalIdx);
}
}
LeaveCriticalSection(&levelRenderer->m_csDirtyChunks);
@ -995,11 +1006,12 @@ int Chunk::getList(int layer)
{
if (!clipChunk->visible) return -1;
int lists = levelRenderer->getGlobalIndexForChunk(x, y, z,level) * 2;
lists += levelRenderer->chunkLists;
int globalIdx = levelRenderer->getGlobalIndexForChunk(x, y, z, level);
int listBase = levelRenderer->getListBaseForGlobalIdx(globalIdx);
if (listBase < 0) return -1;
bool empty = levelRenderer->getGlobalChunkFlag(x, y, z, level, LevelRenderer::CHUNK_FLAG_EMPTY0, layer);
if (!empty) return lists + layer;
bool empty = levelRenderer->getGlobalChunkFlag(x, y, z, level, LevelRenderer::CHUNK_FLAG_EMPTY0, layer);
if (!empty) return listBase + layer;
return -1;
}

View file

@ -77,6 +77,9 @@ C4JThread *LevelRenderer::rebuildThreads[MAX_CHUNK_REBUILD_THREADS];
C4JThread::EventArray *LevelRenderer::s_rebuildCompleteEvents;
C4JThread::Event *LevelRenderer::s_activationEventA[MAX_CHUNK_REBUILD_THREADS];
unordered_map<int, int> m_globalIdxToListBase;
vector<int> m_freeListBases;
// This defines the maximum size of renderable level, must be big enough to cope with actual size of level + view distance at each side
// so that we can render the "infinite" sea at the edges. Currently defined as:
const int overworldSize = LEVEL_MAX_WIDTH + LevelRenderer::PLAYER_VIEW_DISTANCE + LevelRenderer::PLAYER_VIEW_DISTANCE;
@ -149,10 +152,18 @@ LevelRenderer::LevelRenderer(Minecraft *mc, Textures *textures)
this->mc = mc;
this->textures = textures;
chunkLists = MemoryTracker::genLists(getGlobalChunkCount()*2); // *2 here is because there is one renderlist per chunk here for each of the opaque & transparent layers
chunkLists = MemoryTracker::genLists(MAX_RENDER_CHUNK_SLOTS * 2); // *2 here is because there is one renderlist per chunk here for each of the opaque & transparent layers
globalChunkFlags = new unsigned char[getGlobalChunkCount()];
memset(globalChunkFlags, 0, getGlobalChunkCount());
m_globalIdxToListBase.clear();
m_freeListBases.clear();
m_freeListBases.reserve(MAX_RENDER_CHUNK_SLOTS);
for (int i = 0; i < MAX_RENDER_CHUNK_SLOTS; ++i)
{
m_freeListBases.push_back(chunkLists + i * 2);
}
starList = MemoryTracker::genLists(4);
glPushMatrix();
@ -250,6 +261,43 @@ LevelRenderer::LevelRenderer(Minecraft *mc, Textures *textures)
#endif // __PS3__
}
int LevelRenderer::allocateListBaseForGlobalIdx(int globalIdx)
{
AUTO_VAR(it, m_globalIdxToListBase.find(globalIdx));
if (it != m_globalIdxToListBase.end())
return it->second;
if (m_freeListBases.empty())
return -1;
int listBase = m_freeListBases.back();
m_freeListBases.pop_back();
m_globalIdxToListBase[globalIdx] = listBase;
return listBase;
}
void LevelRenderer::freeListBaseForGlobalIdx(int globalIdx)
{
AUTO_VAR(it, m_globalIdxToListBase.find(globalIdx));
if (it == m_globalIdxToListBase.end())
return;
int listBase = it->second;
RenderManager.CBuffClear(listBase + 0);
RenderManager.CBuffClear(listBase + 1);
m_freeListBases.push_back(listBase);
m_globalIdxToListBase.erase(it);
}
int LevelRenderer::getListBaseForGlobalIdx(int globalIdx) const
{
AUTO_VAR(it, m_globalIdxToListBase.find(globalIdx));
if (it == m_globalIdxToListBase.end())
return -1;
return it->second;
}
void LevelRenderer::renderStars()
{
Random random = Random(10842);
@ -787,8 +835,10 @@ int LevelRenderer::renderChunks(int from, int to, int layer, double alpha)
if( ( globalChunkFlags[pClipChunk->globalIdx] & emptyFlag ) == emptyFlag ) continue; // Check that this particular layer isn't empty
// List can be calculated directly from the chunk's global idex
int list = pClipChunk->globalIdx * 2 + layer;
list += chunkLists;
int listBase = getListBaseForGlobalIdx(pClipChunk->globalIdx);
if (listBase < 0)
continue;
int list = listBase + layer;
if(RenderManager.CBuffCall(list, first))
{

View file

@ -210,6 +210,9 @@ public:
#ifdef _LARGE_WORLDS
static const int PLAYER_VIEW_DISTANCE = 18; // Straight line distance from centre to extent of visible world
static const int PLAYER_RENDER_AREA = (PLAYER_VIEW_DISTANCE * PLAYER_VIEW_DISTANCE * 4);
static const int MAX_CHUNKS_PER_PLAYER = PLAYER_RENDER_AREA * CHUNK_Y_COUNT;
static const int MAX_RENDER_CHUNK_SLOTS = MAX_CHUNKS_PER_PLAYER * 4;
#else
static const int PLAYER_RENDER_AREA = 400;
#endif
@ -271,6 +274,10 @@ public:
static void staticCtor();
static int rebuildChunkThreadProc(LPVOID lpParam);
int allocateListBaseForGlobalIdx(int globalIdx);
void freeListBaseForGlobalIdx(int globalIdx);
int getListBaseForGlobalIdx(int globalIdx) const;
CRITICAL_SECTION m_csChunkFlags;
#endif
void nonStackDirtyChunksAdded();

View file

@ -7,7 +7,7 @@ class TilePos;
// The maximum number of chunks that we can store
#ifdef _LARGE_WORLDS
// 4J Stu - Our default map (at zoom level 3) is 1024x1024 blocks (or 64 chunks)
#define LEVEL_MAX_WIDTH (5*64) //(6*54)
#define LEVEL_MAX_WIDTH (64*64) //(6*54) I have tested up to 512x64, but the game was using 16gb of ram to do so, so probably don't set it this high. I am leaving this at 64*64 for now, but feel free to change it lol
#else
#define LEVEL_MAX_WIDTH 54
#endif

View file

@ -67,29 +67,42 @@ Dimension::~Dimension()
delete biomeSource;
}
ChunkSource *Dimension::createRandomLevelSource() const
ChunkSource* Dimension::createRandomLevelSource() const
{
ChunkSource* src = NULL;
#ifdef _OVERRIDE_HEIGHTMAP
// 4J Stu - Added to enable overriding the heightmap from a loaded in data file
if(app.DebugSettingsOn() && app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad())&(1L<<eDebugSetting_EnableHeightWaterBiomeOverride))
if (app.DebugSettingsOn() && app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad()) & (1L << eDebugSetting_EnableHeightWaterBiomeOverride))
{
return new CustomLevelSource(level, level->getSeed(), level->getLevelData()->isGenerateMapFeatures());
src = new CustomLevelSource(level, level->getSeed(), level->getLevelData()->isGenerateMapFeatures());
}
else
#endif
if (levelType == LevelType::lvl_flat)
if (levelType == LevelType::lvl_flat)
{
src = new FlatLevelSource(level, level->getSeed(), level->getLevelData()->isGenerateMapFeatures());
}
else
{
src = new RandomLevelSource(level, level->getSeed(), level->getLevelData()->isGenerateMapFeatures());
}
if (src != NULL)
{
return new FlatLevelSource(level, level->getSeed(), level->getLevelData()->isGenerateMapFeatures());
}
else
{
return new RandomLevelSource(level, level->getSeed(), level->getLevelData()->isGenerateMapFeatures());
src->m_XZSize = level->getLevelData()->getXZSize();
}
return src;
}
ChunkSource *Dimension::createFlatLevelSource() const
ChunkSource* Dimension::createFlatLevelSource() const
{
return new FlatLevelSource(level, level->getSeed(), level->getLevelData()->isGenerateMapFeatures());
ChunkSource* src = new FlatLevelSource(level, level->getSeed(), level->getLevelData()->isGenerateMapFeatures());
if (src != NULL)
{
src->m_XZSize = level->getLevelData()->getXZSize();
}
return src;
}
ChunkStorage *Dimension::createStorage(File dir)

View file

@ -573,9 +573,12 @@ doubleArray RandomLevelSource::getHeights(doubleArray buffer, int x, int y, int
}
bool RandomLevelSource::hasChunk(int x, int y)
bool RandomLevelSource::hasChunk(int x, int z)
{
return true;
const int half = m_XZSize / 2;
return (x >= -half && x < half &&
z >= -half && z < half);
}
void RandomLevelSource::calcWaterDepths(ChunkSource *parent, int xt, int zt)