Simple climate based biome scattering

This commit is contained in:
NSDeathman 2026-03-11 20:46:50 +03:00
parent 0f3738c320
commit 6f725b8355
4 changed files with 145 additions and 18 deletions

View file

@ -5,6 +5,7 @@
#include "net.minecraft.world.level.newbiome.layer.h"
#include "System.h"
#include "BiomeSource.h"
#include "ClimateLayer.h"
#include "..\Minecraft.Client\Minecraft.h"
#include "..\Minecraft.Client\ProgressRenderer.h"
@ -16,12 +17,12 @@ void BiomeSource::_init()
cache = new BiomeCache(this);
playerSpawnBiomes.push_back(Biome::forest);
playerSpawnBiomes.push_back(Biome::taiga);
// 4J-PB - Moving forward plains as a spawnable biome (mainly for the Superflat world)
playerSpawnBiomes.push_back(Biome::plains);
playerSpawnBiomes.push_back(Biome::taigaHills);
playerSpawnBiomes.push_back(Biome::forest);
playerSpawnBiomes.push_back(Biome::forestHills);
playerSpawnBiomes.push_back(Biome::taiga);
playerSpawnBiomes.push_back(Biome::taigaHills);
playerSpawnBiomes.push_back(Biome::jungle);
playerSpawnBiomes.push_back(Biome::jungleHills);
}
@ -30,7 +31,8 @@ void BiomeSource::_init(int64_t seed, LevelType *generator)
{
_init();
LayerArray layers = Layer::getDefaultLayers(seed, generator);
// LayerArray layers = Layer::getDefaultLayers(seed, generator);
LayerArray layers = getClimateLayers(seed, generator);
layer = layers[0];
zoomedLayer = layers[1];
@ -147,6 +149,16 @@ void BiomeSource::getTemperatureBlock(floatArray& temperatures, int x, int z, in
}
}
LayerArray BiomeSource::getClimateLayers(int64_t seed, LevelType* generator)
{
LayerArray layers(2);
// Ãðóáûé ñëîé (ìàñøòàá 0.04) — äëÿ ïðåäâàðèòåëüíûõ ïðîâåðîê, åñëè íóæåí
layers[0] = std::make_shared<ClimateLayer>(seed, 4, 0.04);
// Äåòàëüíûé ñëîé (ìàñøòàá 0.01) — äëÿ ôèíàëüíîé êàðòû áèîìîâ
layers[1] = std::make_shared<ClimateLayer>(seed, 4, 0.01);
return layers;
}
BiomeArray BiomeSource::getRawBiomeBlock(int x, int z, int w, int h) const
{
BiomeArray biomes;
@ -408,6 +420,7 @@ void BiomeSource::update()
}
//#define DEBUG_SEEDS 50
const int MAX_SEED_ATTEMPTS = 100;
// 4J added - find a seed for this biomesource that matches certain criteria
#ifdef __PSVITA__
@ -422,7 +435,7 @@ int64_t BiomeSource::findSeed(LevelType *generator)
ProgressRenderer *mcprogress = Minecraft::GetInstance()->progressRenderer;
mcprogress->progressStage(IDS_PROGRESS_NEW_WORLD_SEED);
#ifndef _CONTENT_PACKAGE
#if 0//ndef _CONTENT_PACKAGE
if(app.DebugSettingsOn() && app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad())&(1L<<eDebugSetting_EnableBiomeOverride))
{
// Do nothing
@ -470,23 +483,25 @@ int64_t BiomeSource::findSeed(LevelType *generator)
mcprogress->progressStagePercentage( tryCount % 100 );
#ifdef __PSVITA__
} while (!matchFound && *pServerRunning);
} while (!matchFound && *pServerRunning && tryCount < MAX_SEED_ATTEMPTS);
#else
} while (!matchFound);
} while (!matchFound && tryCount < MAX_SEED_ATTEMPTS);
#endif
// Clean up
delete pr;
delete indices.data;
#ifdef DEBUG_SEEDS
app.DebugPrintf("%d: %d tries taken, seed used is %lld\n", k, tryCount, bestSeed);
#if 1//def DEBUG_SEEDS
//app.DebugPrintf("%d: %d tries taken, seed used is %lld\n", k, tryCount, bestSeed);
BiomeSource *biomeSource = new BiomeSource(bestSeed);
BiomeArray biomes = biomeSource->getBiomeBlock(-27 * 16, -27 * 16, 54 * 16, 54 * 16);
int size = 64 * 16;
unsigned int *pixels = new unsigned int[54 * 16 * 54 * 16];
for(int i = 0; i < 54 * 16 * 54 * 16; i++ )
BiomeSource *biomeSource = new BiomeSource(bestSeed, generator);
BiomeArray biomes = biomeSource->getBiomeBlock(-27 * 16, -27 * 16, size, size);
unsigned int *pixels = new unsigned int[size * size];
for(int i = 0; i < size * size; i++ )
{
int id = biomes[i]->id;
@ -519,13 +534,13 @@ int64_t BiomeSource::findSeed(LevelType *generator)
if( id & 8 ) pixels[i] |= 0x00808080;
}
D3DXIMAGE_INFO srcInfo;
srcInfo.Format = D3DFMT_LIN_A8R8G8B8;
srcInfo.ImageFileFormat = D3DXIFF_BMP;
srcInfo.Width = 54 * 16;
srcInfo.Height = 54 * 16;
//srcInfo.Format = D3DFMT_LIN_A8R8G8B8;
//srcInfo.ImageFileFormat = D3DXIFF_BMP;
srcInfo.Width = size;
srcInfo.Height = size;
char buf[256];
sprintf(buf,"GAME:\\BiomeTest%d.bmp",k);
sprintf(buf,"GAME:\\BiomeTest%d.bmp", bestSeed);
RenderManager.SaveTextureData(buf, &srcInfo, (int *)pixels);
delete [] pixels;

