Look ma, no Bukkit API in the core package

This commit is contained in:
dfsek
2020-12-11 17:30:17 -07:00
parent 7ee1d2c391
commit 5bf699cba9
345 changed files with 1352 additions and 2642 deletions

View File

@@ -1,19 +0,0 @@
package com.dfsek.terra;
import com.dfsek.terra.api.gaea.profiler.DataType;
import com.dfsek.terra.api.gaea.profiler.Measurement;
import com.dfsek.terra.api.gaea.profiler.WorldProfiler;
import com.dfsek.terra.api.generic.world.World;
public class TerraProfiler extends WorldProfiler {
public TerraProfiler(World w) {
super(w);
this
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "FloraTime")
.addMeasurement(new Measurement(10000000, DataType.PERIOD_MILLISECONDS), "TreeTime")
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "OreTime")
.addMeasurement(new Measurement(5000000, DataType.PERIOD_MILLISECONDS), "CaveTime")
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "StructureTime")
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "ElevationTime");
}
}

View File

@@ -1,80 +0,0 @@
package com.dfsek.terra;
import com.dfsek.terra.api.gaea.biome.BiomeGrid;
import com.dfsek.terra.api.generic.TerraPlugin;
import com.dfsek.terra.api.generic.world.World;
import com.dfsek.terra.api.implementations.bukkit.generator.BukkitChunkGenerator;
import com.dfsek.terra.biome.BiomeZone;
import com.dfsek.terra.biome.grid.master.TerraBiomeGrid;
import com.dfsek.terra.biome.grid.master.TerraRadialBiomeGrid;
import com.dfsek.terra.biome.grid.master.TerraStandardBiomeGrid;
import com.dfsek.terra.config.base.ConfigPack;
import com.dfsek.terra.config.base.ConfigPackTemplate;
import com.dfsek.terra.config.builder.biomegrid.BiomeGridBuilder;
import com.dfsek.terra.debug.Debug;
public class TerraWorld {
private final TerraBiomeGrid grid;
private final BiomeZone zone;
private final ConfigPack config;
private boolean safe;
private final TerraProfiler profiler;
public TerraWorld(World w, ConfigPack c, TerraPlugin main) {
safe = true;
config = c;
profiler = new TerraProfiler(w);
ConfigPackTemplate template = config.getTemplate();
int zoneSize = template.getGrids().size();
BiomeGrid[] definedGrids = new BiomeGrid[zoneSize];
for(int i = 0; i < zoneSize; i++) {
String partName = template.getGrids().get(i);
try {
BiomeGridBuilder g = config.getBiomeGrid(partName);
BiomeGrid b = g.build(w, c);
definedGrids[i] = b;
} catch(NullPointerException e) {
safe = false;
Debug.stack(e);
main.getLogger().severe("No such BiomeGrid " + partName);
main.getLogger().severe("Please check configuration files for errors. Configuration errors will have been reported during initialization.");
main.getLogger().severe("ONLY report this to Terra if you are SURE your config is error-free.");
main.getLogger().severe("Terrain will NOT generate properly at this point. Correct your config before using your server!");
}
}
zone = new BiomeZone(w, c, definedGrids);
if(template.getGridType().equals(TerraBiomeGrid.Type.RADIAL)) {
BiomeGrid internal = config.getBiomeGrid(template.getRadialInternalGrid()).build(w, c);
grid = new TerraRadialBiomeGrid(w, template.getGridFreqX(), template.getGridFreqZ(), zone, config, template.getRadialGridRadius(), internal);
} else grid = new TerraStandardBiomeGrid(w, template.getGridFreqX(), template.getGridFreqZ(), zone, config);
}
public static boolean isTerraWorld(World w) {
return w.getGenerator() instanceof BukkitChunkGenerator;
}
public TerraBiomeGrid getGrid() {
return grid;
}
public ConfigPack getConfig() {
return config;
}
public BiomeZone getZone() {
return zone;
}
public boolean isSafe() {
return safe;
}
public TerraProfiler getProfiler() {
return profiler;
}
}

View File

@@ -1,68 +0,0 @@
package com.dfsek.terra.api;
import com.dfsek.tectonic.loading.TypeRegistry;
import com.dfsek.terra.api.gaea.math.ProbabilityCollection;
import com.dfsek.terra.api.gaea.math.Range;
import com.dfsek.terra.api.generic.TerraPlugin;
import com.dfsek.terra.biome.grid.master.TerraBiomeGrid;
import com.dfsek.terra.biome.palette.PaletteHolder;
import com.dfsek.terra.biome.palette.PaletteLayer;
import com.dfsek.terra.carving.CarverPalette;
import com.dfsek.terra.config.loaders.ImageLoaderLoader;
import com.dfsek.terra.config.loaders.MaterialSetLoader;
import com.dfsek.terra.config.loaders.ProbabilityCollectionLoader;
import com.dfsek.terra.config.loaders.RangeLoader;
import com.dfsek.terra.config.loaders.config.FloraLayerLoader;
import com.dfsek.terra.config.loaders.config.GridSpawnLoader;
import com.dfsek.terra.config.loaders.config.NoiseBuilderLoader;
import com.dfsek.terra.config.loaders.config.OreConfigLoader;
import com.dfsek.terra.config.loaders.config.OreHolderLoader;
import com.dfsek.terra.config.loaders.config.StructureFeatureLoader;
import com.dfsek.terra.config.loaders.config.TreeLayerLoader;
import com.dfsek.terra.config.loaders.palette.CarverPaletteLoader;
import com.dfsek.terra.config.loaders.palette.PaletteHolderLoader;
import com.dfsek.terra.config.loaders.palette.PaletteLayerLoader;
import com.dfsek.terra.generation.config.NoiseBuilder;
import com.dfsek.terra.generation.items.flora.FloraLayer;
import com.dfsek.terra.generation.items.flora.TerraFlora;
import com.dfsek.terra.generation.items.ores.Ore;
import com.dfsek.terra.generation.items.ores.OreConfig;
import com.dfsek.terra.generation.items.ores.OreHolder;
import com.dfsek.terra.generation.items.tree.TreeLayer;
import com.dfsek.terra.image.ImageLoader;
import com.dfsek.terra.procgen.GridSpawn;
import com.dfsek.terra.structure.features.Feature;
import com.dfsek.terra.util.MaterialSet;
import com.dfsek.terra.util.StructureTypeEnum;
public class GenericLoaders implements LoaderRegistrar {
private final TerraPlugin main;
public GenericLoaders(TerraPlugin main) {
this.main = main;
}
@Override
public void register(TypeRegistry registry) {
registry.registerLoader(ProbabilityCollection.class, new ProbabilityCollectionLoader())
.registerLoader(Range.class, new RangeLoader())
.registerLoader(CarverPalette.class, new CarverPaletteLoader())
.registerLoader(GridSpawn.class, new GridSpawnLoader())
.registerLoader(PaletteHolder.class, new PaletteHolderLoader())
.registerLoader(PaletteLayer.class, new PaletteLayerLoader())
.registerLoader(FloraLayer.class, new FloraLayerLoader())
.registerLoader(Ore.Type.class, (t, o, l) -> Ore.Type.valueOf((String) o))
.registerLoader(OreConfig.class, new OreConfigLoader())
.registerLoader(NoiseBuilder.class, new NoiseBuilderLoader())
.registerLoader(TreeLayer.class, new TreeLayerLoader(main))
.registerLoader(MaterialSet.class, new MaterialSetLoader())
.registerLoader(OreHolder.class, new OreHolderLoader())
.registerLoader(Feature.class, new StructureFeatureLoader())
.registerLoader(ImageLoader.class, new ImageLoaderLoader())
.registerLoader(TerraBiomeGrid.Type.class, (t, o, l) -> TerraBiomeGrid.Type.valueOf((String) o))
.registerLoader(StructureTypeEnum.class, (t, o, l) -> StructureTypeEnum.valueOf((String) o))
.registerLoader(ImageLoader.Channel.class, (t, o, l) -> ImageLoader.Channel.valueOf((String) o))
.registerLoader(ImageLoader.Align.class, (t, o, l) -> ImageLoader.Align.valueOf((String) o))
.registerLoader(TerraFlora.Search.class, (t, o, l) -> TerraFlora.Search.valueOf((String) o));
}
}

View File

@@ -1,7 +0,0 @@
package com.dfsek.terra.api;
import com.dfsek.tectonic.loading.TypeRegistry;
public interface LoaderRegistrar {
void register(TypeRegistry registry);
}

View File

@@ -1,26 +0,0 @@
package com.dfsek.terra.api.gaea;
import org.bukkit.plugin.java.JavaPlugin;
public class Debug {
public static JavaPlugin main;
public static void setMain(JavaPlugin main) {
Debug.main = main;
}
public static void info(String message) {
if(Gaea.isDebug()) main.getLogger().info(message);
}
public static void warn(String message) {
if(Gaea.isDebug()) main.getLogger().warning(message);
}
public static void error(String message) {
if(Gaea.isDebug()) main.getLogger().severe(message);
}
public static void stack(Exception e) {
if(Gaea.isDebug()) e.printStackTrace();
}
}

View File

@@ -1,20 +0,0 @@
package com.dfsek.terra.api.gaea;
import com.dfsek.terra.api.generic.world.World;
import java.io.File;
public class Gaea {
private static boolean debug;
public static File getGaeaFolder(World w) {
File f = new File(w.getWorldFolder(), "gaea");
f.mkdirs();
return f;
}
public static boolean isDebug() {
return debug;
}
}

View File

@@ -1,9 +0,0 @@
package com.dfsek.terra.api.gaea;
import com.dfsek.terra.api.gaea.lang.Language;
import org.bukkit.plugin.java.JavaPlugin;
public abstract class GaeaPlugin extends JavaPlugin {
public abstract boolean isDebug();
public abstract Language getLanguage();
}

View File

@@ -1,40 +0,0 @@
package com.dfsek.terra.api.gaea.biome;
import org.bukkit.World;
/**
* Interface to be implemented by a custom generator's Biome enum.<br>
* Represents a custom biome, and contains methods to retrieve information about each type.
*/
public interface Biome {
/**
* Gets the Vanilla biome to represent the custom biome.
*
* @return Biome - The Vanilla biome.
*/
com.dfsek.terra.api.generic.world.Biome getVanillaBiome();
/**
* Gets the BiomeTerrain instance used to generate the biome.
*
* @return BiomeTerrain - The terrain generation instance.
*/
Generator getGenerator();
/**
* Returns the Decorator instance containing information about the population in the biome.
*
* @return Decorator - the Decorator instance.
*/
Decorator getDecorator();
/**
* Gets the BiomeTerrain instance used to generate the biome in this world.
*
* @return BiomeTerrain - The terrain generation instance.
*/
default Generator getGenerator(World w) {
return getGenerator();
}
}

View File

@@ -1,121 +0,0 @@
package com.dfsek.terra.api.gaea.biome;
import com.dfsek.terra.api.gaea.generation.GenerationPhase;
import com.dfsek.terra.api.gaea.math.FastNoiseLite;
import com.dfsek.terra.api.generic.world.World;
import com.dfsek.terra.api.generic.world.vector.Location;
public abstract class BiomeGrid {
private final FastNoiseLite noiseX;
private final FastNoiseLite noiseZ;
private final World world;
private final int sizeX;
private final int sizeZ;
private Biome[][] grid;
public BiomeGrid(World w, double freq1, double freq2, int sizeX, int sizeZ) {
this.sizeX = sizeX;
this.sizeZ = sizeZ;
this.world = w;
this.noiseX = new FastNoiseLite((int) w.getSeed());
this.noiseZ = new FastNoiseLite((int) w.getSeed() + 1);
this.noiseX.setNoiseType(FastNoiseLite.NoiseType.OpenSimplex2);
this.noiseX.setFractalType(FastNoiseLite.FractalType.FBm);
this.noiseX.setFractalOctaves(4);
this.noiseZ.setNoiseType(FastNoiseLite.NoiseType.OpenSimplex2);
this.noiseZ.setFractalType(FastNoiseLite.FractalType.FBm);
this.noiseZ.setFractalOctaves(4);
this.noiseX.setFrequency(freq1);
this.noiseZ.setFrequency(freq2);
}
/**
* Gets the biome at a pair of coordinates.
*
* @param x - X-coordinate at which to fetch biome
* @param z - Z-coordinate at which to fetch biome
* @return Biome - Biome at the given coordinates.
*/
public Biome getBiome(int x, int z, GenerationPhase phase) {
return grid[getBiomeNoiseX(x, z)][getBiomeNoiseZ(x, z)];
}
/**
* Gets the biome at a location.
*
* @param l - The location at which to fetch the biome.
* @return Biome - Biome at the given coordinates.
*/
public Biome getBiome(Location l) {
return getBiome(l, GenerationPhase.POST_GEN);
}
public double[] getRawNoise(int x, int z) {
return new double[] {noiseX.getNoise(x, z), noiseZ.getNoise(x, z)};
}
/**
* Get the raw X-noise for coordinates in the Grid.
*
* @param x X coordinate
* @param z Z coordinate
* @return Normalized noise
*/
public int getBiomeNoiseX(int x, int z) {
return normalize(noiseX.getNoise(x, z), sizeX);
}
/**
* Get the raw Z-noise for coordinates in the Grid.
*
* @param x X coordinate
* @param z Z coordinate
* @return Normalized noise
*/
public int getBiomeNoiseZ(int x, int z) {
return normalize(noiseZ.getNoise(x, z), sizeZ);
}
public Biome[][] getGrid() {
return grid;
}
public void setGrid(Biome[][] grid) {
if(grid.length != sizeX) throw new IllegalArgumentException("Invalid length for grid, expected " + sizeX + ", got " + grid.length);
for(Biome[] gridLayer : grid) {
if(gridLayer.length != sizeZ) throw new IllegalArgumentException("Invalid length for grid layer, expected " + sizeZ + ", got " + gridLayer.length);
}
this.grid = grid;
}
public Biome getBiome(Location l, GenerationPhase phase) {
double biomeNoise = noiseX.getNoise(l.getBlockX(), l.getBlockZ());
double climateNoise = noiseZ.getNoise(l.getBlockX(), l.getBlockZ());
return grid[normalize(biomeNoise, sizeX)][normalize(climateNoise, sizeZ)];
}
public World getWorld() {
return world;
}
public int getSizeX() {
return sizeX;
}
public int getSizeZ() {
return sizeZ;
}
/**
* Takes a noise input and normalizes it to a value between 0 and 15 inclusive.
*
* @param i - The noise value to normalize.
* @return int - The normalized value.
*/
protected int normalize(double i, int range) {
return NormalizationUtil.normalize(i, range, 4);
}
}

View File

@@ -1,22 +0,0 @@
package com.dfsek.terra.api.gaea.biome;
import com.dfsek.terra.api.gaea.math.ProbabilityCollection;
import com.dfsek.terra.api.gaea.tree.Tree;
import com.dfsek.terra.api.gaea.world.Flora;
public abstract class Decorator {
public abstract ProbabilityCollection<Tree> getTrees();
public abstract int getTreeDensity();
public abstract boolean overrideStructureChance();
public abstract org.bukkit.block.Biome getVanillaBiome();
public abstract ProbabilityCollection<Flora> getFlora();
public abstract int getFloraChance();
}

View File

@@ -1,40 +0,0 @@
package com.dfsek.terra.api.gaea.biome;
import com.dfsek.terra.api.gaea.math.Interpolator;
import com.dfsek.terra.api.gaea.world.palette.Palette;
import com.dfsek.terra.api.generic.world.World;
import com.dfsek.terra.api.generic.world.block.BlockData;
public abstract class Generator {
/**
* Gets the 3D noise at a pair of coordinates using the provided FastNoiseLite instance.
*
* @param x - The x coordinate.
* @param y - The y coordinate.
* @param z - The z coordinate.
* @return double - Noise value at the specified coordinates.
*/
public abstract double getNoise(World w, int x, int y, int z);
/**
* Gets the BlocPalette to generate the biome with.
*
* @return BlocPalette - The biome's palette.
*/
public abstract Palette<BlockData> getPalette(int y);
/**
* Returns true if the biome should be interpolated just once, false to use advanced interpolation + blending.
* @return Whether biome should use minimal interpolation
*/
public abstract boolean useMinimalInterpolation();
/**
* Get the type of interpolation to use in this biome.
* @return Interpolation type
*/
public Interpolator.Type getInterpolationType() {
return Interpolator.Type.LINEAR;
}
}

File diff suppressed because one or more lines are too long

View File

@@ -1,111 +0,0 @@
package com.dfsek.terra.api.gaea.command;
import com.dfsek.terra.api.gaea.GaeaPlugin;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Represents a command or subcommand, can be nested via getSubCommands.
*/
public abstract class Command implements CommandExecutor, TabCompleter {
private final GaeaPlugin main;
public Command(GaeaPlugin main) {
this.main = main;
}
public Command(com.dfsek.terra.api.gaea.command.Command parent) {
main = parent.getMain();
}
public GaeaPlugin getMain() {
return main;
}
/**
* Gets the name of the command/subcommand
* @return Name of command
*/
public abstract String getName();
/**
* Gets a list of subcommands
* @return List of subcommands
*/
public abstract List<com.dfsek.terra.api.gaea.command.Command> getSubCommands();
/**
* Executes the given command, returning its success.
* <br>
* If false is returned, then the "usage" plugin.yml entry for this command
* (if defined) will be sent to the player.
*
* @param sender Source of the command
* @param command Command which was executed
* @param label Alias of the command which was used
* @param args Passed command arguments
* @return true if a valid command, otherwise false
*/
public abstract boolean execute(@NotNull CommandSender sender, @NotNull org.bukkit.command.Command command, @NotNull String label, @NotNull String[] args);
/**
* Gets the number of arguments
* @return Number of arguments
*/
public abstract int arguments();
/**
* Executes the given command, invoking subcommands if applicable and returning its success.
* <br>
* If false is returned, then the "usage" plugin.yml entry for this command
* (if defined) will be sent to the player.
*
* @param sender Source of the command
* @param command Command which was executed
* @param label Alias of the command which was used
* @param args Passed command arguments
* @return true if a valid command, otherwise false
*/
@Override
public final boolean onCommand(@NotNull CommandSender sender, @NotNull org.bukkit.command.Command command, @NotNull String label, @NotNull String[] args) {
if(this instanceof DebugCommand && ! main.isDebug()) {
main.getLanguage().send("command.debug-only", sender);
return true;
}
if(args.length > 0) {
for(com.dfsek.terra.api.gaea.command.Command c : getSubCommands()) {
if(c.getName().equals(args[0])) {
return c.onCommand(sender, command, label, Arrays.stream(args, 1, args.length).toArray(String[]::new));
}
}
if(args.length != arguments()) {
main.getLanguage().send("command.invalid", sender, String.valueOf(arguments()), String.valueOf(args.length));
return true;
}
return execute(sender, command, label, args);
}
if(args.length != arguments()) {
main.getLanguage().send("command.invalid", sender, String.valueOf(arguments()), String.valueOf(args.length));
return true;
}
return execute(sender, command, label, new String[] {});
}
public abstract List<String> getTabCompletions(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args);
@Override
public final @Nullable List<String> onTabComplete(@NotNull CommandSender sender, org.bukkit.command.@NotNull Command command, @NotNull String alias, @NotNull String[] args) {
List<String> complete = new ArrayList<>();
if(args.length > 0) for(com.dfsek.terra.api.gaea.command.Command c : getSubCommands()) {
if(c.getName().startsWith(args[0])) complete.add(c.getName());
if(c.getName().equals(args[0])) return c.onTabComplete(sender, command, alias, Arrays.stream(args, 1, args.length).toArray(String[]::new));
}
complete.addAll(getTabCompletions(sender, alias, args));
return complete;
}
}

