9
0
mirror of https://github.com/VolmitSoftware/Iris.git synced 2025-12-25 18:19:14 +00:00

Schematics

This commit is contained in:
Daniel Mills
2020-01-03 01:05:10 -05:00
parent e2c8b6ae02
commit ec43d2012e
22 changed files with 2092 additions and 227 deletions

View File

@@ -4,29 +4,25 @@ import java.util.UUID;
import java.util.function.Function;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.WorldCreator;
import org.bukkit.block.Biome;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.util.Vector;
import ninja.bytecode.iris.generator.IrisGenerator;
import ninja.bytecode.iris.util.RealBiome;
import ninja.bytecode.shuriken.bench.Profiler;
import ninja.bytecode.shuriken.collections.GMap;
import ninja.bytecode.shuriken.collections.GSet;
import ninja.bytecode.shuriken.execution.J;
import ninja.bytecode.shuriken.execution.TaskExecutor;
import ninja.bytecode.shuriken.format.F;
import ninja.bytecode.shuriken.math.M;
public class Iris extends JavaPlugin implements Listener
{
@@ -46,6 +42,7 @@ public class Iris extends JavaPlugin implements Listener
gen = new IrisGenerator();
genPool = new TaskExecutor(getTC(), settings.performance.threadPriority, "Iris Generator");
getServer().getPluginManager().registerEvents((Listener) this, this);
new WandManager();
// Debug world regens
GSet<String> ws = new GSet<>();
@@ -90,6 +87,7 @@ public class Iris extends JavaPlugin implements Listener
public void onDisable()
{
genPool.close();
HandlerList.unregisterAll((Plugin) this);
}
@Override
@@ -101,63 +99,17 @@ public class Iris extends JavaPlugin implements Listener
@EventHandler
public void on(PlayerCommandPreprocessEvent e)
{
if(e.getMessage().toLowerCase().equals("/iris"))
if(e.getMessage().toLowerCase().equals("/iris gen"))
{
e.setCancelled(true);
World wold = e.getPlayer().getWorld();
World w = createIrisWorld();
e.getPlayer().teleport(new Location(w, 0, 256, 0));
e.getPlayer().setFlying(true);
e.getPlayer().setGameMode(GameMode.CREATIVE);
e.setCancelled(true);
wold.setAutoSave(false);
Bukkit.unloadWorld(wold, false);
}
if(e.getMessage().toLowerCase().equals("/iris info"))
{
e.setCancelled(true);
sendInfo(e.getPlayer());
for(Biome i : Biome.values())
{
J.attempt(() -> System.out.print(new RealBiome(i)));
}
}
}
private void sendInfo(Player player)
{
for(int i = 0; i < 18; i++)
{
player.sendMessage("");
}
GMap<String, Function<Vector, Double>> w = values.get(player.getWorld().getName());
for(String i : w.k())
{
double value = w.get(i).apply(player.getLocation().toVector());
String p = i.substring(0, 2);
String v = value + "";
if(p.startsWith("%"))
{
v = F.pc(value, Integer.valueOf(p.substring(1)));
}
if(p.startsWith("D"))
{
v = F.f(value, Integer.valueOf(p.substring(1)));
}
else if(p.startsWith("^"))
{
double c = M.lerpInverse(-11, 37, value);
double f = 32 + (c * (1.8));
v = F.f(c, Integer.valueOf(p.substring(1))) + " \u00B0C / " + F.f(f, Integer.valueOf(p.substring(1))) + " \u00B0F";
}
player.sendMessage(ChatColor.GREEN + i.substring(2) + ": " + ChatColor.RESET + ChatColor.WHITE + ChatColor.BOLD + v);
}
}
private World createIrisWorld()

View File

@@ -9,8 +9,8 @@ public class Settings
public static class PerformanceSettings
{
public PerformanceMode performanceMode = PerformanceMode.HALF_CPU;
public int threadCount = 4;
public PerformanceMode performanceMode = PerformanceMode.MATCH_CPU;
public int threadCount = 12;
public int threadPriority = Thread.MAX_PRIORITY;
}

View File

@@ -0,0 +1,101 @@
package ninja.bytecode.iris;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.EquipmentSlot;
import ninja.bytecode.iris.schematic.Schematic;
import ninja.bytecode.iris.util.WandUtil;
public class WandManager implements Listener
{
public WandManager()
{
Bukkit.getPluginManager().registerEvents(this, Iris.instance);
}
@EventHandler
public void on(PlayerCommandPreprocessEvent e)
{
if(e.getMessage().startsWith("/isave "))
{
e.setCancelled(true);
Schematic s = WandUtil.createSchematic(e.getPlayer().getInventory().getItemInMainHand(), e.getPlayer().getLocation());
File f = new File(Iris.instance.getDataFolder(), "schematics/" + e.getMessage().split("\\Q \\E")[1] + ".ish");
f.getParentFile().mkdirs();
try
{
FileOutputStream fos = new FileOutputStream(f);
s.write(fos);
e.getPlayer().sendMessage("Done!");
}
catch(Throwable e1)
{
e1.printStackTrace();
}
}
if(e.getMessage().startsWith("/iload "))
{
e.setCancelled(true);
Schematic s = new Schematic(1, 1, 1, 1, 1, 1);
File f = new File(Iris.instance.getDataFolder(), "schematics/" + e.getMessage().split("\\Q \\E")[1] + ".ish");
if(!f.exists())
{
e.getPlayer().sendMessage("Not Found");
return;
}
try
{
FileInputStream fin = new FileInputStream(f);
s.read(fin);
WandUtil.pasteSchematic(s, e.getPlayer().getLocation());
e.getPlayer().sendMessage("Done!");
}
catch(Throwable e1)
{
e1.printStackTrace();
}
}
if(e.getMessage().equals("/iris wand"))
{
e.setCancelled(true);
e.getPlayer().getInventory().addItem(WandUtil.createWand());
}
}
@EventHandler
public void on(PlayerInteractEvent e)
{
if(e.getHand().equals(EquipmentSlot.HAND) && WandUtil.isWand(e.getPlayer().getInventory().getItemInMainHand()))
{
if(e.getAction().equals(Action.LEFT_CLICK_BLOCK))
{
e.setCancelled(true);
e.getPlayer().getInventory().setItemInMainHand(WandUtil.update(true, e.getPlayer().getLocation(), e.getPlayer().getInventory().getItemInMainHand()));
e.getPlayer().updateInventory();
}
else if(e.getAction().equals(Action.RIGHT_CLICK_BLOCK))
{
e.setCancelled(true);
e.getPlayer().getInventory().setItemInMainHand(WandUtil.update(false, e.getPlayer().getLocation(), e.getPlayer().getInventory().getItemInMainHand()));
e.getPlayer().updateInventory();
}
}
}
}

View File

@@ -1,5 +1,6 @@
package ninja.bytecode.iris.generator;
import java.io.File;
import java.util.List;
import java.util.Random;
@@ -12,15 +13,19 @@ import ninja.bytecode.iris.Iris;
import ninja.bytecode.iris.generator.biome.IrisBiome;
import ninja.bytecode.iris.generator.layer.GenLayerBase;
import ninja.bytecode.iris.generator.layer.GenLayerBiome;
import ninja.bytecode.iris.generator.layer.GenLayerCaves;
import ninja.bytecode.iris.generator.layer.GenLayerLayeredNoise;
import ninja.bytecode.iris.generator.layer.GenLayerRidge;
import ninja.bytecode.iris.generator.populator.PopulatorTrees;
import ninja.bytecode.iris.generator.populator.BiomeBiasSchematicPopulator;
import ninja.bytecode.iris.schematic.Schematic;
import ninja.bytecode.iris.util.AtomicChunkData;
import ninja.bytecode.iris.util.ChunkPlan;
import ninja.bytecode.iris.util.IrisInterpolation;
import ninja.bytecode.iris.util.MB;
import ninja.bytecode.iris.util.ParallelChunkGenerator;
import ninja.bytecode.shuriken.collections.GList;
import ninja.bytecode.shuriken.execution.J;
import ninja.bytecode.shuriken.logging.L;
import ninja.bytecode.shuriken.math.M;
import ninja.bytecode.shuriken.math.RNG;
@@ -32,8 +37,8 @@ public class IrisGenerator extends ParallelChunkGenerator
private GenLayerLayeredNoise glLNoise;
private GenLayerRidge glRidge;
private GenLayerBiome glBiome;
private GenLayerCaves glCaves;
private RNG rTerrain;
private RNG rScatter;
private World world;
@Override
@@ -45,11 +50,7 @@ public class IrisGenerator extends ParallelChunkGenerator
glLNoise = new GenLayerLayeredNoise(this, world, random, rTerrain.nextParallelRNG(2));
glRidge = new GenLayerRidge(this, world, random, rTerrain.nextParallelRNG(3));
glBiome = new GenLayerBiome(this, world, random, rTerrain.nextParallelRNG(4));
}
public World getWorld()
{
return world;
glCaves = new GenLayerCaves(this, world, random, rTerrain.nextParallelRNG(-1));
}
@Override
@@ -69,8 +70,10 @@ public class IrisGenerator extends ParallelChunkGenerator
hv += glLNoise.generateLayer(hv, wxx, wzx);
hv -= glRidge.generateLayer(hv, wxx, wzx);
int height = (int) Math.round(M.clip(hv, 0D, 1D) * 253);
int max = Math.max(height, seaLevel);
IrisBiome override = null;
for(int i = 0; i < Math.max(height, seaLevel); i++)
for(int i = 0; i < max; i++)
{
MB mb = new MB(Material.STONE);
boolean underwater = i >= height && i < seaLevel;
@@ -88,10 +91,43 @@ public class IrisGenerator extends ParallelChunkGenerator
if(i == height - 1)
{
if(height > 61 && height < glBase.scatterInt(x, i, z, 4) + 65)
{
override = IrisBiome.BEACH;
}
else if(height < 63)
{
if(i < 36)
{
override = IrisBiome.DEEP_OCEAN;
}
else if(i < 50)
{
override = IrisBiome.OCEAN;
}
else
{
override = IrisBiome.LAKE;
}
}
if(override != null)
{
biome = override;
}
mb = biome.getSurface(wx, wz, rTerrain);
}
if(Iris.settings.gen.flatBedrock ? i == 0 : i < glBase.scatterInt(x, i, z, 3))
if(i == 0)
{
mb = BEDROCK;
}
if(Iris.settings.gen.flatBedrock ? i == 1 : i < glBase.scatterInt(x, i, z, 3))
{
mb = BEDROCK;
}
@@ -99,6 +135,13 @@ public class IrisGenerator extends ParallelChunkGenerator
setBlock(x, i, z, mb.material, mb.data);
}
glCaves.genCaves(wxx, wzx, x, z, height, this);
if(override != null)
{
return override.getRealBiome();
}
return biome.getRealBiome();
}
@@ -114,24 +157,73 @@ public class IrisGenerator extends ParallelChunkGenerator
}
@Override
public List<BlockPopulator> getDefaultPopulators(World world)
{
GList<BlockPopulator> p = new GList<>();
int b = 0;
for(IrisBiome i : IrisBiome.getBiomes())
{
b++;
L.i("Processing Populators for Biome " + i.getName());
for(String j : i.getSchematicGroups().keySet())
{
p.add(new BiomeBiasSchematicPopulator(i.getSchematicGroups().get(j), i, loadSchematics(j)));
}
}
J.attempt(() -> p.add(new BiomeBiasSchematicPopulator(5, IrisBiome.JUNGLE, loadSchematics(""))));
L.i("Initialized " + b + " Biomes and " + p.size() + " Populators");
L.flush();
return p;
}
private Schematic[] loadSchematics(String folder)
{
File f = new File(Iris.instance.getDataFolder(), "objects/" + folder);
GList<Schematic> s = new GList<>();
try
{
if(f.exists() && f.isDirectory())
{
for(File i : f.listFiles())
{
if(i.isFile() && i.getName().endsWith(".ish"))
{
s.add(Schematic.load(i));
}
}
}
}
catch(Throwable e)
{
}
return s.toArray(new Schematic[s.size()]);
}
private double getBiomedHeight(int x, int z, ChunkPlan plan)
{
return plan.getHeight(x, z, () -> {
return plan.getHeight(x, z, () ->
{
int wx = (int) Math.round((double) x * Iris.settings.gen.horizontalZoom);
int wz = (int) Math.round((double) z * Iris.settings.gen.horizontalZoom);
IrisBiome biome = glBiome.getBiome(wx * Iris.settings.gen.biomeScale, wz * Iris.settings.gen.biomeScale);
double h = Iris.settings.gen.baseHeight + biome.getHeight();
h += (glBase.getHeight(wx, wz) * biome.getAmp()) - (0.33 * biome.getAmp());
return h;
});
}
@Override
public List<BlockPopulator> getDefaultPopulators(World world)
public World getWorld()
{
GList<BlockPopulator> p = new GList<BlockPopulator>();
p.add(new PopulatorTrees());
return p;
return world;
}
}

View File

@@ -32,6 +32,10 @@ public class IrisBiome
.surface(MB.of(Material.SAND), MB.of(Material.SAND), MB.of(Material.SAND), MB.of(Material.CLAY), MB.of(Material.GRAVEL))
.simplexSurface()
.height(-0.03);
public static final IrisBiome LAKE = new IrisBiome("Lake", Biome.OCEAN)
.surface(MB.of(Material.SAND), MB.of(Material.SAND), MB.of(Material.SAND), MB.of(Material.GRAVEL), MB.of(Material.CLAY), MB.of(Material.GRAVEL))
.simplexSurface()
.height(-0.03);
public static final IrisBiome DEEP_OCEAN = new IrisBiome("Deep Ocean", Biome.DEEP_OCEAN)
.surface(MB.of(Material.SAND), MB.of(Material.CLAY), MB.of(Material.GRAVEL))
.simplexSurface()
@@ -237,7 +241,7 @@ public class IrisBiome
simplexScatter = true;
return this;
}
public IrisBiome scatterSurface()
{
scatterSurface = true;
@@ -312,9 +316,9 @@ public class IrisBiome
});
}
return poly.getChoice(wx * 0.2D, wz * 0.2D);
return poly.getChoice(wx * 0.2D, wz * 0.2D);
}
if(scatterSurface)
{
if(poly == null)
@@ -325,7 +329,7 @@ public class IrisBiome
});
}
return poly.getChoice(wx * 0.2D, wz * 0.2D);
return poly.getChoice(wx * 0.2D, wz * 0.2D);
}
return getSurface().getRandom();
@@ -385,7 +389,12 @@ public class IrisBiome
return null;
}
public static IrisBiome find(Biome biome)
public static GList<IrisBiome> getBiomes()
{
return map.v().remove(IrisBiome.ROAD_GRASSY, IrisBiome.ROAD_GRAVEL, IrisBiome.BEACH, IrisBiome.LAKE, IrisBiome.RIVER);
}
public static IrisBiome findByBiome(Biome biome)
{
if(map.containsKey(biome))
{
@@ -394,4 +403,9 @@ public class IrisBiome
return IrisBiome.PLAINS;
}
public GMap<String, Double> getSchematicGroups()
{
return schematicGroups;
}
}

