Added generation modes.

This commit is contained in:
Harrison Deng 2020-05-04 20:27:44 -05:00
parent 479e28c090
commit 785f7a1ea3
6 changed files with 151 additions and 60 deletions

View File

@ -6,6 +6,7 @@ import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import ca.recrown.islandsurvivalcraft.world.WorldInfoManager; import ca.recrown.islandsurvivalcraft.world.WorldInfoManager;
import ca.recrown.islandsurvivalcraft.world.generation.GeneratorModes;
public class IslandSurvivalCraft extends JavaPlugin implements Listener { public class IslandSurvivalCraft extends JavaPlugin implements Listener {
private PluginManager pluginManager; private PluginManager pluginManager;
@ -29,7 +30,13 @@ public class IslandSurvivalCraft extends JavaPlugin implements Listener {
@Override @Override
public ChunkGenerator getDefaultWorldGenerator(String worldName, String id) { public ChunkGenerator getDefaultWorldGenerator(String worldName, String id) {
return worldInfos.getChunkGenerator(getServer().getWorld(worldName)); GeneratorModes gID = null;
try {
gID = GeneratorModes.valueOf(id);
} catch (NullPointerException | IllegalArgumentException e) {
gID = GeneratorModes.UNIQUE;
}
return worldInfos.getChunkGenerator(getServer().getWorld(worldName), gID);
} }
} }

View File

@ -8,48 +8,49 @@ import ca.recrown.islandsurvivalcraft.world.generation.chunks.IslandWorldChunkGe
public class WorldInfo { public class WorldInfo {
private final WorldInfoManager manager; private final WorldInfoManager manager;
private volatile Random random;
private volatile int seaLevel;
private volatile int worldHeight;
private volatile boolean initialized; private volatile boolean initialized;
public volatile long seed; private volatile long seed;
public volatile BiomeMap biomeMap; private volatile BiomeMap biomeMap;
public volatile TemperatureMap tempMap; private volatile TemperatureMap tempMap;
public volatile IslandWorldMap islandMap; private volatile IslandWorldMap islandMap;
public volatile IslandWorldChunkGenerator generator; private volatile IslandWorldChunkGenerator generator;
/** /**
* Will initialize with the known information extracted from the given world if world is not null. * Will initialize with the known information extracted from the given world if
* If the world is null, this world info will not be initialized and awaits initialization from the generator. * world is not null. If the world is null, this world info will not be
* @param world The world this object is describing. May be null to create a non-initialized info object. * initialized and awaits initialization from the generator.
*
* @param world The world this object is describing. May be null to create a
* non-initialized info object.
*/ */
public WorldInfo(WorldInfoManager manager, World world) { public WorldInfo(WorldInfoManager manager, World world) {
this.manager = manager; this.manager = manager;
if (world != null) { if (world != null) {
initialize(world); initialize(world, null);
} }
} }
public void initialize(World world, IslandWorldChunkGenerator chunkGenerator) { public void initialize(World world, IslandWorldChunkGenerator chunkGenerator) {
if (initialized) throw new IllegalStateException("This world information object has already been initialized."); if (initialized)
initialized = true; throw new IllegalStateException("This world information object has already been initialized.");
this.initialized = true;
this.seed = world.getSeed(); this.seed = world.getSeed();
Random random = new Random(seed); this.random = new Random(seed);
biomeMap = new BiomeMap(random); this.biomeMap = new BiomeMap(random);
tempMap = new TemperatureMap(random); this.tempMap = new TemperatureMap(random);
islandMap = new IslandWorldMap(random); this.islandMap = new IslandWorldMap(random);
generator = chunkGenerator; this.worldHeight = world.getMaxHeight();
generator.initialize(random, true, world.getSeaLevel(), world.getMaxHeight()); this.seaLevel = world.getSeaLevel();
manager.register(world, this); if (chunkGenerator != null) {
} this.generator = chunkGenerator;
this.generator.initialize();
private void initialize(World world) { this.manager.register(world, this);
if (initialized) throw new IllegalStateException("This world information object has already been initialized."); } else {
initialized = true; generator = new IslandWorldChunkGenerator(this);
this.seed = world.getSeed(); }
Random random = new Random(seed);
biomeMap = new BiomeMap(random);
tempMap = new TemperatureMap(random);
islandMap = new IslandWorldMap(random);
generator = new IslandWorldChunkGenerator(this);
generator.initialize(random, true, world.getSeaLevel(), world.getMaxHeight());
} }
/** /**
@ -58,4 +59,67 @@ public class WorldInfo {
public boolean isInitialized() { public boolean isInitialized() {
return initialized; return initialized;
} }
/**
* @return the biomeMap
*/
public BiomeMap getBiomeMap() {
return biomeMap;
}
/**
* @return the generator
*/
public IslandWorldChunkGenerator getGenerator() {
return generator;
}
/**
* @return the islandMap
*/
public IslandWorldMap getIslandMap() {
return islandMap;
}
/**
* @return the manager
*/
public WorldInfoManager getManager() {
return manager;
}
/**
* @return the random
*/
public Random getRandom() {
return random;
}
/**
* @return the seaLevel
*/
public int getSeaLevel() {
return seaLevel;
}
/**
* @return the seed
*/
public long getSeed() {
return seed;
}
/**
* @return the tempMap
*/
public TemperatureMap getTempMap() {
return tempMap;
}
/**
* @return the worldHeight
*/
public int getWorldHeight() {
return worldHeight;
}
} }

View File

@ -12,6 +12,7 @@ import org.bukkit.event.Listener;
import org.bukkit.event.world.ChunkLoadEvent; import org.bukkit.event.world.ChunkLoadEvent;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
import ca.recrown.islandsurvivalcraft.world.generation.GeneratorModes;
import ca.recrown.islandsurvivalcraft.world.generation.chunks.IslandWorldChunkGenerator; import ca.recrown.islandsurvivalcraft.world.generation.chunks.IslandWorldChunkGenerator;
public class WorldInfoManager implements Listener { public class WorldInfoManager implements Listener {
@ -42,20 +43,28 @@ public class WorldInfoManager implements Listener {
* @param world The world the chunk generator is for. If it does not yet exist, it will be created. * @param world The world the chunk generator is for. If it does not yet exist, it will be created.
* @return The chunk generator associated with the given world. * @return The chunk generator associated with the given world.
*/ */
public ChunkGenerator getChunkGenerator(World world) { public ChunkGenerator getChunkGenerator(World world, GeneratorModes mode) {
if (world == null) { WorldInfo worldInfo = null;
WorldInfo worldInfo = new WorldInfo(this, world); if (world != null) {
IslandWorldChunkGenerator islandWorldChunkGenerator = new IslandWorldChunkGenerator(worldInfo); worldInfo = retrieve(world);
return islandWorldChunkGenerator; if (!worldInfo.getGenerator().isInitialized()) {
worldInfo.getGenerator().setGeneratorType(mode);
worldInfo.getGenerator().initialize();
}
return worldInfo.getGenerator();
} else {
worldInfo = new WorldInfo(this, null);
IslandWorldChunkGenerator generator = new IslandWorldChunkGenerator(worldInfo);
generator.setGeneratorType(mode);
return generator;
} }
return retrieve(world).generator;
} }
@EventHandler(priority = EventPriority.MONITOR) @EventHandler(priority = EventPriority.MONITOR)
public void onChunkLoaded(ChunkLoadEvent event) { public void onChunkLoaded(ChunkLoadEvent event) {
if (event.isNewChunk()) { if (event.isNewChunk()) {
Chunk chunk = event.getChunk(); Chunk chunk = event.getChunk();
retrieve(event.getWorld()).generator.updateChunkLoadedCache(chunk.getX(), chunk.getZ()); retrieve(event.getWorld()).getGenerator().updateChunkLoadedCache(chunk.getX(), chunk.getZ());
} }
} }

View File

@ -0,0 +1,5 @@
package ca.recrown.islandsurvivalcraft.world.generation;
public enum GeneratorModes {
UNIQUE
}

View File

@ -22,15 +22,17 @@ import ca.recrown.islandsurvivalcraft.world.BiomeMap;
import ca.recrown.islandsurvivalcraft.world.IslandWorldMap; import ca.recrown.islandsurvivalcraft.world.IslandWorldMap;
import ca.recrown.islandsurvivalcraft.world.TemperatureMap; import ca.recrown.islandsurvivalcraft.world.TemperatureMap;
import ca.recrown.islandsurvivalcraft.world.WorldInfo; import ca.recrown.islandsurvivalcraft.world.WorldInfo;
import ca.recrown.islandsurvivalcraft.world.generation.GeneratorModes;
import ca.recrown.islandsurvivalcraft.world.generation.biomes.BiomeGenerator; import ca.recrown.islandsurvivalcraft.world.generation.biomes.BiomeGenerator;
import ca.recrown.islandsurvivalcraft.world.generation.biomes.UniqueBiomeGenerator; import ca.recrown.islandsurvivalcraft.world.generation.biomes.UniqueBiomeGenerator;
import ca.recrown.islandsurvivalcraft.world.generation.shaders.WorldHeightShader; import ca.recrown.islandsurvivalcraft.world.generation.shaders.WorldHeightShader;
import ca.recrown.islandsurvivalcraft.world.generation.shaders.WorldLayerShader; import ca.recrown.islandsurvivalcraft.world.generation.shaders.WorldLayerShader;
public class IslandWorldChunkGenerator extends ChunkGenerator implements Listener { public class IslandWorldChunkGenerator extends ChunkGenerator implements Listener {
private final int BEDROCK_HEIGHT = 5;
private volatile GeneratorModes generatorType;
private volatile boolean initialized = false; private volatile boolean initialized = false;
private volatile WorldInfo worldInfo; private volatile WorldInfo worldInfo;
private final int BEDROCK_HEIGHT = 5;
private volatile IslandWorldMap islandMap; private volatile IslandWorldMap islandMap;
private volatile TemperatureMap temperatureMap; private volatile TemperatureMap temperatureMap;
private volatile BiomeMap biomeMap; private volatile BiomeMap biomeMap;
@ -42,22 +44,30 @@ public class IslandWorldChunkGenerator extends ChunkGenerator implements Listene
private volatile ExecutorService exAlpha = GeneralUtilities.ISC_EXECUTOR_ALPHA; private volatile ExecutorService exAlpha = GeneralUtilities.ISC_EXECUTOR_ALPHA;
private volatile ExecutorService exBeta = GeneralUtilities.ISC_EXECUTOR_BETA; private volatile ExecutorService exBeta = GeneralUtilities.ISC_EXECUTOR_BETA;
public void initialize(Random random, boolean uniqueBiome, int seaLevel, int worldHeight) { public void initialize() {
if (initialized) throw new IllegalStateException("This generator has already been initialized"); if (initialized) throw new IllegalStateException("This generator has already been initialized.");
initialized = true; initialized = true;
this.islandMap = worldInfo.islandMap; this.islandMap = worldInfo.getIslandMap();
this.temperatureMap = worldInfo.tempMap; this.temperatureMap = worldInfo.getTempMap();
this.biomeMap = worldInfo.biomeMap; this.biomeMap = worldInfo.getBiomeMap();
this.heightShader = new WorldHeightShader(random, islandMap, seaLevel, worldHeight, BEDROCK_HEIGHT + 1); this.heightShader = new WorldHeightShader(worldInfo.getRandom(), islandMap, worldInfo.getSeaLevel(), worldInfo.getWorldHeight(), BEDROCK_HEIGHT + 1);
this.layerShader = new WorldLayerShader(random, seaLevel, worldHeight, islandMap); this.layerShader = new WorldLayerShader(worldInfo.getRandom(), worldInfo.getSeaLevel(), worldInfo.getWorldHeight(), islandMap);
if (uniqueBiome) { if (generatorType == GeneratorModes.UNIQUE) {
biomeGenerator = new UniqueBiomeGenerator(); biomeGenerator = new UniqueBiomeGenerator();
} else { } else {
throw new NotImplementedException(); throw new NotImplementedException();
} }
} }
/**
* @param generatorType the gID to set to.
*/
public void setGeneratorType(GeneratorModes generatorType) {
if (initialized) throw new IllegalStateException("This generator has already been initialized.");
this.generatorType = generatorType;
}
public IslandWorldChunkGenerator(WorldInfo worldInfo) { public IslandWorldChunkGenerator(WorldInfo worldInfo) {
this.worldInfo = worldInfo; this.worldInfo = worldInfo;
} }
@ -69,10 +79,6 @@ public class IslandWorldChunkGenerator extends ChunkGenerator implements Listene
} }
if (!initialized) throw new IllegalStateException("This generator has not been initialized."); if (!initialized) throw new IllegalStateException("This generator has not been initialized.");
long seed = world.getSeed();
int maxHeight = world.getMaxHeight();
int seaLevel = world.getSeaLevel();
LinkedList<Future<Boolean>> tasks = new LinkedList<>(); LinkedList<Future<Boolean>> tasks = new LinkedList<>();
ChunkData chunkData = createChunkData(world); ChunkData chunkData = createChunkData(world);
Future<Boolean> preLoader = exAlpha.submit(() -> { Future<Boolean> preLoader = exAlpha.submit(() -> {
@ -98,7 +104,7 @@ public class IslandWorldChunkGenerator extends ChunkGenerator implements Listene
} }
if (biomeArraySet[localX][localZ][0] == null) throw new IllegalStateException("Biome was null."); if (biomeArraySet[localX][localZ][0] == null) throw new IllegalStateException("Biome was null.");
tasks.add(exBeta.submit(() -> { tasks.add(exBeta.submit(() -> {
for (int y = 0; y < maxHeight; y++) { for (int y = 0; y < worldInfo.getWorldHeight(); y++) {
biomeGrid.setBiome(localX, y, localZ, biomeArraySet[localX][localZ][0]); biomeGrid.setBiome(localX, y, localZ, biomeArraySet[localX][localZ][0]);
} }
return true; return true;
@ -109,11 +115,11 @@ public class IslandWorldChunkGenerator extends ChunkGenerator implements Listene
int currentTerrainHeight = terrainHeight - 1; int currentTerrainHeight = terrainHeight - 1;
int bedrockHeight = random.nextInt(5) + 1; int bedrockHeight = random.nextInt(5) + 1;
if (layerShader.hasSpecialLayers(currentBiomeSet[0])) { if (layerShader.hasSpecialLayers(currentBiomeSet[0])) {
BlockData currentMaterial = layerShader.getMaterialForHeight(seed, worldX, worldZ, currentTerrainHeight, terrainHeight - 1, currentBiomeSet); BlockData currentMaterial = layerShader.getMaterialForHeight(worldInfo.getSeed(), worldX, worldZ, currentTerrainHeight, terrainHeight - 1, currentBiomeSet);
while (currentMaterial != null) { while (currentMaterial != null) {
chunkData.setBlock(localX, currentTerrainHeight, localZ, currentMaterial); chunkData.setBlock(localX, currentTerrainHeight, localZ, currentMaterial);
currentTerrainHeight--; currentTerrainHeight--;
currentMaterial = layerShader.getMaterialForHeight(seed, worldX, worldZ, currentTerrainHeight, terrainHeight - 1, currentBiomeSet); currentMaterial = layerShader.getMaterialForHeight(worldInfo.getSeed(), worldX, worldZ, currentTerrainHeight, terrainHeight - 1, currentBiomeSet);
} }
} else { } else {
int surfaceThickness = layerShader.getSurfaceThickness(worldX, worldZ, currentBiomeSet[0]); int surfaceThickness = layerShader.getSurfaceThickness(worldX, worldZ, currentBiomeSet[0]);
@ -124,8 +130,8 @@ public class IslandWorldChunkGenerator extends ChunkGenerator implements Listene
chunkData.setRegion(localX, currentTerrainHeight, localZ, localX + 1, currentTerrainHeight + transitionThickness + 1, localZ + 1, layerShader.getTransitionMaterial(currentBiomeSet[0])); chunkData.setRegion(localX, currentTerrainHeight, localZ, localX + 1, currentTerrainHeight + transitionThickness + 1, localZ + 1, layerShader.getTransitionMaterial(currentBiomeSet[0]));
} }
chunkData.setRegion(localX, bedrockHeight, localZ, localX + 1, currentTerrainHeight + 1, localZ + 1, Material.STONE); chunkData.setRegion(localX, bedrockHeight, localZ, localX + 1, currentTerrainHeight + 1, localZ + 1, Material.STONE);
if (terrainHeight < seaLevel) { if (terrainHeight < worldInfo.getSeaLevel()) {
chunkData.setRegion(localX, terrainHeight, localZ, localX + 1, seaLevel, localZ + 1, Material.WATER); chunkData.setRegion(localX, terrainHeight, localZ, localX + 1, worldInfo.getSeaLevel(), localZ + 1, Material.WATER);
} }
chunkData.setRegion(localX, 0, localZ, localX + 1, bedrockHeight, localZ + 1, Material.BEDROCK); chunkData.setRegion(localX, 0, localZ, localX + 1, bedrockHeight, localZ + 1, Material.BEDROCK);
} }

View File

@ -29,15 +29,15 @@ public class WorldHeightShader {
if (!mapper.isLand(worldX, worldZ)) { if (!mapper.isLand(worldX, worldZ)) {
height = (int) calculateTerrainFactor(worldX, worldZ, seaLevel * 0.8d, 1.7d, 0.5d, 1d, 0.1d); height = (int) calculateTerrainFactor(worldX, worldZ, seaLevel * 0.8d, 1.7d, 0.5d, 1d, 0.1d);
} else if (biomeName.contains("beach")) { } else if (biomeName.contains("beach")) {
height = (int) (getIslandBiomeHeight(worldX, worldZ, biomeSet[1], 5d)); height = (int) (getIslandBiomeHeight(worldX, worldZ, biomeSet[1], 10d));
} else if (biomeName.contains("shore")) { } else if (biomeName.contains("shore")) {
height = (int) (getIslandBiomeHeight(worldX, worldZ, biomeSet[1], 30d)); height = (int) (getIslandBiomeHeight(worldX, worldZ, biomeSet[1], -30d));
} else { } else {
height = getIslandBiomeHeight(worldX, worldZ, biomeSet[0], 0d) + 1; height = getIslandBiomeHeight(worldX, worldZ, biomeSet[0], 0d) + 1;
} }
if (height > worldHeight) throw new IllegalStateException("Resulting height is greater than world height! Biome this occurred on: " + biomeName);
height = Math.max(minimumHeight, height); height = Math.max(minimumHeight, height);
if (height > worldHeight) throw new IllegalStateException(String.format("Resulting height is greater than world height! Current biome set: %s, maximum height: %d, minimum height %d", biomeSet, worldHeight, minimumHeight));
return height; return height;
} }