View File

@@ -1,8 +0,0 @@
package com.dfsek.terra.api.gaea.command;
/**
* Implementing this interface marks a command as debug-only.
* If a parent command implements this interface, all child commands will be considered debug commands, regardless of whether they implement DebugCommand as well.
*/
public interface DebugCommand {
}

View File

@@ -1,49 +0,0 @@
package com.dfsek.terra.api.gaea.command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
/**
* A command that may only be executed by a player. If executor is not a player, a message will be displayed and no action will be performed.
*/
public abstract class PlayerCommand extends Command {
public PlayerCommand(Command parent) {
super(parent);
}
/**
* Executes the given command, returning its success.
* <br>
* If false is returned, then the "usage" plugin.yml entry for this command
* (if defined) will be sent to the player.
*
* @param sender Source of the command
* @param command Command which was executed
* @param label Alias of the command which was used
* @param args Passed command arguments
* @return true if a valid command, otherwise false
*/
@Override
public final boolean execute(@NotNull CommandSender sender, org.bukkit.command.@NotNull Command command, @NotNull String label, @NotNull String[] args) {
if(!(sender instanceof Player)) {
getMain().getLanguage().send("command.players-only", sender);
return true;
}
Player p = (Player) sender;
return execute(p, command, label, args);
}
/**
* Executes the given command, returning its success.
* <br>
* If false is returned, then the "usage" plugin.yml entry for this command
* (if defined) will be sent to the player.
*
* @param sender Player that executed command
* @param command Command which was executed
* @param label Alias of the command which was used
* @param args Passed command arguments
* @return true if a valid command, otherwise false
*/
public abstract boolean execute(@NotNull Player sender, org.bukkit.command.@NotNull Command command, @NotNull String label, @NotNull String[] args);
}

View File

@@ -1,53 +0,0 @@
package com.dfsek.terra.api.gaea.command;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.entity.Player;
import org.bukkit.generator.ChunkGenerator;
import org.jetbrains.annotations.NotNull;
/**
* A command that must be executed by a player, in a Terra world.
*/
public abstract class WorldCommand extends PlayerCommand {
public WorldCommand(com.dfsek.terra.api.gaea.command.Command parent) {
super(parent);
}
/**
* Executes the given command, returning its success.
* <br>
* If false is returned, then the "usage" plugin.yml entry for this command
* (if defined) will be sent to the player.
*
* @param sender Source of the command
* @param command Command which was executed
* @param label Alias of the command which was used
* @param args Passed command arguments
* @return true if a valid command, otherwise false
*/
@Override
public final boolean execute(@NotNull Player sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if(sender.getWorld().getGenerator() instanceof ChunkGenerator) { // TODO: implementation
return execute(sender, command, label, args, sender.getWorld());
} else {
getMain().getLanguage().send("command.world", sender);
}
return true;
}
/**
* Executes the given command, returning its success.
* <br>
* If false is returned, then the "usage" plugin.yml entry for this command
* (if defined) will be sent to the player.
*
* @param sender Player that executed command
* @param command Command which was executed
* @param label Alias of the command which was used
* @param args Passed command arguments
* @param world World in which command was executed
* @return true if a valid command, otherwise false
*/
public abstract boolean execute(@NotNull Player sender, @NotNull Command command, @NotNull String label, @NotNull String[] args, World world);
}

View File

@@ -1,8 +0,0 @@
package com.dfsek.terra.api.gaea.generation;
/**
* The phase of terrain generation. Used for modifying values based on the phase of generation.
*/
public enum GenerationPhase {
BASE, POPULATE, GENERATION_POPULATE, PALETTE_APPLY, POST_GEN
}

View File

@@ -1,40 +0,0 @@
package com.dfsek.terra.api.gaea.lang;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Language extends YamlConfiguration {
public Language(File file) throws IOException, InvalidConfigurationException {
load(file);
}
@Override
public void load(@NotNull File file) throws IOException, InvalidConfigurationException {
super.load(file);
}
@SuppressWarnings("unchecked")
public Message getMessage(String id) {
Object m = get(id);
Message temp;
if(m instanceof List) {
temp = new MultiLineMessage((List<String>) m);
} else if(m instanceof String) {
temp = new SingleLineMessage((String) m);
} else return new SingleLineMessage("message:" + id + ":translation_undefined");
if(temp.isEmpty()) return new SingleLineMessage("message:" + id + ":translation_undefined");
return temp;
}
public void log(String messageID, Level level, Logger logger, String... args) {
getMessage(messageID).log(logger, level, args);
}
public void send(String messageID, CommandSender sender, String... args) {
getMessage(messageID).send(sender, args);
}
}

View File

@@ -1,12 +0,0 @@
package com.dfsek.terra.api.gaea.lang;
import org.bukkit.command.CommandSender;
import java.util.logging.Level;
import java.util.logging.Logger;
public interface Message {
void log(Logger logger, Level level, String... args);
void send(CommandSender sender, String... args);
boolean isEmpty();
}

View File

@@ -1,34 +0,0 @@
package com.dfsek.terra.api.gaea.lang;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
public class MultiLineMessage implements Message {
private final List<String> message;
public MultiLineMessage(List<String> message) {
this.message = message;
}
@Override
public void log(Logger logger, Level level, String... args) {
for(String line: message) {
logger.log(level, ChatColor.translateAlternateColorCodes('&', String.format(line, Arrays.asList(args).toArray())));
}
}
@Override
public void send(CommandSender sender, String... args) {
for(String line: message) {
sender.sendMessage(ChatColor.translateAlternateColorCodes('&', String.format(line, Arrays.asList(args).toArray())));
}
}
@Override
public boolean isEmpty() {
return message == null || message.isEmpty();
}
}

View File

@@ -1,29 +0,0 @@
package com.dfsek.terra.api.gaea.lang;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
public class SingleLineMessage implements Message {
private final String message;
public SingleLineMessage(String message) {
this.message = message;
}
@Override
public void log(Logger logger, Level level, String... args) {
logger.log(level, ChatColor.translateAlternateColorCodes('&', String.format(message, Arrays.asList(args).toArray())));
}
@Override
public void send(CommandSender sender, String... args) {
sender.sendMessage(ChatColor.translateAlternateColorCodes('&', String.format(message, Arrays.asList(args).toArray())));
}
@Override
public boolean isEmpty() {
return message == null || message.equals("");
}
}

View File

