diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 3fa80cf2d..50b07f269 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -2,7 +2,6 @@ - \ No newline at end of file diff --git a/pom.xml b/pom.xml index adf80f72f..db584e1d5 100644 --- a/pom.xml +++ b/pom.xml @@ -95,7 +95,7 @@ org.polydev gaea - 1.10.0 + 1.10.5 javax.vecmath diff --git a/src/main/java/com/dfsek/terra/Terra.java b/src/main/java/com/dfsek/terra/Terra.java index bcb0605e2..91dd31f35 100644 --- a/src/main/java/com/dfsek/terra/Terra.java +++ b/src/main/java/com/dfsek/terra/Terra.java @@ -1,10 +1,7 @@ package com.dfsek.terra; import com.dfsek.terra.config.ConfigUtil; -import com.mojang.brigadier.arguments.BoolArgumentType; -import com.mojang.brigadier.arguments.StringArgumentType; -import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import com.mojang.brigadier.builder.RequiredArgumentBuilder; +import com.dfsek.terra.generation.TerraChunkGenerator; import com.mojang.brigadier.tree.LiteralCommandNode; import me.lucko.commodore.Commodore; import me.lucko.commodore.CommodoreProvider; diff --git a/src/main/java/com/dfsek/terra/TerraCommand.java b/src/main/java/com/dfsek/terra/TerraCommand.java index 0f00152cf..5ef14cee6 100644 --- a/src/main/java/com/dfsek/terra/TerraCommand.java +++ b/src/main/java/com/dfsek/terra/TerraCommand.java @@ -6,8 +6,10 @@ import com.dfsek.terra.config.ConfigUtil; import com.dfsek.terra.config.WorldConfig; import com.dfsek.terra.config.genconfig.BiomeConfig; import com.dfsek.terra.config.genconfig.OreConfig; +import com.dfsek.terra.generation.TerraChunkGenerator; import com.dfsek.terra.image.WorldImageGenerator; import com.dfsek.terra.structure.GaeaStructure; +import com.dfsek.terra.structure.StructureSpawn; import com.sk89q.worldedit.IncompleteRegionException; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.WorldEditPlugin; @@ -20,6 +22,7 @@ import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.bukkit.command.TabExecutor; import org.bukkit.entity.Player; +import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; import org.polydev.gaea.profiler.WorldProfiler; @@ -170,6 +173,9 @@ public class TerraCommand implements CommandExecutor, TabExecutor { sender.sendMessage("Structure not found."); } return true; + } else if("getspawn".equals(args[1])) { + Vector v = new StructureSpawn(50, 25).getNearestSpawn(pl.getLocation().getBlockX(), pl.getLocation().getBlockZ(), pl.getWorld().getSeed()); + sender.sendMessage(v.getBlockX() + ":" + v.getBlockZ()); } } } catch(ArrayIndexOutOfBoundsException e) { diff --git a/src/main/java/com/dfsek/terra/TerraProfiler.java b/src/main/java/com/dfsek/terra/TerraProfiler.java index 242fd0fe8..7d78eadd6 100644 --- a/src/main/java/com/dfsek/terra/TerraProfiler.java +++ b/src/main/java/com/dfsek/terra/TerraProfiler.java @@ -1,5 +1,6 @@ package com.dfsek.terra; +import com.dfsek.terra.generation.TerraChunkGenerator; import org.bukkit.World; import org.polydev.gaea.profiler.DataType; import org.polydev.gaea.profiler.Measurement; diff --git a/src/main/java/com/dfsek/terra/config/genconfig/AbstractBiomeConfig.java b/src/main/java/com/dfsek/terra/config/genconfig/AbstractBiomeConfig.java index 99a467eee..290cff977 100644 --- a/src/main/java/com/dfsek/terra/config/genconfig/AbstractBiomeConfig.java +++ b/src/main/java/com/dfsek/terra/config/genconfig/AbstractBiomeConfig.java @@ -5,6 +5,7 @@ import com.dfsek.terra.TerraTree; import com.dfsek.terra.config.ConfigUtil; import com.dfsek.terra.config.TerraConfigObject; import org.bukkit.Bukkit; +import org.bukkit.Material; import org.bukkit.block.data.BlockData; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.InvalidConfigurationException; @@ -40,6 +41,10 @@ public class AbstractBiomeConfig extends TerraConfigObject { private int floraAttempts; private Map floraHeights; private TreeMap> paletteMap; + private double slabThreshold; + private Map> slabs; + private Map> stairs; + private boolean useStairs; public AbstractBiomeConfig(File file) throws IOException, InvalidConfigurationException { super(file); @@ -146,6 +151,17 @@ public class AbstractBiomeConfig extends TerraConfigObject { } } + // Get slab stuff + useStairs = false; + if(contains("slabs") && getBoolean("slabs.enable", false)) { + slabThreshold = getDouble("slabs.threshold", 0.1D); + slabs = BiomeConfigUtil.getSlabPalettes(getMapList("slabs.palettes"), this); + if(contains("slabs.stair-palettes") && getBoolean("slabs.use-stairs-if-available", false)) { + stairs = BiomeConfigUtil.getSlabPalettes(getMapList("slabs.stair-palettes"), this); + useStairs = true; + } + } + biomes.put(biomeID, this); } @@ -209,4 +225,20 @@ public class AbstractBiomeConfig extends TerraConfigObject { public static AbstractBiomeConfig fromID(String id) { return biomes.get(id); } + + public Map> getSlabs() { + return slabs; + } + + public double getSlabThreshold() { + return slabThreshold; + } + + public Map> getStairs() { + return stairs; + } + + public boolean shouldUseStairs() { + return useStairs; + } } diff --git a/src/main/java/com/dfsek/terra/config/genconfig/BiomeConfig.java b/src/main/java/com/dfsek/terra/config/genconfig/BiomeConfig.java index b2a031aab..9fe9903cb 100644 --- a/src/main/java/com/dfsek/terra/config/genconfig/BiomeConfig.java +++ b/src/main/java/com/dfsek/terra/config/genconfig/BiomeConfig.java @@ -9,7 +9,9 @@ import com.dfsek.terra.carving.UserDefinedCarver; import com.dfsek.terra.config.ConfigUtil; import com.dfsek.terra.config.TerraConfigObject; import org.bukkit.Bukkit; +import org.bukkit.Material; import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.type.Stairs; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.InvalidConfigurationException; import org.polydev.gaea.math.ProbabilityCollection; @@ -26,6 +28,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Objects; @@ -43,6 +46,9 @@ public class BiomeConfig extends TerraConfigObject { private Map floraHeights; private String eq; private int floraAttempts; + private Map> slabs; + private Map> stairs; + private double slabThreshold; public BiomeConfig(File file) throws InvalidConfigurationException, IOException { super(file); @@ -126,12 +132,14 @@ public class BiomeConfig extends TerraConfigObject { // Get various simple values using getOrDefault config methods. try { + slabThreshold = getDouble("slabs.threshold", Objects.requireNonNull(abstractBiome).getSlabThreshold()); floraChance = getInt("flora-chance", Objects.requireNonNull(abstractBiome).getFloraChance()); floraAttempts = getInt("flora-attempts", Objects.requireNonNull(abstractBiome).getFloraAttempts()); treeChance = getInt("tree-chance", Objects.requireNonNull(abstractBiome).getTreeChance()); treeDensity = getInt("tree-density", Objects.requireNonNull(abstractBiome).getTreeDensity()); eq = getString("noise-equation", Objects.requireNonNull(abstractBiome).getEquation()); } catch(NullPointerException e) { + slabThreshold = getDouble("slabs.threshold", 0.1D); floraChance = getInt("flora-chance", 0); floraAttempts = getInt("flora-attempts", 1); treeChance = getInt("tree-chance", 0); @@ -221,6 +229,39 @@ public class BiomeConfig extends TerraConfigObject { oreHeights = new HashMap<>(); } + + // Get slab stuff + if(contains("slabs") && getBoolean("slabs.enable", false)) { + if(extending && abstractBiome.getSlabs() != null) { + slabs = abstractBiome.getSlabs(); + if(abstractBiome.shouldUseStairs()) { + stairs = abstractBiome.getStairs(); + } + Bukkit.getLogger().info("Using super slabs"); + } else { + slabs = BiomeConfigUtil.getSlabPalettes(getMapList("slabs.palettes"), this); + if(contains("slabs.stair-palettes") && getBoolean("slabs.use-stairs-if-available", false)) { + stairs = BiomeConfigUtil.getSlabPalettes(getMapList("slabs.stair-palettes"), this); + } else stairs = new HashMap<>(); + } + for(Map.Entry> p : stairs.entrySet()) { + try { + for(Palette.PaletteLayer l : p.getValue().getLayers()) { + Iterator i = l.getCollection().iterator(); + while(i.hasNext()) { + Stairs s = (Stairs) ((ProbabilityCollection.ProbabilitySetElement) i.next()).getObject(); + Bukkit.getLogger().info("Stair added: " + s.getAsString()); + } + + } + } catch(ClassCastException e) { + if(ConfigUtil.debug) e.printStackTrace(); + throw new InvalidConfigurationException("Material in stair config is not stair."); + } + } + Bukkit.getLogger().info("[Terra] Slabs: " + slabs.size()); + } + try { // Get UserDefinedBiome instance representing this config. this.biome = new UserDefinedBiome(vanillaBiome, dec, new UserDefinedGenerator(eq, Collections.emptyList(), paletteMap), biomeID); @@ -285,4 +326,16 @@ public class BiomeConfig extends TerraConfigObject { public int getCarverChance(UserDefinedCarver c) { return carvers.getOrDefault(CarverConfig.fromDefinedCarver(c), 0); } + + public double getSlabThreshold() { + return slabThreshold; + } + + public Map> getStairs() { + return stairs; + } + + public Map> getSlabs() { + return slabs; + } } diff --git a/src/main/java/com/dfsek/terra/config/genconfig/BiomeConfigUtil.java b/src/main/java/com/dfsek/terra/config/genconfig/BiomeConfigUtil.java new file mode 100644 index 000000000..e48681d46 --- /dev/null +++ b/src/main/java/com/dfsek/terra/config/genconfig/BiomeConfigUtil.java @@ -0,0 +1,48 @@ +package com.dfsek.terra.config.genconfig; + +import com.dfsek.terra.config.TerraConfigObject; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.block.data.BlockData; +import org.bukkit.configuration.InvalidConfigurationException; +import org.polydev.gaea.math.ProbabilityCollection; +import org.polydev.gaea.world.palette.Palette; +import org.polydev.gaea.world.palette.RandomPalette; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; + +public class BiomeConfigUtil { + public static Map> getSlabPalettes(List> paletteConfigSection, TerraConfigObject config) throws InvalidConfigurationException { + Map> paletteMap = new HashMap<>(); + + for(Map e : paletteConfigSection) { + for(Map.Entry entry : e.entrySet()) { + try { + if(((String) entry.getValue()).startsWith("BLOCK:")) { + try { + Bukkit.getLogger().info("Adding slab palette with single material " + entry.getKey()); + paletteMap.put(Bukkit.createBlockData((String) entry.getKey()).getMaterial(), new RandomPalette(new Random(0)).add(new ProbabilityCollection().add(Bukkit.createBlockData(((String) entry.getValue()).substring(6)), 1), 1)); + } catch(IllegalArgumentException ex) { + throw new InvalidConfigurationException("SEVERE configuration error for Slab Palettes in biome " + config.getID() + ": " + ex.getMessage()); + } + } else { + try { + Palette p = PaletteConfig.fromID((String) entry.getValue()).getPalette(); + if(p.getSize() != 1) throw new InvalidConfigurationException("Slab palette must hold only one layer. Palette " + entry.getValue() + " is too large/small"); + paletteMap.put(Bukkit.createBlockData((String) entry.getKey()).getMaterial(), p); + } catch(NullPointerException ex) { + throw new InvalidConfigurationException("SEVERE configuration error for Slab Palettes in biome " + config.getID() + "\n\nPalette " + entry.getValue() + " cannot be found!"); + } + } + } catch(ClassCastException ex) { + throw new InvalidConfigurationException("SEVERE configuration error for Slab Palettes in biome " + config.getID()); + } + } + } + Bukkit.getLogger().info("Adding " + paletteMap.size() + " slab palettes..."); + return paletteMap; + } +} diff --git a/src/main/java/com/dfsek/terra/generation/SlabGenerator.java b/src/main/java/com/dfsek/terra/generation/SlabGenerator.java new file mode 100644 index 000000000..3878c4bfd --- /dev/null +++ b/src/main/java/com/dfsek/terra/generation/SlabGenerator.java @@ -0,0 +1,85 @@ +package com.dfsek.terra.generation; + +import com.dfsek.terra.biome.TerraBiomeGrid; +import com.dfsek.terra.biome.UserDefinedBiome; +import com.dfsek.terra.config.genconfig.BiomeConfig; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.BlockFace; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.type.Stairs; +import org.bukkit.generator.ChunkGenerator; +import org.bukkit.util.Vector; +import org.polydev.gaea.generation.GenerationPopulator; +import org.polydev.gaea.math.ChunkInterpolator; +import org.polydev.gaea.world.palette.Palette; +import org.polydev.gaea.world.palette.RandomPalette; + +import java.util.Map; +import java.util.Random; + +public class SlabGenerator extends GenerationPopulator { + private static final BlockData AIR = Material.AIR.createBlockData(); + private static final Palette AIRPALETTE = new RandomPalette(new Random(2403)).add(AIR, 1); + @Override + public ChunkGenerator.ChunkData populate(World world, ChunkGenerator.ChunkData chunk, Random random, int chunkX, int chunkZ, ChunkInterpolator interp) { + TerraBiomeGrid g = TerraBiomeGrid.fromWorld(world); + for(byte x = 0; x < 16; x++) { + for(byte z = 0; z < 16; z++) { + int xi = (chunkX << 4) + x; + int zi = (chunkZ << 4) + z; + BiomeConfig config = BiomeConfig.fromBiome((UserDefinedBiome) g.getBiome(xi, zi)); + if(config.getSlabs() == null) continue; + double thresh = config.getSlabThreshold(); + for(int y = 0; y < world.getMaxHeight(); y++) { + if(chunk.getType(x, y, z).isSolid()) continue; + prepareBlockPart(interp, chunk, new Vector(x, y, z), config.getSlabs(), config.getStairs(), thresh); + } + } + } + return chunk; + } + private static void prepareBlockPart(ChunkInterpolator interp, ChunkGenerator.ChunkData chunk, Vector block, Map> slabs, Map> stairs, double thresh) { + BlockData down = chunk.getBlockData(block.getBlockX(), block.getBlockY()-1, block.getBlockZ()); + double _11 = interp.getNoise(block.getBlockX(), block.getBlockY() - 0.5, block.getBlockZ()); + if(_11 > thresh) { + double _00 = interp.getNoise(block.getBlockX() - 0.5, block.getBlockY(), block.getBlockZ() - 0.5); + double _01 = interp.getNoise(block.getBlockX() - 0.5, block.getBlockY(), block.getBlockZ()); + double _02 = interp.getNoise(block.getBlockX() - 0.5, block.getBlockY(), block.getBlockZ() + 0.5); + double _10 = interp.getNoise(block.getBlockX(), block.getBlockY(), block.getBlockZ() - 0.5); + double _12 = interp.getNoise(block.getBlockX(), block.getBlockY(), block.getBlockZ() + 0.5); + double _20 = interp.getNoise(block.getBlockX() + 0.5, block.getBlockY(), block.getBlockZ() - 0.5); + double _21 = interp.getNoise(block.getBlockX() + 0.5, block.getBlockY(), block.getBlockZ()); + double _22 = interp.getNoise(block.getBlockX() + 0.5, block.getBlockY(), block.getBlockZ() + 0.5); + + if(stairs != null) { + Palette stairPalette = stairs.get(down.getMaterial()); + if(stairPalette != null) { + BlockData stair = stairPalette.get(0, block.getBlockX(), block.getBlockZ()); + Stairs finalStair = getStair(new double[] {_00, _01, _02, _10, _12, _20, _21, _22}, (Stairs) stair, thresh); + if(finalStair != null) { + chunk.setBlock(block.getBlockX(), block.getBlockY(), block.getBlockZ(), finalStair); + return; + } + } + } + chunk.setBlock(block.getBlockX(), block.getBlockY(), block.getBlockZ(), slabs.getOrDefault(down.getMaterial(), AIRPALETTE).get(0, block.getBlockX(), block.getBlockZ())); + } + } + + private static Stairs getStair(double[] vals, Stairs stair, double thresh) { + if(vals.length != 8) throw new IllegalArgumentException(); + Stairs stairNew = (Stairs) stair.clone(); + if(vals[1] > thresh) { + stairNew.setFacing(BlockFace.WEST); + } else if(vals[3] > thresh) { + stairNew.setFacing(BlockFace.NORTH); + } else if(vals[4] > thresh) { + stairNew.setFacing(BlockFace.SOUTH); + } else if(vals[6] > thresh) { + stairNew.setFacing(BlockFace.EAST); + } else return null; + return stairNew; + } +} diff --git a/src/main/java/com/dfsek/terra/TerraChunkGenerator.java b/src/main/java/com/dfsek/terra/generation/TerraChunkGenerator.java similarity index 92% rename from src/main/java/com/dfsek/terra/TerraChunkGenerator.java rename to src/main/java/com/dfsek/terra/generation/TerraChunkGenerator.java index 21a785898..fe077d539 100644 --- a/src/main/java/com/dfsek/terra/TerraChunkGenerator.java +++ b/src/main/java/com/dfsek/terra/generation/TerraChunkGenerator.java @@ -1,4 +1,4 @@ -package com.dfsek.terra; +package com.dfsek.terra.generation; import com.dfsek.terra.biome.TerraBiomeGrid; import com.dfsek.terra.config.WorldConfig; @@ -6,6 +6,7 @@ import com.dfsek.terra.population.CavePopulator; import com.dfsek.terra.population.FloraPopulator; import com.dfsek.terra.population.OrePopulator; import com.dfsek.terra.population.TreePopulator; +import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.data.BlockData; @@ -38,8 +39,8 @@ public class TerraChunkGenerator extends GaeaChunkGenerator { ChunkData chunk = createChunkData(world); int sea = WorldConfig.fromWorld(world).seaLevel; for(byte x = 0; x < 16; x++) { - for(int y = 0; y < 256; y++) { - for(byte z = 0; z < 16; z++) { + for(byte z = 0; z < 16; z++) { + for(int y = 0; y < 256; y++) { if(super.getInterpolatedNoise(x, y, z) > 0) chunk.setBlock(x, y, z, STONE); else if(y < sea) chunk.setBlock(x, y, z, WATER); } @@ -59,7 +60,7 @@ public class TerraChunkGenerator extends GaeaChunkGenerator { @Override public List getGenerationPopulators(World world) { - return Collections.emptyList(); + return Collections.singletonList(new SlabGenerator()); } diff --git a/src/main/java/com/dfsek/terra/image/DebugFrame.java b/src/main/java/com/dfsek/terra/image/DebugFrame.java index cbead300f..8f782c84b 100644 --- a/src/main/java/com/dfsek/terra/image/DebugFrame.java +++ b/src/main/java/com/dfsek/terra/image/DebugFrame.java @@ -1,7 +1,6 @@ package com.dfsek.terra.image; -import com.dfsek.terra.Terra; -import com.dfsek.terra.TerraChunkGenerator; +import com.dfsek.terra.generation.TerraChunkGenerator; import com.dfsek.terra.biome.TerraBiomeGrid; import com.dfsek.terra.biome.UserDefinedBiome; import com.dfsek.terra.config.WorldConfig; diff --git a/src/main/java/com/dfsek/terra/structure/StructureSpawn.java b/src/main/java/com/dfsek/terra/structure/StructureSpawn.java new file mode 100644 index 000000000..bdf61c18a --- /dev/null +++ b/src/main/java/com/dfsek/terra/structure/StructureSpawn.java @@ -0,0 +1,45 @@ +package com.dfsek.terra.structure; + +import com.dfsek.terra.config.ConfigUtil; +import org.bukkit.Bukkit; +import org.bukkit.util.Vector; +import org.polydev.gaea.math.MathUtil; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +public class StructureSpawn { + private final int separation; + private final int width; + public StructureSpawn(int width, int separation) { + this.separation = separation; + this.width = width; + } + public Vector getNearestSpawn(int x, int z, long seed) { + int structureChunkX = x / (width + 2*separation); + int structureChunkZ = z / (width + 2*separation); + List zones = new ArrayList<>(); + for(int xi = structureChunkX-1; xi <= structureChunkX+1; xi++) { + for(int zi = structureChunkZ-1; zi <= structureChunkZ+1; zi++) { + zones.add(getStructureChunkSpawn(xi, zi, seed)); + } + } + Vector shortest = zones.get(0); + Vector compare = new Vector(x, 0, z); + for(Vector v : zones) { + if(compare.distanceSquared(shortest) > compare.distanceSquared(v)) shortest = v.clone(); + } + return shortest; + } + private Vector getStructureChunkSpawn(int structureChunkX, int structureChunkZ, long seed) { + if(ConfigUtil.debug) Bukkit.getLogger().info("Structure chunk: " + structureChunkX + ":" + structureChunkZ); + Random r = new Random(MathUtil.getCarverChunkSeed(structureChunkX, structureChunkZ, seed)); + int offsetX = r.nextInt(width); + int offsetZ = r.nextInt(width); + int sx = structureChunkX * (width + 2*separation) + offsetX; + int sz = structureChunkZ * (width + 2*separation) + offsetZ; + if(ConfigUtil.debug) Bukkit.getLogger().info("Structure coords: " + sx + ":" + sz); + return new Vector(sx, 0, sz); + } +} diff --git a/src/main/resources/terra.commodore b/src/main/resources/terra.commodore index 65c37ca8d..5d424a106 100644 --- a/src/main/resources/terra.commodore +++ b/src/main/resources/terra.commodore @@ -33,5 +33,6 @@ terra { respect_chunk brigadier:bool; } } + getspawn; } } \ No newline at end of file