Reworked biome per island generator.
This commit is contained in:
		@@ -1,122 +1,159 @@
 | 
			
		||||
package ca.recrown.islandsurvivalcraft.world.generation;
 | 
			
		||||
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
import ca.recrown.islandsurvivalcraft.world.BiomeSelector;
 | 
			
		||||
import ca.recrown.islandsurvivalcraft.world.IslandWorldMapper;
 | 
			
		||||
 | 
			
		||||
public class BiomePerIslandGenerator implements IslandBiomeGenerator, CoordinateTargetValidatable {
 | 
			
		||||
//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<ChunkBiomes> chunkBiomesCache;
 | 
			
		||||
    private final Cache<Boolean> chunkGenStatusCache;
 | 
			
		||||
    private final TemperatureMapGenerator temperatureMapGenerator;
 | 
			
		||||
    private boolean initialized;
 | 
			
		||||
    private IslandWorldMapper islandLocator;
 | 
			
		||||
    private IslandWorldMapper worldIslandMap;
 | 
			
		||||
    private BiomeSelector biomeSelector;
 | 
			
		||||
    private TemperatureMapGenerator temperatureMapGenerator;
 | 
			
		||||
    private World world;
 | 
			
		||||
    private DepthFirstSearch dfs;
 | 
			
		||||
    private Biome mainBiome;
 | 
			
		||||
    private Biome shoreBiome;
 | 
			
		||||
    private float temperature;
 | 
			
		||||
    private DepthFirstSearch mapWideDFS;
 | 
			
		||||
    private DepthFirstSearch propagator;
 | 
			
		||||
    private LocalIslandPropagator propagatorInfo;
 | 
			
		||||
    CoordinateIdentifier chunkCoords;
 | 
			
		||||
    ChunkBiomes localChunkBiomes;
 | 
			
		||||
    
 | 
			
		||||
    private int chunkX, chunkZ;
 | 
			
		||||
    private Biome[][] chunkCache;
 | 
			
		||||
    float temperature;
 | 
			
		||||
 | 
			