@@ -1,128 +0,0 @@
package com.dfsek.terra.api.gaea.math;
import com.dfsek.terra.api.gaea.biome.BiomeGrid;
import com.dfsek.terra.api.gaea.biome.Generator;
import com.dfsek.terra.api.gaea.generation.GenerationPhase;
import com.dfsek.terra.api.generic.world.World;
import net.jafama.FastMath;
/**
* Class to abstract away the 16 Interpolators needed to generate a chunk.<br>
* Contains method to get interpolated noise at a coordinate within the chunk.
*/
public class ChunkInterpolator3 {
private final Interpolator3[][][] interpGrid = new Interpolator3[4][64][4];
private final Generator[][] gens = new Generator[7][7];
private final boolean[][] needsBiomeInterp = new boolean[5][5];
private final double[][][] noiseStorage = new double[7][7][65];
private final int xOrigin;
private final int zOrigin;
private final World w;
/**
* Instantiates a 3D ChunkInterpolator at a pair of chunk coordinates, with a BiomeGrid and FastNoiseLite instance.
*
* @param chunkX X coordinate of the chunk.
* @param chunkZ Z coordinate of the chunk.
* @param grid BiomeGrid to use for noise fetching.
*/
public ChunkInterpolator3(World w, int chunkX, int chunkZ, BiomeGrid grid) {
this.xOrigin = chunkX << 4;
this.zOrigin = chunkZ << 4;
this.w = w;
for(int x = -1; x < 6; x++) {
for(int z = -1; z < 6; z++) {
gens[x + 1][z + 1] = grid.getBiome(xOrigin + (x << 2), zOrigin + (z << 2), GenerationPhase.BASE).getGenerator();
}
}
for(int x = 0; x < 5; x++) {
for(int z = 0; z < 5; z++) {
needsBiomeInterp[x][z] = compareGens(x+1, z+1);
}
}
storeNoise();
for(byte x = 0; x < 4; x++) {
for(byte z = 0; z < 4; z++) {
for(int y = 0; y < 64; y++) {
interpGrid[x][y][z] = new Interpolator3(
biomeAvg(x, y, z),
biomeAvg(x + 1, y, z),
biomeAvg(x, y + 1, z),
biomeAvg(x + 1, y + 1, z),
biomeAvg(x, y, z + 1),
biomeAvg(x + 1, y, z + 1),
biomeAvg(x, y + 1, z + 1),
biomeAvg(x + 1, y + 1, z + 1), gens[x+1][z+1].getInterpolationType());
}
}
}
}
private boolean compareGens(int x, int z) {
Generator comp = gens[x][z];
if(!comp.equals(gens[x+1][z])) return true;
if(!comp.equals(gens[x][z+1])) return true;
if(!comp.equals(gens[x-1][z])) return true;
if(!comp.equals(gens[x][z-1])) return true;
if(!comp.equals(gens[x+1][z+1])) return true;
if(!comp.equals(gens[x-1][z-1])) return true;
if(!comp.equals(gens[x+1][z-1])) return true;
return !comp.equals(gens[x - 1][z + 1]);
}
private void storeNoise() {
for(byte x = - 1; x < 6; x++) {
for(byte z = - 1; z < 6; z++) {
for(int y = 0; y < 64; y++) {
noiseStorage[x + 1][z + 1][y] = gens[x + 1][z + 1].getNoise(w, (x << 2) + xOrigin, y << 2, (z << 2) + zOrigin);
}
}
}
}
private double biomeAvg(int x, int y, int z) {
if(needsBiomeInterp[x][z]) return (noiseStorage[x + 2][z + 1][y]
+ noiseStorage[x][z + 1][y]
+ noiseStorage[x + 1][z + 2][y]
+ noiseStorage[x + 1][z][y]
+ noiseStorage[x][z][y]
+ noiseStorage[x + 2][z + 2][y]
+ noiseStorage[x + 2][z][y]
+ noiseStorage[x][z + 2][y]
+ noiseStorage[x + 1][z + 1][y]
) / 9D;
else {
if(gens[x+1][z+1].useMinimalInterpolation()) return noiseStorage[x+1][z+1][y];
else return (noiseStorage[x + 2][z + 1][y]
+ noiseStorage[x][z + 1][y]
+ noiseStorage[x + 1][z + 2][y]
+ noiseStorage[x + 1][z][y]
+ noiseStorage[x+1][z+1][y]) / 5D;
}
}
/**
* Gets the noise at a pair of internal chunk coordinates.
*
* @param x The internal X coordinate (0-15).
* @param z The internal Z coordinate (0-15).
* @return double - The interpolated noise at the coordinates.
*/
public double getNoise(double x, double y, double z) {
return interpGrid[reRange(((int) x) / 4, 3)][reRange(((int) y) / 4, 63)][reRange(((int) z) / 4, 3)].trilerp((x % 4) / 4, (y % 4) / 4, (z % 4) / 4);
}
private static int reRange(int value, int high) {
return FastMath.max(FastMath.min(value, high), 0);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,61 +0,0 @@
package com.dfsek.terra.api.gaea.math;
import net.jafama.FastMath;
/**
* Class for bilinear interpolation of values arranged on a unit square.
*/
public class Interpolator {
private final double v0, v1, v2, v3;
private final Type type;
/**
* Constructs an interpolator with given values as vertices of a unit square.
*
* @param v0 - (0,0)
* @param v1 - (1,0)
* @param v2 - (0,1)
* @param v3 - (1,1)
*/
public Interpolator(double v0, double v1, double v2, double v3, Type type) {
this.v0 = v0;
this.v1 = v1;
this.v2 = v2;
this.v3 = v3;
this.type = type;
}
/**
* 1D Linear interpolation between 2 points 1 unit apart.
*
* @param t - Distance from v0. Total distance between v0 and v1 is 1 unit.
* @param v0 - Value at v0.
* @param v1 - Value at v1.
* @return double - The interpolated value.
*/
public static double lerp(double t, double v0, double v1, Type type) {
switch(type) {
case LINEAR: return v0 + t * (v1 - v0);
case NEAREST_NEIGHBOR: return FastMath.abs(v0-t) > FastMath.abs(v1-t) ? v1 : v0;
default: throw new IllegalStateException();
}
}
/**
* 2D Bilinear interpolation between 4 points on a unit square.
*
* @param s - X value
* @param t - Z value
* @return double - The interpolated value.
*/
public double bilerp(double s, double t) {
double v01 = lerp(s, v0, v1, type);
double v23 = lerp(s, v2, v3, type);
double v = lerp(t, v01, v23, type);
return v;
}
public enum Type {
LINEAR, NEAREST_NEIGHBOR
}
}

View File

@@ -1,40 +0,0 @@
package com.dfsek.terra.api.gaea.math;
/**
* Class for bilinear interpolation of values arranged on a unit square.
*/
public class Interpolator3 {
private final double _000, _100, _010, _110, _001, _101, _011, _111;
private final Interpolator.Type type;
/**
* Constructs an interpolator with given values as vertices of a unit cube.
* * @param _000 The value at <code>(t, u, v) = (0, 0, 0)</code>.
* * @param _100 The value at <code>(t, u, v) = (1, 0, 0)</code>.
* * @param _010 The value at <code>(t, u, v) = (0, 1, 0)</code>.
* * @param _110 The value at <code>(t, u, v) = (1, 1, 0)</code>.
* * @param _001 The value at <code>(t, u, v) = (0, 0, 1)</code>.
* * @param _101 The value at <code>(t, u, v) = (1, 0, 1)</code>.
* * @param _011 The value at <code>(t, u, v) = (0, 1, 1)</code>.
* * @param _111 The value at <code>(t, u, v) = (1, 1, 1)</code>.
*/
public Interpolator3(double _000, double _100,
double _010, double _110, double _001, double _101,
double _011, double _111, Interpolator.Type type) {
this._000 = _000;
this._001 = _001;
this._010 = _010;
this._011 = _011;
this._100 = _100;
this._101 = _101;
this._110 = _110;
this._111 = _111;
this.type = type;
}
public double trilerp(double x, double y, double z) {
Interpolator top = new Interpolator(_000, _010, _001, _011, type);
Interpolator bottom = new Interpolator(_100, _110, _101, _111, type);
return Interpolator.lerp(x, top.bilerp(y, z), bottom.bilerp(y, z), type);
}
}

View File

@@ -1,58 +0,0 @@
package com.dfsek.terra.api.gaea.math;
import com.dfsek.terra.api.gaea.util.FastRandom;
import net.jafama.FastMath;
import java.util.Random;
/**
* Utility class for mathematical functions.
*/
public class MathUtil {
/**
* Gets the standard deviation of an array of doubles.
*
* @param numArray The array of numbers to calculate the standard deviation of.
* @return double - The standard deviation.
*/
public static double standardDeviation(double[] numArray) {
double sum = 0.0, standardDeviation = 0.0;
int length = numArray.length;
for(double num : numArray) {
sum += num;
}
double mean = sum / length;
for(double num : numArray) {
standardDeviation += FastMath.pow(num - mean, 2);
}
return FastMath.sqrt(standardDeviation / length);
}
/**
* Gets the carver seed for a chunk.
*
* @param chunkX Chunk's X coordinate
* @param chunkZ Chunk's Z coordinate
* @param seed World seed
* @return long - The carver seed.
*/
public static long getCarverChunkSeed(int chunkX, int chunkZ, long seed) {
Random r = new FastRandom(seed);
return chunkX * r.nextLong() ^ chunkZ * r.nextLong() ^ seed;
}
public static long hashToLong(String s) {
if(s == null) {
return 0;
}
long hash = 0;
for(char c : s.toCharArray()) {
hash = 31L * hash + c;
}
return hash;
}
}

View File

@@ -1,49 +0,0 @@
package com.dfsek.terra.api.gaea.math;
import com.dfsek.terra.api.gaea.biome.NormalizationUtil;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;
@SuppressWarnings("unchecked")
public class ProbabilityCollection<E> {
private final Set<Object> cont = new HashSet<>();
private Object[] array = new Object[0];
private int size;
public com.dfsek.terra.api.gaea.math.ProbabilityCollection<E> add(E item, int probability) {
if(!cont.contains(item)) size++;
cont.add(item);
int oldLength = array.length;
Object[] newArray = new Object[array.length + probability];
System.arraycopy(array, 0, newArray, 0, array.length); // Expand array.
array = newArray;
for(int i = oldLength; i < array.length; i++) array[i] = item;
return this;
}
public E get() {
if(array.length == 0) return null;
return (E) array[ThreadLocalRandom.current().nextInt(array.length)];
}
public E get(Random r) {
if(array.length == 0) return null;
return (E) array[r.nextInt(array.length)];
}
public E get(FastNoiseLite n, double x, double z) {
if(array.length == 0) return null;
return (E) array[NormalizationUtil.normalize(n.getNoise(x, z), array.length, 1)];
}
public int getTotalProbability() {
return array.length;
}
public int size() {
return size;
}
}

View File

@@ -1,123 +0,0 @@
package com.dfsek.terra.api.gaea.math;
import net.jafama.FastMath;
import org.jetbrains.annotations.NotNull;
import java.util.Iterator;
import java.util.Random;
public class Range implements Iterable<Integer> {
private int min;
private int max;
public Range(int min, int max) {
if(min > max) throw new IllegalArgumentException("Minimum must not be grater than maximum!");
this.max = max;
this.min = min;
}
public boolean isInRange(int test) {
return test >= min && test < max;
}
public int getMax() {
return max;
}
public com.dfsek.terra.api.gaea.math.Range setMax(int max) {
this.max = max;
return this;
}
public int getMin() {
return min;
}
public com.dfsek.terra.api.gaea.math.Range setMin(int min) {
this.min = min;
return this;
}
public int getRange() {
return max - min;
}
public com.dfsek.terra.api.gaea.math.Range multiply(int mult) {
min *= mult;
max *= mult;
return this;
}
public com.dfsek.terra.api.gaea.math.Range reflect(int pt) {
return new com.dfsek.terra.api.gaea.math.Range(2 * pt - this.getMax(), 2 * pt - this.getMin());
}
public int get(Random r) {
return r.nextInt((max - min) + 1) + min;
}
public com.dfsek.terra.api.gaea.math.Range intersects(com.dfsek.terra.api.gaea.math.Range other) {
try {
return new com.dfsek.terra.api.gaea.math.Range(FastMath.max(this.getMin(), other.getMin()), FastMath.min(this.getMax(), other.getMax()));
} catch(IllegalArgumentException e) {
return null;
}
}
public com.dfsek.terra.api.gaea.math.Range add(int add) {
this.min += add;
this.max += add;
return this;
}
public com.dfsek.terra.api.gaea.math.Range sub(int sub) {
this.min -= sub;
this.max -= sub;
return this;
}
@Override
public String toString() {
return "Min: " + getMin() + ", Max:" + getMax();
}
@Override
public int hashCode() {
return min * 31 + max;
}
@Override
public boolean equals(Object obj) {
if(! (obj instanceof com.dfsek.terra.api.gaea.math.Range)) return false;
com.dfsek.terra.api.gaea.math.Range other = (com.dfsek.terra.api.gaea.math.Range) obj;
return other.getMin() == this.getMin() && other.getMax() == this.getMax();
}
@NotNull
@Override
public Iterator<Integer> iterator() {
return new RangeIterator(this);
}
private static class RangeIterator implements Iterator<Integer> {
private final com.dfsek.terra.api.gaea.math.Range m;
private Integer current;
public RangeIterator(com.dfsek.terra.api.gaea.math.Range m) {
this.m = m;
current = m.getMin();
}
@Override
public boolean hasNext() {
return current < m.getMax();
}
@Override
public Integer next() {
current++;
return current - 1;
}
}
}

View File

@@ -1,50 +0,0 @@
package com.dfsek.terra.api.gaea.population;
import com.dfsek.terra.api.generic.world.Chunk;
import java.io.Serializable;
import java.util.UUID;
public class ChunkCoordinate implements Serializable {
public static final long serialVersionUID = 7102462856296750285L;
private final int x;
private final int z;
private final UUID worldID;
public ChunkCoordinate(int x, int z, UUID worldID) {
this.x = x;
this.z = z;
this.worldID = worldID;
}
public ChunkCoordinate(Chunk c) {
this.x = c.getX();
this.z = c.getZ();
this.worldID = c.getWorld().getUID();
}
public UUID getWorldID() {
return worldID;
}
public int getX() {
return x;
}
public int getZ() {
return z;
}
@Override
public int hashCode() {
return x * 31 + z;
}
@Override
public boolean equals(Object obj) {
if(! (obj instanceof com.dfsek.terra.api.gaea.population.ChunkCoordinate)) return false;
com.dfsek.terra.api.gaea.population.ChunkCoordinate other = (com.dfsek.terra.api.gaea.population.ChunkCoordinate) obj;
return other.getX() == x && other.getZ() == z;
}
}

View File

@@ -1,94 +0,0 @@
package com.dfsek.terra.api.gaea.population;
import com.dfsek.terra.api.gaea.Gaea;
import com.dfsek.terra.api.gaea.profiler.ProfileFuture;
import com.dfsek.terra.api.gaea.profiler.WorldProfiler;
import com.dfsek.terra.api.gaea.util.FastRandom;
import com.dfsek.terra.api.gaea.util.GlueList;
import com.dfsek.terra.api.gaea.util.SerializationUtil;
import com.dfsek.terra.api.generic.TerraPlugin;
import com.dfsek.terra.api.generic.generator.TerraBlockPopulator;
import com.dfsek.terra.api.generic.world.Chunk;
import com.dfsek.terra.api.generic.world.World;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
public class PopulationManager implements TerraBlockPopulator {
private final List<TerraBlockPopulator> attachedPopulators = new GlueList<>();
private final HashSet<ChunkCoordinate> needsPop = new HashSet<>();
private final TerraPlugin main;
private WorldProfiler profiler;
public PopulationManager(TerraPlugin main) {
this.main = main;
}
public void attach(TerraBlockPopulator populator) {
this.attachedPopulators.add(populator);
}
@Override
@SuppressWarnings("try")
public void populate(@NotNull World world, @NotNull Random random, @NotNull Chunk chunk) {
try(ProfileFuture ignored = measure()) {
needsPop.add(new ChunkCoordinate(chunk));
int x = chunk.getX();
int z = chunk.getZ();
if(main.isEnabled()) {
for(int xi = - 1; xi <= 1; xi++) {
for(int zi = - 1; zi <= 1; zi++) {
if(xi == 0 && zi == 0) continue;
if(world.isChunkGenerated(xi + x, zi + z)) checkNeighbors(xi + x, zi + z, world);
}
}
}
}
}
private ProfileFuture measure() {
if(profiler != null) return profiler.measure("PopulationManagerTime");
return null;
}
public void attachProfiler(WorldProfiler p) {
this.profiler = p;
}
@SuppressWarnings("unchecked")
public synchronized void saveBlocks(World w) throws IOException {
File f = new File(Gaea.getGaeaFolder(w), "chunks.bin");
f.createNewFile();
SerializationUtil.toFile((HashSet<ChunkCoordinate>) needsPop.clone(), f);
}
@SuppressWarnings("unchecked")
public synchronized void loadBlocks(World w) throws IOException, ClassNotFoundException {
File f = new File(Gaea.getGaeaFolder(w), "chunks.bin");
needsPop.addAll((HashSet<ChunkCoordinate>) SerializationUtil.fromFile(f));
}
// Synchronize to prevent chunks from being queued for population multiple times.
public synchronized void checkNeighbors(int x, int z, World w) {
ChunkCoordinate c = new ChunkCoordinate(x, z, w.getUID());
if(w.isChunkGenerated(x + 1, z)
&& w.isChunkGenerated(x - 1, z)
&& w.isChunkGenerated(x, z + 1)
&& w.isChunkGenerated(x, z - 1) && needsPop.contains(c)) {
Random random = new FastRandom(w.getSeed());
long xRand = (random.nextLong() / 2L << 1L) + 1L;
long zRand = (random.nextLong() / 2L << 1L) + 1L;
random.setSeed((long) x * xRand + (long) z * zRand ^ w.getSeed());
Chunk currentChunk = w.getChunkAt(x, z);
for(TerraBlockPopulator r : attachedPopulators) {
r.populate(w, random, currentChunk);
}
needsPop.remove(c);
}
}
}

View File

@@ -1,45 +0,0 @@
package com.dfsek.terra.api.gaea.profiler;
import net.jafama.FastMath;
import net.md_5.bungee.api.ChatColor;
/**
* Class to hold a profiler data value. Contains formatting method to highlight value based on desired range.
*/
public class DataHolder {
private final long desired;
private final DataType type;
private final double desiredRangePercent;
/**
* Constructs a DataHolder with a DataType and a desired value, including a percentage around the desired value considered acceptable
*
* @param type The type of data held in this instance.
* @param desired The desired value. This should be the average value of whatever is being measured.
* @param desiredRangePercent The percentage around the desired value to be considered acceptable.
*/
public DataHolder(DataType type, long desired, double desiredRangePercent) {
this.desired = desired;
this.type = type;
this.desiredRangePercent = desiredRangePercent;
}
/**
* Returns a String, formatted with Bungee ChatColors.<br>
* GREEN if the value is better than desired and outside of acceptable range.<br>
* YELLOW if the value is better or worse than desired, and within acceptable range.<br>
* RED if the value is worse than desired and outside of acceptable range.<br>
*
* @param data The data to format.
* @return String - The formatted data.
*/
public String getFormattedData(long data) {
double range = desiredRangePercent * desired;
ChatColor color = ChatColor.YELLOW;
if(FastMath.abs(data - desired) > range) {
if(data > desired) color = type.getDesire().getHighColor();
else color = type.getDesire().getLowColor();
}
return color + type.getFormatted(data) + ChatColor.RESET;
}
}

View File

@@ -1,24 +0,0 @@
package com.dfsek.terra.api.gaea.profiler;
import net.jafama.FastMath;
public enum DataType {
PERIOD_MILLISECONDS(Desire.LOW, 1000000, "ms"), PERIOD_NANOSECONDS(Desire.LOW, 1, "ns");
private final Desire desire;
private final long divisor;
private final String unit;
DataType(Desire d, long divisor, String unit) {
this.desire = d;
this.divisor = divisor;
this.unit = unit;
}
public String getFormatted(long value) {
return (double) FastMath.round(((double) value / divisor) * 100D) / 100D + unit;
}
public Desire getDesire() {
return desire;
}
}

View File

@@ -1,36 +0,0 @@
package com.dfsek.terra.api.gaea.profiler;
import net.md_5.bungee.api.ChatColor;
/**
* Enum to represent the "goal" of a value, whether it is desirable for the value to be high (e.g. Frequency), or low (e.g. Period)
*/
public enum Desire {
LOW(ChatColor.RED, ChatColor.GREEN), HIGH(ChatColor.GREEN, ChatColor.RED);
private final ChatColor high;
private final ChatColor low;
Desire(ChatColor high, ChatColor low) {
this.high = high;
this.low = low;
}
/**
* Gets the color to display when the numerical value is higher than desired.
*
* @return ChatColor - color of the value.
*/
public ChatColor getHighColor() {
return high;
}
/**
* Gets the color to display when the numerical value is lower than desired.
*
* @return ChatColor - color of the value.
*/
public ChatColor getLowColor() {
return low;
}
}

View File

@@ -1,94 +0,0 @@
package com.dfsek.terra.api.gaea.profiler;
import com.dfsek.terra.api.gaea.math.MathUtil;
import com.dfsek.terra.api.gaea.util.GlueList;
import net.jafama.FastMath;
import org.bukkit.Bukkit;
import java.math.BigInteger;
import java.util.List;
/**
* Class to record and hold all data for a single type of measurement performed by the profiler.
*/
public class Measurement {
private final List<Long> measurements;
private final long desirable;
private final DataType type;
private long min = Long.MAX_VALUE;
private long max = Long.MIN_VALUE;
/**
* Constructs a new Measurement with a desired value and DataType.
*
* @param desirable The desired value of the measurement.
* @param type The type of data the measurement is holding.
*/
public Measurement(long desirable, DataType type) {
this.desirable = desirable;
this.type = type;
measurements = new GlueList<>();
}
public void record(long value) {
max = FastMath.max(value, max);
min = FastMath.min(value, min);
if(value / 1000000 > 5000) Bukkit.getLogger().warning("Measurement took " + type.getFormatted(value));
measurements.add(value);
}
public int size() {
return measurements.size();
}
public ProfileFuture beginMeasurement() {
ProfileFuture future = new ProfileFuture();
long current = System.nanoTime();
future.thenRun(() -> record(System.nanoTime() - current));
return future;
}
public void reset() {
min = Long.MAX_VALUE;
max = Long.MIN_VALUE;
measurements.clear();
}
public DataHolder getDataHolder() {
return new DataHolder(type, desirable, 0.25);
}
public long getMin() {
if(min == Long.MAX_VALUE) return 0;
return min;
}
public long getMax() {
if(max == Long.MIN_VALUE) return 0;
return max;
}
public long average() {
BigInteger running = new BigInteger("0");
List<Long> mTemp = new GlueList<>(measurements);
for(Long l : mTemp) {
running = running.add(BigInteger.valueOf(l));
}
if(measurements.size() == 0) return 0;
return running.divide(BigInteger.valueOf(measurements.size())).longValue();
}
public double getStdDev() {
List<Long> mTemp = new GlueList<>(measurements);
double[] vals = new double[mTemp.size()];
for(int i = 0; i < mTemp.size(); i++) {
vals[i] = mTemp.get(i);
}
return MathUtil.standardDeviation(vals);
}
public int entries() {
return measurements.size();
}
}

View File

@@ -1,18 +0,0 @@
package com.dfsek.terra.api.gaea.profiler;
import java.util.concurrent.CompletableFuture;
public class ProfileFuture extends CompletableFuture<Boolean> implements AutoCloseable {
public ProfileFuture() {
super();
}
public boolean complete() {
return super.complete(true);
}
@Override
public void close() {
this.complete();
}
}

View File

@@ -1,89 +0,0 @@
package com.dfsek.terra.api.gaea.profiler;
import com.dfsek.terra.api.generic.world.World;
import com.dfsek.terra.api.implementations.bukkit.generator.BukkitChunkGenerator;
import com.dfsek.terra.api.implementations.bukkit.generator.BukkitChunkGeneratorWrapper;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import net.jafama.FastMath;
import org.bukkit.ChatColor;
import java.util.Map;
public class WorldProfiler {
private final BiMap<String, Measurement> measures = HashBiMap.create();
private final World world;
private boolean isProfiling;
public WorldProfiler(World w) {
if(!(w.getGenerator() instanceof BukkitChunkGenerator))
throw new IllegalArgumentException("Attempted to instantiate profiler on non-Gaea managed world!");
this.addMeasurement(new Measurement(2500000, DataType.PERIOD_MILLISECONDS), "TotalChunkGenTime")
.addMeasurement(new Measurement(2500000, DataType.PERIOD_MILLISECONDS), "ChunkBaseGenTime")
.addMeasurement(new Measurement(2000000, DataType.PERIOD_MILLISECONDS), "BiomeApplyTime")
.addMeasurement(new Measurement(2000000, DataType.PERIOD_MILLISECONDS), "PopulationManagerTime");
isProfiling = false;
this.world = w;
((BukkitChunkGeneratorWrapper) ((BukkitChunkGenerator) w.getGenerator()).getHandle()).getDelegate().attachProfiler(this);
}
public String getResultsFormatted() {
if(! isProfiling) return "Profiler is not currently running.";
StringBuilder result = new StringBuilder(ChatColor.GOLD + "Gaea World Profiler Results (Min / Avg / Max / Std Dev): \n");
for(Map.Entry<String, Measurement> e : measures.entrySet()) {
result.append(ChatColor.GOLD)
.append(e.getKey())
.append(": ")
.append(e.getValue().getDataHolder().getFormattedData(e.getValue().getMin()))
.append(ChatColor.GOLD)
.append(" / ")
.append(e.getValue().getDataHolder().getFormattedData(e.getValue().average()))
.append(ChatColor.GOLD)
.append(" / ")
.append(e.getValue().getDataHolder().getFormattedData(e.getValue().getMax()))
.append(ChatColor.GOLD)
.append(" / ")
.append(ChatColor.GREEN)
.append((double) FastMath.round((e.getValue().getStdDev() / 1000000) * 100D) / 100D)
.append("ms")
.append(ChatColor.GOLD).append(" (x").append(e.getValue().size()).append(")\n");
}
return result.toString();
}
public void reset() {
for(Map.Entry<String, Measurement> e : measures.entrySet()) {
e.getValue().reset();
}
}
public com.dfsek.terra.api.gaea.profiler.WorldProfiler addMeasurement(Measurement m, String name) {
measures.put(name, m);
return this;
}
public void setMeasurement(String id, long value) {
if(isProfiling) measures.get(id).record(value);
}
public ProfileFuture measure(String id) {
if(isProfiling) return measures.get(id).beginMeasurement();
else return null;
}
public String getID(Measurement m) {
return measures.inverse().get(m);
}
public boolean isProfiling() {
return isProfiling;
}
public void setProfiling(boolean enabled) {
this.isProfiling = enabled;
}
public World getWorld() {
return world;
}
}

View File

@@ -1,50 +0,0 @@
package com.dfsek.terra.api.gaea.serial;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectStreamClass;
import java.lang.reflect.Field;
public class MovedObjectInputStream extends ObjectInputStream {
private final String oldNameSpace;
private final String newNameSpace;
public MovedObjectInputStream(InputStream in, String oldNameSpace, String newNameSpace) throws IOException {
super(in);
this.oldNameSpace = oldNameSpace;
this.newNameSpace = newNameSpace;
}
@Override
protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException {
ObjectStreamClass result = super.readClassDescriptor();
try {
if (result.getName().contains(oldNameSpace)) {
String newClassName = result.getName().replace(oldNameSpace, newNameSpace);
Class localClass = Class.forName(newClassName);
Field nameField = ObjectStreamClass.class.getDeclaredField("name");
nameField.setAccessible(true);
nameField.set(result, newClassName);
ObjectStreamClass localClassDescriptor = ObjectStreamClass.lookup(localClass);
Field suidField = ObjectStreamClass.class.getDeclaredField("suid");
suidField.setAccessible(true);
suidField.set(result, localClassDescriptor.getSerialVersionUID());
}
} catch(Exception e) {
throw new IOException("Exception when trying to replace namespace", e);
}
return result;
}
@Override
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
if (desc.getName().contains(oldNameSpace)) {
String newClassName = desc.getName().replace(oldNameSpace, newNameSpace);
return Class.forName(newClassName);
}
return super.resolveClass(desc);
}
}

View File

@@ -1,101 +0,0 @@
package com.dfsek.terra.api.gaea.structures.loot;
import com.dfsek.terra.api.gaea.structures.loot.functions.AmountFunction;
import com.dfsek.terra.api.gaea.structures.loot.functions.DamageFunction;
import com.dfsek.terra.api.gaea.structures.loot.functions.EnchantWithLevelsFunction;
import com.dfsek.terra.api.gaea.structures.loot.functions.Function;
import com.dfsek.terra.api.gaea.util.GlueList;
import net.jafama.FastMath;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import java.util.List;
import java.util.Random;
/**
* Representation of a single item entry within a Loot Table pool.
*/
public class Entry {
private final Material item;
private final long weight;
private final List<Function> functions = new GlueList<>();
/**
* Instantiates an Entry from a JSON representation.
*
* @param entry The JSON Object to instantiate from.
*/
public Entry(JSONObject entry) {
String id = entry.get("name").toString();
this.item = Material.matchMaterial(id);
long weight1;
try {
weight1 = (long) entry.get("weight");
} catch(NullPointerException e) {
weight1 = 1;
}
this.weight = weight1;
if(entry.containsKey("functions")) {
for(Object function : (JSONArray) entry.get("functions")) {
switch(((String) ((JSONObject) function).get("function"))) {
case "minecraft:set_count":
case "set_count":
Object loot = ((JSONObject) function).get("count");
long max, min;
if(loot instanceof Long) {
max = (Long) loot;
min = (Long) loot;
} else {
max = (long) ((JSONObject) loot).get("max");
min = (long) ((JSONObject) loot).get("min");
}
functions.add(new AmountFunction(FastMath.toIntExact(min), FastMath.toIntExact(max)));
break;
case "minecraft:set_damage":
case "set_damage":
long maxDamage = (long) ((JSONObject) ((JSONObject) function).get("damage")).get("max");
long minDamage = (long) ((JSONObject) ((JSONObject) function).get("damage")).get("min");
functions.add(new DamageFunction(FastMath.toIntExact(minDamage), FastMath.toIntExact(maxDamage)));
break;
case "minecraft:enchant_with_levels":
case "enchant_with_levels":
long maxEnchant = (long) ((JSONObject) ((JSONObject) function).get("levels")).get("max");
long minEnchant = (long) ((JSONObject) ((JSONObject) function).get("levels")).get("min");
JSONArray disabled = null;
if(((JSONObject) function).containsKey("disabled_enchants"))
disabled = (JSONArray) ((JSONObject) function).get("disabled_enchants");
functions.add(new EnchantWithLevelsFunction(FastMath.toIntExact(minEnchant), FastMath.toIntExact(maxEnchant), disabled));
break;
}
}
}
}
/**
* Fetches a single ItemStack from the Entry, applying all functions to it.
*
* @param r The Random instance to apply functions with
* @return ItemStack - The ItemStack with all functions applied.
*/
public ItemStack getItem(Random r) {
ItemStack item = new ItemStack(this.item, 1);
for(Function f : functions) {
item = f.apply(item, r);
}
return item;
}
/**
* Gets the weight attribute of the Entry.
*
* @return long - The weight of the Entry.
*/
public long getWeight() {
return this.weight;
}
}

View File

@@ -1,77 +0,0 @@
package com.dfsek.terra.api.gaea.structures.loot;
import com.dfsek.terra.api.gaea.util.GlueList;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import java.util.List;
import java.util.Random;
/**
* Class representation of a Loot Table to populate chest loot.
*/
public class LootTable {
private final List<Pool> pools = new GlueList<>();
/**
* Instantiates a LootTable from a JSON String.
*
* @param json The JSON String representing the loot table.
* @throws ParseException if malformed JSON is passed.
*/
public LootTable(String json) throws ParseException {
JSONParser jsonParser = new JSONParser();
Object tableJSON = jsonParser.parse(json);
JSONArray poolArray = (JSONArray) ((JSONObject) tableJSON).get("pools");
for(Object pool : poolArray) {
pools.add(new Pool((JSONObject) pool));
}
}
/**
* Fetches a list of ItemStacks from the loot table using the given Random instance.
*
* @param r The Random instance to use.
* @return List&lt;ItemStack&gt; - The list of loot fetched.
*/
public List<ItemStack> getLoot(Random r) {
List<ItemStack> itemList = new GlueList<>();
for(Pool pool : pools) {
itemList.addAll(pool.getItems(r));
}
return itemList;
}
/**
* Fills an Inventory with loot.
*
* @param i The Inventory to fill.
* @param r The The Random instance to use.
*/
public void fillInventory(Inventory i, Random r) {
List<ItemStack> loot = getLoot(r);
for(ItemStack stack : loot) {
int attempts = 0;
while(stack.getAmount() != 0 && attempts < 10) {
ItemStack newStack = stack.clone();
newStack.setAmount(1);
int slot = r.nextInt(i.getSize());
ItemStack slotItem = i.getItem(slot);
if(slotItem == null) {
i.setItem(slot, newStack);
stack.setAmount(stack.getAmount() - 1);
} else if(slotItem.getType() == newStack.getType()) {
ItemStack dep = newStack.clone();
dep.setAmount(newStack.getAmount() + slotItem.getAmount());
i.setItem(slot, dep);
stack.setAmount(stack.getAmount() - 1);
}
attempts++;
}
}
}
}

View File

@@ -1,57 +0,0 @@
package com.dfsek.terra.api.gaea.structures.loot;
import com.dfsek.terra.api.gaea.math.ProbabilityCollection;
import com.dfsek.terra.api.gaea.util.GlueList;
import net.jafama.FastMath;
import org.bukkit.inventory.ItemStack;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import java.util.List;
import java.util.Random;
/**
* Representation of a Loot Table pool, or a set of items to be fetched independently.
*/
public class Pool {
private final int max;
private final int min;
private final ProbabilityCollection<Entry> entries = new ProbabilityCollection<>();
/**
* Instantiates a Pool from a JSON representation.
*
* @param pool The JSON Object to instantiate from.
*/
public Pool(JSONObject pool) {
Object amount = pool.get("rolls");
if(amount instanceof Long) {
max = FastMath.toIntExact((Long) amount);
min = FastMath.toIntExact((Long) amount);
} else {
max = FastMath.toIntExact((Long) ((JSONObject) amount).get("max"));
min = FastMath.toIntExact((Long) ((JSONObject) amount).get("min"));
}
for(Object entryJSON : (JSONArray) pool.get("entries")) {
Entry entry = new Entry((JSONObject) entryJSON);
entries.add(entry, FastMath.toIntExact(entry.getWeight()));
}
}
/**
* Fetches a list of items from the pool using the provided Random instance.
*
* @param r The Random instance to use.
* @return List&lt;ItemStack&gt; - The list of items fetched.
*/
public List<ItemStack> getItems(Random r) {
int rolls = r.nextInt(max - min + 1) + min;
List<ItemStack> items = new GlueList<>();
for(int i = 0; i < rolls; i++) {
items.add(entries.get(r).getItem(r));
}
return items;
}
}

View File

@@ -1,37 +0,0 @@
package com.dfsek.terra.api.gaea.structures.loot.functions;
import org.bukkit.inventory.ItemStack;
import java.util.Random;
/**
* Loot Function fot setting the amount of an item.
*/
public class AmountFunction implements Function {
private final int max;
private final int min;
/**
* Instantiates an AmountFunction.
*
* @param min Minimum amount.
* @param max Maximum amount.
*/
public AmountFunction(int min, int max) {
this.min = min;
this.max = max;
}
/**
* Applies the function to an ItemStack.
*
* @param original The ItemStack on which to apply the function.
* @param r The Random instance to use.
* @return - ItemStack - The mutated ItemStack.
*/
@Override
public ItemStack apply(ItemStack original, Random r) {
original.setAmount(r.nextInt(max - min + 1) + min);
return original;
}
}

View File

@@ -1,42 +0,0 @@
package com.dfsek.terra.api.gaea.structures.loot.functions;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.Damageable;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.Random;
/**
* Loot Function for setting the damage on items in Loot Tables
*/
public class DamageFunction implements Function {
private final int max;
private final int min;
/**
* Instantiates a DamageFunction.
*
* @param min Minimum amount of damage (percentage, out of 100)
* @param max Maximum amount of damage (percentage, out of 100)
*/
public DamageFunction(int min, int max) {
this.min = min;
this.max = max;
}
/**
* Applies the function to an ItemStack.
*
* @param original The ItemStack on which to apply the function.
* @param r The Random instance to use.
* @return - ItemStack - The mutated ItemStack.
*/
@Override
public ItemStack apply(ItemStack original, Random r) {
double itemDurability = (r.nextDouble() * (max - min)) + min;
Damageable damage = (Damageable) original.getItemMeta();
damage.setDamage((int) (original.getType().getMaxDurability() - (itemDurability / 100) * original.getType().getMaxDurability()));
original.setItemMeta((ItemMeta) damage);
return original;
}
}

View File

@@ -1,61 +0,0 @@
package com.dfsek.terra.api.gaea.structures.loot.functions;
import com.dfsek.terra.api.gaea.util.GlueList;
import net.jafama.FastMath;
import org.bukkit.Bukkit;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
import org.json.simple.JSONArray;
import java.util.Collections;
import java.util.List;
import java.util.Random;
public class EnchantWithLevelsFunction implements Function {
private final int min;
private final int max;
private final JSONArray disabled;
public EnchantWithLevelsFunction(int min, int max, JSONArray disabled) {
this.max = max;
this.min = min;
this.disabled = disabled;
}
/**
* Applies the function to an ItemStack.
*
* @param original The ItemStack on which to apply the function.
* @param r The Random instance to use.
* @return - ItemStack - The mutated ItemStack.
*/
@Override
public ItemStack apply(ItemStack original, Random r) {
double enchant = (r.nextDouble() * (max - min)) + min;
List<Enchantment> possible = new GlueList<>();
for(Enchantment ench : Enchantment.values()) {
if(ench.canEnchantItem(original) && (disabled == null || !this.disabled.contains(ench.getName()))) {
possible.add(ench);
}
}
int numEnchant = (r.nextInt((int) FastMath.abs(enchant)) / 10 + 1);
if(possible.size() >= numEnchant) {
Collections.shuffle(possible);
iter:
for(int i = 0; i < numEnchant; i++) {
Enchantment chosen = possible.get(i);
for(Enchantment ench : original.getEnchantments().keySet()) {
if(chosen.conflictsWith(ench)) continue iter;
}
int lvl = r.nextInt(1 + (int) (((enchant / 40 > 1) ? 1 : enchant / 40) * (chosen.getMaxLevel())));
try {
original.addEnchantment(chosen, FastMath.max(lvl, 1));
} catch(IllegalArgumentException e) {
Bukkit.getLogger().warning("[Gaea] Attempted to enchant " + original.getType() + " with " + chosen + " at level " + FastMath.max(lvl, 1) + ", but an unexpected exception occurred! Usually this is caused by a misbehaving enchantment plugin.");
}
}
}
return original;
}
}

View File

@@ -1,19 +0,0 @@
package com.dfsek.terra.api.gaea.structures.loot.functions;
import org.bukkit.inventory.ItemStack;
import java.util.Random;
/**
* Interface for mutating items in Loot Tables.
*/
public interface Function {
/**
* Applies the function to an ItemStack.
*
* @param original The ItemStack on which to apply the function.
* @param r The Random instance to use.
* @return - ItemStack - The mutated ItemStack.
*/
ItemStack apply(ItemStack original, Random r);
}

View File

@@ -1,66 +0,0 @@
package com.dfsek.terra.api.gaea.tree;
import com.dfsek.terra.api.gaea.tree.fractal.FractalTree;
import com.dfsek.terra.api.gaea.tree.fractal.TreeGetter;
import com.dfsek.terra.api.gaea.tree.fractal.trees.Cactus;
import com.dfsek.terra.api.gaea.tree.fractal.trees.IceSpike;
import com.dfsek.terra.api.gaea.tree.fractal.trees.OakTree;
import com.dfsek.terra.api.gaea.tree.fractal.trees.ShatteredPillar;
import com.dfsek.terra.api.gaea.tree.fractal.trees.ShatteredTree;
import com.dfsek.terra.api.gaea.tree.fractal.trees.SmallShatteredPillar;
import com.dfsek.terra.api.gaea.tree.fractal.trees.SmallShatteredTree;
import com.dfsek.terra.api.gaea.tree.fractal.trees.SpruceTree;
import com.dfsek.terra.api.generic.world.vector.Location;
import java.util.Random;
public enum CustomTreeType implements TreeGetter {
SHATTERED_SMALL {
@Override
public FractalTree getTree(Location l, Random r) {
return new SmallShatteredTree(l, r);
}
},
SHATTERED_LARGE {
@Override
public FractalTree getTree(Location l, Random r) {
return new ShatteredTree(l, r);
}
},
GIANT_OAK {
@Override
public FractalTree getTree(Location l, Random r) {
return new OakTree(l, r);
}
},
GIANT_SPRUCE {
@Override
public FractalTree getTree(Location l, Random r) {
return new SpruceTree(l, r);
}
},
SMALL_SHATTERED_PILLAR {
@Override
public FractalTree getTree(Location l, Random r) {
return new SmallShatteredPillar(l, r);
}
},
LARGE_SHATTERED_PILLAR {
@Override
public FractalTree getTree(Location l, Random r) {
return new ShatteredPillar(l, r);
}
},
CACTUS {
@Override
public FractalTree getTree(Location l, Random r) {
return new Cactus(l, r);
}
},
ICE_SPIKE {
@Override
public FractalTree getTree(Location l, Random r) {
return new IceSpike(l, r);
}
}
}

View File

@@ -1,14 +0,0 @@
package com.dfsek.terra.api.gaea.tree;
import com.dfsek.terra.api.generic.world.block.MaterialData;
import com.dfsek.terra.api.generic.world.vector.Location;
import java.util.Random;
import java.util.Set;
public interface Tree {
boolean plant(Location l, Random r);
Set<MaterialData> getSpawnable();
}

View File

@@ -1,105 +0,0 @@
package com.dfsek.terra.api.gaea.tree;
import com.dfsek.terra.api.gaea.tree.fractal.FractalTree;
import com.dfsek.terra.api.generic.world.block.MaterialData;
import com.dfsek.terra.api.generic.world.vector.Location;
import com.dfsek.terra.api.implementations.bukkit.world.block.BukkitMaterialData;
import com.google.common.collect.Sets;
import org.bukkit.Material;
import java.util.Collections;
import java.util.Random;
import java.util.Set;
import java.util.stream.Collectors;
public enum TreeType implements Tree {
SHATTERED_SMALL(null, Collections.singleton(Material.END_STONE)),
SHATTERED_LARGE(null, Collections.singleton(Material.END_STONE)),
GIANT_OAK(null, Sets.newHashSet(Material.GRASS_BLOCK, Material.DIRT, Material.PODZOL)),
GIANT_SPRUCE(null, Sets.newHashSet(Material.GRASS_BLOCK, Material.DIRT, Material.PODZOL)),
SMALL_SHATTERED_PILLAR(null, Collections.singleton(Material.END_STONE)),
LARGE_SHATTERED_PILLAR(null, Collections.singleton(Material.END_STONE)),
CACTUS(null, Sets.newHashSet(Material.SAND, Material.RED_SAND)),
ICE_SPIKE(null, Sets.newHashSet(Material.SNOW_BLOCK, Material.SNOW, Material.STONE, Material.GRASS_BLOCK)),
OAK(org.bukkit.TreeType.TREE, Sets.newHashSet(Material.GRASS_BLOCK, Material.DIRT, Material.PODZOL)),
LARGE_OAK(org.bukkit.TreeType.BIG_TREE, Sets.newHashSet(Material.GRASS_BLOCK, Material.DIRT, Material.PODZOL)),
SPRUCE(org.bukkit.TreeType.REDWOOD, Sets.newHashSet(Material.GRASS_BLOCK, Material.DIRT, Material.PODZOL)),
LARGE_SPRUCE(org.bukkit.TreeType.TALL_REDWOOD, Sets.newHashSet(Material.GRASS_BLOCK, Material.DIRT, Material.PODZOL)),
MEGA_SPRUCE(org.bukkit.TreeType.MEGA_REDWOOD, Sets.newHashSet(Material.GRASS_BLOCK, Material.DIRT, Material.PODZOL)),
BIRCH(org.bukkit.TreeType.BIRCH, Sets.newHashSet(Material.GRASS_BLOCK, Material.DIRT, Material.PODZOL)),
CHORUS_PLANT(org.bukkit.TreeType.CHORUS_PLANT, Sets.newHashSet(Material.END_STONE)),
ACACIA(org.bukkit.TreeType.ACACIA, Sets.newHashSet(Material.GRASS_BLOCK, Material.DIRT, Material.PODZOL)),
TALL_BIRCH(org.bukkit.TreeType.TALL_BIRCH, Sets.newHashSet(Material.GRASS_BLOCK, Material.DIRT, Material.PODZOL)),
JUNGLE(org.bukkit.TreeType.JUNGLE, Sets.newHashSet(Material.GRASS_BLOCK, Material.DIRT, Material.PODZOL)),
SMALL_JUNGLE(org.bukkit.TreeType.SMALL_JUNGLE, Sets.newHashSet(Material.GRASS_BLOCK, Material.DIRT, Material.PODZOL)),
JUNGLE_COCOA(org.bukkit.TreeType.COCOA_TREE, Sets.newHashSet(Material.GRASS_BLOCK, Material.DIRT, Material.PODZOL)),
JUNGLE_BUSH(org.bukkit.TreeType.JUNGLE_BUSH, Sets.newHashSet(Material.GRASS_BLOCK, Material.DIRT, Material.PODZOL)),
DARK_OAK(org.bukkit.TreeType.DARK_OAK, Sets.newHashSet(Material.GRASS_BLOCK, Material.DIRT, Material.PODZOL)),
BROWN_MUSHROOM(org.bukkit.TreeType.BROWN_MUSHROOM, Sets.newHashSet(Material.GRASS_BLOCK, Material.DIRT, Material.PODZOL, Material.MYCELIUM, Material.NETHERRACK, Material.CRIMSON_NYLIUM, Material.WARPED_NYLIUM)),
RED_MUSHROOM(org.bukkit.TreeType.RED_MUSHROOM, Sets.newHashSet(Material.GRASS_BLOCK, Material.DIRT, Material.PODZOL, Material.MYCELIUM, Material.NETHERRACK, Material.CRIMSON_NYLIUM, Material.WARPED_NYLIUM)),
SWAMP_OAK(org.bukkit.TreeType.SWAMP, Sets.newHashSet(Material.GRASS_BLOCK, Material.DIRT, Material.PODZOL)),
WARPED_FUNGUS(org.bukkit.TreeType.WARPED_FUNGUS, Collections.singleton(Material.WARPED_NYLIUM)),
CRIMSON_FUNGUS(org.bukkit.TreeType.CRIMSON_FUNGUS, Collections.singleton(Material.CRIMSON_NYLIUM));
private final org.bukkit.TreeType vanillaType;
private final Set<Material> spawnable;
TreeType(org.bukkit.TreeType vanillaType, Set<Material> spawnable) {
this.vanillaType = vanillaType;
this.spawnable = spawnable;
}
public static com.dfsek.terra.api.gaea.tree.TreeType fromBukkit(org.bukkit.TreeType type) {
switch(type) {
case TREE: return OAK;
case BIRCH: return BIRCH;
case ACACIA: return ACACIA;
case SWAMP: return SWAMP_OAK;
case JUNGLE: return JUNGLE;
case REDWOOD: return SPRUCE;
case BIG_TREE: return LARGE_OAK;
case DARK_OAK: return DARK_OAK;
case COCOA_TREE: return JUNGLE_COCOA;
case TALL_BIRCH: return TALL_BIRCH;
case JUNGLE_BUSH: return JUNGLE_BUSH;
case CHORUS_PLANT: return CHORUS_PLANT;
case MEGA_REDWOOD: return MEGA_SPRUCE;
case RED_MUSHROOM: return RED_MUSHROOM;
case SMALL_JUNGLE: return SMALL_JUNGLE;
case TALL_REDWOOD: return LARGE_SPRUCE;
case WARPED_FUNGUS: return WARPED_FUNGUS;
case BROWN_MUSHROOM: return BROWN_MUSHROOM;
case CRIMSON_FUNGUS: return CRIMSON_FUNGUS;
default: throw new IllegalArgumentException();
}
}
public boolean isCustom() {
return this.vanillaType == null;
}
public org.bukkit.TreeType getVanillaTreeType() {
return vanillaType;
}
public CustomTreeType getCustomTreeType() {
if(getVanillaTreeType() != null) return null;
return CustomTreeType.valueOf(this.toString());
}
public boolean plant(Location l, Random r) {
if(this.getVanillaTreeType() == null) {
if(!spawnable.contains(l.subtract(0, 1, 0).getBlock().getType())) return false;
FractalTree tree = getCustomTreeType().getTree(l, r);
tree.grow();
tree.plant();
return true;
}
return l.getWorld().generateTree(l, this.getVanillaTreeType());
}
@Override
public Set<MaterialData> getSpawnable() {
return spawnable.stream().map(BukkitMaterialData::new).collect(Collectors.toSet());
}
}

View File

@@ -1,31 +0,0 @@
package com.dfsek.terra.api.gaea.tree.fractal;
import com.dfsek.terra.api.generic.world.vector.Location;
import org.bukkit.entity.Entity;
import org.bukkit.util.Consumer;
public class EntitySpawnHolder {
private final Location l;
private final Class<? extends Entity> e;
private final Consumer<Entity> c;
public EntitySpawnHolder(Location l, Class<? extends Entity> e, Consumer<Entity> c) {
this.l = l;
this.e = e;
this.c = c;
}
@SuppressWarnings("rawtypes")
public Class getEntity() {
return e;
}
public Consumer<Entity> getConsumer() {
return c;
}
public Location getLocation() {
return l;
}
}

View File

@@ -1,114 +0,0 @@
package com.dfsek.terra.api.gaea.tree.fractal;
import com.dfsek.terra.api.gaea.util.GlueList;
import com.dfsek.terra.api.generic.world.block.BlockData;
import com.dfsek.terra.api.generic.world.block.MaterialData;
import com.dfsek.terra.api.generic.world.vector.Location;
import com.dfsek.terra.api.implementations.bukkit.world.block.BukkitBlockData;
import org.bukkit.Material;
import org.bukkit.entity.Entity;
import org.bukkit.util.Consumer;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
public abstract class FractalTree {
private final Map<Location, BlockData> treeAssembler = new HashMap<>();
private final List<EntitySpawnHolder> entities = new GlueList<>();
private final Location origin;
private final Random random;
private final List<Material> replaceable = Arrays.asList(Material.AIR, Material.GRASS_BLOCK, Material.DIRT, Material.STONE, Material.COARSE_DIRT, Material.GRAVEL, Material.PODZOL,
Material.GRASS, Material.TALL_GRASS, Material.FERN, Material.POPPY, Material.LARGE_FERN, Material.BLUE_ORCHID, Material.AZURE_BLUET, Material.END_STONE, Material.SNOW, Material.SAND, Material.STONE_BUTTON, Material.DEAD_BUSH);
/**
* Instantiates a TreeGrower at an origin location.
*
* @param origin - The origin location.
* @param random - The random object to use whilst generating the tree.
*/
public FractalTree(Location origin, Random random) {
this.origin = origin.add(0, 1, 0);
this.random = random;
}
/**
* Gets the raw tree map.
*
* @return HashMap&lt;Location, BlockData&gt; - The raw dictionary representation of the tree.
*/
public Map<Location, BlockData> getTree() {
return treeAssembler;
}
/**
* Fetches the Random object used to generate the tree.
*
* @return Random - The Random object.
*/
public Random getRandom() {
return random;
}
/**
* Fetches the origin location.
*
* @return Location - The origin location specified upon instantiation.
*/
public Location getOrigin() {
return origin;
}
/**
* Sets a block in the tree's storage map to a material.
*
* @param l - The location to set.
* @param m - The material to which it will be set.
*/
public void setBlock(Location l, Material m) {
treeAssembler.put(l, new BukkitBlockData(m.createBlockData()));
}
/**
* Grows the tree in memory. Intended to be invoked from an async thread.
*/
public abstract void grow();
/**
* Pastes the tree in the world. Must be invoked from main thread.
*/
@SuppressWarnings("unchecked")
public void plant() {
for(Map.Entry<Location, BlockData> entry : treeAssembler.entrySet()) {
if(replaceable.contains(entry.getKey().getBlock().getType()))
entry.getKey().getBlock().setBlockData(entry.getValue(), false);
}
for(EntitySpawnHolder e : entities) {
Objects.requireNonNull(e.getLocation().getWorld()).spawn(e.getLocation(), e.getEntity(), e.getConsumer());
}
}
@SuppressWarnings("rawtypes, unchecked")
public void spawnEntity(Location spawn, Class clazz, Consumer<Entity> consumer) {
entities.add(new EntitySpawnHolder(spawn, clazz, consumer));
}
/**
* Gets the material at the specified block.
* Returns air if no material has been set.
*
* @param l - The location at which to check.
* @return Material - The material at the specified block.
*/
public MaterialData getMaterial(Location l) {
return treeAssembler.getOrDefault(l, new BukkitBlockData(Material.AIR.createBlockData())).getMaterial();
}
}

View File

@@ -1,66 +0,0 @@
package com.dfsek.terra.api.gaea.tree.fractal;
import com.dfsek.terra.api.gaea.math.ProbabilityCollection;
import com.dfsek.terra.api.generic.world.vector.Location;
import com.dfsek.terra.api.generic.world.vector.Vector3;
import org.bukkit.Material;
public class TreeGeometry {
private final FractalTree tree;
public TreeGeometry(FractalTree tree) {
this.tree = tree;
}
public static Vector3 getPerpendicular(Vector3 v) {
return v.getZ() < v.getX() ? new Vector3(v.getY(), - v.getX(), 0) : new Vector3(0, - v.getZ(), v.getY());
}
public FractalTree getTree() {
return tree;
}
public void generateSphere(Location l, Material m, int radius, boolean overwrite) {
generateSphere(l, new ProbabilityCollection<Material>().add(m, 1), radius, overwrite);
}
public void generateCylinder(Location l, Material m, int radius, int height, boolean overwrite) {
generateCylinder(l, new ProbabilityCollection<Material>().add(m, 1), radius, height, overwrite);
}
public void generateSphere(Location l, ProbabilityCollection<Material> m, int radius, boolean overwrite) {
for(int x = - radius; x <= radius; x++) {
for(int y = - radius; y <= radius; y++) {
for(int z = - radius; z <= radius; z++) {
Vector3 position = l.toVector().clone().add(new Vector3(x, y, z));
if(l.toVector().distance(position) <= radius + 0.5 && (overwrite || tree.getMaterial(position.toLocation(l.getWorld())).isAir()))
tree.setBlock(position.toLocation(l.getWorld()), m.get());
}
}
}
}
public void generateSponge(Location l, ProbabilityCollection<Material> m, int radius, boolean overwrite, int sponginess) {
for(int x = - radius; x <= radius; x++) {
for(int y = - radius; y <= radius; y++) {
for(int z = - radius; z <= radius; z++) {
Vector3 position = l.toVector().clone().add(new Vector3(x, y, z));
if(tree.getRandom().nextInt(100) < sponginess && l.toVector().distance(position) <= radius + 0.5 && (overwrite || tree.getMaterial(position.toLocation(l.getWorld())).isAir()))
tree.setBlock(position.toLocation(l.getWorld()), m.get());
}
}
}
}
public void generateCylinder(Location l, ProbabilityCollection<Material> m, int radius, int height, boolean overwrite) {
for(int x = - radius; x <= radius; x++) {
for(int y = 0; y <= height; y++) {
for(int z = - radius; z <= radius; z++) {
Vector3 position = l.toVector().clone().add(new Vector3(x, 0, z));
if(l.toVector().distance(position) <= radius + 0.5 && (overwrite || tree.getMaterial(position.toLocation(l.getWorld())).isAir()))
tree.setBlock(position.toLocation(l.getWorld()), m.get());
}
}
}
}
}

View File

@@ -1,9 +0,0 @@
package com.dfsek.terra.api.gaea.tree.fractal;
import com.dfsek.terra.api.generic.world.vector.Location;
import java.util.Random;
public interface TreeGetter {
FractalTree getTree(Location l, Random r);
}

View File

@@ -1,28 +0,0 @@
package com.dfsek.terra.api.gaea.tree.fractal.trees;
import com.dfsek.terra.api.gaea.tree.fractal.FractalTree;
import com.dfsek.terra.api.generic.world.vector.Location;
import org.bukkit.Material;
import java.util.Random;
public class Cactus extends FractalTree {
/**
* Instantiates a TreeGrower at an origin location.
*
* @param origin - The origin location.
* @param random - The random object to use whilst generating the tree.
*/
public Cactus(Location origin, Random random) {
super(origin, random);
}
/**
* Grows the tree in memory. Intended to be invoked from an async thread.
*/
@Override
public void grow() {
int h = super.getRandom().nextInt(4) + 1;
for(int i = 0; i < h; i++) setBlock(super.getOrigin().clone().add(0, i, 0), Material.CACTUS);
}
}

View File

@@ -1,47 +0,0 @@
package com.dfsek.terra.api.gaea.tree.fractal.trees;
import com.dfsek.terra.api.gaea.math.ProbabilityCollection;
import com.dfsek.terra.api.gaea.tree.fractal.FractalTree;
import com.dfsek.terra.api.gaea.tree.fractal.TreeGeometry;
import com.dfsek.terra.api.generic.world.vector.Location;
import com.dfsek.terra.api.generic.world.vector.Vector3;
import org.bukkit.Material;
import java.util.Random;
public class IceSpike extends FractalTree {
private final TreeGeometry geo;
private static final ProbabilityCollection<Material> ice = new ProbabilityCollection<Material>().add(Material.PACKED_ICE, 95).add(Material.BLUE_ICE, 5);
/**
* Instantiates a TreeGrower at an origin location.
*
* @param origin - The origin location.
* @param random - The random object to use whilst generating the tree.
*/
public IceSpike(Location origin, Random random) {
super(origin, random);
geo = new TreeGeometry(this);
}
private double getOffset() {
return (getRandom().nextDouble() - 0.5D);
}
/**
* Grows the tree in memory. Intended to be invoked from an async thread.
*/
@Override
public void grow() {
Vector3 direction = new Vector3(getOffset(), 0, getOffset());
Location l1 = super.getOrigin().clone();
int h = super.getRandom().nextInt(16) + 8;
for(int i = 0; i < h; i++) {
geo.generateSponge(l1.clone().add(0, i, 0).add(direction.clone().multiply(i)), ice, (int) ((1 - ((double) i / h)) * 2 + 1), true, 80);
}
for(int i = 0; i < h/3; i++) {
setBlock(l1.clone().add(0, h + i, 0).add(direction.clone().multiply(h + i)), ice.get(super.getRandom()));
}
}
}

View File

@@ -1,59 +0,0 @@
package com.dfsek.terra.api.gaea.tree.fractal.trees;
import com.dfsek.terra.api.gaea.tree.fractal.FractalTree;
import com.dfsek.terra.api.gaea.tree.fractal.TreeGeometry;
import com.dfsek.terra.api.generic.world.vector.Location;
import com.dfsek.terra.api.generic.world.vector.Vector3;
import net.jafama.FastMath;
import org.bukkit.Material;
import java.util.Random;
public class OakTree extends FractalTree {
private final TreeGeometry geo;
/**
* Instantiates a TreeGrower at an origin location.
*
* @param origin - The origin location.
* @param random - The random object to use whilst generating the tree.
*/
public OakTree(Location origin, Random random) {
super(origin, random);
geo = new TreeGeometry(this);
}
/**
* Grows the tree in memory. Intended to be invoked from an async thread.
*/
@Override
public void grow() {
growBranch(super.getOrigin().clone(), new Vector3(super.getRandom().nextInt(5) - 2, super.getRandom().nextInt(4) + 6, super.getRandom().nextInt(5) - 2), 2, 0);
}
private void growBranch(Location l1, Vector3 diff, double d1, int recursions) {
if(recursions > 1) {
geo.generateSphere(l1, Material.OAK_LEAVES, 1 + super.getRandom().nextInt(2) + (3 - recursions), false);
if(recursions > 2) return;
}
if(diff.getY() < 0) diff.rotateAroundAxis(TreeGeometry.getPerpendicular(diff.clone()).normalize(), FastMath.PI);
int d = (int) diff.length();
for(int i = 0; i < d; i++) {
geo.generateSphere(l1.clone().add(diff.clone().multiply((double) i / d)), Material.OAK_WOOD, FastMath.max((int) d1, 0), true);
}
double runningAngle = (double) 45 / (recursions + 1);
growBranch(l1.clone().add(diff), diff.clone().multiply(0.75).rotateAroundX(FastMath.toRadians(runningAngle + getNoise())).rotateAroundZ(FastMath.toRadians(getNoise())),
d1 - 1, recursions + 1);
growBranch(l1.clone().add(diff), diff.clone().multiply(0.75).rotateAroundX(FastMath.toRadians(- runningAngle + getNoise())).rotateAroundZ(FastMath.toRadians(getNoise())),
d1 - 1, recursions + 1);
growBranch(l1.clone().add(diff), diff.clone().multiply(0.75).rotateAroundZ(FastMath.toRadians(runningAngle + getNoise())).rotateAroundX(FastMath.toRadians(getNoise())),
d1 - 1, recursions + 1);
growBranch(l1.clone().add(diff), diff.clone().multiply(0.75).rotateAroundZ(FastMath.toRadians(- runningAngle + getNoise())).rotateAroundX(FastMath.toRadians(getNoise())),
d1 - 1, recursions + 1);
}
private int getNoise() {
return super.getRandom().nextInt(60) - 30;
}
}

View File

@@ -1,52 +0,0 @@
package com.dfsek.terra.api.gaea.tree.fractal.trees;
import com.dfsek.terra.api.gaea.tree.fractal.FractalTree;
import com.dfsek.terra.api.generic.world.vector.Location;
import org.bukkit.Material;
import org.bukkit.entity.EnderCrystal;
import java.util.Random;
public class ShatteredPillar extends FractalTree {
/**
* Instantiates a TreeGrower at an origin location.
*
* @param origin - The origin location.
* @param random - The random object to use whilst generating the tree.
*/
public ShatteredPillar(Location origin, Random random) {
super(origin, random);
}
/**
* Grows the tree in memory. Intended to be invoked from an async thread.
*/
@Override
public void grow() {
int h = super.getRandom().nextInt(5) + 8;
int max = h;
for(int i = - h; i < h; i++) setBlock(super.getOrigin().clone().add(0, i, 0), Material.OBSIDIAN);
h = h + (getRandom().nextBoolean() ? getRandom().nextInt(3) + 1 : - (getRandom().nextInt(3) + 1));
int[] crystalLoc = new int[] {0, 0};
if(h > max) {
max = h;
crystalLoc = new int[] {1, 0};
}
for(int i = - h; i < h; i++) setBlock(super.getOrigin().clone().add(1, i, 0), Material.OBSIDIAN);
h = h + (getRandom().nextBoolean() ? getRandom().nextInt(3) + 1 : - (getRandom().nextInt(3) + 1));
if(h > max) {
max = h;
crystalLoc = new int[] {0, 1};
}
for(int i = - h; i < h; i++) setBlock(super.getOrigin().clone().add(0, i, 1), Material.OBSIDIAN);
h = h + (getRandom().nextBoolean() ? getRandom().nextInt(3) + 1 : - (getRandom().nextInt(3) + 1));
if(h > max) {
max = h;
crystalLoc = new int[] {1, 1};
}
for(int i = - h; i < h; i++) setBlock(super.getOrigin().clone().add(1, i, 1), Material.OBSIDIAN);
if(getRandom().nextInt(100) < 25)
spawnEntity(getOrigin().add(crystalLoc[0] + 0.5, max, crystalLoc[1] + 0.5), EnderCrystal.class,
enderCrystal -> ((EnderCrystal) enderCrystal).setShowingBottom(false));
}
}

View File

@@ -1,66 +0,0 @@
package com.dfsek.terra.api.gaea.tree.fractal.trees;
import com.dfsek.terra.api.gaea.math.ProbabilityCollection;
import com.dfsek.terra.api.gaea.tree.fractal.FractalTree;
import com.dfsek.terra.api.gaea.tree.fractal.TreeGeometry;
import com.dfsek.terra.api.generic.world.vector.Location;
import com.dfsek.terra.api.generic.world.vector.Vector3;
import net.jafama.FastMath;
import org.bukkit.Material;
import java.util.Random;
public class ShatteredTree extends FractalTree {
private final TreeGeometry geo;
private final ProbabilityCollection<Material> bark = new ProbabilityCollection<Material>()
.add(Material.OBSIDIAN, 1)
.add(Material.BLACK_CONCRETE, 1);
private final ProbabilityCollection<Material> leaves = new ProbabilityCollection<Material>()
.add(Material.PURPLE_STAINED_GLASS, 1)
.add(Material.MAGENTA_STAINED_GLASS, 1);
/**
* Instantiates a TreeGrower at an origin location.
*
* @param origin - The origin location.
* @param random - The random object to use whilst generating the tree.
*/
public ShatteredTree(Location origin, Random random) {
super(origin, random);
geo = new TreeGeometry(this);
}
/**
* Grows the tree in memory. Intended to be invoked from an async thread.
*/
@Override
public void grow() {
growBranch(super.getOrigin().clone(), new Vector3(super.getRandom().nextInt(5) - 2, super.getRandom().nextInt(4) + 6, super.getRandom().nextInt(5) - 2), 1, 0);
}
private void growBranch(Location l1, Vector3 diff, double d1, int recursions) {
if(recursions > 2) {
geo.generateSphere(l1, leaves, 1 + super.getRandom().nextInt(2), false);
return;
}
if(diff.getY() < 0) diff.rotateAroundAxis(TreeGeometry.getPerpendicular(diff.clone()).normalize(), FastMath.PI);
int d = (int) diff.length();
for(int i = 0; i < d; i++) {
geo.generateSphere(l1.clone().add(diff.clone().multiply((double) i / d)), bark, FastMath.max((int) d1, 0), true);
}
double runningAngle = (double) 45 / (recursions + 1);
growBranch(l1.clone().add(diff), diff.clone().multiply(0.9).rotateAroundX(FastMath.toRadians(runningAngle + getNoise())).rotateAroundZ(FastMath.toRadians(getNoise())),
d1 - 1, recursions + 1);
growBranch(l1.clone().add(diff), diff.clone().multiply(0.9).rotateAroundX(FastMath.toRadians(- runningAngle + getNoise())).rotateAroundZ(FastMath.toRadians(getNoise())),
d1 - 1, recursions + 1);
growBranch(l1.clone().add(diff), diff.clone().multiply(0.9).rotateAroundZ(FastMath.toRadians(runningAngle + getNoise())).rotateAroundX(FastMath.toRadians(getNoise())),
d1 - 1, recursions + 1);
growBranch(l1.clone().add(diff), diff.clone().multiply(0.9).rotateAroundZ(FastMath.toRadians(- runningAngle + getNoise())).rotateAroundX(FastMath.toRadians(getNoise())),
d1 - 1, recursions + 1);
}
private int getNoise() {
return super.getRandom().nextInt(90) - 45;
}
}

View File

@@ -1,28 +0,0 @@
package com.dfsek.terra.api.gaea.tree.fractal.trees;
import com.dfsek.terra.api.gaea.tree.fractal.FractalTree;
import com.dfsek.terra.api.generic.world.vector.Location;
import org.bukkit.Material;
import java.util.Random;
public class SmallShatteredPillar extends FractalTree {
/**
* Instantiates a TreeGrower at an origin location.
*
* @param origin - The origin location.
* @param random - The random object to use whilst generating the tree.
*/
public SmallShatteredPillar(Location origin, Random random) {
super(origin, random);
}
/**
* Grows the tree in memory. Intended to be invoked from an async thread.
*/
@Override
public void grow() {
int h = super.getRandom().nextInt(5) + 5;
for(int i = - h; i < h; i++) setBlock(super.getOrigin().clone().add(0, i, 0), Material.OBSIDIAN);
}
}

View File

@@ -1,66 +0,0 @@
package com.dfsek.terra.api.gaea.tree.fractal.trees;
import com.dfsek.terra.api.gaea.math.ProbabilityCollection;
import com.dfsek.terra.api.gaea.tree.fractal.FractalTree;
import com.dfsek.terra.api.gaea.tree.fractal.TreeGeometry;
import com.dfsek.terra.api.generic.world.vector.Location;
import com.dfsek.terra.api.generic.world.vector.Vector3;
import net.jafama.FastMath;
import org.bukkit.Material;
import java.util.Random;
public class SmallShatteredTree extends FractalTree {
private final TreeGeometry geo;
private final ProbabilityCollection<Material> bark = new ProbabilityCollection<Material>()
.add(Material.OBSIDIAN, 1)
.add(Material.BLACK_CONCRETE, 1);
private final ProbabilityCollection<Material> leaves = new ProbabilityCollection<Material>()
.add(Material.PURPLE_STAINED_GLASS, 1)
.add(Material.MAGENTA_STAINED_GLASS, 1);
/**
* Instantiates a TreeGrower at an origin location.
*
* @param origin - The origin location.
* @param random - The random object to use whilst generating the tree.
*/
public SmallShatteredTree(Location origin, Random random) {
super(origin, random);
geo = new TreeGeometry(this);
}
/**
* Grows the tree in memory. Intended to be invoked from an async thread.
*/
@Override
public void grow() {
growBranch(super.getOrigin().clone(), new Vector3(super.getRandom().nextInt(5) - 2, super.getRandom().nextInt(3) + 4, super.getRandom().nextInt(5) - 2), 1.5, 0);
}
private void growBranch(Location l1, Vector3 diff, double d1, int recursions) {
if(recursions > 2) {
geo.generateSphere(l1, leaves, 1 + super.getRandom().nextInt(2) + (3 - recursions), false);
return;
}
if(diff.getY() < 0) diff.rotateAroundAxis(TreeGeometry.getPerpendicular(diff.clone()).normalize(), FastMath.PI);
int d = (int) diff.length();
for(int i = 0; i < d; i++) {
geo.generateSphere(l1.clone().add(diff.clone().multiply((double) i / d)), bark, FastMath.max((int) d1, 0), true);
}
double runningAngle = (double) 45 / (recursions + 1);
growBranch(l1.clone().add(diff), diff.clone().multiply(0.7).rotateAroundX(FastMath.toRadians(runningAngle + getNoise())).rotateAroundZ(FastMath.toRadians(getNoise())),
d1 - 1, recursions + 1);
growBranch(l1.clone().add(diff), diff.clone().multiply(0.7).rotateAroundX(FastMath.toRadians(- runningAngle + getNoise())).rotateAroundZ(FastMath.toRadians(getNoise())),
d1 - 1, recursions + 1);
growBranch(l1.clone().add(diff), diff.clone().multiply(0.7).rotateAroundZ(FastMath.toRadians(runningAngle + getNoise())).rotateAroundX(FastMath.toRadians(getNoise())),
d1 - 1, recursions + 1);
growBranch(l1.clone().add(diff), diff.clone().multiply(0.7).rotateAroundZ(FastMath.toRadians(- runningAngle + getNoise())).rotateAroundX(FastMath.toRadians(getNoise())),
d1 - 1, recursions + 1);
}
private int getNoise() {
return super.getRandom().nextInt(90) - 45;
}
}

View File

@@ -1,46 +0,0 @@
package com.dfsek.terra.api.gaea.tree.fractal.trees;
import com.dfsek.terra.api.gaea.tree.fractal.FractalTree;
import com.dfsek.terra.api.gaea.tree.fractal.TreeGeometry;
import com.dfsek.terra.api.generic.world.vector.Location;
import com.dfsek.terra.api.generic.world.vector.Vector3;
import net.jafama.FastMath;
import org.bukkit.Material;
import java.util.Random;
public class SpruceTree extends FractalTree {
private final TreeGeometry geo;
/**
* Instantiates a TreeGrower at an origin location.
*
* @param origin - The origin location.
* @param random - The random object to use whilst generating the tree.
*/
public SpruceTree(Location origin, Random random) {
super(origin, random);
geo = new TreeGeometry(this);
}
/**
* Grows the tree in memory. Intended to be invoked from an async thread.
*/
@Override
public void grow() {
growTrunk(super.getOrigin().clone(), new Vector3(0, 16 + super.getRandom().nextInt(5), 0));
}
private void growTrunk(Location l1, Vector3 diff) {
if(diff.getY() < 0) diff.rotateAroundAxis(TreeGeometry.getPerpendicular(diff.clone()).normalize(), FastMath.PI);
int d = (int) diff.length();
int rad = 7;
for(int i = 0; i < d; i++) {
geo.generateSphere(l1.clone().add(diff.clone().multiply((double) i / d)), Material.SPRUCE_WOOD, (int) ((i > d * 0.65) ? 0.5 : 1.5), true);
if(i > 3)
geo.generateCylinder(l1.clone().add(diff.clone().multiply((double) i / d)), Material.SPRUCE_LEAVES, (int) (((6 - (i % 4))) * (1.25 - ((double) i / d))), 1, false);
}
setBlock(l1.clone().add(diff), Material.SPRUCE_LEAVES);
setBlock(l1.clone().add(diff).add(0, 1, 0), Material.SPRUCE_LEAVES);
}
}

View File

@@ -1,64 +0,0 @@
package com.dfsek.terra.api.gaea.util;
import org.apache.commons.rng.core.source64.XoRoShiRo128PlusPlus;
import java.util.Random;
import java.util.SplittableRandom;
public class FastRandom extends Random {
private XoRoShiRo128PlusPlus random;
public FastRandom() {
super();
SplittableRandom randomseed = new SplittableRandom();
this.random = new XoRoShiRo128PlusPlus(randomseed.nextLong(), randomseed.nextLong());
}
public FastRandom(long seed) {
super(seed);
SplittableRandom randomseed = new SplittableRandom(seed);
this.random = new XoRoShiRo128PlusPlus(randomseed.nextLong(), randomseed.nextLong());
}
@Override
public boolean nextBoolean() {
return random.nextBoolean();
}
@Override
public int nextInt() {
return random.nextInt();
}
@Override
public float nextFloat() {
return (float) random.nextDouble();
}
@Override
public double nextDouble() {
return random.nextDouble();
}
@Override
public synchronized void setSeed(long seed) {
SplittableRandom randomseed = new SplittableRandom(seed);
this.random = new XoRoShiRo128PlusPlus(randomseed.nextLong(), randomseed.nextLong());
}
@Override
public void nextBytes(byte[] bytes) {
random.nextBytes(bytes);
}
@Override
public int nextInt(int bound) {
return random.nextInt(bound);
}
@Override
public long nextLong() {
return random.nextLong();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,38 +0,0 @@
package com.dfsek.terra.api.gaea.util;
import com.dfsek.terra.api.gaea.Debug;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public class JarUtil {
public static void copyResourcesToDirectory(JarFile fromJar, String sourceDir, String destDir) throws IOException {
for(Enumeration<JarEntry> entries = fromJar.entries(); entries.hasMoreElements(); ) {
JarEntry entry = entries.nextElement();
if(entry.getName().startsWith(sourceDir + "/") && ! entry.isDirectory()) {
File dest = new File(destDir + File.separator + entry.getName().substring(sourceDir.length() + 1));
if(dest.exists()) continue;
File parent = dest.getParentFile();
if(parent != null) {
parent.mkdirs();
}
Debug.info("Output does not already exist. Creating... ");
try(FileOutputStream out = new FileOutputStream(dest); InputStream in = fromJar.getInputStream(entry)) {
byte[] buffer = new byte[(8192)];
int s;
while((s = in.read(buffer)) > 0) {
out.write(buffer, 0, s);
}
} catch(IOException e) {
throw new IOException("Could not copy asset from jar file", e);
}
}
}
}
}

View File

@@ -1,26 +0,0 @@
package com.dfsek.terra.api.gaea.util;
import com.dfsek.terra.api.gaea.serial.MovedObjectInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class SerializationUtil {
public static Object fromFile(File f) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new MovedObjectInputStream(new FileInputStream(f), "org.polydev.gaea", "com.dfsek.terra.api.gaea"); // Backwards compat with old Gaea location
Object o = ois.readObject();
ois.close();
return o;
}
public static void toFile(Serializable o, File f) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(f));
oos.writeObject(o);
oos.close();
}
}

