diff --git a/pom.xml b/pom.xml
index 3c6e4739b..e6d172e23 100644
--- a/pom.xml
+++ b/pom.xml
@@ -95,7 +95,7 @@
org.polydev
gaea
- 1.10.42
+ 1.10.45
me.lucko
@@ -114,6 +114,12 @@
7.2.0-SNAPSHOT
provided
+
+ org.junit.jupiter
+ junit-jupiter
+ RELEASE
+ test
+
\ No newline at end of file
diff --git a/src/main/java/com/dfsek/terra/MaxMin.java b/src/main/java/com/dfsek/terra/MaxMin.java
index a2c54a644..9cdc0a353 100644
--- a/src/main/java/com/dfsek/terra/MaxMin.java
+++ b/src/main/java/com/dfsek/terra/MaxMin.java
@@ -1,8 +1,12 @@
package com.dfsek.terra;
+import org.bukkit.Chunk;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Iterator;
import java.util.Random;
-public class MaxMin {
+public class MaxMin implements Iterable {
private final int min;
private final int max;
public MaxMin(int min, int max) {
@@ -21,7 +25,39 @@ public class MaxMin {
public int getMin() {
return min;
}
+
public int get(Random r) {
return r.nextInt((max-min)+1)+min;
}
+
+ @Override
+ public String toString() {
+ return "Min: " + getMin() + " Max:" + getMax();
+ }
+
+ @NotNull
+ @Override
+ public Iterator iterator() {
+ return new MaxMinIterator(this);
+ }
+ private static class MaxMinIterator implements Iterator {
+ private Integer current;
+ private final MaxMin m;
+
+ public MaxMinIterator(MaxMin m) {
+ this.m = m;
+ current = m.getMin();
+ }
+
+ @Override
+ public boolean hasNext() {
+ return current < m.getMax();
+ }
+
+ @Override
+ public Integer next() {
+ current++;
+ return current - 1;
+ }
+ }
}
diff --git a/src/main/java/com/dfsek/terra/Terra.java b/src/main/java/com/dfsek/terra/Terra.java
index ceb03ce06..9765ea7a6 100644
--- a/src/main/java/com/dfsek/terra/Terra.java
+++ b/src/main/java/com/dfsek/terra/Terra.java
@@ -2,13 +2,11 @@ package com.dfsek.terra;
import com.dfsek.terra.config.ConfigUtil;
import com.dfsek.terra.generation.TerraChunkGenerator;
-import com.dfsek.terra.structure.StructureManager;
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.Bukkit;
-import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.command.PluginCommand;
import org.bukkit.configuration.file.FileConfiguration;
@@ -18,13 +16,10 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.InputStream;
-import java.util.Map;
-import java.util.logging.Logger;
public class Terra extends JavaPlugin {
private static FileConfiguration config;
private static Terra instance;
- private static StructureManager manager;
public static Terra getInstance() {
return instance;
@@ -38,7 +33,6 @@ public class Terra extends JavaPlugin {
@Override
public void onEnable() {
ConfigUtil.loadConfig(this);
- manager = new StructureManager(this);
PluginCommand command = getCommand("terra");
command.setExecutor(new TerraCommand());
@@ -67,10 +61,6 @@ public class Terra extends JavaPlugin {
}
}
- public static StructureManager getStructureManager() {
- return manager;
- }
-
@Override
public @Nullable ChunkGenerator getDefaultWorldGenerator(@NotNull String worldName, @Nullable String id) {
return new TerraChunkGenerator();
diff --git a/src/main/java/com/dfsek/terra/TerraCommand.java b/src/main/java/com/dfsek/terra/TerraCommand.java
index 2c51771ab..b4a3a6fb7 100644
--- a/src/main/java/com/dfsek/terra/TerraCommand.java
+++ b/src/main/java/com/dfsek/terra/TerraCommand.java
@@ -9,6 +9,7 @@ import com.dfsek.terra.config.genconfig.OreConfig;
import com.dfsek.terra.generation.TerraChunkGenerator;
import com.dfsek.terra.image.WorldImageGenerator;
import com.dfsek.terra.structure.GaeaStructure;
+import com.dfsek.terra.structure.InitializationException;
import com.dfsek.terra.structure.StructureSpawn;
import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
@@ -158,7 +159,13 @@ public class TerraCommand implements CommandExecutor, TabExecutor {
BlockVector3 max = selection.getMaximumPoint();
Location l1 = new Location(pl.getWorld(), min.getBlockX(), min.getBlockY(), min.getBlockZ());
Location l2 = new Location(pl.getWorld(), max.getBlockX(), max.getBlockY(), max.getBlockZ());
- GaeaStructure structure = new GaeaStructure(l1, l2, args[2]);
+ GaeaStructure structure = null;
+ try {
+ structure = new GaeaStructure(l1, l2, args[2]);
+ } catch(InitializationException e) {
+ sender.sendMessage(e.getMessage());
+ return true;
+ }
try {
File file = new File(Terra.getInstance().getDataFolder() + File.separator + "export" + File.separator + "structures", args[2] + ".tstructure");
file.getParentFile().mkdirs();
@@ -173,14 +180,14 @@ public class TerraCommand implements CommandExecutor, TabExecutor {
try {
GaeaStructure struc = GaeaStructure.load(new File(Terra.getInstance().getDataFolder() + File.separator + "export" + File.separator + "structures", args[2] + ".tstructure"));
if("true".equals(args[3])) struc.paste(pl.getLocation());
- else struc.paste(pl.getLocation(), pl.getLocation().getChunk());
+ //else struc.paste(pl.getLocation(), pl.getLocation().getChunk());
} catch(IOException e) {
e.printStackTrace();
sender.sendMessage("Structure not found.");
}
return true;
} else if("getspawn".equals(args[1])) {
- Vector v = new StructureSpawn(500, 100).getNearestSpawn(pl.getLocation().getBlockX(), pl.getLocation().getBlockZ(), pl.getWorld().getSeed());
+ Vector v = new StructureSpawn(250, 250).getNearestSpawn(pl.getLocation().getBlockX(), pl.getLocation().getBlockZ(), pl.getWorld().getSeed());
sender.sendMessage(v.getBlockX() + ":" + v.getBlockZ());
}
}
diff --git a/src/main/java/com/dfsek/terra/TerraProfiler.java b/src/main/java/com/dfsek/terra/TerraProfiler.java
index ddf534453..2c5ad2d69 100644
--- a/src/main/java/com/dfsek/terra/TerraProfiler.java
+++ b/src/main/java/com/dfsek/terra/TerraProfiler.java
@@ -13,12 +13,12 @@ public class TerraProfiler extends WorldProfiler {
private static final Map profilerMap = new HashMap<>();
public TerraProfiler(World w) {
super(w);
- this.addMeasurement(new Measurement(2500000, DataType.PERIOD_MILLISECONDS), "TotalChunkGenTime")
- .addMeasurement(new Measurement(2500000, DataType.PERIOD_MILLISECONDS), "ChunkBaseGenTime")
- .addMeasurement(new Measurement(2000000, DataType.PERIOD_MILLISECONDS), "BiomeSetTime")
+ this
.addMeasurement(new Measurement(25000000, DataType.PERIOD_MILLISECONDS), "TreeGenTime")
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "FloraTime")
+ .addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "OreTime")
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "CaveTime")
+ .addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "StructureTime")
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "CaveBlockUpdate");
profilerMap.put(w, this);
}
diff --git a/src/main/java/com/dfsek/terra/generation/TerraChunkGenerator.java b/src/main/java/com/dfsek/terra/generation/TerraChunkGenerator.java
index da16583e4..93ce0a436 100644
--- a/src/main/java/com/dfsek/terra/generation/TerraChunkGenerator.java
+++ b/src/main/java/com/dfsek/terra/generation/TerraChunkGenerator.java
@@ -37,7 +37,6 @@ public class TerraChunkGenerator extends GaeaChunkGenerator {
public TerraChunkGenerator() {
super(ChunkInterpolator.InterpolationType.TRILINEAR);
- popMan.attach(new StructurePopulator());
popMan.attach(new TreePopulator());
popMan.attach(new FloraPopulator());
popMan.attach(new OrePopulator());
diff --git a/src/main/java/com/dfsek/terra/population/CavePopulator.java b/src/main/java/com/dfsek/terra/population/CavePopulator.java
index 8b7d1e417..ca45946bf 100644
--- a/src/main/java/com/dfsek/terra/population/CavePopulator.java
+++ b/src/main/java/com/dfsek/terra/population/CavePopulator.java
@@ -22,56 +22,59 @@ import java.util.Set;
public class CavePopulator extends BlockPopulator {
private static final Map shiftStorage = new HashMap<>(); // Persist BlockData created for shifts, to avoid re-calculating each time.
+ private static final BlockData AIR = Material.AIR.createBlockData();
@Override
public void populate(@NotNull World world, @NotNull Random random, @NotNull Chunk chunk) {
- ProfileFuture cave = TerraProfiler.fromWorld(world).measure("CaveTime");
- for(CarverConfig c : CarverConfig.getCarvers()) {
- Map shiftCandidate = new HashMap<>();
- Set updateNeeded = new HashSet<>();
- Map blocks = c.getCarver().carve(chunk.getX(), chunk.getZ(), world).getCarvedBlocks();
- for(Map.Entry e : blocks.entrySet()) {
- Vector v = e.getKey();
- Block b = chunk.getBlock(v.getBlockX(), v.getBlockY(), v.getBlockZ());
- Material m = b.getType();
- 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), c.getUpdateBlocks().contains(m));
- } else if(e.getValue().equals(CarvingData.CarvingType.WALL) && c.isReplaceableOuter(m)){
- if(c.getShiftedBlocks().containsKey(b.getType())) shiftCandidate.put(b.getLocation(), b.getType());
- b.setBlockData(c.getPaletteOuter(v.getBlockY()).get(random), c.getUpdateBlocks().contains(m));
- } else if(e.getValue().equals(CarvingData.CarvingType.TOP) && c.isReplaceableTop(m)){
- if(c.getShiftedBlocks().containsKey(b.getType())) shiftCandidate.put(b.getLocation(), b.getType());
- b.setBlockData(c.getPaletteTop(v.getBlockY()).get(random), c.getUpdateBlocks().contains(m));
- } else if(e.getValue().equals(CarvingData.CarvingType.BOTTOM) && c.isReplaceableBottom(m)){
- if(c.getShiftedBlocks().containsKey(b.getType())) shiftCandidate.put(b.getLocation(), b.getType());
- b.setBlockData(c.getPaletteBottom(v.getBlockY()).get(random), c.getUpdateBlocks().contains(m));
- }
- if(c.getUpdateBlocks().contains(m)) {
- updateNeeded.add(b);
- }
- }
- int i = 0;
- int j = 0;
- for(Location l : shiftCandidate.keySet()) {
- Location mut = l.clone();
- Material orig = l.getBlock().getType();
- do mut.subtract(0, 1, 0);
- while(mut.getBlock().getType().equals(orig));
- try {
- if(c.getShiftedBlocks().get(shiftCandidate.get(l)).contains(mut.getBlock().getType())) {
- mut.getBlock().setBlockData(shiftStorage.computeIfAbsent(shiftCandidate.get(l), Material::createBlockData), false);
- j++;
+ try(ProfileFuture ignored = TerraProfiler.fromWorld(world).measure("CaveTime")) {
+ for(CarverConfig c : CarverConfig.getCarvers()) {
+ Map shiftCandidate = new HashMap<>();
+ Set updateNeeded = new HashSet<>();
+ Map blocks = c.getCarver().carve(chunk.getX(), chunk.getZ(), world).getCarvedBlocks();
+ for(Map.Entry e : blocks.entrySet()) {
+ Vector v = e.getKey();
+ Block b = chunk.getBlock(v.getBlockX(), v.getBlockY(), v.getBlockZ());
+ Material m = b.getType();
+ 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), c.getUpdateBlocks().contains(m));
+ } else if(e.getValue().equals(CarvingData.CarvingType.WALL) && c.isReplaceableOuter(m)) {
+ if(c.getShiftedBlocks().containsKey(b.getType()))
+ shiftCandidate.put(b.getLocation(), b.getType());
+ b.setBlockData(c.getPaletteOuter(v.getBlockY()).get(random), c.getUpdateBlocks().contains(m));
+ } else if(e.getValue().equals(CarvingData.CarvingType.TOP) && c.isReplaceableTop(m)) {
+ if(c.getShiftedBlocks().containsKey(b.getType()))
+ shiftCandidate.put(b.getLocation(), b.getType());
+ b.setBlockData(c.getPaletteTop(v.getBlockY()).get(random), c.getUpdateBlocks().contains(m));
+ } else if(e.getValue().equals(CarvingData.CarvingType.BOTTOM) && c.isReplaceableBottom(m)) {
+ if(c.getShiftedBlocks().containsKey(b.getType()))
+ shiftCandidate.put(b.getLocation(), b.getType());
+ b.setBlockData(c.getPaletteBottom(v.getBlockY()).get(random), c.getUpdateBlocks().contains(m));
}
- } catch(NullPointerException ignored) {}
- i++;
+ if(c.getUpdateBlocks().contains(m)) {
+ updateNeeded.add(b);
+ }
+ }
+ for(Location l : shiftCandidate.keySet()) {
+ Location mut = l.clone();
+ Material orig = l.getBlock().getType();
+ do mut.subtract(0, 1, 0);
+ while(mut.getBlock().getType().equals(orig));
+ try {
+ if(c.getShiftedBlocks().get(shiftCandidate.get(l)).contains(mut.getBlock().getType())) {
+ mut.getBlock().setBlockData(shiftStorage.computeIfAbsent(shiftCandidate.get(l), Material::createBlockData), false);
+ }
+ } catch(NullPointerException ignore) {}
+ }
+ try(ProfileFuture ignore = TerraProfiler.fromWorld(world).measure("CaveBlockUpdate")) {
+ for(Block b : updateNeeded) {
+ BlockData orig = b.getBlockData();
+ b.setBlockData(AIR, false);
+ b.setBlockData(orig, true);
+ }
+ }
}
- for(Block b : updateNeeded) {
- BlockData orig = b.getBlockData();
- b.setBlockData(Material.AIR.createBlockData(), true);
- b.setBlockData(orig, true);
- }
- }
- if(cave != null) cave.complete();
+ }
}
}
diff --git a/src/main/java/com/dfsek/terra/population/FloraPopulator.java b/src/main/java/com/dfsek/terra/population/FloraPopulator.java
index 12b126de7..b5d56ed8d 100644
--- a/src/main/java/com/dfsek/terra/population/FloraPopulator.java
+++ b/src/main/java/com/dfsek/terra/population/FloraPopulator.java
@@ -22,24 +22,25 @@ public class FloraPopulator extends GaeaBlockPopulator {
Set pop = new HashSet<>();
@Override
public void populate(@NotNull World world, @NotNull Random random, @NotNull Chunk chunk) {
- if(pop.contains(chunk)) Bukkit.getLogger().warning("Already populated flora in chunk: " + chunk);
- pop.add(chunk);
- ProfileFuture flora = TerraProfiler.fromWorld(world).measure("FloraTime");
- for(int x = 0; x < 16; x++) {
- for(int z = 0; z < 16; z++) {
- UserDefinedBiome biome = (UserDefinedBiome) TerraBiomeGrid.fromWorld(world).getBiome((chunk.getX() << 4) + x, (chunk.getZ() << 4) + z);
- if(biome.getDecorator().getFloraChance() <= 0 || random.nextInt(100) > biome.getDecorator().getFloraChance())
- continue;
- try {
- BiomeConfig c = BiomeConfig.fromBiome(biome);
- for(int i = 0; i < c.getFloraAttempts(); i++) {
- Flora item = biome.getDecorator().getFlora().get(random);
- Block highest = item.getHighestValidSpawnAt(chunk, x, z);
- if(highest != null && c.getFloraHeights(item).isInRange(highest.getY())) item.plant(highest.getLocation());
- }
- } catch(NullPointerException ignored) {}
+ try (ProfileFuture ignored = TerraProfiler.fromWorld(world).measure("FloraTime")) {
+ if(pop.contains(chunk)) Bukkit.getLogger().warning("Already populated flora in chunk: " + chunk);
+ pop.add(chunk);
+ for(int x = 0; x < 16; x++) {
+ for(int z = 0; z < 16; z++) {
+ UserDefinedBiome biome = (UserDefinedBiome) TerraBiomeGrid.fromWorld(world).getBiome((chunk.getX() << 4) + x, (chunk.getZ() << 4) + z);
+ if(biome.getDecorator().getFloraChance() <= 0 || random.nextInt(100) > biome.getDecorator().getFloraChance())
+ continue;
+ try {
+ BiomeConfig c = BiomeConfig.fromBiome(biome);
+ for(int i = 0; i < c.getFloraAttempts(); i++) {
+ Flora item = biome.getDecorator().getFlora().get(random);
+ Block highest = item.getHighestValidSpawnAt(chunk, x, z);
+ if(highest != null && c.getFloraHeights(item).isInRange(highest.getY()))
+ item.plant(highest.getLocation());
+ }
+ } catch(NullPointerException ignore) {}
+ }
}
}
- if(flora!=null) flora.complete();
}
}
diff --git a/src/main/java/com/dfsek/terra/population/OrePopulator.java b/src/main/java/com/dfsek/terra/population/OrePopulator.java
index 3cf47f71b..65fe93b9e 100644
--- a/src/main/java/com/dfsek/terra/population/OrePopulator.java
+++ b/src/main/java/com/dfsek/terra/population/OrePopulator.java
@@ -1,6 +1,7 @@
package com.dfsek.terra.population;
import com.dfsek.terra.MaxMin;
+import com.dfsek.terra.TerraProfiler;
import com.dfsek.terra.biome.TerraBiomeGrid;
import com.dfsek.terra.biome.UserDefinedBiome;
import com.dfsek.terra.config.genconfig.BiomeConfig;
@@ -11,6 +12,7 @@ import org.bukkit.World;
import org.jetbrains.annotations.NotNull;
import org.polydev.gaea.biome.Biome;
import org.polydev.gaea.population.GaeaBlockPopulator;
+import org.polydev.gaea.profiler.ProfileFuture;
import java.util.Map;
import java.util.Random;
@@ -18,15 +20,17 @@ import java.util.Random;
public class OrePopulator extends GaeaBlockPopulator {
@Override
public void populate(@NotNull World world, @NotNull Random random, @NotNull Chunk chunk) {
- Location l = chunk.getBlock(8, 0, 0).getLocation();
- Biome b = TerraBiomeGrid.fromWorld(world).getBiome(l.getBlockX(), l.getBlockZ());
- for(Map.Entry e : BiomeConfig.fromBiome((UserDefinedBiome) b).getOres().entrySet()) {
- int num = e.getValue().get(random);
- for(int i = 0; i < num; i++) {
- int x = random.nextInt(16);
- int z = random.nextInt(16);
- int y = BiomeConfig.fromBiome((UserDefinedBiome) b).getOreHeight(e.getKey()).get(random);
- e.getKey().doVein(chunk.getBlock(x, y, z).getLocation(), random);
+ try (ProfileFuture ignored = TerraProfiler.fromWorld(world).measure("OreTime")) {
+ Location l = chunk.getBlock(8, 0, 0).getLocation();
+ Biome b = TerraBiomeGrid.fromWorld(world).getBiome(l.getBlockX(), l.getBlockZ());
+ for(Map.Entry e : BiomeConfig.fromBiome((UserDefinedBiome) b).getOres().entrySet()) {
+ int num = e.getValue().get(random);
+ for(int i = 0; i < num; i++) {
+ int x = random.nextInt(16);
+ int z = random.nextInt(16);
+ int y = BiomeConfig.fromBiome((UserDefinedBiome) b).getOreHeight(e.getKey()).get(random);
+ e.getKey().doVein(chunk.getBlock(x, y, z).getLocation(), random);
+ }
}
}
}
diff --git a/src/main/java/com/dfsek/terra/population/StructurePopulator.java b/src/main/java/com/dfsek/terra/population/StructurePopulator.java
index e424b1daf..e737696c0 100644
--- a/src/main/java/com/dfsek/terra/population/StructurePopulator.java
+++ b/src/main/java/com/dfsek/terra/population/StructurePopulator.java
@@ -1,14 +1,17 @@
package com.dfsek.terra.population;
import com.dfsek.terra.Terra;
+import com.dfsek.terra.TerraProfiler;
import com.dfsek.terra.structure.GaeaStructure;
import com.dfsek.terra.structure.StructureSpawn;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.World;
+import org.bukkit.generator.BlockPopulator;
import org.jetbrains.annotations.NotNull;
import org.polydev.gaea.population.GaeaBlockPopulator;
+import org.polydev.gaea.profiler.ProfileFuture;
import java.io.File;
import java.io.IOException;
@@ -16,23 +19,18 @@ import java.util.HashSet;
import java.util.Random;
import java.util.Set;
-public class StructurePopulator extends GaeaBlockPopulator {
- StructureSpawn spawnTest = new StructureSpawn(100, 5);
- Set pop = new HashSet<>();
+public class StructurePopulator extends BlockPopulator {
+ StructureSpawn spawnTest = new StructureSpawn(250, 250);
+ GaeaStructure struc = GaeaStructure.load(new File(Terra.getInstance().getDataFolder() + File.separator + "export" + File.separator + "structures", "demo2.tstructure"));
+ double horizontal = struc.getStructureInfo().getMaxHorizontal()/16D + 1D;
+
+ public StructurePopulator() throws IOException {
+ }
+
@Override
public void populate(@NotNull World world, @NotNull Random random, @NotNull Chunk chunk) {
- if(pop.contains(chunk)) Bukkit.getLogger().warning("Already populated structures in chunk: " + chunk);
- pop.add(chunk);
- Location near = spawnTest.getNearestSpawn((chunk.getX() << 4) + 8, (chunk.getZ() << 4), world.getSeed()).toLocation(world);
- if(near.getChunk().equals(chunk)) {
- Terra.getInstance().getLogger().info("Spawning structure at " + near.toString() + " in chunk " + chunk);
- try {
- GaeaStructure struc = GaeaStructure.load(new File(Terra.getInstance().getDataFolder() + File.separator + "export" + File.separator + "structures", "demo.tstructure"));
- near.setY(world.getHighestBlockYAt(near));
- struc.paste(near);
- } catch(IOException e) {
- e.printStackTrace();
- }
+ try(ProfileFuture ignored = TerraProfiler.fromWorld(world).measure("StructureTime")) {
+
}
}
}
diff --git a/src/main/java/com/dfsek/terra/population/TreePopulator.java b/src/main/java/com/dfsek/terra/population/TreePopulator.java
index 6d0a9e5fe..6634ae6bd 100644
--- a/src/main/java/com/dfsek/terra/population/TreePopulator.java
+++ b/src/main/java/com/dfsek/terra/population/TreePopulator.java
@@ -18,26 +18,26 @@ import java.util.Random;
public class TreePopulator extends GaeaBlockPopulator {
@Override
public void populate(@NotNull World world, @NotNull Random random, @NotNull Chunk chunk) {
- ProfileFuture tree = TerraProfiler.fromWorld(world).measure("TreeGenTime");
- int x = random.nextInt(16); // Decrease chances of chunk-crossing trees
- int z = random.nextInt(16);
- Location origin = chunk.getBlock(x, 0, z).getLocation();
- Biome b = TerraBiomeGrid.fromWorld(world).getBiome(origin);
- if(((UserDefinedDecorator) b.getDecorator()).getTreeChance() < random.nextInt(100)) return;
- int numTrees = 0;
- for(int i = 0; i < 48; i++) {
- int y = WorldUtil.getHighestValidSpawnAt(chunk, x, z);
- if(y <= 0) continue;
- origin = chunk.getBlock(x, y, z).getLocation().add(0, 1, 0);
- b = TerraBiomeGrid.fromWorld(world).getBiome(origin);
- numTrees++;
- try {
- b.getDecorator().getTrees().get(random).plant(origin, random, false, Terra.getInstance());
- } catch(NullPointerException ignored) {}
- if(numTrees >= b.getDecorator().getTreeDensity()) break;
- x = random.nextInt(16); // Decrease chances of chunk-crossing trees
- z = random.nextInt(16);
+ try(ProfileFuture ignored = TerraProfiler.fromWorld(world).measure("TreeGenTime")) {
+ int x = random.nextInt(16); // Decrease chances of chunk-crossing trees
+ int z = random.nextInt(16);
+ Location origin = chunk.getBlock(x, 0, z).getLocation();
+ Biome b = TerraBiomeGrid.fromWorld(world).getBiome(origin);
+ if(((UserDefinedDecorator) b.getDecorator()).getTreeChance() < random.nextInt(100)) return;
+ int numTrees = 0;
+ for(int i = 0; i < 48; i++) {
+ int y = WorldUtil.getHighestValidSpawnAt(chunk, x, z);
+ if(y <= 0) continue;
+ origin = chunk.getBlock(x, y, z).getLocation().add(0, 1, 0);
+ b = TerraBiomeGrid.fromWorld(world).getBiome(origin);
+ numTrees++;
+ try {
+ b.getDecorator().getTrees().get(random).plant(origin, random, false, Terra.getInstance());
+ } catch(NullPointerException ignore) {}
+ if(numTrees >= b.getDecorator().getTreeDensity()) break;
+ x = random.nextInt(16); // Decrease chances of chunk-crossing trees
+ z = random.nextInt(16);
+ }
}
- if(tree!=null) tree.complete();
}
}
diff --git a/src/main/java/com/dfsek/terra/structure/GaeaStructure.java b/src/main/java/com/dfsek/terra/structure/GaeaStructure.java
index 486bd8f8e..af8d548f3 100644
--- a/src/main/java/com/dfsek/terra/structure/GaeaStructure.java
+++ b/src/main/java/com/dfsek/terra/structure/GaeaStructure.java
@@ -1,10 +1,14 @@
package com.dfsek.terra.structure;
+import com.dfsek.terra.MaxMin;
+import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
+import org.bukkit.block.Sign;
import org.bukkit.block.data.BlockData;
+import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.FileInputStream;
@@ -16,14 +20,18 @@ import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Objects;
import java.util.UUID;
+import java.util.function.Consumer;
+import java.util.function.Function;
public class GaeaStructure implements Serializable {
public static final long serialVersionUID = -6664585217063842035L;
private final StructureContainedBlock[][][] structure;
+ private final GaeaStructureInfo structureInfo;
private final String id;
private final UUID uuid;
- public static GaeaStructure load(File f) throws IOException {
+ @NotNull
+ public static GaeaStructure load(@NotNull File f) throws IOException {
try {
return fromFile(f);
} catch(ClassNotFoundException e) {
@@ -31,7 +39,8 @@ public class GaeaStructure implements Serializable {
}
}
- public GaeaStructure(Location l1, Location l2, String id) {
+ public GaeaStructure(@NotNull Location l1, @NotNull Location l2, @NotNull String id) throws InitializationException {
+ int centerX = -1, centerZ = -1;
this.id = id;
this.uuid = UUID.randomUUID();
if(l1.getX() > l2.getX() || l1.getY() > l2.getY() || l1.getZ() > l2.getZ()) throw new IllegalArgumentException("Invalid locations provided!");
@@ -39,13 +48,32 @@ public class GaeaStructure implements Serializable {
for(int x = 0; x <= l2.getBlockX()-l1.getBlockX(); x++) {
for(int y = 0; y <= l2.getBlockY()-l1.getBlockY(); y++) {
for(int z = 0; z <= l2.getBlockZ()-l1.getBlockZ(); z++) {
- structure[x][y][z] = new StructureContainedBlock(x, y, z, Objects.requireNonNull(l1.getWorld()).getBlockAt(l1.clone().add(x, y, z)));
+ Block b = Objects.requireNonNull(l1.getWorld()).getBlockAt(l1.clone().add(x, y, z));
+ BlockData d = b.getBlockData();
+ if(d instanceof Sign) {
+ Sign s = (Sign) b.getState();
+ if(s.getLine(0).equals("[TERRA]")) {
+ d = Bukkit.createBlockData(s.getLine(2)+s.getLine(3));
+ if(s.getLine(1).equals("[CENTER]")) {
+ centerX = x;
+ centerZ = z;
+ }
+ }
+ }
+ structure[x][y][z] = new StructureContainedBlock(x, y, z, d);
}
}
}
+ if(centerX == -1 || centerZ == -1) throw new InitializationException("No structure center specified.");
+ structureInfo = new GaeaStructureInfo(l2.getBlockX()-l1.getBlockX(), l2.getBlockY()-l1.getBlockY(), l2.getBlockZ()-l1.getBlockZ(), centerX, centerZ);
}
- public void paste(Location origin) {
+ @NotNull
+ public GaeaStructureInfo getStructureInfo() {
+ return structureInfo;
+ }
+
+ public void paste(@NotNull Location origin) {
for(StructureContainedBlock[][] bList2 : structure) {
for(StructureContainedBlock[] bList1 : bList2) {
for(StructureContainedBlock block : bList1) {
@@ -57,46 +85,54 @@ public class GaeaStructure implements Serializable {
}
}
- public void paste(Location origin, Chunk c) {
- for(StructureContainedBlock[][] bList2 : structure) {
- for(StructureContainedBlock[] bList1 : bList2) {
- for(StructureContainedBlock block : bList1) {
- Location newLoc = origin.clone().add(block.getX(), block.getY(), block.getZ());
- BlockData data = block.getBlockData();
- if(newLoc.getChunk().equals(c) && !data.getMaterial().equals(Material.STRUCTURE_VOID)) newLoc.getBlock().setBlockData(block.getBlockData());
+ private StructureContainedBlock[][][] executeForBlocksInRange(MaxMin xM, MaxMin yM, MaxMin zM, Consumer exec) {
+ StructureContainedBlock[][][] temp = new StructureContainedBlock[xM.getMax()-xM.getMin()+1][yM.getMax()-yM.getMin()+1][zM.getMax()-zM.getMin()+1];
+ for(int x : xM) {
+ for(int y : yM) {
+ for(int z : zM) {
+ if(isInStructure(x, y, z)) exec.accept(structure[x][y][z]);
}
}
}
+ return temp;
}
- public void save(File f) throws IOException {
+ private boolean isInStructure(int x, int y, int z) {
+ return x < structure.length && y < structure[0].length && z < structure[0][0].length;
+ }
+
+ public void save(@NotNull File f) throws IOException {
toFile(this, f);
}
- private static GaeaStructure fromFile(File f) throws IOException, ClassNotFoundException {
+ @NotNull
+ private static GaeaStructure fromFile(@NotNull File f) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(f));
Object o = ois.readObject();
ois.close();
return (GaeaStructure) o;
}
- public static GaeaStructure fromStream(InputStream f) throws IOException, ClassNotFoundException {
+ @NotNull
+ public static GaeaStructure fromStream(@NotNull InputStream f) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(f);
Object o = ois.readObject();
ois.close();
return (GaeaStructure) o;
}
- private static void toFile(Serializable o, File f) throws IOException {
+ private static void toFile(@NotNull Serializable o, @NotNull File f) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(f));
oos.writeObject(o);
oos.close();
}
+ @NotNull
public String getId() {
return id;
}
+ @NotNull
public UUID getUuid() {
return uuid;
}
diff --git a/src/main/java/com/dfsek/terra/structure/GaeaStructureInfo.java b/src/main/java/com/dfsek/terra/structure/GaeaStructureInfo.java
new file mode 100644
index 000000000..1168339fb
--- /dev/null
+++ b/src/main/java/com/dfsek/terra/structure/GaeaStructureInfo.java
@@ -0,0 +1,43 @@
+package com.dfsek.terra.structure;
+
+import java.io.Serializable;
+
+public class GaeaStructureInfo implements Serializable {
+ public static final long serialVersionUID = -175639605885943678L;
+ private final int sizeX;
+ private final int sizeY;
+ private final int sizeZ;
+ private final int centerX;
+ private final int centerZ;
+ public GaeaStructureInfo(int sizeX, int sizeY, int sizeZ, int centerX, int centerZ) {
+ this.sizeX = sizeX;
+ this.sizeY = sizeY;
+ this.sizeZ = sizeZ;
+ this.centerX = centerX;
+ this.centerZ = centerZ;
+ }
+
+ public int getSizeX() {
+ return sizeX;
+ }
+
+ public int getSizeZ() {
+ return sizeZ;
+ }
+
+ public int getSizeY() {
+ return sizeY;
+ }
+
+ public int getCenterX() {
+ return centerX;
+ }
+
+ public int getCenterZ() {
+ return centerZ;
+ }
+
+ public double getMaxHorizontal() {
+ return Math.sqrt(Math.pow(sizeX, 2) + Math.pow(sizeZ, 2));
+ }
+}
diff --git a/src/main/java/com/dfsek/terra/structure/InitializationException.java b/src/main/java/com/dfsek/terra/structure/InitializationException.java
new file mode 100644
index 000000000..8289a3a83
--- /dev/null
+++ b/src/main/java/com/dfsek/terra/structure/InitializationException.java
@@ -0,0 +1,7 @@
+package com.dfsek.terra.structure;
+
+public class InitializationException extends Exception {
+ public InitializationException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/com/dfsek/terra/structure/StructureContainedBlock.java b/src/main/java/com/dfsek/terra/structure/StructureContainedBlock.java
index 0b91683ba..5f84a0d2e 100644
--- a/src/main/java/com/dfsek/terra/structure/StructureContainedBlock.java
+++ b/src/main/java/com/dfsek/terra/structure/StructureContainedBlock.java
@@ -4,6 +4,7 @@ import org.bukkit.Bukkit;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Entity;
+import org.bukkit.event.block.BlockDamageEvent;
import java.io.Serializable;
@@ -14,11 +15,11 @@ public class StructureContainedBlock implements Serializable {
private final int x;
private final int y;
private final int z;
- public StructureContainedBlock(int x, int y, int z, Block block) {
+ public StructureContainedBlock(int x, int y, int z, BlockData block) {
this.x = x;
this.y = y;
this.z = z;
- this.bl = block.getBlockData();
+ this.bl = block;
dataString = bl.getAsString(false);
}
diff --git a/src/main/java/com/dfsek/terra/structure/StructureManager.java b/src/main/java/com/dfsek/terra/structure/StructureManager.java
deleted file mode 100644
index a5256dced..000000000
--- a/src/main/java/com/dfsek/terra/structure/StructureManager.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.dfsek.terra.structure;
-
-import org.bukkit.plugin.java.JavaPlugin;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.UUID;
-import java.util.logging.Logger;
-
-public class StructureManager {
- private static StructureManager singleton;
- private Logger logger;
- private final Map structures = new HashMap<>();
- public StructureManager(JavaPlugin main) {
- if(singleton!= null) throw new IllegalStateException("Only one instance of StructureManager may exist at a given time.");
- this.logger = main.getLogger();
- logger.info("Initializing StructureManager...");
- singleton = this;
- }
- public GaeaStructure get(UUID uuid) {
- return structures.get(uuid);
- }
- public void load(File file) throws IOException {
- GaeaStructure s = GaeaStructure.load(file);
- structures.put(s.getUuid(), s);
- }
-}
diff --git a/src/test/java/MaxMinTest.java b/src/test/java/MaxMinTest.java
new file mode 100644
index 000000000..5479c9e51
--- /dev/null
+++ b/src/test/java/MaxMinTest.java
@@ -0,0 +1,17 @@
+import com.dfsek.terra.MaxMin;
+import org.jetbrains.annotations.TestOnly;
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class MaxMinTest {
+ @Test
+ public void iterator() {
+ MaxMin m = new MaxMin(0, 100);
+ int i = 0;
+ for(int mint : m) {
+ assertEquals(i, mint);
+ i++;
+ }
+ assertEquals(100, i);
+ }
+}