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.generator.ChunkGenerator;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import ca.recrown.islandsurvivalcraft.worldgeneration.BiomePerIslandGenerator; import ca.recrown.islandsurvivalcraft.world.IslandSurvivalCraftChunkGenerator;
import ca.recrown.islandsurvivalcraft.worldgeneration.IslandSurvivalCraftWorldGenerator; import ca.recrown.islandsurvivalcraft.world.IslandWorldGenerator;
import ca.recrown.islandsurvivalcraft.world.generation.BiomePerIslandGenerator;
public class IslandSurvivalCraft extends JavaPlugin { public class IslandSurvivalCraft extends JavaPlugin {
IslandSurvivalCraftWorldGenerator generator; IslandSurvivalCraftChunkGenerator generator;
@Override @Override
public void onEnable() { public void onEnable() {
generator = new IslandSurvivalCraftWorldGenerator(new BiomePerIslandGenerator()); generator = new IslandSurvivalCraftChunkGenerator(new BiomePerIslandGenerator());
generator.initialize();
super.onEnable(); 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.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@ -11,32 +11,27 @@ import ca.recrown.islandsurvivalcraft.Utilities;
public class BiomeSelector { public class BiomeSelector {
private boolean initialized = false; private boolean initialized = false;
private Random random; private final Random random;
private final HashMap<Biome, Float> lands; private final HashMap<Biome, Float> lands = new HashMap<>();
private HashMap<Float, ArrayList<Biome>> temperaturesForLand; private HashMap<Float, ArrayList<Biome>> temperaturesForLand = new HashMap<>();
private final HashMap<Float, ArrayList<Biome>> temperaturePartitionedLandBiomes; private final HashMap<Float, ArrayList<Biome>> temperaturePartitionedLandBiomes = new HashMap<>();
private final HashMap<Biome, Float> oceans; private final HashMap<Biome, Float> oceans = new HashMap<>();
private HashMap<Float, ArrayList<Biome>> temperaturesForOcean; private HashMap<Float, ArrayList<Biome>> temperaturesForOcean = new HashMap<>();
private final HashMap<Float, ArrayList<Biome>> temperaturePartitionedOceanBiomes; private final HashMap<Float, ArrayList<Biome>> temperaturePartitionedOceanBiomes = new HashMap<>();
public BiomeSelector() { public BiomeSelector(Random random) {
lands = new HashMap<>(); this.random = random;
oceans = new HashMap<>();
temperaturePartitionedLandBiomes = new HashMap<>();
temperaturePartitionedLandBiomes.put(0.05f, new ArrayList<>()); temperaturePartitionedLandBiomes.put(0.05f, new ArrayList<>());
temperaturePartitionedLandBiomes.put(0.30f, new ArrayList<>()); temperaturePartitionedLandBiomes.put(0.30f, new ArrayList<>());
temperaturePartitionedLandBiomes.put(0.95f, new ArrayList<>()); temperaturePartitionedLandBiomes.put(0.95f, new ArrayList<>());
temperaturePartitionedLandBiomes.put(2f, new ArrayList<>()); temperaturePartitionedLandBiomes.put(2f, new ArrayList<>());
temperaturePartitionedOceanBiomes = new HashMap<>();
temperaturePartitionedOceanBiomes.put(0.00f, new ArrayList<>()); temperaturePartitionedOceanBiomes.put(0.00f, new ArrayList<>());
temperaturePartitionedOceanBiomes.put(0.5f, new ArrayList<>()); temperaturePartitionedOceanBiomes.put(0.5f, new ArrayList<>());
} }
public void setRandom(Random random) {
this.random = random;
}
public void initialize() { public void initialize() {
if (initialized) throw new IllegalStateException("Biome selector is already initialized."); 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; 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.CoordinateValidatable;
import ca.recrown.islandsurvivalcraft.pathfinding.DepthFirstSearch; import ca.recrown.islandsurvivalcraft.pathfinding.DepthFirstSearch;
public class IslandLocationGenerator implements CoordinateValidatable { public class IslandLocationMapper implements CoordinateValidatable {
private Random random;
private SimplexOctaveGenerator noiseGenerator; private SimplexOctaveGenerator noiseGenerator;
private final int noiseOctaves = 8; private final int noiseOctaves = 8;
private final int islandGenerationPercent = 47; private final int islandGenerationPercent = 47;
@ -22,17 +21,11 @@ public class IslandLocationGenerator implements CoordinateValidatable {
private int shallowDepth; private int shallowDepth;
private final DepthFirstSearch dfs; private final DepthFirstSearch dfs;
public IslandLocationGenerator() { public IslandLocationMapper(Random random, int seaLevel, int shallowDepth) {
dfs = new DepthFirstSearch(this); dfs = new DepthFirstSearch(this);
}
public void updateParameters(Random random, int seaLevel, int shallowDepth) {
this.seaLevel = seaLevel; this.seaLevel = seaLevel;
this.shallowDepth = shallowDepth; this.shallowDepth = shallowDepth;
if (!random.equals(this.random)) {
this.random = random;
this.noiseGenerator = new SimplexOctaveGenerator(random, noiseOctaves); this.noiseGenerator = new SimplexOctaveGenerator(random, noiseOctaves);
}
this.seaLevel = seaLevel; this.seaLevel = seaLevel;
this.shallowDepth = shallowDepth; this.shallowDepth = shallowDepth;
} }

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; import java.util.Random;
@ -10,8 +10,7 @@ public class BedrockGenerator {
private final int maxBedrockHeight = 5; private final int maxBedrockHeight = 5;
private final int minBedrockHeight = 1; private final int minBedrockHeight = 1;
public void setRandom(Random random) { public BedrockGenerator(Random random) {
if (random.equals(this.random)) return;
this.random = random; this.random = random;
noiseGenerator = new SimplexOctaveGenerator(random, 8); noiseGenerator = new SimplexOctaveGenerator(random, 8);
noiseGenerator.setScale(0.1D); 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.World;
import org.bukkit.block.Biome; 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.CoordinateTargetValidatable;
import ca.recrown.islandsurvivalcraft.pathfinding.DepthFirstSearch; import ca.recrown.islandsurvivalcraft.pathfinding.DepthFirstSearch;
import ca.recrown.islandsurvivalcraft.world.BiomeSelector;
import ca.recrown.islandsurvivalcraft.world.IslandLocationMapper;
public class BiomePerIslandGenerator implements IslandBiomeGenerator, CoordinateTargetValidatable { public class BiomePerIslandGenerator implements IslandBiomeGenerator, CoordinateTargetValidatable {
private IslandLocationGenerator islandLocator; private boolean initialized;
private IslandLocationMapper islandLocator;
private BiomeSelector biomeSelector; private BiomeSelector biomeSelector;
private TemperatureMapGenerator temperatureMapGenerator; private TemperatureMapGenerator temperatureMapGenerator;
private int buildHeight; private int buildHeight;
@ -18,20 +21,20 @@ public class BiomePerIslandGenerator implements IslandBiomeGenerator, Coordinate
private Biome shoreBiome; private Biome shoreBiome;
private float temperature; private float temperature;
private BiomeGrid currentBiomeGrid;
private int currentChunkX, currentChunkZ;
public BiomePerIslandGenerator() { public BiomePerIslandGenerator() {
this.temperatureMapGenerator = new TemperatureMapGenerator(); this.temperatureMapGenerator = new TemperatureMapGenerator();
dfs = new DepthFirstSearch(islandLocator); dfs = new DepthFirstSearch(islandLocator);
} }
@Override @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.islandLocator = mapGenerator;
this.biomeSelector = biomeSelector; this.biomeSelector = biomeSelector;
}
@Override
public void setWorld(World world) {
if (world.equals(this.world)) return;
this.world = world; this.world = world;
this.temperatureMapGenerator.setSeed(world.getSeed()); this.temperatureMapGenerator.setSeed(world.getSeed());
this.buildHeight = world.getMaxHeight(); this.buildHeight = world.getMaxHeight();
@ -49,29 +52,44 @@ public class BiomePerIslandGenerator implements IslandBiomeGenerator, Coordinate
if (mainBiome != null && shoreBiome != null) { if (mainBiome != null && shoreBiome != null) {
return true; 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; return false;
} }
@Override @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 worldX = chunkX * 16 + localX;
int worldZ = chunkZ * 16 + localZ; int worldZ = chunkZ * 16 + localZ;
if (islandLocator.isIsland(worldX, worldZ)) { if (islandLocator.isIsland(worldX, worldZ)) {
if (mainBiome == null && shoreBiome == null) { if (mainBiome == null && shoreBiome == null) {
this.currentBiomeGrid = biomeGrid;
this.currentChunkX = chunkX;
this.currentChunkZ = chunkZ;
if (!dfs.findTarget(this)) { if (!dfs.findTarget(this)) {
temperature = temperatureMapGenerator.getTemperature(worldX, worldZ); temperature = temperatureMapGenerator.getTemperature(worldX, worldZ);
mainBiome = biomeSelector.getLandBiome(temperature); mainBiome = biomeSelector.getLandBiome(temperature);
shoreBiome = biomeSelector.getShoreBiome(mainBiome, temperature); shoreBiome = biomeSelector.getShoreBiome(mainBiome, temperature);
} }
} }
} else { } else {
mainBiome = null; mainBiome = null;
shoreBiome = null; shoreBiome = null;
} }
for (int y = 0; y < buildHeight; y++) {
Biome designatedBiome = mainBiome; Biome designatedBiome = mainBiome;
if (mainBiome == null) { if (mainBiome == null) {
designatedBiome = Biome.OCEAN; designatedBiome = Biome.OCEAN;
@ -79,7 +97,13 @@ public class BiomePerIslandGenerator implements IslandBiomeGenerator, Coordinate
designatedBiome = shoreBiome; designatedBiome = shoreBiome;
} }
biome.setBiome(localX, y, localZ, designatedBiome); 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; 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; import static org.junit.jupiter.api.Assertions.assertEquals;
@ -18,8 +18,7 @@ public class BiomeSelectorTest {
@BeforeAll @BeforeAll
public void setUp() { public void setUp() {
biomeSelector = new BiomeSelector(); biomeSelector = new BiomeSelector(new Random());
biomeSelector.setRandom(new Random());
biomeSelector.initialize(); biomeSelector.initialize();
} }