View File

@@ -1,46 +0,0 @@
package com.dfsek.terra.api.gaea.util;
import net.jafama.FastMath;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.Material;
import java.util.List;
public class WorldUtil {
public static int getHighestValidSpawnAt(Chunk chunk, int x, int z) {
int y;
for(y = chunk.getWorld().getMaxHeight() - 1; (chunk.getBlock(x, y, z).getType() != Material.GRASS_BLOCK
&& chunk.getBlock(x, y, z).getType() != Material.GRAVEL
&& chunk.getBlock(x, y, z).getType() != Material.PODZOL
&& chunk.getBlock(x, y, z).getType() != Material.END_STONE
&& chunk.getBlock(x, y, z).getType() != Material.DIRT
&& chunk.getBlock(x, y, z).getType() != Material.STONE
&& chunk.getBlock(x, y, z).getType() != Material.SAND
&& chunk.getBlock(x, y, z).getType() != Material.RED_SAND
&& chunk.getBlock(x, y, z).getType() != Material.COARSE_DIRT) && y > 0; y--)
;
return y;
}
public static int getHighestBlockAt(Chunk chunk, int x, int z) {
int y;
for(y = chunk.getWorld().getMaxHeight() - 1; (chunk.getBlock(x, y, z).getType().isAir()) && y > 0; y--) ;
return y;
}
public static List<Location> getLocationListBetween(Location loc1, Location loc2) {
int lowX = FastMath.min(loc1.getBlockX(), loc2.getBlockX());
int lowY = FastMath.min(loc1.getBlockY(), loc2.getBlockY());
int lowZ = FastMath.min(loc1.getBlockZ(), loc2.getBlockZ());
List<Location> locs = new GlueList<>();
for(int x = 0; x <= FastMath.abs(loc1.getBlockX() - loc2.getBlockX()); x++) {
for(int y = 0; y <= FastMath.abs(loc1.getBlockY() - loc2.getBlockY()); y++) {
for(int z = 0; z <= FastMath.abs(loc1.getBlockZ() - loc2.getBlockZ()); z++) {
locs.add(new Location(loc1.getWorld(), (double) lowX + x, (double) lowY + y, (double) lowZ + z));
}
}
}
return locs;
}
}