View File

@@ -33,38 +33,7 @@ public class GenLayerBiome extends GenLayer
riverCheck = new CNG(rng.nextParallelRNG(30), 1D, 2).scale(0.00096);
pathCheck = new CNG(rng.nextParallelRNG(31), 1D, 1).scale(0.00096);
roads = new MaxingGenerator(rng.nextParallelRNG(32), 5, 0.00055, 8, factory);
biomeGenerator = new EnumMaxingGenerator<IrisBiome>(rng.nextParallelRNG(33), 0.00755 * Iris.settings.gen.biomeScale, 1,
new IrisBiome[] {
IrisBiome.HAUNTED_FOREST,
IrisBiome.FOREST_MOUNTAINS,
IrisBiome.DESERT,
IrisBiome.DESERT_HILLS,
IrisBiome.MESA,
IrisBiome.DESERT_COMBINED,
IrisBiome.SAVANNA,
IrisBiome.SAVANNA_HILLS,
IrisBiome.DESERT_RED,
IrisBiome.JUNGLE,
IrisBiome.JUNGLE_HILLS,
IrisBiome.SWAMP,
IrisBiome.OCEAN,
IrisBiome.PLAINS,
IrisBiome.DECAYING_PLAINS,
IrisBiome.FOREST,
IrisBiome.FOREST_HILLS,
IrisBiome.BIRCH_FOREST,
IrisBiome.BIRCH_FOREST_HILLS,
IrisBiome.ROOFED_FOREST,
IrisBiome.TAIGA,
IrisBiome.EXTREME_HILLS,
IrisBiome.EXTREME_HILLS_TREES,
IrisBiome.TAIGA_COLD,
IrisBiome.TAIGA_COLD_HILLS,
IrisBiome.ICE_FLATS,
IrisBiome.ICE_MOUNTAINS,
IrisBiome.REDWOOD_TAIGA,
IrisBiome.REDWOOD_TAIGA_HILLS,
}, factory);
biomeGenerator = new EnumMaxingGenerator<IrisBiome>(rng.nextParallelRNG(33), 0.00755 * Iris.settings.gen.biomeScale, 1, IrisBiome.getBiomes().toArray(new IrisBiome[IrisBiome.getBiomes().size()]), factory);
//@done
}
@@ -72,7 +41,7 @@ public class GenLayerBiome extends GenLayer
{
double x = xx + (fracture.noise(zz, xx) * 1550D);
double z = zz - (fracture.noise(xx, zz) * 1550D);
if(riverCheck.noise(x, z) > 0.75)
{
if(biomeGenerator.hasBorder(3, 3 + Math.pow(riverCheck.noise(x, z), 1.25) * 16, x, z))
@@ -80,24 +49,24 @@ public class GenLayerBiome extends GenLayer
return IrisBiome.RIVER;
}
}
IrisBiome cbi = biomeGenerator.getChoice(x, z);
if(pathCheck.noise(x, z) > 0.33)
{
IrisBiome road = IrisBiome.ROAD_GRAVEL;
if(cbi.getSurface().get(0).material.equals(Material.GRASS))
{
road = IrisBiome.ROAD_GRASSY;
}
if(Math.abs(road.getHeight() - cbi.getHeight()) < 0.0001 && roads.hasBorder(4, 3, xx, zz))
{
return road;
}
}
return cbi;
}

