Finished untested biome generator.

Also:
Changed plugin structure to adapt better to server API
Refactored by reorganizing packages.
This commit is contained in:
Harrison Deng 2020-04-21 16:40:29 -05:00
parent 35e52ae61b
commit 533a758799
14 changed files with 200 additions and 123 deletions

View File

@ -3,16 +3,16 @@ package ca.recrown.islandsurvivalcraft;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.plugin.java.JavaPlugin;
import ca.recrown.islandsurvivalcraft.worldgeneration.BiomePerIslandGenerator;
import ca.recrown.islandsurvivalcraft.worldgeneration.IslandSurvivalCraftWorldGenerator;
import ca.recrown.islandsurvivalcraft.world.IslandSurvivalCraftChunkGenerator;
import ca.recrown.islandsurvivalcraft.world.IslandWorldGenerator;
import ca.recrown.islandsurvivalcraft.world.generation.BiomePerIslandGenerator;
public class IslandSurvivalCraft extends JavaPlugin {
IslandSurvivalCraftWorldGenerator generator;
IslandSurvivalCraftChunkGenerator generator;
@Override
public void onEnable() {
generator = new IslandSurvivalCraftWorldGenerator(new BiomePerIslandGenerator());
generator.initialize();
generator = new IslandSurvivalCraftChunkGenerator(new BiomePerIslandGenerator());
super.onEnable();
}

View File

@ -1,4 +1,4 @@
package ca.recrown.islandsurvivalcraft.worldgeneration;
package ca.recrown.islandsurvivalcraft.world;
import java.util.ArrayList;
import java.util.HashMap;
@ -11,32 +11,27 @@ import ca.recrown.islandsurvivalcraft.Utilities;
public class BiomeSelector {
private boolean initialized = false;
private Random random;
private final HashMap<Biome, Float> lands;
private HashMap<Float, ArrayList<Biome>> temperaturesForLand;
private final HashMap<Float, ArrayList<Biome>> temperaturePartitionedLandBiomes;
private final HashMap<Biome, Float> oceans;
private HashMap<Float, ArrayList<Biome>> temperaturesForOcean;
private final HashMap<Float, ArrayList<Biome>> temperaturePartitionedOceanBiomes;
private final Random random;
private final HashMap<Biome, Float> lands = new HashMap<>();
private HashMap<Float, ArrayList<Biome>> temperaturesForLand = new HashMap<>();
private final HashMap<Float, ArrayList<Biome>> temperaturePartitionedLandBiomes = new HashMap<>();
private final HashMap<Biome, Float> oceans = new HashMap<>();
private HashMap<Float, ArrayList<Biome>> temperaturesForOcean = new HashMap<>();
private final HashMap<Float, ArrayList<Biome>> temperaturePartitionedOceanBiomes = new HashMap<>();
public BiomeSelector() {
lands = new HashMap<>();
oceans = new HashMap<>();
temperaturePartitionedLandBiomes = new HashMap<>();
public BiomeSelector(Random random) {
this.random = random;
temperaturePartitionedLandBiomes.put(0.05f, new ArrayList<>());
temperaturePartitionedLandBiomes.put(0.30f, new ArrayList<>());
temperaturePartitionedLandBiomes.put(0.95f, new ArrayList<>());
temperaturePartitionedLandBiomes.put(2f, new ArrayList<>());
temperaturePartitionedOceanBiomes = new HashMap<>();
temperaturePartitionedOceanBiomes.put(0.00f, new ArrayList<>());
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,4 +1,4 @@
package ca.recrown.islandsurvivalcraft.worldgeneration;
package ca.recrown.islandsurvivalcraft.world;
import java.util.Random;
@ -7,8 +7,7 @@ import org.bukkit.util.noise.SimplexOctaveGenerator;
import ca.recrown.islandsurvivalcraft.pathfinding.CoordinateValidatable;
import ca.recrown.islandsurvivalcraft.pathfinding.DepthFirstSearch;
public class IslandLocationGenerator implements CoordinateValidatable {
private Random random;
public class IslandLocationMapper implements CoordinateValidatable {
private SimplexOctaveGenerator noiseGenerator;
private final int noiseOctaves = 8;
private final int islandGenerationPercent = 47;
@ -22,21 +21,15 @@ public class IslandLocationGenerator implements CoordinateValidatable {
private int shallowDepth;
private final DepthFirstSearch dfs;
public IslandLocationGenerator() {
public IslandLocationMapper(Random random, int seaLevel, int shallowDepth) {
dfs = new DepthFirstSearch(this);
this.seaLevel = seaLevel;
this.shallowDepth = shallowDepth;
this.noiseGenerator = new SimplexOctaveGenerator(random, noiseOctaves);
this.seaLevel = seaLevel;
this.shallowDepth = shallowDepth;
}
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;
}
/**
* Considers this land if it is greater than sea level.
* @param worldX the X coordinate of location in world.

View File

@ -0,0 +1,29 @@
package ca.recrown.islandsurvivalcraft.world;
import java.util.Random;
import org.bukkit.World;
import org.bukkit.generator.ChunkGenerator;
import ca.recrown.islandsurvivalcraft.world.generation.IslandBiomeGenerator;
public class IslandSurvivalCraftChunkGenerator extends ChunkGenerator {
private final IslandWorldGeneratorAlternator alternator;
public IslandSurvivalCraftChunkGenerator(IslandBiomeGenerator biomeGenerator) {
alternator = new IslandWorldGeneratorAlternator(biomeGenerator);
}
@Override
public ChunkData generateChunkData(World world, Random random, int chunkX, int chunkZ, BiomeGrid biome) {
IslandWorldGenerator worldGenerator = alternator.getIslandChunkGeneratorSystemForWorld(world, random);
ChunkData chunk = createChunkData(world);
for (int localX = 0; localX < 16; localX++) {
for (int localZ = 0; localZ < 16; localZ++) {
worldGenerator.GenerateChunk(chunkX, chunkZ, localX, localZ, chunk, biome);
}
}
return chunk;
}
}

View File

@ -0,0 +1,48 @@
package ca.recrown.islandsurvivalcraft.world;
import java.util.Random;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.generator.ChunkGenerator.BiomeGrid;
import org.bukkit.generator.ChunkGenerator.ChunkData;
import ca.recrown.islandsurvivalcraft.world.generation.BedrockGenerator;
import ca.recrown.islandsurvivalcraft.world.generation.IslandBiomeGenerator;
/**
* A world generator.
*/
public class IslandWorldGenerator {
private final int maxHeight;
private final BedrockGenerator bedrockGenerator;
private final BiomeSelector biomeSelector;
private final IslandBiomeGenerator biomeGenerator;
public final World world;
public final IslandLocationMapper islandMapGenerator;
public final Random random;
public IslandWorldGenerator(World world, IslandBiomeGenerator generator, Random random) {
this.world = world;
this.maxHeight = world.getMaxHeight();
this.random = random;
this.biomeSelector = new BiomeSelector(random);
this.bedrockGenerator = new BedrockGenerator(random);
this.islandMapGenerator = new IslandLocationMapper(random, world.getSeaLevel(), 4);
this.biomeGenerator = generator;
biomeSelector.initialize();
}
public void GenerateChunk(int chunkX, int chunkZ, int localX, int localZ, ChunkData chunk, BiomeGrid biomeGrid) {
int worldX = 16 * chunkX + localX;
int worldZ = 16 * chunkZ + localZ;
//Sets the biome.
biomeGenerator.GenerateBiome(chunkX, chunkZ, localX, localZ, biomeGrid);
//Sets the bedrock.
int bedrockHeight = bedrockGenerator.getBedrockHeight(worldX, worldZ);
chunk.setRegion(localX, 0, localZ, localX, bedrockHeight, localZ, Material.BEDROCK);
}
}

View File

@ -0,0 +1,31 @@
package ca.recrown.islandsurvivalcraft.world;
import java.util.HashMap;
import java.util.Random;
import java.util.UUID;
import org.bukkit.World;
import ca.recrown.islandsurvivalcraft.world.generation.IslandBiomeGenerator;
/**
* Alternates the data used on a per world basis.
* Uses IslandWorldGenerator as the container for each world.
*/
public class IslandWorldGeneratorAlternator {
private HashMap<UUID, IslandWorldGenerator> chunkGenerator;
private IslandBiomeGenerator islandBiomeGenerator;
public IslandWorldGeneratorAlternator(IslandBiomeGenerator biomeGenerator) {
chunkGenerator = new HashMap<>();
this.islandBiomeGenerator = biomeGenerator;
}
public IslandWorldGenerator getIslandChunkGeneratorSystemForWorld(World world, Random random) {
if (!chunkGenerator.containsKey(world.getUID())) {
chunkGenerator.put(world.getUID(), new IslandWorldGenerator(world, islandBiomeGenerator.getInstance(), random));
}
return chunkGenerator.get(world.getUID());
}
}

View File

@ -1,4 +1,4 @@
package ca.recrown.islandsurvivalcraft.worldgeneration;
package ca.recrown.islandsurvivalcraft.world.generation;
import java.util.Random;
@ -10,8 +10,7 @@ public class BedrockGenerator {
private final int maxBedrockHeight = 5;
private final int minBedrockHeight = 1;
public void setRandom(Random random) {
if (random.equals(this.random)) return;
public BedrockGenerator(Random random) {
this.random = random;
noiseGenerator = new SimplexOctaveGenerator(random, 8);
noiseGenerator.setScale(0.1D);

View File

@ -1,4 +1,4 @@
package ca.recrown.islandsurvivalcraft.worldgeneration;
package ca.recrown.islandsurvivalcraft.world.generation;
import org.bukkit.World;
import org.bukkit.block.Biome;
@ -6,9 +6,12 @@ import org.bukkit.generator.ChunkGenerator.BiomeGrid;
import ca.recrown.islandsurvivalcraft.pathfinding.CoordinateTargetValidatable;
import ca.recrown.islandsurvivalcraft.pathfinding.DepthFirstSearch;
import ca.recrown.islandsurvivalcraft.world.BiomeSelector;
import ca.recrown.islandsurvivalcraft.world.IslandLocationMapper;
public class BiomePerIslandGenerator implements IslandBiomeGenerator, CoordinateTargetValidatable {
private IslandLocationGenerator islandLocator;
private boolean initialized;
private IslandLocationMapper islandLocator;
private BiomeSelector biomeSelector;
private TemperatureMapGenerator temperatureMapGenerator;
private int buildHeight;
@ -17,21 +20,21 @@ public class BiomePerIslandGenerator implements IslandBiomeGenerator, Coordinate
private Biome mainBiome;
private Biome shoreBiome;
private float temperature;
private BiomeGrid currentBiomeGrid;
private int currentChunkX, currentChunkZ;
public BiomePerIslandGenerator() {
this.temperatureMapGenerator = new TemperatureMapGenerator();
dfs = new DepthFirstSearch(islandLocator);
}
@Override
public void initialize(IslandLocationGenerator mapGenerator, BiomeSelector biomeSelector) {
public void initialize(World world, IslandLocationMapper mapGenerator, BiomeSelector biomeSelector) {
if (initialized) throw new IllegalStateException("Biome generator already initialized.");
initialized = true;
this.islandLocator = mapGenerator;
this.biomeSelector = biomeSelector;
}
@Override
public void setWorld(World world) {
if (world.equals(this.world)) return;
this.world = world;
this.temperatureMapGenerator.setSeed(world.getSeed());
this.buildHeight = world.getMaxHeight();
@ -49,37 +52,58 @@ public class BiomePerIslandGenerator implements IslandBiomeGenerator, Coordinate
if (mainBiome != null && shoreBiome != null) {
return true;
}
} else if (x/16 == currentChunkX && y/16 == currentChunkZ) {
int localX = x - (currentChunkX * 16);
int localZ = y - (currentChunkZ * 16);
Biome foundBiome = currentBiomeGrid.getBiome(localX, 0, localZ);
if (islandLocator.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) {
public void GenerateBiome(int chunkX, int chunkZ, int localX, int localZ, BiomeGrid biomeGrid) {
int worldX = chunkX * 16 + localX;
int worldZ = chunkZ * 16 + localZ;
if (islandLocator.isIsland(worldX, worldZ)) {
if (mainBiome == null && shoreBiome == null) {
this.currentBiomeGrid = biomeGrid;
this.currentChunkX = chunkX;
this.currentChunkZ = chunkZ;
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 (islandLocator.isShore(worldX, worldZ)) {
designatedBiome = shoreBiome;
}
biome.setBiome(localX, y, localZ, designatedBiome);
Biome designatedBiome = mainBiome;
if (mainBiome == null) {
designatedBiome = Biome.OCEAN;
} else if (islandLocator.isShore(worldX, worldZ)) {
designatedBiome = shoreBiome;
}
for (int y = 0; y < buildHeight; y++) {
biomeGrid.setBiome(localX, y, localZ, designatedBiome);
}
}
@Override
public IslandBiomeGenerator getInstance() {
return new BiomePerIslandGenerator();
}
}

View File

@ -0,0 +1,14 @@
package ca.recrown.islandsurvivalcraft.world.generation;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.generator.ChunkGenerator.BiomeGrid;
import ca.recrown.islandsurvivalcraft.world.BiomeSelector;
import ca.recrown.islandsurvivalcraft.world.IslandLocationMapper;
public interface IslandBiomeGenerator {
public void initialize(World world, IslandLocationMapper mapGenerator, BiomeSelector biome);
public void GenerateBiome(int chunkX, int chunkZ, int localX, int localZ, BiomeGrid biomeGrid);
public IslandBiomeGenerator getInstance();
}

View File

@ -1,4 +1,4 @@
package ca.recrown.islandsurvivalcraft.worldgeneration;
package ca.recrown.islandsurvivalcraft.world.generation;
import java.util.Random;

View File

@ -0,0 +1,5 @@
package ca.recrown.islandsurvivalcraft.world.shapers;
public class IslandShaper {
}

View File

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

View File

@ -1,50 +0,0 @@
package ca.recrown.islandsurvivalcraft.worldgeneration;
import java.util.Random;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.generator.ChunkGenerator;
public class IslandSurvivalCraftWorldGenerator extends ChunkGenerator {
private final BedrockGenerator bedrockGenerator;
private final BiomeSelector biomeSelector;
private final IslandBiomeGenerator biomeGenerator;
private final IslandLocationGenerator islandMapGenerator;
public IslandSurvivalCraftWorldGenerator(IslandBiomeGenerator generator) {
this.biomeSelector = new BiomeSelector();
this.bedrockGenerator = new BedrockGenerator();
this.islandMapGenerator = new IslandLocationGenerator();
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++) {
int worldX = 16*x + localX;
int worldZ = 16*z + localZ;
//generate bedrock layer
int bedrockHeight = bedrockGenerator.getBedrockHeight(worldX, worldZ);
chunk.setBlock(localX, bedrockHeight, localZ, Material.BEDROCK);
//Set biomes
biomeGenerator.GenerateBiome(x, z, localX, localZ, biome);
}
}
return chunk;
}
}

View File

@ -1,4 +1,4 @@
package ca.recrown.islandsurvivalcraft.worldgeneration;
package ca.recrown.islandsurvivalcraft.world;
import static org.junit.jupiter.api.Assertions.assertEquals;
@ -18,8 +18,7 @@ public class BiomeSelectorTest {
@BeforeAll
public void setUp() {
biomeSelector = new BiomeSelector();
biomeSelector.setRandom(new Random());
biomeSelector = new BiomeSelector(new Random());
biomeSelector.initialize();
}