View File

@@ -1,14 +0,0 @@
package com.dfsek.terra.api.gaea.world;
import com.dfsek.terra.api.gaea.math.Range;
import com.dfsek.terra.api.generic.world.Chunk;
import com.dfsek.terra.api.generic.world.block.Block;
import com.dfsek.terra.api.generic.world.vector.Location;
import java.util.List;
public interface Flora {
List<Block> getValidSpawnsAt(Chunk chunk, int x, int z, Range check);
boolean plant(Location l);
}

View File

@@ -1,21 +0,0 @@
package com.dfsek.terra.api.gaea.world;
import org.bukkit.block.data.BlockData;
public class Ore {
private final int contChance;
private final BlockData oreMaterial;
public Ore(BlockData oreMaterial, int contChance) {
this.contChance = contChance;
this.oreMaterial = oreMaterial;
}
public int getContChance() {
return contChance;
}
public BlockData getType() {
return oreMaterial;
}
}

View File

@@ -1,59 +0,0 @@
package com.dfsek.terra.api.gaea.world.carving;
import com.dfsek.terra.api.gaea.math.MathUtil;
import com.dfsek.terra.api.gaea.util.FastRandom;
import com.dfsek.terra.api.generic.world.World;
import com.dfsek.terra.api.generic.world.vector.Vector3;
import net.jafama.FastMath;
import java.util.Random;
import java.util.function.BiConsumer;
public abstract class Carver {
private final int minY;
private final int maxY;
private final double sixtyFourSq = FastMath.pow(64, 2);
private int carvingRadius = 4;
public Carver(int minY, int maxY) {
this.minY = minY;
this.maxY = maxY;
}
public void carve(int chunkX, int chunkZ, World w, BiConsumer<Vector3, CarvingType> consumer) {
for(int x = chunkX - carvingRadius; x <= chunkX + carvingRadius; x++) {
for(int z = chunkZ - carvingRadius; z <= chunkZ + carvingRadius; z++) {
if(isChunkCarved(w, x, z, new FastRandom(MathUtil.hashToLong(this.getClass().getName() + "_" + x + "&" + z)))) {
long seed = MathUtil.getCarverChunkSeed(x, z, w.getSeed());
Random r = new FastRandom(seed);
Worm carving = getWorm(seed, new Vector3((x << 4) + r.nextInt(16), r.nextInt(maxY - minY + 1) + minY, (z << 4) + r.nextInt(16)));
Vector3 origin = carving.getOrigin();
for(int i = 0; i < carving.getLength(); i++) {
carving.step();
if(carving.getRunning().clone().setY(0).distanceSquared(origin.clone().setY(0)) > sixtyFourSq)
break;
if(FastMath.floorDiv(origin.getBlockX(), 16) != chunkX && FastMath.floorDiv(origin.getBlockZ(), 16) != chunkZ)
continue;
carving.getPoint().carve(chunkX, chunkZ, consumer);
}
}
}
}
}
public int getCarvingRadius() {
return carvingRadius;
}
public void setCarvingRadius(int carvingRadius) {
this.carvingRadius = carvingRadius;
}
public abstract Worm getWorm(long seed, Vector3 l);
public abstract boolean isChunkCarved(World w, int chunkX, int chunkZ, Random r);
public enum CarvingType {
CENTER, WALL, TOP, BOTTOM
}
}