View File

@@ -0,0 +1,78 @@
package ninja.bytecode.iris.generator.layer;
import java.util.Random;
import org.bukkit.Material;
import org.bukkit.World;
import ninja.bytecode.iris.generator.IrisGenerator;
import ninja.bytecode.iris.util.GenLayer;
import ninja.bytecode.iris.util.MaxingGenerator;
import ninja.bytecode.shuriken.math.CNG;
import ninja.bytecode.shuriken.math.RNG;
public class GenLayerCaves extends GenLayer
{
private CNG caveHeight;
private CNG caveGirth;
private CNG caveClamp;
private MaxingGenerator caveVeins;
public GenLayerCaves(IrisGenerator iris, World world, Random random, RNG rng)
{
super(iris, world, random, rng);
caveHeight = new CNG(rng.nextParallelRNG(-100001), 1D, 7).scale(0.00222);
caveGirth = new CNG(rng.nextParallelRNG(-100002), 1D, 12).scale(0.03);
caveClamp = new CNG(rng.nextParallelRNG(-10000), 1D, 3).scale(0.1422);
caveVeins = new MaxingGenerator(rng.nextParallelRNG(-99999), 22, 0.002, 1, (g) -> g.fractureWith(new CNG(rng.nextParallelRNG(-5555), 1D, 4).scale(0.02), 70));
}
public void genCaves(double wxx, double wzx, int x, int z, int s, IrisGenerator g)
{
for(double itr = 0; itr < 0.2; itr += 0.1)
{
double thickness = 0.25 + itr + (0.5 * caveClamp.noise(wxx, wzx));
double size = 3.88D * thickness;
double variance = 8.34D * thickness;
double w = size + (variance * caveGirth.noise(wxx, wzx));
double h = size + (variance * caveGirth.noise(wzx, wxx));
double width = 0;
double height = h;
double elevation = (caveHeight.noise(wxx + (19949D * itr), wzx - (19949D * itr)) * (350)) - 80;
while(width <= w && height > 1D)
{
width+=2;
height-=2;
if(caveVeins.hasBorder(3, width, wxx - (19949D * itr), wzx + (19949D * itr)))
{
double r = (((caveGirth.noise(wxx, wzx, width)) * variance) + height) / 2D;
for(int i = (int) -r; i < r; i++)
{
if(i + height > s)
{
break;
}
Material t = g.getType(x, (int) (elevation + i) - 55, z);
if(t.equals(Material.BEDROCK) || t.equals(Material.WATER) || t.equals(Material.STATIONARY_WATER))
{
continue;
}
g.setBlock(x, (int) (elevation + i) - 55, z, Material.AIR);
}
}
}
}
}
@Override
public double generateLayer(double gnoise, double dx, double dz)
{
return gnoise;
}
}

View File

@@ -0,0 +1,33 @@
package ninja.bytecode.iris.generator.populator;
import java.util.Random;
import org.bukkit.Chunk;
import org.bukkit.World;
import ninja.bytecode.iris.generator.biome.IrisBiome;
import ninja.bytecode.iris.schematic.Schematic;
import ninja.bytecode.iris.util.MB;
public class BiomeBiasSchematicPopulator extends SurfaceBiasSchematicPopulator
{
protected IrisBiome biome;
public BiomeBiasSchematicPopulator(double chance, IrisBiome biome, Schematic... schematics)
{
super(chance, schematics);
this.biome = biome;
for(MB i : biome.getSurface())
{
surface(i.material);
}
}
public void doPopulate(World world, Random random, Chunk source, int wx, int wz)
{
if(world.getBiome(wx, wz).equals(biome.getRealBiome()))
{
super.doPopulate(world, random, source, wx, wz);
}
}
}

View File

@@ -1,67 +0,0 @@
package ninja.bytecode.iris.generator.populator;
import java.util.Random;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.TreeType;
import org.bukkit.World;
import org.bukkit.generator.BlockPopulator;
import ninja.bytecode.iris.Iris;
import ninja.bytecode.iris.generator.biome.IrisBiome;
import ninja.bytecode.shuriken.bench.PrecisionStopwatch;
import ninja.bytecode.shuriken.math.RollingSequence;
public class PopulatorTrees extends BlockPopulator
{
public static RollingSequence timings = new RollingSequence(512);
@Override
public void populate(World world, Random random, Chunk source)
{
if(!Iris.settings.gen.doTrees)
{
return;
}
PrecisionStopwatch f = PrecisionStopwatch.start();
int debuff = 0;
for(int i = 0; i < 16; i++)
{
if(debuff > 0)
{
debuff--;
continue;
}
int x = random.nextInt(15) + (source.getX() * 16);
int z = random.nextInt(15) + (source.getZ() * 16);
int y = world.getHighestBlockYAt(x, z);
Location l = new Location(world, x, y, z);
if(!l.getBlock().getType().isSolid())
{
l.getBlock().setType(Material.AIR, false);
}
IrisBiome biome = IrisBiome.find(world.getBiome(x, z));
TreeType tt = biome.getTreeChanceSingle();
if(tt != null)
{
world.generateTree(l, tt);
}
else
{
debuff += 4;
}
}
f.end();
timings.put(f.getMilliseconds());
}
}

View File

@@ -0,0 +1,35 @@
package ninja.bytecode.iris.generator.populator;
import java.util.Random;
import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import ninja.bytecode.iris.schematic.Schematic;
import ninja.bytecode.iris.util.ChancedPopulator;
public class SchematicPopulator extends ChancedPopulator
{
protected final Schematic[] schematics;
public SchematicPopulator(double chance, Schematic... schematics)
{
super(chance);
this.schematics = schematics;
}
@Override
public void doPopulate(World world, Random random, Chunk source, int wx, int wz)
{
Block b = world.getHighestBlockAt(wx, wz);
if(!b.getRelative(BlockFace.DOWN).getType().isSolid())
{
return;
}
schematics[random.nextInt(schematics.length)].place(world, wx, b.getY() - 1, wz);
}
}

View File

