Implement BiomeConfig, BiomeGridConfig, and PaletteConfig.

This commit is contained in:
dfsek 2020-09-09 20:14:12 -07:00
parent c5dc13f514
commit 98b1dc0e85
15 changed files with 506 additions and 61 deletions

View File

@ -83,7 +83,7 @@
<dependency>
<groupId>org.polydev</groupId>
<artifactId>gaea</artifactId>
<version>1.1.2</version>
<version>1.1.3</version>
</dependency>
</dependencies>

View File

@ -1,13 +1,75 @@
package com.dfsek.terra;
import com.dfsek.terra.config.ConfigUtil;
import com.dfsek.terra.config.WorldConfig;
import com.dfsek.terra.math.NoiseFunction2;
import com.dfsek.terra.math.NoiseFunction3;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.polydev.gaea.math.parsii.eval.Expression;
import org.polydev.gaea.math.parsii.eval.Function;
import org.polydev.gaea.math.parsii.eval.Parser;
import java.util.List;
public class Terra extends JavaPlugin {
static {
Parser.registerFunction("floor", new Function() {
@Override
public int getNumberOfArguments() {
return 1;
}
@Override
public double eval(List<Expression> list) {
return Math.floor(list.get(0).evaluate());
}
@Override
public boolean isNaturalFunction() {
return true;
}
});
Parser.registerFunction("ceil", new Function() {
@Override
public int getNumberOfArguments() {
return 1;
}
@Override
public double eval(List<Expression> list) {
return Math.ceil(list.get(0).evaluate());
}
@Override
public boolean isNaturalFunction() {
return true;
}
});
Parser.registerFunction("round", new Function() {
@Override
public int getNumberOfArguments() {
return 1;
}
@Override
public double eval(List<Expression> list) {
return Math.round(list.get(0).evaluate());
}
@Override
public boolean isNaturalFunction() {
return true;
}
});
Parser.registerFunction("noise2", new NoiseFunction2());
Parser.registerFunction("noise3", new NoiseFunction3());
}
private static FileConfiguration config;
private static Terra instance;
@ -22,9 +84,11 @@ public class Terra extends JavaPlugin {
@Override
public void onEnable() {
super.onEnable();
ConfigUtil.loadConfig(this);
getCommand("terra").setExecutor(new TerraCommand());
saveDefaultConfig();
config = getConfig();
instance = this;
}
@NotNull

View File

@ -20,12 +20,25 @@ public class TerraChunkGenerator extends GaeaChunkGenerator {
super(InterpolationType.TRILINEAR);
}
public ChunkData generateBase(@NotNull World world, @NotNull Random random, int i, int i1, FastNoise fastNoise) {
public ChunkData generateBase(@NotNull World world, @NotNull Random random, int chunkX, int chunkZ, FastNoise fastNoise) {
ChunkData chunk = createChunkData(world);
for(byte x = 0; x < 16; x++) {
for(int y = 0; y < 256; y++) {
for(byte z = 0; z < 16; z++) {
if(super.getInterpolatedNoise(x, y, z) > 0.5) chunk.setBlock(x, y, z, Material.STONE);
if(super.getInterpolatedNoise(x, y, z) > 0) chunk.setBlock(x, y, z, Material.STONE);
}
}
}
for(byte x = 0; x < 16; x++) {
for(byte z = 0; z < 16; z++) {
int paletteLevel = 0;
for(int y = world.getMaxHeight()-1; y > 0; y--) {
if(chunk.getType(x, y, z).isAir()){
paletteLevel = 0;
continue;
}
chunk.setBlock(x, y, z, TerraBiomeGrid.fromWorld(world).getBiome((chunkX << 4) + x, (chunkZ << 4) + z).getGenerator().getPalette().get(paletteLevel, random));
paletteLevel++;
}
}
}
@ -45,6 +58,6 @@ public class TerraChunkGenerator extends GaeaChunkGenerator {
}
public org.polydev.gaea.biome.BiomeGrid getBiomeGrid(World world) {
return new TerraBiomeGrid(world);
return TerraBiomeGrid.fromWorld(world);
}
}

View File

@ -0,0 +1,28 @@
package com.dfsek.terra;
import com.dfsek.terra.biome.TerraBiomeGrid;
import com.dfsek.terra.biome.UserDefinedBiome;
import com.dfsek.terra.config.ConfigUtil;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public class TerraCommand implements CommandExecutor {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if(args.length == 1) {
switch(args[0]) {
case "reload":
ConfigUtil.loadConfig(Terra.getInstance());
sender.sendMessage("Reloaded Terra config.");
break;
case "biome":
if(!(sender instanceof Player)) return false;
sender.sendMessage("You are in " + ((UserDefinedBiome) TerraBiomeGrid.fromWorld(((Player) sender).getWorld()).getBiome(((Player) sender).getLocation())).getConfig().getFriendlyName());
}
}
return true;
}
}

View File

@ -1,20 +1,17 @@
package com.dfsek.terra.biome;
import com.dfsek.terra.Terra;
import com.dfsek.terra.config.ConfigUtil;
import com.dfsek.terra.config.WorldConfig;
import org.bukkit.World;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.polydev.gaea.biome.BiomeGrid;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
public class TerraBiomeGrid extends BiomeGrid {
private UserDefinedBiome[][] grid;
private static final Map<World, TerraBiomeGrid> grids = new HashMap<>();
private final UserDefinedBiome[][] grid;
private final World w;
public TerraBiomeGrid(World w) {
@ -22,15 +19,21 @@ public class TerraBiomeGrid extends BiomeGrid {
this.w = w;
grid = new UserDefinedBiome[16][16];
load();
grids.put(w, this);
}
public void load() {
for(int x = 0; x < 16; x++) {
for(int z = 0; z < 16; z++) {
WorldConfig.fromWorld(w);
grid[x][z] = WorldConfig.getBiomes().get(WorldConfig.fromWorld(w).biomeGrid.get(x).get(z)).getBiome();
}
}
super.setGrid(grid);
super.setGrid(WorldConfig.fromWorld(w).biomeGrid.getBiomeGrid());
}
public static TerraBiomeGrid fromWorld(World w) {
if(grids.containsKey(w)) return grids.get(w);
else return new TerraBiomeGrid(w);
}
public static void reloadAll() {
for(Map.Entry<World, TerraBiomeGrid> e : grids.entrySet()) {
e.getValue().load();
}
}
}

View File

@ -1,5 +1,7 @@
package com.dfsek.terra.biome;
import com.dfsek.terra.config.BiomeConfig;
import com.dfsek.terra.config.ConfigUtil;
import org.bukkit.configuration.file.FileConfiguration;
import org.polydev.gaea.biome.Biome;
import org.polydev.gaea.biome.BiomeTerrain;
@ -11,12 +13,19 @@ import org.polydev.gaea.structures.features.Feature;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
public class UserDefinedBiome implements Biome {
private final UserDefinedGenerator gen;
public UserDefinedBiome(String noiseEq) throws ParseException {
private final BiomeConfig config;
public UserDefinedBiome(BiomeConfig config) throws ParseException {
this.config = config;
Scope s = Scope.create();
gen = new UserDefinedGenerator(s, Parser.parse(noiseEq, s), Collections.emptyList());
gen = new UserDefinedGenerator(s, Parser.parse(Objects.requireNonNull(config.getString("noise-equation")), s), Collections.emptyList(), ConfigUtil.getPalette(config.getString("palette")).getPalette());
}
public BiomeConfig getConfig() {
return config;
}
/**

View File

@ -1,5 +1,7 @@
package com.dfsek.terra.biome;
import com.dfsek.terra.math.NoiseFunction2;
import com.dfsek.terra.math.NoiseFunction3;
import org.polydev.gaea.biome.BiomeTerrain;
import org.polydev.gaea.math.FastNoise;
import org.polydev.gaea.math.parsii.eval.Expression;
@ -15,18 +17,16 @@ public class UserDefinedGenerator extends BiomeTerrain {
private final Variable xVar;
private final Variable yVar;
private final Variable zVar;
private final Variable noise2D;
private final Variable noise3D;
private final BlockPalette p;
public UserDefinedGenerator(Scope s, Expression e, List<Variable> v) {
public UserDefinedGenerator(Scope s, Expression e, List<Variable> v, BlockPalette p) {
this.noiseExp = e;
this.vars = v;
this.p = p;
this.xVar = s.getVariable("x");
this.yVar = s.getVariable("y");
this.zVar = s.getVariable("z");
this.noise2D = s.getVariable("w");
this.noise3D = s.getVariable("t");
}
/**
* Gets the 2D noise at a pair of coordinates using the provided FastNoise instance.
@ -41,8 +41,8 @@ public class UserDefinedGenerator extends BiomeTerrain {
xVar.setValue(x);
yVar.setValue(0);
zVar.setValue(z);
noise2D.setValue(gen.getSimplexFractal(x, z));
noise3D.setValue(0);
NoiseFunction2.setNoise(gen);
NoiseFunction3.setNoise(gen);
return noiseExp.evaluate();
}
@ -60,8 +60,8 @@ public class UserDefinedGenerator extends BiomeTerrain {
xVar.setValue(x);
yVar.setValue(y);
zVar.setValue(z);
noise2D.setValue(gen.getSimplexFractal(x, z));
noise3D.setValue(gen.getSimplexFractal(x, y, z));
NoiseFunction2.setNoise(gen);
NoiseFunction3.setNoise(gen);
return noiseExp.evaluate();
}
@ -72,6 +72,6 @@ public class UserDefinedGenerator extends BiomeTerrain {
*/
@Override
public BlockPalette getPalette() {
return null;
return p;
}
}

View File

@ -1,26 +1,47 @@
package com.dfsek.terra.config;
import com.dfsek.terra.biome.UserDefinedBiome;
import org.bukkit.Bukkit;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull;
import org.polydev.gaea.math.parsii.tokenizer.ParseException;
import java.io.File;
import java.io.IOException;
public class BiomeConfig extends YamlConfiguration {
private final UserDefinedBiome biome;
private final String biomeID;
private final String friendlyName;
public BiomeConfig(File file) throws InvalidConfigurationException, ParseException, IOException {
private UserDefinedBiome biome;
private String biomeID;
private String friendlyName;
private boolean isEnabled = false;
public BiomeConfig(File file) throws InvalidConfigurationException, IOException {
super();
load(file);
}
@Override
public void load(@NotNull File file) throws InvalidConfigurationException, IOException {
isEnabled = false;
super.load(file);
if(!contains("noise-equation")) throw new InvalidConfigurationException("No noise equation included in biome!");
this.biome = new UserDefinedBiome(getString("noise-equation"));
try {
this.biome = new UserDefinedBiome(this);
} catch(ParseException e) {
e.printStackTrace();
Bukkit.getLogger().severe("Unable to parse noise equation!");
}
if(!contains("id")) throw new InvalidConfigurationException("Biome ID unspecified!");
this.biomeID = getString("id");
if(!contains("name")) throw new InvalidConfigurationException("Biome Name unspecified!");
this.friendlyName = getString("name");
isEnabled = true;
}
public boolean isEnabled() {
return isEnabled;
}
public UserDefinedBiome getBiome() {

View File

@ -0,0 +1,59 @@
package com.dfsek.terra.config;
import com.dfsek.terra.biome.UserDefinedBiome;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull;
import org.polydev.gaea.biome.BiomeGrid;
import java.io.File;
import java.io.IOException;
import java.util.List;
public class BiomeGridConfig extends YamlConfiguration {
private String gridID;
private String friendlyName;
private boolean isEnabled = false;
private final UserDefinedBiome[][] grid = new UserDefinedBiome[16][16];
public BiomeGridConfig(File file) throws IOException, InvalidConfigurationException {
super();
load(file);
}
@Override
public void load(@NotNull File file) throws IOException, InvalidConfigurationException {
isEnabled = false;
super.load(file);
if(!contains("grid")) throw new InvalidConfigurationException("Grid not found!");
try {
for(int x = 0; x < 16; x++) {
for(int z = 0; z < 16; z++) {
grid[x][z] = ConfigUtil.getBiome(((List<List<String>>) getList("grid")).get(x).get(z)).getBiome();
}
}
} catch(ClassCastException e) {
throw new InvalidConfigurationException("Malformed grid!");
}
if(!contains("id")) throw new InvalidConfigurationException("Grid ID unspecified!");
this.gridID = getString("id");
if(!contains("name")) throw new InvalidConfigurationException("Grid Name unspecified!");
this.friendlyName = getString("name");
isEnabled = true;
}
public String getFriendlyName() {
return friendlyName;
}
public UserDefinedBiome[][] getBiomeGrid() {
return grid;
}
public boolean isEnabled() {
return isEnabled;
}
public String getGridID() {
return gridID;
}
}

View File

@ -1,4 +1,103 @@
package com.dfsek.terra.config;
import com.dfsek.terra.biome.TerraBiomeGrid;
import com.dfsek.terra.biome.UserDefinedBiome;
import org.bukkit.Bukkit;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.plugin.java.JavaPlugin;
import org.polydev.gaea.commons.io.FilenameUtils;
import org.polydev.gaea.world.BlockPalette;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
import java.util.stream.Stream;
public class ConfigUtil {
private static final Map<String, BiomeConfig> biomes = new HashMap<>();
private static final Map<String, BiomeGridConfig> biomeGrids = new HashMap<>();
private static final Map<String, PaletteConfig> palettes = new HashMap<>();
public static void loadConfig(JavaPlugin main) {
Logger logger = main.getLogger();
logger.info("Loading config values");
try (Stream<Path> paths = Files.walk(Paths.get(main.getDataFolder() + File.separator + "palettes"))) {
paths
.filter(path -> FilenameUtils.wildcardMatch(path.toFile().getName(), "*.yml"))
.forEach(path -> {
logger.info("Loading BlockPalette from " + path.toString());
try {
PaletteConfig grid = new PaletteConfig(path.toFile());
palettes.put(grid.getPaletteID(), grid);
logger.info("Friendly name: " + grid.getFriendlyName());
logger.info("ID: " + grid.getPaletteID());
} catch(IOException | InvalidConfigurationException e) {
e.printStackTrace();
}
});
} catch(IOException e) {
e.printStackTrace();
}
try (Stream<Path> paths = Files.walk(Paths.get(main.getDataFolder() + File.separator + "biomes"))) {
paths
.filter(path -> FilenameUtils.wildcardMatch(path.toFile().getName(), "*.yml"))
.forEach(path -> {
logger.info("Loading biome from " + path.toString());
try {
BiomeConfig biome = new BiomeConfig(path.toFile());
biomes.put(biome.getBiomeID(), biome);
logger.info("Friendly name: " + biome.getFriendlyName());
logger.info("ID: " + biome.getBiomeID());
logger.info("Noise equation: " + biome.get("noise-equation"));
} catch(IOException | InvalidConfigurationException e) {
e.printStackTrace();
}
});
} catch(IOException e) {
e.printStackTrace();
}
try (Stream<Path> paths = Files.walk(Paths.get(main.getDataFolder() + File.separator + "grids"))) {
paths
.filter(path -> FilenameUtils.wildcardMatch(path.toFile().getName(), "*.yml"))
.forEach(path -> {
logger.info("Loading BiomeGrid from " + path.toString());
try {
BiomeGridConfig grid = new BiomeGridConfig(path.toFile());
biomeGrids.put(grid.getGridID(), grid);
logger.info("Friendly name: " + grid.getFriendlyName());
logger.info("ID: " + grid.getGridID());
} catch(IOException | InvalidConfigurationException e) {
e.printStackTrace();
}
});
} catch(IOException e) {
e.printStackTrace();
}
WorldConfig.reloadAll();
TerraBiomeGrid.reloadAll();
}
public static BiomeConfig getBiome(String id) {
return biomes.get(id);
}
public static BiomeGridConfig getGrid(String id) {
return biomeGrids.get(id);
}
public static PaletteConfig getPalette(String id) {
return palettes.get(id);
}
}

View File

@ -0,0 +1,88 @@
package com.dfsek.terra.config;
import org.bukkit.Bukkit;
import org.bukkit.block.data.BlockData;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull;
import org.polydev.gaea.math.ProbabilityCollection;
import org.polydev.gaea.world.BlockPalette;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;
public class PaletteConfig extends YamlConfiguration {
private BlockPalette palette;
private String paletteID;
private boolean isEnabled = false;
private String friendlyName;
public PaletteConfig(File file) throws IOException, InvalidConfigurationException {
load(file);
}
@Override
public void load(@NotNull File file) throws IOException, InvalidConfigurationException {
super.load(file);
palette = new BlockPalette();
for(Map<?, ?> m : getMapList("blocks")) {
try {
ProbabilityCollection<BlockData> layer = new ProbabilityCollection<>();
for(Map.Entry<String, Integer> type : ((Map<String, Integer>) m.get("materials")).entrySet()) {
layer.add(Bukkit.createBlockData(type.getKey()), type.getValue());
Bukkit.getLogger().info("[Terra] Added" + type.getKey() + " with probability " + type.getValue());
}
Bukkit.getLogger().info("[Terra] Added above materials for " + m.get("layers") + " layers.");
palette.addBlockData(layer, (Integer) m.get("layers"));
} catch(ClassCastException e) {
e.printStackTrace();
}
}
if(!contains("id")) throw new InvalidConfigurationException("Grid ID unspecified!");
this.paletteID = getString("id");
if(!contains("name")) throw new InvalidConfigurationException("Grid Name unspecified!");
this.friendlyName = getString("name");
isEnabled = true;
}
public BlockPalette getPalette() {
return palette;
}
public boolean isEnabled() {
return isEnabled;
}
public String getFriendlyName() {
return friendlyName;
}
public String getPaletteID() {
return paletteID;
}
private static class Range {
private final int min;
private final int max;
/**
* Instantiates a Range object with a minimum value (inclusive) and a maximum value (exclusive).
* @param min The minimum value (inclusive).
* @param max The maximum value (exclusive).
*/
public Range(int min, int max) {
this.min = min;
this.max = max;
}
/**
* Tests if a value is within range.
* @param val The value to test.
* @return boolean - Whether the value is within range.
*/
public boolean isInRange(int val) {
return val >= min && val < max;
}
}
}

View File

@ -27,8 +27,7 @@ import java.util.stream.Stream;
public class WorldConfig {
private static JavaPlugin main;
private static final Map<String, WorldConfig> configs = new HashMap<>();
private static final Map<String, BiomeConfig> biomes = new HashMap<>();
public List<List<String>> biomeGrid;
public BiomeGridConfig biomeGrid;
public WorldConfig(String name, JavaPlugin main) {
@ -36,6 +35,12 @@ public class WorldConfig {
load(name);
}
public static void reloadAll() {
for(Map.Entry<String, WorldConfig> e : configs.entrySet()) {
e.getValue().load(e.getKey());
}
}
public static WorldConfig fromWorld(World w) {
return configs.getOrDefault(w.getName(), null);
}
@ -57,31 +62,13 @@ public class WorldConfig {
main.getLogger().severe("Unable to load configuration for world " + w + ".");
}
biomeGrid = (List<List<String>>) config.getList("grids.DEFAULT");
biomeGrid = ConfigUtil.getGrid(config.getStringList("grids").get(0));
try (Stream<Path> paths = Files.walk(Paths.get(main.getDataFolder() + File.separator + "biomes"))) {
paths
.filter(path -> FilenameUtils.wildcardMatch(path.toFile().getName(), "*.yml"))
.forEach(path -> {
Bukkit.getLogger().info(path.toString());
try {
BiomeConfig biome = new BiomeConfig(path.toFile());
biomes.put(biome.getBiomeID(), biome);
} catch(IOException | InvalidConfigurationException | ParseException e) {
e.printStackTrace();
}
});
} catch(IOException e) {
e.printStackTrace();
}
configs.put(w, this);
main.getLogger().info("World load complete. Time elapsed: " + ((double) (System.nanoTime() - start)) / 1000000 + "ms");
}
public static Map<String, BiomeConfig> getBiomes() {
return biomes;
}
}

View File

@ -0,0 +1,34 @@
package com.dfsek.terra.math;
import org.polydev.gaea.math.FastNoise;
import org.polydev.gaea.math.parsii.eval.Expression;
import org.polydev.gaea.math.parsii.eval.Function;
import java.util.List;
public class NoiseFunction2 implements Function {
private static FastNoise gen = new FastNoise();
@Override
public int getNumberOfArguments() {
return 2;
}
@Override
public double eval(List<Expression> list) {
return gen.getSimplexFractal((float) list.get(0).evaluate(), (float) list.get(1).evaluate());
}
@Override
public boolean isNaturalFunction() {
return true;
}
public static void setNoise(FastNoise gen) {
NoiseFunction2.gen = gen;
}
public static FastNoise getNoise() {
return gen;
}
}

View File

@ -0,0 +1,34 @@
package com.dfsek.terra.math;
import org.polydev.gaea.math.FastNoise;
import org.polydev.gaea.math.parsii.eval.Expression;
import org.polydev.gaea.math.parsii.eval.Function;
import java.util.List;
public class NoiseFunction3 implements Function {
private static FastNoise gen = new FastNoise();
@Override
public int getNumberOfArguments() {
return 3;
}
@Override
public double eval(List<Expression> list) {
return gen.getSimplexFractal((float) list.get(0).evaluate(), (float) list.get(1).evaluate(), (float) list.get(2).evaluate());
}
@Override
public boolean isNaturalFunction() {
return true;
}
public static void setNoise(FastNoise gen) {
NoiseFunction3.gen = gen;
}
public static FastNoise getNoise() {
return gen;
}
}

View File

@ -2,4 +2,10 @@ name: Terra
main: com.dfsek.terra.Terra
version: 1.0.0
load: STARTUP
api-version: "1.15"
api-version: "1.15"
commands:
terra:
description: Terra base command
usage: /terra reload
aliases: [te]
permission: terra.command