From a41298604470a919900609b67d443a8f09bd3c8d Mon Sep 17 00:00:00 2001 From: Harrison Date: Sat, 25 Apr 2020 00:18:53 -0500 Subject: [PATCH] New iteration of biome generator. Untested. --- .../generation/BiomePerIslandGenerator.java | 191 ++++++++++-------- 1 file changed, 105 insertions(+), 86 deletions(-) diff --git a/src/main/java/ca/recrown/islandsurvivalcraft/world/generation/BiomePerIslandGenerator.java b/src/main/java/ca/recrown/islandsurvivalcraft/world/generation/BiomePerIslandGenerator.java index 6b14f36..54e91dd 100644 --- a/src/main/java/ca/recrown/islandsurvivalcraft/world/generation/BiomePerIslandGenerator.java +++ b/src/main/java/ca/recrown/islandsurvivalcraft/world/generation/BiomePerIslandGenerator.java @@ -1,13 +1,13 @@ package ca.recrown.islandsurvivalcraft.world.generation; +import org.bukkit.Chunk; import org.bukkit.World; import org.bukkit.block.Biome; import ca.recrown.islandsurvivalcraft.caching.Cache; import ca.recrown.islandsurvivalcraft.caching.CacheValue; import ca.recrown.islandsurvivalcraft.caching.CoordinateIdentifier; -import ca.recrown.islandsurvivalcraft.caching.Identifier; import ca.recrown.islandsurvivalcraft.pathfinding.CoordinateTargetValidatable; import ca.recrown.islandsurvivalcraft.pathfinding.CoordinateValidatable; import ca.recrown.islandsurvivalcraft.pathfinding.DepthFirstSearch; @@ -15,19 +15,19 @@ import ca.recrown.islandsurvivalcraft.world.BiomeSelector; import ca.recrown.islandsurvivalcraft.world.IslandWorldMapper; //Note: technically, the validators have to be run on land, and so, some condition checks may not be nessecary. -public class BiomePerIslandGenerator implements IslandBiomeGenerator, CoordinateValidatable, CoordinateTargetValidatable { - private final Cache chunkBiomesCache; - private final Cache chunkGenStatusCache; - private final TemperatureMapGenerator temperatureMapGenerator; +public class BiomePerIslandGenerator implements IslandBiomeGenerator { private boolean initialized; + private final TemperatureMapGenerator temperatureMapGenerator; + private final Cache chunkBiomesCache; + private final Cache chunkGenStatusCache; private IslandWorldMapper worldIslandMap; private BiomeSelector biomeSelector; private World world; - private DepthFirstSearch mapWideDFS; - private DepthFirstSearch propagator; - private LocalIslandPropagator propagatorInfo; - CoordinateIdentifier chunkCoords; - ChunkBiomes localChunkBiomes; + private final DepthFirstSearch freshCachePropagator; + private final DepthFirstSearch existenceChecker; + private FreshCachePropagationInfo freshCachePropInfo; + private PreviousGenerationInfo existenceInfo; + CoordinateIdentifier currChunkCoords; float temperature; @@ -35,20 +35,20 @@ public class BiomePerIslandGenerator implements IslandBiomeGenerator, Coordinate this.temperatureMapGenerator = new TemperatureMapGenerator(); chunkBiomesCache = new Cache<>(1024); chunkGenStatusCache = new Cache<>(1024); - propagatorInfo = new LocalIslandPropagator(); + freshCachePropInfo = new FreshCachePropagationInfo(); + freshCachePropagator = new DepthFirstSearch(freshCachePropInfo); + existenceInfo = new PreviousGenerationInfo(); + existenceChecker = new DepthFirstSearch(existenceInfo); } @Override public void initialize(final World world, final IslandWorldMapper mapGenerator, final BiomeSelector biomeSelector) { if (initialized) throw new IllegalStateException("Biome generator already initialized."); initialized = true; + this.world = world; this.worldIslandMap = mapGenerator; this.biomeSelector = biomeSelector; - this.world = world; this.temperatureMapGenerator.setSeed(world.getSeed()); - mapWideDFS = new DepthFirstSearch(worldIslandMap); - mapWideDFS.setEndPosition(0, 0); - propagator = new DepthFirstSearch(256, this); } @Override @@ -57,102 +57,121 @@ public class BiomePerIslandGenerator implements IslandBiomeGenerator, Coordinate } @Override - public Biome GenerateBiome(final int chunkX, final int chunkZ, final int localX, final int localZ) { - if (chunkCoords == null || chunkCoords.getX() != chunkX || chunkCoords.getY() != chunkZ) { - chunkCoords = new CoordinateIdentifier(chunkX, chunkZ); - chunkGenStatusCache.retrieveCache(chunkCoords).setValue(true); - localChunkBiomes = new ChunkBiomes(); - chunkBiomesCache.retrieveCache(chunkCoords).setValue(localChunkBiomes); + public Biome GenerateBiome(int chunkX, int chunkZ, int localX, int localZ) { + if (currChunkCoords == null || chunkX != currChunkCoords.getX() || chunkZ != currChunkCoords.getY()) { + currChunkCoords = new CoordinateIdentifier(chunkX, chunkZ); } - int worldX = 16 * chunkX + localX; - int worldZ = 16 * chunkZ + localZ; + int worldX = localX + 16 * chunkX; + int worldZ = localZ + 16 * chunkZ; - this.temperature = temperatureMapGenerator.getTemperature(worldX, worldZ); - if (worldIslandMap.isIsland(worldX, worldZ) && localChunkBiomes.biomes[localX][localZ] == null) { - mapWideDFS.setStartPosition(worldX, worldZ); - if (!mapWideDFS.findTarget(this)) { - if (propagatorInfo.mainBiome == null) propagatorInfo.mainBiome = biomeSelector.getLandBiome(temperature); - if (propagatorInfo.shoreBiome == null) propagatorInfo.shoreBiome = biomeSelector.getShoreBiome(propagatorInfo.mainBiome, temperature); - if (propagatorInfo.shallowBiome == null) propagatorInfo.shallowBiome = biomeSelector.getOceanBiome(temperature); - } - propagator.setStartPosition(worldX, worldZ); - propagator.findTarget(propagatorInfo); + Biome cachedBiome = getBiome(worldX, worldZ); + if (cachedBiome != null) return cachedBiome; + temperature = temperatureMapGenerator.getTemperature(worldX, worldZ); + + if (!worldIslandMap.isIsland(worldX, worldZ)) { + return biomeSelector.getOceanBiome(temperature); } - if (localChunkBiomes.biomes[localX][localZ] == null) { - localChunkBiomes.biomes[localX][localZ] = biomeSelector.getOceanBiome(temperature); + + freshCachePropInfo.clear(); + existenceChecker.setStartPosition(worldX, worldZ); + if (!existenceChecker.findTarget(existenceInfo)) { + if (freshCachePropInfo.main == null) freshCachePropInfo.main = biomeSelector.getLandBiome(temperature); + if (freshCachePropInfo.shore == null) freshCachePropInfo.shore = biomeSelector.getShoreBiome(freshCachePropInfo.main, temperature); + if (freshCachePropInfo.shallow == null) freshCachePropInfo.shallow = biomeSelector.getOceanBiome(temperature); } - return localChunkBiomes.biomes[localX][localZ]; + freshCachePropagator.setStartPosition(worldX, worldZ); + freshCachePropagator.findTarget(freshCachePropInfo); + return getBiome(worldX, worldZ); } - @Override - public boolean validate(int x, int y) { - return (x / 16) == chunkCoords.getX() && (y / 16) == chunkCoords.getY() && worldIslandMap.isIsland(x, y); - } - - @Override - public boolean isCoordinateTarget(int x, int y) { - if ((propagatorInfo.shoreBiome == null || propagatorInfo.mainBiome == null) && worldIslandMap.isLand(x, y)) { - if (propagatorInfo.shoreBiome == null && worldIslandMap.isShore(x, y)) { - propagatorInfo.shoreBiome = getBiomeAt(x, y); - } else if (propagatorInfo.mainBiome != null) { - propagatorInfo.mainBiome = getBiomeAt(x, y); - } - } else if (propagatorInfo.shallowBiome == null) { - propagatorInfo.shallowBiome = getBiomeAt(x, y); - } - return (propagatorInfo.shallowBiome != null && propagatorInfo.mainBiome != null && propagatorInfo.shoreBiome != null); - } - - private Biome getBiomeAt(int worldX, int worldZ) { - int chunkX = worldX / 16; - int chunkZ = worldZ / 16; + private Biome getBiome(int worldX, int worldZ) { int localX = Math.abs(worldX % 16); int localZ = Math.abs(worldZ % 16); + CoordinateIdentifier chunkCoords = new CoordinateIdentifier(worldX / 16, worldZ / 16); - Identifier chunkBiomeID = new CoordinateIdentifier(chunkX, chunkZ); - Identifier chunkGenID = new CoordinateIdentifier(chunkX, chunkZ); + CacheValue chunkBiomes = chunkBiomesCache.retrieveCache(chunkCoords); + if (!chunkBiomes.isEmpty()) { + Biome biome = chunkBiomes.getValue()[localX][localZ]; + if (biome != null) return biome; + } - CacheValue chunkBiomeVal = chunkBiomesCache.retrieveCache(chunkBiomeID); - CacheValue chunkGenVal = chunkGenStatusCache.retrieveCache(chunkGenID); - - if (chunkGenVal.isEmpty()) chunkGenVal.setValue(world.isChunkGenerated(worldX / 16, worldZ / 16)); - - if (chunkGenVal.getValue()) { - if (chunkBiomeVal.isEmpty()) { - chunkBiomeVal.setValue(new ChunkBiomes()); - } - - if (chunkBiomeVal.getValue().biomes[localX][localZ] == null) { - chunkBiomeVal.getValue().biomes[localX][localZ] = world.getBiome(worldX, 0, worldZ); - } - return chunkBiomeVal.getValue().biomes[localX][localZ] = world.getBiome(worldX, 0, worldZ); + CacheValue chunkGenStatus = chunkGenStatusCache.retrieveCache(chunkCoords); + if (chunkGenStatus.isEmpty()) + chunkGenStatus.setValue(world.isChunkGenerated(chunkCoords.getX(), chunkCoords.getY())); + + if (chunkGenStatus.getValue()) { + if (chunkBiomes.isEmpty()) chunkBiomes.setValue(new Biome[16][16]); + chunkBiomes.getValue()[localX][localZ] = world.getBiome(worldX, 0, worldZ); + return chunkBiomes.getValue()[localX][localZ]; } return null; } - private class ChunkBiomes { - public final Biome[][] biomes = new Biome[16][16]; + private void setCacheBiome(int worldX, int worldZ, Biome biome) { + int localX = Math.abs(worldX % 16); + int localZ = Math.abs(worldZ % 16); + CoordinateIdentifier chunkCoords = new CoordinateIdentifier(worldX / 16, worldZ / 16); + + CacheValue chunkBiomes = chunkBiomesCache.retrieveCache(chunkCoords); + if (chunkBiomes.isEmpty()) chunkBiomes.setValue(new Biome[16][16]); + chunkBiomes.getValue()[localX][localZ] = biome; } - private class LocalIslandPropagator implements CoordinateTargetValidatable { - public Biome mainBiome = null; - public Biome shoreBiome = null; - public Biome shallowBiome = null; + private class FreshCachePropagationInfo implements CoordinateTargetValidatable, CoordinateValidatable { + public Biome shore; + public Biome main; + public Biome shallow; @Override public boolean isCoordinateTarget(int x, int y) { - int localX = Math.abs(x % 16); - int localZ = Math.abs(y % 16); if (worldIslandMap.isLand(x, y)) { if (worldIslandMap.isShore(x, y)) { - localChunkBiomes.biomes[localX][localZ] = shoreBiome; + setCacheBiome(x, y, shore); } else { - localChunkBiomes.biomes[localX][localZ] = mainBiome; + setCacheBiome(x, y, main); } - } else if (worldIslandMap.isShallowPortion(x, y)) { - localChunkBiomes.biomes[localX][localZ] = shallowBiome; + } else { + setCacheBiome(x, y, shallow); } return false; } + + @Override + public boolean validate(int x, int y) { + return x / 16 == currChunkCoords.getX() && y / 16 == currChunkCoords.getY() && worldIslandMap.isIsland(x, y); + } + + public boolean allBiomesAcquired() { + return shore != null && main != null && shallow != null; + } + + public void clear() { + main = null; + shore = null; + shallow = null; + } + } + + private class PreviousGenerationInfo implements CoordinateTargetValidatable, CoordinateValidatable { + + @Override + public boolean validate(int x, int y) { + return worldIslandMap.isIsland(x, y); + } + + @Override + public boolean isCoordinateTarget(int x, int y) { + if (freshCachePropInfo.main == null && worldIslandMap.isLand(x, y) && !worldIslandMap.isShore(x, y)) { + freshCachePropInfo.main = getBiome(x, y); + } + if (freshCachePropInfo.shore == null && worldIslandMap.isShore(x, y)) { + freshCachePropInfo.shore = getBiome(x, y); + } + if (freshCachePropInfo.shallow == null && worldIslandMap.isShallowPortion(x, y)) { + freshCachePropInfo.shallow = getBiome(x, y); + } + return freshCachePropInfo.allBiomesAcquired(); + } + } } \ No newline at end of file