mirror of
https://github.com/neoStudiosLCE/neoLegacy.git
synced 2026-08-20 09:57:09 +00:00
Add seed validation for server world creation and override-seed property
The dedicated server previously picked a completely random seed with no biome diversity checks (the client validates but the server skipped it). On top of that, the client's findSeed() was hardcoded to only check a 54-chunk (Classic) area, so Large worlds had no diversity guarantee beyond the center. New server worlds now use findSeed() scaled to the full target world size. Added override-seed in server.properties to fix existing worlds without deleting them.
This commit is contained in:
parent
5dad6c24f7
commit
08f14e32ae
|
|
@ -206,6 +206,8 @@ CMinecraftApp::CMinecraftApp()
|
||||||
m_dwRequiredTexturePackID=0;
|
m_dwRequiredTexturePackID=0;
|
||||||
|
|
||||||
m_bResetNether=false;
|
m_bResetNether=false;
|
||||||
|
m_seedOverride = 0;
|
||||||
|
m_hasSeedOverride = false;
|
||||||
|
|
||||||
#ifdef _XBOX
|
#ifdef _XBOX
|
||||||
// m_bTransferSavesToXboxOne=false;
|
// m_bTransferSavesToXboxOne=false;
|
||||||
|
|
|
||||||
|
|
@ -706,6 +706,8 @@ private:
|
||||||
bool m_bGameNewWorldSizeUseMoat;
|
bool m_bGameNewWorldSizeUseMoat;
|
||||||
unsigned int m_GameNewHellScale;
|
unsigned int m_GameNewHellScale;
|
||||||
#endif
|
#endif
|
||||||
|
int64_t m_seedOverride;
|
||||||
|
bool m_hasSeedOverride;
|
||||||
unsigned int FromBigEndian(unsigned int uiValue);
|
unsigned int FromBigEndian(unsigned int uiValue);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -723,6 +725,10 @@ public:
|
||||||
void SetGameNewHellScale(unsigned int newScale) { m_GameNewHellScale = newScale; }
|
void SetGameNewHellScale(unsigned int newScale) { m_GameNewHellScale = newScale; }
|
||||||
unsigned int GetGameNewHellScale() { return m_GameNewHellScale; }
|
unsigned int GetGameNewHellScale() { return m_GameNewHellScale; }
|
||||||
#endif
|
#endif
|
||||||
|
void SetSeedOverride(int64_t seed) { m_seedOverride = seed; m_hasSeedOverride = true; }
|
||||||
|
bool HasSeedOverride() { return m_hasSeedOverride; }
|
||||||
|
int64_t GetSeedOverride() { return m_seedOverride; }
|
||||||
|
|
||||||
void SetResetNether(bool bResetNether) {m_bResetNether=bResetNether;}
|
void SetResetNether(bool bResetNether) {m_bResetNether=bResetNether;}
|
||||||
bool GetResetNether() {return m_bResetNether;}
|
bool GetResetNether() {return m_bResetNether;}
|
||||||
bool CanRecordStatsAndAchievements();
|
bool CanRecordStatsAndAchievements();
|
||||||
|
|
|
||||||
|
|
@ -735,10 +735,11 @@ bool MinecraftServer::initServer(int64_t seed, NetworkGameInitData *initData, DW
|
||||||
|
|
||||||
if( findSeed )
|
if( findSeed )
|
||||||
{
|
{
|
||||||
|
int worldSizeChunks = (initData && initData->xzSize > 0) ? (int)initData->xzSize : 54;
|
||||||
#ifdef __PSVITA__
|
#ifdef __PSVITA__
|
||||||
seed = BiomeSource::findSeed(pLevelType, &running);
|
seed = BiomeSource::findSeed(pLevelType, &running, worldSizeChunks);
|
||||||
#else
|
#else
|
||||||
seed = BiomeSource::findSeed(pLevelType);
|
seed = BiomeSource::findSeed(pLevelType, worldSizeChunks);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -824,6 +824,20 @@ ServerPropertiesConfig LoadServerPropertiesConfig()
|
||||||
config.maxPlayers = ReadNormalizedIntProperty(&merged, "max-players", kDefaultMaxPlayers, 1, kMaxDedicatedPlayers, &shouldWrite);
|
config.maxPlayers = ReadNormalizedIntProperty(&merged, "max-players", kDefaultMaxPlayers, 1, kMaxDedicatedPlayers, &shouldWrite);
|
||||||
config.seed = 0;
|
config.seed = 0;
|
||||||
config.hasSeed = ReadNormalizedOptionalInt64Property(&merged, "level-seed", &config.seed, &shouldWrite);
|
config.hasSeed = ReadNormalizedOptionalInt64Property(&merged, "level-seed", &config.seed, &shouldWrite);
|
||||||
|
config.overrideSeed = 0;
|
||||||
|
config.hasOverrideSeed = false;
|
||||||
|
{
|
||||||
|
auto it = merged.find("override-seed");
|
||||||
|
if (it != merged.end() && !TrimAscii(it->second).empty())
|
||||||
|
{
|
||||||
|
__int64 parsed = 0;
|
||||||
|
if (TryParseInt64(TrimAscii(it->second), &parsed))
|
||||||
|
{
|
||||||
|
config.overrideSeed = parsed;
|
||||||
|
config.hasOverrideSeed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
config.logLevel = ReadNormalizedLogLevelProperty(&merged, "log-level", eServerLogLevel_Info, &shouldWrite);
|
config.logLevel = ReadNormalizedLogLevelProperty(&merged, "log-level", eServerLogLevel_Info, &shouldWrite);
|
||||||
config.autosaveIntervalSeconds = ReadNormalizedIntProperty(&merged, "autosave-interval", kDefaultAutosaveIntervalSeconds, 5, 3600, &shouldWrite);
|
config.autosaveIntervalSeconds = ReadNormalizedIntProperty(&merged, "autosave-interval", kDefaultAutosaveIntervalSeconds, 5, 3600, &shouldWrite);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,9 @@ namespace ServerRuntime
|
||||||
bool hasSeed;
|
bool hasSeed;
|
||||||
/** `level-seed` */
|
/** `level-seed` */
|
||||||
__int64 seed;
|
__int64 seed;
|
||||||
|
/** `override-seed` replaces the seed for biome generation on existing worlds */
|
||||||
|
bool hasOverrideSeed;
|
||||||
|
__int64 overrideSeed;
|
||||||
/** `log-level` */
|
/** `log-level` */
|
||||||
EServerLogLevel logLevel;
|
EServerLogLevel logLevel;
|
||||||
/** `autosave-interval` (seconds) */
|
/** `autosave-interval` (seconds) */
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,8 @@
|
||||||
#include "../../Minecraft.World/TilePos.h"
|
#include "../../Minecraft.World/TilePos.h"
|
||||||
#include "../../Minecraft.World/compression.h"
|
#include "../../Minecraft.World/compression.h"
|
||||||
#include "../../Minecraft.World/OldChunkStorage.h"
|
#include "../../Minecraft.World/OldChunkStorage.h"
|
||||||
|
#include "../../Minecraft.World/BiomeSource.h"
|
||||||
|
#include "../../Minecraft.World/LevelType.h"
|
||||||
#include "../../Minecraft.World/net.minecraft.world.level.tile.h"
|
#include "../../Minecraft.World/net.minecraft.world.level.tile.h"
|
||||||
#include "../../Minecraft.World/Random.h"
|
#include "../../Minecraft.World/Random.h"
|
||||||
|
|
||||||
|
|
@ -545,6 +547,12 @@ int main(int argc, char **argv)
|
||||||
app.SetGameNewHellScale(serverProperties.worldHellScale);
|
app.SetGameNewHellScale(serverProperties.worldHellScale);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (serverProperties.hasOverrideSeed)
|
||||||
|
{
|
||||||
|
LogInfof("startup", "Seed override active: %lld", serverProperties.overrideSeed);
|
||||||
|
app.SetSeedOverride(serverProperties.overrideSeed);
|
||||||
|
}
|
||||||
|
|
||||||
StorageManager.SetSaveDisabled(serverProperties.disableSaving);
|
StorageManager.SetSaveDisabled(serverProperties.disableSaving);
|
||||||
// Read world name and fixed save-id from server.properties
|
// Read world name and fixed save-id from server.properties
|
||||||
// Delegate load-vs-create decision to WorldManager
|
// Delegate load-vs-create decision to WorldManager
|
||||||
|
|
@ -584,9 +592,17 @@ int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
param->seed = config.seed;
|
param->seed = config.seed;
|
||||||
}
|
}
|
||||||
|
else if (worldBootstrap.saveData == nullptr)
|
||||||
|
{
|
||||||
|
// Only run seed validation when creating a brand-new world.
|
||||||
|
// Existing worlds already have their seed in level.dat.
|
||||||
|
LogInfof("startup", "Finding seed with biome diversity for %d-chunk world...", config.worldSizeChunks);
|
||||||
|
param->seed = BiomeSource::findSeed(LevelType::lvl_normal, config.worldSizeChunks);
|
||||||
|
LogInfof("startup", "Selected seed: %lld", param->seed);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
param->seed = (new Random())->nextLong();
|
param->seed = (new Random())->nextLong(); // placeholder; level.dat seed takes priority
|
||||||
}
|
}
|
||||||
#ifdef _LARGE_WORLDS
|
#ifdef _LARGE_WORLDS
|
||||||
param->xzSize = (unsigned int)config.worldSizeChunks;
|
param->xzSize = (unsigned int)config.worldSizeChunks;
|
||||||
|
|
|
||||||
|
|
@ -411,9 +411,9 @@ void BiomeSource::update()
|
||||||
|
|
||||||
// 4J added - find a seed for this biomesource that matches certain criteria
|
// 4J added - find a seed for this biomesource that matches certain criteria
|
||||||
#ifdef __PSVITA__
|
#ifdef __PSVITA__
|
||||||
int64_t BiomeSource::findSeed(LevelType *generator, bool* pServerRunning) // MGH - added pRunning, so we can early out of this on Vita as it can take up to 60 secs
|
int64_t BiomeSource::findSeed(LevelType *generator, bool* pServerRunning, int worldSizeChunks)
|
||||||
#else
|
#else
|
||||||
int64_t BiomeSource::findSeed(LevelType *generator)
|
int64_t BiomeSource::findSeed(LevelType *generator, int worldSizeChunks)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
@ -440,8 +440,8 @@ int64_t BiomeSource::findSeed(LevelType *generator)
|
||||||
// Raw biome data has one result per 4x4 group of tiles.
|
// Raw biome data has one result per 4x4 group of tiles.
|
||||||
// Removing a border of 8 from each side since we'll be doing special things at the edge to turn our world into an island, and so don't want to count things
|
// Removing a border of 8 from each side since we'll be doing special things at the edge to turn our world into an island, and so don't want to count things
|
||||||
// in the edge region in case they later get removed
|
// in the edge region in case they later get removed
|
||||||
static const int biomeWidth = ( 54 * 4 ) - 16; // Should be even so we can offset evenly
|
const int biomeWidth = ( worldSizeChunks * 4 ) - 16; // Should be even so we can offset evenly
|
||||||
static const int biomeOffset = -( biomeWidth / 2 );
|
const int biomeOffset = -( biomeWidth / 2 );
|
||||||
|
|
||||||
// Storage for our biome indices
|
// Storage for our biome indices
|
||||||
intArray indices = intArray( biomeWidth * biomeWidth );
|
intArray indices = intArray( biomeWidth * biomeWidth );
|
||||||
|
|
|
||||||
|
|
@ -36,9 +36,9 @@ private:
|
||||||
static void getFracs(intArray indices, float *fracs); // 4J added
|
static void getFracs(intArray indices, float *fracs); // 4J added
|
||||||
public:
|
public:
|
||||||
#ifdef __PSVITA__
|
#ifdef __PSVITA__
|
||||||
static int64_t findSeed(LevelType *generator, bool* pServerRunning); // MGH - added pRunning, so we can early out of this on Vita as it can take up to 60 secs // 4J added
|
static int64_t findSeed(LevelType *generator, bool* pServerRunning, int worldSizeChunks = 54);
|
||||||
#else
|
#else
|
||||||
static int64_t findSeed(LevelType *generator); // 4J added
|
static int64_t findSeed(LevelType *generator, int worldSizeChunks = 54);
|
||||||
#endif
|
#endif
|
||||||
~BiomeSource();
|
~BiomeSource();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,15 @@ LevelData::LevelData()
|
||||||
LevelData::LevelData(CompoundTag *tag)
|
LevelData::LevelData(CompoundTag *tag)
|
||||||
{
|
{
|
||||||
seed = tag->getLong(L"RandomSeed");
|
seed = tag->getLong(L"RandomSeed");
|
||||||
|
|
||||||
|
// Allow server.properties to override the world seed for biome generation
|
||||||
|
// on existing worlds (e.g. to fix monotonous biomes after world expansion).
|
||||||
|
if (app.HasSeedOverride())
|
||||||
|
{
|
||||||
|
app.DebugPrintf("Overriding world seed: %lld -> %lld\n", seed, app.GetSeedOverride());
|
||||||
|
seed = app.GetSeedOverride();
|
||||||
|
}
|
||||||
|
|
||||||
m_pGenerator = LevelType::lvl_normal;
|
m_pGenerator = LevelType::lvl_normal;
|
||||||
if (tag->contains(L"generatorName"))
|
if (tag->contains(L"generatorName"))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,12 @@ This project is based on source code of Minecraft Legacy Console Edition v1.6.05
|
||||||
|
|
||||||
## Latest:
|
## Latest:
|
||||||
|
|
||||||
|
Dedicated server biome diversity fix:
|
||||||
|
- The dedicated server previously used a completely random seed with no biome diversity checks — unlike the client which validates seeds to guarantee varied biomes. This could result in server worlds with large regions dominated by only one or two biome types (e.g. all taiga/snowy)
|
||||||
|
- On top of that, the client's seed validation was hardcoded to only check a 54-chunk (Classic) area, so even validated seeds had no diversity guarantee beyond that — making the problem especially noticeable on Large worlds or worlds expanded from Classic to Large
|
||||||
|
- New server worlds now validate seeds for biome diversity, and the validation scales to the full target world size
|
||||||
|
- Added `override-seed` in server.properties to fix existing worlds without deleting them — set it to any seed number and newly generated chunks will use it instead of the original
|
||||||
|
|
||||||
Server list and connection improvements:
|
Server list and connection improvements:
|
||||||
- Server edits and deletions now apply immediately without needing to restart the game
|
- Server edits and deletions now apply immediately without needing to restart the game
|
||||||
- Connecting to an offline/unreachable server no longer freezes the game indefinitely
|
- Connecting to an offline/unreachable server no longer freezes the game indefinitely
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue