Generators

This commit is contained in:
Daniel Mills 2020-05-16 04:41:45 -04:00
parent 89b236ae9e
commit e491401ca0
12 changed files with 467 additions and 76 deletions

View File

@ -12,6 +12,7 @@ import org.bukkit.ChatColor;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.World;
import org.bukkit.WorldCreator;
import org.bukkit.command.Command;
@ -22,6 +23,7 @@ import org.bukkit.generator.ChunkGenerator;
import org.bukkit.inventory.ItemStack;
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.object.IrisBiome;
@ -32,6 +34,9 @@ import ninja.bytecode.iris.util.BoardManager;
import ninja.bytecode.iris.util.BoardProvider;
import ninja.bytecode.iris.util.BoardSettings;
import ninja.bytecode.iris.util.CNG;
import ninja.bytecode.iris.util.Cuboid;
import ninja.bytecode.iris.util.Cuboid.CuboidDirection;
import ninja.bytecode.iris.util.Direction;
import ninja.bytecode.iris.util.GroupedExecutor;
import ninja.bytecode.iris.util.IO;
import ninja.bytecode.iris.util.ScoreDirection;
@ -127,6 +132,7 @@ public class Iris extends JavaPlugin implements BoardProvider
HandlerList.unregisterAll((Plugin) this);
}
@SuppressWarnings("deprecation")
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args)
{
@ -134,28 +140,241 @@ public class Iris extends JavaPlugin implements BoardProvider
{
if(args.length == 0)
{
imsg(sender, "/iris dev - Create a new dev world");
imsg(sender, "/iris wand - Get a wand");
imsg(sender, "/iris dev [dimension] - Create a new dev world");
imsg(sender, "/iris wand [?] - Get a wand / help");
imsg(sender, "/iris save <name> - Save object");
imsg(sender, "/iris load <name> - Load & place object");
}
if(args.length >= 1)
{
if(args[0].equalsIgnoreCase("wand"))
{
((Player) sender).getInventory().addItem(WandController.createWand());
}
if(args[0].equalsIgnoreCase("gui"))
{
try
if(args.length == 1)
{
((Player) sender).getInventory().addItem(WandController.createWand());
}
catch(Throwable e)
else if(args[1].equalsIgnoreCase("x+y"))
{
Player p = (Player) sender;
if(!WandController.isWand(p))
{
sender.sendMessage("Ready your Wand.");
return true;
}
Location[] b = WandController.getCuboid(p.getInventory().getItemInMainHand());
b[0].add(new Vector(0, 1, 0));
b[1].add(new Vector(0, 1, 0));
Location a1 = b[0].clone();
Location a2 = b[1].clone();
Cuboid cursor = new Cuboid(a1, a2);
while(!cursor.containsOnly(Material.AIR))
{
a1.add(new Vector(0, 1, 0));
a2.add(new Vector(0, 1, 0));
cursor = new Cuboid(a1, a2);
}
a1.add(new Vector(0, -1, 0));
a2.add(new Vector(0, -1, 0));
b[0] = a1;
a2 = b[1];
cursor = new Cuboid(a1, a2);
cursor = cursor.contract(CuboidDirection.North);
cursor = cursor.contract(CuboidDirection.South);
cursor = cursor.contract(CuboidDirection.East);
cursor = cursor.contract(CuboidDirection.West);
b[0] = cursor.getLowerNE();
b[1] = cursor.getUpperSW();
p.getInventory().setItemInMainHand(WandController.createWand(b[0], b[1]));
p.updateInventory();
p.playSound(p.getLocation(), Sound.ENTITY_ITEM_FRAME_ROTATE_ITEM, 1f, 0.55f);
}
else if(args[1].equalsIgnoreCase("x&y"))
{
Player p = (Player) sender;
if(!WandController.isWand(p))
{
sender.sendMessage("Ready your Wand.");
return true;
}
Location[] b = WandController.getCuboid(p.getInventory().getItemInMainHand());
Location a1 = b[0].clone();
Location a2 = b[1].clone();
Location a1x = b[0].clone();
Location a2x = b[1].clone();
Cuboid cursor = new Cuboid(a1, a2);
Cuboid cursorx = new Cuboid(a1, a2);
while(!cursor.containsOnly(Material.AIR))
{
a1.add(new Vector(0, 1, 0));
a2.add(new Vector(0, 1, 0));
cursor = new Cuboid(a1, a2);
}
a1.add(new Vector(0, -1, 0));
a2.add(new Vector(0, -1, 0));
while(!cursorx.containsOnly(Material.AIR))
{
a1x.add(new Vector(0, -1, 0));
a2x.add(new Vector(0, -1, 0));
cursorx = new Cuboid(a1x, a2x);
}
a1x.add(new Vector(0, 1, 0));
a2x.add(new Vector(0, 1, 0));
b[0] = a1;
b[1] = a2x;
cursor = new Cuboid(b[0], b[1]);
cursor = cursor.contract(CuboidDirection.North);
cursor = cursor.contract(CuboidDirection.South);
cursor = cursor.contract(CuboidDirection.East);
cursor = cursor.contract(CuboidDirection.West);
b[0] = cursor.getLowerNE();
b[1] = cursor.getUpperSW();
p.getInventory().setItemInMainHand(WandController.createWand(b[0], b[1]));
p.updateInventory();
p.playSound(p.getLocation(), Sound.ENTITY_ITEM_FRAME_ROTATE_ITEM, 1f, 0.55f);
}
else if(args[1].equalsIgnoreCase(">") && args.length > 2)
{
Player p = (Player) sender;
if(!WandController.isWand(p))
{
sender.sendMessage("Ready your Wand.");
return true;
}
int amt = Integer.valueOf(args[2]);
Location[] b = WandController.getCuboid(p.getInventory().getItemInMainHand());
Location a1 = b[0].clone();
Location a2 = b[1].clone();
Direction d = Direction.closest(p.getLocation().getDirection()).reverse();
a1.add(d.toVector().multiply(amt));
a2.add(d.toVector().multiply(amt));
Cuboid cursor = new Cuboid(a1, a2);
b[0] = cursor.getLowerNE();
b[1] = cursor.getUpperSW();
p.getInventory().setItemInMainHand(WandController.createWand(b[0], b[1]));
p.updateInventory();
p.playSound(p.getLocation(), Sound.ENTITY_ITEM_FRAME_ROTATE_ITEM, 1f, 0.55f);
}
else if(args[1].equalsIgnoreCase("+") && args.length > 2)
{
Player p = (Player) sender;
if(!WandController.isWand(p))
{
sender.sendMessage("Ready your Wand.");
return true;
}
int amt = Integer.valueOf(args[2]);
Location[] b = WandController.getCuboid(p.getInventory().getItemInMainHand());
Location a1 = b[0].clone();
Location a2 = b[1].clone();
Cuboid cursor = new Cuboid(a1, a2);
Direction d = Direction.closest(p.getLocation().getDirection()).reverse();
cursor = cursor.expand(d, amt);
b[0] = cursor.getLowerNE();
b[1] = cursor.getUpperSW();
p.getInventory().setItemInMainHand(WandController.createWand(b[0], b[1]));
p.updateInventory();
p.playSound(p.getLocation(), Sound.ENTITY_ITEM_FRAME_ROTATE_ITEM, 1f, 0.55f);
}
else if(args[1].equalsIgnoreCase("-") && args.length > 2)
{
Player p = (Player) sender;
if(!WandController.isWand(p))
{
sender.sendMessage("Ready your Wand.");
return true;
}
int amt = Integer.valueOf(args[2]);
Location[] b = WandController.getCuboid(p.getInventory().getItemInMainHand());
Location a1 = b[0].clone();
Location a2 = b[1].clone();
Cuboid cursor = new Cuboid(a1, a2);
Direction d = Direction.closest(p.getLocation().getDirection()).reverse();
cursor = cursor.expand(d, -amt);
b[0] = cursor.getLowerNE();
b[1] = cursor.getUpperSW();
p.getInventory().setItemInMainHand(WandController.createWand(b[0], b[1]));
p.updateInventory();
p.playSound(p.getLocation(), Sound.ENTITY_ITEM_FRAME_ROTATE_ITEM, 1f, 0.55f);
}
else if(args[1].equalsIgnoreCase("p1"))
{
ItemStack wand = ((Player) sender).getInventory().getItemInMainHand();
if(WandController.isWand(wand))
{
Location[] g = WandController.getCuboid(wand);
g[0] = ((Player) sender).getLocation().getBlock().getLocation().clone().add(0, -1, 0);
((Player) sender).setItemInHand(WandController.createWand(g[0], g[1]));
}
}
else if(args[1].equalsIgnoreCase("p2"))
{
ItemStack wand = ((Player) sender).getInventory().getItemInMainHand();
if(WandController.isWand(wand))
{
Location[] g = WandController.getCuboid(wand);
g[1] = ((Player) sender).getLocation().getBlock().getLocation().clone().add(0, -1, 0);
((Player) sender).setItemInHand(WandController.createWand(g[0], g[1]));
}
}
else if(args[1].equalsIgnoreCase("l1"))
{
ItemStack wand = ((Player) sender).getInventory().getItemInMainHand();
if(WandController.isWand(wand))
{
Location[] g = WandController.getCuboid(wand);
g[0] = ((Player) sender).getTargetBlock((Set<Material>) null, 256).getLocation().clone();
((Player) sender).setItemInHand(WandController.createWand(g[0], g[1]));
}
}
else if(args[1].equalsIgnoreCase("l2"))
{
ItemStack wand = ((Player) sender).getInventory().getItemInMainHand();
if(WandController.isWand(wand))
{
Location[] g = WandController.getCuboid(wand);
g[1] = ((Player) sender).getTargetBlock((Set<Material>) null, 256).getLocation().clone();
((Player) sender).setItemInHand(WandController.createWand(g[0], g[1]));
}
}
else
{
imsg(sender, "/iris wand x+y - Expand up and out");
imsg(sender, "/iris wand x&y - Expand up and down and out");
imsg(sender, "/iris wand > <amt> - Shift in looking direction");
imsg(sender, "/iris wand + <amt> - Expand in looking direction");
imsg(sender, "/iris wand - <amt> - Contract in looking direction");
imsg(sender, "/iris wand p1 - Set wand pos 1 where standing");
imsg(sender, "/iris wand p2 - Set wand pos 2 where standing");
imsg(sender, "/iris wand l1 - Set wand pos 1 where looking");
imsg(sender, "/iris wand l2 - Set wand pos 2 where looking");
}
}
if(args[0].equalsIgnoreCase("save") && args.length >= 2)
@ -223,7 +442,7 @@ public class Iris extends JavaPlugin implements BoardProvider
if(args[0].equalsIgnoreCase("dev"))
{
String dim = "Overworld";
String dim = "overworld";
if(args.length > 1)
{
@ -247,13 +466,20 @@ public class Iris extends JavaPlugin implements BoardProvider
}
}
IrisDimension d = data.getDimensionLoader().load(dimm);
if(d == null)
{
imsg(sender, "Can't find dimension: " + dimm);
return;
}
for(Player i : Bukkit.getOnlinePlayers())
{
imsg(i, "Creating Iris " + dimm + "...");
}
IrisGenerator gx = new IrisGenerator("overworld", 16);
IrisGenerator gx = new IrisGenerator(dimm, 16);
O<Boolean> done = new O<Boolean>();
done.set(false);

View File

@ -44,6 +44,17 @@ public abstract class BiomeChunkGenerator extends DimensionChunkGenerator
return glBiome.generateRegionData(wx, wz, region);
}
protected double interpolateAuxiliaryHeight(double rx, double rz)
{
return IrisInterpolation.getNoise(getDimension().getInterpolationAuxiliaryFunction(), (int) Math.round(rx), (int) Math.round(rz), getDimension().getInterpolationAuxiliaryScale(), (xx, zz) ->
{
double xv = xx / getDimension().getTerrainZoom();
double zv = zz / getDimension().getTerrainZoom();
BiomeResult neighborResult = glBiome.generateData(xv, zv);
return neighborResult.getBiome().getAuxiliaryHeight(xv, zv, getWorld().getSeed() * 3923);
});
}
protected double interpolateHeight(double rx, double rz, Function<IrisBiome, Double> property)
{
return IrisInterpolation.getNoise(getDimension().getInterpolationFunction(), (int) Math.round(rx), (int) Math.round(rz), getDimension().getInterpolationScale(), (xx, zz) ->

View File

@ -157,7 +157,7 @@ public abstract class ParallaxChunkGenerator extends TerrainChunkGenerator imple
getTx().queue(key, () ->
{
IrisBiome b = sampleBiome((i * 16) + 7, (j * 16) + 7).getBiome();
IrisBiome b = sampleTrueBiome((i * 16) + 7, (j * 16) + 7).getBiome();
int g = 1;
for(IrisObjectPlacement k : b.getObjects())

View File

@ -45,21 +45,9 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator
double wx = getZoomed(ox);
double wz = getZoomed(oz);
int depth = 0;
IrisRegion region = glBiome.getRegion(wx, wz);
BiomeResult biomeResult = glBiome.generateRegionData(wx, wz, region);
IrisBiome biome = biomeResult.getBiome();
double lo = interpolateHeight(ox, oz, (b) -> b.getLowHeight());
double hi = interpolateSurface(ox, oz, (b) -> b.getHighHeight());
double noise = lo + (terrainNoise.fitDoubleD(0, hi - lo, wx, wz));
double noise = getNoiseHeight(rx, rz);
int height = (int) Math.round(noise) + fluidHeight;
if(height < fluidHeight + 1)
{
if(biome.isLand())
{
biome = glBiome.generateShoreData(wx, wz, region).getBiome();
}
}
IrisBiome biome = sampleTrueBiome(rx, rz).getBiome();
KList<BlockData> layers = biome.generateLayers(wx, wz, masterRandom, height);
@ -87,15 +75,64 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator
}
}
protected double getNoiseHeight(int rx, int rz)
{
double ox = getModifiedX(rx, rz);
double oz = getModifiedZ(rx, rz);
double wx = getZoomed(ox);
double wz = getZoomed(oz);
double lo = interpolateHeight(ox, oz, (b) -> b.getLowHeight());
double hi = interpolateSurface(ox, oz, (b) -> b.getHighHeight());
return lo + (terrainNoise.fitDoubleD(0, hi - lo, wx, wz)) + interpolateAuxiliaryHeight(rx, rz);
}
public BiomeResult sampleTrueBiome(int x, int z)
{
double wx = getModifiedX(x, z);
double wz = getModifiedZ(x, z);
IrisRegion region = sampleRegion(x, z);
int height = sampleHeight(x, z);
double sh = region.getShoreHeight(wx, wz);
IrisBiome current = sampleBiome(x, z).getBiome();
// Stop shores from spawning on land
if(current.isShore() && height > sh)
{
return glBiome.generateLandData(wx, wz, region);
}
// Stop oceans from spawning on mountains
if(current.isShore() && height <= getDimension().getFluidHeight())
{
return glBiome.generateSeaData(wx, wz, region);
}
// Stop oceans from spawning on land
if(current.isSea() && height > getDimension().getFluidHeight())
{
return glBiome.generateLandData(wx, wz, region);
}
// Stop land from spawning underwater
if(height <= getDimension().getFluidHeight())
{
return glBiome.generateSeaData(wx, wz, region);
}
// Stop land from spawning where shores go
if(height <= getDimension().getFluidHeight() + sh)
{
return glBiome.generateShoreData(wx, wz, region);
}
return glBiome.generateRegionData(wx, wz, region);
}
@Override
protected int onSampleColumnHeight(int cx, int cz, int rx, int rz, int x, int z)
{
int fluidHeight = getDimension().getFluidHeight();
double ox = getModifiedX(rx, rz);
double oz = getModifiedZ(rx, rz);
double lo = interpolateHeight(ox, oz, (b) -> b.getLowHeight());
double hi = interpolateSurface(ox, oz, (b) -> b.getHighHeight());
double noise = lo + (terrainNoise.fitDoubleD(0, hi - lo, getZoomed(ox), getZoomed(oz)));
double noise = getNoiseHeight(rx, rz);
return (int) Math.round(noise) + fluidHeight;
}

View File

@ -52,19 +52,11 @@ public class GenLayerBiome extends GenLayer
double x = bx / iris.getDimension().getBiomeZoom();
double z = bz / iris.getDimension().getBiomeZoom();
// Beach
if(bridge.getDistance(x, z) < regionData.getShoreRatio())
{
return generateShoreData(bx, bz, regionData);
}
// Sea
else if(bridge.getIndex(x, z, 5) == 1)
if(bridge.getIndex(x, z, 5) == 1)
{
return generateSeaData(bx, bz, regionData);
}
// Land
else
{
return generateLandData(bx, bz, regionData);

View File

@ -19,19 +19,43 @@ public class IrisBiome extends IrisRegisteredObject
{
private String name = "A Biome";
private Biome derivative = Biome.THE_VOID;
private double highHeight = 7;
private double highHeight = 3;
private double lowHeight = 1;
private double childShrinkFactor = 1.5;
private KList<String> children = new KList<>();
private KList<IrisBiomePaletteLayer> layers = new KList<IrisBiomePaletteLayer>().qadd(new IrisBiomePaletteLayer());
private KList<IrisBiomeDecorator> decorators = new KList<IrisBiomeDecorator>();
private KList<IrisObjectPlacement> objects = new KList<IrisObjectPlacement>();
private KList<IrisNoiseLayer> auxiliaryGenerators = new KList<IrisNoiseLayer>();
private transient ReentrantLock lock = new ReentrantLock();
private transient CellGenerator childrenCell;
private transient InferredType inferredType;
private transient KList<CNG> layerHeightGenerators;
private transient KList<CNG> layerSurfaceGenerators;
public IrisBiome()
{
}
public double getAuxiliaryHeight(double rx, double rz, long superSeed)
{
if(auxiliaryGenerators.isEmpty())
{
return 0;
}
int hc = hashCode();
double h = 0;
for(IrisNoiseLayer i : auxiliaryGenerators)
{
h += i.getNoise(superSeed + hc, rx, rz);
}
return h;
}
public CellGenerator getChildrenGenerator(RNG random, int sig, double scale)
{
if(childrenCell == null)

View File

@ -17,6 +17,8 @@ public class IrisDimension extends IrisRegisteredObject
private double interpolationScale = 63;
private InterpolationMethod interpolationSurfaceFunction = InterpolationMethod.BICUBIC;
private double interpolationSurfaceScale = 4;
private InterpolationMethod interpolationAuxiliaryFunction = InterpolationMethod.BICUBIC;
private double interpolationAuxiliaryScale = 7;
private Environment environment = Environment.NORMAL;
private KList<String> regions = new KList<>();
private int fluidHeight = 127;

View File

@ -0,0 +1,41 @@
package ninja.bytecode.iris.object;
import java.util.concurrent.locks.ReentrantLock;
import ninja.bytecode.iris.util.CNG;
import ninja.bytecode.iris.util.RNG;
public class IrisNoiseLayer
{
private double zoom;
private double offsetX;
private double offsetZ;
private long seed;
private double min;
private double max;
private ReentrantLock lock;
private transient CNG generator;
public IrisNoiseLayer()
{
lock = new ReentrantLock();
}
protected CNG getGenerator(long superSeed)
{
if(generator == null)
{
lock.lock();
generator = CNG.signature(new RNG(superSeed + 33955677 - seed));
lock.unlock();
}
return generator;
}
public double getNoise(long superSeed, double x, double z)
{
return getGenerator(superSeed).fitDoubleD(min, max, (x / zoom) + offsetX, (z / zoom) + offsetZ);
}
}

View File

@ -1,7 +1,11 @@
package ninja.bytecode.iris.object;
import java.util.concurrent.locks.ReentrantLock;
import lombok.Data;
import lombok.EqualsAndHashCode;
import ninja.bytecode.iris.util.CNG;
import ninja.bytecode.iris.util.RNG;
import ninja.bytecode.shuriken.collections.KList;
@Data
@ -10,8 +14,26 @@ public class IrisRegion extends IrisRegisteredObject
{
private String name = "A Region";
private double shoreRatio = 0.13;
private double shoreHeightMin = 1.2;
private double shoreHeightMax = 3.2;
private double shoreHeightZoom = 3.14;
private double biomeImplosionRatio = 0.4;
private KList<String> landBiomes = new KList<>();
private KList<String> seaBiomes = new KList<>();
private KList<String> shoreBiomes = new KList<>();
private transient CNG shoreHeightGenerator;
private transient ReentrantLock lock = new ReentrantLock();
public double getShoreHeight(double x, double z)
{
if(shoreHeightGenerator == null)
{
lock.lock();
shoreHeightGenerator = CNG.signature(new RNG(hashCode()));
lock.unlock();
}
return shoreHeightGenerator.fitDoubleD(shoreHeightMin, shoreHeightMax, x / shoreHeightZoom, z / shoreHeightZoom);
}
}

View File

@ -68,6 +68,16 @@ public class GroupedExecutor
public void waitFor(String g)
{
if(g == null)
{
return;
}
if(!mirror.containsKey(g))
{
return;
}
while(true)
{
J.sleep(1);

View File

@ -58,6 +58,28 @@ public class ObjectResourceLoader extends ResourceLoader<IrisObject>
return parallaxSize;
}
public IrisObject loadFile(File j, String key, String name)
{
try
{
IrisObject t = new IrisObject(0, 0, 0);
t.read(j);
loadCache.put(key, t);
Iris.hotloader.track(j);
Iris.info("Loading " + resourceTypeName + ": " + j.getPath());
t.setLoadKey(name);
lock.unlock();
return t;
}
catch(Throwable e)
{
lock.unlock();
Iris.warn("Couldn't read " + resourceTypeName + " file: " + j.getPath() + ": " + e.getMessage());
return null;
}
}
public IrisObject load(String name)
{
String key = name + "-" + objectClass.getCanonicalName();
@ -75,25 +97,16 @@ public class ObjectResourceLoader extends ResourceLoader<IrisObject>
{
if(j.isFile() && j.getName().endsWith(".iob") && j.getName().split("\\Q.\\E")[0].equals(name))
{
try
{
IrisObject t = new IrisObject(0, 0, 0);
t.read(j);
loadCache.put(key, t);
Iris.hotloader.track(j);
Iris.info("Loading " + resourceTypeName + ": " + j.getPath());
t.setLoadKey(name);
lock.unlock();
return t;
}
catch(Throwable e)
{
lock.unlock();
Iris.warn("Couldn't read " + resourceTypeName + " file: " + j.getPath() + ": " + e.getMessage());
}
return loadFile(j, key, name);
}
}
File file = new File(i, name + ".iob");
if(file.exists())
{
return loadFile(file, key, name);
}
}
Iris.warn("Couldn't find " + resourceTypeName + ": " + name);

View File

@ -30,6 +30,27 @@ public class ResourceLoader<T extends IrisRegisteredObject>
loadCache = new KMap<>();
}
protected T loadFile(File j, String key, String name)
{
try
{
T t = new Gson().fromJson(IO.readAll(j), objectClass);
loadCache.put(key, t);
Iris.hotloader.track(j);
Iris.info("Loading " + resourceTypeName + ": " + j.getPath());
t.setLoadKey(name);
lock.unlock();
return t;
}
catch(Throwable e)
{
lock.unlock();
Iris.warn("Couldn't read " + resourceTypeName + " file: " + j.getPath() + ": " + e.getMessage());
return null;
}
}
public T load(String name)
{
String key = name + "-" + objectClass.getCanonicalName();
@ -47,24 +68,16 @@ public class ResourceLoader<T extends IrisRegisteredObject>
{
if(j.isFile() && j.getName().endsWith(".json") && j.getName().split("\\Q.\\E")[0].equals(name))
{
try
{
T t = new Gson().fromJson(IO.readAll(j), objectClass);
loadCache.put(key, t);
Iris.hotloader.track(j);
Iris.info("Loading " + resourceTypeName + ": " + j.getPath());
t.setLoadKey(name);
lock.unlock();
return t;
}
catch(Throwable e)
{
lock.unlock();
Iris.warn("Couldn't read " + resourceTypeName + " file: " + j.getPath() + ": " + e.getMessage());
}
return loadFile(j, key, name);
}
}
File file = new File(i, name + ".json");
if(file.exists())
{
return loadFile(file, key, name);
}
}
Iris.warn("Couldn't find " + resourceTypeName + ": " + name);