		||||
    public BiomePerIslandGenerator() {
 | 
			
		||||
        this.temperatureMapGenerator = new TemperatureMapGenerator();
 | 
			
		||||
        chunkCache = new Biome[16][16];
 | 
			
		||||
        chunkBiomesCache = new Cache<>(1024);
 | 
			
		||||
        chunkGenStatusCache = new Cache<>(1024);
 | 
			
		||||
        propagatorInfo = new LocalIslandPropagator();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    @Override
 | 
			
		||||
    public void initialize(World world, IslandWorldMapper mapGenerator, BiomeSelector biomeSelector) {
 | 
			
		||||
    public void initialize(final World world, final IslandWorldMapper mapGenerator, final BiomeSelector biomeSelector) {
 | 
			
		||||
        if (initialized) throw new IllegalStateException("Biome generator already initialized.");
 | 
			
		||||
        initialized = true;
 | 
			
		||||
        this.islandLocator = mapGenerator;
 | 
			
		||||
        this.worldIslandMap = mapGenerator;
 | 
			
		||||
        this.biomeSelector = biomeSelector;
 | 
			
		||||
        this.world = world;
 | 
			
		||||
        this.temperatureMapGenerator.setSeed(world.getSeed());
 | 
			
		||||
        dfs = new DepthFirstSearch(2048, islandLocator);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean isCoordinateTarget(int x, int y) {
 | 
			
		||||
        //Should be ran for a island until finding biome info or until it looked for it's entirety and couldn't find it. This is one island.
 | 
			
		||||
 | 
			
		||||
        //First check if the chunk we're looking at is generated.
 | 
			
		||||
        if (world.isChunkGenerated(x/16, y/16)) {
 | 
			
		||||
            //If so, we know that the biomes have already been assigned, and can therefore use it.
 | 
			
		||||
            Biome foundBiome = world.getBiome(x, 0, y);
 | 
			
		||||
            if (islandLocator.isShore(x, y)) {
 | 
			
		||||
                this.shoreBiome = foundBiome;
 | 
			
		||||
            } else {
 | 
			
		||||
                this.mainBiome = foundBiome;
 | 
			
		||||
            }
 | 
			
		||||
            if (mainBiome != null && shoreBiome != null) {
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        } else
 | 
			
		||||
        
 | 
			
		||||
        //If the same chunk, then do the same thing, except use the chunk biome cache instead to look for it.
 | 
			
		||||
        if (x/16 == chunkX && y/16 == chunkZ) {
 | 
			
		||||
            Biome foundBiome = chunkCache[Math.abs(x % 16)][Math.abs(y % 16)];
 | 
			
		||||
            if (foundBiome == null) return false;
 | 
			
		||||
            if (islandLocator.isShore(x, y)) {
 | 
			
		||||
                this.shoreBiome = foundBiome;
 | 
			
		||||
            } else {
 | 
			
		||||
                this.mainBiome = foundBiome;
 | 
			
		||||
            }
 | 
			
		||||
            if (mainBiome != null && shoreBiome != null) {
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Biome GenerateBiome(int chunkX, int chunkZ, int localX, int localZ) {
 | 
			
		||||
        int worldX = chunkX * 16 + localX;
 | 
			
		||||
        int worldZ = chunkZ * 16 + localZ;
 | 
			
		||||
 | 
			
		||||
        //Clear chunk cache if different chunk
 | 
			
		||||
        if (chunkX != this.chunkX || chunkZ != this.chunkZ) {
 | 
			
		||||
            this.chunkX = chunkX;
 | 
			
		||||
            this.chunkZ = chunkZ;
 | 
			
		||||
            for (int i = 0; i < chunkCache.length; i++) {
 | 
			
		||||
                Arrays.fill(chunkCache[i], null);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (islandLocator.isIsland(worldX, worldZ)) {
 | 
			
		||||
            if (mainBiome == null && shoreBiome == null) {
 | 
			
		||||
                dfs.setStartPosition(worldX, worldZ);
 | 
			
		||||
                if (!dfs.findTarget(this)) {
 | 
			
		||||
                    temperature = temperatureMapGenerator.getTemperature(worldX, worldZ);
 | 
			
		||||
                    mainBiome = biomeSelector.getLandBiome(temperature);
 | 
			
		||||
                    shoreBiome = biomeSelector.getShoreBiome(mainBiome, temperature);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            mainBiome = null;
 | 
			
		||||
            shoreBiome = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        Biome designatedBiome = mainBiome;
 | 
			
		||||
        if (mainBiome == null) {
 | 
			
		||||
            designatedBiome = biomeSelector.getOceanBiome(temperatureMapGenerator.getTemperature(worldX, worldZ));
 | 
			
		||||
        } else if (islandLocator.isShore(worldX, worldZ)) {
 | 
			
		||||
                designatedBiome = shoreBiome;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        chunkCache[localX][localZ] = designatedBiome;
 | 
			
		||||
        return designatedBiome;
 | 
			
		||||
        mapWideDFS = new DepthFirstSearch(worldIslandMap);
 | 
			
		||||
        mapWideDFS.setEndPosition(0, 0);
 | 
			
		||||
        propagator = new DepthFirstSearch(256, this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public IslandBiomeGenerator getInstance() {
 | 
			
		||||
        return new BiomePerIslandGenerator();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @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);
 | 
			
		||||
        }
 | 
			
		||||
        int worldX = 16 * chunkX + localX;
 | 
			
		||||
        int worldZ = 16 * chunkZ + localZ;
 | 
			
		||||
 | 
			
		||||
        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);
 | 
			
		||||
        }
 | 
			
		||||
        if (localChunkBiomes.biomes[localX][localZ] == null) {
 | 
			
		||||
            localChunkBiomes.biomes[localX][localZ] = biomeSelector.getOceanBiome(temperature);
 | 
			
		||||
            return biomeSelector.getOceanBiome(temperature);
 | 
			
		||||
        }
 | 
			
		||||
        return localChunkBiomes.biomes[localX][localZ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @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;
 | 
			
		||||
        int localX = Math.abs(worldX % 16);
 | 
			
		||||
        int localZ = Math.abs(worldZ % 16);
 | 
			
		||||
 | 
			
		||||
        Identifier chunkBiomeID = new CoordinateIdentifier(chunkX, chunkZ);
 | 
			
		||||
        Identifier chunkGenID = new CoordinateIdentifier(chunkX, chunkZ);
 | 
			
		||||
 | 
			
		||||
        CacheValue<ChunkBiomes> chunkBiomeVal = chunkBiomesCache.retrieveCache(chunkBiomeID);
 | 
			
		||||
        CacheValue<Boolean> 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);
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private class ChunkBiomes {
 | 
			
		||||
        public final Biome[][] biomes = new Biome[16][16];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private class LocalIslandPropagator implements CoordinateTargetValidatable {
 | 
			
		||||
        public Biome mainBiome = null;
 | 
			
		||||
        public Biome shoreBiome = null;
 | 
			
		||||
        public Biome shallowBiome = null;
 | 
			
		||||
 | 
			
		||||
        @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;
 | 
			
		||||
                } else {
 | 
			
		||||
                    localChunkBiomes.biomes[localX][localZ] = mainBiome;
 | 
			
		||||
                }
 | 
			
		||||
            } else if (worldIslandMap.isShallowPortion(x, y)) {
 | 
			
		||||
                localChunkBiomes.biomes[localX][localZ] = shallowBiome;
 | 
			
		||||
            }
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user