Reworked biome generation and used DFS for continuity.

Also made changes to structure to better support Bukkit's structure.
This commit is contained in:
Harrison Deng 2020-04-21 02:59:19 -05:00
parent 4fc824f94f
commit 67a93fff5b
11 changed files with 120 additions and 178 deletions

View File

@ -1,9 +1,9 @@
package ca.recrown.islandsurvivalcraft;
import org.bukkit.World;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.plugin.java.JavaPlugin;
import ca.recrown.islandsurvivalcraft.worldgeneration.BiomePerIslandGenerator;
import ca.recrown.islandsurvivalcraft.worldgeneration.IslandSurvivalCraftWorldGenerator;
public class IslandSurvivalCraft extends JavaPlugin {
@ -11,6 +11,8 @@ public class IslandSurvivalCraft extends JavaPlugin {
@Override
public void onEnable() {
generator = new IslandSurvivalCraftWorldGenerator(new BiomePerIslandGenerator());
generator.initialize();
super.onEnable();
}
@ -21,10 +23,6 @@ public class IslandSurvivalCraft extends JavaPlugin {
@Override
public ChunkGenerator getDefaultWorldGenerator(String worldName, String id) {
if (generator == null) {
World world = getServer().getWorld(worldName);
generator = new IslandSurvivalCraftWorldGenerator(this, world, true);
}
return generator;
}
}

View File

@ -82,7 +82,7 @@ public class DepthFirstSearch {
* @param targetValidator
* @return
*/
public boolean findEndNode(CoordinateTargetValidatable targetValidator) {
public boolean findTarget(CoordinateTargetValidatable targetValidator) {
queue = new LinkedList<>();
checkedNodes.clear();
Node begin = startNode;

View File

@ -5,10 +5,14 @@ import java.util.Random;
import org.bukkit.util.noise.SimplexOctaveGenerator;
public class BedrockGenerator {
private Random random;
private SimplexOctaveGenerator noiseGenerator;
private final int maxBedrockHeight = 5;
private final int minBedrockHeight = 1;
public BedrockGenerator(Random random) {
public void setRandom(Random random) {
if (random.equals(this.random)) return;
this.random = random;
noiseGenerator = new SimplexOctaveGenerator(random, 8);
noiseGenerator.setScale(0.1D);
}

View File

@ -1,157 +1,85 @@
package ca.recrown.islandsurvivalcraft.worldgeneration;
import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.generator.ChunkGenerator.BiomeGrid;
import ca.recrown.islandsurvivalcraft.islandbedrockmetadata.IslandMetadataType;
import ca.recrown.islandsurvivalcraft.islandbedrockmetadata.IslandOwnerMetadata;
import ca.recrown.islandsurvivalcraft.islandbedrockmetadata.IslandShoreBiomeMetadata;
import ca.recrown.islandsurvivalcraft.islandbedrockmetadata.IslandTUIDMetadata;
import ca.recrown.islandsurvivalcraft.islandbedrockmetadata.IslandTemperatureMetadata;
import ca.recrown.islandsurvivalcraft.pathfinding.CoordinateTargetValidatable;
import ca.recrown.islandsurvivalcraft.IslandSurvivalCraft;
import ca.recrown.islandsurvivalcraft.islandbedrockmetadata.IslandBedrockMetadataHelper;
import ca.recrown.islandsurvivalcraft.islandbedrockmetadata.IslandMainBiomeMetadata;
import ca.recrown.islandsurvivalcraft.islandbedrockmetadata.IslandMetadataPack;
import ca.recrown.islandsurvivalcraft.pathfinding.DepthFirstSearch;
public class BiomePerIslandGenerator implements IslandBiomeGenerator, CoordinateTargetValidatable {
private IslandMapGenerator mapGenerator;
private Biome currentIslandBiome;
private float currentIslandTemperature;
private Biome currentIslandShoreBiome;
private IslandMapGenerator islandMapGenerator;
private BiomeSelector biomeSelector;
private int worldHeight;
private World world;
private IslandBedrockMetadataHelper metadataHelper;
private TemperatureMapGenerator temperatureMapGenerator;
private String currentTUID;
private IslandSurvivalCraft plugin;
private int buildHeight;
private World world;
private DepthFirstSearch dfs;
private Biome mainBiome;
private Biome shoreBiome;
private float temperature;
public BiomePerIslandGenerator(IslandSurvivalCraft plugin, World world, IslandMapGenerator mapGenerator, BiomeSelector biomeSelector, TemperatureMapGenerator temperatureMapGenerator) {
this.plugin = plugin;
this.temperatureMapGenerator = temperatureMapGenerator;
this.worldHeight = world.getMaxHeight();
this.mapGenerator = mapGenerator;
public BiomePerIslandGenerator() {
this.temperatureMapGenerator = new TemperatureMapGenerator();
dfs = new DepthFirstSearch(islandMapGenerator);
}
@Override
public void initialize(IslandMapGenerator mapGenerator, BiomeSelector biomeSelector) {
this.islandMapGenerator = mapGenerator;
this.biomeSelector = biomeSelector;
}
@Override
public void setWorld(World world) {
if (world.equals(this.world)) return;
this.world = world;
this.metadataHelper = new IslandBedrockMetadataHelper(plugin, world);
}
public void GenerateBiome(int chunkX, int chunkZ, int localX, int localZ, BiomeGrid biome) {
int worldX = chunkX * 16 + localX;
int worldZ = chunkZ * 16 + localZ;
if (mapGenerator.isIsland(worldX, worldZ)) {
IslandMetadataPack sameIslandPack = getSurroundingIslandData(worldX, worldZ);
if (sameIslandPack != null) {
//Old island
currentIslandBiome = sameIslandPack.mainBiomeMetadata.getMainBiome();
currentIslandShoreBiome = sameIslandPack.shoreBiomeMetadata.getShoreBiome();
currentIslandTemperature = sameIslandPack.temperatureMetadata.getTemperature();
currentTUID = sameIslandPack.islandTIUDMetadata.getIUID();
} else {
//New island
currentIslandTemperature = temperatureMapGenerator.getTemperature(worldX, worldZ);
currentIslandBiome = biomeSelector.getLandBiome(currentIslandTemperature);
currentIslandShoreBiome = biomeSelector.getShoreBiome(currentIslandBiome, currentIslandTemperature);
if (currentIslandShoreBiome == null) {
currentIslandShoreBiome = currentIslandBiome;
}
currentTUID = String.valueOf(worldX) + String.valueOf(worldZ);
}
//saving information
IslandMetadataPack current = new IslandMetadataPack();
current.setMainBiome(currentIslandBiome, plugin);
current.setTemperature(currentIslandTemperature, plugin);
current.setShoreBiome(currentIslandShoreBiome, plugin);
current.setTUID(currentTUID, plugin);
metadataHelper.setIslandBedrockMetadataPack(worldX, worldZ, current);
//Set the biome information for the chunk
if (mapGenerator.isShore(worldX, worldZ)) {
setBiome(localX, localZ, biome, currentIslandShoreBiome);
} else {
setBiome(localX, localZ, biome, currentIslandBiome);
}
//Check if island besides this one need to be generated.
if (localX == 0 && mapGenerator.isSameIsland(worldX, worldZ, worldX - 1, worldZ)) {
if (!world.isChunkGenerated(chunkX - 1, chunkZ)) {
Chunk chunk = world.getChunkAt(chunkX - 1, chunkZ);
chunk.load(true);
chunk.unload(true);
}
} else if (localX == 15 && mapGenerator.isSameIsland(worldX, worldZ, worldX + 1, worldZ)) {
if (!world.isChunkGenerated(chunkX + 1, chunkZ)) {
Chunk chunk = world.getChunkAt(chunkX + 1, chunkZ);
chunk.load(true);
chunk.unload(true);
}
}
if (localZ == 0 && mapGenerator.isSameIsland(worldX, worldZ, worldX, worldZ - 1)) {
if (!world.isChunkGenerated(chunkX, chunkZ - 1)) {
Chunk chunk = world.getChunkAt(chunkX, chunkZ - 1);
chunk.load(true);
chunk.unload(true);
}
} else if (localZ == 15 && mapGenerator.isSameIsland(worldX, worldZ, worldX, worldZ + 1)) {
if (!world.isChunkGenerated(chunkX, chunkZ + 1)) {
Chunk chunk = world.getChunkAt(chunkX, chunkZ + 1);
chunk.load(true);
chunk.unload(true);
}
}
}
}
private IslandMetadataPack getSurroundingIslandData(int worldX, int worldZ) {
IslandMetadataPack data = null;
if (mapGenerator.isSameIsland(worldX, worldZ, worldX + 1, worldZ)) {
data = getMetadataPackAt(worldX + 1, worldZ, world);
} else if (mapGenerator.isSameIsland(worldX, worldZ, worldX - 1, worldZ)) {
data = getMetadataPackAt(worldX - 1, worldZ, world);
} else if (mapGenerator.isSameIsland(worldX, worldZ, worldX, worldZ + 1)) {
data = getMetadataPackAt(worldX, worldZ + 1, world);
} else if (mapGenerator.isSameIsland(worldX, worldZ, worldX, worldZ - 1)) {
data = getMetadataPackAt(worldX, worldZ - 1, world);
}
return data;
}
private IslandMetadataPack getMetadataPackAt(int worldX, int worldZ, World world) {
IslandMetadataPack data = new IslandMetadataPack();
data.mainBiomeMetadata = (IslandMainBiomeMetadata) metadataHelper.getIslandBedrockMetadata(worldX, worldZ,
IslandMetadataType.mainBiome);
data.shoreBiomeMetadata = (IslandShoreBiomeMetadata) metadataHelper.getIslandBedrockMetadata(worldX, worldZ,
IslandMetadataType.shoreBiome);
data.temperatureMetadata = (IslandTemperatureMetadata) metadataHelper.getIslandBedrockMetadata(worldX, worldZ,
IslandMetadataType.temperature);
data.ownerMetadata = (IslandOwnerMetadata) metadataHelper.getIslandBedrockMetadata(worldX, worldZ,
IslandMetadataType.ownerUUID);
data.islandTIUDMetadata = (IslandTUIDMetadata) metadataHelper.getIslandBedrockMetadata(worldX, worldZ,
IslandMetadataType.TIUD);
return data;
}
private void setBiome(int localX, int localZ, BiomeGrid biomeGrid, Biome biome) {
for (int y = 0; y < worldHeight; y++) {
biomeGrid.setBiome(localX, y, localZ, biome);
}
this.temperatureMapGenerator.setSeed(world.getSeed());
this.buildHeight = world.getMaxHeight();
}
@Override
public boolean isCoordinateTarget(int x, int y) {
if (world.isChunkGenerated(x/16, y/16)) {
Biome foundBiome = world.getBiome(x, 0, y);
if (islandMapGenerator.isShore(x, y)) {
shoreBiome = foundBiome;
} else {
mainBiome = foundBiome;
}
if (mainBiome != null && shoreBiome != null) {
return true;
}
}
return false;
}
@Override
public void GenerateBiome(int chunkX, int chunkZ, int localX, int localZ, BiomeGrid biome) {
int worldX = chunkX * 16 + localX;
int worldZ = chunkZ * 16 + localZ;
if (islandMapGenerator.isIsland(worldX, worldZ)) {
if (mainBiome == null && shoreBiome == null) {
if (!dfs.findTarget(this)) {
temperature = temperatureMapGenerator.getTemperature(worldX, worldZ);
mainBiome = biomeSelector.getLandBiome(temperature);
shoreBiome = biomeSelector.getShoreBiome(mainBiome, temperature);
}
}
} else {
mainBiome = null;
shoreBiome = null;
}
for (int y = 0; y < buildHeight; y++) {
Biome designatedBiome = mainBiome;
if (mainBiome == null) {
designatedBiome = Biome.OCEAN;
} else if (islandMapGenerator.isShore(worldX, worldZ)) {
designatedBiome = shoreBiome;
}
biome.setBiome(localX, y, localZ, designatedBiome);
}
}
}

View File

@ -11,7 +11,7 @@ import ca.recrown.islandsurvivalcraft.Utilities;
public class BiomeSelector {
private boolean initialized = false;
private final Random random;
private Random random;
private final HashMap<Biome, Float> lands;
private HashMap<Float, ArrayList<Biome>> temperaturesForLand;
private final HashMap<Float, ArrayList<Biome>> temperaturePartitionedLandBiomes;
@ -20,9 +20,7 @@ public class BiomeSelector {
private final HashMap<Float, ArrayList<Biome>> temperaturePartitionedOceanBiomes;
public BiomeSelector(Random random) {
this.random = random;
public BiomeSelector() {
lands = new HashMap<>();
oceans = new HashMap<>();
temperaturePartitionedLandBiomes = new HashMap<>();
@ -35,6 +33,10 @@ public class BiomeSelector {
temperaturePartitionedOceanBiomes.put(0.5f, new ArrayList<>());
}
public void setRandom(Random random) {
this.random = random;
}
public void initialize() {
if (initialized) throw new IllegalStateException("Biome selector is already initialized.");

View File

@ -1,8 +1,10 @@
package ca.recrown.islandsurvivalcraft.worldgeneration;
import org.bukkit.World;
import org.bukkit.generator.ChunkGenerator.BiomeGrid;
public interface IslandBiomeGenerator {
public void initialize(IslandMapGenerator mapGenerator, BiomeSelector biome);
public void setWorld(World world);
public void GenerateBiome(int chunkX, int chunkZ, int localX, int localZ, BiomeGrid biome);
}

View File

@ -8,6 +8,7 @@ import ca.recrown.islandsurvivalcraft.pathfinding.CoordinateValidatable;
import ca.recrown.islandsurvivalcraft.pathfinding.DepthFirstSearch;
public class IslandMapGenerator implements CoordinateValidatable {
private Random random;
private SimplexOctaveGenerator noiseGenerator;
private final int noiseOctaves = 8;
private final int islandGenerationPercent = 47;
@ -17,16 +18,23 @@ public class IslandMapGenerator implements CoordinateValidatable {
private final float shoreFactor = 0.065f;
private final int maxHeightAboveSea = 8;
private final int lowestSeaFloor = 16;
private final int seaLevel;
private final int shallowDepth;
private int seaLevel;
private int shallowDepth;
private final DepthFirstSearch dfs;
public IslandMapGenerator(Random random, int seaLevel, int shallowDepth) {
public IslandMapGenerator() {
dfs = new DepthFirstSearch(this);
}
this.noiseGenerator = new SimplexOctaveGenerator(random, noiseOctaves);
public void updateParameters(Random random, int seaLevel, int shallowDepth) {
this.seaLevel = seaLevel;
this.shallowDepth = shallowDepth;
if (!random.equals(this.random)) {
this.random = random;
this.noiseGenerator = new SimplexOctaveGenerator(random, noiseOctaves);
}
this.seaLevel = seaLevel;
this.shallowDepth = shallowDepth;
dfs = new DepthFirstSearch(this);
}
/**
@ -59,7 +67,7 @@ public class IslandMapGenerator implements CoordinateValidatable {
/**
* These coordinates are considered to be the shore if:
* It is a part of an island,
* within a square radius of shoreSize, there is an edge of the island.
* the island value is less than the shore factor.
* @param worldX the X coordinate of location in world.
* @param worldZ the Z coordinate of location in world.
* @return

View File

@ -2,37 +2,35 @@ package ca.recrown.islandsurvivalcraft.worldgeneration;
import java.util.Random;
import org.apache.commons.lang.NotImplementedException;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.generator.ChunkGenerator;
import ca.recrown.islandsurvivalcraft.IslandSurvivalCraft;
public class IslandSurvivalCraftWorldGenerator extends ChunkGenerator {
private final BedrockGenerator bedrockGenerator;
private final BiomeSelector biomeSelector;
private final IslandBiomeGenerator biomeGenerator;
private final IslandMapGenerator islandMapGenerator;
private final TemperatureMapGenerator temperatureMapGenerator;
private final BedrockGenerator bedrockGenerator;
private final Random random;
public IslandSurvivalCraftWorldGenerator(IslandSurvivalCraft plugin, World world, boolean biomePerIsland) {
random = new Random(world.getSeed());
this.biomeSelector = new BiomeSelector(random);
this.bedrockGenerator = new BedrockGenerator(random);
this.islandMapGenerator = new IslandMapGenerator(random, world.getSeaLevel(), 3);
this.temperatureMapGenerator = new TemperatureMapGenerator(world.getSeed());
if (biomePerIsland) {
this.biomeGenerator = new BiomePerIslandGenerator(plugin, world, islandMapGenerator, biomeSelector, temperatureMapGenerator);
} else {
throw new NotImplementedException();
}
public IslandSurvivalCraftWorldGenerator(IslandBiomeGenerator generator) {
this.biomeSelector = new BiomeSelector();
this.bedrockGenerator = new BedrockGenerator();
this.islandMapGenerator = new IslandMapGenerator();
this.biomeGenerator = generator;
}
public void initialize() {
biomeSelector.initialize();
biomeGenerator.initialize(islandMapGenerator, biomeSelector);
}
@Override
public ChunkData generateChunkData(World world, Random random, int x, int z, BiomeGrid biome) {
bedrockGenerator.setRandom(random);
biomeSelector.setRandom(random);
biomeGenerator.setWorld(world);
islandMapGenerator.updateParameters(random, world.getSeaLevel(), 4);
ChunkData chunk = createChunkData(world);
for (int localX = 0; localX < 16; localX++) {
for (int localZ = 0; localZ < 16; localZ++) {

View File

@ -9,7 +9,8 @@ class TemperatureMapGenerator {
private final double amplitude = 0.22D;
private SimplexOctaveGenerator noiseGenerator;
public TemperatureMapGenerator(long seed) {
public void setSeed(long seed) {
noiseGenerator = new SimplexOctaveGenerator(new Random(seed), 4);
noiseGenerator.setScale(0.0008D);
}

View File

@ -131,7 +131,7 @@ public class DepthFirstSearchTest {
dfs.setValidatable(validator);
dfs.setStartPosition(3, 0);
assertTrue(dfs.findEndNode(validator));
assertTrue(dfs.findTarget(validator));
assertEquals(1, dfs.getEndX());
assertEquals(2, dfs.getEndY());
}
@ -142,7 +142,7 @@ public class DepthFirstSearchTest {
dfs.setValidatable(validator);
dfs.setStartPosition(0, 0);
assertTrue(dfs.findEndNode(validator));
assertTrue(dfs.findTarget(validator));
assertEquals(0, dfs.getEndX());
assertEquals(3, dfs.getEndY());
}
@ -153,6 +153,6 @@ public class DepthFirstSearchTest {
dfs.setValidatable(validator);
dfs.setStartPosition(0, 0);
assertFalse(dfs.findEndNode(validator));
assertFalse(dfs.findTarget(validator));
}
}

View File

@ -18,7 +18,8 @@ public class BiomeSelectorTest {
@BeforeAll
public void setUp() {
biomeSelector = new BiomeSelector(new Random());
biomeSelector = new BiomeSelector();
biomeSelector.setRandom(new Random());
biomeSelector.initialize();
}