diff --git a/pom.xml b/pom.xml
index 166199b1f..c0310d534 100644
--- a/pom.xml
+++ b/pom.xml
@@ -91,7 +91,7 @@
org.polydev
gaea
- 1.9.4
+ 1.9.6
javax.vecmath
diff --git a/src/main/java/com/dfsek/terra/TerraChunkGenerator.java b/src/main/java/com/dfsek/terra/TerraChunkGenerator.java
index 50639abf4..9464d0d3a 100644
--- a/src/main/java/com/dfsek/terra/TerraChunkGenerator.java
+++ b/src/main/java/com/dfsek/terra/TerraChunkGenerator.java
@@ -59,6 +59,7 @@ public class TerraChunkGenerator extends GaeaChunkGenerator {
return Collections.emptyList();
}
+
@Override
public org.polydev.gaea.biome.BiomeGrid getBiomeGrid(World world) {
return TerraBiomeGrid.fromWorld(world);
diff --git a/src/main/java/com/dfsek/terra/TerraCommand.java b/src/main/java/com/dfsek/terra/TerraCommand.java
index 364c0fd2e..c78e4fda0 100644
--- a/src/main/java/com/dfsek/terra/TerraCommand.java
+++ b/src/main/java/com/dfsek/terra/TerraCommand.java
@@ -2,9 +2,11 @@ package com.dfsek.terra;
import com.dfsek.terra.biome.TerraBiomeGrid;
import com.dfsek.terra.biome.UserDefinedBiome;
+import com.dfsek.terra.config.WorldConfig;
import com.dfsek.terra.config.genconfig.BiomeConfig;
import com.dfsek.terra.config.ConfigUtil;
import com.dfsek.terra.config.genconfig.OreConfig;
+import com.dfsek.terra.image.WorldImageGenerator;
import org.bukkit.block.Block;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
@@ -15,6 +17,7 @@ import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.polydev.gaea.profiler.WorldProfiler;
+import java.io.File;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -71,7 +74,42 @@ public class TerraCommand implements CommandExecutor, TabExecutor {
}
ore.doVein(bl.getLocation(), new Random());
return true;
-
+ case "image":
+ if("render".equals(args[1])) {
+ if(! (sender instanceof Player)) {
+ sender.sendMessage("Command is for players only.");
+ return true;
+ }
+ Player pl = (Player) sender;
+ if(args.length != 4) return false;
+ try {
+ WorldImageGenerator g = new WorldImageGenerator(pl.getWorld(), Integer.parseInt(args[2]), Integer.parseInt(args[3]));
+ g.drawWorld(pl.getLocation().getBlockX(), pl.getLocation().getBlockZ());
+ File file = new File(Terra.getInstance().getDataFolder() + File.separator + "map_export" + File.separator + "map_" + System.currentTimeMillis() + ".png");
+ file.mkdirs();
+ file.createNewFile();
+ g.save(file);
+ sender.sendMessage("Saved image to " + file.getPath());
+ return true;
+ } catch(Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ } else if("gui".equals(args[1])) {
+ if(! (sender instanceof Player)) {
+ sender.sendMessage("Command is for players only.");
+ return true;
+ }
+ Player pl = (Player) sender;
+ try {
+ if("raw".equals(args[2])) WorldConfig.fromWorld(pl.getWorld()).imageLoader.debug(false, pl.getWorld());
+ else if("step".equals(args[2])) WorldConfig.fromWorld(pl.getWorld()).imageLoader.debug(true, pl.getWorld());
+ else return false;
+ return true;
+ } catch(NullPointerException e) {
+ return false;
+ }
+ }
}
return false;
}
diff --git a/src/main/java/com/dfsek/terra/biome/BiomeZone.java b/src/main/java/com/dfsek/terra/biome/BiomeZone.java
index cac6d923e..1dd8ef3ae 100644
--- a/src/main/java/com/dfsek/terra/biome/BiomeZone.java
+++ b/src/main/java/com/dfsek/terra/biome/BiomeZone.java
@@ -22,7 +22,7 @@ public class BiomeZone {
private final ImageLoader imageLoader;
private final boolean useImage;
private final ImageLoader.Channel channel;
- private BiomeZone(World w, float freq) {
+ private BiomeZone(World w) {
this.w = w;
this.noise = new FastNoise((int) w.getSeed()+2);
this.noise.setNoiseType(FastNoise.NoiseType.SimplexFractal);
@@ -45,8 +45,16 @@ public class BiomeZone {
return grids[NormalizationUtil.normalize(useImage ? Objects.requireNonNull(imageLoader).getNoiseVal(x, z, channel) : noise.getNoise(x, z), 32)];
}
- protected static BiomeZone fromWorld(World w) {
+ public int getNoise(int x, int z) {
+ return NormalizationUtil.normalize(useImage ? Objects.requireNonNull(imageLoader).getNoiseVal(x, z, channel) : noise.getNoise(x, z), 32);
+ }
+
+ public double getRawNoise(int x, int z) {
+ return useImage ? Objects.requireNonNull(imageLoader).getNoiseVal(x, z, channel) : noise.getNoise(x, z);
+ }
+
+ public static BiomeZone fromWorld(World w) {
if(zones.containsKey(w)) return zones.get(w);
- else return new BiomeZone(w, WorldConfig.fromWorld(w).zoneFreq);
+ else return new BiomeZone(w);
}
}
diff --git a/src/main/java/com/dfsek/terra/biome/TerraBiomeGrid.java b/src/main/java/com/dfsek/terra/biome/TerraBiomeGrid.java
index 4f3a9bac4..8beb7e936 100644
--- a/src/main/java/com/dfsek/terra/biome/TerraBiomeGrid.java
+++ b/src/main/java/com/dfsek/terra/biome/TerraBiomeGrid.java
@@ -36,4 +36,8 @@ public class TerraBiomeGrid extends BiomeGrid {
public Biome getBiome(Location l) {
return getBiome(l.getBlockX(), l.getBlockZ());
}
+
+ public UserDefinedGrid getGrid(int x, int z) {
+ return (UserDefinedGrid) BiomeZone.fromWorld(w).getGrid(x, z);
+ }
}
diff --git a/src/main/java/com/dfsek/terra/biome/UserDefinedGrid.java b/src/main/java/com/dfsek/terra/biome/UserDefinedGrid.java
index 157b4d850..4bd4f5ed0 100644
--- a/src/main/java/com/dfsek/terra/biome/UserDefinedGrid.java
+++ b/src/main/java/com/dfsek/terra/biome/UserDefinedGrid.java
@@ -7,6 +7,7 @@ import org.bukkit.Location;
import org.bukkit.World;
import org.polydev.gaea.biome.Biome;
import org.polydev.gaea.biome.BiomeGrid;
+import org.polydev.gaea.biome.NormalizationUtil;
public class UserDefinedGrid extends BiomeGrid {
private final ImageLoader imageLoader;
@@ -37,9 +38,9 @@ public class UserDefinedGrid extends BiomeGrid {
@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)];
+ double xi = imageLoader.getNoiseVal(x, z, channelX);
+ double zi = imageLoader.getNoiseVal(x, z, channelZ);
+ return super.getGrid()[NormalizationUtil.normalize(xi, getSizeX())][NormalizationUtil.normalize(zi, getSizeZ())];
}
return super.getBiome(x, z);
}
diff --git a/src/main/java/com/dfsek/terra/config/WorldConfig.java b/src/main/java/com/dfsek/terra/config/WorldConfig.java
index e17e0c858..c1e8b19c4 100644
--- a/src/main/java/com/dfsek/terra/config/WorldConfig.java
+++ b/src/main/java/com/dfsek/terra/config/WorldConfig.java
@@ -6,6 +6,7 @@ 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.Bukkit;
import org.bukkit.World;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.FileConfiguration;
@@ -64,45 +65,54 @@ public class WorldConfig {
FileUtils.copyInputStreamToFile(Objects.requireNonNull(main.getResource("world.yml")), configFile);
}
config.load(configFile);
+
+
+ // Get values from config.
+ seaLevel = config.getInt("sea-level", 63);
+ 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());
+ if(biomeZChannel.equals(biomeXChannel)) throw new InvalidConfigurationException("2 objects share the same image channels: biome-x and biome-z");
+ zoneChannel = ImageLoader.Channel.valueOf(Objects.requireNonNull(config.getString("image.channels.zone", "blue")).toUpperCase());
+ if(zoneChannel.equals(biomeXChannel) || zoneChannel.equals(biomeZChannel)) throw new InvalidConfigurationException("2 objects share the same image channels: zone and biome-x/z");
+ if(fromImage) {
+ try {
+ imageLoader = new ImageLoader(new File(Objects.requireNonNull(config.getString("image.image-location"))));
+ Bukkit.getLogger().info("[Terra] Loading world from image.");
+ } catch(IOException | NullPointerException e) {
+ e.printStackTrace();
+ fromImage = false;
+ }
+ }
+
+
+ configs.put(w, this); // WorldConfig must be included in map before Grids are loaded.
+
+ for(int i = 0; i < 32; i++) {
+ String partName = config.getStringList("grids").get(i);
+ if(partName.startsWith("BIOME:")) {
+ UserDefinedBiome[][] temp = new UserDefinedBiome[16][16];
+ UserDefinedBiome b = BiomeConfig.fromID(partName.substring(6)).getBiome();
+ for(int x = 0; x < 16; x++) {
+ for(int z = 0; z < 16; z++) {
+ temp[x][z] = b;
+ }
+ }
+ definedGrids[i] = new UserDefinedGrid(w, freq1, freq2, temp);
+ main.getLogger().info("Loaded single-biome grid " + partName);
+ } else definedGrids[i] = BiomeGridConfig.getBiomeGrids().get(partName).getGrid(w);
+ }
+
} catch(IOException | InvalidConfigurationException e) {
e.printStackTrace();
main.getLogger().severe("Unable to load configuration for world " + w + ".");
}
- // Get values from config.
- seaLevel = config.getInt("sea-level", 63);
- 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.
-
- for(int i = 0; i < 32; i++) {
- String partName = config.getStringList("grids").get(i);
- if(partName.startsWith("BIOME:")) {
- UserDefinedBiome[][] temp = new UserDefinedBiome[16][16];
- UserDefinedBiome b = BiomeConfig.fromID(partName.substring(6)).getBiome();
- for(int x = 0; x < 16; x++) {
- for(int z = 0; z < 16; z++) {
- temp[x][z] = b;
- }
- }
- definedGrids[i] = new UserDefinedGrid(w, freq1, freq2, temp);
- main.getLogger().info("Loaded single-biome grid " + partName);
- } else definedGrids[i] = BiomeGridConfig.getBiomeGrids().get(partName).getGrid(w);
- }
-
main.getLogger().info("World load complete. Time elapsed: " + ((double) (System.nanoTime() - start)) / 1000000 + "ms");
diff --git a/src/main/java/com/dfsek/terra/image/DebugFrame.java b/src/main/java/com/dfsek/terra/image/DebugFrame.java
new file mode 100644
index 000000000..32f96062d
--- /dev/null
+++ b/src/main/java/com/dfsek/terra/image/DebugFrame.java
@@ -0,0 +1,49 @@
+package com.dfsek.terra.image;
+
+import com.dfsek.terra.Terra;
+import com.dfsek.terra.biome.TerraBiomeGrid;
+import com.dfsek.terra.biome.UserDefinedBiome;
+import com.dfsek.terra.config.genconfig.BiomeConfig;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.image.BufferedImage;
+
+public class DebugFrame extends JFrame implements ActionListener {
+ private final int x;
+ private final int z;
+ private final BufferedImage img;
+ public DebugFrame(BufferedImage image, String s) {
+ super(s);
+ this.x = image.getWidth();
+ this.z = image.getHeight();
+ this.img = image;
+ new Timer(500, this).start();
+ }
+
+ @Override
+ public void paint(Graphics g) {
+ super.paintComponents(g);
+ for(Player p : Bukkit.getOnlinePlayers()) {
+ int xp = (int) (((double) Math.floorMod(p.getLocation().getBlockX(), x)/x)*getWidth());
+ int zp = (int) (((double) Math.floorMod(p.getLocation().getBlockZ(), z)/z)*getHeight());
+ g.setColor(new Color(255, 255, 255, 64));
+ g.drawRect(xp+10, zp-5, 20, 20);
+ g.setColor(Color.BLACK);
+ g.drawString(p.getName(), xp+15, zp);
+ g.drawString(BiomeConfig.fromBiome((UserDefinedBiome) TerraBiomeGrid.fromWorld(p.getWorld()).getBiome(p.getLocation())).getID(), xp+15, zp+15);
+ g.fillOval(xp, zp, 10, 10);
+ g.setColor(Color.RED);
+ g.fillOval(xp+3, zp+3, 5, 5);
+ }
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ this.repaint();
+ }
+}
diff --git a/src/main/java/com/dfsek/terra/image/DebugGUI.java b/src/main/java/com/dfsek/terra/image/DebugGUI.java
new file mode 100644
index 000000000..b438fce6b
--- /dev/null
+++ b/src/main/java/com/dfsek/terra/image/DebugGUI.java
@@ -0,0 +1,28 @@
+package com.dfsek.terra.image;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+
+public class DebugGUI extends Thread {
+
+ private final BufferedImage img;
+ public DebugGUI(BufferedImage img) {
+ this.img = img;
+ }
+ @Override
+ public void run() {
+ DebugFrame frame = new DebugFrame(img, "Image2Map Debug GUI");
+ frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
+ frame.setSize(1000, 1000);
+ frame.setResizable(false);
+ ImageIcon imageIcon = new ImageIcon(img.getScaledInstance(1000, 1000, Image.SCALE_SMOOTH));
+ JLabel jLabel = new JLabel();
+ jLabel.setIcon(imageIcon);
+ frame.getContentPane().add(jLabel, BorderLayout.CENTER);
+ frame.pack();
+ frame.setLocationRelativeTo(null);
+ frame.setVisible(true);
+ }
+
+}
diff --git a/src/main/java/com/dfsek/terra/image/ImageLoader.java b/src/main/java/com/dfsek/terra/image/ImageLoader.java
index 84defcd18..f8d4e5bc9 100644
--- a/src/main/java/com/dfsek/terra/image/ImageLoader.java
+++ b/src/main/java/com/dfsek/terra/image/ImageLoader.java
@@ -1,5 +1,11 @@
package com.dfsek.terra.image;
+import com.dfsek.terra.biome.BiomeZone;
+import com.dfsek.terra.biome.TerraBiomeGrid;
+import com.dfsek.terra.config.genconfig.BiomeConfig;
+import org.bukkit.World;
+import org.polydev.gaea.biome.NormalizationUtil;
+
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
@@ -35,9 +41,35 @@ public class ImageLoader {
}
}
+ public void debug(boolean genStep, World w) {
+ BufferedImage newImg = copyImage(image);
+ TerraBiomeGrid tb = TerraBiomeGrid.fromWorld(w);
+ BiomeZone z = BiomeZone.fromWorld(w);
+ if(genStep) {
+ for(int x = 0; x < newImg.getWidth(); x++) {
+ for(int y = 0; y < newImg.getHeight(); y++) {
+ float[] noise = tb.getGrid(x, y).getRawNoise(x, y);
+ newImg.setRGB(x, y, new Color((int) (NormalizationUtil.normalize(noise[0], tb.getGrid(x, y).getSizeX()) * ((double) 255/tb.getGrid(x, y).getSizeX())),
+ (int) (NormalizationUtil.normalize(noise[1], tb.getGrid(x, y).getSizeZ()) * ((double) 255/tb.getGrid(x, y).getSizeZ())),
+ (int) (z.getNoise(x, y) * ((double) 255/32)))
+ .getRGB());
+ }
+ }
+ }
+ DebugGUI debugGUI = new DebugGUI(newImg);
+ debugGUI.start();
+ }
+
public double getNoiseVal(int x, int y, Channel channel) {
return ((double) (getChannel(x, y, channel) - 128)/128)*inverseRoot2;
}
+ private static BufferedImage copyImage(BufferedImage source){
+ BufferedImage b = new BufferedImage(source.getWidth(), source.getHeight(), source.getType());
+ Graphics g = b.getGraphics();
+ g.drawImage(source, 0, 0, null);
+ g.dispose();
+ return b;
+ }
public enum Channel {
RED, GREEN, BLUE, ALPHA
diff --git a/src/main/java/com/dfsek/terra/image/WorldImageGenerator.java b/src/main/java/com/dfsek/terra/image/WorldImageGenerator.java
new file mode 100644
index 000000000..c86bf2451
--- /dev/null
+++ b/src/main/java/com/dfsek/terra/image/WorldImageGenerator.java
@@ -0,0 +1,44 @@
+package com.dfsek.terra.image;
+
+import com.dfsek.terra.biome.BiomeZone;
+import com.dfsek.terra.biome.TerraBiomeGrid;
+import com.dfsek.terra.config.WorldConfig;
+import org.bukkit.World;
+import org.polydev.gaea.biome.NormalizationUtil;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+
+public class WorldImageGenerator {
+ private final World w;
+ private final BufferedImage draw;
+ public WorldImageGenerator(World w, int width, int height) {
+ draw = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+ this.w = w;
+ }
+ public void drawWorld(int centerX, int centerZ) {
+ TerraBiomeGrid tb = TerraBiomeGrid.fromWorld(w);
+ int imY = 0;
+ for(int y = centerZ - (draw.getHeight()/2); y < centerZ + (draw.getHeight()/2); y++) {
+ int imX = 0;
+ for(int x = centerX - (draw.getWidth()/2); x < centerX + (draw.getWidth()/2); x++) {
+ int zone = NormalizationUtil.normalize(BiomeZone.fromWorld(w).getRawNoise(x, y), 256);
+ float[] noise = tb.getGrid(x, y).getRawNoise(x, y);
+ Color c = new Color(NormalizationUtil.normalize(noise[0], 256), NormalizationUtil.normalize(noise[1], 256), zone);
+ draw.setRGB(imX, imY, c.getRGB());
+ imX++;
+ }
+ imY++;
+ }
+ }
+ public void save(File file) {
+ try {
+ ImageIO.write(draw, "png", file);
+ } catch(IOException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/src/main/resources/terra.commodore b/src/main/resources/terra.commodore
index 749f705f3..57c59cafc 100644
--- a/src/main/resources/terra.commodore
+++ b/src/main/resources/terra.commodore
@@ -13,4 +13,15 @@ terra {
ore {
ore brigadier:string single_word;
}
+ image {
+ render {
+ size_x brigadier:integer {
+ size_z brigadier:integer;
+ }
+ }
+ gui {
+ raw;
+ step;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/test/java/DistributionTest.java b/src/test/java/DistributionTest.java
index b0d4c7bcd..8a31f24e4 100644
--- a/src/test/java/DistributionTest.java
+++ b/src/test/java/DistributionTest.java
@@ -19,7 +19,7 @@ public class DistributionTest {
noise.setFrequency(0.02f);
noise.setFractalOctaves(4);
System.out.println(noise);
- int attempts = 3;
+ int attempts = 8;
int[] numbers = new int[attempts];
double min = Integer.MAX_VALUE;
double max = Integer.MIN_VALUE;
diff --git a/test.sh b/test.sh
index 62eef0697..4312c9a86 100755
--- a/test.sh
+++ b/test.sh
@@ -26,7 +26,7 @@ cp $DIRECTORY/prod/$PROJECT.jar $DIRECTORY/server/plugins/$PROJECT.jar
cd $DIRECTORY/server || exit
if ! test -f "paperclip.jar"; then
echo "Paper not found. Downloading now."
- wget https://papermc.io/api/v1/paper/1.16.2/latest/download -O paperclip.jar
+ wget https://papermc.io/api/v1/paper/1.16.3/latest/download -O paperclip.jar
fi
if [ -z "$(grep true eula.txt 2>/dev/null)" ]; then
echo