diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
index f945bc9c9..25e81a323 100644
--- a/.idea/jarRepositories.xml
+++ b/.idea/jarRepositories.xml
@@ -6,6 +6,11 @@
+
+
+
+
+
@@ -21,6 +26,11 @@
+
+
+
+
+
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index 35eb1ddfb..3fa80cf2d 100644
--- a/.idea/vcs.xml
+++ b/.idea/vcs.xml
@@ -2,5 +2,7 @@
+
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 78aa01e08..166199b1f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -27,11 +27,15 @@
org.polydev.gaea
- com.dfsek.terra.gaea
+ com.dfsek.terra.lib.gaea
org.apache.commons
- com.dfsek.terra.commons
+ com.dfsek.terra.lib.commons
+
+
+ me.lucko.commodore
+ com.dfsek.terra.lib
@@ -55,6 +59,10 @@
spigotmc-repo
https://hub.spigotmc.org/nexus/content/repositories/snapshots/
+
+ minecraft-repo
+ https://libraries.minecraft.net/
+
gaea.local
gaea
@@ -83,7 +91,7 @@
org.polydev
gaea
- 1.9.0
+ 1.9.4
javax.vecmath
@@ -92,11 +100,16 @@
test
- javax.vecmath
- vecmath
- 1.5.2
+ me.lucko
+ commodore
+ 1.9
compile
+
+ org.apache.commons
+ commons-imaging
+ 1.0-alpha2
+
\ No newline at end of file
diff --git a/src/main/java/com/dfsek/terra/Terra.java b/src/main/java/com/dfsek/terra/Terra.java
index 99e40b31f..bcb0605e2 100644
--- a/src/main/java/com/dfsek/terra/Terra.java
+++ b/src/main/java/com/dfsek/terra/Terra.java
@@ -1,12 +1,24 @@
package com.dfsek.terra;
import com.dfsek.terra.config.ConfigUtil;
+import com.mojang.brigadier.arguments.BoolArgumentType;
+import com.mojang.brigadier.arguments.StringArgumentType;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
+import com.mojang.brigadier.tree.LiteralCommandNode;
+import me.lucko.commodore.Commodore;
+import me.lucko.commodore.CommodoreProvider;
+import me.lucko.commodore.file.CommodoreFileFormat;
+import org.bukkit.command.Command;
+import org.bukkit.command.PluginCommand;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import java.io.InputStream;
+
public class Terra extends JavaPlugin {
private static FileConfiguration config;
private static Terra instance;
@@ -23,15 +35,32 @@ public class Terra extends JavaPlugin {
@Override
public void onEnable() {
ConfigUtil.loadConfig(this);
- getCommand("terra").setExecutor(new TerraCommand());
+ //getCommand("terra").setExecutor(new TerraCommand());
+
+ PluginCommand command = getCommand("terra");
+ command.setExecutor(new TerraCommand());
+ if (CommodoreProvider.isSupported()) {
+ Commodore commodore = CommodoreProvider.getCommodore(this);
+ try {
+ register(this, command, commodore);
+ } catch(Exception e) {
+ e.printStackTrace();
+ }
+ } else getLogger().severe("Brigadier is not properly supported! Commands will NOT work properly!");
saveDefaultConfig();
config = getConfig();
instance = this;
}
- @NotNull
- public static FileConfiguration getConfigFile() {
- return config;
+ public static void register(JavaPlugin plugin, Command pluginCommand, Commodore commodore) throws Exception {
+ try (InputStream is = Terra.class.getResourceAsStream("/terra.commodore")) {
+ if (is == null) {
+ throw new Exception("Brigadier command data missing from jar");
+ }
+
+ LiteralCommandNode> commandNode = CommodoreFileFormat.parse(is);
+ commodore.register(pluginCommand, commandNode, player -> player.hasPermission("terra.command"));
+ }
}
@Override
diff --git a/src/main/java/com/dfsek/terra/TerraCommand.java b/src/main/java/com/dfsek/terra/TerraCommand.java
index f60650595..364c0fd2e 100644
--- a/src/main/java/com/dfsek/terra/TerraCommand.java
+++ b/src/main/java/com/dfsek/terra/TerraCommand.java
@@ -9,24 +9,29 @@ import org.bukkit.block.Block;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
+import org.bukkit.command.TabCompleter;
+import org.bukkit.command.TabExecutor;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.polydev.gaea.profiler.WorldProfiler;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
import java.util.Random;
-public class TerraCommand implements CommandExecutor {
+public class TerraCommand implements CommandExecutor, TabExecutor {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
switch(args[0]) {
case "reload":
ConfigUtil.loadConfig(Terra.getInstance());
sender.sendMessage("Reloaded Terra config.");
- break;
+ return true;
case "biome":
if(!(sender instanceof Player)) return false;
sender.sendMessage("You are in " + BiomeConfig.fromBiome((UserDefinedBiome) TerraBiomeGrid.fromWorld(((Player) sender).getWorld()).getBiome(((Player) sender).getLocation())).getFriendlyName());
- break;
+ return true;
case "profile":
if(! (sender instanceof Player)) {
sender.sendMessage("Command is for players only.");
@@ -53,16 +58,6 @@ public class TerraCommand implements CommandExecutor {
}
} else sender.sendMessage("World is not a Terra world!");
break;
- case "get_data":
- if(! (sender instanceof Player)) {
- sender.sendMessage("Command is for players only.");
- return true;
- }
- Block b = ((Player) sender).getTargetBlockExact(25);
- sender.sendMessage(b.getBlockData().getAsString());
- //NMSStructure villageBase = new NMSStructure(((Player) sender).getLocation(), NMSStructure.getAsTag(Class.forName("net.minecraft.server.v1_16_R2.AbstractDragonController").getResourceAsStream("/data/minecraft/structures/village/plains/town_centers/plains_fountain_01.nbt")));
- //villageBase.paste();
- break;
case "ore":
if(! (sender instanceof Player)) {
sender.sendMessage("Command is for players only.");
@@ -75,7 +70,16 @@ public class TerraCommand implements CommandExecutor {
return true;
}
ore.doVein(bl.getLocation(), new Random());
+ return true;
+
}
- return true;
+ return false;
+ }
+ @Override
+ public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
+ //System.out.println("Label " + label + " args: " + Arrays.toString(args));
+ if(args[0].equals("tpbiome")) return BiomeConfig.getBiomeIDs();
+ else if(args[0].equals("ore")) return OreConfig.getOreIDs();
+ else return Collections.emptyList();
}
}
diff --git a/src/main/java/com/dfsek/terra/biome/BiomeZone.java b/src/main/java/com/dfsek/terra/biome/BiomeZone.java
index 1ed44432f..cac6d923e 100644
--- a/src/main/java/com/dfsek/terra/biome/BiomeZone.java
+++ b/src/main/java/com/dfsek/terra/biome/BiomeZone.java
@@ -1,36 +1,48 @@
package com.dfsek.terra.biome;
import com.dfsek.terra.config.WorldConfig;
+import com.dfsek.terra.image.ImageLoader;
import org.bukkit.World;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import org.polydev.gaea.biome.BiomeGrid;
import org.polydev.gaea.biome.NormalizationUtil;
import org.polydev.gaea.math.FastNoise;
import java.util.HashMap;
import java.util.Map;
+import java.util.Objects;
public class BiomeZone {
private BiomeGrid[] grids;
private final World w;
private final FastNoise noise;
private static final Map zones = new HashMap<>();
+ @Nullable
+ private final ImageLoader imageLoader;
+ private final boolean useImage;
+ private final ImageLoader.Channel channel;
private BiomeZone(World w, float freq) {
this.w = w;
this.noise = new FastNoise((int) w.getSeed()+2);
this.noise.setNoiseType(FastNoise.NoiseType.SimplexFractal);
this.noise.setFractalOctaves(4);
this.noise.setFrequency(WorldConfig.fromWorld(w).zoneFreq);
- setZones(WorldConfig.fromWorld(w).definedGrids);
+ WorldConfig c = WorldConfig.fromWorld(w);
+ setZones(c.definedGrids);
+ imageLoader = c.imageLoader;
+ useImage = c.fromImage;
+ channel = c.zoneChannel;
zones.put(w, this);
}
- public void setZones(BiomeGrid[] grids) {
+ public void setZones(@NotNull BiomeGrid[] grids) {
if(grids.length != 32) throw new IllegalArgumentException("Illegal number of grids!");
this.grids = grids;
}
protected BiomeGrid getGrid(int x, int z) {
- return grids[NormalizationUtil.normalize(noise.getNoise(x, z), 32)];
+ return grids[NormalizationUtil.normalize(useImage ? Objects.requireNonNull(imageLoader).getNoiseVal(x, z, channel) : noise.getNoise(x, z), 32)];
}
protected static BiomeZone fromWorld(World w) {
diff --git a/src/main/java/com/dfsek/terra/biome/UserDefinedGenerator.java b/src/main/java/com/dfsek/terra/biome/UserDefinedGenerator.java
index f9b2f6bad..b8f6cbc2e 100644
--- a/src/main/java/com/dfsek/terra/biome/UserDefinedGenerator.java
+++ b/src/main/java/com/dfsek/terra/biome/UserDefinedGenerator.java
@@ -1,8 +1,11 @@
package com.dfsek.terra.biome;
import com.dfsek.terra.Terra;
+import com.dfsek.terra.config.WorldConfig;
+import com.dfsek.terra.image.ImageLoader;
import com.dfsek.terra.math.NoiseFunction2;
import com.dfsek.terra.math.NoiseFunction3;
+import org.bukkit.World;
import org.polydev.gaea.biome.BiomeTerrain;
import org.polydev.gaea.math.FastNoise;
import org.polydev.gaea.math.parsii.eval.Expression;
@@ -45,7 +48,7 @@ public class UserDefinedGenerator extends BiomeTerrain {
* @return double - Noise value at the specified coordinates.
*/
@Override
- public double getNoise(FastNoise gen, int x, int z) {
+ public double getNoise(FastNoise gen, World w, int x, int z) {
synchronized(noiseLock) {
xVar.setValue(x);
yVar.setValue(0);
@@ -66,7 +69,7 @@ public class UserDefinedGenerator extends BiomeTerrain {
* @return double - Noise value at the specified coordinates.
*/
@Override
- public double getNoise(FastNoise gen, int x, int y, int z) {
+ public double getNoise(FastNoise gen, World w, int x, int y, int z) {
synchronized(noiseLock) {
xVar.setValue(x);
yVar.setValue(y);
diff --git a/src/main/java/com/dfsek/terra/biome/UserDefinedGrid.java b/src/main/java/com/dfsek/terra/biome/UserDefinedGrid.java
index eca57d171..157b4d850 100644
--- a/src/main/java/com/dfsek/terra/biome/UserDefinedGrid.java
+++ b/src/main/java/com/dfsek/terra/biome/UserDefinedGrid.java
@@ -1,18 +1,51 @@
package com.dfsek.terra.biome;
+import com.dfsek.terra.config.WorldConfig;
import com.dfsek.terra.config.genconfig.BiomeGridConfig;
+import com.dfsek.terra.image.ImageLoader;
+import org.bukkit.Location;
import org.bukkit.World;
+import org.polydev.gaea.biome.Biome;
import org.polydev.gaea.biome.BiomeGrid;
public class UserDefinedGrid extends BiomeGrid {
+ private final ImageLoader imageLoader;
+ private final boolean fromImage;
+ private final ImageLoader.Channel channelX;
+ private final ImageLoader.Channel channelZ;
public UserDefinedGrid(World w, float freq1, float freq2, BiomeGridConfig config) {
super(w, freq1, freq2, config.getBiomeGrid().length, config.getBiomeGrid()[0].length);
super.setNormalType(NormalType.LOOKUP4096);
super.setGrid(config.getBiomeGrid());
+ WorldConfig c = WorldConfig.fromWorld(w);
+ imageLoader = c.imageLoader;
+ fromImage = c.fromImage;
+ channelX = c.biomeXChannel;
+ channelZ = c.biomeZChannel;
}
public UserDefinedGrid(World w, float freq1, float freq2, UserDefinedBiome[][] b) {
super(w, freq1, freq2, b.length, b[0].length);
super.setNormalType(NormalType.LOOKUP4096);
super.setGrid(b);
+ WorldConfig c = WorldConfig.fromWorld(w);
+ imageLoader = c.imageLoader;
+ fromImage = c.fromImage;
+ channelX = c.biomeXChannel;
+ channelZ = c.biomeZChannel;
+ }
+
+ @Override
+ public Biome getBiome(int x, int z) {
+ if(fromImage) {
+ int xi = imageLoader.getChannel(x, z, channelX);
+ int zi = imageLoader.getChannel(x, z, channelZ);
+ return super.getGrid()[getSizeX() * (xi/256)][getSizeZ() * (zi/256)];
+ }
+ return super.getBiome(x, z);
+ }
+
+ @Override
+ public Biome getBiome(Location l) {
+ return this.getBiome(l.getBlockX(), l.getBlockZ());
}
}
diff --git a/src/main/java/com/dfsek/terra/config/WorldConfig.java b/src/main/java/com/dfsek/terra/config/WorldConfig.java
index 6277fe94c..e17e0c858 100644
--- a/src/main/java/com/dfsek/terra/config/WorldConfig.java
+++ b/src/main/java/com/dfsek/terra/config/WorldConfig.java
@@ -5,6 +5,7 @@ import com.dfsek.terra.biome.UserDefinedBiome;
import com.dfsek.terra.biome.UserDefinedGrid;
import com.dfsek.terra.config.genconfig.BiomeConfig;
import com.dfsek.terra.config.genconfig.BiomeGridConfig;
+import com.dfsek.terra.image.ImageLoader;
import org.bukkit.World;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.FileConfiguration;
@@ -26,7 +27,13 @@ public class WorldConfig {
public float freq1;
public float freq2;
public int seaLevel;
+ public boolean fromImage;
public UserDefinedGrid[] definedGrids = new UserDefinedGrid[32];
+ public ImageLoader.Channel biomeXChannel;
+ public ImageLoader.Channel biomeZChannel;
+ public ImageLoader.Channel zoneChannel;
+ public ImageLoader.Channel terrainChannel;
+ public ImageLoader imageLoader;
public WorldConfig(World w, JavaPlugin main) {
@@ -67,6 +74,16 @@ public class WorldConfig {
zoneFreq = 1f/config.getInt("frequencies.zone", 1536);
freq1 = 1f/config.getInt("frequencies.grid-1", 256);
freq2 = 1f/config.getInt("frequencies.grid-2", 512);
+ fromImage = config.getBoolean("image.use-image", false);
+ biomeXChannel = ImageLoader.Channel.valueOf(Objects.requireNonNull(config.getString("image.channels.biome-x", "red")).toUpperCase());
+ biomeZChannel = ImageLoader.Channel.valueOf(Objects.requireNonNull(config.getString("image.channels.biome-z", "green")).toUpperCase());
+ zoneChannel = ImageLoader.Channel.valueOf(Objects.requireNonNull(config.getString("image.channels.zone", "blue")).toUpperCase());
+ try {
+ imageLoader = new ImageLoader(new File(Objects.requireNonNull(config.getString("image.image-location"))));
+ } catch(IOException | NullPointerException e) {
+ e.printStackTrace();
+ fromImage = false;
+ }
configs.put(w, this); // WorldConfig must be included in map before Grids are loaded.
diff --git a/src/main/java/com/dfsek/terra/config/genconfig/BiomeConfig.java b/src/main/java/com/dfsek/terra/config/genconfig/BiomeConfig.java
index 94574ae22..6d2c69fd2 100644
--- a/src/main/java/com/dfsek/terra/config/genconfig/BiomeConfig.java
+++ b/src/main/java/com/dfsek/terra/config/genconfig/BiomeConfig.java
@@ -24,8 +24,11 @@ import org.polydev.gaea.world.palette.RandomPalette;
import java.io.File;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
@@ -194,6 +197,10 @@ public class BiomeConfig extends TerraConfigObject {
throw new IllegalArgumentException("No BiomeConfig for provided biome.");
}
+ public static List getBiomeIDs() {
+ return new ArrayList<>(biomes.keySet());
+ }
+
public static BiomeConfig fromID(String id) {
return biomes.get(id);
}
diff --git a/src/main/java/com/dfsek/terra/config/genconfig/CarverConfig.java b/src/main/java/com/dfsek/terra/config/genconfig/CarverConfig.java
index 659bd3bb0..71ccc640c 100644
--- a/src/main/java/com/dfsek/terra/config/genconfig/CarverConfig.java
+++ b/src/main/java/com/dfsek/terra/config/genconfig/CarverConfig.java
@@ -28,6 +28,7 @@ public class CarverConfig extends TerraConfigObject {
private String id;
private Set replaceableInner;
private Set replaceableOuter;
+ private Set update;
private Map> shift;
private Map> inner;
private Map> outer;
@@ -71,6 +72,16 @@ public class CarverConfig extends TerraConfigObject {
throw new InvalidConfigurationException("Could not load data for " + s);
}
}
+
+ update = new HashSet<>();
+ for(String s : getStringList("update")) {
+ try {
+ if(update.contains(Bukkit.createBlockData(s).getMaterial())) Bukkit.getLogger().warning("Duplicate material in update list: " + s);
+ update.add(Bukkit.createBlockData(s).getMaterial());
+ } catch(NullPointerException | IllegalArgumentException e) {
+ throw new InvalidConfigurationException("Could not load data for " + s);
+ }
+ }
shift = new HashMap<>();
for(Map.Entry e : getConfigurationSection("shift").getValues(false).entrySet()) {
Set l = new HashSet<>();
@@ -120,6 +131,10 @@ public class CarverConfig extends TerraConfigObject {
return shift;
}
+ public Set getUpdateBlocks() {
+ return update;
+ }
+
public boolean isReplaceableInner(Material m) {
if(replaceIsBlacklistInner) {
return !replaceableInner.contains(m);
diff --git a/src/main/java/com/dfsek/terra/config/genconfig/OreConfig.java b/src/main/java/com/dfsek/terra/config/genconfig/OreConfig.java
index c95c8bed9..01d1d7778 100644
--- a/src/main/java/com/dfsek/terra/config/genconfig/OreConfig.java
+++ b/src/main/java/com/dfsek/terra/config/genconfig/OreConfig.java
@@ -14,6 +14,7 @@ import org.polydev.gaea.math.FastNoise;
import java.io.File;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -81,6 +82,10 @@ public class OreConfig extends TerraConfigObject {
}
}
+ public static List getOreIDs() {
+ return new ArrayList<>(ores.keySet());
+ }
+
@Override
public String toString() {
return "Ore with name " + getFriendlyName() + ", ID " + getID();
diff --git a/src/main/java/com/dfsek/terra/image/ImageLoader.java b/src/main/java/com/dfsek/terra/image/ImageLoader.java
new file mode 100644
index 000000000..84defcd18
--- /dev/null
+++ b/src/main/java/com/dfsek/terra/image/ImageLoader.java
@@ -0,0 +1,45 @@
+package com.dfsek.terra.image;
+
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+
+import javax.imageio.ImageIO;
+
+public class ImageLoader {
+ private final BufferedImage image;
+ double inverseRoot2 = 0.7071067811865475;
+ public ImageLoader(File file) throws IOException {
+ image = ImageIO.read(file);
+ }
+
+
+ public int getChannel(int x, int y, Channel channel) {
+ int rgb;
+ try {
+ rgb = image.getRGB(Math.floorMod(x, image.getWidth()), Math.floorMod(y, image.getHeight()));
+ } catch(ArrayIndexOutOfBoundsException e) {
+ e.printStackTrace();
+ throw new IllegalArgumentException("Index " + x + "/" + x + "out of bounds for size " + image.getWidth() + "/" + image.getHeight());
+ }
+ switch(channel) {
+ case RED: return rgb >> 16 & 0xff;
+ case GREEN: return rgb >> 8 & 0xff;
+ case BLUE: return rgb & 0xff;
+ case ALPHA: return rgb >> 32 & 0xff;
+ default: throw new IllegalArgumentException();
+ }
+ }
+
+ public double getNoiseVal(int x, int y, Channel channel) {
+ return ((double) (getChannel(x, y, channel) - 128)/128)*inverseRoot2;
+ }
+
+ public enum Channel {
+ RED, GREEN, BLUE, ALPHA
+ }
+}
diff --git a/src/main/java/com/dfsek/terra/population/CavePopulator.java b/src/main/java/com/dfsek/terra/population/CavePopulator.java
index 32bc6a504..103116bff 100644
--- a/src/main/java/com/dfsek/terra/population/CavePopulator.java
+++ b/src/main/java/com/dfsek/terra/population/CavePopulator.java
@@ -32,7 +32,6 @@ public class CavePopulator extends BlockPopulator {
Vector v = e.getKey();
Block b = chunk.getBlock(v.getBlockX(), v.getBlockY(), v.getBlockZ());
Material m = b.getType();
- boolean liquid = b.getType().equals(Material.WATER) || b.getType().equals(Material.LAVA);
if(e.getValue().equals(CarvingData.CarvingType.CENTER) && c.isReplaceableInner(m)) {
if(c.getShiftedBlocks().containsKey(b.getType())) shiftCandidate.put(b.getLocation(), b.getType());
b.setBlockData(c.getPaletteInner(v.getBlockY()).get(random), false);
@@ -40,7 +39,7 @@ public class CavePopulator extends BlockPopulator {
if(c.getShiftedBlocks().containsKey(b.getType())) shiftCandidate.put(b.getLocation(), b.getType());
b.setBlockData(c.getPaletteOuter(v.getBlockY()).get(random), false);
}
- if(liquid) {
+ if(c.getUpdateBlocks().contains(m)) {
updateNeeded.add(b);
}
}
diff --git a/src/main/resources/terra.commodore b/src/main/resources/terra.commodore
new file mode 100644
index 000000000..749f705f3
--- /dev/null
+++ b/src/main/resources/terra.commodore
@@ -0,0 +1,16 @@
+terra {
+ biome;
+ reload;
+ profile {
+ start;
+ stop;
+ reset;
+ query;
+ }
+ tpbiome {
+ biome brigadier:string single_word;
+ }
+ ore {
+ ore brigadier:string single_word;
+ }
+}
\ No newline at end of file