mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2025-12-26 02:29:14 +00:00
Reorganize
This commit is contained in:
20
src/main/java/com/volmit/iris/GeneratedChunk.java
Normal file
20
src/main/java/com/volmit/iris/GeneratedChunk.java
Normal file
@@ -0,0 +1,20 @@
|
||||
package ninja.bytecode.iris;
|
||||
|
||||
import org.bukkit.generator.ChunkGenerator.BiomeGrid;
|
||||
import org.bukkit.generator.ChunkGenerator.ChunkData;
|
||||
|
||||
import lombok.Data;
|
||||
import ninja.bytecode.iris.util.ChunkPosition;
|
||||
|
||||
@Data
|
||||
public class GeneratedChunk
|
||||
{
|
||||
private ChunkPosition pos;
|
||||
private ChunkData data;
|
||||
private BiomeGrid grid;
|
||||
|
||||
public GeneratedChunk(ChunkPosition pos)
|
||||
{
|
||||
this.pos = pos;
|
||||
}
|
||||
}
|
||||
843
src/main/java/com/volmit/iris/Iris.java
Normal file
843
src/main/java/com/volmit/iris/Iris.java
Normal file
@@ -0,0 +1,843 @@
|
||||
package ninja.bytecode.iris;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.FluidCollisionMode;
|
||||
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.block.data.BlockData;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.HandlerList;
|
||||
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 org.zeroturnaround.zip.ZipUtil;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import ninja.bytecode.iris.generator.IrisChunkGenerator;
|
||||
import ninja.bytecode.iris.object.IrisBiome;
|
||||
import ninja.bytecode.iris.object.IrisDimension;
|
||||
import ninja.bytecode.iris.object.IrisGenerator;
|
||||
import ninja.bytecode.iris.object.IrisObject;
|
||||
import ninja.bytecode.iris.object.IrisObjectPlacement;
|
||||
import ninja.bytecode.iris.object.IrisRegion;
|
||||
import ninja.bytecode.iris.util.BiomeResult;
|
||||
import ninja.bytecode.iris.util.BlockDataTools;
|
||||
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.Desc;
|
||||
import ninja.bytecode.iris.util.Direction;
|
||||
import ninja.bytecode.iris.util.GroupedExecutor;
|
||||
import ninja.bytecode.iris.util.IO;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
import ninja.bytecode.iris.util.ScoreDirection;
|
||||
import ninja.bytecode.iris.wand.WandController;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
import ninja.bytecode.shuriken.collections.KMap;
|
||||
import ninja.bytecode.shuriken.collections.KSet;
|
||||
import ninja.bytecode.shuriken.execution.J;
|
||||
import ninja.bytecode.shuriken.format.Form;
|
||||
import ninja.bytecode.shuriken.json.JSONException;
|
||||
import ninja.bytecode.shuriken.json.JSONObject;
|
||||
import ninja.bytecode.shuriken.logging.L;
|
||||
import ninja.bytecode.shuriken.math.RollingSequence;
|
||||
import ninja.bytecode.shuriken.reaction.O;
|
||||
import ninja.bytecode.shuriken.tools.JarScanner;
|
||||
|
||||
public class Iris extends JavaPlugin implements BoardProvider
|
||||
{
|
||||
public static KList<GroupedExecutor> executors = new KList<>();
|
||||
public static Iris instance;
|
||||
public static IrisDataManager data;
|
||||
public static IrisHotloadManager hotloader;
|
||||
public static WandController wand;
|
||||
private static String last = "";
|
||||
private BoardManager manager;
|
||||
private RollingSequence hits = new RollingSequence(20);
|
||||
|
||||
public Iris()
|
||||
{
|
||||
IO.delete(new File("iris"));
|
||||
}
|
||||
|
||||
public void onEnable()
|
||||
{
|
||||
instance = this;
|
||||
hotloader = new IrisHotloadManager();
|
||||
data = new IrisDataManager(getDataFolder());
|
||||
wand = new WandController();
|
||||
manager = new BoardManager(this, BoardSettings.builder().boardProvider(this).scoreDirection(ScoreDirection.UP).build());
|
||||
J.a(() ->
|
||||
{
|
||||
try
|
||||
{
|
||||
writeDocs();
|
||||
}
|
||||
catch(JSONException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException | IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle(Player player)
|
||||
{
|
||||
return ChatColor.GREEN + "Iris";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getLines(Player player)
|
||||
{
|
||||
World world = player.getWorld();
|
||||
List<String> lines = new ArrayList<>();
|
||||
|
||||
if(world.getGenerator() instanceof IrisChunkGenerator)
|
||||
{
|
||||
IrisChunkGenerator g = (IrisChunkGenerator) world.getGenerator();
|
||||
int x = player.getLocation().getBlockX();
|
||||
int z = player.getLocation().getBlockZ();
|
||||
BiomeResult er = g.sampleTrueBiome(x, z);
|
||||
IrisBiome b = er != null ? er.getBiome() : null;
|
||||
lines.add("&7&m-----------------");
|
||||
lines.add(ChatColor.GREEN + "Speed" + ChatColor.GRAY + ": " + ChatColor.BOLD + "" + ChatColor.GRAY + Form.f(g.getMetrics().getPerSecond().getAverage(), 0) + "/s " + Form.duration(g.getMetrics().getTotal().getAverage(), 1) + "");
|
||||
lines.add(ChatColor.GREEN + "Loss" + ChatColor.GRAY + ": " + ChatColor.BOLD + "" + ChatColor.GRAY + Form.duration(g.getMetrics().getLoss().getAverage(), 4) + "");
|
||||
lines.add(ChatColor.GREEN + "Generators" + ChatColor.GRAY + ": " + Form.f(CNG.creates));
|
||||
lines.add(ChatColor.GREEN + "Noise" + ChatColor.GRAY + ": " + Form.f((int) hits.getAverage()));
|
||||
lines.add(ChatColor.GREEN + "Parallax Chunks" + ChatColor.GRAY + ": " + Form.f((int) g.getParallaxMap().getLoadedChunks().size()));
|
||||
lines.add(ChatColor.GREEN + "Objects" + ChatColor.GRAY + ": " + Form.f(Iris.data.getObjectLoader().count()) + " (~" + Form.memSize(752 * Iris.data.getObjectLoader().getTotalStorage(), 0) + ")");
|
||||
lines.add(ChatColor.GREEN + "Biomes" + ChatColor.GRAY + ": " + Form.f(Iris.data.getBiomeLoader().count()));
|
||||
lines.add(ChatColor.GREEN + "Regions" + ChatColor.GRAY + ": " + Form.f(Iris.data.getRegionLoader().count()));
|
||||
lines.add(ChatColor.GREEN + "Height" + ChatColor.GRAY + ": " + (int) g.getTerrainHeight(x, z) + " (" + (int) g.getTerrainWaterHeight(x, z) + ")");
|
||||
lines.add(ChatColor.GREEN + "Height" + ChatColor.GRAY + ": " + (int) g.getTerrainHeight(x, z) + " (" + (int) g.getTerrainWaterHeight(x, z) + ")");
|
||||
|
||||
if(er != null && b != null)
|
||||
{
|
||||
lines.add(ChatColor.GREEN + "Biome" + ChatColor.GRAY + ": " + b.getName());
|
||||
lines.add(ChatColor.GREEN + "File" + ChatColor.GRAY + ": " + b.getLoadKey());
|
||||
}
|
||||
|
||||
lines.add("&7&m-----------------");
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
lines.add(ChatColor.GREEN + "Join an Iris World!");
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
public void writeDocs() throws IOException, JSONException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException
|
||||
{
|
||||
JarScanner j = new JarScanner(getFile(), "ninja.bytecode.iris.object");
|
||||
j.scan();
|
||||
File of = new File(getDataFolder(), "packs");
|
||||
of.mkdirs();
|
||||
KMap<String, String> files = new KMap<>();
|
||||
|
||||
for(Class<?> i : j.getClasses())
|
||||
{
|
||||
if(i.isAnnotationPresent(Desc.class))
|
||||
{
|
||||
Desc d = i.getAnnotation(Desc.class);
|
||||
KList<String> page = new KList<>();
|
||||
page.add("# " + i.getSimpleName());
|
||||
page.add("> " + d.value());
|
||||
|
||||
page.add("```json");
|
||||
page.add(new JSONObject(new Gson().toJson(i.getConstructor().newInstance())).toString(4));
|
||||
page.add("```");
|
||||
|
||||
page.add("");
|
||||
for(java.lang.reflect.Field k : i.getDeclaredFields())
|
||||
{
|
||||
if(k.isAnnotationPresent(Desc.class))
|
||||
{
|
||||
page.add("## " + k.getName());
|
||||
page.add("> " + k.getAnnotation(Desc.class).value());
|
||||
page.add("");
|
||||
}
|
||||
}
|
||||
|
||||
String pge = page.toString("\n");
|
||||
files.put(i.getSimpleName(), pge);
|
||||
}
|
||||
}
|
||||
|
||||
for(String i : files.k())
|
||||
{
|
||||
IO.writeAll(new File(of, i + ".md"), files.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
public void onDisable()
|
||||
{
|
||||
for(GroupedExecutor i : executors)
|
||||
{
|
||||
i.close();
|
||||
}
|
||||
|
||||
executors.clear();
|
||||
manager.onDisable();
|
||||
Bukkit.getScheduler().cancelTasks(this);
|
||||
HandlerList.unregisterAll((Plugin) this);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args)
|
||||
{
|
||||
if(command.getName().equals("iris"))
|
||||
{
|
||||
if(args.length == 0)
|
||||
{
|
||||
imsg(sender, "/iris dev [dimension] - Create a new dev world");
|
||||
imsg(sender, "/iris what <look/hand> - Data about items & blocks");
|
||||
imsg(sender, "/iris goto <name> - Fast goto biome");
|
||||
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("goto") && args.length == 2)
|
||||
{
|
||||
if(sender instanceof Player)
|
||||
{
|
||||
Player p = (Player) sender;
|
||||
World world = p.getWorld();
|
||||
IrisChunkGenerator g = (IrisChunkGenerator) world.getGenerator();
|
||||
int tries = 10000;
|
||||
IrisBiome biome = data.getBiomeLoader().load(args[1]);
|
||||
|
||||
if(biome == null)
|
||||
{
|
||||
sender.sendMessage("Not a biome. Use the file name (without extension)");
|
||||
}
|
||||
|
||||
while(tries > 0)
|
||||
{
|
||||
tries--;
|
||||
|
||||
int xx = (int) (RNG.r.i(-29999970, 29999970));
|
||||
int zz = (int) (RNG.r.i(-29999970, 29999970));
|
||||
if(g.sampleTrueBiome(xx, zz).getBiome().getLoadKey().equals(biome.getLoadKey()))
|
||||
{
|
||||
p.teleport(new Location(world, xx, world.getHighestBlockYAt(xx, zz), zz));
|
||||
sender.sendMessage("Found in " + (10000 - tries) + "!");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
sender.sendMessage("Tried to find " + biome.getName() + " looked in 10,000 places no dice.");
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if(args[0].equalsIgnoreCase("what"))
|
||||
{
|
||||
if(args.length != 2)
|
||||
{
|
||||
imsg(sender, "/iris what <look/hand> - Data about items & blocks");
|
||||
return true;
|
||||
}
|
||||
|
||||
BlockData bd = null;
|
||||
|
||||
try
|
||||
{
|
||||
if(args[1].toLowerCase().startsWith("h"))
|
||||
{
|
||||
bd = BlockDataTools.getBlockData(((Player) sender).getInventory().getItemInMainHand().getType().name());
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
bd = ((Player) sender).getTargetBlockExact(128, FluidCollisionMode.NEVER).getBlockData();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
if(bd == null)
|
||||
{
|
||||
imsg(sender, "No data found.");
|
||||
return true;
|
||||
}
|
||||
|
||||
imsg(sender, "Material: " + ChatColor.GREEN + bd.getMaterial().name());
|
||||
imsg(sender, "Full: " + ChatColor.WHITE + bd.getAsString(true));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if(args[0].equalsIgnoreCase("wand"))
|
||||
{
|
||||
if(args.length == 1)
|
||||
{
|
||||
((Player) sender).getInventory().addItem(WandController.createWand());
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
ItemStack wand = ((Player) sender).getInventory().getItemInMainHand();
|
||||
IrisObject o = WandController.createSchematic(wand);
|
||||
try
|
||||
{
|
||||
o.write(new File(getDataFolder(), "objects/" + args[1] + ".iob"));
|
||||
imsg(sender, "Saved " + "objects/" + args[1] + ".iob");
|
||||
((Player) sender).getWorld().playSound(((Player) sender).getLocation(), Sound.BLOCK_ENCHANTMENT_TABLE_USE, 1f, 1.5f);
|
||||
}
|
||||
|
||||
catch(IOException e)
|
||||
{
|
||||
imsg(sender, "Failed to save " + "objects/" + args[1] + ".iob");
|
||||
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if(args[0].equalsIgnoreCase("load") && args.length >= 2)
|
||||
{
|
||||
File file = new File(getDataFolder(), "objects/" + args[1] + ".iob");
|
||||
boolean intoWand = false;
|
||||
|
||||
for(String i : args)
|
||||
{
|
||||
if(i.equalsIgnoreCase("-edit"))
|
||||
{
|
||||
intoWand = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(!file.exists())
|
||||
{
|
||||
imsg(sender, "Can't find " + "objects/" + args[1] + ".iob");
|
||||
}
|
||||
|
||||
ItemStack wand = ((Player) sender).getInventory().getItemInMainHand();
|
||||
IrisObject o = new IrisObject(0, 0, 0);
|
||||
|
||||
try
|
||||
{
|
||||
o.read(new File(getDataFolder(), "objects/" + args[1] + ".iob"));
|
||||
imsg(sender, "Loaded " + "objects/" + args[1] + ".iob");
|
||||
|
||||
((Player) sender).getWorld().playSound(((Player) sender).getLocation(), Sound.BLOCK_ENCHANTMENT_TABLE_USE, 1f, 1.5f);
|
||||
Location block = ((Player) sender).getTargetBlock((Set<Material>) null, 256).getLocation().clone().add(0, 1, 0);
|
||||
|
||||
if(intoWand && WandController.isWand(wand))
|
||||
{
|
||||
wand = WandController.createWand(block.clone().subtract(o.getCenter()).add(o.getW() - 1, o.getH(), o.getD() - 1), block.clone().subtract(o.getCenter()));
|
||||
((Player) sender).getInventory().setItemInMainHand(wand);
|
||||
imsg(sender, "Updated wand for " + "objects/" + args[1] + ".iob");
|
||||
}
|
||||
|
||||
WandController.pasteSchematic(o, block);
|
||||
imsg(sender, "Placed " + "objects/" + args[1] + ".iob");
|
||||
}
|
||||
|
||||
catch(IOException e)
|
||||
{
|
||||
imsg(sender, "Failed to load " + "objects/" + args[1] + ".iob");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if(args[0].equalsIgnoreCase("package") || args[0].equalsIgnoreCase("pkg"))
|
||||
{
|
||||
String dim = "overworld";
|
||||
|
||||
if(args.length > 1)
|
||||
{
|
||||
dim = args[1];
|
||||
}
|
||||
|
||||
boolean obfuscate = false;
|
||||
|
||||
for(String i : args)
|
||||
{
|
||||
if(i.equalsIgnoreCase("-o"))
|
||||
{
|
||||
obfuscate = true;
|
||||
}
|
||||
}
|
||||
|
||||
String dimm = dim;
|
||||
IrisDimension dimension = data.getDimensionLoader().load(dimm);
|
||||
File folder = new File(getDataFolder(), "exports/" + dimension.getLoadKey());
|
||||
folder.mkdirs();
|
||||
Iris.info("Packaging Dimension " + dimension.getName());
|
||||
KSet<IrisRegion> regions = new KSet<>();
|
||||
KSet<IrisBiome> biomes = new KSet<>();
|
||||
KSet<IrisGenerator> generators = new KSet<>();
|
||||
dimension.getRegions().forEach((i) -> regions.add(data.getRegionLoader().load(i)));
|
||||
regions.forEach((i) -> biomes.addAll(i.getAllBiomes()));
|
||||
biomes.forEach((i) -> i.getGenerators().forEach((j) -> generators.add(j.getCachedGenerator())));
|
||||
KMap<String, String> renameObjects = new KMap<>();
|
||||
|
||||
for(IrisBiome i : biomes)
|
||||
{
|
||||
for(IrisObjectPlacement j : i.getObjects())
|
||||
{
|
||||
KList<String> newNames = new KList<>();
|
||||
|
||||
for(String k : j.getPlace())
|
||||
{
|
||||
if(renameObjects.containsKey(k))
|
||||
{
|
||||
newNames.add(renameObjects.get(k));
|
||||
continue;
|
||||
}
|
||||
|
||||
String name = obfuscate ? UUID.randomUUID().toString().replaceAll("-", "") : k;
|
||||
newNames.add(name);
|
||||
renameObjects.put(k, name);
|
||||
}
|
||||
|
||||
if(obfuscate)
|
||||
{
|
||||
j.setPlace(newNames);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
KMap<String, KList<String>> lookupObjects = renameObjects.flip();
|
||||
|
||||
biomes.forEach((i) -> i.getObjects().forEach((j) -> j.getPlace().forEach((k) ->
|
||||
{
|
||||
try
|
||||
{
|
||||
Iris.info("- " + k + " (Object)");
|
||||
IO.copyFile(Iris.data.getObjectLoader().findFile(lookupObjects.get(k).get(0)), new File(folder, "objects/" + k + ".iob"));
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
|
||||
}
|
||||
})));
|
||||
|
||||
try
|
||||
{
|
||||
IO.writeAll(new File(folder, "dimensions/" + dimension.getLoadKey() + ".json"), new JSONObject(new Gson().toJson(dimension)).toString(0));
|
||||
|
||||
for(IrisGenerator i : generators)
|
||||
{
|
||||
Iris.info("- " + i.getLoadKey() + " (Generator)");
|
||||
IO.writeAll(new File(folder, "generators/" + i.getLoadKey() + ".json"), new JSONObject(new Gson().toJson(i)).toString(0));
|
||||
}
|
||||
|
||||
for(IrisRegion i : regions)
|
||||
{
|
||||
Iris.info("- " + i.getName() + " (Region)");
|
||||
IO.writeAll(new File(folder, "regions/" + i.getLoadKey() + ".json"), new JSONObject(new Gson().toJson(i)).toString(0));
|
||||
}
|
||||
|
||||
for(IrisBiome i : biomes)
|
||||
{
|
||||
Iris.info("- " + i.getName() + " (Biome)");
|
||||
IO.writeAll(new File(folder, "biomes/" + i.getLoadKey() + ".json"), new JSONObject(new Gson().toJson(i)).toString(0));
|
||||
}
|
||||
|
||||
ZipUtil.pack(folder, new File(getDataFolder(), "exports/" + dimension.getLoadKey() + ".iris"));
|
||||
IO.delete(folder);
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
L.ex(e);
|
||||
}
|
||||
|
||||
sender.sendMessage("Done!");
|
||||
}
|
||||
|
||||
if(args[0].equalsIgnoreCase("dev"))
|
||||
{
|
||||
String dim = "overworld";
|
||||
|
||||
if(args.length > 1)
|
||||
{
|
||||
dim = args[1];
|
||||
}
|
||||
|
||||
String dimm = dim;
|
||||
|
||||
Bukkit.getScheduler().scheduleSyncDelayedTask(this, () ->
|
||||
{
|
||||
for(World i : Bukkit.getWorlds())
|
||||
{
|
||||
if(i.getName().startsWith("iris/"))
|
||||
{
|
||||
for(Player j : Bukkit.getOnlinePlayers())
|
||||
{
|
||||
imsg(j, "Unloading " + i.getName());
|
||||
}
|
||||
|
||||
Bukkit.unloadWorld(i, false);
|
||||
}
|
||||
}
|
||||
|
||||
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 + "...");
|
||||
}
|
||||
|
||||
int tc = Math.max(Runtime.getRuntime().availableProcessors(), 4);
|
||||
IrisChunkGenerator gx = new IrisChunkGenerator(dimm, tc);
|
||||
info("Generating with " + tc + " threads per chunk");
|
||||
O<Boolean> done = new O<Boolean>();
|
||||
done.set(false);
|
||||
|
||||
J.a(() ->
|
||||
{
|
||||
int req = 740;
|
||||
while(!done.get())
|
||||
{
|
||||
for(Player i : Bukkit.getOnlinePlayers())
|
||||
{
|
||||
imsg(i, "Generating " + Form.pc((double) gx.getGenerated() / (double) req));
|
||||
}
|
||||
J.sleep(3000);
|
||||
}
|
||||
});
|
||||
World world = Bukkit.createWorld(new WorldCreator("iris/" + UUID.randomUUID()).generator(gx));
|
||||
done.set(true);
|
||||
|
||||
for(Player i : Bukkit.getOnlinePlayers())
|
||||
{
|
||||
imsg(i, "Generating 100%");
|
||||
}
|
||||
|
||||
for(Player i : Bukkit.getOnlinePlayers())
|
||||
{
|
||||
i.teleport(new Location(world, 0, 100, 0));
|
||||
|
||||
Bukkit.getScheduler().scheduleSyncDelayedTask(this, () ->
|
||||
{
|
||||
imsg(i, "Have Fun!");
|
||||
i.setGameMode(GameMode.SPECTATOR);
|
||||
}, 5);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void imsg(CommandSender s, String msg)
|
||||
{
|
||||
s.sendMessage(ChatColor.GREEN + "[" + ChatColor.DARK_GRAY + "Iris" + ChatColor.GREEN + "]" + ChatColor.GRAY + ": " + msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChunkGenerator getDefaultWorldGenerator(String worldName, String id)
|
||||
{
|
||||
return new IrisChunkGenerator("overworld", 16);
|
||||
}
|
||||
|
||||
public static void msg(String string)
|
||||
{
|
||||
String msg = ChatColor.GREEN + "[Iris]: " + ChatColor.GRAY + string;
|
||||
|
||||
if(last.equals(msg))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
last = msg;
|
||||
|
||||
Bukkit.getConsoleSender().sendMessage(msg);
|
||||
}
|
||||
|
||||
public static void warn(String string)
|
||||
{
|
||||
msg(ChatColor.YELLOW + string);
|
||||
}
|
||||
|
||||
public static void error(String string)
|
||||
{
|
||||
msg(ChatColor.RED + string);
|
||||
}
|
||||
|
||||
public static void verbose(String string)
|
||||
{
|
||||
msg(ChatColor.GRAY + string);
|
||||
}
|
||||
|
||||
public static void success(String string)
|
||||
{
|
||||
msg(ChatColor.GREEN + string);
|
||||
}
|
||||
|
||||
public static void info(String string)
|
||||
{
|
||||
msg(ChatColor.WHITE + string);
|
||||
}
|
||||
|
||||
public void hit(long hits2)
|
||||
{
|
||||
hits.put(hits2);
|
||||
}
|
||||
}
|
||||
37
src/main/java/com/volmit/iris/IrisContext.java
Normal file
37
src/main/java/com/volmit/iris/IrisContext.java
Normal file
@@ -0,0 +1,37 @@
|
||||
package ninja.bytecode.iris;
|
||||
|
||||
import org.bukkit.World;
|
||||
|
||||
import ninja.bytecode.iris.object.IrisDimension;
|
||||
import ninja.bytecode.iris.object.IrisRegion;
|
||||
import ninja.bytecode.iris.util.BiomeResult;
|
||||
import ninja.bytecode.shuriken.collections.KMap;
|
||||
|
||||
public interface IrisContext
|
||||
{
|
||||
static KMap<World, IrisContext> contexts = new KMap<>();
|
||||
|
||||
public static void pushContext(IrisContext context)
|
||||
{
|
||||
contexts.put(context.getWorld(), context);
|
||||
}
|
||||
|
||||
public static IrisContext of(World world)
|
||||
{
|
||||
return contexts.get(world);
|
||||
}
|
||||
|
||||
public BiomeResult getBiome(int x, int z);
|
||||
|
||||
public IrisDimension getDimension();
|
||||
|
||||
public IrisRegion getRegion(int x, int z);
|
||||
|
||||
public IrisMetrics getMetrics();
|
||||
|
||||
public int getHeight(int x, int z);
|
||||
|
||||
public World getWorld();
|
||||
|
||||
public void onHotloaded();
|
||||
}
|
||||
127
src/main/java/com/volmit/iris/IrisDataManager.java
Normal file
127
src/main/java/com/volmit/iris/IrisDataManager.java
Normal file
@@ -0,0 +1,127 @@
|
||||
package ninja.bytecode.iris;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.bukkit.World.Environment;
|
||||
import org.bukkit.block.Biome;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import lombok.Data;
|
||||
import ninja.bytecode.iris.object.IrisBiome;
|
||||
import ninja.bytecode.iris.object.IrisBiomeDecorator;
|
||||
import ninja.bytecode.iris.object.IrisDimension;
|
||||
import ninja.bytecode.iris.object.IrisGenerator;
|
||||
import ninja.bytecode.iris.object.IrisNoiseGenerator;
|
||||
import ninja.bytecode.iris.object.IrisObjectPlacement;
|
||||
import ninja.bytecode.iris.object.IrisRegion;
|
||||
import ninja.bytecode.iris.util.IO;
|
||||
import ninja.bytecode.iris.util.ObjectResourceLoader;
|
||||
import ninja.bytecode.iris.util.ResourceLoader;
|
||||
import ninja.bytecode.shuriken.json.JSONObject;
|
||||
|
||||
@Data
|
||||
public class IrisDataManager
|
||||
{
|
||||
private File dataFolder;
|
||||
private File packs;
|
||||
private ResourceLoader<IrisBiome> biomeLoader;
|
||||
private ResourceLoader<IrisRegion> regionLoader;
|
||||
private ResourceLoader<IrisDimension> dimensionLoader;
|
||||
private ResourceLoader<IrisGenerator> generatorLoader;
|
||||
private ObjectResourceLoader objectLoader;
|
||||
|
||||
public void hotloaded()
|
||||
{
|
||||
packs.mkdirs();
|
||||
this.regionLoader = new ResourceLoader<>(packs, "regions", "Region", IrisRegion.class);
|
||||
this.biomeLoader = new ResourceLoader<>(packs, "biomes", "Biome", IrisBiome.class);
|
||||
this.dimensionLoader = new ResourceLoader<>(packs, "dimensions", "Dimension", IrisDimension.class);
|
||||
this.generatorLoader = new ResourceLoader<>(packs, "generators", "Generator", IrisGenerator.class);
|
||||
this.objectLoader = new ObjectResourceLoader(packs, "objects", "Object");
|
||||
writeExamples();
|
||||
}
|
||||
|
||||
public IrisDataManager(File dataFolder)
|
||||
{
|
||||
this.dataFolder = dataFolder;
|
||||
this.packs = new File(dataFolder, "packs");
|
||||
hotloaded();
|
||||
}
|
||||
|
||||
private void writeExamples()
|
||||
{
|
||||
File examples = new File(dataFolder, "example");
|
||||
examples.mkdirs();
|
||||
String biomes = "";
|
||||
String envs = "";
|
||||
|
||||
for(Biome i : Biome.values())
|
||||
{
|
||||
biomes += i.name() + "\n";
|
||||
}
|
||||
|
||||
for(Environment i : Environment.values())
|
||||
{
|
||||
envs += i.name() + "\n";
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
new File(examples, "example-pack/regions").mkdirs();
|
||||
new File(examples, "example-pack/biomes").mkdirs();
|
||||
new File(examples, "example-pack/dimensions").mkdirs();
|
||||
new File(examples, "example-pack/generators").mkdirs();
|
||||
IO.writeAll(new File(examples, "biome-list.txt"), biomes);
|
||||
IO.writeAll(new File(examples, "environment-list.txt"), envs);
|
||||
|
||||
IrisGenerator gen = new IrisGenerator();
|
||||
IrisNoiseGenerator n = new IrisNoiseGenerator();
|
||||
n.setSeed(1000);
|
||||
IrisNoiseGenerator nf = new IrisNoiseGenerator();
|
||||
nf.setIrisBased(false);
|
||||
nf.setOctaves(3);
|
||||
nf.setOpacity(16);
|
||||
nf.setZoom(24);
|
||||
nf.setSeed(44);
|
||||
n.getFracture().add(nf);
|
||||
IrisNoiseGenerator nf2 = new IrisNoiseGenerator();
|
||||
nf2.setIrisBased(false);
|
||||
nf2.setOctaves(8);
|
||||
nf2.setOpacity(24);
|
||||
nf2.setZoom(64);
|
||||
nf2.setSeed(55);
|
||||
n.getFracture().add(nf2);
|
||||
gen.getComposite().add(n);
|
||||
|
||||
IrisDimension dim = new IrisDimension();
|
||||
|
||||
IrisRegion region = new IrisRegion();
|
||||
region.getLandBiomes().add("plains");
|
||||
region.getLandBiomes().add("desert");
|
||||
region.getLandBiomes().add("forest");
|
||||
region.getLandBiomes().add("mountains");
|
||||
region.getSeaBiomes().add("ocean");
|
||||
region.getShoreBiomes().add("beach");
|
||||
|
||||
IrisObjectPlacement o = new IrisObjectPlacement();
|
||||
o.getPlace().add("schematic1");
|
||||
o.getPlace().add("schematic2");
|
||||
|
||||
IrisBiome biome = new IrisBiome();
|
||||
biome.getChildren().add("another_biome");
|
||||
biome.getDecorators().add(new IrisBiomeDecorator());
|
||||
biome.getObjects().add(o);
|
||||
|
||||
IO.writeAll(new File(examples, "example-pack/biomes/example-biome.json"), new JSONObject(new Gson().toJson(biome)).toString(4));
|
||||
IO.writeAll(new File(examples, "example-pack/regions/example-region.json"), new JSONObject(new Gson().toJson(region)).toString(4));
|
||||
IO.writeAll(new File(examples, "example-pack/dimensions/example-dimension.json"), new JSONObject(new Gson().toJson(dim)).toString(4));
|
||||
IO.writeAll(new File(examples, "example-pack/generators/example-generator.json"), new JSONObject(new Gson().toJson(gen)).toString(4));
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
58
src/main/java/com/volmit/iris/IrisHotloadManager.java
Normal file
58
src/main/java/com/volmit/iris/IrisHotloadManager.java
Normal file
@@ -0,0 +1,58 @@
|
||||
package ninja.bytecode.iris;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import ninja.bytecode.iris.util.ChronoLatch;
|
||||
import ninja.bytecode.iris.util.FileWatcher;
|
||||
import ninja.bytecode.shuriken.collections.KSet;
|
||||
|
||||
public class IrisHotloadManager
|
||||
{
|
||||
private ChronoLatch latch;
|
||||
private KSet<FileWatcher> watchers;
|
||||
|
||||
public IrisHotloadManager()
|
||||
{
|
||||
watchers = new KSet<>();
|
||||
latch = new ChronoLatch(3000);
|
||||
}
|
||||
|
||||
public void check(IrisContext ch)
|
||||
{
|
||||
if(!latch.flip())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Bukkit.getScheduler().scheduleSyncDelayedTask(Iris.instance, () ->
|
||||
{
|
||||
boolean modified = false;
|
||||
int c = 0;
|
||||
|
||||
for(FileWatcher i : watchers)
|
||||
{
|
||||
if(i.checkModified())
|
||||
{
|
||||
c++;
|
||||
Iris.info("File Modified: " + i.getFile().getPath());
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(modified)
|
||||
{
|
||||
watchers.clear();
|
||||
Iris.success("Hotloading Iris (" + c + " File" + (c == 1 ? "" : "s") + " changed)");
|
||||
Iris.data.hotloaded();
|
||||
ch.onHotloaded();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void track(File file)
|
||||
{
|
||||
watchers.add(new FileWatcher(file));
|
||||
}
|
||||
}
|
||||
21
src/main/java/com/volmit/iris/IrisMetrics.java
Normal file
21
src/main/java/com/volmit/iris/IrisMetrics.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package ninja.bytecode.iris;
|
||||
|
||||
import lombok.Data;
|
||||
import ninja.bytecode.shuriken.math.RollingSequence;
|
||||
|
||||
@Data
|
||||
public class IrisMetrics
|
||||
{
|
||||
private final RollingSequence total;
|
||||
private final RollingSequence perSecond;
|
||||
private final RollingSequence loss;
|
||||
public int generators = 0;
|
||||
public int noiseHits = 0;
|
||||
|
||||
public IrisMetrics(int memory)
|
||||
{
|
||||
total = new RollingSequence(memory);
|
||||
perSecond = new RollingSequence(5);
|
||||
loss = new RollingSequence(memory);
|
||||
}
|
||||
}
|
||||
9
src/main/java/com/volmit/iris/IrisSettings.java
Normal file
9
src/main/java/com/volmit/iris/IrisSettings.java
Normal file
@@ -0,0 +1,9 @@
|
||||
package ninja.bytecode.iris;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class IrisSettings
|
||||
{
|
||||
private int threads = 8;
|
||||
}
|
||||
250
src/main/java/com/volmit/iris/generator/BiomeChunkGenerator.java
Normal file
250
src/main/java/com/volmit/iris/generator/BiomeChunkGenerator.java
Normal file
@@ -0,0 +1,250 @@
|
||||
package ninja.bytecode.iris.generator;
|
||||
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.bukkit.World;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import ninja.bytecode.iris.Iris;
|
||||
import ninja.bytecode.iris.layer.GenLayerBiome;
|
||||
import ninja.bytecode.iris.object.InferredType;
|
||||
import ninja.bytecode.iris.object.IrisBiome;
|
||||
import ninja.bytecode.iris.object.IrisBiomeGeneratorLink;
|
||||
import ninja.bytecode.iris.object.IrisDimension;
|
||||
import ninja.bytecode.iris.object.IrisGenerator;
|
||||
import ninja.bytecode.iris.object.IrisRegion;
|
||||
import ninja.bytecode.iris.util.BiomeResult;
|
||||
import ninja.bytecode.iris.util.CNG;
|
||||
import ninja.bytecode.iris.util.ChronoLatch;
|
||||
import ninja.bytecode.iris.util.ChunkPosition;
|
||||
import ninja.bytecode.iris.util.IrisInterpolation;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
import ninja.bytecode.shuriken.collections.KMap;
|
||||
import ninja.bytecode.shuriken.math.M;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public abstract class BiomeChunkGenerator extends DimensionChunkGenerator
|
||||
{
|
||||
protected ReentrantLock regLock;
|
||||
private KMap<String, IrisGenerator> generators;
|
||||
private KMap<String, IrisGenerator> ceilingGenerators;
|
||||
protected GenLayerBiome glBiome;
|
||||
protected CNG masterFracture;
|
||||
private KMap<ChunkPosition, BiomeResult> biomeHitCache;
|
||||
private KMap<ChunkPosition, BiomeResult> ceilingBiomeHitCache;
|
||||
protected ChronoLatch cwarn = new ChronoLatch(1000);
|
||||
private IrisBiome[] biomeCache;
|
||||
|
||||
public BiomeChunkGenerator(String dimensionName)
|
||||
{
|
||||
super(dimensionName);
|
||||
generators = new KMap<>();
|
||||
ceilingGenerators = new KMap<>();
|
||||
regLock = new ReentrantLock();
|
||||
biomeHitCache = new KMap<>();
|
||||
ceilingBiomeHitCache = new KMap<>();
|
||||
biomeCache = new IrisBiome[256];
|
||||
}
|
||||
|
||||
public void onInit(World world, RNG rng)
|
||||
{
|
||||
loadGenerators();
|
||||
glBiome = new GenLayerBiome(this, masterRandom.nextParallelRNG(1));
|
||||
masterFracture = CNG.signature(rng.nextParallelRNG(13)).scale(0.12);
|
||||
}
|
||||
|
||||
protected IrisBiome getCachedBiome(int x, int z)
|
||||
{
|
||||
return biomeCache[(z << 4) | x];
|
||||
}
|
||||
|
||||
protected void cacheBiome(int x, int z, IrisBiome b)
|
||||
{
|
||||
biomeCache[(z << 4) | x] = b;
|
||||
}
|
||||
|
||||
public KMap<ChunkPosition, BiomeResult> getBiomeHitCache()
|
||||
{
|
||||
return getDimension().isInverted() ? ceilingBiomeHitCache : biomeHitCache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHotload()
|
||||
{
|
||||
super.onHotload();
|
||||
biomeHitCache = new KMap<>();
|
||||
ceilingBiomeHitCache = new KMap<>();
|
||||
loadGenerators();
|
||||
}
|
||||
|
||||
public void registerGenerator(IrisGenerator g, IrisDimension dim)
|
||||
{
|
||||
KMap<String, IrisGenerator> generators = dim.isInverted() ? ceilingGenerators : this.generators;
|
||||
|
||||
regLock.lock();
|
||||
if(g.getLoadKey() == null || generators.containsKey(g.getLoadKey()))
|
||||
{
|
||||
regLock.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
regLock.unlock();
|
||||
generators.put(g.getLoadKey(), g);
|
||||
}
|
||||
|
||||
protected KMap<String, IrisGenerator> getGenerators()
|
||||
{
|
||||
return getDimension().isInverted() ? ceilingGenerators : generators;
|
||||
}
|
||||
|
||||
protected double getBiomeHeight(double rx, double rz)
|
||||
{
|
||||
double h = 0;
|
||||
|
||||
for(IrisGenerator i : getGenerators().values())
|
||||
{
|
||||
h += interpolateGenerator(rx, rz, i);
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
protected double interpolateGenerator(double rx, double rz, IrisGenerator gen)
|
||||
{
|
||||
double hi = IrisInterpolation.getNoise(gen.getInterpolationFunction(), (int) Math.round(rx), (int) Math.round(rz), gen.getInterpolationScale(), (xx, zz) ->
|
||||
{
|
||||
IrisBiome b = sampleBiome((int) xx, (int) zz).getBiome();
|
||||
|
||||
for(IrisBiomeGeneratorLink i : b.getGenerators())
|
||||
{
|
||||
if(i.getGenerator().equals(gen.getLoadKey()))
|
||||
{
|
||||
return i.getMax();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
|
||||
double lo = IrisInterpolation.getNoise(gen.getInterpolationFunction(), (int) Math.round(rx), (int) Math.round(rz), gen.getInterpolationScale(), (xx, zz) ->
|
||||
{
|
||||
IrisBiome b = sampleBiome((int) xx, (int) zz).getBiome();
|
||||
|
||||
for(IrisBiomeGeneratorLink i : b.getGenerators())
|
||||
{
|
||||
if(i.getGenerator().equals(gen.getLoadKey()))
|
||||
{
|
||||
return i.getMin();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
|
||||
return M.lerp(lo, hi, gen.getHeight(rx, rz, world.getSeed() + 239945));
|
||||
}
|
||||
|
||||
protected void loadGenerators()
|
||||
{
|
||||
generators.clear();
|
||||
ceilingGenerators.clear();
|
||||
loadGenerators(((CeilingChunkGenerator) this).getFloorDimension());
|
||||
loadGenerators(((CeilingChunkGenerator) this).getCeilingDimension());
|
||||
}
|
||||
|
||||
protected void loadGenerators(IrisDimension dim)
|
||||
{
|
||||
if(dim == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
KList<String> touch = new KList<>();
|
||||
KList<String> loadQueue = new KList<>();
|
||||
|
||||
for(String i : dim.getRegions())
|
||||
{
|
||||
IrisRegion r = Iris.data.getRegionLoader().load(i);
|
||||
|
||||
if(r != null)
|
||||
{
|
||||
loadQueue.addAll(r.getLandBiomes());
|
||||
loadQueue.addAll(r.getSeaBiomes());
|
||||
loadQueue.addAll(r.getShoreBiomes());
|
||||
loadQueue.addAll(r.getRidgeBiomeKeys());
|
||||
loadQueue.addAll(r.getSpotBiomeKeys());
|
||||
}
|
||||
}
|
||||
|
||||
while(!loadQueue.isEmpty())
|
||||
{
|
||||
String next = loadQueue.pop();
|
||||
|
||||
if(!touch.contains(next))
|
||||
{
|
||||
touch.add(next);
|
||||
IrisBiome biome = Iris.data.getBiomeLoader().load(next);
|
||||
biome.getGenerators().forEach((i) -> registerGenerator(i.getCachedGenerator(), dim));
|
||||
loadQueue.addAll(biome.getChildren());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IrisRegion sampleRegion(int x, int z)
|
||||
{
|
||||
double wx = getModifiedX(x, z);
|
||||
double wz = getModifiedZ(x, z);
|
||||
return glBiome.getRegion(wx, wz);
|
||||
}
|
||||
|
||||
public BiomeResult sampleBiome(int x, int z)
|
||||
{
|
||||
if(!getDimension().getFocus().equals(""))
|
||||
{
|
||||
IrisBiome biome = Iris.data.getBiomeLoader().load(getDimension().getFocus());
|
||||
|
||||
for(String i : getDimension().getRegions())
|
||||
{
|
||||
IrisRegion reg = Iris.data.getRegionLoader().load(i);
|
||||
|
||||
if(reg.getLandBiomes().contains(biome.getLoadKey()))
|
||||
{
|
||||
biome.setInferredType(InferredType.LAND);
|
||||
break;
|
||||
}
|
||||
|
||||
if(reg.getSeaBiomes().contains(biome.getLoadKey()))
|
||||
{
|
||||
biome.setInferredType(InferredType.SEA);
|
||||
break;
|
||||
}
|
||||
|
||||
if(reg.getShoreBiomes().contains(biome.getLoadKey()))
|
||||
{
|
||||
biome.setInferredType(InferredType.SHORE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return new BiomeResult(biome, 0);
|
||||
}
|
||||
|
||||
ChunkPosition pos = new ChunkPosition(x, z);
|
||||
|
||||
if(getBiomeHitCache().containsKey(pos))
|
||||
{
|
||||
return getBiomeHitCache().get(pos);
|
||||
}
|
||||
|
||||
double wx = getModifiedX(x, z);
|
||||
double wz = getModifiedZ(x, z);
|
||||
IrisRegion region = glBiome.getRegion(wx, wz);
|
||||
BiomeResult res = glBiome.generateRegionData(wx, wz, x, z, region);
|
||||
getBiomeHitCache().put(pos, res);
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
package ninja.bytecode.iris.generator;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import ninja.bytecode.iris.Iris;
|
||||
import ninja.bytecode.iris.object.IrisDimension;
|
||||
import ninja.bytecode.iris.util.InvertedBiomeGrid;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
|
||||
public abstract class CeilingChunkGenerator extends PostBlockChunkGenerator
|
||||
{
|
||||
protected boolean generatingCeiling = false;
|
||||
protected boolean ceilingCached = false;
|
||||
protected IrisDimension cacheCeiling = null;
|
||||
protected IrisDimension cacheFloor = null;
|
||||
|
||||
public CeilingChunkGenerator(String dimensionName, int threads)
|
||||
{
|
||||
super(dimensionName, threads);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid)
|
||||
{
|
||||
targetFloor();
|
||||
generate(random, x, z, data, grid);
|
||||
|
||||
if(getFloorDimension().isMirrorCeiling())
|
||||
{
|
||||
writeInverted(copy(data), data);
|
||||
}
|
||||
|
||||
else if(getCeilingDimension() != null)
|
||||
{
|
||||
ChunkData ceiling = createChunkData(world);
|
||||
InvertedBiomeGrid ceilingGrid = new InvertedBiomeGrid(grid);
|
||||
targetCeiling();
|
||||
generate(random, x, z, ceiling, ceilingGrid);
|
||||
writeInverted(ceiling, data);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHotload()
|
||||
{
|
||||
super.onHotload();
|
||||
ceilingCached = false;
|
||||
cacheCeiling = null;
|
||||
cacheFloor = null;
|
||||
}
|
||||
|
||||
private void targetFloor()
|
||||
{
|
||||
generatingCeiling = false;
|
||||
}
|
||||
|
||||
private void targetCeiling()
|
||||
{
|
||||
generatingCeiling = true;
|
||||
}
|
||||
|
||||
private void generate(RNG random, int x, int z, ChunkData ceiling, BiomeGrid grid)
|
||||
{
|
||||
super.onGenerate(random, x, z, ceiling, grid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IrisDimension getDimension()
|
||||
{
|
||||
return generatingCeiling ? getCeilingDimension() : getFloorDimension();
|
||||
}
|
||||
|
||||
public IrisDimension getFloorDimension()
|
||||
{
|
||||
if(cacheFloor != null)
|
||||
{
|
||||
return cacheFloor;
|
||||
}
|
||||
|
||||
return cacheFloor = super.getDimension();
|
||||
}
|
||||
|
||||
public IrisDimension getCeilingDimension()
|
||||
{
|
||||
if(ceilingCached)
|
||||
{
|
||||
return cacheCeiling;
|
||||
}
|
||||
|
||||
if(getFloorDimension().getCeiling().isEmpty())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
IrisDimension c = Iris.data.getDimensionLoader().load(getFloorDimension().getCeiling());
|
||||
|
||||
if(c != null)
|
||||
{
|
||||
c.setInverted(true);
|
||||
}
|
||||
|
||||
ceilingCached = true;
|
||||
cacheCeiling = c;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
public void writeInverted(ChunkData data, ChunkData into)
|
||||
{
|
||||
for(int i = 0; i < 16; i++)
|
||||
{
|
||||
for(int j = 0; j < data.getMaxHeight(); j++)
|
||||
{
|
||||
for(int k = 0; k < 16; k++)
|
||||
{
|
||||
BlockData b = data.getBlockData(i, j, k);
|
||||
|
||||
if(b == null || b.getMaterial().equals(Material.AIR))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
into.setBlock(i, data.getMaxHeight() - j, k, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ChunkData copy(ChunkData d)
|
||||
{
|
||||
ChunkData copy = createChunkData(world);
|
||||
|
||||
for(int i = 0; i < 16; i++)
|
||||
{
|
||||
for(int j = 0; j < d.getMaxHeight(); j++)
|
||||
{
|
||||
for(int k = 0; k < 16; k++)
|
||||
{
|
||||
BlockData b = d.getBlockData(i, j, k);
|
||||
|
||||
if(b == null || b.getMaterial().equals(Material.AIR))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
copy.setBlock(i, j, k, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,310 @@
|
||||
package ninja.bytecode.iris.generator;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
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.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||
import org.bukkit.event.world.ChunkLoadEvent;
|
||||
import org.bukkit.event.world.ChunkUnloadEvent;
|
||||
import org.bukkit.event.world.WorldUnloadEvent;
|
||||
import org.bukkit.generator.BlockPopulator;
|
||||
import org.bukkit.generator.ChunkGenerator;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import ninja.bytecode.iris.Iris;
|
||||
import ninja.bytecode.iris.IrisContext;
|
||||
import ninja.bytecode.iris.IrisMetrics;
|
||||
import ninja.bytecode.iris.util.BlockDataTools;
|
||||
import ninja.bytecode.iris.util.CNG;
|
||||
import ninja.bytecode.iris.util.ChronoLatch;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
import ninja.bytecode.shuriken.bench.PrecisionStopwatch;
|
||||
import ninja.bytecode.shuriken.logging.L;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public abstract class ContextualChunkGenerator extends ChunkGenerator implements Listener
|
||||
{
|
||||
protected boolean failing;
|
||||
protected int task;
|
||||
protected boolean initialized;
|
||||
protected RNG masterRandom;
|
||||
protected ChronoLatch perSecond;
|
||||
protected ChronoLatch tickLatch;
|
||||
protected ChronoLatch pushLatch;
|
||||
protected IrisMetrics metrics;
|
||||
protected World world;
|
||||
protected int generated;
|
||||
protected int ticks;
|
||||
protected boolean pregenDone;
|
||||
|
||||
public ContextualChunkGenerator()
|
||||
{
|
||||
pushLatch = new ChronoLatch(3000);
|
||||
tickLatch = new ChronoLatch(650);
|
||||
perSecond = new ChronoLatch(1000);
|
||||
CNG.creates = 0;
|
||||
generated = 0;
|
||||
ticks = 0;
|
||||
task = -1;
|
||||
initialized = false;
|
||||
failing = false;
|
||||
pregenDone = false;
|
||||
}
|
||||
|
||||
protected abstract void onGenerate(RNG masterRandom, int x, int z, ChunkData data, BiomeGrid grid);
|
||||
|
||||
protected abstract void onInit(World world, RNG masterRandom);
|
||||
|
||||
protected abstract void onTick(int ticks);
|
||||
|
||||
protected abstract void onClose();
|
||||
|
||||
protected abstract void onFailure(Throwable e);
|
||||
|
||||
protected abstract void onChunkLoaded(Chunk c);
|
||||
|
||||
protected abstract void onChunkUnloaded(Chunk c);
|
||||
|
||||
protected abstract void onPlayerJoin(Player p);
|
||||
|
||||
protected abstract void onPlayerLeft(Player p);
|
||||
|
||||
private void init(World world, RNG rng)
|
||||
{
|
||||
if(initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.world = world;
|
||||
this.masterRandom = new RNG(world.getSeed());
|
||||
metrics = new IrisMetrics(128);
|
||||
initialized = true;
|
||||
Bukkit.getServer().getPluginManager().registerEvents(this, Iris.instance);
|
||||
task = Bukkit.getScheduler().scheduleSyncRepeatingTask(Iris.instance, this::tick, 0, 0);
|
||||
onInit(world, masterRandom);
|
||||
}
|
||||
|
||||
private void tick()
|
||||
{
|
||||
if(perSecond.flip())
|
||||
{
|
||||
if(generated > 770)
|
||||
{
|
||||
pregenDone = true;
|
||||
}
|
||||
|
||||
if(pregenDone)
|
||||
{
|
||||
metrics.getPerSecond().put(generated);
|
||||
generated = 0;
|
||||
}
|
||||
}
|
||||
|
||||
onTick(ticks++);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void on(PlayerTeleportEvent e)
|
||||
{
|
||||
if(e.getFrom().getWorld().equals(world) && !e.getTo().getWorld().equals(world))
|
||||
{
|
||||
tick();
|
||||
onPlayerLeft(e.getPlayer());
|
||||
}
|
||||
|
||||
if(!e.getFrom().getWorld().equals(world) && e.getTo().getWorld().equals(world))
|
||||
{
|
||||
tick();
|
||||
onPlayerJoin(e.getPlayer());
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void on(PlayerQuitEvent e)
|
||||
{
|
||||
if(e.getPlayer().getWorld().equals(world))
|
||||
{
|
||||
tick();
|
||||
onPlayerLeft(e.getPlayer());
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void on(PlayerJoinEvent e)
|
||||
{
|
||||
if(e.getPlayer().getWorld().equals(world))
|
||||
{
|
||||
tick();
|
||||
onPlayerJoin(e.getPlayer());
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void on(ChunkLoadEvent e)
|
||||
{
|
||||
if(e.getWorld().equals(world))
|
||||
{
|
||||
tick();
|
||||
onChunkLoaded(e.getChunk());
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void on(ChunkUnloadEvent e)
|
||||
{
|
||||
if(e.getWorld().equals(world))
|
||||
{
|
||||
tick();
|
||||
onChunkUnloaded(e.getChunk());
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void on(WorldUnloadEvent e)
|
||||
{
|
||||
if(world != null && e.getWorld().equals(world))
|
||||
{
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
protected void close()
|
||||
{
|
||||
HandlerList.unregisterAll(this);
|
||||
Bukkit.getScheduler().cancelTask(getTask());
|
||||
onClose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSpawn(World world, int x, int z)
|
||||
{
|
||||
return super.canSpawn(world, x, z);
|
||||
}
|
||||
|
||||
protected ChunkData generateChunkDataFailure(World world, Random no, int x, int z, BiomeGrid biomeGrid)
|
||||
{
|
||||
ChunkData c = Bukkit.createChunkData(world);
|
||||
|
||||
for(int i = 0; i < 16; i++)
|
||||
{
|
||||
for(int j = 0; j < 16; j++)
|
||||
{
|
||||
int h = 0;
|
||||
|
||||
if(j == i || j + i == 16)
|
||||
{
|
||||
c.setBlock(i, h, j, BlockDataTools.getBlockData("RED_TERRACOTTA"));
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
c.setBlock(i, h, j, BlockDataTools.getBlockData("BLACK_TERRACOTTA"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChunkData generateChunkData(World world, Random no, int x, int z, BiomeGrid biomeGrid)
|
||||
{
|
||||
PrecisionStopwatch sx = PrecisionStopwatch.start();
|
||||
|
||||
if(failing)
|
||||
{
|
||||
return generateChunkDataFailure(world, no, x, z, biomeGrid);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if(pushLatch.flip())
|
||||
{
|
||||
if(this.world == null)
|
||||
{
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
Iris.hotloader.check((IrisContext) this);
|
||||
|
||||
if(this instanceof IrisContext)
|
||||
{
|
||||
IrisContext.pushContext((IrisContext) this);
|
||||
}
|
||||
}
|
||||
|
||||
PrecisionStopwatch s = PrecisionStopwatch.start();
|
||||
RNG random = new RNG(world.getSeed());
|
||||
init(world, random.nextParallelRNG(0));
|
||||
ChunkData c = Bukkit.createChunkData(world);
|
||||
onGenerate(random, x, z, c, biomeGrid);
|
||||
metrics.getTotal().put(s.getMilliseconds());
|
||||
generated++;
|
||||
long hits = CNG.hits;
|
||||
CNG.hits = 0;
|
||||
Iris.instance.hit(hits);
|
||||
metrics.getLoss().put(sx.getMilliseconds() - s.getMilliseconds());
|
||||
return c;
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
fail(e);
|
||||
}
|
||||
|
||||
return generateChunkDataFailure(world, no, x, z, biomeGrid);
|
||||
}
|
||||
|
||||
public void onHotload()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected void fail(Throwable e)
|
||||
{
|
||||
failing = true;
|
||||
Iris.error("ERROR! Failed to generate chunk! Iris has entered a failed state!");
|
||||
|
||||
for(Player i : world.getPlayers())
|
||||
{
|
||||
Iris.instance.imsg(i, ChatColor.DARK_RED + "Iris Generator has entered a failed state!");
|
||||
Iris.instance.imsg(i, ChatColor.RED + "- Check the console for the error.");
|
||||
Iris.instance.imsg(i, ChatColor.RED + "- Then simply run /iris dev");
|
||||
}
|
||||
|
||||
L.ex(e);
|
||||
onFailure(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BlockPopulator> getDefaultPopulators(World world)
|
||||
{
|
||||
return super.getDefaultPopulators(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getFixedSpawnLocation(World world, Random random)
|
||||
{
|
||||
return super.getFixedSpawnLocation(world, random);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isParallelCapable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package ninja.bytecode.iris.generator;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import ninja.bytecode.iris.Iris;
|
||||
import ninja.bytecode.iris.object.InferredType;
|
||||
import ninja.bytecode.iris.object.IrisBiome;
|
||||
import ninja.bytecode.iris.object.IrisDimension;
|
||||
import ninja.bytecode.iris.object.IrisRegion;
|
||||
import ninja.bytecode.iris.util.BiomeResult;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public abstract class DimensionChunkGenerator extends ContextualChunkGenerator
|
||||
{
|
||||
protected final String dimensionName;
|
||||
protected static final BlockData AIR = Material.AIR.createBlockData();
|
||||
protected static final BlockData BEDROCK = Material.BEDROCK.createBlockData();
|
||||
|
||||
public DimensionChunkGenerator(String dimensionName)
|
||||
{
|
||||
super();
|
||||
this.dimensionName = dimensionName;
|
||||
}
|
||||
|
||||
public IrisDimension getDimension()
|
||||
{
|
||||
IrisDimension d = Iris.data.getDimensionLoader().load(dimensionName);
|
||||
|
||||
if(d == null)
|
||||
{
|
||||
Iris.error("Can't find dimension: " + dimensionName);
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
protected BiomeResult focus()
|
||||
{
|
||||
IrisBiome biome = Iris.data.getBiomeLoader().load(getDimension().getFocus());
|
||||
|
||||
for(String i : getDimension().getRegions())
|
||||
{
|
||||
IrisRegion reg = Iris.data.getRegionLoader().load(i);
|
||||
|
||||
if(reg.getLandBiomes().contains(biome.getLoadKey()))
|
||||
{
|
||||
biome.setInferredType(InferredType.LAND);
|
||||
break;
|
||||
}
|
||||
|
||||
if(reg.getSeaBiomes().contains(biome.getLoadKey()))
|
||||
{
|
||||
biome.setInferredType(InferredType.SEA);
|
||||
break;
|
||||
}
|
||||
|
||||
if(reg.getShoreBiomes().contains(biome.getLoadKey()))
|
||||
{
|
||||
biome.setInferredType(InferredType.SHORE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return new BiomeResult(biome, 0);
|
||||
}
|
||||
|
||||
public double getModifiedX(int rx, int rz)
|
||||
{
|
||||
return (getDimension().cosRotate() * rx) + (-getDimension().sinRotate() * rz) +
|
||||
|
||||
getDimension().getCoordFracture(masterRandom, 39392).fitDoubleD(-getDimension().getCoordFractureDistance() / 2, getDimension().getCoordFractureDistance() / 2, rx, rz);
|
||||
}
|
||||
|
||||
public double getModifiedZ(int rx, int rz)
|
||||
{
|
||||
return (getDimension().sinRotate() * rx) + (getDimension().cosRotate() * rz) +
|
||||
|
||||
getDimension().getCoordFracture(masterRandom, 39392).fitDoubleD(-getDimension().getCoordFractureDistance() / 2, getDimension().getCoordFractureDistance() / 2, rx, rz);
|
||||
}
|
||||
|
||||
public double getZoomed(double modified)
|
||||
{
|
||||
return (double) (modified) / getDimension().getTerrainZoom();
|
||||
}
|
||||
|
||||
public double getUnzoomed(double modified)
|
||||
{
|
||||
return (double) (modified) * getDimension().getTerrainZoom();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package ninja.bytecode.iris.generator;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import ninja.bytecode.iris.Iris;
|
||||
import ninja.bytecode.iris.IrisContext;
|
||||
import ninja.bytecode.iris.object.IrisBiome;
|
||||
import ninja.bytecode.iris.object.IrisRegion;
|
||||
import ninja.bytecode.iris.util.BiomeResult;
|
||||
import ninja.bytecode.shuriken.collections.KMap;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class IrisChunkGenerator extends CeilingChunkGenerator implements IrisContext
|
||||
{
|
||||
private Method initLighting;
|
||||
private KMap<Player, IrisBiome> b = new KMap<>();
|
||||
|
||||
public IrisChunkGenerator(String dimensionName, int threads)
|
||||
{
|
||||
super(dimensionName, threads);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeResult getBiome(int x, int z)
|
||||
{
|
||||
return sampleBiome(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IrisRegion getRegion(int x, int z)
|
||||
{
|
||||
return sampleRegion(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight(int x, int z)
|
||||
{
|
||||
return sampleHeight(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTick(int ticks)
|
||||
{
|
||||
super.onTick(ticks);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onClose()
|
||||
{
|
||||
super.onClose();
|
||||
Iris.info("Closing Iris Dimension " + getWorld().getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFailure(Throwable e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onChunkLoaded(Chunk c)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onChunkUnloaded(Chunk c)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPlayerJoin(Player p)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPlayerLeft(Player p)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHotloaded()
|
||||
{
|
||||
onHotload();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,309 @@
|
||||
package ninja.bytecode.iris.generator;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import ninja.bytecode.iris.Iris;
|
||||
import ninja.bytecode.iris.object.IrisBiome;
|
||||
import ninja.bytecode.iris.object.IrisDepositGenerator;
|
||||
import ninja.bytecode.iris.object.IrisObjectPlacement;
|
||||
import ninja.bytecode.iris.object.IrisRegion;
|
||||
import ninja.bytecode.iris.object.atomics.AtomicSliver;
|
||||
import ninja.bytecode.iris.object.atomics.AtomicSliverMap;
|
||||
import ninja.bytecode.iris.object.atomics.AtomicWorldData;
|
||||
import ninja.bytecode.iris.object.atomics.MasterLock;
|
||||
import ninja.bytecode.iris.util.BiomeMap;
|
||||
import ninja.bytecode.iris.util.ChunkPosition;
|
||||
import ninja.bytecode.iris.util.HeightMap;
|
||||
import ninja.bytecode.iris.util.IObjectPlacer;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
import ninja.bytecode.shuriken.collections.KMap;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public abstract class ParallaxChunkGenerator extends TerrainChunkGenerator implements IObjectPlacer
|
||||
{
|
||||
private KMap<ChunkPosition, AtomicSliver> sliverCache;
|
||||
protected AtomicWorldData parallaxMap;
|
||||
private KMap<ChunkPosition, AtomicSliver> ceilingSliverCache;
|
||||
protected AtomicWorldData ceilingParallaxMap;
|
||||
private MasterLock masterLock;
|
||||
private ReentrantLock lock = new ReentrantLock();
|
||||
private int sliverBuffer;
|
||||
|
||||
public ParallaxChunkGenerator(String dimensionName, int threads)
|
||||
{
|
||||
super(dimensionName, threads);
|
||||
sliverCache = new KMap<>();
|
||||
ceilingSliverCache = new KMap<>();
|
||||
sliverBuffer = 0;
|
||||
masterLock = new MasterLock();
|
||||
}
|
||||
|
||||
public void onInit(World world, RNG rng)
|
||||
{
|
||||
super.onInit(world, rng);
|
||||
parallaxMap = new AtomicWorldData(world, "floor");
|
||||
ceilingParallaxMap = new AtomicWorldData(world, "ceiling");
|
||||
}
|
||||
|
||||
protected KMap<ChunkPosition, AtomicSliver> getSliverCache()
|
||||
{
|
||||
return getDimension().isInverted() ? ceilingSliverCache : sliverCache;
|
||||
}
|
||||
|
||||
protected void onClose()
|
||||
{
|
||||
super.onClose();
|
||||
|
||||
try
|
||||
{
|
||||
parallaxMap.unloadAll(true);
|
||||
ceilingParallaxMap.unloadAll(true);
|
||||
}
|
||||
|
||||
catch(IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHighest(int x, int z)
|
||||
{
|
||||
return getHighest(x, z, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHighest(int x, int z, boolean ignoreFluid)
|
||||
{
|
||||
return (int) Math.round(ignoreFluid ? getTerrainHeight(x, z) : getTerrainWaterHeight(x, z));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(int x, int y, int z, BlockData d)
|
||||
{
|
||||
getMasterLock().lock((x >> 4) + "." + (z >> 4));
|
||||
getParallaxSliver(x, z).set(y, d);
|
||||
getMasterLock().unlock((x >> 4) + "." + (z >> 4));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockData get(int x, int y, int z)
|
||||
{
|
||||
BlockData b = sampleSliver(x, z).getBlock().get(y);
|
||||
return b == null ? AIR : b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSolid(int x, int y, int z)
|
||||
{
|
||||
return get(x, y, z).getMaterial().isSolid();
|
||||
}
|
||||
|
||||
public AtomicSliver getParallaxSliver(int wx, int wz)
|
||||
{
|
||||
getMasterLock().lock("gpc");
|
||||
getMasterLock().lock((wx >> 4) + "." + (wz >> 4));
|
||||
AtomicSliverMap map = getParallaxChunk(wx >> 4, wz >> 4);
|
||||
getMasterLock().unlock("gpc");
|
||||
AtomicSliver sliver = map.getSliver(wx & 15, wz & 15);
|
||||
getMasterLock().unlock((wx >> 4) + "." + (wz >> 4));
|
||||
|
||||
return sliver;
|
||||
}
|
||||
|
||||
public boolean isParallaxGenerated(int x, int z)
|
||||
{
|
||||
return getParallaxChunk(x, z).isParallaxGenerated();
|
||||
}
|
||||
|
||||
public boolean isWorldGenerated(int x, int z)
|
||||
{
|
||||
return getParallaxChunk(x, z).isWorldGenerated();
|
||||
}
|
||||
|
||||
public AtomicWorldData getParallaxMap()
|
||||
{
|
||||
return getDimension().isInverted() ? ceilingParallaxMap : parallaxMap;
|
||||
}
|
||||
|
||||
public AtomicSliverMap getParallaxChunk(int x, int z)
|
||||
{
|
||||
try
|
||||
{
|
||||
return getParallaxMap().loadChunk(x, z);
|
||||
}
|
||||
|
||||
catch(IOException e)
|
||||
{
|
||||
fail(e);
|
||||
}
|
||||
|
||||
return new AtomicSliverMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid, HeightMap height, BiomeMap biomeMap)
|
||||
{
|
||||
super.onPostGenerate(random, x, z, data, grid, height, biomeMap);
|
||||
getBiomeHitCache().clear();
|
||||
|
||||
if(getDimension().isPlaceObjects())
|
||||
{
|
||||
onGenerateParallax(random, x, z);
|
||||
injectBiomeSky(x, z, grid);
|
||||
getParallaxChunk(x, z).inject(data);
|
||||
setSliverBuffer(getSliverCache().size());
|
||||
getParallaxChunk(x, z).setWorldGenerated(true);
|
||||
getSliverCache().clear();
|
||||
getMasterLock().clear();
|
||||
}
|
||||
|
||||
super.onPostParallaxPostGenerate(random, x, z, data, grid, height, biomeMap);
|
||||
}
|
||||
|
||||
protected void injectBiomeSky(int x, int z, BiomeGrid grid)
|
||||
{
|
||||
if(getDimension().isInverted())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int rx;
|
||||
int rz;
|
||||
|
||||
for(int i = 0; i < 16; i++)
|
||||
{
|
||||
rx = (x * 16) + i;
|
||||
for(int j = 0; j < 16; j++)
|
||||
{
|
||||
rz = (z * 16) + j;
|
||||
|
||||
int min = sampleSliver(rx, rz).getHighestBiome();
|
||||
int max = getParallaxSliver(rx, rz).getHighestBlock();
|
||||
|
||||
if(min < max)
|
||||
{
|
||||
IrisBiome biome = getCachedBiome(i, j);
|
||||
|
||||
for(int g = min; g <= max; g++)
|
||||
{
|
||||
grid.setBiome(i, g, j, biome.getSkyBiome(masterRandom, rz, g, rx));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void onGenerateParallax(RNG random, int x, int z)
|
||||
{
|
||||
String key = "par." + x + "." + "z";
|
||||
ChunkPosition rad = Iris.data.getObjectLoader().getParallaxSize();
|
||||
|
||||
for(int ii = x - (rad.getX() / 2); ii <= x + (rad.getX() / 2); ii++)
|
||||
{
|
||||
int i = ii;
|
||||
|
||||
for(int jj = z - (rad.getZ() / 2); jj <= z + (rad.getZ() / 2); jj++)
|
||||
{
|
||||
int j = jj;
|
||||
|
||||
if(isParallaxGenerated(ii, jj))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if(isWorldGenerated(ii, jj))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
getAccelerant().queue(key, () ->
|
||||
{
|
||||
IrisBiome b = sampleTrueBiome((i * 16) + 7, (j * 16) + 7).getBiome();
|
||||
IrisRegion r = sampleRegion((i * 16) + 7, (j * 16) + 7);
|
||||
RNG ro = random.nextParallelRNG(496888 + i + j);
|
||||
|
||||
int g = 1;
|
||||
|
||||
for(IrisObjectPlacement k : b.getObjects())
|
||||
{
|
||||
placeObject(k, i, j, random.nextParallelRNG((34 * ((i * 30) + (j * 30) + g++) * i * j) + i - j + 3569222));
|
||||
}
|
||||
|
||||
for(IrisDepositGenerator k : getDimension().getDeposits())
|
||||
{
|
||||
for(int l = 0; l < ro.i(k.getMinPerChunk(), k.getMaxPerChunk()); l++)
|
||||
{
|
||||
k.generate((x * 16) + ro.nextInt(16), (z * 16) + ro.nextInt(16), ro, this);
|
||||
}
|
||||
}
|
||||
|
||||
for(IrisDepositGenerator k : r.getDeposits())
|
||||
{
|
||||
for(int l = 0; l < ro.i(k.getMinPerChunk(), k.getMaxPerChunk()); l++)
|
||||
{
|
||||
k.generate((x * 16) + ro.nextInt(16), (z * 16) + ro.nextInt(16), ro, this);
|
||||
}
|
||||
}
|
||||
|
||||
for(IrisDepositGenerator k : b.getDeposits())
|
||||
{
|
||||
for(int l = 0; l < ro.i(k.getMinPerChunk(), k.getMaxPerChunk()); l++)
|
||||
{
|
||||
k.generate((x * 16) + ro.nextInt(16), (z * 16) + ro.nextInt(16), ro, this);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
getParallaxChunk(ii, jj).setParallaxGenerated(true);
|
||||
}
|
||||
}
|
||||
|
||||
getAccelerant().waitFor(key);
|
||||
}
|
||||
|
||||
public void placeObject(IrisObjectPlacement o, int x, int z, RNG rng)
|
||||
{
|
||||
for(int i = 0; i < o.getTriesForChunk(rng); i++)
|
||||
{
|
||||
rng = rng.nextParallelRNG((i * 3 + 8) - 23040);
|
||||
o.getSchematic(rng).place((x * 16) + rng.nextInt(16), (z * 16) + rng.nextInt(16), this, o, rng);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTick(int ticks)
|
||||
{
|
||||
getParallaxMap().clean(ticks);
|
||||
Iris.data.getObjectLoader().clean();
|
||||
}
|
||||
|
||||
public AtomicSliver sampleSliver(int x, int z)
|
||||
{
|
||||
ChunkPosition key = new ChunkPosition(x, z);
|
||||
|
||||
if(getSliverCache().containsKey(key))
|
||||
{
|
||||
return getSliverCache().get(key);
|
||||
}
|
||||
|
||||
AtomicSliver s = new AtomicSliver(x & 15, z & 15);
|
||||
onGenerateColumn(x >> 4, z >> 4, x, z, x & 15, z & 15, s, null);
|
||||
getSliverCache().put(key, s);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPreventingDecay()
|
||||
{
|
||||
return getDimension().isPreventLeafDecay();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package ninja.bytecode.iris.generator;
|
||||
|
||||
import org.bukkit.World;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import ninja.bytecode.iris.Iris;
|
||||
import ninja.bytecode.iris.object.atomics.AtomicSliver;
|
||||
import ninja.bytecode.iris.object.atomics.AtomicSliverMap;
|
||||
import ninja.bytecode.iris.util.BiomeMap;
|
||||
import ninja.bytecode.iris.util.GroupedExecutor;
|
||||
import ninja.bytecode.iris.util.HeightMap;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public abstract class ParallelChunkGenerator extends BiomeChunkGenerator
|
||||
{
|
||||
private GroupedExecutor accelerant;
|
||||
private int threads;
|
||||
|
||||
public ParallelChunkGenerator(String dimensionName, int threads)
|
||||
{
|
||||
super(dimensionName);
|
||||
this.threads = threads;
|
||||
}
|
||||
|
||||
public void changeThreadCount(int tc)
|
||||
{
|
||||
threads = tc;
|
||||
GroupedExecutor e = accelerant;
|
||||
accelerant = new GroupedExecutor(threads, Thread.NORM_PRIORITY, "Iris Generator - " + world.getName());
|
||||
Iris.executors.add(accelerant);
|
||||
|
||||
if(e != null)
|
||||
{
|
||||
e.close();
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void onGenerateColumn(int cx, int cz, int wx, int wz, int x, int z, AtomicSliver sliver, BiomeMap biomeMap);
|
||||
|
||||
protected abstract int onSampleColumnHeight(int cx, int cz, int wx, int wz, int x, int z);
|
||||
|
||||
protected abstract void onPostGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid, HeightMap height, BiomeMap biomeMap);
|
||||
|
||||
protected int sampleHeight(int x, int z)
|
||||
{
|
||||
return onSampleColumnHeight(x >> 4, z >> 4, x, z, x & 15, z & 15);
|
||||
}
|
||||
|
||||
protected void onGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid)
|
||||
{
|
||||
AtomicSliverMap map = new AtomicSliverMap();
|
||||
HeightMap height = new HeightMap();
|
||||
String key = "c" + x + "," + z;
|
||||
BiomeMap biomeMap = new BiomeMap();
|
||||
int ii, jj;
|
||||
|
||||
for(ii = 0; ii < 16; ii++)
|
||||
{
|
||||
int i = ii;
|
||||
int wx = (x * 16) + i;
|
||||
|
||||
for(jj = 0; jj < 16; jj++)
|
||||
{
|
||||
int j = jj;
|
||||
int wz = (z * 16) + j;
|
||||
AtomicSliver sliver = map.getSliver(i, j);
|
||||
|
||||
accelerant.queue(key, () ->
|
||||
{
|
||||
onGenerateColumn(x, z, wx, wz, i, j, sliver, biomeMap);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
accelerant.waitFor(key);
|
||||
map.write(data, grid, height);
|
||||
onPostGenerate(random, x, z, data, grid, height, biomeMap);
|
||||
}
|
||||
|
||||
protected void onClose()
|
||||
{
|
||||
accelerant.close();
|
||||
}
|
||||
|
||||
public void onInit(World world, RNG rng)
|
||||
{
|
||||
super.onInit(world, rng);
|
||||
changeThreadCount(threads);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isParallelCapable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
package ninja.bytecode.iris.generator;
|
||||
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import ninja.bytecode.iris.Iris;
|
||||
import ninja.bytecode.iris.layer.post.PostNippleSmoother;
|
||||
import ninja.bytecode.iris.layer.post.PostPotholeFiller;
|
||||
import ninja.bytecode.iris.layer.post.PostSlabber;
|
||||
import ninja.bytecode.iris.layer.post.PostWallPatcher;
|
||||
import ninja.bytecode.iris.object.IrisDimension;
|
||||
import ninja.bytecode.iris.util.IPostBlockAccess;
|
||||
import ninja.bytecode.iris.util.IrisPostBlockFilter;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
|
||||
public abstract class PostBlockChunkGenerator extends ParallaxChunkGenerator implements IPostBlockAccess
|
||||
{
|
||||
protected boolean generatingCeiling = false;
|
||||
protected boolean ceilingCached = false;
|
||||
protected IrisDimension cacheCeiling = null;
|
||||
protected IrisDimension cacheFloor = null;
|
||||
private int currentPostX;
|
||||
private int currentPostZ;
|
||||
private ChunkData currentData;
|
||||
private KList<IrisPostBlockFilter> filters;
|
||||
private String postKey;
|
||||
private ReentrantLock lock;
|
||||
|
||||
public PostBlockChunkGenerator(String dimensionName, int threads)
|
||||
{
|
||||
super(dimensionName, threads);
|
||||
filters = new KList<>();
|
||||
postKey = "post-" + dimensionName;
|
||||
lock = new ReentrantLock();
|
||||
}
|
||||
|
||||
public void onInit(World world, RNG rng)
|
||||
{
|
||||
super.onInit(world, rng);
|
||||
filters.add(new PostNippleSmoother(this));
|
||||
filters.add(new PostPotholeFiller(this));
|
||||
filters.add(new PostWallPatcher(this));
|
||||
filters.add(new PostSlabber(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid)
|
||||
{
|
||||
super.onGenerate(random, x, z, data, grid);
|
||||
|
||||
if(!getDimension().isPostProcess())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
currentData = data;
|
||||
currentPostX = x;
|
||||
currentPostZ = z;
|
||||
int rx, i, j;
|
||||
|
||||
for(i = 0; i < 16; i++)
|
||||
{
|
||||
rx = (x * 16) + i;
|
||||
|
||||
for(j = 0; j < 16; j++)
|
||||
{
|
||||
int rxx = rx;
|
||||
int rzz = (z * 16) + j;
|
||||
|
||||
getAccelerant().queue(postKey, () ->
|
||||
{
|
||||
for(IrisPostBlockFilter f : filters)
|
||||
{
|
||||
int rxxx = rxx;
|
||||
int rzzx = rzz;
|
||||
|
||||
f.onPost(rxxx, rzzx);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
getAccelerant().waitFor(postKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockData getPostBlock(int x, int y, int z)
|
||||
{
|
||||
if(x >> 4 == currentPostX && z >> 4 == currentPostZ)
|
||||
{
|
||||
lock.lock();
|
||||
BlockData d = currentData.getBlockData(x & 15, y, z & 15);
|
||||
lock.unlock();
|
||||
return d == null ? AIR : d;
|
||||
}
|
||||
|
||||
return sampleSliver(x, z).get(y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPostBlock(int x, int y, int z, BlockData d)
|
||||
{
|
||||
if(x >> 4 == currentPostX && z >> 4 == currentPostZ)
|
||||
{
|
||||
lock.lock();
|
||||
currentData.setBlock(x & 15, y, z & 15, d);
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
Iris.warn("Post Block Overdraw: " + currentPostX + "," + currentPostZ + " into " + (x >> 4) + ", " + (z >> 4));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int highestTerrainOrFluidBlock(int x, int z)
|
||||
{
|
||||
return getHighest(x, z, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int highestTerrainBlock(int x, int z)
|
||||
{
|
||||
return getHighest(x, z, true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,386 @@
|
||||
package ninja.bytecode.iris.generator;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.data.Bisected;
|
||||
import org.bukkit.block.data.Bisected.Half;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import ninja.bytecode.iris.layer.GenLayerCave;
|
||||
import ninja.bytecode.iris.object.DecorationPart;
|
||||
import ninja.bytecode.iris.object.InferredType;
|
||||
import ninja.bytecode.iris.object.IrisBiome;
|
||||
import ninja.bytecode.iris.object.IrisBiomeDecorator;
|
||||
import ninja.bytecode.iris.object.IrisRegion;
|
||||
import ninja.bytecode.iris.object.atomics.AtomicSliver;
|
||||
import ninja.bytecode.iris.util.BiomeMap;
|
||||
import ninja.bytecode.iris.util.BiomeResult;
|
||||
import ninja.bytecode.iris.util.BlockDataTools;
|
||||
import ninja.bytecode.iris.util.HeightMap;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
import ninja.bytecode.shuriken.math.M;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public abstract class TerrainChunkGenerator extends ParallelChunkGenerator
|
||||
{
|
||||
private long lastUpdateRequest = M.ms();
|
||||
private long lastChunkLoad = M.ms();
|
||||
private GenLayerCave glCave;
|
||||
private RNG rockRandom;
|
||||
|
||||
public TerrainChunkGenerator(String dimensionName, int threads)
|
||||
{
|
||||
super(dimensionName, threads);
|
||||
}
|
||||
|
||||
public void onInit(World world, RNG rng)
|
||||
{
|
||||
super.onInit(world, rng);
|
||||
rockRandom = getMasterRandom().nextParallelRNG(2858678);
|
||||
glCave = new GenLayerCave(this, rng.nextParallelRNG(238948));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onGenerateColumn(int cx, int cz, int rx, int rz, int x, int z, AtomicSliver sliver, BiomeMap biomeMap)
|
||||
{
|
||||
try
|
||||
{
|
||||
BlockData block;
|
||||
int fluidHeight = getDimension().getFluidHeight();
|
||||
double ox = getModifiedX(rx, rz);
|
||||
double oz = getModifiedZ(rx, rz);
|
||||
double wx = getZoomed(ox);
|
||||
double wz = getZoomed(oz);
|
||||
int depth = 0;
|
||||
double noise = getNoiseHeight(rx, rz);
|
||||
int height = (int) Math.round(noise) + fluidHeight;
|
||||
IrisBiome biome = sampleTrueBiome(rx, rz).getBiome();
|
||||
KList<BlockData> layers = biome.generateLayers(wx, wz, masterRandom, height, height - getFluidHeight());
|
||||
KList<BlockData> seaLayers = biome.isSea() ? biome.generateSeaLayers(wx, wz, masterRandom, fluidHeight - height) : new KList<>();
|
||||
cacheBiome(x, z, biome);
|
||||
|
||||
for(int k = Math.max(height, fluidHeight); k < Math.max(height, fluidHeight) + 3; k++)
|
||||
{
|
||||
if(k < Math.max(height, fluidHeight) + 3)
|
||||
{
|
||||
if(biomeMap != null)
|
||||
{
|
||||
sliver.set(k, biome.getGroundBiome(masterRandom, rz, k, rx));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(int k = Math.max(height, fluidHeight); k >= 0; k--)
|
||||
{
|
||||
if(k == 0)
|
||||
{
|
||||
sliver.set(0, BEDROCK);
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean underwater = k > height && k <= fluidHeight;
|
||||
|
||||
if(biomeMap != null)
|
||||
{
|
||||
sliver.set(k, biome.getGroundBiome(masterRandom, rz, k, rx));
|
||||
biomeMap.setBiome(x, z, biome);
|
||||
}
|
||||
|
||||
if(underwater)
|
||||
{
|
||||
block = seaLayers.hasIndex(fluidHeight - k) ? layers.get(depth) : getDimension().getFluid(rockRandom, wx, k, wz);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
block = layers.hasIndex(depth) ? layers.get(depth) : getDimension().getRock(rockRandom, wx, k, wz);
|
||||
depth++;
|
||||
}
|
||||
|
||||
sliver.set(k, block);
|
||||
|
||||
if(k == height && block.getMaterial().isSolid() && k < fluidHeight)
|
||||
{
|
||||
decorateUnderwater(biome, sliver, wx, k, wz, rx, rz, block);
|
||||
}
|
||||
|
||||
if(k == Math.max(height, fluidHeight) && block.getMaterial().isSolid() && k < 255 && k > fluidHeight)
|
||||
{
|
||||
decorateLand(biome, sliver, wx, k, wz, rx, rz, block);
|
||||
}
|
||||
}
|
||||
|
||||
glCave.genCaves(rx, rz, x, z, sliver);
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
fail(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean canPlace(Material mat, Material onto)
|
||||
{
|
||||
if(onto.equals(Material.GRASS_PATH))
|
||||
{
|
||||
if(!mat.isSolid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(onto.equals(Material.ACACIA_LEAVES) || onto.equals(Material.BIRCH_LEAVES) || onto.equals(Material.DARK_OAK_LEAVES) || onto.equals(Material.JUNGLE_LEAVES) || onto.equals(Material.OAK_LEAVES) || onto.equals(Material.SPRUCE_LEAVES))
|
||||
{
|
||||
if(!mat.isSolid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void decorateLand(IrisBiome biome, AtomicSliver sliver, double wx, int k, double wz, int rx, int rz, BlockData block)
|
||||
{
|
||||
if(!getDimension().isDecorate())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int j = 0;
|
||||
|
||||
for(IrisBiomeDecorator i : biome.getDecorators())
|
||||
{
|
||||
if(i.getPartOf().equals(DecorationPart.SHORE_LINE) && !touchesSea(rx, rz))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
BlockData d = i.getBlockData(getMasterRandom().nextParallelRNG(biome.hashCode() + j++), wx, wz);
|
||||
|
||||
if(d != null)
|
||||
{
|
||||
if(!canPlace(d.getMaterial(), block.getMaterial()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if(d.getMaterial().equals(Material.CACTUS))
|
||||
{
|
||||
if(!block.getMaterial().equals(Material.SAND) && !block.getMaterial().equals(Material.RED_SAND))
|
||||
{
|
||||
sliver.set(k, BlockDataTools.getBlockData("RED_SAND"));
|
||||
}
|
||||
}
|
||||
|
||||
if(d instanceof Bisected && k < 254)
|
||||
{
|
||||
Bisected t = ((Bisected) d.clone());
|
||||
t.setHalf(Half.TOP);
|
||||
Bisected b = ((Bisected) d.clone());
|
||||
b.setHalf(Half.BOTTOM);
|
||||
sliver.set(k + 1, b);
|
||||
sliver.set(k + 2, t);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
int stack = i.getHeight(getMasterRandom().nextParallelRNG(39456 + i.hashCode()), wx, wz);
|
||||
|
||||
if(stack == 1)
|
||||
{
|
||||
sliver.set(k + 1, d);
|
||||
}
|
||||
|
||||
else if(k < 255 - stack)
|
||||
{
|
||||
for(int l = 0; l < stack; l++)
|
||||
{
|
||||
sliver.set(k + l + 1, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void decorateUnderwater(IrisBiome biome, AtomicSliver sliver, double wx, int y, double wz, int rx, int rz, BlockData block)
|
||||
{
|
||||
if(!getDimension().isDecorate())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int j = 0;
|
||||
|
||||
for(IrisBiomeDecorator i : biome.getDecorators())
|
||||
{
|
||||
if(biome.getInferredType().equals(InferredType.SHORE))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
BlockData d = i.getBlockData(getMasterRandom().nextParallelRNG(biome.hashCode() + j++), wx, wz);
|
||||
|
||||
if(d != null)
|
||||
{
|
||||
int stack = i.getHeight(getMasterRandom().nextParallelRNG(39456 + i.hashCode()), wx, wz);
|
||||
|
||||
if(stack == 1)
|
||||
{
|
||||
sliver.set(i.getPartOf().equals(DecorationPart.SEA_SURFACE) ? (getFluidHeight() + 1) : (y + 1), d);
|
||||
}
|
||||
|
||||
else if(y < getFluidHeight() - stack)
|
||||
{
|
||||
for(int l = 0; l < stack; l++)
|
||||
{
|
||||
sliver.set(i.getPartOf().equals(DecorationPart.SEA_SURFACE) ? (getFluidHeight() + 1 + l) : (y + l + 1), d);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid, HeightMap height, BiomeMap biomeMap)
|
||||
{
|
||||
onPreParallaxPostGenerate(random, x, z, data, grid, height, biomeMap);
|
||||
}
|
||||
|
||||
protected void onPreParallaxPostGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid, HeightMap height, BiomeMap biomeMap)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected void onPostParallaxPostGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid, HeightMap height, BiomeMap biomeMap)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected double getNoiseHeight(int rx, int rz)
|
||||
{
|
||||
double wx = getZoomed(rx);
|
||||
double wz = getZoomed(rz);
|
||||
|
||||
return getBiomeHeight(wx, wz);
|
||||
}
|
||||
|
||||
public BiomeResult sampleTrueBiomeBase(int x, int z)
|
||||
{
|
||||
if(!getDimension().getFocus().equals(""))
|
||||
{
|
||||
return focus();
|
||||
}
|
||||
|
||||
double wx = getModifiedX(x, z);
|
||||
double wz = getModifiedZ(x, z);
|
||||
IrisRegion region = sampleRegion(x, z);
|
||||
int height = (int) Math.round(getTerrainHeight(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, x, z, region);
|
||||
}
|
||||
|
||||
// Stop land & shore from spawning underwater
|
||||
if(current.isShore() || current.isLand() && height <= getDimension().getFluidHeight())
|
||||
{
|
||||
return glBiome.generateSeaData(wx, wz, x, z, region);
|
||||
}
|
||||
|
||||
// Stop oceans from spawning on land
|
||||
if(current.isSea() && height > getDimension().getFluidHeight())
|
||||
{
|
||||
return glBiome.generateLandData(wx, wz, x, z, region);
|
||||
}
|
||||
|
||||
// Stop land from spawning underwater
|
||||
if(height <= getDimension().getFluidHeight())
|
||||
{
|
||||
return glBiome.generateSeaData(wx, wz, x, z, region);
|
||||
}
|
||||
|
||||
// Stop land from spawning where shores go
|
||||
if(height <= getDimension().getFluidHeight() + sh)
|
||||
{
|
||||
return glBiome.generateShoreData(wx, wz, x, z, region);
|
||||
}
|
||||
|
||||
return glBiome.generateRegionData(wx, wz, x, z, region);
|
||||
}
|
||||
|
||||
public BiomeResult sampleTrueBiome(int x, int z)
|
||||
{
|
||||
if(!getDimension().getFocus().equals(""))
|
||||
{
|
||||
return focus();
|
||||
}
|
||||
|
||||
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);
|
||||
BiomeResult res = sampleTrueBiomeBase(x, z);
|
||||
IrisBiome current = res.getBiome();
|
||||
|
||||
// Stop oceans from spawning on the first level of beach
|
||||
if(current.isSea() && height > getDimension().getFluidHeight() - sh)
|
||||
{
|
||||
return glBiome.generateShoreData(wx, wz, x, z, region);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int onSampleColumnHeight(int cx, int cz, int rx, int rz, int x, int z)
|
||||
{
|
||||
int fluidHeight = getDimension().getFluidHeight();
|
||||
double noise = getNoiseHeight(rx, rz);
|
||||
|
||||
return (int) Math.round(noise) + fluidHeight;
|
||||
}
|
||||
|
||||
private boolean touchesSea(int rx, int rz)
|
||||
{
|
||||
return isFluidAtHeight(rx + 1, rz) || isFluidAtHeight(rx - 1, rz) || isFluidAtHeight(rx, rz - 1) || isFluidAtHeight(rx, rz + 1);
|
||||
}
|
||||
|
||||
public boolean isUnderwater(int x, int z)
|
||||
{
|
||||
return isFluidAtHeight(x, z);
|
||||
}
|
||||
|
||||
public boolean isFluidAtHeight(int x, int z)
|
||||
{
|
||||
return Math.round(getTerrainHeight(x, z)) < getFluidHeight();
|
||||
}
|
||||
|
||||
public int getFluidHeight()
|
||||
{
|
||||
return getDimension().getFluidHeight();
|
||||
}
|
||||
|
||||
public double getTerrainHeight(int x, int z)
|
||||
{
|
||||
return getNoiseHeight(x, z) + getFluidHeight();
|
||||
}
|
||||
|
||||
public double getTerrainWaterHeight(int x, int z)
|
||||
{
|
||||
return Math.max(getTerrainHeight(x, z), getFluidHeight());
|
||||
}
|
||||
}
|
||||
182
src/main/java/com/volmit/iris/layer/GenLayerBiome.java
Normal file
182
src/main/java/com/volmit/iris/layer/GenLayerBiome.java
Normal file
@@ -0,0 +1,182 @@
|
||||
package ninja.bytecode.iris.layer;
|
||||
|
||||
import ninja.bytecode.iris.Iris;
|
||||
import ninja.bytecode.iris.generator.DimensionChunkGenerator;
|
||||
import ninja.bytecode.iris.object.InferredType;
|
||||
import ninja.bytecode.iris.object.IrisBiome;
|
||||
import ninja.bytecode.iris.object.IrisRegion;
|
||||
import ninja.bytecode.iris.object.IrisRegionRidge;
|
||||
import ninja.bytecode.iris.object.IrisRegionSpot;
|
||||
import ninja.bytecode.iris.util.BiomeResult;
|
||||
import ninja.bytecode.iris.util.CellGenerator;
|
||||
import ninja.bytecode.iris.util.GenLayer;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
|
||||
public class GenLayerBiome extends GenLayer
|
||||
{
|
||||
private CellGenerator region;
|
||||
private CellGenerator bridge;
|
||||
private CellGenerator land;
|
||||
private CellGenerator shore;
|
||||
private CellGenerator sea;
|
||||
private DimensionChunkGenerator iris;
|
||||
|
||||
public GenLayerBiome(DimensionChunkGenerator iris, RNG rng)
|
||||
{
|
||||
super(iris, rng);
|
||||
this.iris = iris;
|
||||
region = new CellGenerator(rng.nextParallelRNG(1188519));
|
||||
bridge = new CellGenerator(rng.nextParallelRNG(1541462));
|
||||
land = new CellGenerator(rng.nextParallelRNG(9045162));
|
||||
shore = new CellGenerator(rng.nextParallelRNG(2342812));
|
||||
sea = new CellGenerator(rng.nextParallelRNG(6135621));
|
||||
}
|
||||
|
||||
public IrisRegion getRegion(double bx, double bz)
|
||||
{
|
||||
region.setShuffle(8);
|
||||
region.setCellScale(0.33 / iris.getDimension().getRegionZoom());
|
||||
double x = bx / iris.getDimension().getBiomeZoom();
|
||||
double z = bz / iris.getDimension().getBiomeZoom();
|
||||
String regionId = iris.getDimension().getRegions().get(region.getIndex(x, z, iris.getDimension().getRegions().size()));
|
||||
|
||||
return Iris.data.getRegionLoader().load(regionId);
|
||||
}
|
||||
|
||||
public BiomeResult generateData(double bx, double bz, int rawX, int rawZ)
|
||||
{
|
||||
return generateRegionData(bx, bz, rawX, rawZ, getRegion(bx, bz));
|
||||
}
|
||||
|
||||
public boolean isSea(double bx, double bz, IrisRegion regionData)
|
||||
{
|
||||
bridge.setShuffle(0);
|
||||
bridge.setCellScale(0.33 / iris.getDimension().getContinentZoom());
|
||||
double x = bx / iris.getDimension().getBiomeZoom();
|
||||
double z = bz / iris.getDimension().getBiomeZoom();
|
||||
return bridge.getIndex(x, z, 5) == 1;
|
||||
}
|
||||
|
||||
public BiomeResult generateRegionData(double bx, double bz, int rawX, int rawZ, IrisRegion regionData)
|
||||
{
|
||||
if(isSea(bx, bz, regionData))
|
||||
{
|
||||
return generateSeaData(bx, bz, rawX, rawZ, regionData);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
return generateLandData(bx, bz, rawX, rawZ, regionData);
|
||||
}
|
||||
}
|
||||
|
||||
public BiomeResult generateBiomeData(double bx, double bz, IrisRegion regionData, CellGenerator cell, KList<String> biomes, InferredType inferredType)
|
||||
{
|
||||
double x = bx / iris.getDimension().getBiomeZoom();
|
||||
double z = bz / iris.getDimension().getBiomeZoom();
|
||||
IrisBiome biome = Iris.data.getBiomeLoader().load(biomes.get(sea.getIndex(x, z, biomes.size())));
|
||||
biome.setInferredType(inferredType);
|
||||
|
||||
return implode(bx, bz, regionData, cell, new BiomeResult(biome, cell.getDistance(x, z)));
|
||||
}
|
||||
|
||||
public BiomeResult generatePureSeaData(double bx, double bz, int rawX, int rawZ, IrisRegion regionData)
|
||||
{
|
||||
sea.setShuffle(42);
|
||||
sea.setCellScale(0.56 / iris.getDimension().getSeaZoom());
|
||||
return generateBiomeData(bx, bz, regionData, sea, regionData.getSeaBiomes(), InferredType.SEA);
|
||||
}
|
||||
|
||||
public BiomeResult generateImpureData(int rawX, int rawZ, InferredType type, IrisRegion regionData, BiomeResult pureResult)
|
||||
{
|
||||
for(IrisRegionRidge i : regionData.getRidgeBiomes())
|
||||
{
|
||||
if(i.getType().equals(type) && i.isRidge(rng, rawX, rawZ))
|
||||
{
|
||||
return new BiomeResult(Iris.data.getBiomeLoader().load(i.getBiome()).infer(i.getAs(), type), 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
for(IrisRegionSpot i : regionData.getSpotBiomes())
|
||||
{
|
||||
if(i.getType().equals(type) && i.isSpot(rng, rawX, rawZ))
|
||||
{
|
||||
return new BiomeResult(Iris.data.getBiomeLoader().load(i.getBiome()).infer(i.getAs(), type), 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
return pureResult;
|
||||
}
|
||||
|
||||
public BiomeResult generateSeaData(double bx, double bz, int rawX, int rawZ, IrisRegion regionData)
|
||||
{
|
||||
return generateImpureData(rawX, rawZ, InferredType.SEA, regionData, generatePureSeaData(bx, bz, rawX, rawZ, regionData));
|
||||
}
|
||||
|
||||
public BiomeResult generatePureLandData(double bx, double bz, int rawX, int rawZ, IrisRegion regionData)
|
||||
{
|
||||
land.setShuffle(12);
|
||||
land.setCellScale(0.6 / iris.getDimension().getLandZoom());
|
||||
return generateBiomeData(bx, bz, regionData, land, regionData.getLandBiomes(), InferredType.LAND);
|
||||
}
|
||||
|
||||
public BiomeResult generateLandData(double bx, double bz, int rawX, int rawZ, IrisRegion regionData)
|
||||
{
|
||||
return generateImpureData(rawX, rawZ, InferredType.LAND, regionData, generatePureLandData(bx, bz, rawX, rawZ, regionData));
|
||||
}
|
||||
|
||||
public BiomeResult generatePureShoreData(double bx, double bz, int rawX, int rawZ, IrisRegion regionData)
|
||||
{
|
||||
shore.setShuffle(4);
|
||||
shore.setCellScale(0.8 / iris.getDimension().getShoreZoom());
|
||||
return generateBiomeData(bx, bz, regionData, shore, regionData.getShoreBiomes(), InferredType.SHORE);
|
||||
}
|
||||
|
||||
public BiomeResult generateShoreData(double bx, double bz, int rawX, int rawZ, IrisRegion regionData)
|
||||
{
|
||||
return generateImpureData(rawX, rawZ, InferredType.SHORE, regionData, generatePureShoreData(bx, bz, rawX, rawZ, regionData));
|
||||
}
|
||||
|
||||
public BiomeResult implode(double bx, double bz, IrisRegion regionData, CellGenerator parentCell, BiomeResult parent)
|
||||
{
|
||||
return implode(bx, bz, regionData, parentCell, parent, 1);
|
||||
}
|
||||
|
||||
public BiomeResult implode(double bx, double bz, IrisRegion regionData, CellGenerator parentCell, BiomeResult parent, int hits)
|
||||
{
|
||||
if(hits > 9)
|
||||
{
|
||||
return parent;
|
||||
}
|
||||
|
||||
double x = bx / iris.getDimension().getBiomeZoom();
|
||||
double z = bz / iris.getDimension().getBiomeZoom();
|
||||
if(parent.getDistance() > regionData.getBiomeImplosionRatio())
|
||||
{
|
||||
if(!parent.getBiome().getChildren().isEmpty())
|
||||
{
|
||||
CellGenerator childCell = parent.getBiome().getChildrenGenerator(rng, 123, parentCell.getCellScale() * parent.getBiome().getChildShrinkFactor());
|
||||
int r = childCell.getIndex(x, z, parent.getBiome().getChildren().size() + 1);
|
||||
|
||||
if(r == parent.getBiome().getChildren().size())
|
||||
{
|
||||
return new BiomeResult(parent.getBiome(), childCell.getDistance(x, z));
|
||||
}
|
||||
|
||||
IrisBiome biome = Iris.data.getBiomeLoader().load(parent.getBiome().getChildren().get(r));
|
||||
biome.setInferredType(parent.getBiome().getInferredType());
|
||||
|
||||
return implode(bx, bz, regionData, childCell, new BiomeResult(biome, childCell.getDistance(x, z)), hits + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double generate(double x, double z)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
134
src/main/java/com/volmit/iris/layer/GenLayerCave.java
Normal file
134
src/main/java/com/volmit/iris/layer/GenLayerCave.java
Normal file
@@ -0,0 +1,134 @@
|
||||
package ninja.bytecode.iris.layer;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import ninja.bytecode.iris.generator.DimensionChunkGenerator;
|
||||
import ninja.bytecode.iris.object.atomics.AtomicSliver;
|
||||
import ninja.bytecode.iris.util.BlockDataTools;
|
||||
import ninja.bytecode.iris.util.CNG;
|
||||
import ninja.bytecode.iris.util.CaveResult;
|
||||
import ninja.bytecode.iris.util.FastNoise;
|
||||
import ninja.bytecode.iris.util.FastNoise.CellularDistanceFunction;
|
||||
import ninja.bytecode.iris.util.FastNoise.CellularReturnType;
|
||||
import ninja.bytecode.iris.util.FastNoise.NoiseType;
|
||||
import ninja.bytecode.iris.util.GenLayer;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
|
||||
public class GenLayerCave extends GenLayer
|
||||
{
|
||||
public static final BlockData CAVE_AIR = BlockDataTools.getBlockData("CAVE_AIR");
|
||||
public static final BlockData AIR = BlockDataTools.getBlockData("AIR");
|
||||
private static final KList<CaveResult> EMPTY = new KList<>();
|
||||
private CNG gincline;
|
||||
private CNG shuffle;
|
||||
private FastNoise gg;
|
||||
|
||||
public GenLayerCave(DimensionChunkGenerator iris, RNG rng)
|
||||
{
|
||||
//@builder
|
||||
super(iris, rng);
|
||||
shuffle = CNG.signature(rng.nextParallelRNG(1348566));
|
||||
gincline = new CNG(rng.nextParallelRNG(26512), 1D, 3).scale(0.00452);
|
||||
gg = new FastNoise(324895 * rng.nextParallelRNG(49678).imax());
|
||||
//@done
|
||||
}
|
||||
|
||||
public KList<CaveResult> genCaves(double wxx, double wzz, int x, int z, AtomicSliver data)
|
||||
{
|
||||
if(!iris.getDimension().isCaves())
|
||||
{
|
||||
return EMPTY;
|
||||
}
|
||||
|
||||
KList<CaveResult> result = new KList<>();
|
||||
shuffle.scale(0.01);
|
||||
double shuffleDistance = 72;
|
||||
gg.SetNoiseType(NoiseType.Cellular);
|
||||
gg.SetCellularReturnType(CellularReturnType.Distance2Sub);
|
||||
gg.SetCellularDistanceFunction(CellularDistanceFunction.Natural);
|
||||
|
||||
for(int i = 0; i < 2; i++)
|
||||
{
|
||||
double wx = wxx + (shuffle.noise(wxx, wzz) * shuffleDistance);
|
||||
double wz = wzz + (shuffle.noise(wzz, wxx) * shuffleDistance);
|
||||
double incline = 157;
|
||||
double baseWidth = (9 * iris.getDimension().getCaveScale());
|
||||
double distanceCheck = 0.0132 * baseWidth;
|
||||
double distanceTake = 0.0032 * baseWidth;
|
||||
double drop = (-i * 7) + 44 + iris.getDimension().getCaveShift();
|
||||
double caveHeightNoise = incline * gincline.noise((wx + (10000 * i)), (wz - (10000 * i)));
|
||||
caveHeightNoise += shuffle.fitDoubleD(-1, 1, wxx - caveHeightNoise, wzz + caveHeightNoise) * 3;
|
||||
|
||||
int ceiling = 0;
|
||||
int floor = 256;
|
||||
|
||||
for(double tunnelHeight = 1; tunnelHeight <= baseWidth; tunnelHeight++)
|
||||
{
|
||||
double distance = (gg.GetCellular((float) wx + (10000 * i), (float) wz - (10000 * i)) + 1D) / 2D;
|
||||
if(distance < distanceCheck - (tunnelHeight * distanceTake))
|
||||
{
|
||||
int caveHeight = (int) Math.round(caveHeightNoise - drop);
|
||||
int pu = (int) (caveHeight + tunnelHeight);
|
||||
int pd = (int) (caveHeight - tunnelHeight);
|
||||
if(dig(x, pu, z, data))
|
||||
{
|
||||
ceiling = pu > ceiling ? pu : ceiling;
|
||||
floor = pu < floor ? pu : floor;
|
||||
}
|
||||
|
||||
if(dig(x, pd, z, data))
|
||||
{
|
||||
ceiling = pd > ceiling ? pd : ceiling;
|
||||
floor = pd < floor ? pd : floor;
|
||||
}
|
||||
|
||||
if(tunnelHeight == 1)
|
||||
{
|
||||
if(dig(x, (int) (caveHeight), z, data))
|
||||
{
|
||||
ceiling = caveHeight > ceiling ? caveHeight : ceiling;
|
||||
floor = caveHeight < floor ? caveHeight : floor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result.add(new CaveResult(floor, ceiling));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean dig(int x, int y, int z, AtomicSliver data)
|
||||
{
|
||||
Material a = data.getType(y);
|
||||
Material c = data.getType(y + 1);
|
||||
Material f = data.getType(y - 1);
|
||||
|
||||
if(can(a) && canAir(c) && canAir(f))
|
||||
{
|
||||
data.set(y, CAVE_AIR);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean canAir(Material m)
|
||||
{
|
||||
return (m.isSolid() || m.equals(Material.AIR) || m.equals(Material.CAVE_AIR)) && !m.equals(Material.BEDROCK);
|
||||
}
|
||||
|
||||
public boolean can(Material m)
|
||||
{
|
||||
return m.isSolid() && !m.equals(Material.BEDROCK);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double generate(double x, double z)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package ninja.bytecode.iris.layer.post;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import ninja.bytecode.iris.generator.PostBlockChunkGenerator;
|
||||
import ninja.bytecode.iris.util.IrisPostBlockFilter;
|
||||
|
||||
public class PostNippleSmoother extends IrisPostBlockFilter
|
||||
{
|
||||
public PostNippleSmoother(PostBlockChunkGenerator gen)
|
||||
{
|
||||
super(gen);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPost(int x, int z)
|
||||
{
|
||||
int h = highestTerrainBlock(x, z);
|
||||
int ha = highestTerrainBlock(x + 1, z);
|
||||
int hb = highestTerrainBlock(x, z + 1);
|
||||
int hc = highestTerrainBlock(x - 1, z);
|
||||
int hd = highestTerrainBlock(x, z - 1);
|
||||
|
||||
if(ha == h - 1 && hb == h - 1 && hc == h - 1 && hd == h - 1)
|
||||
{
|
||||
BlockData bc = getPostBlock(x, h, z);
|
||||
BlockData b = getPostBlock(x, h + 1, z);
|
||||
Material m = bc.getMaterial();
|
||||
|
||||
if(m.isSolid())
|
||||
{
|
||||
setPostBlock(x, h, z, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package ninja.bytecode.iris.layer.post;
|
||||
|
||||
import ninja.bytecode.iris.generator.PostBlockChunkGenerator;
|
||||
import ninja.bytecode.iris.util.IrisPostBlockFilter;
|
||||
|
||||
public class PostPotholeFiller extends IrisPostBlockFilter
|
||||
{
|
||||
public PostPotholeFiller(PostBlockChunkGenerator gen)
|
||||
{
|
||||
super(gen);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPost(int x, int z)
|
||||
{
|
||||
int h = highestTerrainBlock(x, z);
|
||||
int ha = highestTerrainBlock(x + 1, z);
|
||||
int hb = highestTerrainBlock(x, z + 1);
|
||||
int hc = highestTerrainBlock(x - 1, z);
|
||||
int hd = highestTerrainBlock(x, z - 1);
|
||||
|
||||
if(ha == h + 1 && hb == h + 1 && hc == h + 1 && hd == h + 1)
|
||||
{
|
||||
setPostBlock(x, h + 1, z, getPostBlock(x, h, z));
|
||||
}
|
||||
}
|
||||
}
|
||||
50
src/main/java/com/volmit/iris/layer/post/PostSlabber.java
Normal file
50
src/main/java/com/volmit/iris/layer/post/PostSlabber.java
Normal file
@@ -0,0 +1,50 @@
|
||||
package ninja.bytecode.iris.layer.post;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.block.data.Waterlogged;
|
||||
|
||||
import ninja.bytecode.iris.generator.PostBlockChunkGenerator;
|
||||
import ninja.bytecode.iris.util.IrisPostBlockFilter;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
|
||||
public class PostSlabber extends IrisPostBlockFilter
|
||||
{
|
||||
public static final Material AIR = Material.AIR;
|
||||
public static final Material WATER = Material.WATER;
|
||||
private RNG rng;
|
||||
|
||||
public PostSlabber(PostBlockChunkGenerator gen)
|
||||
{
|
||||
super(gen);
|
||||
rng = gen.getMasterRandom().nextParallelRNG(1239456);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPost(int x, int z)
|
||||
{
|
||||
int h = highestTerrainBlock(x, z);
|
||||
|
||||
if(highestTerrainBlock(x + 1, z) == h + 1 || highestTerrainBlock(x, z + 1) == h + 1 || highestTerrainBlock(x - 1, z) == h + 1 || highestTerrainBlock(x, z - 1) == h + 1)
|
||||
{
|
||||
BlockData d = gen.sampleTrueBiome(x, z).getBiome().getSlab().get(rng, x, h, z);
|
||||
if(d != null)
|
||||
{
|
||||
if(d.getMaterial().equals(AIR))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(d instanceof Waterlogged)
|
||||
{
|
||||
((Waterlogged) d).setWaterlogged(getPostBlock(x, h + 1, z).getMaterial().equals(Material.WATER));
|
||||
}
|
||||
|
||||
if(getPostBlock(x, h + 2, z).getMaterial().equals(AIR) || getPostBlock(x, h + 2, z).getMaterial().equals(WATER))
|
||||
{
|
||||
setPostBlock(x, h + 1, z, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package ninja.bytecode.iris.layer.post;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import ninja.bytecode.iris.generator.PostBlockChunkGenerator;
|
||||
import ninja.bytecode.iris.object.IrisBiome;
|
||||
import ninja.bytecode.iris.util.IrisPostBlockFilter;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
|
||||
public class PostWallPatcher extends IrisPostBlockFilter
|
||||
{
|
||||
public static final Material AIR = Material.AIR;
|
||||
private RNG rng;
|
||||
|
||||
public PostWallPatcher(PostBlockChunkGenerator gen)
|
||||
{
|
||||
super(gen);
|
||||
rng = gen.getMasterRandom().nextParallelRNG(1239456);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPost(int x, int z)
|
||||
{
|
||||
IrisBiome biome = gen.sampleTrueBiome(x, z).getBiome();
|
||||
|
||||
if(!biome.getWall().getPalette().isEmpty())
|
||||
{
|
||||
int h = highestTerrainBlock(x, z);
|
||||
int ha = highestTerrainBlock(x + 1, z);
|
||||
int hb = highestTerrainBlock(x, z + 1);
|
||||
int hc = highestTerrainBlock(x - 1, z);
|
||||
int hd = highestTerrainBlock(x, z - 1);
|
||||
|
||||
if(ha < h - 2 || hb < h - 2 || hc < h - 2 || hd < h - 2)
|
||||
{
|
||||
int max = Math.abs(Math.max(h - ha, Math.max(h - hb, Math.max(h - hc, h - hd))));
|
||||
|
||||
for(int i = h; i > h - max; i--)
|
||||
{
|
||||
BlockData d = biome.getWall().get(rng, x + i, i + h, z + i);
|
||||
|
||||
if(d != null)
|
||||
{
|
||||
if(d.getMaterial().equals(AIR))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
setPostBlock(x, i, z, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
6
src/main/java/com/volmit/iris/object/Blueprint.java
Normal file
6
src/main/java/com/volmit/iris/object/Blueprint.java
Normal file
@@ -0,0 +1,6 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
public class Blueprint
|
||||
{
|
||||
|
||||
}
|
||||
8
src/main/java/com/volmit/iris/object/DecorationPart.java
Normal file
8
src/main/java/com/volmit/iris/object/DecorationPart.java
Normal file
@@ -0,0 +1,8 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
public enum DecorationPart
|
||||
{
|
||||
NONE,
|
||||
SHORE_LINE,
|
||||
SEA_SURFACE
|
||||
}
|
||||
7
src/main/java/com/volmit/iris/object/Dispersion.java
Normal file
7
src/main/java/com/volmit/iris/object/Dispersion.java
Normal file
@@ -0,0 +1,7 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
public enum Dispersion
|
||||
{
|
||||
SCATTER,
|
||||
WISPY,
|
||||
}
|
||||
8
src/main/java/com/volmit/iris/object/Envelope.java
Normal file
8
src/main/java/com/volmit/iris/object/Envelope.java
Normal file
@@ -0,0 +1,8 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
public enum Envelope
|
||||
{
|
||||
EVERYWHERE,
|
||||
CELLS,
|
||||
VEINS,
|
||||
}
|
||||
10
src/main/java/com/volmit/iris/object/InferredType.java
Normal file
10
src/main/java/com/volmit/iris/object/InferredType.java
Normal file
@@ -0,0 +1,10 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
public enum InferredType
|
||||
{
|
||||
SHORE,
|
||||
LAND,
|
||||
SEA,
|
||||
CAVE,
|
||||
DEFER;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
public enum InterpolationMethod
|
||||
{
|
||||
NONE,
|
||||
BILINEAR,
|
||||
BICUBIC,
|
||||
HERMITE
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import lombok.Data;
|
||||
import ninja.bytecode.iris.util.Desc;
|
||||
|
||||
@Desc("Represents a rotation axis with intervals and maxes")
|
||||
@Data
|
||||
public class IrisAxisRotationClamp
|
||||
{
|
||||
@Desc("Should this axis be rotated at all?")
|
||||
private boolean enabled = false;
|
||||
|
||||
@Desc("The minimum angle (from) or set this and max to zero for any angle degrees")
|
||||
private double min = 0;
|
||||
|
||||
@Desc("The maximum angle (to) or set this and min to zero for any angle degrees")
|
||||
private double max = 0;
|
||||
|
||||
@Desc("Iris spins the axis but not freely. For example an interval of 90 would mean 4 possible angles (right angles) degrees")
|
||||
private double interval = 0;
|
||||
|
||||
public IrisAxisRotationClamp()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public IrisAxisRotationClamp(boolean enabled, double min, double max, double interval)
|
||||
{
|
||||
this.enabled = enabled;
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
this.interval = interval;
|
||||
}
|
||||
|
||||
public boolean isUnlimited()
|
||||
{
|
||||
return min == max;
|
||||
}
|
||||
|
||||
public double getRadians(int rng)
|
||||
{
|
||||
if(isUnlimited())
|
||||
{
|
||||
return Math.toRadians((rng * interval) % 360D);
|
||||
}
|
||||
|
||||
double deg = min + (rng * interval) % (Math.abs(max - min) / 360D);
|
||||
return Math.toRadians(deg);
|
||||
}
|
||||
}
|
||||
386
src/main/java/com/volmit/iris/object/IrisBiome.java
Normal file
386
src/main/java/com/volmit/iris/object/IrisBiome.java
Normal file
@@ -0,0 +1,386 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import ninja.bytecode.iris.util.CNG;
|
||||
import ninja.bytecode.iris.util.CellGenerator;
|
||||
import ninja.bytecode.iris.util.Desc;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
import ninja.bytecode.shuriken.logging.L;
|
||||
|
||||
@Desc("Represents a biome in iris.")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class IrisBiome extends IrisRegistrant
|
||||
{
|
||||
@Desc("This is the human readable name for this biome. This can and should be different than the file name. This is not used for loading biomes in other objects.")
|
||||
private String name = "A Biome";
|
||||
|
||||
@Desc("This changes the dispersion of the biome colors if multiple derivatives are chosen")
|
||||
private Dispersion biomeDispersion = Dispersion.SCATTER;
|
||||
|
||||
@Desc("This zooms in the biome colors if multiple derivatives are chosen")
|
||||
private double biomeZoom = 1;
|
||||
|
||||
@Desc("Layers no longer descend from the surface block, they descend from the max possible height the biome can produce (constant) creating mesa like layers.")
|
||||
private boolean lockLayers = false;
|
||||
|
||||
@Desc("The rarity of this biome (integer)")
|
||||
private int rarity = 1;
|
||||
|
||||
@Desc("The raw derivative of this biome. This is required or the terrain will not properly generate. Use any vanilla biome type. Look in examples/biome-list.txt")
|
||||
private Biome derivative = Biome.THE_VOID;
|
||||
|
||||
@Desc("You can instead specify multiple biome derivatives to randomly scatter colors in this biome")
|
||||
private KList<Biome> biomeScatter = new KList<>();
|
||||
|
||||
@Desc("Since 1.13 supports 3D biomes, you can add different derivative colors for anything above the terrain. (Think swampy tree leaves with a desert looking grass surface)")
|
||||
private KList<Biome> biomeSkyScatter = new KList<>();
|
||||
|
||||
@Desc("If this biome has children biomes, and the gen layer chooses one of this biomes children, how much smaller will it be (inside of this biome). Higher values means a smaller biome relative to this biome's size. Set higher than 1.0 and below 3.0 for best results.")
|
||||
private double childShrinkFactor = 1.5;
|
||||
|
||||
@Desc("List any biome names (file names without.json) here as children. Portions of this biome can sometimes morph into their children. Iris supports cyclic relationships such as A > B > A > B. Iris will stop checking 9 biomes down the tree.")
|
||||
private KList<String> children = new KList<>();
|
||||
|
||||
@Desc("The default slab if iris decides to place a slab in this biome. Default is no slab.")
|
||||
private IrisBiomePaletteLayer slab = new IrisBiomePaletteLayer().zero();
|
||||
|
||||
@Desc("The default wall if iris decides to place a wall higher than 2 blocks (steep hills or possibly cliffs)")
|
||||
private IrisBiomePaletteLayer wall = new IrisBiomePaletteLayer().zero();
|
||||
|
||||
@Desc("This defines the layers of materials in this biome. Each layer has a palette and min/max height and some other properties. Usually a grassy/sandy layer then a dirt layer then a stone layer. Iris will fill in the remaining blocks below your layers with stone.")
|
||||
private KList<IrisBiomePaletteLayer> layers = new KList<IrisBiomePaletteLayer>().qadd(new IrisBiomePaletteLayer());
|
||||
|
||||
@Desc("This defines the layers of materials in this biome. Each layer has a palette and min/max height and some other properties. Usually a grassy/sandy layer then a dirt layer then a stone layer. Iris will fill in the remaining blocks below your layers with stone.")
|
||||
private KList<IrisBiomePaletteLayer> seaLayers = new KList<IrisBiomePaletteLayer>();
|
||||
|
||||
@Desc("Decorators are used for things like tall grass, bisected flowers, and even kelp or cactus (random heights)")
|
||||
private KList<IrisBiomeDecorator> decorators = new KList<IrisBiomeDecorator>();
|
||||
|
||||
@Desc("Objects define what schematics (iob files) iris will place in this biome")
|
||||
private KList<IrisObjectPlacement> objects = new KList<IrisObjectPlacement>();
|
||||
|
||||
@Desc("Generators for this biome. Multiple generators with different interpolation sizes will mix with other biomes how you would expect. This defines your biome height relative to the fluid height. Use negative for oceans.")
|
||||
private KList<IrisBiomeGeneratorLink> generators = new KList<IrisBiomeGeneratorLink>().qadd(new IrisBiomeGeneratorLink());
|
||||
|
||||
@Desc("Define biome deposit generators that add onto the existing regional and global deposit generators")
|
||||
private KList<IrisDepositGenerator> deposits = new KList<>();
|
||||
|
||||
private transient ReentrantLock lock = new ReentrantLock();
|
||||
private transient CellGenerator childrenCell;
|
||||
private transient InferredType inferredType;
|
||||
private transient CNG biomeGenerator;
|
||||
private transient int maxHeight = Integer.MIN_VALUE;
|
||||
private transient KList<BlockData> fullLayerSpec;
|
||||
private transient KList<CNG> layerHeightGenerators;
|
||||
private transient KList<CNG> layerSeaHeightGenerators;
|
||||
private transient KList<CNG> layerSurfaceGenerators;
|
||||
private transient KList<CNG> layerSeaSurfaceGenerators;
|
||||
|
||||
public IrisBiome()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public double getHeight(double x, double z, long seed)
|
||||
{
|
||||
double height = 0;
|
||||
|
||||
for(IrisBiomeGeneratorLink i : generators)
|
||||
{
|
||||
height += i.getHeight(x, z, seed);
|
||||
}
|
||||
|
||||
return Math.max(0, Math.min(height, 255));
|
||||
}
|
||||
|
||||
public CNG getBiomeGenerator(RNG random)
|
||||
{
|
||||
if(biomeGenerator == null)
|
||||
{
|
||||
biomeGenerator = CNG.signature(random.nextParallelRNG(213949 + hashCode())).scale(biomeDispersion.equals(Dispersion.SCATTER) ? 1000D : 0.1D);
|
||||
}
|
||||
|
||||
return biomeGenerator;
|
||||
}
|
||||
|
||||
public CellGenerator getChildrenGenerator(RNG random, int sig, double scale)
|
||||
{
|
||||
if(childrenCell == null)
|
||||
{
|
||||
childrenCell = new CellGenerator(random.nextParallelRNG(sig * 213));
|
||||
childrenCell.setCellScale(scale);
|
||||
}
|
||||
|
||||
return childrenCell;
|
||||
}
|
||||
|
||||
public KList<BlockData> generateLayers(double wx, double wz, RNG random, int maxDepth, int height)
|
||||
{
|
||||
if(isLockLayers())
|
||||
{
|
||||
return generateLockedLayers(wx, wz, random, maxDepth, height);
|
||||
}
|
||||
|
||||
KList<BlockData> data = new KList<>();
|
||||
|
||||
if(maxDepth <= 0)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
for(int i = 0; i < layers.size(); i++)
|
||||
{
|
||||
CNG hgen = getLayerHeightGenerators(random).get(i);
|
||||
int d = hgen.fit(layers.get(i).getMinHeight(), layers.get(i).getMaxHeight(), wx / layers.get(i).getTerrainZoom(), wz / layers.get(i).getTerrainZoom());
|
||||
|
||||
if(d < 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for(int j = 0; j < d; j++)
|
||||
{
|
||||
if(data.size() >= maxDepth)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
data.add(getLayers().get(i).get(random.nextParallelRNG(i + j), (wx + j) / layers.get(i).getTerrainZoom(), j, (wz - j) / layers.get(i).getTerrainZoom()));
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
L.ex(e);
|
||||
}
|
||||
}
|
||||
|
||||
if(data.size() >= maxDepth)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public KList<BlockData> generateLockedLayers(double wx, double wz, RNG random, int maxDepth, int height)
|
||||
{
|
||||
KList<BlockData> data = new KList<>();
|
||||
KList<BlockData> real = new KList<>();
|
||||
|
||||
if(maxDepth <= 0)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
for(int i = 0; i < layers.size(); i++)
|
||||
{
|
||||
CNG hgen = getLayerHeightGenerators(random).get(i);
|
||||
int d = hgen.fit(layers.get(i).getMinHeight(), layers.get(i).getMaxHeight(), wx / layers.get(i).getTerrainZoom(), wz / layers.get(i).getTerrainZoom());
|
||||
|
||||
if(d < 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for(int j = 0; j < d; j++)
|
||||
{
|
||||
try
|
||||
{
|
||||
data.add(getLayers().get(i).get(random.nextParallelRNG(i + j), (wx + j) / layers.get(i).getTerrainZoom(), j, (wz - j) / layers.get(i).getTerrainZoom()));
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
L.ex(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(data.isEmpty())
|
||||
{
|
||||
return real;
|
||||
}
|
||||
|
||||
for(int i = 0; i < maxDepth; i++)
|
||||
{
|
||||
int offset = (getMaxHeight() - height) - i;
|
||||
int index = offset % data.size();
|
||||
real.add(data.get(index < 0 ? 0 : index));
|
||||
}
|
||||
|
||||
return real;
|
||||
}
|
||||
|
||||
private int getMaxHeight()
|
||||
{
|
||||
if(maxHeight == Integer.MIN_VALUE)
|
||||
{
|
||||
lock.lock();
|
||||
|
||||
maxHeight = 0;
|
||||
|
||||
for(IrisBiomeGeneratorLink i : getGenerators())
|
||||
{
|
||||
maxHeight += i.getMax();
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
return maxHeight;
|
||||
}
|
||||
|
||||
public IrisBiome infer(InferredType t, InferredType type)
|
||||
{
|
||||
setInferredType(t.equals(InferredType.DEFER) ? type : t);
|
||||
return this;
|
||||
}
|
||||
|
||||
public KList<BlockData> generateSeaLayers(double wx, double wz, RNG random, int maxDepth)
|
||||
{
|
||||
KList<BlockData> data = new KList<>();
|
||||
|
||||
for(int i = 0; i < seaLayers.size(); i++)
|
||||
{
|
||||
CNG hgen = getLayerSeaHeightGenerators(random).get(i);
|
||||
int d = hgen.fit(seaLayers.get(i).getMinHeight(), seaLayers.get(i).getMaxHeight(), wx / seaLayers.get(i).getTerrainZoom(), wz / seaLayers.get(i).getTerrainZoom());
|
||||
|
||||
if(d < 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for(int j = 0; j < d; j++)
|
||||
{
|
||||
if(data.size() >= maxDepth)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
data.add(getSeaLayers().get(i).get(random.nextParallelRNG(i + j), (wx + j) / seaLayers.get(i).getTerrainZoom(), j, (wz - j) / seaLayers.get(i).getTerrainZoom()));
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
L.ex(e);
|
||||
}
|
||||
}
|
||||
|
||||
if(data.size() >= maxDepth)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public KList<CNG> getLayerHeightGenerators(RNG rng)
|
||||
{
|
||||
lock.lock();
|
||||
if(layerHeightGenerators == null)
|
||||
{
|
||||
layerHeightGenerators = new KList<>();
|
||||
|
||||
int m = 7235;
|
||||
|
||||
for(IrisBiomePaletteLayer i : getLayers())
|
||||
{
|
||||
layerHeightGenerators.add(i.getHeightGenerator(rng.nextParallelRNG((m++) * m * m * m)));
|
||||
}
|
||||
}
|
||||
lock.unlock();
|
||||
|
||||
return layerHeightGenerators;
|
||||
}
|
||||
|
||||
public KList<CNG> getLayerSeaHeightGenerators(RNG rng)
|
||||
{
|
||||
lock.lock();
|
||||
if(layerSeaHeightGenerators == null)
|
||||
{
|
||||
layerSeaHeightGenerators = new KList<>();
|
||||
|
||||
int m = 7735;
|
||||
|
||||
for(IrisBiomePaletteLayer i : getSeaLayers())
|
||||
{
|
||||
layerSeaHeightGenerators.add(i.getHeightGenerator(rng.nextParallelRNG((m++) * m * m * m)));
|
||||
}
|
||||
}
|
||||
lock.unlock();
|
||||
|
||||
return layerSeaHeightGenerators;
|
||||
}
|
||||
|
||||
public boolean isLand()
|
||||
{
|
||||
if(inferredType == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return inferredType.equals(InferredType.LAND);
|
||||
}
|
||||
|
||||
public boolean isSea()
|
||||
{
|
||||
if(inferredType == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return inferredType.equals(InferredType.SEA);
|
||||
}
|
||||
|
||||
public boolean isShore()
|
||||
{
|
||||
if(inferredType == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return inferredType.equals(InferredType.SHORE);
|
||||
}
|
||||
|
||||
public Biome getSkyBiome(RNG rng, double x, double y, double z)
|
||||
{
|
||||
if(biomeSkyScatter.size() == 1)
|
||||
{
|
||||
return biomeSkyScatter.get(0);
|
||||
}
|
||||
|
||||
if(biomeSkyScatter.isEmpty())
|
||||
{
|
||||
return getGroundBiome(rng, x, y, z);
|
||||
}
|
||||
|
||||
return biomeSkyScatter.get(getBiomeGenerator(rng).fit(0, biomeSkyScatter.size() - 1, x, y, z));
|
||||
}
|
||||
|
||||
public Biome getGroundBiome(RNG rng, double x, double y, double z)
|
||||
{
|
||||
if(biomeSkyScatter.isEmpty())
|
||||
{
|
||||
return getDerivative();
|
||||
}
|
||||
|
||||
if(biomeScatter.size() == 1)
|
||||
{
|
||||
return biomeScatter.get(0);
|
||||
}
|
||||
|
||||
return biomeScatter.get(getBiomeGenerator(rng).fit(0, biomeScatter.size() - 1, x, y, z));
|
||||
}
|
||||
}
|
||||
153
src/main/java/com/volmit/iris/object/IrisBiomeDecorator.java
Normal file
153
src/main/java/com/volmit/iris/object/IrisBiomeDecorator.java
Normal file
@@ -0,0 +1,153 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import lombok.Data;
|
||||
import ninja.bytecode.iris.util.BlockDataTools;
|
||||
import ninja.bytecode.iris.util.CNG;
|
||||
import ninja.bytecode.iris.util.Desc;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
import ninja.bytecode.shuriken.collections.KMap;
|
||||
|
||||
@Desc("A biome decorator is used for placing flowers, grass, cacti and so on")
|
||||
@Data
|
||||
public class IrisBiomeDecorator
|
||||
{
|
||||
@Desc("The varience dispersion is used when multiple blocks are put in the palette. Scatter scrambles them, Wispy shows streak-looking varience")
|
||||
private Dispersion variance = Dispersion.SCATTER;
|
||||
|
||||
@Desc("Dispersion is used to pick places to spawn. Scatter randomly places them (vanilla) or Wispy for a streak like patch system.")
|
||||
private Dispersion dispersion = Dispersion.SCATTER;
|
||||
|
||||
@Desc("If this decorator has a height more than 1 this changes how it picks the height between your maxes. Scatter = random, Wispy = wavy heights")
|
||||
private Dispersion verticalVariance = Dispersion.SCATTER;
|
||||
|
||||
@Desc("Tells iris where this decoration is a part of. I.e. SHORE_LINE or SEA_SURFACE")
|
||||
private DecorationPart partOf = DecorationPart.NONE;
|
||||
|
||||
@Desc("The minimum repeat stack height (setting to 3 would stack 3 of <block> on top of each other")
|
||||
private int stackMin = 1;
|
||||
|
||||
@Desc("The maximum repeat stack height")
|
||||
private int stackMax = 1;
|
||||
|
||||
@Desc("The zoom is for zooming in or out wispy dispersions. Makes patches bigger the higher this zoom value is/")
|
||||
private double zoom = 1;
|
||||
|
||||
@Desc("The vertical zoom is for wispy stack heights. Zooming this in makes stack heights more slowly change over a distance")
|
||||
private double verticalZoom = 1;
|
||||
|
||||
@Desc("The chance for this decorator to decorate at a given X,Y coordinate. This is hit 256 times per chunk (per surface block)")
|
||||
private double chance = 0.1;
|
||||
|
||||
@Desc("The palette of blocks to pick from when this decorator needs to place.")
|
||||
private KList<String> palette = new KList<String>().qadd("GRASS");
|
||||
|
||||
private transient KMap<Long, CNG> layerGenerators;
|
||||
private transient CNG heightGenerator;
|
||||
private transient KList<BlockData> blockData;
|
||||
private transient RNG nrng;
|
||||
|
||||
public int getHeight(RNG rng, double x, double z)
|
||||
{
|
||||
if(stackMin == stackMax)
|
||||
{
|
||||
return stackMin;
|
||||
}
|
||||
|
||||
return getGenerator(rng).fit(stackMin, stackMax, x * (verticalVariance.equals(Dispersion.SCATTER) ? 1000D : 1D), z * (verticalVariance.equals(Dispersion.SCATTER) ? 1000D : 1D));
|
||||
}
|
||||
|
||||
public CNG getHeightGenerator(RNG rng)
|
||||
{
|
||||
if(heightGenerator == null)
|
||||
{
|
||||
heightGenerator = CNG.signature(rng.nextParallelRNG(getBlockData().size() + stackMax + stackMin)).scale(1D / verticalZoom);
|
||||
}
|
||||
|
||||
return heightGenerator;
|
||||
}
|
||||
|
||||
public CNG getGenerator(RNG rng)
|
||||
{
|
||||
long key = rng.nextParallelRNG(1).nextLong();
|
||||
|
||||
if(layerGenerators == null)
|
||||
{
|
||||
layerGenerators = new KMap<>();
|
||||
}
|
||||
|
||||
if(!layerGenerators.containsKey(key))
|
||||
{
|
||||
layerGenerators.put(key, CNG.signature(rng.nextParallelRNG(getBlockData().size())).scale(1D / zoom));
|
||||
}
|
||||
|
||||
return layerGenerators.get(key);
|
||||
}
|
||||
|
||||
public KList<String> add(String b)
|
||||
{
|
||||
palette.add(b);
|
||||
return palette;
|
||||
}
|
||||
|
||||
public BlockData getBlockData(RNG rng, double x, double z)
|
||||
{
|
||||
if(getGenerator(rng) == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if(getBlockData() == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if(getBlockData().isEmpty())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if(nrng == null)
|
||||
{
|
||||
nrng = rng.nextParallelRNG(2398552 + hashCode());
|
||||
}
|
||||
|
||||
double xx = dispersion.equals(Dispersion.SCATTER) ? nrng.i(-100000, 100000) : x;
|
||||
double zz = dispersion.equals(Dispersion.SCATTER) ? nrng.i(-100000, 100000) : z;
|
||||
|
||||
if(getGenerator(rng).fitDoubleD(0D, 1D, xx, zz) <= chance)
|
||||
{
|
||||
try
|
||||
{
|
||||
return getBlockData().get(getGenerator(rng.nextParallelRNG(53)).fit(0, getBlockData().size() - 1, xx, zz));
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public KList<BlockData> getBlockData()
|
||||
{
|
||||
if(blockData == null)
|
||||
{
|
||||
blockData = new KList<>();
|
||||
for(String i : palette)
|
||||
{
|
||||
BlockData bx = BlockDataTools.getBlockData(i);
|
||||
if(bx != null)
|
||||
{
|
||||
blockData.add(bx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return blockData;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import lombok.Data;
|
||||
import ninja.bytecode.iris.Iris;
|
||||
import ninja.bytecode.iris.util.Desc;
|
||||
import ninja.bytecode.iris.util.IrisInterpolation;
|
||||
|
||||
@Desc("This represents a link to a generator for a biome")
|
||||
@Data
|
||||
public class IrisBiomeGeneratorLink
|
||||
{
|
||||
@Desc("The generator id")
|
||||
private String generator = "default";
|
||||
|
||||
@Desc("The min block value (value + fluidHeight)")
|
||||
private int min = 0;
|
||||
|
||||
@Desc("The max block value (value + fluidHeight)")
|
||||
private int max = 0;
|
||||
|
||||
private transient IrisGenerator gen;
|
||||
|
||||
public IrisBiomeGeneratorLink()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public IrisGenerator getCachedGenerator()
|
||||
{
|
||||
if(gen == null)
|
||||
{
|
||||
gen = Iris.data.getGeneratorLoader().load(getGenerator());
|
||||
|
||||
if(gen == null)
|
||||
{
|
||||
gen = new IrisGenerator();
|
||||
}
|
||||
}
|
||||
|
||||
return gen;
|
||||
}
|
||||
|
||||
public double getHeight(double x, double z, long seed)
|
||||
{
|
||||
double g = getCachedGenerator().getHeight(x, z, seed);
|
||||
g = g < 0 ? 0 : g;
|
||||
g = g > 1 ? 1 : g;
|
||||
|
||||
return IrisInterpolation.lerp(min, max, g);
|
||||
}
|
||||
}
|
||||
123
src/main/java/com/volmit/iris/object/IrisBiomePaletteLayer.java
Normal file
123
src/main/java/com/volmit/iris/object/IrisBiomePaletteLayer.java
Normal file
@@ -0,0 +1,123 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import lombok.Data;
|
||||
import ninja.bytecode.iris.util.BlockDataTools;
|
||||
import ninja.bytecode.iris.util.CNG;
|
||||
import ninja.bytecode.iris.util.Desc;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
|
||||
@Desc("A layer of surface / subsurface material in biomes")
|
||||
@Data
|
||||
public class IrisBiomePaletteLayer
|
||||
{
|
||||
@Desc("The dispersion of materials from the palette")
|
||||
private Dispersion dispersion = Dispersion.SCATTER;
|
||||
|
||||
@Desc("The min thickness of this layer")
|
||||
private int minHeight = 1;
|
||||
|
||||
@Desc("The max thickness of this layer")
|
||||
private int maxHeight = 1;
|
||||
|
||||
@Desc("The terrain zoom mostly for zooming in on a wispy palette")
|
||||
private double terrainZoom = 5;
|
||||
|
||||
@Desc("The palette of blocks to be used in this layer")
|
||||
private KList<String> palette = new KList<String>().qadd("GRASS_BLOCK");
|
||||
|
||||
private transient ReentrantLock lock = new ReentrantLock();
|
||||
private transient KList<BlockData> blockData;
|
||||
private transient CNG layerGenerator;
|
||||
private transient CNG heightGenerator;
|
||||
|
||||
public CNG getHeightGenerator(RNG rng)
|
||||
{
|
||||
if(heightGenerator == null)
|
||||
{
|
||||
heightGenerator = CNG.signature(rng.nextParallelRNG(minHeight * maxHeight + getBlockData().size()));
|
||||
}
|
||||
|
||||
return heightGenerator;
|
||||
}
|
||||
|
||||
public BlockData get(RNG rng, double x, double y, double z)
|
||||
{
|
||||
if(layerGenerator == null)
|
||||
{
|
||||
cacheGenerator(rng);
|
||||
}
|
||||
|
||||
if(layerGenerator != null)
|
||||
{
|
||||
if(dispersion.equals(Dispersion.SCATTER))
|
||||
{
|
||||
return getBlockData().get(layerGenerator.fit(0, 30000000, x, y, z) % getBlockData().size());
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
return getBlockData().get(layerGenerator.fit(0, getBlockData().size() - 1, x, y, z));
|
||||
}
|
||||
}
|
||||
|
||||
if(getBlockData().isEmpty())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return getBlockData().get(0);
|
||||
}
|
||||
|
||||
public void cacheGenerator(RNG rng)
|
||||
{
|
||||
RNG rngx = rng.nextParallelRNG(minHeight + maxHeight + getBlockData().size());
|
||||
|
||||
switch(dispersion)
|
||||
{
|
||||
case SCATTER:
|
||||
layerGenerator = CNG.signature(rngx).freq(1000000);
|
||||
break;
|
||||
case WISPY:
|
||||
layerGenerator = CNG.signature(rngx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public KList<String> add(String b)
|
||||
{
|
||||
palette.add(b);
|
||||
|
||||
return palette;
|
||||
}
|
||||
|
||||
public KList<BlockData> getBlockData()
|
||||
{
|
||||
lock.lock();
|
||||
if(blockData == null)
|
||||
{
|
||||
blockData = new KList<>();
|
||||
for(String ix : palette)
|
||||
{
|
||||
BlockData bx = BlockDataTools.getBlockData(ix);
|
||||
if(bx != null)
|
||||
{
|
||||
blockData.add(bx);
|
||||
}
|
||||
}
|
||||
}
|
||||
lock.unlock();
|
||||
|
||||
return blockData;
|
||||
}
|
||||
|
||||
public IrisBiomePaletteLayer zero()
|
||||
{
|
||||
palette.clear();
|
||||
return this;
|
||||
}
|
||||
}
|
||||
172
src/main/java/com/volmit/iris/object/IrisDepositGenerator.java
Normal file
172
src/main/java/com/volmit/iris/object/IrisDepositGenerator.java
Normal file
@@ -0,0 +1,172 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.util.BlockVector;
|
||||
|
||||
import lombok.Data;
|
||||
import ninja.bytecode.iris.generator.ParallaxChunkGenerator;
|
||||
import ninja.bytecode.iris.util.BlockDataTools;
|
||||
import ninja.bytecode.iris.util.Desc;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
|
||||
@Data
|
||||
public class IrisDepositGenerator
|
||||
{
|
||||
@Desc("The minimum height this deposit can generate at")
|
||||
private int minHeight = 7;
|
||||
|
||||
@Desc("The maximum height this deposit can generate at")
|
||||
private int maxHeight = 55;
|
||||
|
||||
@Desc("The minimum amount of deposit blocks per clump")
|
||||
private int minSize = 3;
|
||||
|
||||
@Desc("The maximum amount of deposit blocks per clump")
|
||||
private int maxSize = 5;
|
||||
|
||||
@Desc("The maximum amount of clumps per chunk")
|
||||
private int maxPerChunk = 3;
|
||||
|
||||
@Desc("The minimum amount of clumps per chunk")
|
||||
private int minPerChunk = 1;
|
||||
|
||||
@Desc("The palette of blocks to be used in this deposit generator")
|
||||
private KList<String> palette = new KList<String>();
|
||||
|
||||
@Desc("Ore varience is how many different objects clumps iris will create")
|
||||
private int varience = 8;
|
||||
|
||||
private transient IrisObjectPlacement config = createDepositConfig();
|
||||
private transient ReentrantLock lock = new ReentrantLock();
|
||||
private transient KList<IrisObject> objects;
|
||||
private transient KList<BlockData> blockData;
|
||||
|
||||
public IrisObject getClump(RNG rng)
|
||||
{
|
||||
lock.lock();
|
||||
|
||||
if(objects == null)
|
||||
{
|
||||
RNG rngv = rng.nextParallelRNG(3957778);
|
||||
objects = new KList<>();
|
||||
|
||||
for(int i = 0; i < varience; i++)
|
||||
{
|
||||
objects.add(generateClumpObject(rngv.nextParallelRNG(2349 * i + 3598)));
|
||||
}
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
return objects.get(rng.i(0, objects.size() - 1));
|
||||
}
|
||||
|
||||
private IrisObjectPlacement createDepositConfig()
|
||||
{
|
||||
IrisObjectPlacement p = new IrisObjectPlacement();
|
||||
IrisObjectRotation rot = new IrisObjectRotation();
|
||||
rot.setEnabled(true);
|
||||
IrisAxisRotationClamp xc = new IrisAxisRotationClamp();
|
||||
IrisAxisRotationClamp yc = new IrisAxisRotationClamp();
|
||||
IrisAxisRotationClamp zc = new IrisAxisRotationClamp();
|
||||
xc.setEnabled(true);
|
||||
xc.setInterval(45);
|
||||
yc.setEnabled(true);
|
||||
yc.setInterval(45);
|
||||
zc.setEnabled(true);
|
||||
zc.setInterval(45);
|
||||
rot.setXAxis(xc);
|
||||
rot.setYAxis(yc);
|
||||
rot.setZAxis(zc);
|
||||
p.setRotation(rot);
|
||||
p.setUnderwater(true);
|
||||
p.setMeld(true);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
private IrisObject generateClumpObject(RNG rngv)
|
||||
{
|
||||
int s = rngv.i(minSize, maxSize);
|
||||
int dim = (int) Math.round(Math.pow(s, 1D / 3D));
|
||||
int w = dim / 2;
|
||||
IrisObject o = new IrisObject(dim, dim, dim);
|
||||
|
||||
if(s == 1)
|
||||
{
|
||||
o.getBlocks().put(o.getCenter(), nextBlock(rngv));
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
while(s > 0)
|
||||
{
|
||||
s--;
|
||||
BlockVector ang = new BlockVector(rngv.i(-w, w), rngv.i(-w, w), rngv.i(-w, w));
|
||||
BlockVector pos = o.getCenter().clone().add(ang).toBlockVector();
|
||||
o.getBlocks().put(pos, nextBlock(rngv));
|
||||
}
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
private BlockData nextBlock(RNG rngv)
|
||||
{
|
||||
return getBlockData().get(rngv.i(0, getBlockData().size() - 1));
|
||||
}
|
||||
|
||||
public KList<BlockData> getBlockData()
|
||||
{
|
||||
lock.lock();
|
||||
|
||||
if(blockData == null)
|
||||
{
|
||||
blockData = new KList<>();
|
||||
|
||||
for(String ix : palette)
|
||||
{
|
||||
BlockData bx = BlockDataTools.getBlockData(ix);
|
||||
|
||||
if(bx != null)
|
||||
{
|
||||
blockData.add(bx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
|
||||
return blockData;
|
||||
}
|
||||
|
||||
public void generate(int x, int z, RNG rng, ParallaxChunkGenerator g)
|
||||
{
|
||||
IrisObject clump = getClump(rng);
|
||||
int height = (int) (Math.round(g.getTerrainHeight(x, z))) - 5;
|
||||
|
||||
if(height < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int i = Math.max(0, minHeight);
|
||||
int a = Math.min(height, Math.min(256, maxHeight));
|
||||
|
||||
if(i >= a)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int h = rng.i(i, a);
|
||||
|
||||
if(h > maxHeight || h < minHeight)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
clump.place(x, h, z, g, config, rng);
|
||||
}
|
||||
}
|
||||
311
src/main/java/com/volmit/iris/object/IrisDimension.java
Normal file
311
src/main/java/com/volmit/iris/object/IrisDimension.java
Normal file
@@ -0,0 +1,311 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.bukkit.World.Environment;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import ninja.bytecode.iris.util.BlockDataTools;
|
||||
import ninja.bytecode.iris.util.CNG;
|
||||
import ninja.bytecode.iris.util.Desc;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
|
||||
@Desc("Represents a dimension")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class IrisDimension extends IrisRegistrant
|
||||
{
|
||||
@Desc("The human readable name of this dimension")
|
||||
private String name = "A Dimension";
|
||||
|
||||
@Desc("The interpolation function for splicing noise maxes together")
|
||||
private InterpolationMethod interpolationFunction = InterpolationMethod.BICUBIC;
|
||||
|
||||
@Desc("The interpolation distance scale. Increase = more smooth, less detail")
|
||||
private double interpolationScale = 63;
|
||||
|
||||
@Desc("The Thickness scale of cave veins")
|
||||
private double caveThickness = 1D;
|
||||
|
||||
@Desc("The cave web scale. Smaller values means scaled up vein networks.")
|
||||
private double caveScale = 1D;
|
||||
|
||||
@Desc("Shift the Y value of the cave networks up or down.")
|
||||
private double caveShift = 0D;
|
||||
|
||||
@Desc("Generate caves or not.")
|
||||
private boolean caves = true;
|
||||
|
||||
@Desc("Carve terrain or not")
|
||||
private boolean carving = true;
|
||||
|
||||
@Desc("Generate decorations or not")
|
||||
private boolean decorate = true;
|
||||
|
||||
@Desc("Use post processing features. Usually for production only as there is a gen speed cost.")
|
||||
private boolean postProcess = true;
|
||||
|
||||
@Desc("The ceiling dimension. Leave blank for normal sky.")
|
||||
private String ceiling = "";
|
||||
|
||||
@Desc("Mirrors the generator floor into the ceiling. Think nether but worse...")
|
||||
private boolean mirrorCeiling = false;
|
||||
|
||||
@Desc("The world environment")
|
||||
private Environment environment = Environment.NORMAL;
|
||||
|
||||
@Desc("Define all of the regions to include in this dimension. Dimensions -> Regions -> Biomes -> Objects etc")
|
||||
private KList<String> regions = new KList<>();
|
||||
|
||||
@Desc("The fluid height for this dimension")
|
||||
private int fluidHeight = 63;
|
||||
|
||||
@Desc("Keep this either undefined or empty. Setting any biome name into this will force iris to only generate the specified biome. Great for testing.")
|
||||
private String focus = "";
|
||||
|
||||
@Desc("Zoom in or out the biome size. Higher = bigger biomes")
|
||||
private double biomeZoom = 5D;
|
||||
|
||||
@Desc("Zoom in or out the terrain. This stretches the terrain. Due to performance improvements, Higher than 2.0 may cause weird rounding artifacts. Lower = more terrain changes per block. Its a true zoom-out.")
|
||||
private double terrainZoom = 2D;
|
||||
|
||||
@Desc("You can rotate the input coordinates by an angle. This can make terrain appear more natural (less sharp corners and lines). This literally rotates the entire dimension by an angle. Hint: Try 12 degrees or something not on a 90 or 45 degree angle.")
|
||||
private double dimensionAngleDeg = 0;
|
||||
|
||||
@Desc("Iris adds a few roughness filters to noise. Increasing this smooths it out. Decreasing this makes it bumpier/scratchy")
|
||||
private double roughnessZoom = 2D;
|
||||
|
||||
@Desc("The height of the roughness filters")
|
||||
private int roughnessHeight = 3;
|
||||
|
||||
@Desc("Coordinate fracturing applies noise to the input coordinates. This creates the 'iris swirls' and wavy features. The distance pushes these waves further into places they shouldnt be. This is a block value multiplier.")
|
||||
private double coordFractureDistance = 20;
|
||||
|
||||
@Desc("Coordinate fracturing zoom. Higher = less frequent warping, Lower = more frequent and rapid warping / swirls.")
|
||||
private double coordFractureZoom = 8;
|
||||
|
||||
@Desc("This zooms in the land space")
|
||||
private double landZoom = 1;
|
||||
|
||||
@Desc("This zooms in the cave biome space")
|
||||
private double caveBiomeZoom = 1;
|
||||
|
||||
@Desc("This can zoom the shores")
|
||||
private double shoreZoom = 1;
|
||||
|
||||
@Desc("This zooms oceanic biomes")
|
||||
private double seaZoom = 1;
|
||||
|
||||
@Desc("Zoom in continents")
|
||||
private double continentZoom = 1;
|
||||
|
||||
@Desc("Change the size of regions")
|
||||
private double regionZoom = 1;
|
||||
|
||||
@Desc("Disable this to stop placing schematics in biomes")
|
||||
private boolean placeObjects = true;
|
||||
|
||||
@Desc("Prevent Leaf decay as if placed in creative mode")
|
||||
private boolean preventLeafDecay = false;
|
||||
|
||||
@Desc("Define global deposit generators")
|
||||
private KList<IrisDepositGenerator> deposits = new KList<>();
|
||||
|
||||
@Desc("The dispersion of materials for the rock palette")
|
||||
private Dispersion dispersion = Dispersion.SCATTER;
|
||||
|
||||
@Desc("The rock zoom mostly for zooming in on a wispy palette")
|
||||
private double rockZoom = 5;
|
||||
|
||||
@Desc("The palette of blocks for 'stone'")
|
||||
private KList<String> rockPalette = new KList<String>().qadd("STONE");
|
||||
|
||||
@Desc("The palette of blocks for 'water'")
|
||||
private KList<String> fluidPalette = new KList<String>().qadd("WATER");
|
||||
|
||||
private transient ReentrantLock rockLock = new ReentrantLock();
|
||||
private transient ReentrantLock fluidLock = new ReentrantLock();
|
||||
private transient KList<BlockData> rockData;
|
||||
private transient KList<BlockData> fluidData;
|
||||
private transient CNG rockLayerGenerator;
|
||||
private transient CNG fluidLayerGenerator;
|
||||
private transient CNG coordFracture;
|
||||
private transient Double sinr;
|
||||
private transient Double cosr;
|
||||
private transient Double rad;
|
||||
private transient boolean inverted;
|
||||
|
||||
public CNG getCoordFracture(RNG rng, int signature)
|
||||
{
|
||||
if(coordFracture == null)
|
||||
{
|
||||
coordFracture = CNG.signature(rng.nextParallelRNG(signature));
|
||||
coordFracture.scale(0.012 / coordFractureZoom);
|
||||
}
|
||||
|
||||
return coordFracture;
|
||||
}
|
||||
|
||||
public BlockData getRock(RNG rng, double x, double y, double z)
|
||||
{
|
||||
if(getRockData().size() == 1)
|
||||
{
|
||||
return getRockData().get(0);
|
||||
}
|
||||
|
||||
if(rockLayerGenerator == null)
|
||||
{
|
||||
cacheRockGenerator(rng);
|
||||
}
|
||||
|
||||
if(rockLayerGenerator != null)
|
||||
{
|
||||
if(dispersion.equals(Dispersion.SCATTER))
|
||||
{
|
||||
return getRockData().get(rockLayerGenerator.fit(0, 30000000, x, y, z) % getRockData().size());
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
return getRockData().get(rockLayerGenerator.fit(0, getRockData().size() - 1, x, y, z));
|
||||
}
|
||||
}
|
||||
|
||||
return getRockData().get(0);
|
||||
}
|
||||
|
||||
public void cacheRockGenerator(RNG rng)
|
||||
{
|
||||
RNG rngx = rng.nextParallelRNG(getRockData().size() * hashCode());
|
||||
|
||||
switch(dispersion)
|
||||
{
|
||||
case SCATTER:
|
||||
rockLayerGenerator = CNG.signature(rngx).freq(1000000);
|
||||
break;
|
||||
case WISPY:
|
||||
rockLayerGenerator = CNG.signature(rngx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public KList<BlockData> getRockData()
|
||||
{
|
||||
rockLock.lock();
|
||||
|
||||
if(rockData == null)
|
||||
{
|
||||
rockData = new KList<>();
|
||||
for(String ix : rockPalette)
|
||||
{
|
||||
BlockData bx = BlockDataTools.getBlockData(ix);
|
||||
if(bx != null)
|
||||
{
|
||||
rockData.add(bx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rockLock.unlock();
|
||||
|
||||
return rockData;
|
||||
}
|
||||
|
||||
public BlockData getFluid(RNG rng, double x, double y, double z)
|
||||
{
|
||||
if(getFluidData().size() == 1)
|
||||
{
|
||||
return getFluidData().get(0);
|
||||
}
|
||||
|
||||
if(fluidLayerGenerator == null)
|
||||
{
|
||||
cacheFluidGenerator(rng);
|
||||
}
|
||||
|
||||
if(fluidLayerGenerator != null)
|
||||
{
|
||||
if(dispersion.equals(Dispersion.SCATTER))
|
||||
{
|
||||
return getFluidData().get(fluidLayerGenerator.fit(0, 30000000, x, y, z) % getFluidData().size());
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
return getFluidData().get(fluidLayerGenerator.fit(0, getFluidData().size() - 1, x, y, z));
|
||||
}
|
||||
}
|
||||
|
||||
return getFluidData().get(0);
|
||||
}
|
||||
|
||||
public void cacheFluidGenerator(RNG rng)
|
||||
{
|
||||
RNG rngx = rng.nextParallelRNG(getFluidData().size() * hashCode());
|
||||
|
||||
switch(dispersion)
|
||||
{
|
||||
case SCATTER:
|
||||
fluidLayerGenerator = CNG.signature(rngx).freq(1000000);
|
||||
break;
|
||||
case WISPY:
|
||||
fluidLayerGenerator = CNG.signature(rngx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public KList<BlockData> getFluidData()
|
||||
{
|
||||
fluidLock.lock();
|
||||
|
||||
if(fluidData == null)
|
||||
{
|
||||
fluidData = new KList<>();
|
||||
for(String ix : fluidPalette)
|
||||
{
|
||||
BlockData bx = BlockDataTools.getBlockData(ix);
|
||||
if(bx != null)
|
||||
{
|
||||
fluidData.add(bx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fluidLock.unlock();
|
||||
|
||||
return fluidData;
|
||||
}
|
||||
|
||||
public double getDimensionAngle()
|
||||
{
|
||||
if(rad == null)
|
||||
{
|
||||
rad = Math.toRadians(dimensionAngleDeg);
|
||||
}
|
||||
|
||||
return rad;
|
||||
}
|
||||
|
||||
public double sinRotate()
|
||||
{
|
||||
if(sinr == null)
|
||||
{
|
||||
sinr = Math.sin(getDimensionAngle());
|
||||
}
|
||||
|
||||
return sinr;
|
||||
}
|
||||
|
||||
public double cosRotate()
|
||||
{
|
||||
if(cosr == null)
|
||||
{
|
||||
cosr = Math.cos(getDimensionAngle());
|
||||
}
|
||||
|
||||
return cosr;
|
||||
}
|
||||
}
|
||||
98
src/main/java/com/volmit/iris/object/IrisGenerator.java
Normal file
98
src/main/java/com/volmit/iris/object/IrisGenerator.java
Normal file
@@ -0,0 +1,98 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import ninja.bytecode.iris.Iris;
|
||||
import ninja.bytecode.iris.util.Desc;
|
||||
import ninja.bytecode.iris.util.IrisInterpolation;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
|
||||
@Desc("Represents a composite generator of noise gens")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class IrisGenerator extends IrisRegistrant
|
||||
{
|
||||
@Desc("The zoom or frequency.")
|
||||
private double zoom = 1;
|
||||
|
||||
@Desc("The opacity, essentially a multiplier on the output.")
|
||||
private double opacity = 1;
|
||||
|
||||
@Desc("The offset to shift this noise x")
|
||||
private double offsetX = 0;
|
||||
|
||||
@Desc("The offset to shift this noise z")
|
||||
private double offsetZ = 0;
|
||||
|
||||
@Desc("The seed for this generator")
|
||||
private long seed = 1;
|
||||
|
||||
@Desc("The interpolation method when two biomes use different heights but this same generator")
|
||||
private InterpolationMethod interpolationFunction = InterpolationMethod.BICUBIC;
|
||||
|
||||
@Desc("The interpolation distance scale (blocks) when two biomes use different heights but this same generator")
|
||||
private double interpolationScale = 7;
|
||||
|
||||
@Desc("Cliff Height Max. Disable with 0 for min and max")
|
||||
private double cliffHeightMax = 0;
|
||||
|
||||
@Desc("Cliff Height Min. Disable with 0 for min and max")
|
||||
private double cliffHeightMin = 0;
|
||||
|
||||
@Desc("The list of noise gens this gen contains.")
|
||||
private KList<IrisNoiseGenerator> composite = new KList<IrisNoiseGenerator>();
|
||||
|
||||
@Desc("The noise gen for cliff height.")
|
||||
private IrisNoiseGenerator cliffHeightGenerator = new IrisNoiseGenerator();
|
||||
|
||||
public double getMax()
|
||||
{
|
||||
return opacity;
|
||||
}
|
||||
|
||||
public boolean hasCliffs()
|
||||
{
|
||||
return cliffHeightMax > 0;
|
||||
}
|
||||
|
||||
public double getHeight(double rx, double rz, long superSeed)
|
||||
{
|
||||
if(composite.isEmpty())
|
||||
{
|
||||
Iris.warn("Useless Generator: Composite is empty in " + getLoadKey());
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hc = hashCode();
|
||||
double h = 0;
|
||||
double tp = 0;
|
||||
|
||||
for(IrisNoiseGenerator i : composite)
|
||||
{
|
||||
tp += i.getOpacity();
|
||||
h += i.getNoise(seed + superSeed + hc, (rx + offsetX) / zoom, (rz + offsetZ) / zoom);
|
||||
}
|
||||
|
||||
double v = (h / tp) * opacity;
|
||||
|
||||
if(Double.isNaN(v))
|
||||
{
|
||||
Iris.warn("Nan value on gen: " + getLoadKey() + ": H = " + h + " TP = " + tp + " OPACITY = " + opacity + " ZOOM = " + zoom);
|
||||
}
|
||||
|
||||
return hasCliffs() ? cliff(rx, rz, v, superSeed + 294596) : v;
|
||||
}
|
||||
|
||||
public double getCliffHeight(double rx, double rz, double superSeed)
|
||||
{
|
||||
int hc = hashCode();
|
||||
double h = cliffHeightGenerator.getNoise((long) (seed + superSeed + hc), (rx + offsetX) / zoom, (rz + offsetZ) / zoom);
|
||||
return IrisInterpolation.lerp(cliffHeightMin, cliffHeightMax, h);
|
||||
}
|
||||
|
||||
public double cliff(double rx, double rz, double v, double superSeed)
|
||||
{
|
||||
double cliffHeight = getCliffHeight(rx, rz, superSeed - 34857);
|
||||
return (Math.round((v * 255D) / cliffHeight) * cliffHeight) / 255D;
|
||||
}
|
||||
}
|
||||
117
src/main/java/com/volmit/iris/object/IrisNoiseGenerator.java
Normal file
117
src/main/java/com/volmit/iris/object/IrisNoiseGenerator.java
Normal file
@@ -0,0 +1,117 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import lombok.Data;
|
||||
import ninja.bytecode.iris.util.CNG;
|
||||
import ninja.bytecode.iris.util.Desc;
|
||||
import ninja.bytecode.iris.util.IrisInterpolation;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
|
||||
@Desc("A noise generator")
|
||||
@Data
|
||||
public class IrisNoiseGenerator
|
||||
{
|
||||
@Desc("The coordinate input zoom")
|
||||
private double zoom = 1;
|
||||
|
||||
@Desc("The output multiplier")
|
||||
private double opacity = 1;
|
||||
|
||||
@Desc("Coordinate offset x")
|
||||
private double offsetX = 0;
|
||||
|
||||
@Desc("Height output offset y")
|
||||
private double offsetY = 0;
|
||||
|
||||
@Desc("Coordinate offset z")
|
||||
private double offsetZ = 0;
|
||||
|
||||
@Desc("The seed")
|
||||
private long seed = 0;
|
||||
|
||||
@Desc("Apply a parametric curve on the output")
|
||||
private boolean parametric = false;
|
||||
@Desc("Apply a bezier curve on the output")
|
||||
private boolean bezier = false;
|
||||
|
||||
@Desc("Apply a sin-center curve on the output (0, and 1 = 0 and 0.5 = 1.0 using a sinoid shape.)")
|
||||
private boolean sinCentered = false;
|
||||
|
||||
@Desc("The exponent noise^EXPONENT")
|
||||
private double exponent = 1;
|
||||
|
||||
@Desc("Enable / disable. Outputs offsetY if disabled")
|
||||
private boolean enabled = true;
|
||||
|
||||
@Desc("If this generator uses the default iris swirly/wispy noise generator. Set to false for pure simplex.")
|
||||
private boolean irisBased = true;
|
||||
|
||||
@Desc("Multiple octaves for multple generators of changing zooms added together")
|
||||
private int octaves = 1;
|
||||
|
||||
@Desc("Apply a child noise generator to fracture the input coordinates of this generator")
|
||||
private KList<IrisNoiseGenerator> fracture = new KList<>();
|
||||
|
||||
private transient ReentrantLock lock;
|
||||
private transient CNG generator;
|
||||
|
||||
public IrisNoiseGenerator()
|
||||
{
|
||||
lock = new ReentrantLock();
|
||||
}
|
||||
|
||||
public IrisNoiseGenerator(boolean enabled)
|
||||
{
|
||||
this();
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
protected CNG getGenerator(long superSeed)
|
||||
{
|
||||
if(generator == null)
|
||||
{
|
||||
lock.lock();
|
||||
generator = irisBased ? CNG.signature(new RNG(superSeed + 33955677 - seed)) : new CNG(new RNG(superSeed + 33955677 - seed), 1D, octaves);
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
return generator;
|
||||
}
|
||||
|
||||
public double getMax()
|
||||
{
|
||||
return getOffsetY() + opacity;
|
||||
}
|
||||
|
||||
public double getNoise(long superSeed, double xv, double zv)
|
||||
{
|
||||
if(!enabled)
|
||||
{
|
||||
return offsetY;
|
||||
}
|
||||
|
||||
double x = xv;
|
||||
double z = zv;
|
||||
int g = 33;
|
||||
|
||||
for(IrisNoiseGenerator i : fracture)
|
||||
{
|
||||
if(i.isEnabled())
|
||||
{
|
||||
x += i.getNoise(superSeed + seed + g, xv, zv);
|
||||
z -= i.getNoise(superSeed + seed + g, zv, xv);
|
||||
}
|
||||
g += 819;
|
||||
}
|
||||
|
||||
double n = getGenerator(superSeed).fitDoubleD(0, opacity, (x / zoom) + offsetX, (z / zoom) + offsetZ);
|
||||
n = (exponent != 1 ? n < 0 ? -Math.pow(-n, exponent) : Math.pow(n, exponent) : n) + offsetY;
|
||||
n = parametric ? IrisInterpolation.parametric(n, 1) : n;
|
||||
n = bezier ? IrisInterpolation.bezier(n) : n;
|
||||
n = sinCentered ? IrisInterpolation.sinCenter(n) : n;
|
||||
|
||||
return n;
|
||||
}
|
||||
}
|
||||
221
src/main/java/com/volmit/iris/object/IrisObject.java
Normal file
221
src/main/java/com/volmit/iris/object/IrisObject.java
Normal file
@@ -0,0 +1,221 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.block.data.type.Leaves;
|
||||
import org.bukkit.util.BlockVector;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import ninja.bytecode.iris.util.BlockDataTools;
|
||||
import ninja.bytecode.iris.util.ChunkPosition;
|
||||
import ninja.bytecode.iris.util.IObjectPlacer;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
import ninja.bytecode.shuriken.collections.KMap;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class IrisObject extends IrisRegistrant
|
||||
{
|
||||
private static final Material SNOW = Material.SNOW;
|
||||
private static final BlockData[] SNOW_LAYERS = new BlockData[] {BlockDataTools.getBlockData("minecraft:snow[layers=1]"), BlockDataTools.getBlockData("minecraft:snow[layers=2]"), BlockDataTools.getBlockData("minecraft:snow[layers=3]"), BlockDataTools.getBlockData("minecraft:snow[layers=4]"), BlockDataTools.getBlockData("minecraft:snow[layers=5]"), BlockDataTools.getBlockData("minecraft:snow[layers=6]"), BlockDataTools.getBlockData("minecraft:snow[layers=7]"), BlockDataTools.getBlockData("minecraft:snow[layers=8]")};
|
||||
private KMap<BlockVector, BlockData> blocks;
|
||||
private int w;
|
||||
private int d;
|
||||
private int h;
|
||||
private transient BlockVector center;
|
||||
|
||||
public IrisObject(int w, int h, int d)
|
||||
{
|
||||
blocks = new KMap<>();
|
||||
this.w = w;
|
||||
this.h = h;
|
||||
this.d = d;
|
||||
center = new BlockVector(w / 2, h / 2, d / 2);
|
||||
}
|
||||
|
||||
public static BlockVector sampleSize(File file) throws IOException
|
||||
{
|
||||
FileInputStream in = new FileInputStream(file);
|
||||
DataInputStream din = new DataInputStream(in);
|
||||
BlockVector bv = new BlockVector(din.readInt(), din.readInt(), din.readInt());
|
||||
din.close();
|
||||
return bv;
|
||||
}
|
||||
|
||||
public void read(InputStream in) throws IOException
|
||||
{
|
||||
DataInputStream din = new DataInputStream(in);
|
||||
this.w = din.readInt();
|
||||
this.h = din.readInt();
|
||||
this.d = din.readInt();
|
||||
center = new BlockVector(w / 2, h / 2, d / 2);
|
||||
int s = din.readInt();
|
||||
|
||||
for(int i = 0; i < s; i++)
|
||||
{
|
||||
blocks.put(new BlockVector(din.readShort(), din.readShort(), din.readShort()), BlockDataTools.getBlockData(din.readUTF()));
|
||||
}
|
||||
}
|
||||
|
||||
public void read(File file) throws IOException
|
||||
{
|
||||
FileInputStream fin = new FileInputStream(file);
|
||||
read(fin);
|
||||
fin.close();
|
||||
}
|
||||
|
||||
public void write(File file) throws IOException
|
||||
{
|
||||
file.getParentFile().mkdirs();
|
||||
FileOutputStream out = new FileOutputStream(file);
|
||||
write(out);
|
||||
out.close();
|
||||
}
|
||||
|
||||
public void write(OutputStream o) throws IOException
|
||||
{
|
||||
DataOutputStream dos = new DataOutputStream(o);
|
||||
dos.writeInt(w);
|
||||
dos.writeInt(h);
|
||||
dos.writeInt(d);
|
||||
dos.writeInt(blocks.size());
|
||||
for(BlockVector i : blocks.k())
|
||||
{
|
||||
dos.writeShort(i.getBlockX());
|
||||
dos.writeShort(i.getBlockY());
|
||||
dos.writeShort(i.getBlockZ());
|
||||
dos.writeUTF(blocks.get(i).getAsString(true));
|
||||
}
|
||||
}
|
||||
|
||||
public void setUnsigned(int x, int y, int z, BlockData block)
|
||||
{
|
||||
if(x >= w || y >= h || z >= d)
|
||||
{
|
||||
throw new RuntimeException(x + " " + y + " " + z + " exceeds limit of " + w + " " + h + " " + d);
|
||||
}
|
||||
|
||||
BlockVector v = new BlockVector(x, y, z).subtract(center).toBlockVector();
|
||||
|
||||
if(block == null)
|
||||
{
|
||||
blocks.remove(v);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
blocks.put(v, block);
|
||||
}
|
||||
}
|
||||
|
||||
public void place(int x, int z, IObjectPlacer placer, IrisObjectPlacement config, RNG rng)
|
||||
{
|
||||
place(x, -1, z, placer, config, rng);
|
||||
}
|
||||
|
||||
public void place(int x, int yv, int z, IObjectPlacer placer, IrisObjectPlacement config, RNG rng)
|
||||
{
|
||||
boolean yf = rng.nextBoolean();
|
||||
boolean xf = rng.nextBoolean();
|
||||
int spinx = rng.imax() / 1000;
|
||||
int spiny = rng.imax() / 1000;
|
||||
int spinz = rng.imax() / 1000;
|
||||
int y = yv < 0 ? placer.getHighest(x, z, config.isUnderwater()) + config.getRotation().rotate(new BlockVector(0, getCenter().getBlockY(), 0), yf, xf, spinx, spiny, spinz).getBlockY() : yv;
|
||||
KMap<ChunkPosition, Integer> heightmap = config.getSnow() > 0 ? new KMap<>() : null;
|
||||
|
||||
if(!config.isUnderwater() && !config.isOnwater() && placer.isUnderwater(x, z))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for(BlockVector g : blocks.k())
|
||||
{
|
||||
BlockVector i = g.clone();
|
||||
i = config.getRotation().rotate(i.clone(), yf, xf, spinx, spiny, spinz).clone();
|
||||
i = config.getTranslate().translate(i.clone()).clone();
|
||||
BlockData data = blocks.get(g);
|
||||
|
||||
if(placer.isPreventingDecay() && data instanceof Leaves && !((Leaves) data).isPersistent())
|
||||
{
|
||||
((Leaves) data).setPersistent(true);
|
||||
}
|
||||
|
||||
for(IrisObjectReplace j : config.getEdit())
|
||||
{
|
||||
if(j.getFind().matches(data))
|
||||
{
|
||||
data = j.getReplace();
|
||||
}
|
||||
}
|
||||
|
||||
int xx = x + (int) Math.round(i.getX());
|
||||
int yy = y + (int) Math.round(i.getY());
|
||||
int zz = z + (int) Math.round(i.getZ());
|
||||
|
||||
if(heightmap != null)
|
||||
{
|
||||
ChunkPosition pos = new ChunkPosition(xx, zz);
|
||||
|
||||
if(!heightmap.containsKey(pos))
|
||||
{
|
||||
heightmap.put(pos, yy);
|
||||
}
|
||||
|
||||
if(heightmap.get(pos) < yy)
|
||||
{
|
||||
heightmap.put(pos, yy);
|
||||
}
|
||||
}
|
||||
|
||||
if(config.isMeld() && !placer.isSolid(xx, yy, zz))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
placer.set(xx, yy, zz, data);
|
||||
}
|
||||
|
||||
if(heightmap != null)
|
||||
{
|
||||
RNG rngx = rng.nextParallelRNG(3468854);
|
||||
|
||||
for(ChunkPosition i : heightmap.k())
|
||||
{
|
||||
int vx = i.getX();
|
||||
int vy = heightmap.get(i);
|
||||
int vz = i.getZ();
|
||||
|
||||
if(config.getSnow() > 0)
|
||||
{
|
||||
BlockData bd = placer.get(vx, vy, vz);
|
||||
if(bd != null && bd.getMaterial().equals(SNOW))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int height = rngx.i(0, (int) (config.getSnow() * 7));
|
||||
placer.set(vx, vy + 1, vz, SNOW_LAYERS[Math.max(Math.min(height, 7), 0)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void place(Location at)
|
||||
{
|
||||
for(BlockVector i : blocks.k())
|
||||
{
|
||||
at.clone().add(0, getCenter().getY(), 0).add(i).getBlock().setBlockData(blocks.get(i), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import lombok.Data;
|
||||
import ninja.bytecode.iris.Iris;
|
||||
import ninja.bytecode.iris.util.Desc;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
|
||||
@Data
|
||||
public class IrisObjectPlacement
|
||||
{
|
||||
@Desc("List of objects to place")
|
||||
private KList<String> place = new KList<>();
|
||||
|
||||
@Desc("Find and replace blocks")
|
||||
private KList<IrisObjectReplace> edit = new KList<>();
|
||||
|
||||
@Desc("Translate this object's placement")
|
||||
private IrisObjectTranslate translate = new IrisObjectTranslate();
|
||||
|
||||
@Desc("Rotate this objects placement")
|
||||
private IrisObjectRotation rotation = new IrisObjectRotation();
|
||||
|
||||
@Desc("The maximum layer level of a snow filter overtop of this placement. Set to 0 to disable. Max of 1.")
|
||||
private double snow = 0;
|
||||
|
||||
@Desc("The chance for this to place in a chunk. If you need multiple per chunk, set this to 1 and use density.")
|
||||
private double chance = 1;
|
||||
|
||||
@Desc("If the chance check passes, place this many in a single chunk")
|
||||
private int density = 1;
|
||||
|
||||
@Desc("If set to true, objects will place on the terrain height, ignoring the water surface.")
|
||||
private boolean underwater = false;
|
||||
|
||||
@Desc("If set to true, objects will place on the fluid height level Such as boats.")
|
||||
private boolean onwater = false;
|
||||
|
||||
@Desc("If set to true, this object will only place parts of itself where blocks already exist.")
|
||||
private boolean meld = false;
|
||||
|
||||
public IrisObjectPlacement()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public IrisObject getSchematic(RNG random)
|
||||
{
|
||||
if(place.isEmpty())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return Iris.data.getObjectLoader().load(place.get(random.nextInt(place.size())));
|
||||
}
|
||||
|
||||
public int getTriesForChunk(RNG random)
|
||||
{
|
||||
if(chance <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(chance >= 1 || random.nextDouble() < chance)
|
||||
{
|
||||
return density;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
46
src/main/java/com/volmit/iris/object/IrisObjectReplace.java
Normal file
46
src/main/java/com/volmit/iris/object/IrisObjectReplace.java
Normal file
@@ -0,0 +1,46 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import lombok.Data;
|
||||
import ninja.bytecode.iris.util.BlockDataTools;
|
||||
import ninja.bytecode.iris.util.Desc;
|
||||
|
||||
@Desc("Find and replace object materials")
|
||||
@Data
|
||||
public class IrisObjectReplace
|
||||
{
|
||||
private String find;
|
||||
private String replace;
|
||||
|
||||
private transient ReentrantLock lock = new ReentrantLock();
|
||||
private transient BlockData findData;
|
||||
private transient BlockData replaceData;
|
||||
|
||||
public IrisObjectReplace()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public BlockData getFind()
|
||||
{
|
||||
if(findData == null)
|
||||
{
|
||||
findData = BlockDataTools.getBlockData(find);
|
||||
}
|
||||
|
||||
return findData;
|
||||
}
|
||||
|
||||
public BlockData getReplace()
|
||||
{
|
||||
if(replaceData == null)
|
||||
{
|
||||
replaceData = BlockDataTools.getBlockData(replace);
|
||||
}
|
||||
|
||||
return replaceData;
|
||||
}
|
||||
}
|
||||
112
src/main/java/com/volmit/iris/object/IrisObjectRotation.java
Normal file
112
src/main/java/com/volmit/iris/object/IrisObjectRotation.java
Normal file
@@ -0,0 +1,112 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import org.bukkit.util.BlockVector;
|
||||
|
||||
import lombok.Data;
|
||||
import ninja.bytecode.iris.util.Desc;
|
||||
|
||||
@Desc("Configures rotation for iris")
|
||||
@Data
|
||||
public class IrisObjectRotation
|
||||
{
|
||||
@Desc("If this rotator is enabled or not")
|
||||
private boolean enabled = true;
|
||||
@Desc("The x axis rotation")
|
||||
private IrisAxisRotationClamp xAxis = new IrisAxisRotationClamp();
|
||||
@Desc("The y axis rotation")
|
||||
private IrisAxisRotationClamp yAxis = new IrisAxisRotationClamp(true, 0, 0, 90);
|
||||
@Desc("The z axis rotation")
|
||||
private IrisAxisRotationClamp zAxis = new IrisAxisRotationClamp();
|
||||
|
||||
public IrisObjectRotation()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public double getYRotation(int spin)
|
||||
{
|
||||
return getRotation(spin, yAxis);
|
||||
}
|
||||
|
||||
public double getXRotation(int spin)
|
||||
{
|
||||
return getRotation(spin, xAxis);
|
||||
}
|
||||
|
||||
public double getZRotation(int spin)
|
||||
{
|
||||
return getRotation(spin, zAxis);
|
||||
}
|
||||
|
||||
public double getRotation(int spin, IrisAxisRotationClamp clamp)
|
||||
{
|
||||
if(!enabled)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!clamp.isEnabled())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return clamp.getRadians(spin);
|
||||
}
|
||||
|
||||
public BlockVector rotate(BlockVector b, boolean yf, boolean xf, int spinx, int spiny, int spinz)
|
||||
{
|
||||
if(!canRotate())
|
||||
{
|
||||
return b;
|
||||
}
|
||||
|
||||
BlockVector v = b.clone();
|
||||
|
||||
if(yf && canRotateY())
|
||||
{
|
||||
v.rotateAroundY(getYRotation(spiny));
|
||||
}
|
||||
|
||||
if(xf && canRotateX())
|
||||
{
|
||||
v.rotateAroundX(getXRotation(spinx));
|
||||
}
|
||||
|
||||
if(canRotateZ())
|
||||
{
|
||||
v.rotateAroundZ(getZRotation(spinz));
|
||||
}
|
||||
|
||||
if(!xf && canRotateX())
|
||||
{
|
||||
v.rotateAroundX(getXRotation(spinx));
|
||||
}
|
||||
|
||||
if(!yf && canRotateY())
|
||||
{
|
||||
v.rotateAroundY(getYRotation(spiny));
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
public boolean canRotateX()
|
||||
{
|
||||
return enabled && xAxis.isEnabled();
|
||||
}
|
||||
|
||||
public boolean canRotateY()
|
||||
{
|
||||
return enabled && yAxis.isEnabled();
|
||||
}
|
||||
|
||||
public boolean canRotateZ()
|
||||
{
|
||||
return enabled && zAxis.isEnabled();
|
||||
}
|
||||
|
||||
public boolean canRotate()
|
||||
{
|
||||
return canRotateX() || canRotateY() || canRotateZ();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import org.bukkit.util.BlockVector;
|
||||
|
||||
import lombok.Data;
|
||||
import ninja.bytecode.iris.util.Desc;
|
||||
|
||||
@Desc("Translate objects")
|
||||
@Data
|
||||
public class IrisObjectTranslate
|
||||
{
|
||||
@Desc("The x shift in blocks")
|
||||
private int x;
|
||||
|
||||
@Desc("The x shift in blocks")
|
||||
private int y;
|
||||
|
||||
@Desc("The x shift in blocks")
|
||||
private int z;
|
||||
|
||||
public IrisObjectTranslate()
|
||||
{
|
||||
x = 0;
|
||||
y = 0;
|
||||
z = 0;
|
||||
}
|
||||
|
||||
public boolean canTranslate()
|
||||
{
|
||||
return x != 0 || y != 0 || z != 0;
|
||||
}
|
||||
|
||||
public BlockVector translate(BlockVector i)
|
||||
{
|
||||
if(canTranslate())
|
||||
{
|
||||
return (BlockVector) i.clone().add(new BlockVector(x, y, z));
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
}
|
||||
127
src/main/java/com/volmit/iris/object/IrisRegion.java
Normal file
127
src/main/java/com/volmit/iris/object/IrisRegion.java
Normal file
@@ -0,0 +1,127 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import ninja.bytecode.iris.Iris;
|
||||
import ninja.bytecode.iris.util.CNG;
|
||||
import ninja.bytecode.iris.util.Desc;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
import ninja.bytecode.shuriken.collections.KMap;
|
||||
import ninja.bytecode.shuriken.collections.KSet;
|
||||
|
||||
@Desc("Represents an iris region")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class IrisRegion extends IrisRegistrant
|
||||
{
|
||||
@Desc("The name of the region")
|
||||
private String name = "A Region";
|
||||
@Desc("The shore ration (How much percent of land should be a shore)")
|
||||
private double shoreRatio = 0.13;
|
||||
|
||||
@Desc("The min shore height")
|
||||
private double shoreHeightMin = 1.2;
|
||||
|
||||
@Desc("The the max shore height")
|
||||
private double shoreHeightMax = 3.2;
|
||||
|
||||
@Desc("The varience of the shore height")
|
||||
private double shoreHeightZoom = 3.14;
|
||||
|
||||
@Desc("The biome implosion ratio, how much to implode biomes into children (chance)")
|
||||
private double biomeImplosionRatio = 0.4;
|
||||
|
||||
@Desc("A list of root-level biomes in this region. Don't specify child biomes of other biomes here. Just the root parents.")
|
||||
private KList<String> landBiomes = new KList<>();
|
||||
|
||||
@Desc("A list of root-level biomes in this region. Don't specify child biomes of other biomes here. Just the root parents.")
|
||||
private KList<String> seaBiomes = new KList<>();
|
||||
|
||||
@Desc("A list of root-level biomes in this region. Don't specify child biomes of other biomes here. Just the root parents.")
|
||||
private KList<String> shoreBiomes = new KList<>();
|
||||
|
||||
@Desc("Ridge biomes create a vein-like network like rivers through this region")
|
||||
private KList<IrisRegionRidge> ridgeBiomes = new KList<>();
|
||||
|
||||
@Desc("Spot biomes splotch themselves across this region like lakes")
|
||||
private KList<IrisRegionSpot> spotBiomes = new KList<>();
|
||||
|
||||
@Desc("Define regional deposit generators that add onto the global deposit generators")
|
||||
private KList<IrisDepositGenerator> deposits = new KList<>();
|
||||
|
||||
private transient KList<String> cacheRidge;
|
||||
private transient KList<String> cacheSpot;
|
||||
private transient CNG shoreHeightGenerator;
|
||||
private transient ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
public KList<String> getRidgeBiomeKeys()
|
||||
{
|
||||
lock.lock();
|
||||
if(cacheRidge == null)
|
||||
{
|
||||
cacheRidge = new KList<String>();
|
||||
ridgeBiomes.forEach((i) -> cacheRidge.add(i.getBiome()));
|
||||
}
|
||||
lock.unlock();
|
||||
|
||||
return cacheRidge;
|
||||
}
|
||||
|
||||
public KList<String> getSpotBiomeKeys()
|
||||
{
|
||||
lock.lock();
|
||||
if(cacheSpot == null)
|
||||
{
|
||||
cacheSpot = new KList<String>();
|
||||
spotBiomes.forEach((i) -> cacheSpot.add(i.getBiome()));
|
||||
}
|
||||
lock.unlock();
|
||||
|
||||
return cacheSpot;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public KList<IrisBiome> getAllBiomes()
|
||||
{
|
||||
KMap<String, IrisBiome> b = new KMap<>();
|
||||
KSet<String> names = new KSet<>();
|
||||
names.addAll(landBiomes);
|
||||
names.addAll(seaBiomes);
|
||||
names.addAll(shoreBiomes);
|
||||
spotBiomes.forEach((i) -> names.add(i.getBiome()));
|
||||
ridgeBiomes.forEach((i) -> names.add(i.getBiome()));
|
||||
|
||||
while(!names.isEmpty())
|
||||
{
|
||||
for(String i : new KList<>(names))
|
||||
{
|
||||
if(b.containsKey(i))
|
||||
{
|
||||
names.remove(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
IrisBiome biome = Iris.data.getBiomeLoader().load(i);
|
||||
b.put(biome.getLoadKey(), biome);
|
||||
names.remove(i);
|
||||
names.addAll(biome.getChildren());
|
||||
}
|
||||
}
|
||||
|
||||
return b.v();
|
||||
}
|
||||
}
|
||||
69
src/main/java/com/volmit/iris/object/IrisRegionRidge.java
Normal file
69
src/main/java/com/volmit/iris/object/IrisRegionRidge.java
Normal file
@@ -0,0 +1,69 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import lombok.Data;
|
||||
import ninja.bytecode.iris.util.CellGenerator;
|
||||
import ninja.bytecode.iris.util.Desc;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
|
||||
@Desc("A ridge config")
|
||||
@Data
|
||||
public class IrisRegionRidge
|
||||
{
|
||||
@Desc("The biome name")
|
||||
private String biome;
|
||||
@Desc("The type this biome should override (land sea or shore)")
|
||||
private InferredType type = InferredType.LAND;
|
||||
@Desc("What type this spot is (i.e. target SEA but as LAND) like an island. Default matches the target type")
|
||||
private InferredType as = InferredType.DEFER;
|
||||
@Desc("The chance this biome will be placed in a given spot")
|
||||
private double chance = 0.75;
|
||||
@Desc("The scale of the biome ridge. Higher values = wider veins & bigger connected cells")
|
||||
private double scale = 5;
|
||||
@Desc("The chance scale (cell chances)")
|
||||
private double chanceScale = 4;
|
||||
@Desc("The shuffle, how 'natural' this looks. Compared to pure polygons")
|
||||
private double shuffle = 16;
|
||||
@Desc("The chance shuffle (polygon cell chances)")
|
||||
private double chanceShuffle = 128;
|
||||
@Desc("The thickness of the vein")
|
||||
private double thickness = 0.125;
|
||||
private transient CellGenerator spot;
|
||||
private transient CellGenerator ridge;
|
||||
|
||||
public IrisRegionRidge()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public boolean isRidge(RNG rng, double x, double z)
|
||||
{
|
||||
if(ridge == null)
|
||||
{
|
||||
ridge = new CellGenerator(rng.nextParallelRNG(165583 * hashCode()));
|
||||
ridge.setCellScale(scale);
|
||||
ridge.setShuffle(shuffle);
|
||||
}
|
||||
|
||||
if(spot == null)
|
||||
{
|
||||
spot = new CellGenerator(rng.nextParallelRNG(168523 * hashCode()));
|
||||
spot.setCellScale(chanceScale);
|
||||
spot.setShuffle(shuffle);
|
||||
}
|
||||
|
||||
if(chance < 1)
|
||||
{
|
||||
if(spot.getIndex(x, z, 1000) > chance * 1000)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(ridge.getDistance(x, z) <= thickness)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
48
src/main/java/com/volmit/iris/object/IrisRegionSpot.java
Normal file
48
src/main/java/com/volmit/iris/object/IrisRegionSpot.java
Normal file
@@ -0,0 +1,48 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import lombok.Data;
|
||||
import ninja.bytecode.iris.util.CellGenerator;
|
||||
import ninja.bytecode.iris.util.Desc;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
|
||||
@Desc("A spot config")
|
||||
@Data
|
||||
public class IrisRegionSpot
|
||||
{
|
||||
@Desc("The biome to be placed")
|
||||
private String biome;
|
||||
@Desc("Where this spot overrides. Land sea or shore")
|
||||
private InferredType type = InferredType.LAND;
|
||||
@Desc("What type this spot is (i.e. target SEA but as LAND) like an island. Default matches the target type")
|
||||
private InferredType as = InferredType.DEFER;
|
||||
@Desc("The scale of splotches")
|
||||
private double scale = 1;
|
||||
@Desc("Rarity is how often this splotch appears. higher = less often")
|
||||
private double rarity = 1;
|
||||
@Desc("The shuffle or how natural the splotch looks like (anti-polygon)")
|
||||
private double shuffle = 128;
|
||||
|
||||
private transient CellGenerator spot;
|
||||
|
||||
public IrisRegionSpot()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public boolean isSpot(RNG rng, double x, double z)
|
||||
{
|
||||
if(spot == null)
|
||||
{
|
||||
spot = new CellGenerator(rng.nextParallelRNG(168583 * hashCode()));
|
||||
spot.setCellScale(scale);
|
||||
spot.setShuffle(shuffle);
|
||||
}
|
||||
|
||||
if(spot.getIndex(x, z, (int) (Math.round(rarity) + 8)) == (int) ((Math.round(rarity) + 8) / 2))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
9
src/main/java/com/volmit/iris/object/IrisRegistrant.java
Normal file
9
src/main/java/com/volmit/iris/object/IrisRegistrant.java
Normal file
@@ -0,0 +1,9 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class IrisRegistrant
|
||||
{
|
||||
private String loadKey;
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package ninja.bytecode.iris.object.atomics;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.bukkit.World;
|
||||
|
||||
import ninja.bytecode.iris.util.ByteArrayTag;
|
||||
import ninja.bytecode.iris.util.CompoundTag;
|
||||
import ninja.bytecode.iris.util.NBTInputStream;
|
||||
import ninja.bytecode.iris.util.NBTOutputStream;
|
||||
import ninja.bytecode.iris.util.Tag;
|
||||
import ninja.bytecode.shuriken.collections.KMap;
|
||||
|
||||
public class AtomicRegionData
|
||||
{
|
||||
private final World world;
|
||||
private KMap<String, Tag> tag;
|
||||
|
||||
public AtomicRegionData(World world)
|
||||
{
|
||||
this.world = world;
|
||||
tag = new KMap<>();
|
||||
}
|
||||
|
||||
public void read(InputStream in) throws IOException
|
||||
{
|
||||
NBTInputStream nin = new NBTInputStream(in);
|
||||
tag = new KMap<>();
|
||||
tag.putAll(((CompoundTag) nin.readTag()).getValue());
|
||||
nin.close();
|
||||
}
|
||||
|
||||
public void write(OutputStream out) throws IOException
|
||||
{
|
||||
NBTOutputStream nos = new NBTOutputStream(out);
|
||||
nos.writeTag(new CompoundTag("imca", tag));
|
||||
nos.close();
|
||||
}
|
||||
|
||||
public boolean contains(int rx, int rz)
|
||||
{
|
||||
return tag.containsKey(rx + "." + rz);
|
||||
}
|
||||
|
||||
public void delete(int rx, int rz)
|
||||
{
|
||||
tag.remove(rx + "." + rz);
|
||||
}
|
||||
|
||||
public void set(int rx, int rz, AtomicSliverMap data) throws IOException
|
||||
{
|
||||
if(data == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ByteArrayOutputStream boas = new ByteArrayOutputStream();
|
||||
data.write(boas);
|
||||
tag.put(rx + "." + rz, new ByteArrayTag(rx + "." + rz, boas.toByteArray()));
|
||||
}
|
||||
|
||||
public AtomicSliverMap get(int rx, int rz) throws IOException
|
||||
{
|
||||
AtomicSliverMap data = new AtomicSliverMap();
|
||||
|
||||
if(!contains(rx, rz))
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
ByteArrayTag btag = (ByteArrayTag) tag.get(rx + "." + rz);
|
||||
ByteArrayInputStream in = new ByteArrayInputStream(btag.getValue());
|
||||
data.read(in);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public World getWorld()
|
||||
{
|
||||
return world;
|
||||
}
|
||||
}
|
||||
169
src/main/java/com/volmit/iris/object/atomics/AtomicSliver.java
Normal file
169
src/main/java/com/volmit/iris/object/atomics/AtomicSliver.java
Normal file
@@ -0,0 +1,169 @@
|
||||
package ninja.bytecode.iris.object.atomics;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.generator.ChunkGenerator.BiomeGrid;
|
||||
import org.bukkit.generator.ChunkGenerator.ChunkData;
|
||||
|
||||
import lombok.Data;
|
||||
import ninja.bytecode.iris.util.BlockDataTools;
|
||||
import ninja.bytecode.iris.util.HeightMap;
|
||||
import ninja.bytecode.shuriken.collections.KMap;
|
||||
|
||||
@Data
|
||||
public class AtomicSliver
|
||||
{
|
||||
public static final BlockData AIR = BlockDataTools.getBlockData("AIR");
|
||||
private KMap<Integer, BlockData> block;
|
||||
private KMap<Integer, Biome> biome;
|
||||
private int highestBlock = 0;
|
||||
private int highestBiome = 0;
|
||||
private int x;
|
||||
private int z;
|
||||
|
||||
public AtomicSliver(int x, int z)
|
||||
{
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
this.block = new KMap<>();
|
||||
this.biome = new KMap<>();
|
||||
}
|
||||
|
||||
public Material getType(int h)
|
||||
{
|
||||
return get(h).getMaterial();
|
||||
}
|
||||
|
||||
public BlockData get(int h)
|
||||
{
|
||||
BlockData b = block.get(h);
|
||||
|
||||
if(b == null)
|
||||
{
|
||||
return AIR;
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
public void set(int h, BlockData d)
|
||||
{
|
||||
if(d == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
block.put(h, d);
|
||||
highestBlock = h > highestBlock ? h : highestBlock;
|
||||
}
|
||||
|
||||
public void setSilently(int h, BlockData d)
|
||||
{
|
||||
if(d == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
block.put(h, d);
|
||||
}
|
||||
|
||||
public boolean isSolid(int h)
|
||||
{
|
||||
return getType(h).isSolid();
|
||||
}
|
||||
|
||||
public void set(int h, Biome d)
|
||||
{
|
||||
biome.put(h, d);
|
||||
highestBiome = h > highestBiome ? h : highestBiome;
|
||||
}
|
||||
|
||||
public void write(ChunkData d)
|
||||
{
|
||||
for(int i = 0; i <= highestBlock; i++)
|
||||
{
|
||||
if(block.get(i) == null)
|
||||
{
|
||||
d.setBlock(x, i, z, AIR);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
d.setBlock(x, i, z, block.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void write(BiomeGrid d)
|
||||
{
|
||||
for(int i = 0; i <= highestBiome; i++)
|
||||
{
|
||||
if(biome.get(i) != null)
|
||||
{
|
||||
d.setBiome(x, i, z, biome.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void write(HeightMap height)
|
||||
{
|
||||
height.setHeight(x, z, highestBlock);
|
||||
}
|
||||
|
||||
public void read(DataInputStream din) throws IOException
|
||||
{
|
||||
this.block = new KMap<Integer, BlockData>();
|
||||
int h = din.readByte() - Byte.MIN_VALUE;
|
||||
highestBlock = h;
|
||||
|
||||
for(int i = 0; i <= h; i++)
|
||||
{
|
||||
block.put(i, BlockDataTools.getBlockData(din.readUTF()));
|
||||
}
|
||||
}
|
||||
|
||||
public void write(DataOutputStream dos) throws IOException
|
||||
{
|
||||
dos.writeByte(highestBlock + Byte.MIN_VALUE);
|
||||
|
||||
for(int i = 0; i <= highestBlock; i++)
|
||||
{
|
||||
BlockData dat = block.get(i);
|
||||
dos.writeUTF((dat == null ? AIR : dat).getAsString(true));
|
||||
}
|
||||
}
|
||||
|
||||
public void insert(AtomicSliver atomicSliver)
|
||||
{
|
||||
for(int i = 0; i < 256; i++)
|
||||
{
|
||||
if(block.get(i) == null || block.get(i).equals(AIR))
|
||||
{
|
||||
BlockData b = atomicSliver.block.get(i);
|
||||
if(b == null || b.equals(AIR))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
block.put(i, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void inject(ChunkData currentData)
|
||||
{
|
||||
for(int i = 0; i < 256; i++)
|
||||
{
|
||||
if(block.get(i) != null && !block.get(i).equals(AIR))
|
||||
{
|
||||
BlockData b = block.get(i);
|
||||
currentData.setBlock(x, i, z, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package ninja.bytecode.iris.object.atomics;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.bukkit.generator.ChunkGenerator.BiomeGrid;
|
||||
import org.bukkit.generator.ChunkGenerator.ChunkData;
|
||||
|
||||
import lombok.Data;
|
||||
import ninja.bytecode.iris.util.HeightMap;
|
||||
|
||||
@Data
|
||||
public class AtomicSliverMap
|
||||
{
|
||||
private final AtomicSliver[] slivers;
|
||||
private boolean parallaxGenerated;
|
||||
private boolean worldGenerated;
|
||||
|
||||
public AtomicSliverMap()
|
||||
{
|
||||
parallaxGenerated = false;
|
||||
worldGenerated = false;
|
||||
slivers = new AtomicSliver[256];
|
||||
|
||||
for(int i = 0; i < 16; i++)
|
||||
{
|
||||
for(int j = 0; j < 16; j++)
|
||||
{
|
||||
slivers[i * 16 + j] = new AtomicSliver(i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void insert(AtomicSliverMap map)
|
||||
{
|
||||
for(int i = 0; i < 256; i++)
|
||||
{
|
||||
slivers[i].insert(map.slivers[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void write(OutputStream out) throws IOException
|
||||
{
|
||||
DataOutputStream dos = new DataOutputStream(out);
|
||||
dos.writeBoolean(isParallaxGenerated());
|
||||
dos.writeBoolean(isWorldGenerated());
|
||||
for(int i = 0; i < 256; i++)
|
||||
{
|
||||
slivers[i].write(dos);
|
||||
}
|
||||
|
||||
dos.flush();
|
||||
}
|
||||
|
||||
public void read(InputStream in) throws IOException
|
||||
{
|
||||
DataInputStream din = new DataInputStream(in);
|
||||
parallaxGenerated = din.readBoolean();
|
||||
worldGenerated = din.readBoolean();
|
||||
|
||||
for(int i = 0; i < 256; i++)
|
||||
{
|
||||
slivers[i].read(din);
|
||||
}
|
||||
}
|
||||
|
||||
public AtomicSliver getSliver(int x, int z)
|
||||
{
|
||||
return slivers[x * 16 + z];
|
||||
}
|
||||
|
||||
public void write(ChunkData data, BiomeGrid grid, HeightMap height)
|
||||
{
|
||||
for(AtomicSliver i : slivers)
|
||||
{
|
||||
if(i != null)
|
||||
{
|
||||
i.write(data);
|
||||
i.write(grid);
|
||||
i.write(height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void inject(ChunkData currentData)
|
||||
{
|
||||
for(AtomicSliver i : slivers)
|
||||
{
|
||||
i.inject(currentData);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,285 @@
|
||||
package ninja.bytecode.iris.object.atomics;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.bukkit.World;
|
||||
|
||||
import ninja.bytecode.iris.Iris;
|
||||
import ninja.bytecode.iris.util.ChronoLatch;
|
||||
import ninja.bytecode.iris.util.ChunkPosition;
|
||||
import ninja.bytecode.shuriken.collections.KMap;
|
||||
import ninja.bytecode.shuriken.math.M;
|
||||
|
||||
public class AtomicWorldData
|
||||
{
|
||||
private World world;
|
||||
private KMap<ChunkPosition, AtomicSliverMap> loadedChunks;
|
||||
private KMap<ChunkPosition, AtomicRegionData> loadedSections;
|
||||
private KMap<ChunkPosition, Long> lastRegion;
|
||||
private KMap<ChunkPosition, Long> lastChunk;
|
||||
private String prefix;
|
||||
private ChronoLatch cl = new ChronoLatch(15000);
|
||||
|
||||
public AtomicWorldData(World world, String prefix)
|
||||
{
|
||||
this.world = world;
|
||||
loadedSections = new KMap<>();
|
||||
loadedChunks = new KMap<>();
|
||||
lastRegion = new KMap<>();
|
||||
lastChunk = new KMap<>();
|
||||
this.prefix = prefix;
|
||||
getSubregionFolder().mkdirs();
|
||||
}
|
||||
|
||||
public KMap<ChunkPosition, AtomicRegionData> getLoadedRegions()
|
||||
{
|
||||
return loadedSections;
|
||||
}
|
||||
|
||||
public AtomicRegionData getSubregion(int x, int z) throws IOException
|
||||
{
|
||||
lastRegion.put(new ChunkPosition(x, z), M.ms());
|
||||
|
||||
if(!isSectionLoaded(x, z))
|
||||
{
|
||||
loadedSections.put(new ChunkPosition(x, z), loadSection(x, z));
|
||||
}
|
||||
|
||||
AtomicRegionData f = loadedSections.get(new ChunkPosition(x, z));
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
public void saveAll() throws IOException
|
||||
{
|
||||
saveChunks();
|
||||
|
||||
for(ChunkPosition i : loadedSections.keySet())
|
||||
{
|
||||
saveSection(i);
|
||||
}
|
||||
}
|
||||
|
||||
public void unloadAll(boolean save) throws IOException
|
||||
{
|
||||
saveChunks();
|
||||
|
||||
for(ChunkPosition i : loadedSections.keySet())
|
||||
{
|
||||
unloadSection(i, save);
|
||||
}
|
||||
|
||||
loadedSections.clear();
|
||||
loadedChunks.clear();
|
||||
lastRegion.clear();
|
||||
}
|
||||
|
||||
public void deleteSection(int x, int z) throws IOException
|
||||
{
|
||||
unloadSection(x, z, false);
|
||||
getSubregionFile(x, z).delete();
|
||||
}
|
||||
|
||||
public boolean isSectionLoaded(int x, int z)
|
||||
{
|
||||
return isSectionLoaded(new ChunkPosition(x, z));
|
||||
}
|
||||
|
||||
public boolean isSectionLoaded(ChunkPosition s)
|
||||
{
|
||||
return loadedSections.containsKey(s);
|
||||
}
|
||||
|
||||
public boolean unloadSection(int x, int z, boolean save) throws IOException
|
||||
{
|
||||
return unloadSection(new ChunkPosition(x, z), save);
|
||||
}
|
||||
|
||||
public boolean unloadSection(ChunkPosition s, boolean save) throws IOException
|
||||
{
|
||||
if(!isSectionLoaded(s))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(save)
|
||||
{
|
||||
saveSection(s);
|
||||
}
|
||||
|
||||
loadedSections.remove(s);
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean saveSection(int x, int z) throws IOException
|
||||
{
|
||||
return saveSection(new ChunkPosition(x, z));
|
||||
}
|
||||
|
||||
public boolean saveSection(ChunkPosition s) throws IOException
|
||||
{
|
||||
if(!isSectionLoaded(s.getX(), s.getZ()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
saveChunks(s);
|
||||
AtomicRegionData data = loadedSections.get(s);
|
||||
FileOutputStream fos = new FileOutputStream(getSubregionFile(s.getX(), s.getZ()));
|
||||
data.write(fos);
|
||||
fos.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void saveChunks() throws IOException
|
||||
{
|
||||
for(ChunkPosition i : loadedChunks.k())
|
||||
{
|
||||
saveChunk(i);
|
||||
}
|
||||
}
|
||||
|
||||
public void saveChunks(ChunkPosition reg) throws IOException
|
||||
{
|
||||
for(ChunkPosition i : loadedChunks.k())
|
||||
{
|
||||
int x = i.getX();
|
||||
int z = i.getZ();
|
||||
|
||||
if(x >> 5 == reg.getX() && z >> 5 == reg.getZ())
|
||||
{
|
||||
saveChunk(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void saveChunk(ChunkPosition i) throws IOException
|
||||
{
|
||||
int x = i.getX();
|
||||
int z = i.getZ();
|
||||
AtomicRegionData dat = loadSection(x >> 5, z >> 5);
|
||||
dat.set(x & 31, z & 31, loadedChunks.get(i));
|
||||
loadedChunks.remove(i);
|
||||
}
|
||||
|
||||
public AtomicSliverMap loadChunk(int x, int z) throws IOException
|
||||
{
|
||||
ChunkPosition pos = new ChunkPosition(x, z);
|
||||
lastChunk.put(pos, M.ms());
|
||||
if(loadedChunks.containsKey(pos))
|
||||
{
|
||||
return loadedChunks.get(pos);
|
||||
}
|
||||
|
||||
AtomicRegionData dat = loadSection(x >> 5, z >> 5);
|
||||
AtomicSliverMap m = dat.get(x & 31, z & 31);
|
||||
loadedChunks.put(pos, m);
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
public boolean hasChunk(int x, int z) throws IOException
|
||||
{
|
||||
return loadSection(x >> 5, z >> 5).contains(x & 31, z & 31);
|
||||
}
|
||||
|
||||
public AtomicRegionData loadSection(int x, int z) throws IOException
|
||||
{
|
||||
ChunkPosition pos = new ChunkPosition(x, z);
|
||||
lastRegion.put(pos, M.ms());
|
||||
|
||||
if(isSectionLoaded(x, z))
|
||||
{
|
||||
return loadedSections.get(pos);
|
||||
}
|
||||
|
||||
File file = getSubregionFile(x, z);
|
||||
|
||||
if(!file.exists())
|
||||
{
|
||||
AtomicRegionData dat = createSection(x, z);
|
||||
loadedSections.put(pos, dat);
|
||||
return dat;
|
||||
}
|
||||
|
||||
FileInputStream fin = new FileInputStream(file);
|
||||
AtomicRegionData data = new AtomicRegionData(world);
|
||||
data.read(fin);
|
||||
fin.close();
|
||||
loadedSections.put(pos, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
public AtomicRegionData createSection(int x, int z)
|
||||
{
|
||||
if(isSectionLoaded(x, z))
|
||||
{
|
||||
return loadedSections.get(new ChunkPosition(x, z));
|
||||
}
|
||||
|
||||
AtomicRegionData data = new AtomicRegionData(world);
|
||||
loadedSections.put(new ChunkPosition(x, z), data);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public File getSubregionFile(int x, int z)
|
||||
{
|
||||
return new File(getSubregionFolder(), "sr." + x + "." + z + ".smca");
|
||||
}
|
||||
|
||||
public File getSubregionFolder()
|
||||
{
|
||||
return new File(world.getWorldFolder(), "subregion-" + prefix);
|
||||
}
|
||||
|
||||
public KMap<ChunkPosition, AtomicSliverMap> getLoadedChunks()
|
||||
{
|
||||
return loadedChunks;
|
||||
}
|
||||
|
||||
public void clean(int j)
|
||||
{
|
||||
if(!cl.flip())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for(ChunkPosition i : lastRegion.k())
|
||||
{
|
||||
if(M.ms() - lastRegion.get(i) > 60000)
|
||||
{
|
||||
lastRegion.remove(i);
|
||||
|
||||
try
|
||||
{
|
||||
unloadSection(i, true);
|
||||
}
|
||||
|
||||
catch(IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(ChunkPosition i : lastChunk.k())
|
||||
{
|
||||
if(M.ms() - lastChunk.get(i) > 60000)
|
||||
{
|
||||
try
|
||||
{
|
||||
saveChunk(i);
|
||||
}
|
||||
|
||||
catch(IOException e)
|
||||
{
|
||||
Iris.warn("Failed to save chunk");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
48
src/main/java/com/volmit/iris/object/atomics/MasterLock.java
Normal file
48
src/main/java/com/volmit/iris/object/atomics/MasterLock.java
Normal file
@@ -0,0 +1,48 @@
|
||||
package ninja.bytecode.iris.object.atomics;
|
||||
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import ninja.bytecode.shuriken.collections.KMap;
|
||||
|
||||
public class MasterLock
|
||||
{
|
||||
private KMap<String, ReentrantLock> locks;
|
||||
private ReentrantLock lock;
|
||||
|
||||
public MasterLock()
|
||||
{
|
||||
locks = new KMap<>();
|
||||
lock = new ReentrantLock();
|
||||
}
|
||||
|
||||
public void clear()
|
||||
{
|
||||
locks.clear();
|
||||
}
|
||||
|
||||
public void lock(String key)
|
||||
{
|
||||
lock.lock();
|
||||
if(!locks.containsKey(key))
|
||||
{
|
||||
locks.put(key, new ReentrantLock());
|
||||
}
|
||||
|
||||
ReentrantLock l = locks.get(key);
|
||||
lock.unlock();
|
||||
l.lock();
|
||||
}
|
||||
|
||||
public void unlock(String key)
|
||||
{
|
||||
lock.lock();
|
||||
if(!locks.containsKey(key))
|
||||
{
|
||||
locks.put(key, new ReentrantLock());
|
||||
}
|
||||
|
||||
ReentrantLock l = locks.get(key);
|
||||
lock.unlock();
|
||||
l.unlock();
|
||||
}
|
||||
}
|
||||
85
src/main/java/com/volmit/iris/util/Average.java
Normal file
85
src/main/java/com/volmit/iris/util/Average.java
Normal file
@@ -0,0 +1,85 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
/**
|
||||
* Provides an incredibly fast averaging object. It swaps values from a sum
|
||||
* using an array. Averages do not use any form of looping. An average of 10,000
|
||||
* entries is the same speed as an average with 5 entries.
|
||||
*
|
||||
* @author cyberpwn
|
||||
*
|
||||
*/
|
||||
public class Average {
|
||||
protected double[] values;
|
||||
private double average;
|
||||
private double lastSum;
|
||||
private boolean dirty;
|
||||
protected int cursor;
|
||||
private boolean brandNew;
|
||||
|
||||
/**
|
||||
* Create an average holder
|
||||
*
|
||||
* @param size the size of entries to keep
|
||||
*/
|
||||
public Average(int size) {
|
||||
values = new double[size];
|
||||
DoubleArrayUtils.fill(values, 0);
|
||||
brandNew = true;
|
||||
average = 0;
|
||||
cursor = 0;
|
||||
lastSum = 0;
|
||||
dirty = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a value into the average (rolls over if full)
|
||||
*
|
||||
* @param i the value
|
||||
*/
|
||||
public void put(double i) {
|
||||
|
||||
dirty = true;
|
||||
|
||||
if(brandNew)
|
||||
{
|
||||
DoubleArrayUtils.fill(values, i);
|
||||
lastSum = size() * i;
|
||||
brandNew = false;
|
||||
return;
|
||||
}
|
||||
|
||||
double current = values[cursor];
|
||||
lastSum = (lastSum - current) + i;
|
||||
values[cursor] = i;
|
||||
cursor = cursor + 1 < size() ? cursor + 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current average
|
||||
*
|
||||
* @return the average
|
||||
*/
|
||||
public double getAverage() {
|
||||
if (dirty) {
|
||||
calculateAverage();
|
||||
return getAverage();
|
||||
}
|
||||
|
||||
return average;
|
||||
}
|
||||
|
||||
private void calculateAverage() {
|
||||
average = lastSum / (double) size();
|
||||
dirty = false;
|
||||
}
|
||||
|
||||
public int size()
|
||||
{
|
||||
return values.length;
|
||||
}
|
||||
|
||||
public boolean isDirty()
|
||||
{
|
||||
return dirty;
|
||||
}
|
||||
}
|
||||
31
src/main/java/com/volmit/iris/util/Axis.java
Normal file
31
src/main/java/com/volmit/iris/util/Axis.java
Normal file
@@ -0,0 +1,31 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
public enum Axis
|
||||
{
|
||||
X(1, 0, 0),
|
||||
Y(0, 1, 0),
|
||||
Z(0, 0, 1);
|
||||
|
||||
private int x;
|
||||
private int y;
|
||||
private int z;
|
||||
|
||||
private Axis(int x, int y, int z)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public Vector positive()
|
||||
{
|
||||
return new Vector(x, y, z);
|
||||
}
|
||||
|
||||
public Vector negative()
|
||||
{
|
||||
return VectorMath.reverse(positive());
|
||||
}
|
||||
}
|
||||
219
src/main/java/com/volmit/iris/util/BasePerlinNoiseGenerator.java
Normal file
219
src/main/java/com/volmit/iris/util/BasePerlinNoiseGenerator.java
Normal file
@@ -0,0 +1,219 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Generates noise using the "classic" perlin generator
|
||||
*
|
||||
* @see SimplexNoiseC "Improved" and faster version with slighly
|
||||
* different results
|
||||
*/
|
||||
public class BasePerlinNoiseGenerator extends NoiseGenerator
|
||||
{
|
||||
protected static final int grad3[][] = {{1, 1, 0}, {-1, 1, 0}, {1, -1, 0}, {-1, -1, 0}, {1, 0, 1}, {-1, 0, 1}, {1, 0, -1}, {-1, 0, -1}, {0, 1, 1}, {0, -1, 1}, {0, 1, -1}, {0, -1, -1}};
|
||||
private static final BasePerlinNoiseGenerator instance = new BasePerlinNoiseGenerator();
|
||||
|
||||
protected BasePerlinNoiseGenerator()
|
||||
{
|
||||
int p[] = {151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180};
|
||||
|
||||
for(int i = 0; i < 512; i++)
|
||||
{
|
||||
perm[i] = p[i & 255];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a seeded perlin noise generator for the given seed
|
||||
*
|
||||
* @param seed
|
||||
* Seed to construct this generator for
|
||||
*/
|
||||
public BasePerlinNoiseGenerator(long seed)
|
||||
{
|
||||
this(new Random(seed));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a seeded perlin noise generator with the given Random
|
||||
*
|
||||
* @param rand
|
||||
* Random to construct with
|
||||
*/
|
||||
public BasePerlinNoiseGenerator(Random rand)
|
||||
{
|
||||
offsetX = rand.nextDouble() * 256;
|
||||
offsetY = rand.nextDouble() * 256;
|
||||
offsetZ = rand.nextDouble() * 256;
|
||||
|
||||
for(int i = 0; i < 256; i++)
|
||||
{
|
||||
perm[i] = rand.nextInt(256);
|
||||
}
|
||||
|
||||
for(int i = 0; i < 256; i++)
|
||||
{
|
||||
int pos = rand.nextInt(256 - i) + i;
|
||||
int old = perm[i];
|
||||
|
||||
perm[i] = perm[pos];
|
||||
perm[pos] = old;
|
||||
perm[i + 256] = perm[i];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes and returns the 1D unseeded perlin noise for the given coordinates
|
||||
* in 1D space
|
||||
*
|
||||
* @param x
|
||||
* X coordinate
|
||||
* @return Noise at given location, from range -1 to 1
|
||||
*/
|
||||
public static double getNoise(double x)
|
||||
{
|
||||
return instance.noise(x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes and returns the 2D unseeded perlin noise for the given coordinates
|
||||
* in 2D space
|
||||
*
|
||||
* @param x
|
||||
* X coordinate
|
||||
* @param y
|
||||
* Y coordinate
|
||||
* @return Noise at given location, from range -1 to 1
|
||||
*/
|
||||
public static double getNoise(double x, double y)
|
||||
{
|
||||
return instance.noise(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes and returns the 3D unseeded perlin noise for the given coordinates
|
||||
* in 3D space
|
||||
*
|
||||
* @param x
|
||||
* X coordinate
|
||||
* @param y
|
||||
* Y coordinate
|
||||
* @param z
|
||||
* Z coordinate
|
||||
* @return Noise at given location, from range -1 to 1
|
||||
*/
|
||||
public static double getNoise(double x, double y, double z)
|
||||
{
|
||||
return instance.noise(x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the singleton unseeded instance of this generator
|
||||
*
|
||||
* @return Singleton
|
||||
*/
|
||||
public static BasePerlinNoiseGenerator getInstance()
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double noise(double x, double y, double z)
|
||||
{
|
||||
x += offsetX;
|
||||
y += offsetY;
|
||||
z += offsetZ;
|
||||
|
||||
int floorX = floor(x);
|
||||
int floorY = floor(y);
|
||||
int floorZ = floor(z);
|
||||
|
||||
// Find unit cube containing the point
|
||||
int X = floorX & 255;
|
||||
int Y = floorY & 255;
|
||||
int Z = floorZ & 255;
|
||||
|
||||
// Get relative xyz coordinates of the point within the cube
|
||||
x -= floorX;
|
||||
y -= floorY;
|
||||
z -= floorZ;
|
||||
|
||||
// Compute fade curves for xyz
|
||||
double fX = fade(x);
|
||||
double fY = fade(y);
|
||||
double fZ = fade(z);
|
||||
|
||||
// Hash coordinates of the cube corners
|
||||
int A = perm[X] + Y;
|
||||
int AA = perm[A] + Z;
|
||||
int AB = perm[A + 1] + Z;
|
||||
int B = perm[X + 1] + Y;
|
||||
int BA = perm[B] + Z;
|
||||
int BB = perm[B + 1] + Z;
|
||||
|
||||
return lerp(fZ, lerp(fY, lerp(fX, grad(perm[AA], x, y, z), grad(perm[BA], x - 1, y, z)), lerp(fX, grad(perm[AB], x, y - 1, z), grad(perm[BB], x - 1, y - 1, z))), lerp(fY, lerp(fX, grad(perm[AA + 1], x, y, z - 1), grad(perm[BA + 1], x - 1, y, z - 1)), lerp(fX, grad(perm[AB + 1], x, y - 1, z - 1), grad(perm[BB + 1], x - 1, y - 1, z - 1))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates noise for the 1D coordinates using the specified number of octaves
|
||||
* and parameters
|
||||
*
|
||||
* @param x
|
||||
* X-coordinate
|
||||
* @param octaves
|
||||
* Number of octaves to use
|
||||
* @param frequency
|
||||
* How much to alter the frequency by each octave
|
||||
* @param amplitude
|
||||
* How much to alter the amplitude by each octave
|
||||
* @return Resulting noise
|
||||
*/
|
||||
public static double getNoise(double x, int octaves, double frequency, double amplitude)
|
||||
{
|
||||
return instance.noise(x, octaves, frequency, amplitude);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates noise for the 2D coordinates using the specified number of octaves
|
||||
* and parameters
|
||||
*
|
||||
* @param x
|
||||
* X-coordinate
|
||||
* @param y
|
||||
* Y-coordinate
|
||||
* @param octaves
|
||||
* Number of octaves to use
|
||||
* @param frequency
|
||||
* How much to alter the frequency by each octave
|
||||
* @param amplitude
|
||||
* How much to alter the amplitude by each octave
|
||||
* @return Resulting noise
|
||||
*/
|
||||
public static double getNoise(double x, double y, int octaves, double frequency, double amplitude)
|
||||
{
|
||||
return instance.noise(x, y, octaves, frequency, amplitude);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates noise for the 3D coordinates using the specified number of octaves
|
||||
* and parameters
|
||||
*
|
||||
* @param x
|
||||
* X-coordinate
|
||||
* @param y
|
||||
* Y-coordinate
|
||||
* @param z
|
||||
* Z-coordinate
|
||||
* @param octaves
|
||||
* Number of octaves to use
|
||||
* @param frequency
|
||||
* How much to alter the frequency by each octave
|
||||
* @param amplitude
|
||||
* How much to alter the amplitude by each octave
|
||||
* @return Resulting noise
|
||||
*/
|
||||
public static double getNoise(double x, double y, double z, int octaves, double frequency, double amplitude)
|
||||
{
|
||||
return instance.noise(x, y, z, octaves, frequency, amplitude);
|
||||
}
|
||||
}
|
||||
9
src/main/java/com/volmit/iris/util/BiomeDominance.java
Normal file
9
src/main/java/com/volmit/iris/util/BiomeDominance.java
Normal file
@@ -0,0 +1,9 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import ninja.bytecode.iris.object.IrisBiome;
|
||||
import ninja.bytecode.shuriken.collections.KMap;
|
||||
|
||||
public class BiomeDominance extends KMap<IrisBiome, Double>
|
||||
{
|
||||
private static final long serialVersionUID = 9055245062942178392L;
|
||||
}
|
||||
23
src/main/java/com/volmit/iris/util/BiomeMap.java
Normal file
23
src/main/java/com/volmit/iris/util/BiomeMap.java
Normal file
@@ -0,0 +1,23 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import ninja.bytecode.iris.object.IrisBiome;
|
||||
|
||||
public class BiomeMap
|
||||
{
|
||||
private final IrisBiome[] height;
|
||||
|
||||
public BiomeMap()
|
||||
{
|
||||
height = new IrisBiome[256];
|
||||
}
|
||||
|
||||
public void setBiome(int x, int z, IrisBiome h)
|
||||
{
|
||||
height[x * 16 + z] = h;
|
||||
}
|
||||
|
||||
public IrisBiome getBiome(int x, int z)
|
||||
{
|
||||
return height[x * 16 + z];
|
||||
}
|
||||
}
|
||||
22
src/main/java/com/volmit/iris/util/BiomeResult.java
Normal file
22
src/main/java/com/volmit/iris/util/BiomeResult.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import lombok.Data;
|
||||
import ninja.bytecode.iris.object.IrisBiome;
|
||||
|
||||
@Data
|
||||
public class BiomeResult
|
||||
{
|
||||
private IrisBiome biome;
|
||||
private double distance;
|
||||
|
||||
public BiomeResult(IrisBiome biome, double distance)
|
||||
{
|
||||
this.biome = biome;
|
||||
this.distance = distance;
|
||||
}
|
||||
|
||||
public boolean is(BiomeResult r)
|
||||
{
|
||||
return biome.getName().equals(r.biome.getName());
|
||||
}
|
||||
}
|
||||
82
src/main/java/com/volmit/iris/util/BlockDataTools.java
Normal file
82
src/main/java/com/volmit/iris/util/BlockDataTools.java
Normal file
@@ -0,0 +1,82 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import ninja.bytecode.iris.Iris;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
import ninja.bytecode.shuriken.collections.KMap;
|
||||
|
||||
public class BlockDataTools
|
||||
{
|
||||
private static final KMap<String, BlockData> bdc = new KMap<>();
|
||||
private static final KList<String> nulls = new KList<>();
|
||||
|
||||
public static BlockData getBlockData(String bd)
|
||||
{
|
||||
if(bdc.containsKey(bd))
|
||||
{
|
||||
return bdc.get(bd).clone();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
BlockData bdx = parseBlockData(bd);
|
||||
|
||||
if(bdx == null)
|
||||
{
|
||||
Iris.warn("Unknown Block Data '" + bd + "'");
|
||||
nulls.add(bd);
|
||||
return bdx;
|
||||
}
|
||||
|
||||
bdc.put(bd, bdx);
|
||||
|
||||
return bdx;
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
Iris.warn("Unknown Block Data '" + bd + "'");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static BlockData parseBlockData(String ix)
|
||||
{
|
||||
try
|
||||
{
|
||||
BlockData bx = Bukkit.createBlockData(ix);
|
||||
|
||||
if(bx != null)
|
||||
{
|
||||
return bx;
|
||||
}
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
String i = ix.toUpperCase().trim();
|
||||
i = i.equals("WOOL") ? "WHITE_WOOL" : i;
|
||||
i = i.equals("CONCRETE") ? "WHITE_CONCRETE" : i;
|
||||
|
||||
try
|
||||
{
|
||||
Material m = Material.valueOf(i);
|
||||
|
||||
return m.createBlockData();
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
28
src/main/java/com/volmit/iris/util/BlockPosition.java
Normal file
28
src/main/java/com/volmit/iris/util/BlockPosition.java
Normal file
@@ -0,0 +1,28 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class BlockPosition
|
||||
{
|
||||
private int x;
|
||||
private int y;
|
||||
private int z;
|
||||
|
||||
public BlockPosition(int x, int y, int z)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public int getChunkX()
|
||||
{
|
||||
return x >> 4;
|
||||
}
|
||||
|
||||
public int getChunkZ()
|
||||
{
|
||||
return z >> 4;
|
||||
}
|
||||
}
|
||||
131
src/main/java/com/volmit/iris/util/Board.java
Normal file
131
src/main/java/com/volmit/iris/util/Board.java
Normal file
@@ -0,0 +1,131 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.scoreboard.DisplaySlot;
|
||||
import org.bukkit.scoreboard.Objective;
|
||||
import org.bukkit.scoreboard.Scoreboard;
|
||||
import org.bukkit.scoreboard.Team;
|
||||
|
||||
import lombok.NonNull;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author Missionary (missionarymc@gmail.com)
|
||||
* @since 3/23/2018
|
||||
*/
|
||||
public class Board {
|
||||
|
||||
private static final String[] CACHED_ENTRIES = new String[ChatColor.values().length];
|
||||
|
||||
private static final Function<String, String> APPLY_COLOR_TRANSLATION = s -> ChatColor.translateAlternateColorCodes('&', s);
|
||||
|
||||
static {
|
||||
IntStream.range(0, 15).forEach(i -> CACHED_ENTRIES[i] = ChatColor.values()[i].toString() + ChatColor.RESET);
|
||||
}
|
||||
|
||||
private final Player player;
|
||||
private final Objective objective;
|
||||
private final Team team;
|
||||
@Setter private BoardSettings boardSettings;
|
||||
private boolean ready;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public Board(@NonNull final Player player, final BoardSettings boardSettings) {
|
||||
this.player = player;
|
||||
this.boardSettings = boardSettings;
|
||||
this.objective = this.getScoreboard().getObjective("board") == null ? this.getScoreboard().registerNewObjective("board", "dummy") : this.getScoreboard().getObjective("board");
|
||||
this.objective.setDisplaySlot(DisplaySlot.SIDEBAR);
|
||||
this.team = this.getScoreboard().getTeam("board") == null ? this.getScoreboard().registerNewTeam("board") : this.getScoreboard().getTeam("board");
|
||||
this.team.setAllowFriendlyFire(true);
|
||||
this.team.setCanSeeFriendlyInvisibles(false);
|
||||
this.team.setPrefix("");
|
||||
this.team.setSuffix("");
|
||||
this.ready = true;
|
||||
}
|
||||
|
||||
public Scoreboard getScoreboard() {
|
||||
return (player != null) ? player.getScoreboard() : null;
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
this.resetScoreboard();
|
||||
}
|
||||
|
||||
public void update() {
|
||||
// Checking if we are ready to start updating the Scoreboard.
|
||||
if (!ready) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Making sure the player is connected.
|
||||
if (!player.isOnline()) {
|
||||
remove();
|
||||
return;
|
||||
}
|
||||
|
||||
// Making sure the Scoreboard Provider is set.
|
||||
if (boardSettings == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Getting their Scoreboard display from the Scoreboard Provider.
|
||||
final List<String> entries = boardSettings.getBoardProvider().getLines(player).stream().map(APPLY_COLOR_TRANSLATION).collect(Collectors.toList());
|
||||
|
||||
if (boardSettings.getScoreDirection() == ScoreDirection.UP) {
|
||||
Collections.reverse(entries);
|
||||
}
|
||||
|
||||
// Setting the Scoreboard title
|
||||
String title = boardSettings.getBoardProvider().getTitle(player);
|
||||
if (title.length() > 32) {
|
||||
Bukkit.getLogger().warning("The title " + title + " is over 32 characters in length, substringing to prevent errors.");
|
||||
title = title.substring(0, 32);
|
||||
}
|
||||
objective.setDisplayName(ChatColor.translateAlternateColorCodes('&', title));
|
||||
|
||||
// Clearing previous Scoreboard values if entry sizes don't match.
|
||||
if (this.getScoreboard().getEntries().size() != entries.size())
|
||||
this.getScoreboard().getEntries().forEach(this::removeEntry);
|
||||
|
||||
// Setting Scoreboard lines.
|
||||
for (int i = 0; i < entries.size(); i++) {
|
||||
String str = entries.get(i);
|
||||
BoardEntry entry = BoardEntry.translateToEntry(str);
|
||||
Team team = getScoreboard().getTeam(CACHED_ENTRIES[i]);
|
||||
|
||||
if (team == null) {
|
||||
team = this.getScoreboard().registerNewTeam(CACHED_ENTRIES[i]);
|
||||
team.addEntry(team.getName());
|
||||
}
|
||||
|
||||
team.setPrefix(entry.getPrefix());
|
||||
team.setSuffix(entry.getSuffix());
|
||||
|
||||
switch (boardSettings.getScoreDirection()) {
|
||||
case UP:
|
||||
objective.getScore(team.getName()).setScore(1 + i);
|
||||
break;
|
||||
case DOWN:
|
||||
objective.getScore(team.getName()).setScore(15 - i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeEntry(String id) {
|
||||
this.getScoreboard().resetScores(id);
|
||||
}
|
||||
|
||||
public void resetScoreboard() {
|
||||
ready = false;
|
||||
player.setScoreboard(Bukkit.getScoreboardManager().getMainScoreboard());
|
||||
}
|
||||
}
|
||||
40
src/main/java/com/volmit/iris/util/BoardEntry.java
Normal file
40
src/main/java/com/volmit/iris/util/BoardEntry.java
Normal file
@@ -0,0 +1,40 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.bukkit.ChatColor;
|
||||
|
||||
/**
|
||||
* @author Missionary (missionarymc@gmail.com)
|
||||
* @since 3/29/2018
|
||||
*/
|
||||
public class BoardEntry {
|
||||
|
||||
@Getter
|
||||
private final String prefix, suffix;
|
||||
|
||||
private BoardEntry(final String prefix, final String suffix) {
|
||||
this.prefix = prefix;
|
||||
this.suffix = suffix;
|
||||
}
|
||||
|
||||
public static BoardEntry translateToEntry(String input) {
|
||||
if (input.isEmpty()) {
|
||||
return new BoardEntry("", "");
|
||||
}
|
||||
if (input.length() <= 16) {
|
||||
return new BoardEntry(input, "");
|
||||
} else {
|
||||
String prefix = input.substring(0, 16);
|
||||
String suffix = "";
|
||||
|
||||
if (prefix.endsWith("\u00a7")) {
|
||||
prefix = prefix.substring(0, prefix.length() - 1);
|
||||
suffix = "\u00a7" + suffix;
|
||||
}
|
||||
|
||||
suffix = StringUtils.left(ChatColor.getLastColors(prefix) + suffix + input.substring(16), 16);
|
||||
return new BoardEntry(prefix, suffix);
|
||||
}
|
||||
}
|
||||
}
|
||||
86
src/main/java/com/volmit/iris/util/BoardManager.java
Normal file
86
src/main/java/com/volmit/iris/util/BoardManager.java
Normal file
@@ -0,0 +1,86 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* @author Missionary (missionarymc@gmail.com)
|
||||
* @since 3/23/2018
|
||||
*/
|
||||
public class BoardManager implements Listener {
|
||||
|
||||
private final JavaPlugin plugin;
|
||||
private BoardSettings boardSettings;
|
||||
private Map<UUID, Board> scoreboards;
|
||||
private BukkitTask updateTask;
|
||||
|
||||
public BoardManager(JavaPlugin plugin, BoardSettings boardSettings) {
|
||||
this.plugin = plugin;
|
||||
this.boardSettings = boardSettings;
|
||||
this.scoreboards = new ConcurrentHashMap<>();
|
||||
this.updateTask = new BoardUpdateTask(this).runTaskTimer(plugin, 2L, 2L);
|
||||
plugin.getServer().getPluginManager().registerEvents(this, plugin);
|
||||
plugin.getServer().getOnlinePlayers().forEach(this::setup);
|
||||
}
|
||||
|
||||
public void setBoardSettings(BoardSettings boardSettings) {
|
||||
this.boardSettings = boardSettings;
|
||||
scoreboards.values().forEach(board -> board.setBoardSettings(boardSettings));
|
||||
}
|
||||
|
||||
public boolean hasBoard(Player player) {
|
||||
return scoreboards.containsKey(player.getUniqueId());
|
||||
}
|
||||
|
||||
public Optional<Board> getBoard(Player player) {
|
||||
return Optional.ofNullable(scoreboards.get(player.getUniqueId()));
|
||||
}
|
||||
|
||||
private void setup(Player player) {
|
||||
Optional.ofNullable(scoreboards.remove(player.getUniqueId())).ifPresent(Board::resetScoreboard);
|
||||
if (player.getScoreboard() == Bukkit.getScoreboardManager().getMainScoreboard()) {
|
||||
player.setScoreboard(Bukkit.getScoreboardManager().getNewScoreboard());
|
||||
}
|
||||
scoreboards.put(player.getUniqueId(), new Board(player, boardSettings));
|
||||
}
|
||||
|
||||
private void remove(Player player) {
|
||||
Optional.ofNullable(scoreboards.remove(player.getUniqueId())).ifPresent(Board::remove);
|
||||
}
|
||||
|
||||
public Map<UUID, Board> getScoreboards() {
|
||||
return Collections.unmodifiableMap(scoreboards);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onJoin(final PlayerJoinEvent e) {
|
||||
plugin.getServer().getScheduler().runTaskLater(plugin, () -> {
|
||||
if (e.getPlayer().isOnline()) { // Set this up 2 ticks later.
|
||||
setup(e.getPlayer());
|
||||
}
|
||||
}, 2L);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onQuit(final PlayerQuitEvent e) {
|
||||
this.remove(e.getPlayer());
|
||||
}
|
||||
|
||||
public void onDisable() {
|
||||
updateTask.cancel();
|
||||
plugin.getServer().getOnlinePlayers().forEach(this::remove);
|
||||
scoreboards.clear();
|
||||
}
|
||||
}
|
||||
25
src/main/java/com/volmit/iris/util/BoardProvider.java
Normal file
25
src/main/java/com/volmit/iris/util/BoardProvider.java
Normal file
@@ -0,0 +1,25 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.scoreboard.Objective;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface BoardProvider {
|
||||
|
||||
/**
|
||||
* Gets the title for {@link Objective#getDisplayName()}
|
||||
*
|
||||
* @param player The {@link Player} to supply
|
||||
* @return The title for the objective
|
||||
*/
|
||||
String getTitle(Player player);
|
||||
|
||||
/**
|
||||
* Gets the contents to be displayed on the {@link Board}
|
||||
*
|
||||
* @param player The {@link Player} to supply
|
||||
* @return The {@link List} of contents
|
||||
*/
|
||||
List<String> getLines(Player player);
|
||||
}
|
||||
18
src/main/java/com/volmit/iris/util/BoardSettings.java
Normal file
18
src/main/java/com/volmit/iris/util/BoardSettings.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author Missionary (missionarymc@gmail.com)
|
||||
* @since 5/31/2018
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
public class BoardSettings {
|
||||
|
||||
private BoardProvider boardProvider;
|
||||
|
||||
private ScoreDirection scoreDirection;
|
||||
|
||||
}
|
||||
26
src/main/java/com/volmit/iris/util/BoardUpdateTask.java
Normal file
26
src/main/java/com/volmit/iris/util/BoardUpdateTask.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* @author Missionary (missionarymc@gmail.com)
|
||||
* @since 5/31/2018
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class BoardUpdateTask extends BukkitRunnable {
|
||||
|
||||
private static final Predicate<UUID> PLAYER_IS_ONLINE = uuid -> Bukkit.getPlayer(uuid) != null;
|
||||
|
||||
private final BoardManager boardManager;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
boardManager.getScoreboards().entrySet().stream().filter(entrySet -> PLAYER_IS_ONLINE.test(entrySet.getKey())).forEach(entrySet -> entrySet.getValue().update());
|
||||
}
|
||||
}
|
||||
7
src/main/java/com/volmit/iris/util/BorderCheck.java
Normal file
7
src/main/java/com/volmit/iris/util/BorderCheck.java
Normal file
@@ -0,0 +1,7 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface BorderCheck<T>
|
||||
{
|
||||
public T get(double x, double z);
|
||||
}
|
||||
44
src/main/java/com/volmit/iris/util/Borders.java
Normal file
44
src/main/java/com/volmit/iris/util/Borders.java
Normal file
@@ -0,0 +1,44 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import ninja.bytecode.shuriken.math.M;
|
||||
|
||||
public class Borders
|
||||
{
|
||||
public static <T> double getDistanceToBorder(double x, double z, int samples, double minRadius, double maxRadius, double jump, BorderCheck<T> check)
|
||||
{
|
||||
double offset = 0;
|
||||
double fract = 1;
|
||||
|
||||
for(double i = minRadius; i < maxRadius; i += jump * fract)
|
||||
{
|
||||
offset += jump / 3D;
|
||||
fract += 0.333;
|
||||
|
||||
if(isBorderWithin(x, z, samples, maxRadius, offset, check))
|
||||
{
|
||||
return minRadius;
|
||||
}
|
||||
}
|
||||
|
||||
return maxRadius;
|
||||
}
|
||||
|
||||
public static <T> boolean isBorderWithin(double x, double z, int samples, double radius, double offset, BorderCheck<T> check)
|
||||
{
|
||||
T center = check.get(x, z);
|
||||
double ajump = Math.toRadians(360D / (double) samples) + offset;
|
||||
|
||||
for(int i = 0; i < samples; i++)
|
||||
{
|
||||
double dx = M.sin((float) ajump * i) * radius;
|
||||
double dz = M.cos((float) ajump * i) * radius;
|
||||
|
||||
if(!center.equals(check.get(x + dx, z + dz)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
82
src/main/java/com/volmit/iris/util/ByteArrayTag.java
Normal file
82
src/main/java/com/volmit/iris/util/ByteArrayTag.java
Normal file
@@ -0,0 +1,82 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
/*
|
||||
* JNBT License
|
||||
*
|
||||
* Copyright (c) 2010 Graham Edgecombe
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the JNBT team nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/**
|
||||
* The <code>TAG_Byte_Array</code> tag.
|
||||
*
|
||||
* @author Graham Edgecombe
|
||||
*
|
||||
*/
|
||||
public final class ByteArrayTag extends Tag {
|
||||
|
||||
/**
|
||||
* The value.
|
||||
*/
|
||||
private final byte[] value;
|
||||
|
||||
/**
|
||||
* Creates the tag.
|
||||
*
|
||||
* @param name The name.
|
||||
* @param value The value.
|
||||
*/
|
||||
public ByteArrayTag(String name, byte[] value) {
|
||||
super(name);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder hex = new StringBuilder();
|
||||
for (byte b : value) {
|
||||
String hexDigits = Integer.toHexString(b).toUpperCase();
|
||||
if (hexDigits.length() == 1) {
|
||||
hex.append("0");
|
||||
}
|
||||
hex.append(hexDigits).append(" ");
|
||||
}
|
||||
String name = getName();
|
||||
String append = "";
|
||||
if (name != null && !name.equals("")) {
|
||||
append = "(\"" + this.getName() + "\")";
|
||||
}
|
||||
return "TAG_Byte_Array" + append + ": " + hex.toString();
|
||||
}
|
||||
|
||||
}
|
||||
74
src/main/java/com/volmit/iris/util/ByteTag.java
Normal file
74
src/main/java/com/volmit/iris/util/ByteTag.java
Normal file
@@ -0,0 +1,74 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
/*
|
||||
* JNBT License
|
||||
*
|
||||
* Copyright (c) 2010 Graham Edgecombe
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the JNBT team nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/**
|
||||
* The <code>TAG_Byte</code> tag.
|
||||
*
|
||||
* @author Graham Edgecombe
|
||||
*
|
||||
*/
|
||||
public final class ByteTag extends Tag {
|
||||
|
||||
/**
|
||||
* The value.
|
||||
*/
|
||||
private final byte value;
|
||||
|
||||
/**
|
||||
* Creates the tag.
|
||||
*
|
||||
* @param name The name.
|
||||
* @param value The value.
|
||||
*/
|
||||
public ByteTag(String name, byte value) {
|
||||
super(name);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Byte getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String name = getName();
|
||||
String append = "";
|
||||
if (name != null && !name.equals("")) {
|
||||
append = "(\"" + this.getName() + "\")";
|
||||
}
|
||||
return "TAG_Byte" + append + ": " + value;
|
||||
}
|
||||
|
||||
}
|
||||
49
src/main/java/com/volmit/iris/util/CDou.java
Normal file
49
src/main/java/com/volmit/iris/util/CDou.java
Normal file
@@ -0,0 +1,49 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
public class CDou
|
||||
{
|
||||
private double number;
|
||||
private double max;
|
||||
|
||||
public CDou(double max)
|
||||
{
|
||||
number = 0;
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
public CDou set(double n)
|
||||
{
|
||||
number = n;
|
||||
circ();
|
||||
return this;
|
||||
}
|
||||
|
||||
public CDou add(double a)
|
||||
{
|
||||
number += a;
|
||||
circ();
|
||||
return this;
|
||||
}
|
||||
|
||||
public CDou sub(double a)
|
||||
{
|
||||
number -= a;
|
||||
circ();
|
||||
return this;
|
||||
}
|
||||
|
||||
public double get()
|
||||
{
|
||||
return number;
|
||||
}
|
||||
|
||||
public void circ()
|
||||
{
|
||||
if(number < 0)
|
||||
{
|
||||
number = max - (Math.abs(number) > max ? max : Math.abs(number));
|
||||
}
|
||||
|
||||
number = number % (max);
|
||||
}
|
||||
}
|
||||
225
src/main/java/com/volmit/iris/util/CNG.java
Normal file
225
src/main/java/com/volmit/iris/util/CNG.java
Normal file
@@ -0,0 +1,225 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
|
||||
public class CNG
|
||||
{
|
||||
public static long hits = 0;
|
||||
public static long creates = 0;
|
||||
public static final NoiseInjector ADD = (s, v) -> new double[] {s + v, 1};
|
||||
public static final NoiseInjector SRC_SUBTRACT = (s, v) -> new double[] {s - v < 0 ? 0 : s - v, -1};
|
||||
public static final NoiseInjector DST_SUBTRACT = (s, v) -> new double[] {v - s < 0 ? 0 : s - v, -1};
|
||||
public static final NoiseInjector MULTIPLY = (s, v) -> new double[] {s * v, 0};
|
||||
public static final NoiseInjector MAX = (s, v) -> new double[] {Math.max(s, v), 0};
|
||||
public static final NoiseInjector MIN = (s, v) -> new double[] {Math.min(s, v), 0};
|
||||
public static final NoiseInjector SRC_MOD = (s, v) -> new double[] {s % v, 0};
|
||||
public static final NoiseInjector SRC_POW = (s, v) -> new double[] {Math.pow(s, v), 0};
|
||||
public static final NoiseInjector DST_MOD = (s, v) -> new double[] {v % s, 0};
|
||||
public static final NoiseInjector DST_POW = (s, v) -> new double[] {Math.pow(v, s), 0};
|
||||
private double freq;
|
||||
private double amp;
|
||||
private double scale;
|
||||
private double fscale;
|
||||
private KList<CNG> children;
|
||||
private CNG fracture;
|
||||
private SNG generator;
|
||||
private final double opacity;
|
||||
private NoiseInjector injector;
|
||||
private RNG rng;
|
||||
private int oct;
|
||||
private double patch;
|
||||
private double up;
|
||||
private double down;
|
||||
private double power;
|
||||
|
||||
public static CNG signature(RNG rng)
|
||||
{
|
||||
//@builder
|
||||
return new CNG(rng.nextParallelRNG(17), 1D, 3)
|
||||
.scale(0.012)
|
||||
.fractureWith(new CNG(rng.nextParallelRNG(18), 1, 2)
|
||||
.scale(0.018)
|
||||
.child(new CNG(rng.nextParallelRNG(19), 1, 2)
|
||||
.scale(0.1))
|
||||
.fractureWith(new CNG(rng.nextParallelRNG(20), 1, 2)
|
||||
.scale(0.15), 24), 44).down(0.3).patch(2.5);
|
||||
//@done
|
||||
}
|
||||
|
||||
public CNG(RNG random)
|
||||
{
|
||||
this(random, 1);
|
||||
}
|
||||
|
||||
public CNG(RNG random, int octaves)
|
||||
{
|
||||
this(random, 1D, octaves);
|
||||
}
|
||||
|
||||
public CNG(RNG random, double opacity, int octaves)
|
||||
{
|
||||
creates += octaves;
|
||||
this.oct = octaves;
|
||||
this.rng = random;
|
||||
power = 1;
|
||||
freq = 1;
|
||||
amp = 1;
|
||||
scale = 1;
|
||||
patch = 1;
|
||||
fscale = 1;
|
||||
fracture = null;
|
||||
generator = new SNG(random);
|
||||
this.opacity = opacity;
|
||||
this.injector = ADD;
|
||||
}
|
||||
|
||||
public CNG child(CNG c)
|
||||
{
|
||||
if(children == null)
|
||||
{
|
||||
children = new KList<>();
|
||||
}
|
||||
|
||||
children.add(c);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public RNG nextRNG()
|
||||
{
|
||||
return getRNG().nextRNG();
|
||||
}
|
||||
|
||||
public RNG getRNG()
|
||||
{
|
||||
return rng;
|
||||
}
|
||||
|
||||
public CNG fractureWith(CNG c, double scale)
|
||||
{
|
||||
fracture = c;
|
||||
fscale = scale;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CNG scale(double c)
|
||||
{
|
||||
scale = c;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CNG freq(double c)
|
||||
{
|
||||
freq = c;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CNG amp(double c)
|
||||
{
|
||||
amp = c;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CNG patch(double c)
|
||||
{
|
||||
patch = c;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CNG up(double c)
|
||||
{
|
||||
up = c;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CNG down(double c)
|
||||
{
|
||||
down = c;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CNG injectWith(NoiseInjector i)
|
||||
{
|
||||
injector = i;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int fit(int min, int max, double... dim)
|
||||
{
|
||||
if(min == max)
|
||||
{
|
||||
return min;
|
||||
}
|
||||
|
||||
double noise = noise(dim);
|
||||
|
||||
return (int) Math.round(IrisInterpolation.lerp(min, max, noise));
|
||||
}
|
||||
|
||||
public int fitDouble(double min, double max, double... dim)
|
||||
{
|
||||
if(min == max)
|
||||
{
|
||||
return (int) Math.round(min);
|
||||
}
|
||||
|
||||
double noise = noise(dim);
|
||||
|
||||
return (int) Math.round(IrisInterpolation.lerp(min, max, noise));
|
||||
}
|
||||
|
||||
public double fitDoubleD(double min, double max, double... dim)
|
||||
{
|
||||
if(min == max)
|
||||
{
|
||||
return min;
|
||||
}
|
||||
|
||||
double noise = noise(dim);
|
||||
|
||||
return IrisInterpolation.lerp(min, max, noise);
|
||||
}
|
||||
|
||||
public int fitDoubleExponent(double min, double max, double exponent, double... dim)
|
||||
{
|
||||
if(min == max)
|
||||
{
|
||||
return (int) Math.round(min);
|
||||
}
|
||||
|
||||
double noise = noise(dim);
|
||||
|
||||
return (int) Math.round(IrisInterpolation.lerp(min, max, exponent == 1 ? noise : Math.pow(noise, exponent)));
|
||||
}
|
||||
|
||||
public double noise(double... dim)
|
||||
{
|
||||
double f = fracture != null ? (fracture.noise(dim) - 0.5) * fscale : 0D;
|
||||
double x = dim.length > 0 ? dim[0] + f : 0D;
|
||||
double y = dim.length > 1 ? dim[1] - f : 0D;
|
||||
double z = dim.length > 2 ? dim[2] + f : 0D;
|
||||
double n = ((generator.noise(x * scale, y * scale, z * scale, oct, freq, amp, true) / 2D) + 0.5D) * opacity;
|
||||
n = power != 1D ? Math.pow(n, power) : n;
|
||||
double m = 1;
|
||||
hits += oct;
|
||||
if(children == null)
|
||||
{
|
||||
return (n - down + up) * patch;
|
||||
}
|
||||
|
||||
for(CNG i : children)
|
||||
{
|
||||
double[] r = injector.combine(n, i.noise(dim));
|
||||
n = r[0];
|
||||
m += r[1];
|
||||
}
|
||||
|
||||
return ((n / m) - down + up) * patch;
|
||||
}
|
||||
|
||||
public CNG pow(double power)
|
||||
{
|
||||
this.power = power;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
6
src/main/java/com/volmit/iris/util/CallbackCV.java
Normal file
6
src/main/java/com/volmit/iris/util/CallbackCV.java
Normal file
@@ -0,0 +1,6 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
public interface Callback<T>
|
||||
{
|
||||
public void run(T t);
|
||||
}
|
||||
16
src/main/java/com/volmit/iris/util/CaveResult.java
Normal file
16
src/main/java/com/volmit/iris/util/CaveResult.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class CaveResult
|
||||
{
|
||||
private int floor;
|
||||
private int ceiling;
|
||||
|
||||
public CaveResult(int floor, int ceiling)
|
||||
{
|
||||
this.floor = floor;
|
||||
this.ceiling = ceiling;
|
||||
}
|
||||
}
|
||||
59
src/main/java/com/volmit/iris/util/CellGenerator.java
Normal file
59
src/main/java/com/volmit/iris/util/CellGenerator.java
Normal file
@@ -0,0 +1,59 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import ninja.bytecode.iris.util.FastNoise.CellularDistanceFunction;
|
||||
import ninja.bytecode.iris.util.FastNoise.CellularReturnType;
|
||||
import ninja.bytecode.iris.util.FastNoise.NoiseType;
|
||||
|
||||
public class CellGenerator
|
||||
{
|
||||
private FastNoise fn;
|
||||
private FastNoise fd;
|
||||
private CNG cng;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private double cellScale;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private double shuffle;
|
||||
|
||||
public CellGenerator(RNG rng)
|
||||
{
|
||||
shuffle = 128;
|
||||
cellScale = 0.73;
|
||||
cng = CNG.signature(rng.nextParallelRNG(3204));
|
||||
RNG rx = rng.nextParallelRNG(8735652);
|
||||
int s = rx.nextInt();
|
||||
fn = new FastNoise(s);
|
||||
fn.SetNoiseType(NoiseType.Cellular);
|
||||
fn.SetCellularReturnType(CellularReturnType.CellValue);
|
||||
fn.SetCellularDistanceFunction(CellularDistanceFunction.Natural);
|
||||
fd = new FastNoise(s);
|
||||
fd.SetNoiseType(NoiseType.Cellular);
|
||||
fd.SetCellularReturnType(CellularReturnType.Distance2Sub);
|
||||
fd.SetCellularDistanceFunction(CellularDistanceFunction.Natural);
|
||||
}
|
||||
|
||||
public float getDistance(double x, double z)
|
||||
{
|
||||
return ((fd.GetCellular((float) ((x * cellScale) + (cng.noise(x, z) * shuffle)), (float) ((z * cellScale) + (cng.noise(z, x) * shuffle)))) + 1f) / 2f;
|
||||
}
|
||||
|
||||
public float getDistance(double x, double y, double z)
|
||||
{
|
||||
return ((fd.GetCellular((float) ((x * cellScale) + (cng.noise(x, y, z) * shuffle)), (float) ((y * cellScale) + (cng.noise(x, y, z) * shuffle)), (float) ((z * cellScale) + (cng.noise(z, y, x) * shuffle)))) + 1f) / 2f;
|
||||
}
|
||||
|
||||
public float getValue(double x, double z, int possibilities)
|
||||
{
|
||||
return ((fn.GetCellular((float) ((x * cellScale) + (cng.noise(x, z) * shuffle)), (float) ((z * cellScale) + (cng.noise(z, x) * shuffle))) + 1f) / 2f) * (possibilities - 1);
|
||||
}
|
||||
|
||||
public int getIndex(double x, double z, int possibilities)
|
||||
{
|
||||
return (int) Math.round(getValue(x, z, possibilities));
|
||||
}
|
||||
}
|
||||
29
src/main/java/com/volmit/iris/util/ChronoLatch.java
Normal file
29
src/main/java/com/volmit/iris/util/ChronoLatch.java
Normal file
@@ -0,0 +1,29 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
public class ChronoLatch
|
||||
{
|
||||
private long interval;
|
||||
private long since;
|
||||
|
||||
public ChronoLatch(long interval, boolean openedAtStart)
|
||||
{
|
||||
this.interval = interval;
|
||||
since = System.currentTimeMillis() - (openedAtStart ? interval * 2 : 0);
|
||||
}
|
||||
|
||||
public ChronoLatch(long interval)
|
||||
{
|
||||
this(interval, true);
|
||||
}
|
||||
|
||||
public boolean flip()
|
||||
{
|
||||
if(System.currentTimeMillis() - since > interval)
|
||||
{
|
||||
since = System.currentTimeMillis();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
16
src/main/java/com/volmit/iris/util/ChunkPosition.java
Normal file
16
src/main/java/com/volmit/iris/util/ChunkPosition.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ChunkPosition
|
||||
{
|
||||
private int x;
|
||||
private int z;
|
||||
|
||||
public ChunkPosition(int x, int z)
|
||||
{
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
}
|
||||
}
|
||||
83
src/main/java/com/volmit/iris/util/CompoundTag.java
Normal file
83
src/main/java/com/volmit/iris/util/CompoundTag.java
Normal file
@@ -0,0 +1,83 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
/*
|
||||
* JNBT License
|
||||
*
|
||||
* Copyright (c) 2010 Graham Edgecombe
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the JNBT team nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The <code>TAG_Compound</code> tag.
|
||||
*
|
||||
* @author Graham Edgecombe
|
||||
*
|
||||
*/
|
||||
public final class CompoundTag extends Tag {
|
||||
|
||||
/**
|
||||
* The value.
|
||||
*/
|
||||
private final Map<String, Tag> value;
|
||||
|
||||
/**
|
||||
* Creates the tag.
|
||||
*
|
||||
* @param name The name.
|
||||
* @param value The value.
|
||||
*/
|
||||
public CompoundTag(String name, Map<String, Tag> value) {
|
||||
super(name);
|
||||
this.value = Collections.unmodifiableMap(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Tag> getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String name = getName();
|
||||
String append = "";
|
||||
if (name != null && !name.equals("")) {
|
||||
append = "(\"" + this.getName() + "\")";
|
||||
}
|
||||
StringBuilder bldr = new StringBuilder();
|
||||
bldr.append("TAG_Compound" + append + ": " + value.size() + " entries\r\n{\r\n");
|
||||
for (Map.Entry<String, Tag> entry : value.entrySet()) {
|
||||
bldr.append(" " + entry.getValue().toString().replaceAll("\r\n", "\r\n ") + "\r\n");
|
||||
}
|
||||
bldr.append("}");
|
||||
return bldr.toString();
|
||||
}
|
||||
|
||||
}
|
||||
7
src/main/java/com/volmit/iris/util/Consumer2.java
Normal file
7
src/main/java/com/volmit/iris/util/Consumer2.java
Normal file
@@ -0,0 +1,7 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Consumer2<A, B>
|
||||
{
|
||||
public void accept(A a, B b);
|
||||
}
|
||||
7
src/main/java/com/volmit/iris/util/Consumer3.java
Normal file
7
src/main/java/com/volmit/iris/util/Consumer3.java
Normal file
@@ -0,0 +1,7 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Consumer3<A, B, C>
|
||||
{
|
||||
public void accept(A a, B b, C c);
|
||||
}
|
||||
33
src/main/java/com/volmit/iris/util/Contained.java
Normal file
33
src/main/java/com/volmit/iris/util/Contained.java
Normal file
@@ -0,0 +1,33 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
public class Contained<T>
|
||||
{
|
||||
private T t;
|
||||
|
||||
public Contained(T t)
|
||||
{
|
||||
set(t);
|
||||
}
|
||||
|
||||
public Contained()
|
||||
{
|
||||
this(null);
|
||||
}
|
||||
|
||||
public void mod(Function<T, T> x)
|
||||
{
|
||||
set(x.apply(t));
|
||||
}
|
||||
|
||||
public T get()
|
||||
{
|
||||
return t;
|
||||
}
|
||||
|
||||
public void set(T t)
|
||||
{
|
||||
this.t = t;
|
||||
}
|
||||
}
|
||||
884
src/main/java/com/volmit/iris/util/Cuboid.java
Normal file
884
src/main/java/com/volmit/iris/util/Cuboid.java
Normal file
@@ -0,0 +1,884 @@
|
||||
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 ninja.bytecode.shuriken.collections.KList;
|
||||
|
||||
/**
|
||||
* 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 KList<Entity> getEntities()
|
||||
{
|
||||
KList<Entity> en = new KList<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);
|
||||
}
|
||||
}
|
||||
|
||||
public Cuboid expand(Direction dir, int amount)
|
||||
{
|
||||
int ax = dir.toVector().getBlockX() == 1 ? amount : 0;
|
||||
int sx = dir.toVector().getBlockX() == -1 ? -amount : 0;
|
||||
int ay = dir.toVector().getBlockY() == 1 ? amount : 0;
|
||||
int sy = dir.toVector().getBlockY() == -1 ? -amount : 0;
|
||||
int az = dir.toVector().getBlockZ() == 1 ? amount : 0;
|
||||
int sz = dir.toVector().getBlockZ() == -1 ? -amount : 0;
|
||||
return new Cuboid(worldName, x1 + sx, y1 + sy, z1 + sz, x2 + ax, y2 + ay, z2 + az);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
16
src/main/java/com/volmit/iris/util/CuboidException.java
Normal file
16
src/main/java/com/volmit/iris/util/CuboidException.java
Normal 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;
|
||||
}
|
||||
20
src/main/java/com/volmit/iris/util/DOP.java
Normal file
20
src/main/java/com/volmit/iris/util/DOP.java
Normal file
@@ -0,0 +1,20 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
public abstract class DOP
|
||||
{
|
||||
private String type;
|
||||
|
||||
public DOP(String type)
|
||||
{
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public abstract Vector op(Vector v);
|
||||
|
||||
public String getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
}
|
||||
14
src/main/java/com/volmit/iris/util/Desc.java
Normal file
14
src/main/java/com/volmit/iris/util/Desc.java
Normal file
@@ -0,0 +1,14 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
import static java.lang.annotation.RetentionPolicy.*;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RUNTIME)
|
||||
@Target({PARAMETER, TYPE, FIELD})
|
||||
public @interface Desc
|
||||
{
|
||||
String value();
|
||||
}
|
||||
86
src/main/java/com/volmit/iris/util/Dimension.java
Normal file
86
src/main/java/com/volmit/iris/util/Dimension.java
Normal 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;
|
||||
}
|
||||
}
|
||||
24
src/main/java/com/volmit/iris/util/DimensionFace.java
Normal file
24
src/main/java/com/volmit/iris/util/DimensionFace.java
Normal 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
|
||||
}
|
||||
535
src/main/java/com/volmit/iris/util/Direction.java
Normal file
535
src/main/java/com/volmit/iris/util/Direction.java
Normal file
@@ -0,0 +1,535 @@
|
||||
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import org.bukkit.Axis;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import ninja.bytecode.iris.util.Cuboid.CuboidDirection;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
import ninja.bytecode.shuriken.collections.KMap;
|
||||
|
||||
/**
|
||||
* 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 static KMap<GBiset<Direction, Direction>, DOP> permute = null;
|
||||
|
||||
private int x;
|
||||
private int y;
|
||||
private int z;
|
||||
private CuboidDirection f;
|
||||
|
||||
public static Direction getDirection(BlockFace f)
|
||||
{
|
||||
switch(f)
|
||||
{
|
||||
case DOWN:
|
||||
return D;
|
||||
case EAST:
|
||||
return E;
|
||||
case EAST_NORTH_EAST:
|
||||
return E;
|
||||
case EAST_SOUTH_EAST:
|
||||
return E;
|
||||
case NORTH:
|
||||
return N;
|
||||
case NORTH_EAST:
|
||||
return N;
|
||||
case NORTH_NORTH_EAST:
|
||||
return N;
|
||||
case NORTH_NORTH_WEST:
|
||||
return N;
|
||||
case NORTH_WEST:
|
||||
return N;
|
||||
case SELF:
|
||||
return U;
|
||||
case SOUTH:
|
||||
return S;
|
||||
case SOUTH_EAST:
|
||||
return S;
|
||||
case SOUTH_SOUTH_EAST:
|
||||
return S;
|
||||
case SOUTH_SOUTH_WEST:
|
||||
return S;
|
||||
case SOUTH_WEST:
|
||||
return S;
|
||||
case UP:
|
||||
return U;
|
||||
case WEST:
|
||||
return W;
|
||||
case WEST_NORTH_WEST:
|
||||
return W;
|
||||
case WEST_SOUTH_WEST:
|
||||
return W;
|
||||
}
|
||||
|
||||
return D;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
switch(this)
|
||||
{
|
||||
case D:
|
||||
return "Down";
|
||||
case E:
|
||||
return "East";
|
||||
case N:
|
||||
return "North";
|
||||
case S:
|
||||
return "South";
|
||||
case U:
|
||||
return "Up";
|
||||
case W:
|
||||
return "West";
|
||||
}
|
||||
|
||||
return "?";
|
||||
}
|
||||
|
||||
public boolean isVertical()
|
||||
{
|
||||
return equals(D) || equals(U);
|
||||
}
|
||||
|
||||
public static Direction closest(Vector v)
|
||||
{
|
||||
double m = Double.MAX_VALUE;
|
||||
Direction s = null;
|
||||
|
||||
for(Direction i : values())
|
||||
{
|
||||
Vector x = i.toVector();
|
||||
double g = x.dot(v);
|
||||
|
||||
if(g < m)
|
||||
{
|
||||
m = g;
|
||||
s = i;
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
public static Direction closest(Vector v, Direction... d)
|
||||
{
|
||||
double m = Double.MAX_VALUE;
|
||||
Direction s = null;
|
||||
|
||||
for(Direction i : d)
|
||||
{
|
||||
Vector x = i.toVector();
|
||||
double g = x.distance(v);
|
||||
|
||||
if(g < m)
|
||||
{
|
||||
m = g;
|
||||
s = i;
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
public static Direction closest(Vector v, KList<Direction> d)
|
||||
{
|
||||
double m = Double.MAX_VALUE;
|
||||
Direction s = null;
|
||||
|
||||
for(Direction i : d)
|
||||
{
|
||||
Vector x = i.toVector();
|
||||
double g = x.distance(v);
|
||||
|
||||
if(g < m)
|
||||
{
|
||||
m = g;
|
||||
s = i;
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
public Vector toVector()
|
||||
{
|
||||
return new Vector(x, y, z);
|
||||
}
|
||||
|
||||
public boolean isCrooked(Direction to)
|
||||
{
|
||||
if(equals(to.reverse()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(equals(to))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private Direction(int x, int y, int z, CuboidDirection f)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.f = f;
|
||||
}
|
||||
|
||||
public Vector angle(Vector initial, Direction d)
|
||||
{
|
||||
calculatePermutations();
|
||||
|
||||
for(GBiset<Direction, Direction> i : permute.keySet())
|
||||
{
|
||||
if(i.getA().equals(this) && i.getB().equals(d))
|
||||
{
|
||||
return permute.get(i).op(initial);
|
||||
}
|
||||
}
|
||||
|
||||
return initial;
|
||||
}
|
||||
|
||||
public Direction reverse()
|
||||
{
|
||||
switch(this)
|
||||
{
|
||||
case D:
|
||||
return U;
|
||||
case E:
|
||||
return W;
|
||||
case N:
|
||||
return S;
|
||||
case S:
|
||||
return N;
|
||||
case U:
|
||||
return D;
|
||||
case W:
|
||||
return E;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public int x()
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
public int y()
|
||||
{
|
||||
return y;
|
||||
}
|
||||
|
||||
public int z()
|
||||
{
|
||||
return z;
|
||||
}
|
||||
|
||||
public CuboidDirection f()
|
||||
{
|
||||
return f;
|
||||
}
|
||||
|
||||
public static KList<Direction> news()
|
||||
{
|
||||
return new KList<Direction>().add(N, E, W, S);
|
||||
}
|
||||
|
||||
public static Direction getDirection(Vector v)
|
||||
{
|
||||
Vector k = VectorMath.triNormalize(v.clone().normalize());
|
||||
|
||||
for(Direction i : udnews())
|
||||
{
|
||||
if(i.x == k.getBlockX() && i.y == k.getBlockY() && i.z == k.getBlockZ())
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return Direction.N;
|
||||
}
|
||||
|
||||
public static KList<Direction> udnews()
|
||||
{
|
||||
return new KList<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;
|
||||
}
|
||||
|
||||
public static void calculatePermutations()
|
||||
{
|
||||
if(permute != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
permute = new KMap<GBiset<Direction, Direction>, DOP>();
|
||||
|
||||
for(Direction i : udnews())
|
||||
{
|
||||
for(Direction j : udnews())
|
||||
{
|
||||
GBiset<Direction, Direction> b = new GBiset<Direction, Direction>(i, j);
|
||||
|
||||
if(i.equals(j))
|
||||
{
|
||||
permute.put(b, new DOP("DIRECT")
|
||||
{
|
||||
@Override
|
||||
public Vector op(Vector v)
|
||||
{
|
||||
return v;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
else if(i.reverse().equals(j))
|
||||
{
|
||||
if(i.isVertical())
|
||||
{
|
||||
permute.put(b, new DOP("R180CCZ")
|
||||
{
|
||||
@Override
|
||||
public Vector op(Vector v)
|
||||
{
|
||||
return VectorMath.rotate90CCZ(VectorMath.rotate90CCZ(v));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
permute.put(b, new DOP("R180CCY")
|
||||
{
|
||||
@Override
|
||||
public Vector op(Vector v)
|
||||
{
|
||||
return VectorMath.rotate90CCY(VectorMath.rotate90CCY(v));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
else if(getDirection(VectorMath.rotate90CX(i.toVector())).equals(j))
|
||||
{
|
||||
permute.put(b, new DOP("R90CX")
|
||||
{
|
||||
@Override
|
||||
public Vector op(Vector v)
|
||||
{
|
||||
return VectorMath.rotate90CX(v);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
else if(getDirection(VectorMath.rotate90CCX(i.toVector())).equals(j))
|
||||
{
|
||||
permute.put(b, new DOP("R90CCX")
|
||||
{
|
||||
@Override
|
||||
public Vector op(Vector v)
|
||||
{
|
||||
return VectorMath.rotate90CCX(v);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
else if(getDirection(VectorMath.rotate90CY(i.toVector())).equals(j))
|
||||
{
|
||||
permute.put(b, new DOP("R90CY")
|
||||
{
|
||||
@Override
|
||||
public Vector op(Vector v)
|
||||
{
|
||||
return VectorMath.rotate90CY(v);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
else if(getDirection(VectorMath.rotate90CCY(i.toVector())).equals(j))
|
||||
{
|
||||
permute.put(b, new DOP("R90CCY")
|
||||
{
|
||||
@Override
|
||||
public Vector op(Vector v)
|
||||
{
|
||||
return VectorMath.rotate90CCY(v);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
else if(getDirection(VectorMath.rotate90CZ(i.toVector())).equals(j))
|
||||
{
|
||||
permute.put(b, new DOP("R90CZ")
|
||||
{
|
||||
@Override
|
||||
public Vector op(Vector v)
|
||||
{
|
||||
return VectorMath.rotate90CZ(v);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
else if(getDirection(VectorMath.rotate90CCZ(i.toVector())).equals(j))
|
||||
{
|
||||
permute.put(b, new DOP("R90CCZ")
|
||||
{
|
||||
@Override
|
||||
public Vector op(Vector v)
|
||||
{
|
||||
return VectorMath.rotate90CCZ(v);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
permute.put(b, new DOP("FAIL")
|
||||
{
|
||||
@Override
|
||||
public Vector op(Vector v)
|
||||
{
|
||||
return v;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public BlockFace getFace()
|
||||
{
|
||||
switch(this)
|
||||
{
|
||||
case D:
|
||||
return BlockFace.DOWN;
|
||||
case E:
|
||||
return BlockFace.EAST;
|
||||
case N:
|
||||
return BlockFace.NORTH;
|
||||
case S:
|
||||
return BlockFace.SOUTH;
|
||||
case U:
|
||||
return BlockFace.UP;
|
||||
case W:
|
||||
return BlockFace.WEST;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Axis getAxis()
|
||||
{
|
||||
switch(this)
|
||||
{
|
||||
case D:
|
||||
return Axis.Y;
|
||||
case E:
|
||||
return Axis.X;
|
||||
case N:
|
||||
return Axis.Z;
|
||||
case S:
|
||||
return Axis.Z;
|
||||
case U:
|
||||
return Axis.Y;
|
||||
case W:
|
||||
return Axis.X;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
29
src/main/java/com/volmit/iris/util/DoubleArrayUtils.java
Normal file
29
src/main/java/com/volmit/iris/util/DoubleArrayUtils.java
Normal file
@@ -0,0 +1,29 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
|
||||
public class DoubleArrayUtils
|
||||
{
|
||||
public static void shiftRight(double[] values, double push)
|
||||
{
|
||||
for(int index = values.length - 2; index >= 0; index--)
|
||||
{
|
||||
values[index + 1] = values[index];
|
||||
}
|
||||
|
||||
values[0] = push;
|
||||
}
|
||||
|
||||
public static void wrapRight(double[] values)
|
||||
{
|
||||
double last = values[values.length - 1];
|
||||
shiftRight(values, last);
|
||||
}
|
||||
|
||||
public static void fill(double[] values, double value)
|
||||
{
|
||||
for(int i = 0; i < values.length; i++)
|
||||
{
|
||||
values[i] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
74
src/main/java/com/volmit/iris/util/DoubleTag.java
Normal file
74
src/main/java/com/volmit/iris/util/DoubleTag.java
Normal file
@@ -0,0 +1,74 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
/*
|
||||
* JNBT License
|
||||
*
|
||||
* Copyright (c) 2010 Graham Edgecombe
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the JNBT team nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/**
|
||||
* The <code>TAG_Double</code> tag.
|
||||
*
|
||||
* @author Graham Edgecombe
|
||||
*
|
||||
*/
|
||||
public final class DoubleTag extends Tag {
|
||||
|
||||
/**
|
||||
* The value.
|
||||
*/
|
||||
private final double value;
|
||||
|
||||
/**
|
||||
* Creates the tag.
|
||||
*
|
||||
* @param name The name.
|
||||
* @param value The value.
|
||||
*/
|
||||
public DoubleTag(String name, double value) {
|
||||
super(name);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String name = getName();
|
||||
String append = "";
|
||||
if (name != null && !name.equals("")) {
|
||||
append = "(\"" + this.getName() + "\")";
|
||||
}
|
||||
return "TAG_Double" + append + ": " + value;
|
||||
}
|
||||
|
||||
}
|
||||
60
src/main/java/com/volmit/iris/util/EndTag.java
Normal file
60
src/main/java/com/volmit/iris/util/EndTag.java
Normal file
@@ -0,0 +1,60 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
/*
|
||||
* JNBT License
|
||||
*
|
||||
* Copyright (c) 2010 Graham Edgecombe
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the JNBT team nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/**
|
||||
* The <code>TAG_End</code> tag.
|
||||
*
|
||||
* @author Graham Edgecombe
|
||||
*
|
||||
*/
|
||||
public final class EndTag extends Tag {
|
||||
|
||||
/**
|
||||
* Creates the tag.
|
||||
*/
|
||||
public EndTag() {
|
||||
super("");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TAG_End";
|
||||
}
|
||||
|
||||
}
|
||||
2197
src/main/java/com/volmit/iris/util/FastNoise.java
Normal file
2197
src/main/java/com/volmit/iris/util/FastNoise.java
Normal file
File diff suppressed because it is too large
Load Diff
161
src/main/java/com/volmit/iris/util/FastParticle.java
Normal file
161
src/main/java/com/volmit/iris/util/FastParticle.java
Normal file
@@ -0,0 +1,161 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
/**
|
||||
* Simple Bukkit Particles API with 1.7 to 1.13.2 support !
|
||||
* <p>
|
||||
* You can find the project on <a href="https://github.com/MrMicky-FR/FastParticles">GitHub</a>
|
||||
*
|
||||
* @author MrMicky
|
||||
*/
|
||||
public final class FastParticle {
|
||||
|
||||
private static final ParticleSender PARTICLE_SENDER;
|
||||
|
||||
static {
|
||||
if (FastReflection.optionalClass("org.bukkit.Particle$DustOptions").isPresent()) {
|
||||
PARTICLE_SENDER = new ParticleSender.ParticleSender1_13();
|
||||
} else if (FastReflection.optionalClass("org.bukkit.Particle").isPresent()) {
|
||||
PARTICLE_SENDER = new ParticleSender.ParticleSenderImpl();
|
||||
} else {
|
||||
PARTICLE_SENDER = new ParticleSenderLegacy();
|
||||
}
|
||||
}
|
||||
|
||||
private FastParticle() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/*
|
||||
* Worlds methods
|
||||
*/
|
||||
public static void spawnParticle(World world, ParticleType particle, Location location, int count) {
|
||||
spawnParticle(world, particle, location.getX(), location.getY(), location.getZ(), count);
|
||||
}
|
||||
|
||||
public static void spawnParticle(World world, ParticleType particle, double x, double y, double z, int count) {
|
||||
spawnParticle(world, particle, x, y, z, count, null);
|
||||
}
|
||||
|
||||
public static <T> void spawnParticle(World world, ParticleType particle, Location location, int count, T data) {
|
||||
spawnParticle(world, particle, location.getX(), location.getY(), location.getZ(), count, data);
|
||||
}
|
||||
|
||||
public static <T> void spawnParticle(World world, ParticleType particle, double x, double y, double z, int count,
|
||||
T data) {
|
||||
spawnParticle(world, particle, x, y, z, count, 0.0D, 0.0D, 0.0D, data);
|
||||
}
|
||||
|
||||
public static void spawnParticle(World world, ParticleType particle, Location location, int count, double offsetX,
|
||||
double offsetY, double offsetZ) {
|
||||
spawnParticle(world, particle, location.getX(), location.getY(), location.getZ(), count, offsetX, offsetY, offsetZ);
|
||||
}
|
||||
|
||||
public static void spawnParticle(World world, ParticleType particle, double x, double y, double z, int count,
|
||||
double offsetX, double offsetY, double offsetZ) {
|
||||
spawnParticle(world, particle, x, y, z, count, offsetX, offsetY, offsetZ, null);
|
||||
}
|
||||
|
||||
public static <T> void spawnParticle(World world, ParticleType particle, Location location, int count,
|
||||
double offsetX, double offsetY, double offsetZ, T data) {
|
||||
spawnParticle(world, particle, location.getX(), location.getY(), location.getZ(), count, offsetX, offsetY,
|
||||
offsetZ, data);
|
||||
}
|
||||
|
||||
public static <T> void spawnParticle(World world, ParticleType particle, double x, double y, double z, int count,
|
||||
double offsetX, double offsetY, double offsetZ, T data) {
|
||||
spawnParticle(world, particle, x, y, z, count, offsetX, offsetY, offsetZ, 1.0D, data);
|
||||
}
|
||||
|
||||
public static void spawnParticle(World world, ParticleType particle, Location location, int count, double offsetX,
|
||||
double offsetY, double offsetZ, double extra) {
|
||||
spawnParticle(world, particle, location.getX(), location.getY(), location.getZ(), count, offsetX, offsetY, offsetZ, extra);
|
||||
}
|
||||
|
||||
public static void spawnParticle(World world, ParticleType particle, double x, double y, double z, int count,
|
||||
double offsetX, double offsetY, double offsetZ, double extra) {
|
||||
spawnParticle(world, particle, x, y, z, count, offsetX, offsetY, offsetZ, extra, null);
|
||||
}
|
||||
|
||||
public static <T> void spawnParticle(World world, ParticleType particle, Location location, int count,
|
||||
double offsetX, double offsetY, double offsetZ, double extra, T data) {
|
||||
spawnParticle(world, particle, location.getX(), location.getY(), location.getZ(), count, offsetX, offsetY, offsetZ, extra, data);
|
||||
}
|
||||
|
||||
public static <T> void spawnParticle(World world, ParticleType particle, double x, double y, double z, int count,
|
||||
double offsetX, double offsetY, double offsetZ, double extra, T data) {
|
||||
sendParticle(world, particle, x, y, z, count, offsetX, offsetY, offsetZ, extra, data);
|
||||
}
|
||||
|
||||
/*
|
||||
* Player methods
|
||||
*/
|
||||
public static void spawnParticle(Player player, ParticleType particle, Location location, int count) {
|
||||
spawnParticle(player, particle, location.getX(), location.getY(), location.getZ(), count);
|
||||
}
|
||||
|
||||
public static void spawnParticle(Player player, ParticleType particle, double x, double y, double z, int count) {
|
||||
spawnParticle(player, particle, x, y, z, count, null);
|
||||
}
|
||||
|
||||
public static <T> void spawnParticle(Player player, ParticleType particle, Location location, int count, T data) {
|
||||
spawnParticle(player, particle, location.getX(), location.getY(), location.getZ(), count, data);
|
||||
}
|
||||
|
||||
public static <T> void spawnParticle(Player player, ParticleType particle, double x, double y, double z, int count,
|
||||
T data) {
|
||||
spawnParticle(player, particle, x, y, z, count, 0.0D, 0.0D, 0.0D, data);
|
||||
}
|
||||
|
||||
public static void spawnParticle(Player player, ParticleType particle, Location location, int count, double offsetX,
|
||||
double offsetY, double offsetZ) {
|
||||
spawnParticle(player, particle, location.getX(), location.getY(), location.getZ(), count, offsetX, offsetY, offsetZ);
|
||||
}
|
||||
|
||||
public static void spawnParticle(Player player, ParticleType particle, double x, double y, double z, int count,
|
||||
double offsetX, double offsetY, double offsetZ) {
|
||||
spawnParticle(player, particle, x, y, z, count, offsetX, offsetY, offsetZ, null);
|
||||
}
|
||||
|
||||
public static <T> void spawnParticle(Player player, ParticleType particle, Location location, int count,
|
||||
double offsetX, double offsetY, double offsetZ, T data) {
|
||||
spawnParticle(player, particle, location.getX(), location.getY(), location.getZ(), count, offsetX, offsetY, offsetZ, data);
|
||||
}
|
||||
|
||||
public static <T> void spawnParticle(Player player, ParticleType particle, double x, double y, double z, int count,
|
||||
double offsetX, double offsetY, double offsetZ, T data) {
|
||||
spawnParticle(player, particle, x, y, z, count, offsetX, offsetY, offsetZ, 1.0D, data);
|
||||
}
|
||||
|
||||
public static void spawnParticle(Player player, ParticleType particle, Location location, int count, double offsetX,
|
||||
double offsetY, double offsetZ, double extra) {
|
||||
spawnParticle(player, particle, location.getX(), location.getY(), location.getZ(), count, offsetX, offsetY, offsetZ, extra);
|
||||
}
|
||||
|
||||
public static void spawnParticle(Player player, ParticleType particle, double x, double y, double z, int count,
|
||||
double offsetX, double offsetY, double offsetZ, double extra) {
|
||||
spawnParticle(player, particle, x, y, z, count, offsetX, offsetY, offsetZ, extra, null);
|
||||
}
|
||||
|
||||
public static <T> void spawnParticle(Player player, ParticleType particle, Location location, int count,
|
||||
double offsetX, double offsetY, double offsetZ, double extra, T data) {
|
||||
spawnParticle(player, particle, location.getX(), location.getY(), location.getZ(), count, offsetX, offsetY, offsetZ, extra, data);
|
||||
}
|
||||
|
||||
public static <T> void spawnParticle(Player player, ParticleType particle, double x, double y, double z, int count,
|
||||
double offsetX, double offsetY, double offsetZ, double extra, T data) {
|
||||
sendParticle(player, particle, x, y, z, count, offsetX, offsetY, offsetZ, extra, data);
|
||||
}
|
||||
|
||||
private static void sendParticle(Object receiver, ParticleType particle, double x, double y, double z, int count,
|
||||
double offsetX, double offsetY, double offsetZ, double extra, Object data) {
|
||||
if (!particle.isSupported()) {
|
||||
throw new IllegalArgumentException("The particle '" + particle + "' is not compatible with your server version");
|
||||
}
|
||||
|
||||
PARTICLE_SENDER.spawnParticle(receiver, particle, x, y, z, count, offsetX, offsetY, offsetZ, extra, data);
|
||||
}
|
||||
}
|
||||
59
src/main/java/com/volmit/iris/util/FastReflection.java
Normal file
59
src/main/java/com/volmit/iris/util/FastReflection.java
Normal file
@@ -0,0 +1,59 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Small reflection class to use CraftBukkit and NMS
|
||||
*
|
||||
* @author MrMicky
|
||||
*/
|
||||
public final class FastReflection {
|
||||
|
||||
public static final String OBC_PACKAGE = "org.bukkit.craftbukkit";
|
||||
public static final String NMS_PACKAGE = "net.minecraft.server";
|
||||
|
||||
public static final String VERSION = Bukkit.getServer().getClass().getPackage().getName().substring(OBC_PACKAGE.length() + 1);
|
||||
|
||||
private FastReflection() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public static String nmsClassName(String className) {
|
||||
return NMS_PACKAGE + '.' + VERSION + '.' + className;
|
||||
}
|
||||
|
||||
public static Class<?> nmsClass(String className) throws ClassNotFoundException {
|
||||
return Class.forName(nmsClassName(className));
|
||||
}
|
||||
|
||||
public static Optional<Class<?>> nmsOptionalClass(String className) {
|
||||
return optionalClass(nmsClassName(className));
|
||||
}
|
||||
|
||||
public static String obcClassName(String className) {
|
||||
return OBC_PACKAGE + '.' + VERSION + '.' + className;
|
||||
}
|
||||
|
||||
public static Class<?> obcClass(String className) throws ClassNotFoundException {
|
||||
return Class.forName(obcClassName(className));
|
||||
}
|
||||
|
||||
public static Optional<Class<?>> obcOptionalClass(String className) {
|
||||
return optionalClass(obcClassName(className));
|
||||
}
|
||||
|
||||
public static Optional<Class<?>> optionalClass(String className) {
|
||||
try {
|
||||
return Optional.of(Class.forName(className));
|
||||
} catch (ClassNotFoundException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public static Object enumValueOf(Class<?> enumClass, String enumName) {
|
||||
return Enum.valueOf((Class<Enum>) enumClass, enumName.toUpperCase());
|
||||
}
|
||||
}
|
||||
44
src/main/java/com/volmit/iris/util/FileWatcher.java
Normal file
44
src/main/java/com/volmit/iris/util/FileWatcher.java
Normal file
@@ -0,0 +1,44 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
|
||||
@Data
|
||||
public class FileWatcher
|
||||
{
|
||||
@Getter
|
||||
private final File file;
|
||||
private boolean exists;
|
||||
private long lastModified;
|
||||
private long size;
|
||||
|
||||
public FileWatcher(File file)
|
||||
{
|
||||
this.file = file;
|
||||
readProperties();
|
||||
}
|
||||
|
||||
private void readProperties()
|
||||
{
|
||||
exists = file.exists();
|
||||
lastModified = exists ? file.lastModified() : -1;
|
||||
size = exists ? file.length() : -1;
|
||||
}
|
||||
|
||||
public boolean checkModified()
|
||||
{
|
||||
long m = lastModified;
|
||||
long g = size;
|
||||
boolean mod = false;
|
||||
readProperties();
|
||||
|
||||
if(lastModified != m || g != size)
|
||||
{
|
||||
mod = true;
|
||||
}
|
||||
|
||||
return mod;
|
||||
}
|
||||
}
|
||||
74
src/main/java/com/volmit/iris/util/FloatTag.java
Normal file
74
src/main/java/com/volmit/iris/util/FloatTag.java
Normal file
@@ -0,0 +1,74 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
/*
|
||||
* JNBT License
|
||||
*
|
||||
* Copyright (c) 2010 Graham Edgecombe
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the JNBT team nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/**
|
||||
* The <code>TAG_Float</code> tag.
|
||||
*
|
||||
* @author Graham Edgecombe
|
||||
*
|
||||
*/
|
||||
public final class FloatTag extends Tag {
|
||||
|
||||
/**
|
||||
* The value.
|
||||
*/
|
||||
private final float value;
|
||||
|
||||
/**
|
||||
* Creates the tag.
|
||||
*
|
||||
* @param name The name.
|
||||
* @param value The value.
|
||||
*/
|
||||
public FloatTag(String name, float value) {
|
||||
super(name);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String name = getName();
|
||||
String append = "";
|
||||
if (name != null && !name.equals("")) {
|
||||
append = "(\"" + this.getName() + "\")";
|
||||
}
|
||||
return "TAG_Float" + append + ": " + value;
|
||||
}
|
||||
|
||||
}
|
||||
77
src/main/java/com/volmit/iris/util/GBiset.java
Normal file
77
src/main/java/com/volmit/iris/util/GBiset.java
Normal file
@@ -0,0 +1,77 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* A Biset
|
||||
*
|
||||
* @author cyberpwn
|
||||
*
|
||||
* @param <A>
|
||||
* the first object type
|
||||
* @param <B>
|
||||
* the second object type
|
||||
*/
|
||||
@SuppressWarnings("hiding")
|
||||
public class GBiset<A, B> implements Serializable
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
private A a;
|
||||
private B b;
|
||||
|
||||
/**
|
||||
* Create a new Biset
|
||||
*
|
||||
* @param a
|
||||
* the first object
|
||||
* @param b
|
||||
* the second object
|
||||
*/
|
||||
public GBiset(A a, B b)
|
||||
{
|
||||
this.a = a;
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the object of the type A
|
||||
*
|
||||
* @return the first object
|
||||
*/
|
||||
public A getA()
|
||||
{
|
||||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the first object
|
||||
*
|
||||
* @param a
|
||||
* the first object A
|
||||
*/
|
||||
public void setA(A a)
|
||||
{
|
||||
this.a = a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the second object
|
||||
*
|
||||
* @return the second object
|
||||
*/
|
||||
public B getB()
|
||||
{
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the second object
|
||||
*
|
||||
* @param b
|
||||
*/
|
||||
public void setB(B b)
|
||||
{
|
||||
this.b = b;
|
||||
}
|
||||
}
|
||||
51
src/main/java/com/volmit/iris/util/GListAdapter.java
Normal file
51
src/main/java/com/volmit/iris/util/GListAdapter.java
Normal file
@@ -0,0 +1,51 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
|
||||
/**
|
||||
* 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 KList<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);
|
||||
}
|
||||
17
src/main/java/com/volmit/iris/util/GenLayer.java
Normal file
17
src/main/java/com/volmit/iris/util/GenLayer.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import ninja.bytecode.iris.generator.DimensionChunkGenerator;
|
||||
|
||||
public abstract class GenLayer
|
||||
{
|
||||
protected final RNG rng;
|
||||
protected final DimensionChunkGenerator iris;
|
||||
|
||||
public GenLayer(DimensionChunkGenerator iris, RNG rng)
|
||||
{
|
||||
this.iris = iris;
|
||||
this.rng = rng;
|
||||
}
|
||||
|
||||
public abstract double generate(double x, double z);
|
||||
}
|
||||
132
src/main/java/com/volmit/iris/util/GroupedExecutor.java
Normal file
132
src/main/java/com/volmit/iris/util/GroupedExecutor.java
Normal file
@@ -0,0 +1,132 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory;
|
||||
import java.util.concurrent.ForkJoinWorkerThread;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import ninja.bytecode.shuriken.collections.KMap;
|
||||
import ninja.bytecode.shuriken.execution.J;
|
||||
import ninja.bytecode.shuriken.execution.NastyRunnable;
|
||||
|
||||
public class GroupedExecutor
|
||||
{
|
||||
private int xc;
|
||||
private ExecutorService service;
|
||||
private ReentrantLock lock;
|
||||
private KMap<String, Integer> mirror;
|
||||
|
||||
public GroupedExecutor(int threadLimit, int priority, String name)
|
||||
{
|
||||
xc = 1;
|
||||
lock = new ReentrantLock();
|
||||
mirror = new KMap<String, Integer>();
|
||||
|
||||
if(threadLimit == 1)
|
||||
{
|
||||
service = Executors.newSingleThreadExecutor((r) ->
|
||||
{
|
||||
Thread t = new Thread(r);
|
||||
t.setName(name);
|
||||
t.setPriority(priority);
|
||||
|
||||
return t;
|
||||
});
|
||||
}
|
||||
|
||||
else if(threadLimit > 1)
|
||||
{
|
||||
final ForkJoinWorkerThreadFactory factory = new ForkJoinWorkerThreadFactory()
|
||||
{
|
||||
@Override
|
||||
public ForkJoinWorkerThread newThread(ForkJoinPool pool)
|
||||
{
|
||||
final ForkJoinWorkerThread worker = ForkJoinPool.defaultForkJoinWorkerThreadFactory.newThread(pool);
|
||||
worker.setName(name + " " + xc++);
|
||||
worker.setPriority(priority);
|
||||
return worker;
|
||||
}
|
||||
};
|
||||
|
||||
service = new ForkJoinPool(threadLimit, factory, null, false);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
service = Executors.newCachedThreadPool((r) ->
|
||||
{
|
||||
Thread t = new Thread(r);
|
||||
t.setName(name + " " + xc++);
|
||||
t.setPriority(priority);
|
||||
|
||||
return t;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void waitFor(String g)
|
||||
{
|
||||
if(g == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(!mirror.containsKey(g))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while(true)
|
||||
{
|
||||
J.sleep(1);
|
||||
|
||||
if(mirror.get(g) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void queue(String q, NastyRunnable r)
|
||||
{
|
||||
lock.lock();
|
||||
if(!mirror.containsKey(q))
|
||||
{
|
||||
mirror.put(q, 0);
|
||||
}
|
||||
mirror.put(q, mirror.get(q) + 1);
|
||||
lock.unlock();
|
||||
service.execute(() ->
|
||||
{
|
||||
try
|
||||
{
|
||||
r.run();
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
lock.lock();
|
||||
mirror.put(q, mirror.get(q) - 1);
|
||||
lock.unlock();
|
||||
});
|
||||
}
|
||||
|
||||
public void close()
|
||||
{
|
||||
J.a(() ->
|
||||
{
|
||||
J.sleep(10000);
|
||||
service.shutdown();
|
||||
});
|
||||
}
|
||||
|
||||
public void closeNow()
|
||||
{
|
||||
service.shutdown();
|
||||
}
|
||||
}
|
||||
24
src/main/java/com/volmit/iris/util/HeightMap.java
Normal file
24
src/main/java/com/volmit/iris/util/HeightMap.java
Normal file
@@ -0,0 +1,24 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class HeightMap
|
||||
{
|
||||
private final byte[] height;
|
||||
|
||||
public HeightMap()
|
||||
{
|
||||
height = new byte[256];
|
||||
Arrays.fill(height, Byte.MIN_VALUE);
|
||||
}
|
||||
|
||||
public void setHeight(int x, int z, int h)
|
||||
{
|
||||
height[x * 16 + z] = (byte) (h + Byte.MIN_VALUE);
|
||||
}
|
||||
|
||||
public int getHeight(int x, int z)
|
||||
{
|
||||
return height[x * 16 + z] - Byte.MIN_VALUE;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user