Add options for landmass generation: vanilla, continents, or archipelago

This commit is contained in:
Cheeserolls 2015-06-19 23:47:37 +01:00
parent 9220148251
commit 7508fbf9c7
9 changed files with 339 additions and 30 deletions

View file

@ -1,8 +1,7 @@
package biomesoplenty.client.gui;
import biomesoplenty.common.world.BOPWorldSettings;
import biomesoplenty.common.world.BOPWorldSettings.TemperatureVariationScheme;
import biomesoplenty.common.world.BOPWorldSettings.BiomeSize;
import biomesoplenty.common.world.BOPWorldSettings.*;
import com.google.common.base.Predicate;
import com.google.common.primitives.Floats;
@ -147,7 +146,8 @@ public class GuiBOPConfigureWorld extends GuiScreen implements GuiSlider.FormatH
GENERATE_BOP_GEMS (102),
AMPLITUDE_LABEL(103),
AMPLITUDE (104),
BIOME_SIZE (105);
BIOME_SIZE (105),
LAND_SCHEME (106);
private int id;
@ -182,6 +182,7 @@ public class GuiBOPConfigureWorld extends GuiScreen implements GuiSlider.FormatH
GuiBOPConfigPage.GuiListEntry[] page0 = new GuiBOPConfigPage.GuiListEntry[] {
new GuiBOPConfigPage.GuiEnumButtonEntry<BiomeSize>(GuiEntries.BIOME_SIZE.getId(), "Biome Size: %s", true, this.settings.biomeSize),
new GuiBOPConfigPage.GuiEnumButtonEntry<TemperatureVariationScheme>(GuiEntries.TEMP_SCHEME.getId(), "Temperature: %s", true, this.settings.tempScheme),
new GuiBOPConfigPage.GuiEnumButtonEntry<LandMassScheme>(GuiEntries.LAND_SCHEME.getId(), "Land Mass: %s", true, this.settings.landScheme),
new GuiBOPConfigPage.GuiSlideEntry(GuiEntries.AMPLITUDE.getId(), "Amplitude", true, this, 0.2F, 3.0F, this.settings.amplitude)
};
@ -237,6 +238,10 @@ public class GuiBOPConfigureWorld extends GuiScreen implements GuiSlider.FormatH
switch (entry)
{
case LAND_SCHEME:
LandMassScheme[] land_values = LandMassScheme.values();
this.settings.landScheme = land_values[ordinal % land_values.length];
break;
case TEMP_SCHEME:
TemperatureVariationScheme[] temp_values = TemperatureVariationScheme.values();
this.settings.tempScheme = temp_values[ordinal % temp_values.length];

View file

@ -22,6 +22,13 @@ public class BOPWorldSettings
public static Gson serializer = new GsonBuilder().create();
public static enum LandMassScheme
{
VANILLA,
CONTINENTS,
ARCHIPELAGO;
}
public static enum TemperatureVariationScheme
{
VANILLA,
@ -50,6 +57,7 @@ public class BOPWorldSettings
// BOP World properties
public LandMassScheme landScheme = LandMassScheme.VANILLA;
public TemperatureVariationScheme tempScheme = TemperatureVariationScheme.VANILLA;
public BiomeSize biomeSize = BiomeSize.MEDIUM;
public float amplitude = 1.0F;
@ -89,6 +97,7 @@ public class BOPWorldSettings
public String toJson()
{
JsonObject obj = new JsonObject();
obj.addProperty("landScheme", this.landScheme.name().toLowerCase());
obj.addProperty("tempScheme", this.tempScheme.name().toLowerCase());
obj.addProperty("biomeSize", this.biomeSize.name().toLowerCase());
obj.addProperty("amplitude", this.amplitude);
@ -104,6 +113,7 @@ public class BOPWorldSettings
public void fromConfigObj(BOPConfig.IConfigObj worldConfig)
{
this.landScheme = worldConfig.getEnum("landScheme", this.landScheme, LandMassScheme.class);
this.tempScheme = worldConfig.getEnum("tempScheme", this.tempScheme, TemperatureVariationScheme.class);
this.biomeSize = worldConfig.getEnum("biomeSize", this.biomeSize, BiomeSize.class);
this.amplitude = worldConfig.getFloat("amplitude", this.amplitude);
@ -114,6 +124,7 @@ public class BOPWorldSettings
{
// BOP default values
this.landScheme = LandMassScheme.VANILLA;
this.tempScheme = TemperatureVariationScheme.VANILLA;
this.biomeSize = BiomeSize.MEDIUM;
this.amplitude = 1.0F;

View file

@ -9,6 +9,7 @@
package biomesoplenty.common.world;
import biomesoplenty.api.biome.BOPBiome;
import biomesoplenty.common.world.BOPWorldSettings.LandMassScheme;
import biomesoplenty.common.world.BOPWorldSettings.TemperatureVariationScheme;
import biomesoplenty.common.world.layer.*;
import net.minecraft.world.World;
@ -21,7 +22,6 @@ public class WorldChunkManagerBOP extends WorldChunkManager
{
// TODO: ability to vary landmass creation - eg continents, archipelago etc
// TODO: client reported different chunkProviderSettings than the server
public WorldChunkManagerBOP(long seed, WorldType worldType, String chunkProviderSettings)
{
super();
@ -31,9 +31,11 @@ public class WorldChunkManagerBOP extends WorldChunkManager
}
// load the settings object
BOPWorldSettings settings = new BOPWorldSettings(chunkProviderSettings);
System.out.println("settings for world: "+settings.toJson());
// note on the client side, chunkProviderSettings is an empty string
// I'm not sure if this is a bug or deliberate, but it might have some consequences when the biomes/genlayers are different between client and server
// The same thing happens in vanilla minecraft
System.out.println("settings for world: "+chunkProviderSettings);
BOPWorldSettings settings = new BOPWorldSettings(chunkProviderSettings);
// loop through the biomes and apply the settings
for (BiomeGenBase biome : BiomeGenBase.getBiomeGenArray())
@ -58,30 +60,51 @@ public class WorldChunkManagerBOP extends WorldChunkManager
}
// generate the regions of land and sea
public static GenLayer initialLandAndSeaLayer()
public static GenLayer initialLandAndSeaLayer(LandMassScheme scheme)
{
GenLayer stack = new GenLayerIsland(1L);
stack = new GenLayerFuzzyZoom(2000L, stack);
stack = new GenLayerAddIsland(1L, stack);
stack = new GenLayerZoom(2001L, stack);
stack = new GenLayerAddIsland(2L, stack);
stack = new GenLayerAddIsland(50L, stack);
stack = new GenLayerAddIsland(70L, stack);
stack = new GenLayerRemoveTooMuchOcean(2L, stack);
System.out.println("Setting up landmass "+scheme.name());
GenLayer stack;
switch(scheme)
{
case CONTINENTS:
stack = new GenLayerIslandBOP(1L, 4);
stack = new GenLayerFuzzyZoom(2000L, stack);
stack = new GenLayerZoom(2001L, stack);
stack = new GenLayerIslandBOP(3L, 20, stack);
break;
case ARCHIPELAGO:
stack = new GenLayerAllSame(1L, 0);
stack = new GenLayerRemoveTooMuchOcean(2L, stack);
break;
case VANILLA: default:
stack = new GenLayerIsland(1L);
stack = new GenLayerFuzzyZoom(2000L, stack);
stack = new GenLayerRaggedEdges(1L, stack);
stack = new GenLayerZoom(2001L, stack);
stack = new GenLayerRaggedEdges(2L, stack);
stack = new GenLayerRaggedEdges(50L, stack);
stack = new GenLayerRaggedEdges(70L, stack);
stack = new GenLayerRemoveTooMuchOcean(2L, stack);
break;
}
return stack;
}
// superimpose hot and cold regions an a land and sea layer
public static GenLayer addHotAndColdRegions(GenLayer landAndSea, TemperatureVariationScheme scheme, long worldSeed)
public static GenLayer addHotAndColdRegions(GenLayer landAndSea, TemperatureVariationScheme tempScheme, long worldSeed)
{
GenLayer stack;
switch (scheme)
switch (tempScheme)
{
// The 'random' scheme places small hot and cold regions all over the map completely at random
// this results in biomes scattered randomly like in Minecraft before v1.7
case RANDOM:
stack = new GenLayerAddIsland(3L, landAndSea);
stack = new GenLayerRaggedEdges(3L, landAndSea);
stack = new GenLayerZoom(2002L, stack);
stack = new GenLayerZoom(2002L, stack);
stack = new GenLayerHeatRandom(2L, stack);
@ -92,7 +115,7 @@ public class WorldChunkManagerBOP extends WorldChunkManager
// the result is bands of temperature in the East-West direction
// travelling North/South you find different temperatures, travelling East/West you find different biomes of a similar temperature
case LATITUDE:
stack = new GenLayerAddIsland(3L, landAndSea);
stack = new GenLayerRaggedEdges(3L, landAndSea);
stack = new GenLayerZoom(2002L, stack);
stack = new GenLayerHeatLatitude(2L, stack, 10, worldSeed);
stack = new GenLayerEdge(3L, stack, GenLayerEdge.Mode.SPECIAL);
@ -116,16 +139,46 @@ public class WorldChunkManagerBOP extends WorldChunkManager
return stack;
}
// generate the regions of land and sea
public static GenLayer secondaryLandMasses(GenLayer hotAndCold, LandMassScheme scheme)
{
GenLayer stack = hotAndCold;
switch(scheme)
{
case CONTINENTS:
stack = new GenLayerRaggedEdges(4L, stack);
stack = new GenLayerAddMushroomIsland(5L, stack);
stack = new GenLayerDeepOcean(4L, stack);
break;
case ARCHIPELAGO:
stack = new GenLayerArchipelago(1L, 2, stack);
stack = new GenLayerAddMushroomIsland(5L, stack);
stack = new GenLayerDeepOcean(4L, stack);
break;
case VANILLA: default:
stack = new GenLayerRaggedEdges(4L, hotAndCold);
stack = new GenLayerAddMushroomIsland(5L, stack);
stack = new GenLayerDeepOcean(4L, stack);
break;
}
return stack;
}
public static GenLayer allocateBiomes(long worldSeed, WorldTypeBOP worldType, BOPWorldSettings settings, GenLayer hotAndCold, GenLayer riversAndSubBiomesInit)
{
// allocate the basic biomes
GenLayer stack = new GenLayerBiomeBOP(200L, hotAndCold, worldType);
GenLayer stack = new GenLayerBiomeBOP(200L, hotAndCold, worldType, settings);
stack = GenLayerZoom.magnify(1000L, stack, 2);
stack = new GenLayerBiomeEdgeBOP(1000L, stack);
// use the hillsInit layer to change some biomes to sub-biomes like hills or rare mutated variants
GenLayer subBiomesInit = GenLayerZoom.magnify(1000L, riversAndSubBiomesInit, 2);
stack = new GenLayerSubBiomesBOP(1000L, stack, subBiomesInit);
stack = new GenLayerSubBiomesBOP(1000L, stack, subBiomesInit, settings);
return stack;
}
@ -137,15 +190,13 @@ public class WorldChunkManagerBOP extends WorldChunkManager
int riverSize = 4;
// first few layers just create areas of land and sea, continents and islands
GenLayer mainBranch = initialLandAndSeaLayer();
GenLayer mainBranch = initialLandAndSeaLayer(settings.landScheme);
// now add hot and cold regions (and two zooms)
mainBranch = addHotAndColdRegions(mainBranch, settings.tempScheme, worldSeed);
// add mushroom islands and deep oceans
mainBranch = new GenLayerAddIsland(4L, mainBranch);
mainBranch = new GenLayerAddMushroomIsland(5L, mainBranch);
mainBranch = new GenLayerDeepOcean(4L, mainBranch);
// add mushroom islands and deep oceans and other land masses
mainBranch = secondaryLandMasses(mainBranch, settings.landScheme);
// fork off a new branch as a seed for rivers and sub biomes
GenLayer riversAndSubBiomesInit = new GenLayerRiverInit(100L, mainBranch);
@ -158,7 +209,7 @@ public class WorldChunkManagerBOP extends WorldChunkManager
for (int i = 0; i < biomeSize; ++i)
{
mainBranch = new GenLayerZoom((long)(1000 + i), mainBranch);
if (i == 0) {mainBranch = new GenLayerAddIsland(3L, mainBranch);}
if (i == 0) {mainBranch = new GenLayerRaggedEdges(3L, mainBranch);}
if (i == 1 || biomeSize == 1) {mainBranch = new GenLayerShore(1000L, mainBranch);}
}
mainBranch = new GenLayerSmooth(1000L, mainBranch);

View file

@ -0,0 +1,37 @@
/*******************************************************************************
* Copyright 2015, the Biomes O' Plenty Team
*
* This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International Public License.
*
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/4.0/.
******************************************************************************/
package biomesoplenty.common.world.layer;
import net.minecraft.world.gen.layer.GenLayer;
import net.minecraft.world.gen.layer.IntCache;
public class GenLayerAllSame extends GenLayer
{
private final int val;
public GenLayerAllSame(long seed, int val)
{
super(seed);
this.val = val;
}
@Override
public int[] getInts(int areaX, int areaY, int areaWidth, int areaHeight)
{
int[] out = IntCache.getIntCache(areaWidth * areaHeight);
for (int y = 0; y < areaHeight; ++y)
{
for (int x = 0; x < areaWidth; ++x)
{
this.initChunkSeed((long)(areaX + x), (long)(areaY + y));
out[x + y * areaWidth] = this.val;
}
}
return out;
}
}

View file

@ -0,0 +1,43 @@
/*******************************************************************************
* Copyright 2015, the Biomes O' Plenty Team
*
* This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International Public License.
*
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/4.0/.
******************************************************************************/
package biomesoplenty.common.world.layer;
import net.minecraft.world.gen.layer.GenLayer;
import net.minecraft.world.gen.layer.IntCache;
public class GenLayerArchipelago extends GenLayer
{
private final int seaChance;
public GenLayerArchipelago(long seed, int islandChance, GenLayer parent)
{
super(seed);
this.seaChance = islandChance;
this.parent = parent;
}
@Override
public int[] getInts(int areaX, int areaY, int areaWidth, int areaHeight)
{
int[] out = IntCache.getIntCache(areaWidth * areaHeight);
int[] parentVals = this.parent.getInts(areaX, areaY, areaWidth, areaHeight);
// randomly set land areas
for (int y = 0; y < areaHeight; ++y)
{
for (int x = 0; x < areaWidth; ++x)
{
this.initChunkSeed((long)(areaX + x), (long)(areaY + y));
out[x + y * areaWidth] = this.nextInt(this.seaChance) == 0 ? 0 : parentVals[x + y * areaWidth];
}
}
return out;
}
}

View file

@ -33,16 +33,19 @@ import biomesoplenty.common.biome.BOPBiomeManager;
import biomesoplenty.common.util.biome.BiomeUtils;
import biomesoplenty.common.util.config.BOPConfig.ConfigFileObj;
import biomesoplenty.common.util.config.BOPConfig.IConfigObj;
import biomesoplenty.common.world.BOPWorldSettings;
import biomesoplenty.common.world.WorldTypeBOP;
import biomesoplenty.core.BiomesOPlenty;
public class GenLayerBiomeBOP extends GenLayerBiome
{
private List<BiomeEntry>[] biomes;
private BOPWorldSettings settings;
public GenLayerBiomeBOP(long seed, GenLayer parentLayer, WorldTypeBOP worldType)
public GenLayerBiomeBOP(long seed, GenLayer parentLayer, WorldTypeBOP worldType, BOPWorldSettings settings)
{
super(seed, parentLayer, worldType, "");
this.settings = settings;
// get the vanilla biomes (and their hard-coded default weights) from the vanilla GenLayerBiome class private field 'biomes'
biomes = ReflectionHelper.getPrivateValue(GenLayerBiome.class, this, "biomes");

View file

@ -0,0 +1,70 @@
/*******************************************************************************
* Copyright 2015, the Biomes O' Plenty Team
*
* This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International Public License.
*
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/4.0/.
******************************************************************************/
package biomesoplenty.common.world.layer;
import net.minecraft.world.gen.layer.GenLayer;
import net.minecraft.world.gen.layer.IntCache;
public class GenLayerIslandBOP extends GenLayer
{
private final int islandChance;
public GenLayerIslandBOP(long seed, int islandChance)
{
this(seed, islandChance, null);
}
public GenLayerIslandBOP(long seed, int islandChance, GenLayer parent)
{
super(seed);
this.islandChance = islandChance;
this.parent = parent;
}
@Override
public int[] getInts(int areaX, int areaY, int areaWidth, int areaHeight)
{
int[] out = IntCache.getIntCache(areaWidth * areaHeight);
if (this.parent == null)
{
// randomly set land areas
for (int y = 0; y < areaHeight; ++y)
{
for (int x = 0; x < areaWidth; ++x)
{
this.initChunkSeed((long)(areaX + x), (long)(areaY + y));
out[x + y * areaWidth] = this.nextInt(this.islandChance) == 0 ? 1 : 0;
}
}
// set the origin as land, always
if (areaX > -areaWidth && areaX <= 0 && areaY > -areaHeight && areaY <= 0)
{
out[-areaX + -areaY * areaWidth] = 1;
}
}
else
{
int[] parentVals = this.parent.getInts(areaX, areaY, areaWidth, areaHeight);
// randomly set land areas
for (int y = 0; y < areaHeight; ++y)
{
for (int x = 0; x < areaWidth; ++x)
{
this.initChunkSeed((long)(areaX + x), (long)(areaY + y));
out[x + y * areaWidth] = ((parentVals[x + y * areaWidth] == 0) ? ((this.nextInt(this.islandChance) == 0) ? 1 : 0) : parentVals[x + y * areaWidth]);
}
}
}
return out;
}
}

View file

@ -0,0 +1,79 @@
/*******************************************************************************
* Copyright 2015, the Biomes O' Plenty Team
*
* This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International Public License.
*
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/4.0/.
******************************************************************************/
package biomesoplenty.common.world.layer;
import net.minecraft.world.gen.layer.GenLayer;
import net.minecraft.world.gen.layer.IntCache;
public class GenLayerRaggedEdges extends GenLayer
{
public GenLayerRaggedEdges(long seed, GenLayer parent)
{
super(seed);
this.parent = parent;
}
@Override
public int[] getInts(int areaX, int areaY, int areaWidth, int areaHeight)
{
int outerWidth = areaWidth + 2;
int outerHeight = areaHeight + 2;
int[] parentVals = this.parent.getInts(areaX - 1, areaY - 1, outerWidth, outerHeight);
int[] out = IntCache.getIntCache(areaWidth * areaHeight);
for (int y = 0; y < areaHeight; ++y)
{
for (int x = 0; x < areaWidth; ++x)
{
int northWestVal = parentVals[x + 0 + (y + 0) * outerWidth];
int northEastVal = parentVals[x + 2 + (y + 0) * outerWidth];
int southWestVal = parentVals[x + 0 + (y + 2) * outerWidth];
int southEastVal = parentVals[x + 2 + (y + 2) * outerWidth];
int centerVal = parentVals[x + 1 + (y + 1) * outerWidth];
this.initChunkSeed((long)(x + areaX), (long)(y + areaY));
if (centerVal == 0 && (northWestVal != 0 || northEastVal != 0 || southWestVal != 0 || southEastVal != 0))
{
// center is an ocean touching land on at least one corner
// with a one in 3 chance, turn the ocean into a random one of the corners
if (this.nextInt(3) == 0)
{
int counter = 1;
int replacement = 1;
if (northWestVal != 0 && this.nextInt(counter++) == 0) {replacement = northWestVal;}
if (northEastVal != 0 && this.nextInt(counter++) == 0) {replacement = northEastVal;}
if (southWestVal != 0 && this.nextInt(counter++) == 0) {replacement = southWestVal;}
if (southEastVal != 0 && this.nextInt(counter++) == 0) {replacement = southEastVal;}
out[x + y * areaWidth] = replacement;
}
else
{
out[x + y * areaWidth] = 0;
}
}
else if (centerVal > 0 && (northWestVal == 0 || northEastVal == 0 || southWestVal == 0 || southEastVal == 0))
{
// center is a land square, with ocean on at least one corner
// with a one in 5 chance, turn the center into ocean
out[x + y * areaWidth] = (this.nextInt(5) == 0) ? 0 : centerVal;
}
else
{
// otherwise, leave it alone
out[x + y * areaWidth] = centerVal;
}
}
}
return out;
}
}

View file

@ -11,18 +11,22 @@ package biomesoplenty.common.world.layer;
import java.util.List;
import biomesoplenty.common.init.ModBiomes;
import biomesoplenty.common.world.BOPWorldSettings;
import net.minecraft.world.biome.BiomeGenBase;
import net.minecraft.world.gen.layer.GenLayer;
import net.minecraft.world.gen.layer.IntCache;
public class GenLayerSubBiomesBOP extends GenLayer
{
private GenLayer subBiomesInit;
private BOPWorldSettings settings;
public GenLayerSubBiomesBOP(long seed, GenLayer biomesLayer, GenLayer subBiomesInit)
public GenLayerSubBiomesBOP(long seed, GenLayer biomesLayer, GenLayer subBiomesInit, BOPWorldSettings settings)
{
super(seed);
this.parent = biomesLayer;
this.subBiomesInit = subBiomesInit;
this.settings = settings;
}
@Override
@ -122,6 +126,12 @@ public class GenLayerSubBiomesBOP extends GenLayer
// For many biomes, this is the 'hills' version
public int getCommonSubBiome(int biomeId)
{
// prevent too many islands when using CONTINENTS
// TODO: this is a horrible hacky special case - would prefer a more elegant system
if (this.settings.landScheme == BOPWorldSettings.LandMassScheme.CONTINENTS && biomeId == BiomeGenBase.deepOcean.biomeID && this.nextInt(4)!=0)
{
return biomeId;
}
List<Integer> subBiomeIds = ModBiomes.subBiomesMap.get(biomeId);
if (subBiomeIds == null) {return biomeId;}