@@ -0,0 +1,44 @@
package ninja.bytecode.iris.generator.populator;
import java.util.Random;
import org.bukkit.Chunk;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import ninja.bytecode.iris.schematic.Schematic;
import ninja.bytecode.shuriken.collections.GList;
public class SurfaceBiasSchematicPopulator extends SchematicPopulator
{
private GList<Material> bias;
public SurfaceBiasSchematicPopulator(double chance, Schematic... schematics)
{
super(chance, schematics);
this.bias = new GList<>();
}
public SurfaceBiasSchematicPopulator surface(Material mb)
{
bias.add(mb);
return this;
}
@Override
public void doPopulate(World world, Random random, Chunk source, int wx, int wz)
{
Block b = world.getHighestBlockAt(wx, wz);
for(Material i : bias)
{
if(b.getRelative(BlockFace.DOWN).getType().equals(i))
{
schematics[random.nextInt(schematics.length)].place(world, wx, b.getY() - 1, wz);
break;
}
}
}
}

View File

@@ -0,0 +1,210 @@
package ninja.bytecode.iris.schematic;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.zip.GZIPInputStream;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.util.BlockVector;
import ninja.bytecode.iris.util.MB;
import ninja.bytecode.shuriken.collections.GMap;
import ninja.bytecode.shuriken.io.CustomOutputStream;
import ninja.bytecode.shuriken.logging.L;
public class Schematic
{
private int w;
private int h;
private int d;
private int x;
private int y;
private int z;
private final GMap<BlockVector, MB> s;
public Schematic(int w, int h, int d, int x, int y, int z)
{
this.w = w;
this.h = h;
this.d = d;
this.x = x;
this.y = y;
this.z = z;
s = new GMap<>();
}
public int getW()
{
return w;
}
public int getH()
{
return h;
}
public int getD()
{
return d;
}
public int getX()
{
return x;
}
public int getY()
{
return y;
}
public int getZ()
{
return z;
}
public GMap<BlockVector, MB> getSchematic()
{
return s;
}
@SuppressWarnings("deprecation")
public void read(InputStream in) throws IOException
{
GZIPInputStream gzi = new GZIPInputStream(in);
DataInputStream din = new DataInputStream(gzi);
w = din.readInt();
h = din.readInt();
d = din.readInt();
x = din.readInt();
y = din.readInt();
z = din.readInt();
int l = din.readInt();
clear();
for(int i = 0; i < l; i++)
{
s.put(new BlockVector(din.readInt(), din.readInt(), din.readInt()), new MB(Material.getMaterial((int)din.readByte()), din.readByte()));
}
din.close();
}
@SuppressWarnings("deprecation")
public void write(OutputStream out) throws IOException
{
CustomOutputStream cos = new CustomOutputStream(out, 9);
DataOutputStream dos = new DataOutputStream(cos);
dos.writeInt(w);
dos.writeInt(h);
dos.writeInt(d);
dos.writeInt(x);
dos.writeInt(y);
dos.writeInt(z);
dos.writeInt(s.size());
for(BlockVector i : s.keySet())
{
dos.writeInt(i.getBlockX());
dos.writeInt(i.getBlockY());
dos.writeInt(i.getBlockZ());
dos.writeByte(s.get(i).material.getId());
dos.writeByte(s.get(i).data);
}
dos.close();
}
public BlockVector getOffset()
{
return new BlockVector(x, y, z);
}
public MB get(int x, int y, int z)
{
return s.get(new BlockVector(x, y, z));
}
public boolean has(int x, int y, int z)
{
return s.contains(new BlockVector(x, y, z));
}
public void put(int x, int y, int z, MB mb)
{
s.put(new BlockVector(x, y, z), mb);
}
public Schematic copy()
{
Schematic s = new Schematic(w, h, d, x, y, z);
s.fill(this.s);
return s;
}
public void clear()
{
s.clear();
}
public void fill(GMap<BlockVector, MB> b)
{
clear();
s.put(b);
}
@SuppressWarnings("deprecation")
public void place(World source, int wx, int wy, int wz)
{
Location start = new Location(source, wx, wy, wz).clone().subtract(getOffset());
for(BlockVector i : getSchematic().keySet())
{
MB b = getSchematic().get(i);
Block blk = start.clone().add(i).getBlock();
if(!blk.isEmpty() && !b.material.isOccluding())
{
continue;
}
blk.setTypeIdAndData(b.material.getId(), b.data, false);
}
}
public static Schematic load(File f) throws IOException
{
L.i("Loading Schematic: " + f.getPath());
Schematic s = new Schematic(1, 1, 1, 1, 1, 1);
FileInputStream fin = new FileInputStream(f);
s.read(fin);
return s;
}
}

View File

@@ -0,0 +1,48 @@
package ninja.bytecode.iris.util;
import java.util.Random;
import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.generator.BlockPopulator;
import ninja.bytecode.shuriken.math.M;
public abstract class ChancedPopulator extends BlockPopulator
{
private final double chance;
public ChancedPopulator(double chance)
{
this.chance = chance;
}
@Override
public void populate(World world, Random random, Chunk source)
{
if(chance == 0)
{
return;
}
if(chance > 0 && chance < 1 && M.r(chance))
{
doPopulate(world, random, source, (source.getX() << 4) + random.nextInt(16), (source.getZ() << 4) + random.nextInt(16));
}
if(chance > 1)
{
for(int i = 0; i < (int) chance; i++)
{
doPopulate(world, random, source, (source.getX() << 4) + random.nextInt(16), (source.getZ() << 4) + random.nextInt(16));
}
if(M.r(chance - ((int) chance)))
{
doPopulate(world, random, source, (source.getX() << 4) + random.nextInt(16), (source.getZ() << 4) + random.nextInt(16));
}
}
}
public abstract void doPopulate(World world, Random random, Chunk source, int x, int z);
}

View File

