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->zm = zm;
clipChunk->globalIdx = LevelRenderer::getGlobalIndexForChunk(x, y, z, level); clipChunk->globalIdx = LevelRenderer::getGlobalIndexForChunk(x, y, z, level);
int globalIdx = clipChunk->globalIdx;
#if 1 #if 1
// 4J - we're not using offsetted renderlists anymore, so just set the full position of this chunk into x/y/zRenderOffs where // 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 we're the first thing to be referencing this, mark it up as dirty to get rebuilt
if( refCount == 1 ) if( refCount == 1 )
{ {
int listBase = levelRenderer->allocateListBaseForGlobalIdx(globalIdx);
if (listBase < 0)
{
__debugbreak();
}
// printf("Setting %d %d %d dirty [%d]\n",x,y,z, idx); // 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). // 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. // 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 r = 1;
int lists = levelRenderer->getGlobalIndexForChunk(this->x,this->y,this->z,level) * 2; int globalIdx = levelRenderer->getGlobalIndexForChunk(this->x, this->y, this->z, level);
lists += levelRenderer->chunkLists; int listBase = levelRenderer->getListBaseForGlobalIdx(globalIdx);
if (listBase < 0)
{
__debugbreak();
PIXEndNamedEvent();
return;
}
PIXEndNamedEvent(); PIXEndNamedEvent();
@ -324,7 +336,7 @@ void Chunk::rebuild()
for (int currentLayer = 0; currentLayer < 2; currentLayer++) for (int currentLayer = 0; currentLayer < 2; currentLayer++)
{ {
levelRenderer->setGlobalChunkFlag(this->x, this->y, this->z, level, LevelRenderer::CHUNK_FLAG_EMPTY0, 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; delete region;
@ -381,7 +393,7 @@ void Chunk::rebuild()
started = true; started = true;
MemSect(31); MemSect(31);
glNewList(lists + currentLayer, GL_COMPILE); glNewList(listBase + currentLayer, GL_COMPILE);
MemSect(0); MemSect(0);
glPushMatrix(); glPushMatrix();
glDepthMask(true); // 4J added glDepthMask(true); // 4J added
@ -459,12 +471,12 @@ void Chunk::rebuild()
{ {
// 4J - added - clear any renderer data associated with this unused list // 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); 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)) if((currentLayer==0)&&(!renderNextLayer))
{ {
levelRenderer->setGlobalChunkFlag(this->x, this->y, this->z, level, LevelRenderer::CHUNK_FLAG_EMPTY1); levelRenderer->setGlobalChunkFlag(this->x, this->y, this->z, level, LevelRenderer::CHUNK_FLAG_EMPTY1);
RenderManager.CBuffClear(lists + 1); RenderManager.CBuffClear(listBase + 1);
break; break;
} }
} }
@ -670,8 +682,12 @@ void Chunk::rebuild_SPU()
Region region(level, x0 - r, y0 - r, z0 - r, x1 + r, y1 + r, z1 + r); Region region(level, x0 - r, y0 - r, z0 - r, x1 + r, y1 + r, z1 + r);
TileRenderer tileRenderer(&region); TileRenderer tileRenderer(&region);
int lists = levelRenderer->getGlobalIndexForChunk(this->x,this->y,this->z,level) * 2; int globalIdx = levelRenderer->getGlobalIndexForChunk(this->x, this->y, this->z, level);
lists += levelRenderer->chunkLists; int listBase = levelRenderer->getListBaseForGlobalIdx(globalIdx);
if (listBase < 0)
{
return;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 4J - optimisation begins. // 4J - optimisation begins.
@ -700,7 +716,7 @@ void Chunk::rebuild_SPU()
bool rendered = false; bool rendered = false;
{ {
glNewList(lists + currentLayer, GL_COMPILE); glNewList(listBase + currentLayer, GL_COMPILE);
MemSect(0); MemSect(0);
glPushMatrix(); glPushMatrix();
glDepthMask(true); // 4J added glDepthMask(true); // 4J added
@ -796,7 +812,7 @@ void Chunk::rebuild_SPU()
{ {
// 4J - added - clear any renderer data associated with this unused list // 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); 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); unsigned char refCount = levelRenderer->decGlobalChunkRefCount(x, y, z, level);
assigned = false; assigned = false;
// printf("\t\t [dec] refcount %d at %d, %d, %d\n",refCount,x,y,z); // 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; int globalIdx = levelRenderer->getGlobalIndexForChunk(x, y, z, level);
if(lists >= 0) 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->setGlobalChunkFlags(x, y, z, level, 0);
levelRenderer->freeListBaseForGlobalIdx(globalIdx);
} }
} }
LeaveCriticalSection(&levelRenderer->m_csDirtyChunks); LeaveCriticalSection(&levelRenderer->m_csDirtyChunks);
@ -995,11 +1006,12 @@ int Chunk::getList(int layer)
{ {
if (!clipChunk->visible) return -1; if (!clipChunk->visible) return -1;
int lists = levelRenderer->getGlobalIndexForChunk(x, y, z,level) * 2; int globalIdx = levelRenderer->getGlobalIndexForChunk(x, y, z, level);
lists += levelRenderer->chunkLists; int listBase = levelRenderer->getListBaseForGlobalIdx(globalIdx);
if (listBase < 0) return -1;
bool empty = levelRenderer->getGlobalChunkFlag(x, y, z, level, LevelRenderer::CHUNK_FLAG_EMPTY0, layer); bool empty = levelRenderer->getGlobalChunkFlag(x, y, z, level, LevelRenderer::CHUNK_FLAG_EMPTY0, layer);
if (!empty) return lists + layer; if (!empty) return listBase + layer;
return -1; return -1;
} }

View file

@ -77,6 +77,9 @@ C4JThread *LevelRenderer::rebuildThreads[MAX_CHUNK_REBUILD_THREADS];
C4JThread::EventArray *LevelRenderer::s_rebuildCompleteEvents; C4JThread::EventArray *LevelRenderer::s_rebuildCompleteEvents;
C4JThread::Event *LevelRenderer::s_activationEventA[MAX_CHUNK_REBUILD_THREADS]; 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 // 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: // 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; 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->mc = mc;
this->textures = textures; 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()]; globalChunkFlags = new unsigned char[getGlobalChunkCount()];
memset(globalChunkFlags, 0, 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); starList = MemoryTracker::genLists(4);
glPushMatrix(); glPushMatrix();
@ -250,6 +261,43 @@ LevelRenderer::LevelRenderer(Minecraft *mc, Textures *textures)
#endif // __PS3__ #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() void LevelRenderer::renderStars()
{ {
Random random = Random(10842); 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 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 // List can be calculated directly from the chunk's global idex
int list = pClipChunk->globalIdx * 2 + layer; int listBase = getListBaseForGlobalIdx(pClipChunk->globalIdx);
list += chunkLists; if (listBase < 0)
continue;
int list = listBase + layer;
if(RenderManager.CBuffCall(list, first)) if(RenderManager.CBuffCall(list, first))
{ {

View file

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

View file

@ -7,7 +7,7 @@ class TilePos;
// The maximum number of chunks that we can store // The maximum number of chunks that we can store
#ifdef _LARGE_WORLDS #ifdef _LARGE_WORLDS
// 4J Stu - Our default map (at zoom level 3) is 1024x1024 blocks (or 64 chunks) // 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 #else
#define LEVEL_MAX_WIDTH 54 #define LEVEL_MAX_WIDTH 54
#endif #endif

View file

@ -67,29 +67,42 @@ Dimension::~Dimension()
delete biomeSource; delete biomeSource;
} }
ChunkSource *Dimension::createRandomLevelSource() const ChunkSource* Dimension::createRandomLevelSource() const
{ {
ChunkSource* src = NULL;
#ifdef _OVERRIDE_HEIGHTMAP #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 else
#endif #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()); src->m_XZSize = level->getLevelData()->getXZSize();
}
else
{
return new RandomLevelSource(level, level->getSeed(), level->getLevelData()->isGenerateMapFeatures());
} }
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) 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) void RandomLevelSource::calcWaterDepths(ChunkSource *parent, int xt, int zt)