View File

@@ -1,119 +0,0 @@
package com.dfsek.terra.api.gaea.world.carving;
import com.dfsek.terra.api.generic.world.vector.Vector3;
import net.jafama.FastMath;
import java.util.Random;
import java.util.function.BiConsumer;
public abstract class Worm {
private final Random r;
private final Vector3 origin;
private final Vector3 running;
private final int length;
private int topCut = 0;
private int bottomCut = 0;
private int[] radius = new int[] {0, 0, 0};
public Worm(int length, Random r, Vector3 origin) {
this.r = r;
this.length = length;
this.origin = origin;
this.running = origin;
}
public void setBottomCut(int bottomCut) {
this.bottomCut = bottomCut;
}
public void setTopCut(int topCut) {
this.topCut = topCut;
}
public Vector3 getOrigin() {
return origin;
}
public int getLength() {
return length;
}
public Vector3 getRunning() {
return running;
}
public WormPoint getPoint() {
return new WormPoint(running, radius, topCut, bottomCut);
}
public int[] getRadius() {
return radius;
}
public void setRadius(int[] radius) {
this.radius = radius;
}
public Random getRandom() {
return r;
}
public abstract void step();
public static class WormPoint {
private final Vector3 origin;
private final int topCut;
private final int bottomCut;
private final int[] rad;
public WormPoint(Vector3 origin, int[] rad, int topCut, int bottomCut) {
this.origin = origin;
this.rad = rad;
this.topCut = topCut;
this.bottomCut = bottomCut;
}
private static double ellipseEquation(int x, int y, int z, double xr, double yr, double zr) {
return (FastMath.pow2(x) / FastMath.pow2(xr + 0.5D)) + (FastMath.pow2(y) / FastMath.pow2(yr + 0.5D)) + (FastMath.pow2(z) / FastMath.pow2(zr + 0.5D));
}
public Vector3 getOrigin() {
return origin;
}
public int getRadius(int index) {
return rad[index];
}
public void carve(int chunkX, int chunkZ, BiConsumer<Vector3, Carver.CarvingType> consumer) {
int xRad = getRadius(0);
int yRad = getRadius(1);
int zRad = getRadius(2);
int originX = (chunkX << 4);
int originZ = (chunkZ << 4);
for(int x = -xRad - 1; x <= xRad + 1; x++) {
if(!(FastMath.floorDiv(origin.getBlockX() + x, 16) == chunkX)) continue;
for(int z = -zRad - 1; z <= zRad + 1; z++) {
if(!(FastMath.floorDiv(origin.getBlockZ() + z, 16) == chunkZ)) continue;
for(int y = -yRad - 1; y <= yRad + 1; y++) {
Vector3 position = origin.clone().add(new Vector3(x, y, z));
if(position.getY() < 0 || position.getY() > 255) continue;
double eq = ellipseEquation(x, y, z, xRad, yRad, zRad);
if(eq <= 1 &&
y >= -yRad - 1 + bottomCut && y <= yRad + 1 - topCut) {
consumer.accept(new Vector3(position.getBlockX() - originX, position.getBlockY(), position.getBlockZ() - originZ), Carver.CarvingType.CENTER);
} else if(eq <= 1.5) {
Carver.CarvingType type = Carver.CarvingType.WALL;
if(y <= -yRad - 1 + bottomCut) {
type = Carver.CarvingType.BOTTOM;
} else if(y >= yRad + 1 - topCut) {
type = Carver.CarvingType.TOP;
}
consumer.accept(new Vector3(position.getBlockX() - originX, position.getBlockY(), position.getBlockZ() - originZ), type);
}
}
}
}
}
}
}

View File

@@ -1,116 +0,0 @@
package com.dfsek.terra.api.gaea.world.palette;
import com.dfsek.terra.api.gaea.math.FastNoiseLite;
import com.dfsek.terra.api.gaea.math.ProbabilityCollection;
import com.dfsek.terra.api.gaea.util.GlueList;
import java.util.List;
import java.util.Random;
/**
* A class representation of a "slice" of the world.
* Used to get a section of blocks, based on the depth at which they are found.
*/
public abstract class Palette<E> {
private final List<PaletteLayer<E>> pallet = new GlueList<>();
/**
* Constructs a blank palette.
*/
public Palette() {
}
/**
* Adds a material to the palette, for a number of layers.
*
* @param m - The material to add to the palette.
* @param layers - The number of layers the material occupies.
* @return - BlockPalette instance for chaining.
*/
public com.dfsek.terra.api.gaea.world.palette.Palette<E> add(E m, int layers) {
for(int i = 0; i < layers; i++) {
pallet.add(new PaletteLayer<>(m));
}
return this;
}
/**
* Adds a ProbabilityCollection to the palette, for a number of layers.
*
* @param m - The ProbabilityCollection to add to the palette.
* @param layers - The number of layers the material occupies.
* @return - BlockPalette instance for chaining.
*/
public com.dfsek.terra.api.gaea.world.palette.Palette<E> add(ProbabilityCollection<E> m, int layers) {
for(int i = 0; i < layers; i++) {
pallet.add(new PaletteLayer<>(m));
}
return this;
}
/**
* Fetches a material from the palette, at a given layer.
*
* @param layer - The layer at which to fetch the material.
* @return BlockData - The material fetched.
*/
public abstract E get(int layer, int x, int z);
public int getSize() {
return pallet.size();
}
public List<PaletteLayer<E>> getLayers() {
return pallet;
}
/**
* Class representation of a layer of a BlockPalette.
*/
public static class PaletteLayer<E> {
private final boolean col; // Is layer using a collection?
private ProbabilityCollection<E> collection;
private E m;
/**
* Constructs a PaletteLayer with a ProbabilityCollection of materials and a number of layers.
*
* @param type - The collection of materials to choose from.
*/
public PaletteLayer(ProbabilityCollection<E> type) {
this.col = true;
this.collection = type;
}
/**
* Constructs a PaletteLayer with a single Material and a number of layers.
*
* @param type - The material to use.
*/
public PaletteLayer(E type) {
this.col = false;
this.m = type;
}
/**
* Gets a material from the layer.
*
* @return Material - the material..
*/
public E get(Random random) {
if(col) return this.collection.get(random);
return m;
}
public E get(FastNoiseLite random, int x, int z) {
if(col) return this.collection.get(random, x, z);
return m;
}
public ProbabilityCollection<E> getCollection() {
return collection;
}
}
}

View File

@@ -1,20 +0,0 @@
package com.dfsek.terra.api.gaea.world.palette;
import java.util.List;
import java.util.Random;
public class RandomPalette<E> extends Palette<E> {
private final Random r;
public RandomPalette(Random r) {
this.r = r;
}
@Override
public E get(int layer, int x, int z) {
if(layer > this.getSize()) return this.getLayers().get(this.getLayers().size() - 1).get(r);
List<PaletteLayer<E>> pl = getLayers();
if(layer >= pl.size()) return pl.get(pl.size() - 1).get(r);
return pl.get(layer).get(r);
}
}

View File

@@ -1,21 +0,0 @@
package com.dfsek.terra.api.gaea.world.palette;
import com.dfsek.terra.api.gaea.math.FastNoiseLite;
import java.util.List;
public class SimplexPalette<E> extends Palette<E> {
private final FastNoiseLite r;
public SimplexPalette(FastNoiseLite r) {
this.r = r;
}
@Override
public E get(int layer, int x, int z) {
if(layer > this.getSize()) return this.getLayers().get(this.getLayers().size() - 1).get(r, x, z);
List<PaletteLayer<E>> pl = getLayers();
if(layer >= pl.size()) return pl.get(pl.size() - 1).get(r, x, z);
return pl.get(layer).get(r, x, z);
}
}

View File

@@ -1,8 +0,0 @@
package com.dfsek.terra.api.generic;
/**
* An interface that contains a platform delegate.
*/
public interface Handle {
Object getHandle();
}

View File

