2026-03-01 12:16:08 +08:00
# include "stdafx.h"
# include "net.minecraft.world.level.h"
# include "net.minecraft.world.level.biome.h"
# include "net.minecraft.world.level.levelgen.h"
# include "net.minecraft.world.level.levelgen.feature.h"
# include "net.minecraft.world.level.levelgen.structure.h"
# include "net.minecraft.world.level.levelgen.synth.h"
# include "net.minecraft.world.level.tile.h"
# include "net.minecraft.world.level.storage.h"
2026-03-03 03:04:10 +08:00
# include "net.minecraft.world.entity.h"
2026-03-01 12:16:08 +08:00
# include "RandomLevelSource.h"
# ifdef __PS3__
# include "..\Minecraft.Client\PS3\SPU_Tasks\PerlinNoise\PerlinNoiseJob.h"
# include "C4JSpursJob.h"
static PerlinNoise_DataIn g_lperlinNoise1_SPU __attribute__ ( ( __aligned__ ( 16 ) ) ) ;
static PerlinNoise_DataIn g_lperlinNoise2_SPU __attribute__ ( ( __aligned__ ( 16 ) ) ) ;
static PerlinNoise_DataIn g_perlinNoise1_SPU __attribute__ ( ( __aligned__ ( 16 ) ) ) ;
static PerlinNoise_DataIn g_scaleNoise_SPU __attribute__ ( ( __aligned__ ( 16 ) ) ) ;
static PerlinNoise_DataIn g_depthNoise_SPU __attribute__ ( ( __aligned__ ( 16 ) ) ) ;
2026-03-03 03:04:10 +08:00
//#define DISABLE_SPU_CODE
2026-03-01 12:16:08 +08:00
# endif
const double RandomLevelSource : : SNOW_SCALE = 0.3 ;
const double RandomLevelSource : : SNOW_CUTOFF = 0.5 ;
2026-03-02 17:39:35 +07:00
RandomLevelSource : : RandomLevelSource ( Level * level , __int64 seed , bool generateStructures ) : generateStructures ( generateStructures )
2026-03-01 12:16:08 +08:00
{
m_XZSize = level - > getLevelData ( ) - > getXZSize ( ) ;
2026-03-03 03:04:10 +08:00
# ifdef _LARGE_WORLDS
level - > getLevelData ( ) - > getMoatFlags ( & m_classicEdgeMoat , & m_smallEdgeMoat , & m_mediumEdgeMoat ) ;
# endif
2026-03-01 12:16:08 +08:00
caveFeature = new LargeCaveFeature ( ) ;
strongholdFeature = new StrongholdFeature ( ) ;
2026-03-03 03:04:10 +08:00
villageFeature = new VillageFeature ( m_XZSize ) ;
mineShaftFeature = new MineShaftFeature ( ) ;
2026-03-01 12:16:08 +08:00
scatteredFeature = new RandomScatteredLargeFeature ( ) ;
canyonFeature = new CanyonFeature ( ) ;
2026-03-03 03:04:10 +08:00
this - > level = level ;
2026-03-01 12:16:08 +08:00
2026-03-03 03:04:10 +08:00
random = new Random ( seed ) ;
2026-03-01 12:16:08 +08:00
pprandom = new Random ( seed ) ; // 4J - added, so that we can have a separate random for doing post-processing in parallel with creation
2026-03-03 03:04:10 +08:00
lperlinNoise1 = new PerlinNoise ( random , 16 ) ;
lperlinNoise2 = new PerlinNoise ( random , 16 ) ;
perlinNoise1 = new PerlinNoise ( random , 8 ) ;
perlinNoise3 = new PerlinNoise ( random , 4 ) ;
2026-03-01 12:16:08 +08:00
2026-03-03 03:04:10 +08:00
scaleNoise = new PerlinNoise ( random , 10 ) ;
depthNoise = new PerlinNoise ( random , 16 ) ;
2026-03-01 12:16:08 +08:00
2026-03-03 03:04:10 +08:00
if ( FLOATING_ISLANDS )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
floatingIslandScale = new PerlinNoise ( random , 10 ) ;
floatingIslandNoise = new PerlinNoise ( random , 16 ) ;
}
2026-03-01 12:16:08 +08:00
else
{
floatingIslandScale = NULL ;
floatingIslandNoise = NULL ;
}
2026-03-03 03:04:10 +08:00
forestNoise = new PerlinNoise ( random , 8 ) ;
2026-03-01 12:16:08 +08:00
}
RandomLevelSource : : ~ RandomLevelSource ( )
{
delete caveFeature ;
delete strongholdFeature ;
delete villageFeature ;
delete mineShaftFeature ;
delete scatteredFeature ;
delete canyonFeature ;
2026-03-03 03:04:10 +08:00
this - > level = level ;
2026-03-01 12:16:08 +08:00
2026-03-03 03:04:10 +08:00
delete random ; ;
delete lperlinNoise1 ;
delete lperlinNoise2 ;
delete perlinNoise1 ;
delete perlinNoise3 ;
2026-03-01 12:16:08 +08:00
2026-03-03 03:04:10 +08:00
delete scaleNoise ;
delete depthNoise ;
2026-03-01 12:16:08 +08:00
2026-03-03 03:04:10 +08:00
if ( FLOATING_ISLANDS )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
delete floatingIslandScale ;
delete floatingIslandNoise ;
}
2026-03-01 12:16:08 +08:00
2026-03-03 03:04:10 +08:00
delete forestNoise ;
2026-03-01 12:16:08 +08:00
if ( pows . data ! = NULL ) delete [ ] pows . data ;
}
int g_numPrepareHeightCalls = 0 ;
LARGE_INTEGER g_totalPrepareHeightsTime = { 0 , 0 } ;
LARGE_INTEGER g_averagePrepareHeightsTime = { 0 , 0 } ;
2026-03-03 03:04:10 +08:00
# ifdef _LARGE_WORLDS
int RandomLevelSource : : getMinDistanceToEdge ( int xxx , int zzz , int worldSize , float falloffStart )
{
// Get distance to edges of world in x
// we have to do a proper line dist check here
int min = - worldSize / 2 ;
int max = ( worldSize / 2 ) - 1 ;
// // only check if either x or z values are within the falloff
// if(xxx > (min - falloffStart)
Vec3 * topLeft = Vec3 : : newTemp ( min , 0 , min ) ;
Vec3 * topRight = Vec3 : : newTemp ( max , 0 , min ) ;
Vec3 * bottomLeft = Vec3 : : newTemp ( min , 0 , max ) ;
Vec3 * bottomRight = Vec3 : : newTemp ( max , 0 , max ) ;
float closest = falloffStart ;
float dist ;
// make sure we're in range of the edges before we do a full distance check
if ( ( xxx > ( min - falloffStart ) & & xxx < ( min + falloffStart ) ) | |
( xxx > ( max - falloffStart ) & & xxx < ( max + falloffStart ) ) )
{
Vec3 * point = Vec3 : : newTemp ( xxx , 0 , zzz ) ;
if ( xxx > 0 )
dist = point - > distanceFromLine ( topRight , bottomRight ) ;
else
dist = point - > distanceFromLine ( topLeft , bottomLeft ) ;
closest = dist ;
}
// make sure we're in range of the edges before we do a full distance check
if ( ( zzz > ( min - falloffStart ) & & zzz < ( min + falloffStart ) ) | |
( zzz > ( max - falloffStart ) & & zzz < ( max + falloffStart ) ) )
{
Vec3 * point = Vec3 : : newTemp ( xxx , 0 , zzz ) ;
if ( zzz > 0 )
dist = point - > distanceFromLine ( bottomLeft , bottomRight ) ;
else
dist = point - > distanceFromLine ( topLeft , topRight ) ;
if ( dist < closest )
closest = dist ;
}
return closest ;
}
float RandomLevelSource : : getHeightFalloff ( int xxx , int zzz , int * pEMin )
{
///////////////////////////////////////////////////////////////////
// 4J - add this chunk of code to make land "fall-off" at the edges of
// a finite world - size of that world is currently hard-coded in here
const int worldSize = m_XZSize * 16 ;
const int falloffStart = 32 ; // chunks away from edge were we start doing fall-off
const float falloffMax = 128.0f ; // max value we need to get to falloff by the edge of the map
float comp = 0.0f ;
int emin = getMinDistanceToEdge ( xxx , zzz , worldSize , falloffStart ) ;
// check if we have a larger world that should have moats
int expandedWorldSizes [ 3 ] = { LEVEL_WIDTH_CLASSIC * 16 ,
LEVEL_WIDTH_SMALL * 16 ,
LEVEL_WIDTH_MEDIUM * 16 } ;
bool expandedMoatValues [ 3 ] = { m_classicEdgeMoat , m_smallEdgeMoat , m_mediumEdgeMoat } ;
for ( int i = 0 ; i < 3 ; i + + )
{
if ( expandedMoatValues [ i ] & & ( worldSize > expandedWorldSizes [ i ] ) )
{
// this world has been expanded, with moat settings, so we need fallofs at this edges too
int eminMoat = getMinDistanceToEdge ( xxx , zzz , expandedWorldSizes [ i ] , falloffStart ) ;
if ( eminMoat < emin )
{
emin = eminMoat ;
}
}
}
// Calculate how much we want the world to fall away, if we're in the defined region to do so
if ( emin < falloffStart )
{
int falloff = falloffStart - emin ;
comp = ( ( float ) falloff / ( float ) falloffStart ) * falloffMax ;
}
* pEMin = emin ;
return comp ;
// 4J - end of extra code
///////////////////////////////////////////////////////////////////
}
# else
// MGH - go back to using the simpler version for PS3/vita/360, as it was causing a lot of slow down on the tuturial generation
float RandomLevelSource : : getHeightFalloff ( int xxx , int zzz , int * pEMin )
{
///////////////////////////////////////////////////////////////////
// 4J - add this chunk of code to make land "fall-off" at the edges of
// a finite world - size of that world is currently hard-coded in here
const int worldSize = m_XZSize * 16 ;
const int falloffStart = 32 ; // chunks away from edge were we start doing fall-off
const float falloffMax = 128.0f ; // max value we need to get to falloff by the edge of the map
// Get distance to edges of world in x
int xxx0 = xxx + ( worldSize / 2 ) ;
if ( xxx0 < 0 ) xxx0 = 0 ;
int xxx1 = ( ( worldSize / 2 ) - 1 ) - xxx ;
if ( xxx1 < 0 ) xxx1 = 0 ;
// Get distance to edges of world in z
int zzz0 = zzz + ( worldSize / 2 ) ;
if ( zzz0 < 0 ) zzz0 = 0 ;
int zzz1 = ( ( worldSize / 2 ) - 1 ) - zzz ;
if ( zzz1 < 0 ) zzz1 = 0 ;
// Get min distance to any edge
int emin = xxx0 ;
if ( xxx1 < emin ) emin = xxx1 ;
if ( zzz0 < emin ) emin = zzz0 ;
if ( zzz1 < emin ) emin = zzz1 ;
float comp = 0.0f ;
// Calculate how much we want the world to fall away, if we're in the defined region to do so
if ( emin < falloffStart )
{
int falloff = falloffStart - emin ;
comp = ( ( float ) falloff / ( float ) falloffStart ) * falloffMax ;
}
// 4J - end of extra code
///////////////////////////////////////////////////////////////////
* pEMin = emin ;
return comp ;
}
# endif // _LARGE_WORLDS
2026-03-01 12:16:08 +08:00
void RandomLevelSource : : prepareHeights ( int xOffs , int zOffs , byteArray blocks )
{
LARGE_INTEGER startTime ;
2026-03-03 03:04:10 +08:00
int xChunks = 16 / CHUNK_WIDTH ;
2026-03-01 12:16:08 +08:00
int yChunks = Level : : genDepth / CHUNK_HEIGHT ;
int waterHeight = level - > seaLevel ;
2026-03-03 03:04:10 +08:00
int xSize = xChunks + 1 ;
int ySize = Level : : genDepth / CHUNK_HEIGHT + 1 ;
int zSize = xChunks + 1 ;
2026-03-01 12:16:08 +08:00
BiomeArray biomes ; // 4J created locally here for thread safety, java has this as a class member
level - > getBiomeSource ( ) - > getRawBiomeBlock ( biomes , xOffs * CHUNK_WIDTH - 2 , zOffs * CHUNK_WIDTH - 2 , xSize + 5 , zSize + 5 ) ;
doubleArray buffer ; // 4J - used to be declared with class level scope but tidying up for thread safety reasons
2026-03-03 03:04:10 +08:00
buffer = getHeights ( buffer , xOffs * xChunks , 0 , zOffs * xChunks , xSize , ySize , zSize , biomes ) ;
2026-03-01 12:16:08 +08:00
QueryPerformanceCounter ( & startTime ) ;
2026-03-03 03:04:10 +08:00
for ( int xc = 0 ; xc < xChunks ; xc + + )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
for ( int zc = 0 ; zc < xChunks ; zc + + )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
for ( int yc = 0 ; yc < yChunks ; yc + + )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
double yStep = 1 / ( double ) CHUNK_HEIGHT ;
double s0 = buffer [ ( ( xc + 0 ) * zSize + ( zc + 0 ) ) * ySize + ( yc + 0 ) ] ;
double s1 = buffer [ ( ( xc + 0 ) * zSize + ( zc + 1 ) ) * ySize + ( yc + 0 ) ] ;
double s2 = buffer [ ( ( xc + 1 ) * zSize + ( zc + 0 ) ) * ySize + ( yc + 0 ) ] ;
double s3 = buffer [ ( ( xc + 1 ) * zSize + ( zc + 1 ) ) * ySize + ( yc + 0 ) ] ;
double s0a = ( buffer [ ( ( xc + 0 ) * zSize + ( zc + 0 ) ) * ySize + ( yc + 1 ) ] - s0 ) * yStep ;
double s1a = ( buffer [ ( ( xc + 0 ) * zSize + ( zc + 1 ) ) * ySize + ( yc + 1 ) ] - s1 ) * yStep ;
double s2a = ( buffer [ ( ( xc + 1 ) * zSize + ( zc + 0 ) ) * ySize + ( yc + 1 ) ] - s2 ) * yStep ;
double s3a = ( buffer [ ( ( xc + 1 ) * zSize + ( zc + 1 ) ) * ySize + ( yc + 1 ) ] - s3 ) * yStep ;
for ( int y = 0 ; y < CHUNK_HEIGHT ; y + + )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
double xStep = 1 / ( double ) CHUNK_WIDTH ;
2026-03-01 12:16:08 +08:00
2026-03-03 03:04:10 +08:00
double _s0 = s0 ;
double _s1 = s1 ;
double _s0a = ( s2 - s0 ) * xStep ;
double _s1a = ( s3 - s1 ) * xStep ;
2026-03-01 12:16:08 +08:00
2026-03-03 03:04:10 +08:00
for ( int x = 0 ; x < CHUNK_WIDTH ; x + + )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
int offs = ( x + xc * CHUNK_WIDTH ) < < Level : : genDepthBitsPlusFour | ( 0 + zc * CHUNK_WIDTH ) < < Level : : genDepthBits | ( yc * CHUNK_HEIGHT + y ) ;
int step = 1 < < Level : : genDepthBits ;
2026-03-01 12:16:08 +08:00
offs - = step ;
2026-03-03 03:04:10 +08:00
double zStep = 1 / ( double ) CHUNK_WIDTH ;
2026-03-01 12:16:08 +08:00
2026-03-03 03:04:10 +08:00
double val = _s0 ;
double vala = ( _s1 - _s0 ) * zStep ;
2026-03-01 12:16:08 +08:00
val - = vala ;
2026-03-03 03:04:10 +08:00
for ( int z = 0 ; z < CHUNK_WIDTH ; z + + )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
// 4J Stu - I have removed all uses of the new getHeightFalloff function for now as we had some problems with PS3/PSVita world generation
// I have fixed the non large worlds method, however we will be happier if the current builds go out with completely old code
// We can put the new code back in mid-november 2014 once those PS3/Vita builds are gone (and the PS4 doesn't have world enlarging in these either anyway)
2026-03-01 12:16:08 +08:00
int xxx = ( ( xOffs * 16 ) + x + ( xc * CHUNK_WIDTH ) ) ;
int zzz = ( ( zOffs * 16 ) + z + ( zc * CHUNK_WIDTH ) ) ;
2026-03-03 03:04:10 +08:00
int emin ;
float comp = getHeightFalloff ( xxx , zzz , & emin ) ;
2026-03-01 12:16:08 +08:00
// 4J - slightly rearranged this code (as of java 1.0.1 merge) to better fit with
// changes we've made edge-of-world things - original sets blocks[offs += step] directly
// here rather than setting a tileId
int tileId = 0 ;
// 4J - this comparison used to just be with 0.0f but is now varied by block above
2026-03-03 03:04:10 +08:00
if ( ( val + = vala ) > comp )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
tileId = ( byte ) Tile : : stone_Id ;
}
2026-03-01 12:16:08 +08:00
else if ( yc * CHUNK_HEIGHT + y < waterHeight )
{
2026-03-03 03:04:10 +08:00
tileId = ( byte ) Tile : : calmWater_Id ;
}
2026-03-01 12:16:08 +08:00
// 4J - more extra code to make sure that the column at the edge of the world is just water & rock, to match the infinite sea that
// continues on after the edge of the world.
if ( emin = = 0 )
{
// This matches code in MultiPlayerChunkCache that makes the geometry which continues at the edge of the world
2026-03-03 03:04:10 +08:00
if ( yc * CHUNK_HEIGHT + y < = ( level - > getSeaLevel ( ) - 10 ) ) tileId = Tile : : stone_Id ;
2026-03-01 12:16:08 +08:00
else if ( yc * CHUNK_HEIGHT + y < level - > getSeaLevel ( ) ) tileId = Tile : : calmWater_Id ;
}
blocks [ offs + = step ] = tileId ;
2026-03-03 03:04:10 +08:00
}
_s0 + = _s0a ;
_s1 + = _s1a ;
}
s0 + = s0a ;
s1 + = s1a ;
s2 + = s2a ;
s3 + = s3a ;
}
}
}
}
2026-03-01 12:16:08 +08:00
LARGE_INTEGER endTime ;
QueryPerformanceCounter ( & endTime ) ;
LARGE_INTEGER timeInFunc ;
timeInFunc . QuadPart = endTime . QuadPart - startTime . QuadPart ;
g_numPrepareHeightCalls + + ;
g_totalPrepareHeightsTime . QuadPart + = timeInFunc . QuadPart ;
g_averagePrepareHeightsTime . QuadPart = g_totalPrepareHeightsTime . QuadPart / g_numPrepareHeightCalls ;
delete [ ] buffer . data ;
delete [ ] biomes . data ;
}
void RandomLevelSource : : buildSurfaces ( int xOffs , int zOffs , byteArray blocks , BiomeArray biomes )
{
2026-03-03 03:04:10 +08:00
int waterHeight = level - > seaLevel ;
2026-03-01 12:16:08 +08:00
2026-03-03 03:04:10 +08:00
double s = 1 / 32.0 ;
2026-03-01 12:16:08 +08:00
doubleArray depthBuffer ( 16 * 16 ) ; // 4J - used to be declared with class level scope but moved here for thread safety
2026-03-03 03:04:10 +08:00
depthBuffer = perlinNoise3 - > getRegion ( depthBuffer , xOffs * 16 , zOffs * 16 , 0 , 16 , 16 , 1 , s * 2 , s * 2 , s * 2 ) ;
2026-03-01 12:16:08 +08:00
2026-03-03 03:04:10 +08:00
for ( int x = 0 ; x < 16 ; x + + )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
for ( int z = 0 ; z < 16 ; z + + )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
Biome * b = biomes [ z + x * 16 ] ;
2026-03-01 12:16:08 +08:00
float temp = b - > getTemperature ( ) ;
2026-03-03 03:04:10 +08:00
int runDepth = ( int ) ( depthBuffer [ x + z * 16 ] / 3 + 3 + random - > nextDouble ( ) * 0.25 ) ;
2026-03-01 12:16:08 +08:00
2026-03-03 03:04:10 +08:00
int run = - 1 ;
2026-03-01 12:16:08 +08:00
2026-03-03 03:04:10 +08:00
byte top = b - > topMaterial ;
byte material = b - > material ;
2026-03-01 12:16:08 +08:00
LevelGenerationOptions * lgo = app . getLevelGenerationOptions ( ) ;
if ( lgo ! = NULL )
{
lgo - > getBiomeOverride ( b - > id , material , top ) ;
}
2026-03-03 03:04:10 +08:00
for ( int y = Level : : genDepthMinusOne ; y > = 0 ; y - - )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
int offs = ( z * 16 + x ) * Level : : genDepth + y ;
2026-03-01 12:16:08 +08:00
if ( y < = 1 + random - > nextInt ( 2 ) ) // 4J - changed to make the bedrock not have bits you can get stuck in
2026-03-03 03:04:10 +08:00
// if (y <= 0 + random->nextInt(5))
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
blocks [ offs ] = ( byte ) Tile : : unbreakable_Id ;
}
2026-03-01 12:16:08 +08:00
else
{
2026-03-03 03:04:10 +08:00
int old = blocks [ offs ] ;
2026-03-01 12:16:08 +08:00
2026-03-03 03:04:10 +08:00
if ( old = = 0 )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
run = - 1 ;
}
else if ( old = = Tile : : stone_Id )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
if ( run = = - 1 )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
if ( runDepth < = 0 )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
top = 0 ;
material = ( byte ) Tile : : stone_Id ;
}
2026-03-01 12:16:08 +08:00
else if ( y > = waterHeight - 4 & & y < = waterHeight + 1 )
{
2026-03-03 03:04:10 +08:00
top = b - > topMaterial ;
2026-03-01 12:16:08 +08:00
material = b - > material ;
if ( lgo ! = NULL )
{
lgo - > getBiomeOverride ( b - > id , material , top ) ;
}
2026-03-03 03:04:10 +08:00
}
2026-03-01 12:16:08 +08:00
2026-03-03 03:04:10 +08:00
if ( y < waterHeight & & top = = 0 )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
if ( temp < 0.15f ) top = ( byte ) Tile : : ice_Id ;
else top = ( byte ) Tile : : calmWater_Id ;
}
run = runDepth ;
if ( y > = waterHeight - 1 ) blocks [ offs ] = top ;
else blocks [ offs ] = material ;
}
2026-03-01 12:16:08 +08:00
else if ( run > 0 )
{
2026-03-03 03:04:10 +08:00
run - - ;
blocks [ offs ] = material ;
2026-03-01 12:16:08 +08:00
2026-03-03 03:04:10 +08:00
// place a few sandstone blocks beneath sand runs
if ( run = = 0 & & material = = Tile : : sand_Id )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
run = random - > nextInt ( 4 ) ;
material = ( byte ) Tile : : sandStone_Id ;
}
}
}
}
}
}
}
2026-03-01 12:16:08 +08:00
delete [ ] depthBuffer . data ;
}
LevelChunk * RandomLevelSource : : create ( int x , int z )
{
return getChunk ( x , z ) ;
}
LevelChunk * RandomLevelSource : : getChunk ( int xOffs , int zOffs )
{
2026-03-03 03:04:10 +08:00
random - > setSeed ( xOffs * 341873128712l + zOffs * 132897987541l ) ;
2026-03-01 12:16:08 +08:00
// 4J - now allocating this with a physical alloc & bypassing general memory management so that it will get cleanly freed
int blocksSize = Level : : genDepth * 16 * 16 ;
byte * tileData = ( byte * ) XPhysicalAlloc ( blocksSize , MAXULONG_PTR , 4096 , PAGE_READWRITE ) ;
XMemSet128 ( tileData , 0 , blocksSize ) ;
byteArray blocks = byteArray ( tileData , blocksSize ) ;
2026-03-03 03:04:10 +08:00
// byteArray blocks = byteArray(16 * level->depth * 16);
2026-03-01 12:16:08 +08:00
2026-03-03 03:04:10 +08:00
// LevelChunk *levelChunk = new LevelChunk(level, blocks, xOffs, zOffs); // 4J - moved to below
2026-03-01 12:16:08 +08:00
prepareHeights ( xOffs , zOffs , blocks ) ;
// 4J - Some changes made here to how biomes, temperatures and downfalls are passed around for thread safety
BiomeArray biomes ;
2026-03-03 03:04:10 +08:00
level - > getBiomeSource ( ) - > getBiomeBlock ( biomes , xOffs * 16 , zOffs * 16 , 16 , 16 , true ) ;
2026-03-01 12:16:08 +08:00
2026-03-03 03:04:10 +08:00
buildSurfaces ( xOffs , zOffs , blocks , biomes ) ;
2026-03-01 12:16:08 +08:00
delete [ ] biomes . data ;
2026-03-03 03:04:10 +08:00
caveFeature - > apply ( this , level , xOffs , zOffs , blocks ) ;
2026-03-01 12:16:08 +08:00
// 4J Stu Design Change - 1.8 gen goes stronghold, mineshaft, village, canyon
// this changed in 1.2 to canyon, mineshaft, village, stronghold
// This change makes sense as it stops canyons running through other structures
canyonFeature - > apply ( this , level , xOffs , zOffs , blocks ) ;
if ( generateStructures )
{
mineShaftFeature - > apply ( this , level , xOffs , zOffs , blocks ) ;
villageFeature - > apply ( this , level , xOffs , zOffs , blocks ) ;
strongholdFeature - > apply ( this , level , xOffs , zOffs , blocks ) ;
scatteredFeature - > apply ( this , level , xOffs , zOffs , blocks ) ;
}
2026-03-03 03:04:10 +08:00
// canyonFeature.apply(this, level, xOffs, zOffs, blocks);
// townFeature.apply(this, level, xOffs, zOffs, blocks);
// addCaves(xOffs, zOffs, blocks);
// addTowns(xOffs, zOffs, blocks);
2026-03-01 12:16:08 +08:00
2026-03-03 03:04:10 +08:00
// levelChunk->recalcHeightmap(); // 4J - removed & moved into its own method
2026-03-01 12:16:08 +08:00
// 4J - this now creates compressed block data from the blocks array passed in, so moved it until after the blocks are actually finalised. We also
// now need to free the passed in blocks as the LevelChunk doesn't use the passed in allocation anymore.
LevelChunk * levelChunk = new LevelChunk ( level , blocks , xOffs , zOffs ) ;
XPhysicalFree ( tileData ) ;
2026-03-03 03:04:10 +08:00
return levelChunk ;
2026-03-01 12:16:08 +08:00
}
// 4J - removed & moved into its own method from getChunk, so we can call recalcHeightmap after the chunk is added into the cache. Without
// doing this, then loads of the lightgaps() calls will fail to add any lights, because adding a light checks if the cache has this chunk in.
// lightgaps also does light 1 block into the neighbouring chunks, and maybe that is somehow enough to get lighting to propagate round the world,
// but this just doesn't seem right - this isn't a new fault in the 360 version, have checked that java does the same.
void RandomLevelSource : : lightChunk ( LevelChunk * lc )
{
lc - > recalcHeightmap ( ) ;
}
doubleArray RandomLevelSource : : getHeights ( doubleArray buffer , int x , int y , int z , int xSize , int ySize , int zSize , BiomeArray & biomes )
{
2026-03-03 03:04:10 +08:00
if ( buffer . data = = NULL )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
buffer = doubleArray ( xSize * ySize * zSize ) ;
}
2026-03-01 12:16:08 +08:00
if ( pows . data = = NULL )
{
pows = floatArray ( 5 * 5 ) ;
for ( int xb = - 2 ; xb < = 2 ; xb + + )
{
for ( int zb = - 2 ; zb < = 2 ; zb + + )
{
float ppp = 10.0f / Mth : : sqrt ( xb * xb + zb * zb + 0.2f ) ;
pows [ xb + 2 + ( zb + 2 ) * 5 ] = ppp ;
}
}
}
2026-03-03 03:04:10 +08:00
double s = 1 * 684.412 ;
double hs = 1 * 684.412 ;
2026-03-01 12:16:08 +08:00
doubleArray pnr , ar , br , sr , dr , fi , fis ; // 4J - used to be declared with class level scope but moved here for thread safety
2026-03-03 03:04:10 +08:00
if ( FLOATING_ISLANDS )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
fis = floatingIslandScale - > getRegion ( fis , x , y , z , xSize , 1 , zSize , 1.0 , 0 , 1.0 ) ;
fi = floatingIslandNoise - > getRegion ( fi , x , y , z , xSize , 1 , zSize , 500.0 , 0 , 500.0 ) ;
}
2026-03-01 12:16:08 +08:00
# if defined __PS3__ && !defined DISABLE_SPU_CODE
C4JSpursJobQueue : : Port port ( " C4JSpursJob_PerlinNoise " ) ;
C4JSpursJob_PerlinNoise perlinJob1 ( & g_scaleNoise_SPU ) ;
C4JSpursJob_PerlinNoise perlinJob2 ( & g_depthNoise_SPU ) ;
C4JSpursJob_PerlinNoise perlinJob3 ( & g_perlinNoise1_SPU ) ;
C4JSpursJob_PerlinNoise perlinJob4 ( & g_lperlinNoise1_SPU ) ;
C4JSpursJob_PerlinNoise perlinJob5 ( & g_lperlinNoise2_SPU ) ;
g_scaleNoise_SPU . set ( scaleNoise , sr , x , z , xSize , zSize , 1.121 , 1.121 , 0.5 ) ;
g_depthNoise_SPU . set ( depthNoise , dr , x , z , xSize , zSize , 200.0 , 200.0 , 0.5 ) ;
g_perlinNoise1_SPU . set ( perlinNoise1 , pnr , x , y , z , xSize , ySize , zSize , s / 80.0 , hs / 160.0 , s / 80.0 ) ;
g_lperlinNoise1_SPU . set ( lperlinNoise1 , ar , x , y , z , xSize , ySize , zSize , s , hs , s ) ;
g_lperlinNoise2_SPU . set ( lperlinNoise2 , br , x , y , z , xSize , ySize , zSize , s , hs , s ) ;
port . submitJob ( & perlinJob1 ) ;
port . submitJob ( & perlinJob2 ) ;
port . submitJob ( & perlinJob3 ) ;
port . submitJob ( & perlinJob4 ) ;
port . submitJob ( & perlinJob5 ) ;
port . waitForCompletion ( ) ;
2026-03-03 03:04:10 +08:00
# else
sr = scaleNoise - > getRegion ( sr , x , z , xSize , zSize , 1.121 , 1.121 , 0.5 ) ;
dr = depthNoise - > getRegion ( dr , x , z , xSize , zSize , 200.0 , 200.0 , 0.5 ) ;
pnr = perlinNoise1 - > getRegion ( pnr , x , y , z , xSize , ySize , zSize , s / 80.0 , hs / 160.0 , s / 80.0 ) ;
ar = lperlinNoise1 - > getRegion ( ar , x , y , z , xSize , ySize , zSize , s , hs , s ) ;
br = lperlinNoise2 - > getRegion ( br , x , y , z , xSize , ySize , zSize , s , hs , s ) ;
2026-03-01 12:16:08 +08:00
# endif
x = z = 0 ;
2026-03-03 03:04:10 +08:00
int p = 0 ;
int pp = 0 ;
2026-03-01 12:16:08 +08:00
2026-03-03 03:04:10 +08:00
for ( int xx = 0 ; xx < xSize ; xx + + )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
for ( int zz = 0 ; zz < zSize ; zz + + )
2026-03-01 12:16:08 +08:00
{
float sss = 0 ;
float ddd = 0 ;
float pow = 0 ;
int rr = 2 ;
Biome * mb = biomes [ ( xx + 2 ) + ( zz + 2 ) * ( xSize + 5 ) ] ;
for ( int xb = - rr ; xb < = rr ; xb + + )
{
for ( int zb = - rr ; zb < = rr ; zb + + )
{
Biome * b = biomes [ ( xx + xb + 2 ) + ( zz + zb + 2 ) * ( xSize + 5 ) ] ;
float ppp = pows [ xb + 2 + ( zb + 2 ) * 5 ] / ( b - > depth + 2 ) ;
if ( b - > depth > mb - > depth )
{
ppp / = 2 ;
}
sss + = b - > scale * ppp ;
ddd + = b - > depth * ppp ;
pow + = ppp ;
}
}
sss / = pow ;
ddd / = pow ;
sss = sss * 0.9f + 0.1f ;
ddd = ( ddd * 4 - 1 ) / 8.0f ;
2026-03-03 03:04:10 +08:00
double rdepth = ( dr [ pp ] / 8000.0 ) ;
if ( rdepth < 0 ) rdepth = - rdepth * 0.3 ;
rdepth = rdepth * 3.0 - 2.0 ;
if ( rdepth < 0 )
2026-03-01 12:16:08 +08:00
{
rdepth = rdepth / 2 ;
2026-03-03 03:04:10 +08:00
if ( rdepth < - 1 ) rdepth = - 1 ;
rdepth = rdepth / 1.4 ;
rdepth / = 2 ;
}
2026-03-01 12:16:08 +08:00
else
{
2026-03-03 03:04:10 +08:00
if ( rdepth > 1 ) rdepth = 1 ;
rdepth = rdepth / 8 ;
}
2026-03-01 12:16:08 +08:00
2026-03-03 03:04:10 +08:00
pp + + ;
2026-03-01 12:16:08 +08:00
2026-03-03 03:04:10 +08:00
for ( int yy = 0 ; yy < ySize ; yy + + )
2026-03-01 12:16:08 +08:00
{
double depth = ddd ;
double scale = sss ;
depth + = rdepth * 0.2 ;
depth = depth * ySize / 16.0 ;
double yCenter = ySize / 2.0 + depth * 4 ;
2026-03-03 03:04:10 +08:00
double val = 0 ;
2026-03-01 12:16:08 +08:00
double yOffs = ( yy - ( yCenter ) ) * 12 * 128 / Level : : genDepth / scale ;
2026-03-03 03:04:10 +08:00
if ( yOffs < 0 ) yOffs * = 4 ;
2026-03-01 12:16:08 +08:00
2026-03-03 03:04:10 +08:00
double bb = ar [ p ] / 512 ;
double cc = br [ p ] / 512 ;
2026-03-01 12:16:08 +08:00
2026-03-03 03:04:10 +08:00
double v = ( pnr [ p ] / 10 + 1 ) / 2 ;
if ( v < 0 ) val = bb ;
else if ( v > 1 ) val = cc ;
else val = bb + ( cc - bb ) * v ;
val - = yOffs ;
2026-03-01 12:16:08 +08:00
2026-03-03 03:04:10 +08:00
if ( yy > ySize - 4 )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
double slide = ( yy - ( ySize - 4 ) ) / ( 4 - 1.0f ) ;
val = val * ( 1 - slide ) + - 10 * slide ;
}
2026-03-01 12:16:08 +08:00
2026-03-03 03:04:10 +08:00
buffer [ p ] = val ;
p + + ;
}
}
}
2026-03-01 12:16:08 +08:00
delete [ ] pnr . data ;
delete [ ] ar . data ;
delete [ ] br . data ;
delete [ ] sr . data ;
delete [ ] dr . data ;
delete [ ] fi . data ;
delete [ ] fis . data ;
2026-03-03 03:04:10 +08:00
return buffer ;
2026-03-01 12:16:08 +08:00
}
bool RandomLevelSource : : hasChunk ( int x , int y )
{
return true ;
}
void RandomLevelSource : : calcWaterDepths ( ChunkSource * parent , int xt , int zt )
{
2026-03-03 03:04:10 +08:00
int xo = xt * 16 ;
int zo = zt * 16 ;
for ( int x = 0 ; x < 16 ; x + + )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
int y = level - > getSeaLevel ( ) ;
for ( int z = 0 ; z < 16 ; z + + )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
int xp = xo + x + 7 ;
int zp = zo + z + 7 ;
int h = level - > getHeightmap ( xp , zp ) ;
if ( h < = 0 )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
if ( level - > getHeightmap ( xp - 1 , zp ) > 0 | | level - > getHeightmap ( xp + 1 , zp ) > 0 | | level - > getHeightmap ( xp , zp - 1 ) > 0 | | level - > getHeightmap ( xp , zp + 1 ) > 0 )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
bool hadWater = false ;
if ( hadWater | | ( level - > getTile ( xp - 1 , y , zp ) = = Tile : : calmWater_Id & & level - > getData ( xp - 1 , y , zp ) < 7 ) ) hadWater = true ;
if ( hadWater | | ( level - > getTile ( xp + 1 , y , zp ) = = Tile : : calmWater_Id & & level - > getData ( xp + 1 , y , zp ) < 7 ) ) hadWater = true ;
if ( hadWater | | ( level - > getTile ( xp , y , zp - 1 ) = = Tile : : calmWater_Id & & level - > getData ( xp , y , zp - 1 ) < 7 ) ) hadWater = true ;
if ( hadWater | | ( level - > getTile ( xp , y , zp + 1 ) = = Tile : : calmWater_Id & & level - > getData ( xp , y , zp + 1 ) < 7 ) ) hadWater = true ;
if ( hadWater )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
for ( int x2 = - 5 ; x2 < = 5 ; x2 + + )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
for ( int z2 = - 5 ; z2 < = 5 ; z2 + + )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
int d = ( x2 > 0 ? x2 : - x2 ) + ( z2 > 0 ? z2 : - z2 ) ;
2026-03-01 12:16:08 +08:00
2026-03-03 03:04:10 +08:00
if ( d < = 5 )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
d = 6 - d ;
if ( level - > getTile ( xp + x2 , y , zp + z2 ) = = Tile : : calmWater_Id )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
int od = level - > getData ( xp + x2 , y , zp + z2 ) ;
if ( od < 7 & & od < d )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
level - > setData ( xp + x2 , y , zp + z2 , d , Tile : : UPDATE_ALL ) ;
}
}
}
}
}
if ( hadWater )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
level - > setTileAndData ( xp , y , zp , Tile : : calmWater_Id , 7 , Tile : : UPDATE_CLIENTS ) ;
for ( int y2 = 0 ; y2 < y ; y2 + + )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
level - > setTileAndData ( xp , y2 , zp , Tile : : calmWater_Id , 8 , Tile : : UPDATE_CLIENTS ) ;
}
}
}
}
}
}
}
2026-03-01 12:16:08 +08:00
}
// 4J - changed this to used pprandom rather than random, so that we can run it concurrently with getChunk
void RandomLevelSource : : postProcess ( ChunkSource * parent , int xt , int zt )
{
2026-03-03 03:04:10 +08:00
HeavyTile : : instaFall = true ;
int xo = xt * 16 ;
int zo = zt * 16 ;
2026-03-01 12:16:08 +08:00
2026-03-03 03:04:10 +08:00
Biome * biome = level - > getBiome ( xo + 16 , zo + 16 ) ;
2026-03-01 12:16:08 +08:00
2026-03-03 03:04:10 +08:00
if ( FLOATING_ISLANDS )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
calcWaterDepths ( parent , xt , zt ) ;
}
2026-03-01 12:16:08 +08:00
pprandom - > setSeed ( level - > getSeed ( ) ) ;
2026-03-02 17:39:35 +07:00
__int64 xScale = pprandom - > nextLong ( ) / 2 * 2 + 1 ;
__int64 zScale = pprandom - > nextLong ( ) / 2 * 2 + 1 ;
2026-03-01 12:16:08 +08:00
pprandom - > setSeed ( ( ( xt * xScale ) + ( zt * zScale ) ) ^ level - > getSeed ( ) ) ;
bool hasVillage = false ;
PIXBeginNamedEvent ( 0 , " Structure postprocessing " ) ;
if ( generateStructures )
{
mineShaftFeature - > postProcess ( level , pprandom , xt , zt ) ;
hasVillage = villageFeature - > postProcess ( level , pprandom , xt , zt ) ;
strongholdFeature - > postProcess ( level , pprandom , xt , zt ) ;
scatteredFeature - > postProcess ( level , random , xt , zt ) ;
}
PIXEndNamedEvent ( ) ;
PIXBeginNamedEvent ( 0 , " Lakes " ) ;
2026-03-03 03:04:10 +08:00
if ( biome ! = Biome : : desert & & biome ! = Biome : : desertHills )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
if ( ! hasVillage & & pprandom - > nextInt ( 4 ) = = 0 )
{
int x = xo + pprandom - > nextInt ( 16 ) + 8 ;
int y = pprandom - > nextInt ( Level : : genDepth ) ;
int z = zo + pprandom - > nextInt ( 16 ) + 8 ;
2026-03-01 12:16:08 +08:00
2026-03-03 03:04:10 +08:00
LakeFeature calmWater ( Tile : : calmWater_Id ) ;
calmWater . place ( level , pprandom , x , y , z ) ;
}
2026-03-01 12:16:08 +08:00
}
PIXEndNamedEvent ( ) ;
PIXBeginNamedEvent ( 0 , " Lava " ) ;
if ( ! hasVillage & & pprandom - > nextInt ( 8 ) = = 0 )
{
int x = xo + pprandom - > nextInt ( 16 ) + 8 ;
int y = pprandom - > nextInt ( pprandom - > nextInt ( Level : : genDepth - 8 ) + 8 ) ;
int z = zo + pprandom - > nextInt ( 16 ) + 8 ;
if ( y < level - > seaLevel | | pprandom - > nextInt ( 10 ) = = 0 )
{
2026-03-03 03:04:10 +08:00
LakeFeature calmLava ( Tile : : calmLava_Id ) ;
calmLava . place ( level , pprandom , x , y , z ) ;
2026-03-01 12:16:08 +08:00
}
}
PIXEndNamedEvent ( ) ;
PIXBeginNamedEvent ( 0 , " Monster rooms " ) ;
2026-03-03 03:04:10 +08:00
for ( int i = 0 ; i < 8 ; i + + )
{
2026-03-01 12:16:08 +08:00
int x = xo + pprandom - > nextInt ( 16 ) + 8 ;
int y = pprandom - > nextInt ( Level : : genDepth ) ;
int z = zo + pprandom - > nextInt ( 16 ) + 8 ;
2026-03-03 03:04:10 +08:00
MonsterRoomFeature mrf ;
mrf . place ( level , pprandom , x , y , z ) ;
2026-03-01 12:16:08 +08:00
}
PIXEndNamedEvent ( ) ;
PIXBeginNamedEvent ( 0 , " Biome decorate " ) ;
biome - > decorate ( level , pprandom , xo , zo ) ;
PIXEndNamedEvent ( ) ;
2026-03-03 03:04:10 +08:00
PIXBeginNamedEvent ( 0 , " Process Schematics " ) ;
2026-03-01 12:16:08 +08:00
app . processSchematics ( parent - > getChunk ( xt , zt ) ) ;
2026-03-03 03:04:10 +08:00
PIXEndNamedEvent ( ) ;
2026-03-01 12:16:08 +08:00
2026-03-03 03:04:10 +08:00
PIXBeginNamedEvent ( 0 , " Post process mobs " ) ;
2026-03-01 12:16:08 +08:00
MobSpawner : : postProcessSpawnMobs ( level , biome , xo + 8 , zo + 8 , 16 , 16 , pprandom ) ;
2026-03-03 03:04:10 +08:00
PIXEndNamedEvent ( ) ;
2026-03-01 12:16:08 +08:00
2026-03-03 03:04:10 +08:00
PIXBeginNamedEvent ( 0 , " Update ice and snow " ) ;
2026-03-01 12:16:08 +08:00
// 4J - brought forward from 1.2.3 to get snow back in taiga biomes
2026-03-03 03:04:10 +08:00
xo + = 8 ;
zo + = 8 ;
for ( int x = 0 ; x < 16 ; x + + )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
for ( int z = 0 ; z < 16 ; z + + )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
int y = level - > getTopRainBlock ( xo + x , zo + z ) ;
2026-03-01 12:16:08 +08:00
2026-03-03 03:04:10 +08:00
if ( level - > shouldFreezeIgnoreNeighbors ( x + xo , y - 1 , z + zo ) )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
level - > setTileAndData ( x + xo , y - 1 , z + zo , Tile : : ice_Id , 0 , Tile : : UPDATE_CLIENTS ) ;
}
if ( level - > shouldSnow ( x + xo , y , z + zo ) )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
level - > setTileAndData ( x + xo , y , z + zo , Tile : : topSnow_Id , 0 , Tile : : UPDATE_CLIENTS ) ;
}
}
}
PIXEndNamedEvent ( ) ;
2026-03-01 12:16:08 +08:00
2026-03-03 03:04:10 +08:00
HeavyTile : : instaFall = false ;
2026-03-01 12:16:08 +08:00
}
bool RandomLevelSource : : save ( bool force , ProgressListener * progressListener )
{
return true ;
}
bool RandomLevelSource : : tick ( )
{
return false ;
}
bool RandomLevelSource : : shouldSave ( )
{
return true ;
}
wstring RandomLevelSource : : gatherStats ( )
{
return L " RandomLevelSource " ;
}
vector < Biome : : MobSpawnerData * > * RandomLevelSource : : getMobsAt ( MobCategory * mobCategory , int x , int y , int z )
{
2026-03-03 03:04:10 +08:00
Biome * biome = level - > getBiome ( x , z ) ;
if ( biome = = NULL )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
return NULL ;
}
if ( mobCategory = = MobCategory : : monster & & scatteredFeature - > isSwamphut ( x , y , z ) )
{
return scatteredFeature - > getSwamphutEnemies ( ) ;
}
return biome - > getMobs ( mobCategory ) ;
2026-03-01 12:16:08 +08:00
}
TilePos * RandomLevelSource : : findNearestMapFeature ( Level * level , const wstring & featureName , int x , int y , int z )
{
2026-03-03 03:04:10 +08:00
if ( LargeFeature : : STRONGHOLD = = featureName & & strongholdFeature ! = NULL )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
return strongholdFeature - > getNearestGeneratedFeature ( level , x , y , z ) ;
}
return NULL ;
2026-03-01 12:16:08 +08:00
}
2026-03-03 03:04:10 +08:00
void RandomLevelSource : : recreateLogicStructuresForChunk ( int chunkX , int chunkZ )
{
if ( generateStructures )
{
mineShaftFeature - > apply ( this , level , chunkX , chunkZ , NULL ) ;
villageFeature - > apply ( this , level , chunkX , chunkZ , NULL ) ;
strongholdFeature - > apply ( this , level , chunkX , chunkZ , NULL ) ;
scatteredFeature - > apply ( this , level , chunkX , chunkZ , NULL ) ;
}
}