View file

@ -47,6 +47,8 @@ public:
virtual Biome *getBiome(ChunkPos *cp);
virtual Biome *getBiome(int x, int z);
static LayerArray getClimateLayers(int64_t seed, LevelType* generator);
// 4J - changed the interface for these methods, mainly for thread safety
virtual float getDownfall(int x, int z) const;
virtual floatArray getDownfallBlock(int x, int z, int w, int h) const;

View file

@ -0,0 +1,81 @@
#include "stdafx.h"
#include "ClimateLayer.h"
#include "Random.h"
#include "Mth.h"
#include "IntCache.h"
ClimateLayer::ClimateLayer(int64_t seed, int octaves, double scale)
: Layer(seed), scale(scale)
{
Random random(seed);
temperatureNoise = new PerlinNoise(&random, octaves);
humidityNoise = new PerlinNoise(&random, octaves);
initBiomeCenters();
}
ClimateLayer::~ClimateLayer()
{
delete temperatureNoise;
delete humidityNoise;
}
void ClimateLayer::initBiomeCenters()
{
// Çàäà¸ì öåíòðû îñíîâíûõ áèîìîâ â ïðîñòðàíñòâå (òåìïåðàòóðà, âëàæíîñòü)
// Çíà÷åíèÿ ïîäîáðàíû íà îñíîâå setTemperatureAndDownfall() èç Biome.cpp
centers.push_back({ 0.00f, 0.25f, Biome::iceFlats }); // õîëîäíûå ðàâíèíû
centers.push_back({ 0.10f, 0.80f, Biome::taiga }); // òàéãà
centers.push_back({ 0.30f, 0.30f, Biome::extremeHills }); // ýêñòðåìàëüíûå õîëìû
centers.push_back({ 0.70f, 0.40f, Biome::plains }); // ðàâíèíû
centers.push_back({ 0.70f, 0.70f, Biome::forest }); // ëåñ
centers.push_back({ 0.80f, 0.95f, Biome::swampland }); // áîëîòî
centers.push_back({ 0.95f, 0.05f, Biome::desert }); // ïóñòûíÿ
centers.push_back({ 0.95f, 0.85f, Biome::jungle }); // äæóíãëè
// Ïðèìå÷àíèå: îêåàíè÷åñêèå áèîìû íå âêëþ÷åíû — îíè áóäóò îïðåäåëÿòüñÿ ïî âûñîòå îòäåëüíî.
// Õîëìèñòûå âàðèàíòû (desertHills, forestHills è ò.ä.) ìîæíî äîáàâèòü ïîçæå,
// èñïîëüçóÿ äîïîëíèòåëüíûé øóì âûñîòû èëè âòîðîé ïðîõîä.
}
Biome* ClimateLayer::getBiomeForClimate(float temp, float hum) const
{
float bestDist = 1e9f;
Biome* bestBiome = Biome::plains; // çàïàñíîé âàðèàíò
for (const auto& c : centers) {
float dx = temp - c.temp;
float dy = hum - c.hum;
float dist = dx * dx + dy * dy; // êâàäðàò åâêëèäîâà ðàññòîÿíèÿ
if (dist < bestDist) {
bestDist = dist;
bestBiome = c.biome;
}
}
return bestBiome;
}
intArray ClimateLayer::getArea(int xo, int yo, int w, int h)
{
IntCache::releaseAll();
intArray result = IntCache::allocate(w * h);
for (int y = 0; y < h; ++y) {
for (int x = 0; x < w; ++x) {
int worldX = xo + x;
int worldY = yo + y;
// Ïîëó÷àåì çíà÷åíèÿ øóìà â äèàïàçîíå ïðèìåðíî [-1, 1]
double tempNoise = temperatureNoise->getValue(worldX * scale, worldY * scale);
double humNoise = humidityNoise->getValue(worldX * scale, worldY * scale);
// Íîðìàëèçóåì â [0, 1] (ëîãèñòè÷åñêàÿ ôóíêöèÿ èëè ïðîñòî clamp)
float normTemp = Mth::clamp((float)((tempNoise + 1.0) * 0.5), 0.0f, 1.0f);
float normHum = Mth::clamp((float)((humNoise + 1.0) * 0.5), 0.0f, 1.0f);
Biome* biome = getBiomeForClimate(normTemp, normHum);
result[x + y * w] = biome->id;
}
}
return result;
}

View file

@ -0,0 +1,29 @@
#pragma once
#include "Layer.h"
#include "PerlinNoise.h"
#include "Biome.h"
#include <vector>
class ClimateLayer : public Layer
{
private:
PerlinNoise* temperatureNoise;
PerlinNoise* humidityNoise;
double scale; // ìàñøòàá øóìà (÷åì ìåíüøå, òåì êðóïíåå áèîìû)
struct BiomeCenter {
float temp;
float hum;
Biome* biome;
};
std::vector<BiomeCenter> centers;
void initBiomeCenters(); // çàïîëíèòü öåíòðû áèîìîâ
Biome* getBiomeForClimate(float temp, float hum) const;
public:
ClimateLayer(int64_t seed, int octaves = 4, double scale = 0.01);
virtual ~ClimateLayer();
virtual intArray getArea(int xo, int yo, int w, int h) override;
};