@@ -1,21 +0,0 @@
package com.dfsek.terra.api.generic;
import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.api.LoaderRegistrar;
import com.dfsek.terra.api.generic.world.World;
import com.dfsek.terra.api.generic.world.WorldHandle;
import com.dfsek.terra.config.base.PluginConfig;
import java.util.logging.Logger;
public interface TerraPlugin extends LoaderRegistrar {
WorldHandle getHandle();
boolean isEnabled();
TerraWorld getWorld(World world);
Logger getLogger();
PluginConfig getTerraConfig();
}

View File

@@ -1,11 +0,0 @@
package com.dfsek.terra.api.generic.generator;
import com.dfsek.terra.api.generic.Handle;
import com.dfsek.terra.api.generic.world.Chunk;
import com.dfsek.terra.api.generic.world.World;
import java.util.Random;
public interface BlockPopulator extends Handle {
void populate(World world, Random random, Chunk chunk);
}

View File

@@ -1,10 +0,0 @@
package com.dfsek.terra.api.generic.generator;
import com.dfsek.terra.api.generic.world.Chunk;
import com.dfsek.terra.api.generic.world.World;
import java.util.Random;
public interface TerraBlockPopulator {
void populate(World world, Random random, Chunk chunk);
}

View File

@@ -1,31 +0,0 @@
package com.dfsek.terra.api.generic.generator;
import com.dfsek.terra.api.gaea.profiler.WorldProfiler;
import com.dfsek.terra.api.generic.world.BiomeGrid;
import com.dfsek.terra.api.generic.world.World;
import com.dfsek.terra.config.base.ConfigPack;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Random;
public interface TerraChunkGenerator {
ChunkGenerator.ChunkData generateChunkData(@NotNull World world, @NotNull Random random, int x, int z, @NotNull BiomeGrid biome, ChunkGenerator.ChunkData original);
void attachProfiler(WorldProfiler profiler);
boolean isParallelCapable();
boolean shouldGenerateCaves();
boolean shouldGenerateDecorations();
boolean shouldGenerateMobs();
boolean shouldGenerateStructures();
ConfigPack getConfigPack();
List<TerraBlockPopulator> getPopulators();
}

View File

@@ -1,6 +0,0 @@
package com.dfsek.terra.api.generic.world;
import com.dfsek.terra.api.generic.Handle;
public interface Biome extends Handle {
}

View File

@@ -1,46 +0,0 @@
package com.dfsek.terra.api.generic.world;
import com.dfsek.terra.api.generic.Handle;
import org.jetbrains.annotations.NotNull;
public interface BiomeGrid extends Handle {
/**
* Get biome at x, z within chunk being generated
*
* @param x - 0-15
* @param z - 0-15
* @return Biome value
*/
@NotNull
Biome getBiome(int x, int z);
/**
* Get biome at x, z within chunk being generated
*
* @param x - 0-15
* @param y - 0-255
* @param z - 0-15
* @return Biome value
*/
@NotNull
Biome getBiome(int x, int y, int z);
/**
* Set biome at x, z within chunk being generated
*
* @param x - 0-15
* @param z - 0-15
* @param bio - Biome value
*/
void setBiome(int x, int z, @NotNull Biome bio);
/**
* Set biome at x, z within chunk being generated
*
* @param x - 0-15
* @param y - 0-255
* @param z - 0-15
* @param bio - Biome value
*/
void setBiome(int x, int y, int z, @NotNull Biome bio);
}

View File

@@ -1,14 +0,0 @@
package com.dfsek.terra.api.generic.world;
import com.dfsek.terra.api.generic.Handle;
import com.dfsek.terra.api.generic.world.block.Block;
public interface Chunk extends Handle {
int getX();
int getZ();
World getWorld();
Block getBlock(int x, int y, int z);
}

View File

@@ -1,38 +0,0 @@
package com.dfsek.terra.api.generic.world;
import com.dfsek.terra.api.generic.Handle;
import com.dfsek.terra.api.generic.generator.ChunkGenerator;
import com.dfsek.terra.api.generic.world.block.Block;
import com.dfsek.terra.api.generic.world.vector.Location;
import org.bukkit.TreeType;
import org.bukkit.entity.Entity;
import org.bukkit.util.Consumer;
import java.io.File;
import java.util.UUID;
public interface World extends Handle {
long getSeed();
int getMaxHeight();
ChunkGenerator getGenerator();
String getName();
UUID getUID();
boolean isChunkGenerated(int x, int z);
Chunk getChunkAt(int x, int z);
File getWorldFolder();
Block getBlockAt(int x, int y, int z);
Block getBlockAt(Location l);
boolean generateTree(Location l, TreeType vanillaTreeType); // TODO: Bukkit treetype is bad
void spawn(Location location, Class<Entity> entity, Consumer<Entity> consumer); // TODO: Bukkit Entity is bad
}

View File

@@ -1,20 +0,0 @@
package com.dfsek.terra.api.generic.world;
import com.dfsek.terra.api.generic.world.block.Block;
import com.dfsek.terra.api.generic.world.block.BlockData;
import com.dfsek.terra.api.generic.world.block.MaterialData;
/**
* Interface to be implemented for world manipulation.
*/
public interface WorldHandle {
void setBlockData(Block block, BlockData data, boolean physics);
BlockData getBlockData(Block block);
MaterialData getType(Block block);
BlockData createBlockData(String data);
MaterialData createMaterialData(String data);
}

View File

@@ -1,28 +0,0 @@
package com.dfsek.terra.api.generic.world.block;
import com.dfsek.terra.api.generic.Handle;
import com.dfsek.terra.api.generic.world.vector.Location;
public interface Block extends Handle {
void setBlockData(BlockData data, boolean physics);
BlockData getBlockData();
Block getRelative(BlockFace face);
Block getRelative(BlockFace face, int len);
boolean isEmpty();
Location getLocation();
MaterialData getType();
int getX();
int getZ();
int getY();
boolean isPassable();
}

View File

@@ -1,11 +0,0 @@
package com.dfsek.terra.api.generic.world.block;
import com.dfsek.terra.api.generic.Handle;
public interface BlockData extends Cloneable, Handle {
MaterialData getMaterial();
boolean matches(MaterialData materialData);
BlockData clone();
}

View File

@@ -1,148 +0,0 @@
package com.dfsek.terra.api.generic.world.block;
import com.dfsek.terra.api.generic.world.vector.Vector3;
import org.jetbrains.annotations.NotNull;
public enum BlockFace {
NORTH(0, 0, -1),
EAST(1, 0, 0),
SOUTH(0, 0, 1),
WEST(-1, 0, 0),
UP(0, 1, 0),
DOWN(0, -1, 0),
NORTH_EAST(NORTH, EAST),
NORTH_WEST(NORTH, WEST),
SOUTH_EAST(SOUTH, EAST),
SOUTH_WEST(SOUTH, WEST),
WEST_NORTH_WEST(WEST, NORTH_WEST),
NORTH_NORTH_WEST(NORTH, NORTH_WEST),
NORTH_NORTH_EAST(NORTH, NORTH_EAST),
EAST_NORTH_EAST(EAST, NORTH_EAST),
EAST_SOUTH_EAST(EAST, SOUTH_EAST),
SOUTH_SOUTH_EAST(SOUTH, SOUTH_EAST),
SOUTH_SOUTH_WEST(SOUTH, SOUTH_WEST),
WEST_SOUTH_WEST(WEST, SOUTH_WEST),
SELF(0, 0, 0);
private final int modX;
private final int modY;
private final int modZ;
BlockFace(final int modX, final int modY, final int modZ) {
this.modX = modX;
this.modY = modY;
this.modZ = modZ;
}
BlockFace(final BlockFace face1, final BlockFace face2) {
this.modX = face1.getModX() + face2.getModX();
this.modY = face1.getModY() + face2.getModY();
this.modZ = face1.getModZ() + face2.getModZ();
}
/**
* Get the amount of X-coordinates to modify to get the represented block
*
* @return Amount of X-coordinates to modify
*/
public int getModX() {
return modX;
}
/**
* Get the amount of Y-coordinates to modify to get the represented block
*
* @return Amount of Y-coordinates to modify
*/
public int getModY() {
return modY;
}
/**
* Get the amount of Z-coordinates to modify to get the represented block
*
* @return Amount of Z-coordinates to modify
*/
public int getModZ() {
return modZ;
}
/**
* Gets the normal vector corresponding to this block face.
*
* @return the normal vector
*/
@NotNull
public Vector3 getDirection() {
Vector3 direction = new Vector3(modX, modY, modZ);
if(modX != 0 || modY != 0 || modZ != 0) {
direction.normalize();
}
return direction;
}
@NotNull
public org.bukkit.block.BlockFace getOppositeFace() {
switch(this) {
case NORTH:
return org.bukkit.block.BlockFace.SOUTH;
case SOUTH:
return org.bukkit.block.BlockFace.NORTH;
case EAST:
return org.bukkit.block.BlockFace.WEST;
case WEST:
return org.bukkit.block.BlockFace.EAST;
case UP:
return org.bukkit.block.BlockFace.DOWN;
case DOWN:
return org.bukkit.block.BlockFace.UP;
case NORTH_EAST:
return org.bukkit.block.BlockFace.SOUTH_WEST;
case NORTH_WEST:
return org.bukkit.block.BlockFace.SOUTH_EAST;
case SOUTH_EAST:
return org.bukkit.block.BlockFace.NORTH_WEST;
case SOUTH_WEST:
return org.bukkit.block.BlockFace.NORTH_EAST;
case WEST_NORTH_WEST:
return org.bukkit.block.BlockFace.EAST_SOUTH_EAST;
case NORTH_NORTH_WEST:
return org.bukkit.block.BlockFace.SOUTH_SOUTH_EAST;
case NORTH_NORTH_EAST:
return org.bukkit.block.BlockFace.SOUTH_SOUTH_WEST;
case EAST_NORTH_EAST:
return org.bukkit.block.BlockFace.WEST_SOUTH_WEST;
case EAST_SOUTH_EAST:
return org.bukkit.block.BlockFace.WEST_NORTH_WEST;
case SOUTH_SOUTH_EAST:
return org.bukkit.block.BlockFace.NORTH_NORTH_WEST;
case SOUTH_SOUTH_WEST:
return org.bukkit.block.BlockFace.NORTH_NORTH_EAST;
case WEST_SOUTH_WEST:
return org.bukkit.block.BlockFace.EAST_NORTH_EAST;
case SELF:
return org.bukkit.block.BlockFace.SELF;
}
return org.bukkit.block.BlockFace.SELF;
}
}

View File

@@ -1,13 +0,0 @@
package com.dfsek.terra.api.generic.world.block;
import com.dfsek.terra.api.generic.Handle;
public interface MaterialData extends Handle {
boolean matches(MaterialData other);
boolean matches(BlockData other);
boolean isSolid();
boolean isAir();
}

View File

@@ -1,20 +0,0 @@
package com.dfsek.terra.api.generic.world.block.data;
import com.dfsek.terra.api.generic.world.block.BlockData;
public interface Bisected extends BlockData {
Half getHalf();
void setHalf(Half half);
enum Half {
/**
* The top half of the block, normally with the higher y coordinate.
*/
TOP,
/**
* The bottom half of the block, normally with the lower y coordinate.
*/
BOTTOM
}
}

View File

@@ -1,10 +0,0 @@
package com.dfsek.terra.api.generic.world.block.data;
import com.dfsek.terra.api.generic.world.block.BlockData;
import com.dfsek.terra.api.generic.world.block.BlockFace;
public interface Directional extends BlockData {
BlockFace getFacing();
void setFacing(BlockFace facing);
}

View File

@@ -1,12 +0,0 @@
package com.dfsek.terra.api.generic.world.block.data;
import com.dfsek.terra.api.generic.world.block.BlockData;
import com.dfsek.terra.api.generic.world.block.BlockFace;
import java.util.Set;
public interface MultipleFacing extends BlockData {
Set<BlockFace> getFaces();
void setFace(BlockFace face, boolean facing);
}

View File

@@ -1,10 +0,0 @@
package com.dfsek.terra.api.generic.world.block.data;
import com.dfsek.terra.api.generic.world.block.BlockData;
import com.dfsek.terra.api.generic.world.block.BlockFace;
public interface Rotatable extends BlockData {
BlockFace getRotation();
void setRotation(BlockFace face);
}

View File

@@ -1,4 +0,0 @@
package com.dfsek.terra.api.generic.world.block.data;
public interface Slab extends Bisected, Waterlogged {
}

View File

@@ -1,30 +0,0 @@
package com.dfsek.terra.api.generic.world.block.data;
public interface Stairs extends Waterlogged, Directional, Bisected {
Shape getShape();
void setShape(Shape shape);
enum Shape {
/**
* Regular stair block.
*/
STRAIGHT,
/**
* Inner corner stair block with higher left side.
*/
INNER_LEFT,
/**
* Inner corner stair block with higher right side.
*/
INNER_RIGHT,
/**
* Outer corner stair block with higher left side.
*/
OUTER_LEFT,
/**
* Outer corner stair block with higher right side.
*/
OUTER_RIGHT
}
}

View File

@@ -1,9 +0,0 @@
package com.dfsek.terra.api.generic.world.block.data;
import com.dfsek.terra.api.generic.world.block.BlockData;
public interface Waterlogged extends BlockData {
boolean isWaterlogged();
void setWaterlogged(boolean waterlogged);
}

View File

@@ -1,108 +0,0 @@
package com.dfsek.terra.api.generic.world.vector;
import com.dfsek.terra.api.generic.world.World;
import com.dfsek.terra.api.generic.world.block.Block;
public class Location implements Cloneable {
private World world;
private Vector3 vector;
public Location(World w, double x, double y, double z) {
this.world = w;
this.vector = new Vector3(x, y, z);
}
public Location(World w, Vector3 vector) {
this.world = w;
this.vector = vector;
}
public void setWorld(World world) {
this.world = world;
}
public Vector3 getVector() {
return vector;
}
public void setVector(Vector3 vector) {
this.vector = vector;
}
@Override
public Location clone() {
try {
Location other = (Location) super.clone();
other.setVector(other.getVector().clone());
return other;
} catch(CloneNotSupportedException e) {
throw new Error(e);
}
}
public int getBlockX() {
return vector.getBlockX();
}
public int getBlockY() {
return vector.getBlockY();
}
public int getBlockZ() {
return vector.getBlockZ();
}
public double getY() {
return vector.getY();
}
public Location setY(double y) {
vector.setY(y);
return this;
}
public double getX() {
return vector.getX();
}
public Location setX(double x) {
vector.setX(x);
return this;
}
public double getZ() {
return vector.getZ();
}
public Location setZ(double z) {
vector.setZ(z);
return this;
}
public World getWorld() {
return world;
}
public Location add(double x, double y, double z) {
vector.add(x, y, z);
return this;
}
public Block getBlock() {
return world.getBlockAt(this);
}
public Location subtract(int x, int y, int z) {
vector.subtract(x, y, z);
return this;
}
public Location add(Vector3 add) {
vector.add(add);
return this;
}
public Vector3 toVector() {
return vector.clone();
}
}

View File

@@ -1,180 +0,0 @@
package com.dfsek.terra.api.generic.world.vector;
import net.jafama.FastMath;
/**
* oh yeah
*/
@SuppressWarnings("unused")
public class Vector2 implements Cloneable {
private double x;
private double z;
/**
* Create a vector with a given X and Z component
*
* @param x X component
* @param z Z component
*/
public Vector2(double x, double z) {
this.x = x;
this.z = z;
}
/**
* Get X component
*
* @return X component
*/
public double getX() {
return x;
}
public Vector2 setX(double x) {
this.x = x;
return this;
}
/**
* Get Z component
*
* @return Z component
*/
public double getZ() {
return z;
}
public Vector2 setZ(double z) {
this.z = z;
return this;
}
/**
* Multiply X and Z components by a value.
*
* @param m Value to multiply
* @return Mutated vector, for chaining.
*/
public Vector2 multiply(double m) {
x *= m;
z *= m;
return this;
}
/**
* Add this vector to another.
*
* @param other Vector to add
* @return Mutated vector, for chaining.
*/
public Vector2 add(Vector2 other) {
x += other.x;
z += other.z;
return this;
}
/**
* Subtract a vector from this vector,
*
* @param other Vector to subtract
* @return Mutated vector, for chaining.
*/
public Vector2 subtract(Vector2 other) {
x -= other.x;
z -= other.z;
return this;
}
/**
* Normalize this vector to length 1
*
* @return Mutated vector, for chaining.
*/
public Vector2 normalize() {
divide(length());
return this;
}
/**
* Divide X and Z components by a value.
*
* @param d Divisor
* @return Mutated vector, for chaining.
*/
public Vector2 divide(double d) {
x /= d;
z /= d;
return this;
}
/**
* Get the length of this Vector
*
* @return length
*/
public double length() {
return FastMath.sqrt(lengthSquared());
}
/**
* Get the squared length of this Vector
*
* @return squared length
*/
public double lengthSquared() {
return x * x + z * z;
}
/**
* Get the distance from this vector to another.
*
* @param other Another vector
* @return Distance between vectors
*/
public double distance(Vector2 other) {
return FastMath.sqrt(distanceSquared(other));
}
/**
* Get the squared distance between 2 vectors.
*
* @param other Another vector
* @return Squared distance
*/
public double distanceSquared(Vector2 other) {
double dx = other.x - x;
double dz = other.z - z;
return dx * dx + dz * dz;
}
@Override
public int hashCode() {
int hash = 17;
hash = 31 * hash + Double.hashCode(x);
hash = 31 * hash + Double.hashCode(z);
return hash;
}
@Override
public boolean equals(Object obj) {
if(!(obj instanceof Vector2)) {
return false;
}
Vector2 other = (Vector2) obj;
return other.x == this.x && other.z == this.z;
}
@Override
public Vector2 clone() {
try {
return (Vector2) super.clone();
} catch(CloneNotSupportedException e) {
throw new Error(e);
}
}
@Override
public String toString() {
return "(" + x + ", " + z + ")";
}
}

View File