@@ -2,18 +2,28 @@ package ninja.bytecode.iris.util;
import java.util.function.Supplier;
import org.bukkit.util.BlockVector;
import ninja.bytecode.iris.generator.biome.IrisBiome;
import ninja.bytecode.iris.schematic.Schematic;
import ninja.bytecode.shuriken.collections.GMap;
public class ChunkPlan
{
private final GMap<ChunkedVector, Double> heightCache;
private final GMap<ChunkedVector, IrisBiome> biomeCache;
private final GMap<BlockVector, Schematic> schematics;
public ChunkPlan()
{
this.heightCache = new GMap<ChunkedVector, Double>();
this.biomeCache = new GMap<ChunkedVector, IrisBiome>();
this.schematics = new GMap<>();
this.heightCache = new GMap<>();
this.biomeCache = new GMap<>();
}
public void planSchematic(BlockVector b, Schematic s)
{
schematics.put(b, s);
}
public IrisBiome getBiome(int x, int z)

View File

@@ -0,0 +1,910 @@
package ninja.bytecode.iris.util;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.material.MaterialData;
import ninja.bytecode.shuriken.collections.GList;
/**
* Cuboids
*
* @author cyberpwn
*/
public class Cuboid implements Iterable<Block>, Cloneable, ConfigurationSerializable
{
protected final String worldName;
protected int x1, y1, z1;
protected int x2, y2, z2;
/**
* Construct a Cuboid given two Location objects which represent any two corners
* of the Cuboid.
*
* @param l1
* one of the corners
* @param l2
* the other corner
*/
public Cuboid(Location l1, Location l2)
{
if(!l1.getWorld().equals(l2.getWorld()))
{
throw new IllegalArgumentException("locations must be on the same world");
}
worldName = l1.getWorld().getName();
x1 = Math.min(l1.getBlockX(), l2.getBlockX());
y1 = Math.min(l1.getBlockY(), l2.getBlockY());
z1 = Math.min(l1.getBlockZ(), l2.getBlockZ());
x2 = Math.max(l1.getBlockX(), l2.getBlockX());
y2 = Math.max(l1.getBlockY(), l2.getBlockY());
z2 = Math.max(l1.getBlockZ(), l2.getBlockZ());
}
public GList<LivingEntity> getLivingEntities()
{
return new GList<LivingEntity>(new GListAdapter<Entity, LivingEntity>()
{
@Override
public LivingEntity onAdapt(Entity from)
{
if(from instanceof LivingEntity)
{
return (LivingEntity) from;
}
return null;
}
}.adapt(getEntities()));
}
public GList<Entity> getEntities()
{
GList<Entity> en = new GList<Entity>();
for(Chunk i : getChunks())
{
for(Entity j : i.getEntities())
{
if(contains(j.getLocation()))
{
en.add(j);
}
}
}
return en;
}
/**
* Set the locations
*
* @param l1
* a
* @param l2
* b
*/
public void set(Location l1, Location l2)
{
x1 = Math.min(l1.getBlockX(), l2.getBlockX());
y1 = Math.min(l1.getBlockY(), l2.getBlockY());
z1 = Math.min(l1.getBlockZ(), l2.getBlockZ());
x2 = Math.max(l1.getBlockX(), l2.getBlockX());
y2 = Math.max(l1.getBlockY(), l2.getBlockY());
z2 = Math.max(l1.getBlockZ(), l2.getBlockZ());
}
/**
* Construct a one-block Cuboid at the given Location of the Cuboid.
*
* @param l1
* location of the Cuboid
*/
public Cuboid(Location l1)
{
this(l1, l1);
}
/**
* Copy constructor.
*
* @param other
* the Cuboid to copy
*/
public Cuboid(Cuboid other)
{
this(other.getWorld().getName(), other.x1, other.y1, other.z1, other.x2, other.y2, other.z2);
}
/**
* Construct a Cuboid in the given World and xyz co-ordinates
*
* @param world
* the Cuboid's world
* @param x1
* X co-ordinate of corner 1
* @param y1
* Y co-ordinate of corner 1
* @param z1
* Z co-ordinate of corner 1
* @param x2
* X co-ordinate of corner 2
* @param y2
* Y co-ordinate of corner 2
* @param z2
* Z co-ordinate of corner 2
*/
public Cuboid(World world, int x1, int y1, int z1, int x2, int y2, int z2)
{
this.worldName = world.getName();
this.x1 = Math.min(x1, x2);
this.x2 = Math.max(x1, x2);
this.y1 = Math.min(y1, y2);
this.y2 = Math.max(y1, y2);
this.z1 = Math.min(z1, z2);
this.z2 = Math.max(z1, z2);
}
/**
* Construct a Cuboid in the given world name and xyz co-ordinates.
*
* @param worldName
* the Cuboid's world name
* @param x1
* X co-ordinate of corner 1
* @param y1
* Y co-ordinate of corner 1
* @param z1
* Z co-ordinate of corner 1
* @param x2
* X co-ordinate of corner 2
* @param y2
* Y co-ordinate of corner 2
* @param z2
* Z co-ordinate of corner 2
*/
private Cuboid(String worldName, int x1, int y1, int z1, int x2, int y2, int z2)
{
this.worldName = worldName;
this.x1 = Math.min(x1, x2);
this.x2 = Math.max(x1, x2);
this.y1 = Math.min(y1, y2);
this.y2 = Math.max(y1, y2);
this.z1 = Math.min(z1, z2);
this.z2 = Math.max(z1, z2);
}
public Cuboid(Map<String, Object> map)
{
worldName = (String) map.get("worldName");
x1 = (Integer) map.get("x1");
x2 = (Integer) map.get("x2");
y1 = (Integer) map.get("y1");
y2 = (Integer) map.get("y2");
z1 = (Integer) map.get("z1");
z2 = (Integer) map.get("z2");
}
@Override
public Map<String, Object> serialize()
{
Map<String, Object> map = new HashMap<String, Object>();
map.put("worldName", worldName);
map.put("x1", x1);
map.put("y1", y1);
map.put("z1", z1);
map.put("x2", x2);
map.put("y2", y2);
map.put("z2", z2);
return map;
}
public Cuboid flatten(int level)
{
return new Cuboid(getWorld(), x1, level, z1, x2, level, z2);
}
/**
* Get the Location of the lower northeast corner of the Cuboid (minimum XYZ
* co-ordinates).
*
* @return Location of the lower northeast corner
*/
public Location getLowerNE()
{
return new Location(getWorld(), x1, y1, z1);
}
/**
* Get the Location of the upper southwest corner of the Cuboid (maximum XYZ
* co-ordinates).
*
* @return Location of the upper southwest corner
*/
public Location getUpperSW()
{
return new Location(getWorld(), x2, y2, z2);
}
/**
* Get the the centre of the Cuboid
*
* @return Location at the centre of the Cuboid
*/
public Location getCenter()
{
int x1 = getUpperX() + 1;
int y1 = getUpperY() + 1;
int z1 = getUpperZ() + 1;
return new Location(getWorld(), getLowerX() + (x1 - getLowerX()) / 2.0, getLowerY() + (y1 - getLowerY()) / 2.0, getLowerZ() + (z1 - getLowerZ()) / 2.0);
}
/**
* Get the Cuboid's world.
*
* @return the World object representing this Cuboid's world
* @throws IllegalStateException
* if the world is not loaded
*/
public World getWorld()
{
World world = Bukkit.getWorld(worldName);
if(world == null)
{
throw new IllegalStateException("world '" + worldName + "' is not loaded");
}
return world;
}
/**
* Get the size of this Cuboid along the X axis
*
* @return Size of Cuboid along the X axis
*/
public int getSizeX()
{
return (x2 - x1) + 1;
}
/**
* Get the size of this Cuboid along the Y axis
*
* @return Size of Cuboid along the Y axis
*/
public int getSizeY()
{
return (y2 - y1) + 1;
}
/**
* Get the size of this Cuboid along the Z axis
*
* @return Size of Cuboid along the Z axis
*/
public int getSizeZ()
{
return (z2 - z1) + 1;
}
/**
* Get the cuboid dimensions
*
* @return the dimensions
*/
public Dimension getDimension()
{
return new Dimension(getSizeX(), getSizeY(), getSizeZ());
}
/**
* Get the minimum X co-ordinate of this Cuboid
*
* @return the minimum X co-ordinate
*/
public int getLowerX()
{
return x1;
}
/**
* Get the minimum Y co-ordinate of this Cuboid
*
* @return the minimum Y co-ordinate
*/
public int getLowerY()
{
return y1;
}
/**
* Get the minimum Z co-ordinate of this Cuboid
*
* @return the minimum Z co-ordinate
*/
public int getLowerZ()
{
return z1;
}
/**
* Get the maximum X co-ordinate of this Cuboid
*
* @return the maximum X co-ordinate
*/
public int getUpperX()
{
return x2;
}
/**
* Get the maximum Y co-ordinate of this Cuboid
*
* @return the maximum Y co-ordinate
*/
public int getUpperY()
{
return y2;
}
/**
* Get the maximum Z co-ordinate of this Cuboid
*
* @return the maximum Z co-ordinate
*/
public int getUpperZ()
{
return z2;
}
/**
* Get the Blocks at the eight corners of the Cuboid.
*
* @return array of Block objects representing the Cuboid corners
*/
public Block[] corners()
{
Block[] res = new Block[8];
World w = getWorld();
res[0] = w.getBlockAt(x1, y1, z1);
res[1] = w.getBlockAt(x1, y1, z2);
res[2] = w.getBlockAt(x1, y2, z1);
res[3] = w.getBlockAt(x1, y2, z2);
res[4] = w.getBlockAt(x2, y1, z1);
res[5] = w.getBlockAt(x2, y1, z2);
res[6] = w.getBlockAt(x2, y2, z1);
res[7] = w.getBlockAt(x2, y2, z2);
return res;
}
/**
* Expand the Cuboid in the given direction by the given amount. Negative
* amounts will shrink the Cuboid in the given direction. Shrinking a cuboid's
* face past the opposite face is not an error and will return a valid Cuboid.
*
* @param dir
* the direction in which to expand
* @param amount
* the number of blocks by which to expand
* @return a new Cuboid expanded by the given direction and amount
*/
public Cuboid expand(CuboidDirection dir, int amount)
{
switch(dir)
{
case North:
return new Cuboid(worldName, x1 - amount, y1, z1, x2, y2, z2);
case South:
return new Cuboid(worldName, x1, y1, z1, x2 + amount, y2, z2);
case East:
return new Cuboid(worldName, x1, y1, z1 - amount, x2, y2, z2);
case West:
return new Cuboid(worldName, x1, y1, z1, x2, y2, z2 + amount);
case Down:
return new Cuboid(worldName, x1, y1 - amount, z1, x2, y2, z2);
case Up:
return new Cuboid(worldName, x1, y1, z1, x2, y2 + amount, z2);
default:
throw new IllegalArgumentException("invalid direction " + dir);
}
}
/**
* Shift the Cuboid in the given direction by the given amount.
*
* @param dir
* the direction in which to shift
* @param amount
* the number of blocks by which to shift
* @return a new Cuboid shifted by the given direction and amount
*/
public Cuboid shift(CuboidDirection dir, int amount)
{
return expand(dir, amount).expand(dir.opposite(), -amount);
}
/**
* Outset (grow) the Cuboid in the given direction by the given amount.
*
* @param dir
* the direction in which to outset (must be Horizontal, Vertical, or
* Both)
* @param amount
* the number of blocks by which to outset
* @return a new Cuboid outset by the given direction and amount
*/
public Cuboid outset(CuboidDirection dir, int amount)
{
Cuboid c;
switch(dir)
{
case Horizontal:
c = expand(CuboidDirection.North, amount).expand(CuboidDirection.South, amount).expand(CuboidDirection.East, amount).expand(CuboidDirection.West, amount);
break;
case Vertical:
c = expand(CuboidDirection.Down, amount).expand(CuboidDirection.Up, amount);
break;
case Both:
c = outset(CuboidDirection.Horizontal, amount).outset(CuboidDirection.Vertical, amount);
break;
default:
throw new IllegalArgumentException("invalid direction " + dir);
}
return c;
}
/**
* Inset (shrink) the Cuboid in the given direction by the given amount.
* Equivalent to calling outset() with a negative amount.
*
* @param dir
* the direction in which to inset (must be Horizontal, Vertical, or
* Both)
* @param amount
* the number of blocks by which to inset
* @return a new Cuboid inset by the given direction and amount
*/
public Cuboid inset(CuboidDirection dir, int amount)
{
return outset(dir, -amount);
}
/**
* Return true if the point at (x,y,z) is contained within this Cuboid.
*
* @param x
* the X co-ordinate
* @param y
* the Y co-ordinate
* @param z
* the Z co-ordinate
* @return true if the given point is within this Cuboid, false otherwise
*/
public boolean contains(int x, int y, int z)
{
return x >= x1 && x <= x2 && y >= y1 && y <= y2 && z >= z1 && z <= z2;
}
/**
* Check if the given Block is contained within this Cuboid.
*
* @param b
* the Block to check for
* @return true if the Block is within this Cuboid, false otherwise
*/
public boolean contains(Block b)
{
return contains(b.getLocation());
}
/**
* Check if the given Location is contained within this Cuboid.
*
* @param l
* the Location to check for
* @return true if the Location is within this Cuboid, false otherwise
*/
public boolean contains(Location l)
{
return worldName.equals(l.getWorld().getName()) && contains(l.getBlockX(), l.getBlockY(), l.getBlockZ());
}
/**
* Get the volume of this Cuboid.
*
* @return the Cuboid volume, in blocks
*/
public int volume()
{
return getSizeX() * getSizeY() * getSizeZ();
}
/**
* Get the average light level of all empty (air) blocks in the Cuboid. Returns
* 0 if there are no empty blocks.
*
* @return the average light level of this Cuboid
*/
public byte averageLightLevel()
{
long total = 0;
int n = 0;
for(Block b : this)
{
if(b.isEmpty())
{
total += b.getLightLevel();
++n;
}
}
return n > 0 ? (byte) (total / n) : 0;
}
/**
* Contract the Cuboid, returning a Cuboid with any air around the edges
* removed, just large enough to include all non-air blocks.
*
* @return a new Cuboid with no external air blocks
*/
public Cuboid contract()
{
return this.contract(CuboidDirection.Down).contract(CuboidDirection.South).contract(CuboidDirection.East).contract(CuboidDirection.Up).contract(CuboidDirection.North).contract(CuboidDirection.West);
}
/**
* Contract the Cuboid in the given direction, returning a new Cuboid which has
* no exterior empty space. E.g. a direction of Down will push the top face
* downwards as much as possible.
*
* @param dir
* the direction in which to contract
* @return a new Cuboid contracted in the given direction
*/
public Cuboid contract(CuboidDirection dir)
{
Cuboid face = getFace(dir.opposite());
switch(dir)
{
case Down:
while(face.containsOnly(Material.AIR) && face.getLowerY() > this.getLowerY())
{
face = face.shift(CuboidDirection.Down, 1);
}
return new Cuboid(worldName, x1, y1, z1, x2, face.getUpperY(), z2);
case Up:
while(face.containsOnly(Material.AIR) && face.getUpperY() < this.getUpperY())
{
face = face.shift(CuboidDirection.Up, 1);
}
return new Cuboid(worldName, x1, face.getLowerY(), z1, x2, y2, z2);
case North:
while(face.containsOnly(Material.AIR) && face.getLowerX() > this.getLowerX())
{
face = face.shift(CuboidDirection.North, 1);
}
return new Cuboid(worldName, x1, y1, z1, face.getUpperX(), y2, z2);
case South:
while(face.containsOnly(Material.AIR) && face.getUpperX() < this.getUpperX())
{
face = face.shift(CuboidDirection.South, 1);
}
return new Cuboid(worldName, face.getLowerX(), y1, z1, x2, y2, z2);
case East:
while(face.containsOnly(Material.AIR) && face.getLowerZ() > this.getLowerZ())
{
face = face.shift(CuboidDirection.East, 1);
}
return new Cuboid(worldName, x1, y1, z1, x2, y2, face.getUpperZ());
case West:
while(face.containsOnly(Material.AIR) && face.getUpperZ() < this.getUpperZ())
{
face = face.shift(CuboidDirection.West, 1);
}
return new Cuboid(worldName, x1, y1, face.getLowerZ(), x2, y2, z2);
default:
throw new IllegalArgumentException("Invalid direction " + dir);
}
}
/**
* Get the Cuboid representing the face of this Cuboid. The resulting Cuboid
* will be one block thick in the axis perpendicular to the requested face.
*
* @param dir
* which face of the Cuboid to get
* @return the Cuboid representing this Cuboid's requested face
*/
public Cuboid getFace(CuboidDirection dir)
{
switch(dir)
{
case Down:
return new Cuboid(worldName, x1, y1, z1, x2, y1, z2);
case Up:
return new Cuboid(worldName, x1, y2, z1, x2, y2, z2);
case North:
return new Cuboid(worldName, x1, y1, z1, x1, y2, z2);
case South:
return new Cuboid(worldName, x2, y1, z1, x2, y2, z2);
case East:
return new Cuboid(worldName, x1, y1, z1, x2, y2, z1);
case West:
return new Cuboid(worldName, x1, y1, z2, x2, y2, z2);
default:
throw new IllegalArgumentException("Invalid direction " + dir);
}
}
/**
* Check if the Cuboid contains only blocks of the given type
*
* @param material
* the material to check for
* @return true if this Cuboid contains only blocks of the given type
*/
public boolean containsOnly(Material material)
{
for(Block b : this)
{
if(b.getType() != material)
{
return false;
}
}
return true;
}
/**
* Get the Cuboid big enough to hold both this Cuboid and the given one.
*
* @param other
* the other Cuboid to include
* @return a new Cuboid large enough to hold this Cuboid and the given Cuboid
*/
public Cuboid getBoundingCuboid(Cuboid other)
{
if(other == null)
{
return this;
}
int xMin = Math.min(getLowerX(), other.getLowerX());
int yMin = Math.min(getLowerY(), other.getLowerY());
int zMin = Math.min(getLowerZ(), other.getLowerZ());
int xMax = Math.max(getUpperX(), other.getUpperX());
int yMax = Math.max(getUpperY(), other.getUpperY());
int zMax = Math.max(getUpperZ(), other.getUpperZ());
return new Cuboid(worldName, xMin, yMin, zMin, xMax, yMax, zMax);
}
/**
* Get a block relative to the lower NE point of the Cuboid.
*
* @param x
* the X co-ordinate
* @param y
* the Y co-ordinate
* @param z
* the Z co-ordinate
* @return the block at the given position
*/
public Block getRelativeBlock(int x, int y, int z)
{
return getWorld().getBlockAt(x1 + x, y1 + y, z1 + z);
}
/**
* Get a block relative to the lower NE point of the Cuboid in the given World.
* This version of getRelativeBlock() should be used if being called many times,
* to avoid excessive calls to getWorld().
*
* @param w
* the World
* @param x
* the X co-ordinate
* @param y
* the Y co-ordinate
* @param z
* the Z co-ordinate
* @return the block at the given position
*/
public Block getRelativeBlock(World w, int x, int y, int z)
{
return w.getBlockAt(x1 + x, y1 + y, z1 + z);
}
/**
* Get a list of the chunks which are fully or partially contained in this
* cuboid.
*
* @return a list of Chunk objects
*/
public List<Chunk> getChunks()
{
List<Chunk> res = new ArrayList<Chunk>();
World w = getWorld();
int x1 = getLowerX() & ~0xf;
int x2 = getUpperX() & ~0xf;
int z1 = getLowerZ() & ~0xf;
int z2 = getUpperZ() & ~0xf;
for(int x = x1; x <= x2; x += 16)
{
for(int z = z1; z <= z2; z += 16)
{
res.add(w.getChunkAt(x >> 4, z >> 4));
}
}
return res;
}
/**
* Set all the blocks within the Cuboid to the given block ID and data byte.
*
* @param blockId
* the block ID
* @param data
* the block data
* @deprecated use {@link #fill(MaterialData, MassBlockUpdate)}
*/
@Deprecated
public void fill(int blockId, byte data)
{
for(Block b : this)
{
b.setTypeIdAndData(blockId, data, false);
}
}
/**
* Set all the blocks within the Cuboid to the given MaterialData, using a
* MassBlockUpdate object for fast updates.
*
* @param mat
* the MaterialData to set
* @param mbu
* the MassBlockUpdate object
*/
/**
* Reset the light level of all blocks within this Cuboid.
*/
/*
* (non-Javadoc)
*
* @see java.lang.Iterable#iterator()
*/
@Override
public Iterator<Block> iterator()
{
return new CuboidIterator(getWorld(), x1, y1, z1, x2, y2, z2);
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#clone()
*/
@Override
public Cuboid clone() throws CloneNotSupportedException
{
return new Cuboid(this);
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString()
{
return "Cuboid: " + worldName + "," + x1 + "," + y1 + "," + z1 + "=>" + x2 + "," + y2 + "," + z2;
}
public class CuboidIterator implements Iterator<Block>
{
private World w;
private int baseX, baseY, baseZ;
private int x, y, z;
private int sizeX, sizeY, sizeZ;
public CuboidIterator(World w, int x1, int y1, int z1, int x2, int y2, int z2)
{
this.w = w;
baseX = x1;
baseY = y1;
baseZ = z1;
sizeX = Math.abs(x2 - x1) + 1;
sizeY = Math.abs(y2 - y1) + 1;
sizeZ = Math.abs(z2 - z1) + 1;
x = y = z = 0;
}
@Override
public boolean hasNext()
{
return x < sizeX && y < sizeY && z < sizeZ;
}
@Override
public Block next()
{
Block b = w.getBlockAt(baseX + x, baseY + y, baseZ + z);
if(++x >= sizeX)
{
x = 0;
if(++y >= sizeY)
{
y = 0;
++z;
}
}
return b;
}
@Override
public void remove()
{
// nop
}
}
public enum CuboidDirection
{
North,
East,
South,
West,
Up,
Down,
Horizontal,
Vertical,
Both,
Unknown;
public CuboidDirection opposite()
{
switch(this)
{
case North:
return South;
case East:
return West;
case South:
return North;
case West:
return East;
case Horizontal:
return Vertical;
case Vertical:
return Horizontal;
case Up:
return Down;
case Down:
return Up;
case Both:
return Both;
default:
return Unknown;
}
}
}
}

View File

@@ -0,0 +1,16 @@
package ninja.bytecode.iris.util;
/**
* Represents a cuboid exception
*
* @author cyberpwn
*/
public class CuboidException extends Exception
{
public CuboidException(String string)
{
super(string);
}
private static final long serialVersionUID = 1L;
}

View File

@@ -0,0 +1,86 @@
package ninja.bytecode.iris.util;
/**
* Dimensions
*
* @author cyberpwn
*/
public class Dimension
{
private final int width;
private final int height;
private final int depth;
/**
* Make a dimension
*
* @param width
* width of this (X)
* @param height
* the height (Y)
* @param depth
* the depth (Z)
*/
public Dimension(int width, int height, int depth)
{
this.width = width;
this.height = height;
this.depth = depth;
}
/**
* Make a dimension
*
* @param width
* width of this (X)
* @param height
* the height (Y)
*/
public Dimension(int width, int height)
{
this.width = width;
this.height = height;
this.depth = 0;
}
/**
* Get the direction of the flat part of this dimension (null if no thin
* face)
*
* @return the direction of the flat pane or null
*/
public DimensionFace getPane()
{
if(width == 1)
{
return DimensionFace.X;
}
if(height == 1)
{
return DimensionFace.Y;
}
if(depth == 1)
{
return DimensionFace.Z;
}
return null;
}
public int getWidth()
{
return width;
}
public int getHeight()
{
return height;
}
public int getDepth()
{
return depth;
}
}

View File

@@ -0,0 +1,24 @@
package ninja.bytecode.iris.util;
/**
* Represents a dimension (coordinates not worlds)
*
* @author cyberpwn
*/
public enum DimensionFace
{
/**
* The X dimension (width)
*/
X,
/**
* The Y dimension (height)
*/
Y,
/**
* The Z dimension (depth)
*/
Z
}

View File

@@ -0,0 +1,137 @@
package ninja.bytecode.iris.util;
import ninja.bytecode.iris.util.Cuboid.CuboidDirection;
import ninja.bytecode.shuriken.collections.GList;
/**
* Directions
*
* @author cyberpwn
*/
public enum Direction
{
U(0, 1, 0, CuboidDirection.Up),
D(0, -1, 0, CuboidDirection.Down),
N(0, 0, -1, CuboidDirection.North),
S(0, 0, 1, CuboidDirection.South),
E(1, 0, 0, CuboidDirection.East),
W(-1, 0, 0, CuboidDirection.West);
private int x;
private int y;
private int z;
private CuboidDirection f;
private Direction(int x, int y, int z, CuboidDirection f)
{
this.x = x;
this.y = y;
this.z = z;
this.f = f;
}
public int x()
{
return x;
}
public int y()
{
return y;
}
public int z()
{
return z;
}
public CuboidDirection f()
{
return f;
}
public static GList<Direction> news()
{
return new GList<Direction>().add(N, E, W, S);
}
public static GList<Direction> udnews()
{
return new GList<Direction>().add(U, D, N, E, W, S);
}
/**
* Get the directional value from the given byte from common directional blocks
* (MUST BE BETWEEN 0 and 5 INCLUSIVE)
*
* @param b
* the byte
* @return the direction or null if the byte is outside of the inclusive range
* 0-5
*/
public static Direction fromByte(byte b)
{
if(b > 5 || b < 0)
{
return null;
}
if(b == 0)
{
return D;
}
else if(b == 1)
{
return U;
}
else if(b == 2)
{
return N;
}
else if(b == 3)
{
return S;
}
else if(b == 4)
{
return W;
}
else
{
return E;
}
}
/**
* Get the byte value represented in some directional blocks
*
* @return the byte value
*/
public byte byteValue()
{
switch(this)
{
case D:
return 0;
case E:
return 5;
case N:
return 2;
case S:
return 3;
case U:
return 1;
case W:
return 4;
default:
break;
}
return -1;
}
}

View File

@@ -0,0 +1,51 @@
package ninja.bytecode.iris.util;
import java.util.List;
import ninja.bytecode.shuriken.collections.GList;
/**
* Adapts a list of objects into a list of other objects
*
* @author cyberpwn
* @param <FROM>
* the from object in lists (the item INSIDE the list)
* @param <TO>
* the to object in lists (the item INSIDE the list)
*/
public abstract class GListAdapter<FROM, TO>
{
/**
* Adapts a list of FROM to a list of TO
*
* @param from
* the from list
* @return the to list
*/
public List<TO> adapt(List<FROM> from)
{
List<TO> adapted = new GList<TO>();
for(FROM i : from)
{
TO t = onAdapt(i);
if(t != null)
{
adapted.add(onAdapt(i));
}
}
return adapted;
}
/**
* Adapts a list object FROM to TO for use with the adapt method
*
* @param from
* the from object
* @return the to object
*/
public abstract TO onAdapt(FROM from);
}

View File

@@ -2,21 +2,16 @@ package ninja.bytecode.iris.util;
import java.util.Random;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.generator.ChunkGenerator;
import ninja.bytecode.iris.Iris;
import ninja.bytecode.iris.generator.populator.PopulatorTrees;
import ninja.bytecode.shuriken.Shuriken;
import ninja.bytecode.shuriken.execution.ChronoLatch;
import ninja.bytecode.shuriken.execution.J;
import ninja.bytecode.shuriken.execution.TaskExecutor.TaskGroup;
import ninja.bytecode.shuriken.execution.TaskExecutor.TaskResult;
import ninja.bytecode.shuriken.format.F;
import ninja.bytecode.shuriken.logging.L;
import ninja.bytecode.shuriken.math.RollingSequence;
import ninja.bytecode.shuriken.reaction.O;
@@ -31,42 +26,12 @@ public abstract class ParallelChunkGenerator extends ChunkGenerator
private boolean ready = false;
int cg = 0;
private ChronoLatch cl = new ChronoLatch(1000);
private ChronoLatch cs = new ChronoLatch(1000);
private RollingSequence rs = new RollingSequence(512);
private RollingSequence cps = new RollingSequence(3);
private World world;
@SuppressWarnings("deprecation")
public ParallelChunkGenerator()
public World getWorld()
{
Bukkit.getScheduler().scheduleAsyncRepeatingTask(Iris.instance, () ->
{
J.attempt(() ->
{
if(world.getPlayers().isEmpty())
{
return;
}
if(cs.flip())
{
cps.put(cg);
cg = 0;
}
double total = rs.getAverage() + PopulatorTrees.timings.getAverage();
double rcs = (1000D / total);
double work = cps.getAverage() / (rcs + 1);
L.i("Terrain Gen for " + world.getName());
L.i("- Terrain (MLTC): " + F.duration(rs.getAverage(), 2));
L.i("- Trees (SGLC): " + F.duration(PopulatorTrees.timings.getAverage(), 2));
L.i("Total: " + F.duration(total, 3) + " Work: " + F.f(cps.getAverage(), 0) + "/s of " + F.f(rcs, 0) + "/s (" + F.pc(work, 0) + " utilization)");
L.flush();
System.out.println("");
});
}, 20, 5);
return world;
}
public void generateFullColumn(int a, int b, int c, int d, BiomeGrid g, ChunkPlan p)
@@ -144,33 +109,33 @@ public abstract class ParallelChunkGenerator extends ChunkGenerator
public abstract void decorateColumn(int wx, int wz, int x, int z, ChunkPlan plan);
@SuppressWarnings("deprecation")
protected void setBlock(int x, int y, int z, Material b)
public void setBlock(int x, int y, int z, Material b)
{
setBlock(x, y, z, b.getId(), (byte) 0);
}
@SuppressWarnings("deprecation")
protected void setBlock(int x, int y, int z, Material b, byte d)
public void setBlock(int x, int y, int z, Material b, byte d)
{
setBlock(x, y, z, b.getId(), d);
}
protected void setBlock(int x, int y, int z, int b)
public void setBlock(int x, int y, int z, int b)
{
setBlock(x, y, z, b, (byte) 0);
}
protected void setBlock(int x, int y, int z, int b, byte d)
public void setBlock(int x, int y, int z, int b, byte d)
{
data.setBlock(x, y, z, b, d);
}
protected Material getType(int x, int y, int z)
public Material getType(int x, int y, int z)
{
return data.getType(x, y, z);
}
protected byte getData(int x, int y, int z)
public byte getData(int x, int y, int z)
{
return data.getData(x, y, z);
}

View File

@@ -0,0 +1,157 @@
package ninja.bytecode.iris.util;
import java.util.Iterator;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.util.BlockVector;
import org.bukkit.util.Vector;
import ninja.bytecode.iris.schematic.Schematic;
import ninja.bytecode.shuriken.collections.GList;
public class WandUtil
{
@SuppressWarnings("deprecation")
public static void pasteSchematic(Schematic s, Location at)
{
Location start = at.clone().add(s.getOffset());
for(BlockVector i : s.getSchematic().keySet())
{
MB b = s.getSchematic().get(i);
System.out.println("Pasted " + b.material + " @ " + start.clone().add(i));
start.clone().add(i).getBlock().setTypeIdAndData(b.material.getId(), b.data, false);
}
}
@SuppressWarnings("deprecation")
public static Schematic createSchematic(ItemStack wand, Location at)
{
if(!isWand(wand))
{
return null;
}
try
{
Location[] f = getCuboid(wand);
Cuboid c = new Cuboid(f[0], f[1]);
Vector v = at.clone().subtract(c.getLowerNE()).toVector();
Schematic s = new Schematic(c.getSizeX(), c.getSizeY(), c.getSizeZ(), v.getBlockX(), v.getBlockY(), v.getBlockZ());
Iterator<Block> bb = c.iterator();
while(bb.hasNext())
{
Block b = bb.next();
if(b.getType().equals(Material.AIR))
{
continue;
}
BlockVector bv = b.getLocation().toVector().toBlockVector().subtract(c.getLowerNE().toVector().toBlockVector()).toBlockVector();
System.out.println("Load " + bv + " " + b.getType());
s.put(bv.getBlockX(), bv.getBlockY(), bv.getBlockZ(), new MB(b.getType(), b.getData()));
}
return s;
}
catch(Throwable e)
{
e.printStackTrace();
}
return null;
}
public static Location stringToLocation(String s)
{
try
{
String[] f = s.split("\\Q in \\E");
String[] g = f[0].split("\\Q,\\E");
return new Location(Bukkit.getWorld(f[1]), Integer.valueOf(g[0]), Integer.valueOf(g[1]), Integer.valueOf(g[2]));
}
catch(Throwable e)
{
return null;
}
}
public static String locationToString(Location s)
{
if(s == null)
{
return "<#>";
}
return s.getBlockX() + "," + s.getBlockY() + "," + s.getBlockZ() + " in " + s.getWorld().getName();
}
public static ItemStack createWand()
{
return createWand(null, null);
}
public static ItemStack update(boolean left, Location a, ItemStack item)
{
if(!isWand(item))
{
return item;
}
Location[] f = getCuboid(item);
Location other = left ? f[1] : f[0];
return createWand(left ? a : other, left ? other : a);
}
public static ItemStack createWand(Location a, Location b)
{
ItemStack is = new ItemStack(Material.BLAZE_ROD);
is.addUnsafeEnchantment(Enchantment.ARROW_INFINITE, 1);
ItemMeta im = is.getItemMeta();
im.setDisplayName(ChatColor.BOLD + "" + ChatColor.GOLD + "Wand of Iris");
im.setUnbreakable(true);
im.addItemFlags(ItemFlag.HIDE_ATTRIBUTES, ItemFlag.HIDE_PLACED_ON, ItemFlag.HIDE_POTION_EFFECTS, ItemFlag.HIDE_DESTROYS, ItemFlag.HIDE_ENCHANTS);
im.setLore(new GList<String>().add(locationToString(a), locationToString(b)));
is.setItemMeta(im);
return is;
}
public static Location[] getCuboid(ItemStack is)
{
ItemMeta im = is.getItemMeta();
return new Location[] {stringToLocation(im.getLore().get(0)), stringToLocation(im.getLore().get(1))};
}
public static boolean isWand(ItemStack item)
{
if(!item.getType().equals(createWand().getType()))
{
return false;
}
if(!item.getItemMeta().getEnchants().equals(createWand().getItemMeta().getEnchants()))
{
return false;
}
if(!item.getItemMeta().getDisplayName().equals(createWand().getItemMeta().getDisplayName()))
{
return false;
}
return true;
}
}