@@ -1,310 +0,0 @@
package com.dfsek.terra.api.generic.world.vector;
import com.dfsek.terra.api.generic.world.World;
import net.jafama.FastMath;
import org.bukkit.util.NumberConversions;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
public class Vector3 implements Cloneable {
/**
* Threshold for fuzzy equals().
*/
private static final double epsilon = 0.000001;
private double x;
private double y;
private double z;
public Vector3(double x, double y, double z) {
this.x = x;
this.y = y;
this.z = z;
}
/**
* Get the threshold used for equals().
*
* @return The epsilon.
*/
public static double getEpsilon() {
return epsilon;
}
public double getZ() {
return z;
}
public Vector3 setZ(double z) {
this.z = z;
return this;
}
public double getX() {
return x;
}
public Vector3 setX(double x) {
this.x = x;
return this;
}
public double getY() {
return y;
}
public Vector3 setY(double y) {
this.y = y;
return this;
}
public int getBlockX() {
return FastMath.floorToInt(x);
}
public int getBlockY() {
return FastMath.floorToInt(y);
}
public int getBlockZ() {
return FastMath.floorToInt(z);
}
public Vector3 multiply(double m) {
x *= m;
y *= m;
z *= m;
return this;
}
public Vector3 add(double x, double y, double z) {
this.x += x;
this.y += y;
this.z += z;
return this;
}
public Vector3 add(Vector3 other) {
this.x += other.getX();
this.y += other.getY();
this.z += other.getZ();
return this;
}
public Vector3 add(Vector2 other) {
this.x += other.getX();
this.z += other.getZ();
return this;
}
public double lengthSquared() {
return x * x + y * y + z * z;
}
@Override
public Vector3 clone() {
try {
return (Vector3) super.clone();
} catch(CloneNotSupportedException e) {
throw new Error(e);
}
}
public double length() {
return FastMath.sqrt(lengthSquared());
}
/**
* Returns if a vector is normalized
*
* @return whether the vector is normalised
*/
public boolean isNormalized() {
return Math.abs(this.lengthSquared() - 1) < getEpsilon();
}
/**
* Rotates the vector around the x axis.
* <p>
* This piece of math is based on the standard rotation matrix for vectors
* in three dimensional space. This matrix can be found here:
* <a href="https://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">Rotation
* Matrix</a>.
*
* @param angle the angle to rotate the vector about. This angle is passed
* in radians
* @return the same vector
*/
@NotNull
public Vector3 rotateAroundX(double angle) {
double angleCos = Math.cos(angle);
double angleSin = Math.sin(angle);
double y = angleCos * getY() - angleSin * getZ();
double z = angleSin * getY() + angleCos * getZ();
return setY(y).setZ(z);
}
/**
* Rotates the vector around the y axis.
* <p>
* This piece of math is based on the standard rotation matrix for vectors
* in three dimensional space. This matrix can be found here:
* <a href="https://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">Rotation
* Matrix</a>.
*
* @param angle the angle to rotate the vector about. This angle is passed
* in radians
* @return the same vector
*/
@NotNull
public Vector3 rotateAroundY(double angle) {
double angleCos = Math.cos(angle);
double angleSin = Math.sin(angle);
double x = angleCos * getX() + angleSin * getZ();
double z = -angleSin * getX() + angleCos * getZ();
return setX(x).setZ(z);
}
/**
* Rotates the vector around the z axis
* <p>
* This piece of math is based on the standard rotation matrix for vectors
* in three dimensional space. This matrix can be found here:
* <a href="https://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">Rotation
* Matrix</a>.
*
* @param angle the angle to rotate the vector about. This angle is passed
* in radians
* @return the same vector
*/
@NotNull
public Vector3 rotateAroundZ(double angle) {
double angleCos = Math.cos(angle);
double angleSin = Math.sin(angle);
double x = angleCos * getX() - angleSin * getY();
double y = angleSin * getX() + angleCos * getY();
return setX(x).setY(y);
}
/**
* Get the distance between this vector and another. The value of this
* method is not cached and uses a costly square-root function, so do not
* repeatedly call this method to get the vector's magnitude. NaN will be
* returned if the inner result of the sqrt() function overflows, which
* will be caused if the distance is too long.
*
* @param o The other vector
* @return the distance
*/
public double distance(@NotNull Vector3 o) {
return FastMath.sqrt(NumberConversions.square(x - o.x) + NumberConversions.square(y - o.y) + NumberConversions.square(z - o.z));
}
/**
* Get the squared distance between this vector and another.
*
* @param o The other vector
* @return the distance
*/
public double distanceSquared(@NotNull Vector3 o) {
return NumberConversions.square(x - o.x) + NumberConversions.square(y - o.y) + NumberConversions.square(z - o.z);
}
/**
* Rotates the vector around a given arbitrary axis in 3 dimensional space.
*
* <p>
* Rotation will follow the general Right-Hand-Rule, which means rotation
* will be counterclockwise when the axis is pointing towards the observer.
* <p>
* This method will always make sure the provided axis is a unit vector, to
* not modify the length of the vector when rotating. If you are experienced
* with the scaling of a non-unit axis vector, you can use
* {@link Vector#rotateAroundNonUnitAxis(Vector, double)}.
*
* @param axis the axis to rotate the vector around. If the passed vector is
* not of length 1, it gets copied and normalized before using it for the
* rotation. Please use {@link Vector#normalize()} on the instance before
* passing it to this method
* @param angle the angle to rotate the vector around the axis
* @return the same vector
* @throws IllegalArgumentException if the provided axis vector instance is
* null
*/
@NotNull
public Vector3 rotateAroundAxis(@NotNull Vector3 axis, double angle) throws IllegalArgumentException {
return rotateAroundNonUnitAxis(axis.isNormalized() ? axis : axis.clone().normalize(), angle);
}
/**
* Rotates the vector around a given arbitrary axis in 3 dimensional space.
*
* <p>
* Rotation will follow the general Right-Hand-Rule, which means rotation
* will be counterclockwise when the axis is pointing towards the observer.
* <p>
* Note that the vector length will change accordingly to the axis vector
* length. If the provided axis is not a unit vector, the rotated vector
* will not have its previous length. The scaled length of the resulting
* vector will be related to the axis vector. If you are not perfectly sure
* about the scaling of the vector, use
* {@link Vector#rotateAroundAxis(Vector, double)}
*
* @param axis the axis to rotate the vector around.
* @param angle the angle to rotate the vector around the axis
* @return the same vector
* @throws IllegalArgumentException if the provided axis vector instance is
* null
*/
@NotNull
public Vector3 rotateAroundNonUnitAxis(@NotNull Vector3 axis, double angle) throws IllegalArgumentException {
double x = getX(), y = getY(), z = getZ();
double x2 = axis.getX(), y2 = axis.getY(), z2 = axis.getZ();
double cosTheta = Math.cos(angle);
double sinTheta = Math.sin(angle);
double dotProduct = this.dot(axis);
double xPrime = x2 * dotProduct * (1d - cosTheta)
+ x * cosTheta
+ (-z2 * y + y2 * z) * sinTheta;
double yPrime = y2 * dotProduct * (1d - cosTheta)
+ y * cosTheta
+ (z2 * x - x2 * z) * sinTheta;
double zPrime = z2 * dotProduct * (1d - cosTheta)
+ z * cosTheta
+ (-y2 * x + x2 * y) * sinTheta;
return setX(xPrime).setY(yPrime).setZ(zPrime);
}
/**
* Calculates the dot product of this vector with another. The dot product
* is defined as x1*x2+y1*y2+z1*z2. The returned value is a scalar.
*
* @param other The other vector
* @return dot product
*/
public double dot(@NotNull Vector3 other) {
return x * other.x + y * other.y + z * other.z;
}
public Location toLocation(World world) {
return new Location(world, this.clone());
}
public Vector3 normalize() {
return this.multiply(1D / this.length());
}
public Vector3 subtract(int x, int y, int z) {
this.x -= x;
this.y -= y;
this.z = -z;
return this;
}
}

View File

@@ -1,40 +0,0 @@
package com.dfsek.terra.api.implementations.bukkit;
import com.dfsek.terra.api.generic.world.Biome;
import com.dfsek.terra.api.generic.world.BiomeGrid;
import com.dfsek.terra.api.implementations.bukkit.world.BukkitBiome;
import org.bukkit.generator.ChunkGenerator;
import org.jetbrains.annotations.NotNull;
public class BukkitBiomeGrid implements BiomeGrid {
private final ChunkGenerator.BiomeGrid delegate;
public BukkitBiomeGrid(ChunkGenerator.BiomeGrid biomeGrid) {
this.delegate = biomeGrid;
}
@Override
public ChunkGenerator.BiomeGrid getHandle() {
return delegate;
}
@Override
public @NotNull Biome getBiome(int x, int z) {
return new BukkitBiome(delegate.getBiome(x, z));
}
@Override
public @NotNull Biome getBiome(int x, int y, int z) {
return new BukkitBiome(delegate.getBiome(x, y, z));
}
@Override
public void setBiome(int x, int z, @NotNull Biome bio) {
delegate.setBiome(x, z, ((BukkitBiome) bio).getHandle());
}
@Override
public void setBiome(int x, int y, int z, @NotNull Biome bio) {
delegate.setBiome(x, y, z, ((BukkitBiome) bio).getHandle());
}
}

View File

@@ -1,39 +0,0 @@
package com.dfsek.terra.api.implementations.bukkit;
import com.dfsek.terra.api.generic.world.Chunk;
import com.dfsek.terra.api.generic.world.World;
import com.dfsek.terra.api.generic.world.block.Block;
import com.dfsek.terra.api.implementations.bukkit.world.block.BukkitBlock;
public class BukkitChunk implements Chunk {
private final org.bukkit.Chunk delegate;
public BukkitChunk(org.bukkit.Chunk delegate) {
this.delegate = delegate;
}
@Override
public int getX() {
return delegate.getX();
}
@Override
public int getZ() {
return delegate.getZ();
}
@Override
public World getWorld() {
return new BukkitWorld(delegate.getWorld());
}
@Override
public Block getBlock(int x, int y, int z) {
return new BukkitBlock(delegate.getBlock(x, y, z));
}
@Override
public org.bukkit.Chunk getHandle() {
return delegate;
}
}

View File

@@ -1,100 +0,0 @@
package com.dfsek.terra.api.implementations.bukkit;
import com.dfsek.terra.api.generic.generator.ChunkGenerator;
import com.dfsek.terra.api.generic.world.Chunk;
import com.dfsek.terra.api.generic.world.World;
import com.dfsek.terra.api.generic.world.block.Block;
import com.dfsek.terra.api.generic.world.vector.Location;
import com.dfsek.terra.api.implementations.bukkit.generator.BukkitChunkGenerator;
import com.dfsek.terra.api.implementations.bukkit.world.block.BukkitBlock;
import org.bukkit.TreeType;
import org.bukkit.entity.Entity;
import org.bukkit.util.Consumer;
import java.io.File;
import java.util.UUID;
public class BukkitWorld implements World {
private final org.bukkit.World delegate;
public BukkitWorld(org.bukkit.World delegate) {
this.delegate = delegate;
}
@Override
public long getSeed() {
return delegate.getSeed();
}
@Override
public int getMaxHeight() {
return delegate.getMaxHeight();
}
@Override
public ChunkGenerator getGenerator() {
return new BukkitChunkGenerator(delegate.getGenerator());
}
@Override
public String getName() {
return delegate.getName();
}
@Override
public UUID getUID() {
return delegate.getUID();
}
@Override
public boolean isChunkGenerated(int x, int z) {
return delegate.isChunkGenerated(x, z);
}
@Override
public Chunk getChunkAt(int x, int z) {
return new BukkitChunk(delegate.getChunkAt(x, z));
}
@Override
public File getWorldFolder() {
return delegate.getWorldFolder();
}
@Override
public Block getBlockAt(int x, int y, int z) {
return new BukkitBlock(delegate.getBlockAt(x, y, z));
}
@Override
public Block getBlockAt(Location l) {
return new BukkitBlock(delegate.getBlockAt(l.getBlockX(), l.getBlockY(), l.getBlockZ()));
}
@Override
public boolean generateTree(Location l, TreeType vanillaTreeType) {
return delegate.generateTree(new org.bukkit.Location(((BukkitWorld) l.getWorld()).getHandle(), l.getX(), l.getY(), l.getZ()), vanillaTreeType);
}
@Override
public void spawn(Location l, Class<Entity> entity, Consumer<Entity> consumer) {
delegate.spawn(new org.bukkit.Location(((BukkitWorld) l.getWorld()).getHandle(), l.getX(), l.getY(), l.getZ()), entity, consumer);
}
@Override
public org.bukkit.World getHandle() {
return delegate;
}
@Override
public boolean equals(Object obj) {
if(!(obj instanceof BukkitWorld)) return false;
BukkitWorld other = (BukkitWorld) obj;
return other.getHandle().equals(delegate);
}
@Override
public int hashCode() {
return delegate.hashCode();
}
}

View File

@@ -1,45 +0,0 @@
package com.dfsek.terra.api.implementations.bukkit;
import com.dfsek.terra.api.generic.world.WorldHandle;
import com.dfsek.terra.api.generic.world.block.Block;
import com.dfsek.terra.api.generic.world.block.BlockData;
import com.dfsek.terra.api.generic.world.block.MaterialData;
import com.dfsek.terra.api.generic.world.block.data.Waterlogged;
import com.dfsek.terra.api.implementations.bukkit.world.block.BukkitBlockData;
import com.dfsek.terra.api.implementations.bukkit.world.block.BukkitMaterialData;
import com.dfsek.terra.api.implementations.bukkit.world.block.data.BukkitStairs;
import com.dfsek.terra.api.implementations.bukkit.world.block.data.BukkitWaterlogged;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.block.data.type.Stairs;
public class BukkitWorldHandle implements WorldHandle {
@Override
public void setBlockData(Block block, BlockData data, boolean physics) {
block.setBlockData(data, physics);
}
@Override
public BlockData getBlockData(Block block) {
return block.getBlockData();
}
@Override
public MaterialData getType(Block block) {
return block.getType();
}
@Override
public BlockData createBlockData(String data) {
org.bukkit.block.data.BlockData bukkitData = Bukkit.createBlockData(data);
if(bukkitData instanceof Stairs) return new BukkitStairs(bukkitData);
if(bukkitData instanceof Waterlogged) return new BukkitWaterlogged(bukkitData);
return new BukkitBlockData(Bukkit.createBlockData(data));
}
@Override
public MaterialData createMaterialData(String data) {
return new BukkitMaterialData(Material.matchMaterial(data));
}
}

View File

@@ -1,164 +0,0 @@
package com.dfsek.terra.api.implementations.bukkit;
import com.dfsek.tectonic.loading.TypeRegistry;
import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.api.GenericLoaders;
import com.dfsek.terra.api.gaea.GaeaPlugin;
import com.dfsek.terra.api.gaea.lang.Language;
import com.dfsek.terra.api.generic.TerraPlugin;
import com.dfsek.terra.api.generic.world.Biome;
import com.dfsek.terra.api.generic.world.World;
import com.dfsek.terra.api.generic.world.WorldHandle;
import com.dfsek.terra.api.generic.world.block.BlockData;
import com.dfsek.terra.api.generic.world.block.MaterialData;
import com.dfsek.terra.api.implementations.bukkit.generator.BukkitChunkGenerator;
import com.dfsek.terra.api.implementations.bukkit.generator.BukkitChunkGeneratorWrapper;
import com.dfsek.terra.api.implementations.bukkit.world.BukkitBiome;
import com.dfsek.terra.command.TerraCommand;
import com.dfsek.terra.command.structure.LocateCommand;
import com.dfsek.terra.config.base.ConfigPack;
import com.dfsek.terra.config.base.PluginConfig;
import com.dfsek.terra.config.lang.LangUtil;
import com.dfsek.terra.debug.Debug;
import com.dfsek.terra.generation.TerraChunkGenerator;
import com.dfsek.terra.listeners.EventListener;
import com.dfsek.terra.listeners.SpigotListener;
import com.dfsek.terra.registry.ConfigRegistry;
import com.dfsek.terra.util.PaperUtil;
import org.bstats.bukkit.Metrics;
import org.bukkit.Bukkit;
import org.bukkit.command.PluginCommand;
import org.bukkit.entity.EntityType;
import org.bukkit.generator.ChunkGenerator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
public class TerraBukkitPlugin extends GaeaPlugin implements TerraPlugin {
private final Map<String, TerraChunkGenerator> generatorMap = new HashMap<>();
private final Map<World, TerraWorld> worldMap = new HashMap<>();
private final Map<String, ConfigPack> worlds = new HashMap<>();
private final ConfigRegistry registry = new ConfigRegistry();
private final PluginConfig config = new PluginConfig();
private WorldHandle handle = new BukkitWorldHandle();
private final GenericLoaders genericLoaders = new GenericLoaders(this);
public void reload() {
Map<World, TerraWorld> newMap = new HashMap<>();
worldMap.forEach((world, tw) -> {
String packID = tw.getConfig().getTemplate().getID();
newMap.put(world, new TerraWorld(world, registry.get(packID), this));
});
worldMap.clear();
worldMap.putAll(newMap);
}
public void setHandle(WorldHandle handle) {
getLogger().warning("|-------------------------------------------------------|");
getLogger().warning("A third-party addon has injected a custom WorldHandle!");
getLogger().warning("If you encounter issues, try *without* the addon before");
getLogger().warning("reporting to Terra. Report issues with the addon to the");
getLogger().warning("addon's maintainers!");
getLogger().warning("|-------------------------------------------------------|");
this.handle = handle;
}
@Override
public void onDisable() {
TerraChunkGenerator.saveAll();
}
@Override
public void onEnable() {
Debug.setLogger(getLogger()); // Set debug logger.
saveDefaultConfig();
Metrics metrics = new Metrics(this, 9017); // Set up bStats.
metrics.addCustomChart(new Metrics.SingleLineChart("worlds", worldMap::size)); // World number chart.
config.load(this); // Load master config.yml
LangUtil.load(config.getLanguage(), this); // Load language.
Debug.setDebug(isDebug());
registry.loadAll(this); // Load all config packs.
PluginCommand c = Objects.requireNonNull(getCommand("terra"));
TerraCommand command = new TerraCommand(this); // Set up main Terra command.
c.setExecutor(command);
c.setTabCompleter(command);
LocateCommand locate = new LocateCommand(command, false);
PluginCommand locatePl = Objects.requireNonNull(getCommand("locate"));
locatePl.setExecutor(locate); // Override locate command. Once Paper accepts StructureLocateEvent this will be unneeded on Paper implementations.
locatePl.setTabCompleter(locate);
long save = config.getDataSaveInterval();
Bukkit.getScheduler().runTaskTimerAsynchronously(this, TerraChunkGenerator::saveAll, save, save); // Schedule population data saving
Bukkit.getPluginManager().registerEvents(new EventListener(this), this); // Register master event listener
Bukkit.getPluginManager().registerEvents(new SpigotListener(this), this); // Register Spigot event listener, once Paper accepts StructureLocateEvent PR Spigot and Paper events will be separate.
PaperUtil.checkPaper(this);
}
@Override
public @Nullable ChunkGenerator getDefaultWorldGenerator(@NotNull String worldName, @Nullable String id) {
return new BukkitChunkGeneratorWrapper(generatorMap.computeIfAbsent(worldName, name -> {
if(!registry.contains(id)) throw new IllegalArgumentException("No such config pack \"" + id + "\"");
worlds.put(worldName, registry.get(id));
return new TerraChunkGenerator(registry.get(id), this);
}));
}
@Override
public boolean isDebug() {
return config.isDebug();
}
@Override
public Language getLanguage() {
return LangUtil.getLanguage();
}
public ConfigRegistry getRegistry() {
return registry;
}
public TerraWorld getWorld(World w) {
if(!(w.getGenerator() instanceof BukkitChunkGenerator))
throw new IllegalArgumentException("Not a Terra world! " + w.getGenerator());
if(!worlds.containsKey(w.getName())) {
getLogger().warning("Unexpected world load detected: \"" + w.getName() + "\"");
return new TerraWorld(w, ((TerraChunkGenerator) w.getGenerator()).getConfigPack(), this);
}
return worldMap.computeIfAbsent(w, world -> new TerraWorld(w, worlds.get(w.getName()), this));
}
@NotNull
@Override
public PluginConfig getTerraConfig() {
return config;
}
@Override
public WorldHandle getHandle() {
return handle;
}
@Override
public void register(TypeRegistry registry) {
registry
.registerLoader(BlockData.class, (t, o, l) -> handle.createBlockData((String) o))
.registerLoader(MaterialData.class, (t, o, l) -> handle.createMaterialData((String) o))
.registerLoader(Biome.class, (t, o, l) -> new BukkitBiome(org.bukkit.block.Biome.valueOf((String) o)))
.registerLoader(EntityType.class, (t, o, l) -> EntityType.valueOf((String) o));
genericLoaders.register(registry);
}
}

Some files were not shown because too many files have changed in this diff Show More