diff --git a/src/main/java/ninja/bytecode/iris/Iris.java b/src/main/java/ninja/bytecode/iris/Iris.java index 4a2f04f58..3d43d3fe3 100644 --- a/src/main/java/ninja/bytecode/iris/Iris.java +++ b/src/main/java/ninja/bytecode/iris/Iris.java @@ -19,6 +19,7 @@ import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.util.Vector; import ninja.bytecode.iris.generator.IrisGenerator; +import ninja.bytecode.iris.generator.biome.IrisBiome; import ninja.bytecode.shuriken.bench.Profiler; import ninja.bytecode.shuriken.collections.GMap; import ninja.bytecode.shuriken.collections.GSet; @@ -61,6 +62,20 @@ public class Iris extends JavaPlugin implements Listener { Bukkit.unloadWorld(i, false); } + + Bukkit.getScheduler().scheduleSyncRepeatingTask(this, () -> { + for(World i : Bukkit.getWorlds()) + { + if(i.getGenerator() instanceof IrisGenerator) + { + for(Player j : i.getPlayers()) + { + IrisBiome biome = IrisBiome.findByBiome(j.getLocation().getBlock().getBiome()); + biome.applyEffects(j); + } + } + } + }, 0, 15); } private int getTC() diff --git a/src/main/java/ninja/bytecode/iris/Settings.java b/src/main/java/ninja/bytecode/iris/Settings.java index 6afcb56ef..e054f4450 100644 --- a/src/main/java/ninja/bytecode/iris/Settings.java +++ b/src/main/java/ninja/bytecode/iris/Settings.java @@ -9,20 +9,20 @@ public class Settings public static class PerformanceSettings { - public PerformanceMode performanceMode = PerformanceMode.MATCH_CPU; + public PerformanceMode performanceMode = PerformanceMode.HALF_CPU; public int threadCount = 12; - public int threadPriority = Thread.MAX_PRIORITY; + public int threadPriority = Thread.MIN_PRIORITY; } public static class GeneratorSettings { - public double horizontalZoom = 0.525; // 2.225 - 1.625 (big) + public double horizontalZoom = 0.525; // 0.525 public double heightFracture = 155; public double heightMultiplier = 0.806; public double heightExponentBase = 1; public double heightExponentMultiplier = 1.41; public double heightScale = 1; - public double superHeightScale = 0.65; + public double superHeightScale = 0.95; public double baseHeight = 0.165; public int seaLevel = 63; public double biomeScale = 2.46; diff --git a/src/main/java/ninja/bytecode/iris/WandManager.java b/src/main/java/ninja/bytecode/iris/WandManager.java index 903707f6d..ee40b91e1 100644 --- a/src/main/java/ninja/bytecode/iris/WandManager.java +++ b/src/main/java/ninja/bytecode/iris/WandManager.java @@ -1,18 +1,27 @@ package ninja.bytecode.iris; +import java.awt.Color; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.block.Action; import org.bukkit.event.player.PlayerCommandPreprocessEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.util.Vector; import ninja.bytecode.iris.schematic.Schematic; +import ninja.bytecode.iris.util.Cuboid; +import ninja.bytecode.iris.util.Cuboid.CuboidDirection; +import ninja.bytecode.iris.util.ParticleEffect; +import ninja.bytecode.iris.util.ParticleRedstone; import ninja.bytecode.iris.util.WandUtil; public class WandManager implements Listener @@ -20,6 +29,96 @@ public class WandManager implements Listener public WandManager() { Bukkit.getPluginManager().registerEvents(this, Iris.instance); + Bukkit.getScheduler().scheduleSyncRepeatingTask(Iris.instance, () -> + { + for(Player i : Bukkit.getOnlinePlayers()) + { + tick(i); + } + }, 0, 4); + } + + @EventHandler + public void tick(Player p) + { + if(WandUtil.isWand(p.getInventory().getItemInMainHand())) + { + Location[] d = WandUtil.getCuboid(p.getInventory().getItemInMainHand()); + ParticleEffect.CRIT_MAGIC.display(0.1f, 1, d[0].clone().add(0.5, 0.5, 0.5).clone().add(Vector.getRandom().subtract(Vector.getRandom()).normalize().clone().multiply(0.65)), p); + ParticleEffect.CRIT.display(0.1f, 1, d[1].clone().add(0.5, 0.5, 0.5).clone().add(Vector.getRandom().subtract(Vector.getRandom()).normalize().clone().multiply(0.65)), p); + + if(!d[0].getWorld().equals(d[1].getWorld())) + { + return; + } + + if(d[0].distanceSquared(d[1]) > 64 * 64) + { + return; + } + + int minx = Math.min(d[0].getBlockX(), d[1].getBlockX()); + int miny = Math.min(d[0].getBlockY(), d[1].getBlockY()); + int minz = Math.min(d[0].getBlockZ(), d[1].getBlockZ()); + int maxx = Math.max(d[0].getBlockX(), d[1].getBlockX()); + int maxy = Math.max(d[0].getBlockY(), d[1].getBlockY()); + int maxz = Math.max(d[0].getBlockZ(), d[1].getBlockZ()); + + for(double j = minx - 1; j < maxx + 1; j += 0.25) + { + for(double k = miny - 1; k < maxy + 1; k += 0.25) + { + for(double l = minz - 1; l < maxz + 1; l += 0.25) + { + boolean jj = j == minx || j == maxx; + boolean kk = k == miny || k == maxy; + boolean ll = l == minz || l == maxz; + double aa = j; + double bb = k; + double cc = l; + + if((jj && kk) || (jj && ll) || (ll && kk)) + { + Vector push = new Vector(0, 0, 0); + + if(j == minx) + { + push.add(new Vector(-0.55, 0, 0)); + } + + if(k == miny) + { + push.add(new Vector(0, -0.55, 0)); + } + + if(l == minz) + { + push.add(new Vector(0, 0, -0.55)); + } + + if(j == maxx) + { + push.add(new Vector(0.55, 0, 0)); + } + + if(k == maxy) + { + push.add(new Vector(0, 0.55, 0)); + } + + if(l == maxz) + { + push.add(new Vector(0, 0, 0.55)); + } + + Location lv = new Location(d[0].getWorld(), aa, bb, cc).clone().add(0.5, 0.5, 0.5).clone().add(push); + int color = Color.getHSBColor((float) (0.5f + (Math.sin((aa + bb + cc + (p.getTicksLived() / 2)) / 20f) / 2)), 1, 1).getRGB(); + new ParticleRedstone().setColor(new Color(color)).play(lv, p); + } + } + } + } + } } @EventHandler @@ -37,13 +136,13 @@ public class WandManager implements Listener s.write(fos); e.getPlayer().sendMessage("Done!"); } - + catch(Throwable e1) { e1.printStackTrace(); } } - + if(e.getMessage().startsWith("/iload ")) { e.setCancelled(true); @@ -54,7 +153,7 @@ public class WandManager implements Listener e.getPlayer().sendMessage("Not Found"); return; } - + try { FileInputStream fin = new FileInputStream(f); @@ -62,13 +161,45 @@ public class WandManager implements Listener WandUtil.pasteSchematic(s, e.getPlayer().getLocation()); e.getPlayer().sendMessage("Done!"); } - + catch(Throwable e1) { e1.printStackTrace(); } } + if(e.getMessage().startsWith("/iup")) + { + e.setCancelled(true); + Location[] b = WandUtil.getCuboid(e.getPlayer().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(); + e.getPlayer().getInventory().setItemInMainHand(WandUtil.createWand(b[0], b[1])); + e.getPlayer().updateInventory(); + } + if(e.getMessage().equals("/iris wand")) { e.setCancelled(true); @@ -84,7 +215,7 @@ public class WandManager implements Listener if(e.getAction().equals(Action.LEFT_CLICK_BLOCK)) { e.setCancelled(true); - e.getPlayer().getInventory().setItemInMainHand(WandUtil.update(true, e.getPlayer().getLocation(), e.getPlayer().getInventory().getItemInMainHand())); + e.getPlayer().getInventory().setItemInMainHand(WandUtil.update(true, e.getClickedBlock().getLocation(), e.getPlayer().getInventory().getItemInMainHand())); e.getPlayer().updateInventory(); } @@ -92,7 +223,7 @@ public class WandManager implements Listener else if(e.getAction().equals(Action.RIGHT_CLICK_BLOCK)) { e.setCancelled(true); - e.getPlayer().getInventory().setItemInMainHand(WandUtil.update(false, e.getPlayer().getLocation(), e.getPlayer().getInventory().getItemInMainHand())); + e.getPlayer().getInventory().setItemInMainHand(WandUtil.update(false, e.getClickedBlock().getLocation(), e.getPlayer().getInventory().getItemInMainHand())); e.getPlayer().updateInventory(); } diff --git a/src/main/java/ninja/bytecode/iris/generator/IrisGenerator.java b/src/main/java/ninja/bytecode/iris/generator/IrisGenerator.java index bea636895..b5b723964 100644 --- a/src/main/java/ninja/bytecode/iris/generator/IrisGenerator.java +++ b/src/main/java/ninja/bytecode/iris/generator/IrisGenerator.java @@ -15,6 +15,12 @@ import ninja.bytecode.iris.generator.layer.GenLayerBase; import ninja.bytecode.iris.generator.layer.GenLayerBiome; import ninja.bytecode.iris.generator.layer.GenLayerCaves; import ninja.bytecode.iris.generator.layer.GenLayerLayeredNoise; +import ninja.bytecode.iris.generator.layer.GenLayerOreCoal; +import ninja.bytecode.iris.generator.layer.GenLayerOreDiamond; +import ninja.bytecode.iris.generator.layer.GenLayerOreEmerald; +import ninja.bytecode.iris.generator.layer.GenLayerOreGold; +import ninja.bytecode.iris.generator.layer.GenLayerOreIron; +import ninja.bytecode.iris.generator.layer.GenLayerOreLapis; import ninja.bytecode.iris.generator.layer.GenLayerRidge; import ninja.bytecode.iris.generator.populator.BiomeBiasSchematicPopulator; import ninja.bytecode.iris.schematic.Schematic; @@ -31,6 +37,24 @@ import ninja.bytecode.shuriken.math.RNG; public class IrisGenerator extends ParallelChunkGenerator { + //@builder + public static final GList ROCK = new GList().add(new MB[] { + MB.of(Material.STONE), + MB.of(Material.STONE), + MB.of(Material.STONE), + MB.of(Material.STONE), + MB.of(Material.STONE), + MB.of(Material.STONE), + MB.of(Material.STONE, 5), + MB.of(Material.STONE, 5), + MB.of(Material.COBBLESTONE), + MB.of(Material.COBBLESTONE), + MB.of(Material.SMOOTH_BRICK), + MB.of(Material.SMOOTH_BRICK, 1), + MB.of(Material.SMOOTH_BRICK, 2), + MB.of(Material.SMOOTH_BRICK, 3), + }); + //@done private MB WATER = new MB(Material.STATIONARY_WATER); private MB BEDROCK = new MB(Material.BEDROCK); private GenLayerBase glBase; @@ -38,6 +62,12 @@ public class IrisGenerator extends ParallelChunkGenerator private GenLayerRidge glRidge; private GenLayerBiome glBiome; private GenLayerCaves glCaves; + private GenLayerOreIron glOreIron; + private GenLayerOreCoal glOreCoal; + private GenLayerOreLapis glOreLapis; + private GenLayerOreGold glOreGold; + private GenLayerOreEmerald glOreEmerald; + private GenLayerOreDiamond glOreDiamond; private RNG rTerrain; private World world; @@ -51,6 +81,12 @@ public class IrisGenerator extends ParallelChunkGenerator glRidge = new GenLayerRidge(this, world, random, rTerrain.nextParallelRNG(3)); glBiome = new GenLayerBiome(this, world, random, rTerrain.nextParallelRNG(4)); glCaves = new GenLayerCaves(this, world, random, rTerrain.nextParallelRNG(-1)); + glOreIron = new GenLayerOreIron(this, world, random, rTerrain.nextParallelRNG(-500), 10); + glOreLapis = new GenLayerOreLapis(this, world, random, rTerrain.nextParallelRNG(-501), 15); + glOreCoal = new GenLayerOreCoal(this, world, random, rTerrain.nextParallelRNG(-502), 20); + glOreGold = new GenLayerOreGold(this, world, random, rTerrain.nextParallelRNG(-503), 25); + glOreEmerald = new GenLayerOreEmerald(this, world, random, rTerrain.nextParallelRNG(-504), 30); + glOreDiamond = new GenLayerOreDiamond(this, world, random, rTerrain.nextParallelRNG(-505), 35); } @Override @@ -75,7 +111,7 @@ public class IrisGenerator extends ParallelChunkGenerator for(int i = 0; i < max; i++) { - MB mb = new MB(Material.STONE); + MB mb = ROCK.get(glBase.scatterInt(wzx, i, wxx, ROCK.size())); boolean underwater = i >= height && i < seaLevel; boolean underground = i < height; @@ -120,6 +156,12 @@ public class IrisGenerator extends ParallelChunkGenerator } mb = biome.getSurface(wx, wz, rTerrain); + MB mbx = biome.getScatterChanceSingle(); + + if(!mbx.material.equals(Material.AIR)) + { + setBlock(x, i + 1, z, mbx.material, mbx.data); + } } if(i == 0) @@ -136,6 +178,12 @@ public class IrisGenerator extends ParallelChunkGenerator } glCaves.genCaves(wxx, wzx, x, z, height, this); + glOreIron.genOre(wxx, wzx, x, z, height, this, biome); + glOreLapis.genOre(wxx, wzx, x, z, height, this, biome); + glOreCoal.genOre(wxx, wzx, x, z, height, this, biome); + glOreGold.genOre(wxx, wzx, x, z, height, this, biome); + glOreEmerald.genOre(wxx, wzx, x, z, height, this, biome); + glOreDiamond.genOre(wxx, wzx, x, z, height, this, biome); if(override != null) { @@ -162,7 +210,7 @@ public class IrisGenerator extends ParallelChunkGenerator { GList p = new GList<>(); int b = 0; - for(IrisBiome i : IrisBiome.getBiomes()) + for(IrisBiome i : IrisBiome.getAllBiomes()) { b++; L.i("Processing Populators for Biome " + i.getName()); @@ -172,9 +220,7 @@ public class IrisGenerator extends ParallelChunkGenerator p.add(new BiomeBiasSchematicPopulator(i.getSchematicGroups().get(j), i, loadSchematics(j))); } } - - J.attempt(() -> p.add(new BiomeBiasSchematicPopulator(5, IrisBiome.JUNGLE, loadSchematics("")))); - + L.i("Initialized " + b + " Biomes and " + p.size() + " Populators"); L.flush(); @@ -186,25 +232,18 @@ public class IrisGenerator extends ParallelChunkGenerator File f = new File(Iris.instance.getDataFolder(), "objects/" + folder); GList s = new GList<>(); - try + if(f.exists() && f.isDirectory()) { - if(f.exists() && f.isDirectory()) + for(File i : f.listFiles()) { - for(File i : f.listFiles()) + if(i.isFile() && i.getName().endsWith(".ish")) { - if(i.isFile() && i.getName().endsWith(".ish")) - { - s.add(Schematic.load(i)); - } + J.attempt(()-> s.add(Schematic.load(i))); } } } - catch(Throwable e) - { - - } - + L.i("Loaded " + s.size() + " Schematics in " + folder); return s.toArray(new Schematic[s.size()]); } diff --git a/src/main/java/ninja/bytecode/iris/generator/biome/IrisBiome.java b/src/main/java/ninja/bytecode/iris/generator/biome/IrisBiome.java index 28b324c4f..3bc5c9d03 100644 --- a/src/main/java/ninja/bytecode/iris/generator/biome/IrisBiome.java +++ b/src/main/java/ninja/bytecode/iris/generator/biome/IrisBiome.java @@ -3,8 +3,10 @@ package ninja.bytecode.iris.generator.biome; import java.lang.reflect.Field; import org.bukkit.Material; -import org.bukkit.TreeType; import org.bukkit.block.Biome; +import org.bukkit.entity.Player; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; import ninja.bytecode.iris.util.MB; import ninja.bytecode.iris.util.PolygonGenerator; @@ -21,7 +23,9 @@ public class IrisBiome public static final IrisBiome RIVER = new IrisBiome("River", Biome.RIVER) .surface(MB.of(Material.SAND)); public static final IrisBiome BEACH = new IrisBiome("Beach", Biome.BEACHES) - .surface(MB.of(Material.SAND)); + .surface(MB.of(Material.SAND)) + .height(0.12) + .schematic("palm", 0.83); public static final IrisBiome ROAD_GRAVEL = new IrisBiome("Gravel Road", Biome.PLAINS) .surface(MB.of(Material.GRAVEL), MB.of(Material.COBBLESTONE)) .scatter(MB.of(Material.TORCH), 0.05); @@ -42,127 +46,181 @@ public class IrisBiome .height(-0.07); public static final IrisBiome DESERT = new IrisBiome("Desert", Biome.DESERT) .surface(MB.of(Material.SAND)) + .schematic("deadwood", 0.03) .scatter(MB.of(Material.DEAD_BUSH, 0), 0.008) .dirt(MB.of(Material.SANDSTONE)); public static final IrisBiome DESERT_RED = new IrisBiome("Red Desert", Biome.DESERT) .surface(MB.of(Material.SAND, 1)) + .schematic("deadwood", 0.03) .scatter(MB.of(Material.DEAD_BUSH, 0), 0.008) .dirt(MB.of(Material.RED_SANDSTONE)); public static final IrisBiome DESERT_COMBINED = new IrisBiome("Combined Desert", Biome.DESERT) .surface(MB.of(Material.SAND), MB.of(Material.SAND, 1)) .scatter(MB.of(Material.DEAD_BUSH, 0), 0.008) + .schematic("deadwood", 0.05) .dirt(MB.of(Material.SANDSTONE), MB.of(Material.RED_SANDSTONE)) .simplexSurface(); public static final IrisBiome DESERT_HILLS = new IrisBiome("Desert Hills", Biome.DESERT_HILLS) .surface(MB.of(Material.SAND)) .amp(0.75) + .height(0.137) + .schematic("deadwood", 0.03) .scatter(MB.of(Material.DEAD_BUSH, 0), 0.08) .dirt(MB.of(Material.SANDSTONE)); public static final IrisBiome MESA = new IrisBiome("Mesa", Biome.MESA) .surface(MB.of(Material.HARD_CLAY), MB.of(Material.STAINED_CLAY, 1), MB.of(Material.STAINED_CLAY, 8), MB.of(Material.STAINED_CLAY, 12)) .dirt(MB.of(Material.CLAY), MB.of(Material.SAND), MB.of(Material.SAND, 1)) + .schematic("boulder", 0.02) .simplexSurface(); public static final IrisBiome SAVANNA = new IrisBiome("Savanna", Biome.SAVANNA) - .tree(TreeType.ACACIA, 0.102) + .schematic("deadwood", 0.03) + .schematic("boulder", 0.02) .scatter(MB.of(Material.LONG_GRASS, 1), 0.18); public static final IrisBiome SAVANNA_HILLS = new IrisBiome("Savanna Hills", Biome.SAVANNA_ROCK) .scatter(MB.of(Material.LONG_GRASS, 1), 0.18) - .tree(TreeType.ACACIA, 0.102) + .schematic("deadwood", 0.01) + .schematic("boulder", 0.02) + .height(0.13) .amp(0.75); + public static final IrisBiome OCEAN_2 = new IrisBiome("Ocean 2", Biome.OCEAN) + .surface(MB.of(Material.SAND), MB.of(Material.SAND), MB.of(Material.SAND), MB.of(Material.CLAY), MB.of(Material.GRAVEL)) + .simplexSurface() + .height(-0.03); public static final IrisBiome JUNGLE = new IrisBiome("Jungle", Biome.JUNGLE) .scatter(MB.of(Material.LONG_GRASS, 1), 0.058) - .tree(TreeType.JUNGLE, 0.9) - .tree(TreeType.JUNGLE_BUSH, 0.3) - .tree(TreeType.SMALL_JUNGLE, 0.1) + .schematic("boulder", 0.02) .scatter(MB.of(Material.LONG_GRASS, 2), 0.013); public static final IrisBiome JUNGLE_HILLS = new IrisBiome("Jungle Hills", Biome.JUNGLE_HILLS) .scatter(MB.of(Material.LONG_GRASS, 1), 0.081) - .tree(TreeType.JUNGLE, 0.9) - .tree(TreeType.JUNGLE_BUSH, 0.3) - .tree(TreeType.SMALL_JUNGLE, 0.1) + .schematic("boulder", 0.02) .amp(1.75) - .height(0.166) + .height(0.13) .scatter(MB.of(Material.LONG_GRASS, 2), 0.02); public static final IrisBiome SWAMP = new IrisBiome("Swamp", Biome.SWAMPLAND) .scatter(MB.of(Material.LONG_GRASS, 1), 0.04) - .tree(TreeType.SWAMP, 0.25) + .schematic("willow", 2.5) + .schematic("boulder", 0.02) .scatter(MB.of(Material.LONG_GRASS, 2), 0.03); public static final IrisBiome PLAINS = new IrisBiome("Plains", Biome.PLAINS) .scatter(MB.of(Material.LONG_GRASS, 1), 0.38) + .schematic("oak_bush", 0.25) + .schematic("boulder", 0.02) .amp(0.4) .scatter(MB.of(Material.LONG_GRASS, 2), 0.03); + public static final IrisBiome OCEAN_3 = new IrisBiome("Ocean 3", Biome.OCEAN) + .surface(MB.of(Material.SAND), MB.of(Material.SAND), MB.of(Material.SAND), MB.of(Material.CLAY), MB.of(Material.GRAVEL)) + .simplexSurface() + .height(-0.03); public static final IrisBiome DECAYING_PLAINS = new IrisBiome("Decaying Plains", Biome.PLAINS) .surface(MB.of(Material.GRASS_PATH), MB.of(Material.GRASS)) .scatter(MB.of(Material.LONG_GRASS, 1), 0.04) + .schematic("deadwood", 0.03) .simplexSurface(); public static final IrisBiome FOREST = new IrisBiome("Forest", Biome.FOREST) .scatter(MB.of(Material.LONG_GRASS, 1), 0.23) - .tree(TreeType.TREE, 0.7) + .schematic("oak", 2.31) + .schematic("boulder", 0.02) + .schematic("cracked_oak", 0.03) + .schematic("oak_large", 1.41) .scatter(MB.of(Material.LONG_GRASS, 2), 0.13); public static final IrisBiome FOREST_HILLS = new IrisBiome("Forest Hills", Biome.FOREST_HILLS) .scatter(MB.of(Material.LONG_GRASS, 1), 0.23) + .schematic("oak", 2.31) + .schematic("boulder", 0.02) + .schematic("cracked_oak", 0.03) + .schematic("oak_large", 0.31) .amp(0.75) - .tree(TreeType.TREE, 0.7) + .height(0.13) .scatter(MB.of(Material.LONG_GRASS, 2), 0.13); public static final IrisBiome FOREST_MOUNTAINS = new IrisBiome("Forest Mountains", Biome.MUTATED_EXTREME_HILLS_WITH_TREES) .scatter(MB.of(Material.LONG_GRASS, 1), 0.13) .amp(2.25) - .height(0.265) - .tree(TreeType.MEGA_REDWOOD, 0.5) - .tree(TreeType.TALL_REDWOOD, 0.7) + .schematic("pine", 2.31) + .schematic("boulder", 0.04) + .schematic("redwood", 1.11) + .schematic("redwood_tall", 2.51) + .height(0.165) .scatter(MB.of(Material.LONG_GRASS, 2), 0.13); public static final IrisBiome HAUNTED_FOREST = new IrisBiome("Haunted Forest", Biome.MUTATED_SWAMPLAND) .scatter(MB.of(Material.LONG_GRASS, 1), 0.13) - .tree(TreeType.JUNGLE_BUSH, 0.5) - .tree(TreeType.BIG_TREE, 0.4) - .tree(TreeType.SWAMP, 0.4) - .tree(TreeType.JUNGLE, 0.4) - .tree(TreeType.SMALL_JUNGLE, 0.4) - .tree(TreeType.JUNGLE_BUSH, 0.5) .scatter(MB.of(Material.LONG_GRASS, 2), 0.13) - .surface(MB.of(Material.GRASS), MB.of(Material.GRASS), MB.of(Material.GRASS), MB.of(Material.GRASS), MB.of(Material.DIRT), MB.of(Material.DIRT, 1), MB.of(Material.DIRT, 2)) + .schematic("willow", 2.31) + .schematic("oak", 1.31) + .schematic("boulder", 0.01) + .schematic("cracked_oak", 0.03) + .schematic("oak_bush", 1.83) + .addEffect(new PotionEffect(PotionEffectType.SLOW_DIGGING, 100, 0)) + .addEffect(new PotionEffect(PotionEffectType.SLOW, 100, 0)) + .addEffect(new PotionEffect(PotionEffectType.HUNGER, 100, 0)) + .surface(MB.of(Material.GRASS), MB.of(Material.GRASS), MB.of(Material.GRASS), MB.of(Material.GRASS), MB.of(Material.SOUL_SAND), MB.of(Material.DIRT), MB.of(Material.DIRT, 1), MB.of(Material.DIRT, 2)) .scatterSurface(); public static final IrisBiome BIRCH_FOREST = new IrisBiome("Birch Forest", Biome.BIRCH_FOREST) .scatter(MB.of(Material.LONG_GRASS, 1), 0.23) - .tree(TreeType.BIRCH, 0.7) + .schematic("birch", 2.51) + .schematic("boulder", 0.02) + .schematic("birch_small", 3.25) .scatter(MB.of(Material.LONG_GRASS, 2), 0.13); public static final IrisBiome BIRCH_FOREST_HILLS = new IrisBiome("Birch Forest Hills", Biome.BIRCH_FOREST_HILLS) .scatter(MB.of(Material.LONG_GRASS, 1), 0.23) - .tree(TreeType.BIRCH, 0.7) + .schematic("birch", 2.51) + .schematic("boulder", 0.02) + .schematic("birch_small", 3.25) .amp(0.75) + .height(0.13) .scatter(MB.of(Material.LONG_GRASS, 2), 0.13); + public static final IrisBiome OCEAN_4 = new IrisBiome("Ocean 4", Biome.OCEAN) + .surface(MB.of(Material.SAND), MB.of(Material.SAND), MB.of(Material.SAND), MB.of(Material.CLAY), MB.of(Material.GRAVEL)) + .simplexSurface() + .height(-0.03); public static final IrisBiome ROOFED_FOREST = new IrisBiome("Roofed Forest", Biome.ROOFED_FOREST) .scatter(MB.of(Material.LONG_GRASS, 1), 0.23) - .tree(TreeType.DARK_OAK, 0.9) + .schematic("boulder", 0.02) .scatter(MB.of(Material.LONG_GRASS, 2), 0.13); public static final IrisBiome TAIGA = new IrisBiome("Taiga", Biome.TAIGA) - .tree(TreeType.REDWOOD, 0.4) + .schematic("cracked_pine", 0.03) + .schematic("pine", 2.51) + .schematic("boulder", 0.08) .scatter(MB.of(Material.LONG_GRASS, 2), 0.07); public static final IrisBiome EXTREME_HILLS = new IrisBiome("Extreme Hills", Biome.EXTREME_HILLS) .scatter(MB.of(Material.LONG_GRASS, 2), 0.04) .amp(1.565) - .height(0.22); + .height(0.142); public static final IrisBiome EXTREME_HILLS_TREES = new IrisBiome("Extreme Hills +", Biome.EXTREME_HILLS_WITH_TREES) .scatter(MB.of(Material.LONG_GRASS, 2), 0.09) - .tree(TreeType.REDWOOD, 0.1) + .schematic("boulder", 0.02) + .schematic("pine", 1.02) + .schematic("redwood_tall", 3.02) .amp(1.525) - .height(0.22); + .height(0.152); public static final IrisBiome TAIGA_COLD = new IrisBiome("Taiga Cold", Biome.TAIGA_COLD) - .tree(TreeType.REDWOOD, 0.3) - .scatter(MB.of(Material.LONG_GRASS, 2), 0.04); + .scatter(MB.of(Material.LONG_GRASS, 2), 0.04) + .schematic("pine", 2.51) + .schematic("boulder", 0.02) + .schematic("cracked_pine", 0.03); public static final IrisBiome TAIGA_COLD_HILLS = new IrisBiome("Taiga Cold Hills", Biome.TAIGA_COLD_HILLS) - .tree(TreeType.REDWOOD, 0.15).amp(0.75); + .schematic("pine", 2.51) + .schematic("boulder", 0.02) + .schematic("cracked_pine", 0.03); public static final IrisBiome ICE_FLATS = new IrisBiome("Ice Flats", Biome.ICE_FLATS); public static final IrisBiome ICE_MOUNTAINS = new IrisBiome("Ice Mountains", Biome.ICE_MOUNTAINS) .amp(1.45); + public static final IrisBiome OCEAN_5 = new IrisBiome("Ocean 5", Biome.OCEAN) + .surface(MB.of(Material.SAND), MB.of(Material.SAND), MB.of(Material.SAND), MB.of(Material.CLAY), MB.of(Material.GRAVEL)) + .simplexSurface() + .height(-0.03); public static final IrisBiome REDWOOD_TAIGA = new IrisBiome("Redwood Taiga", Biome.REDWOOD_TAIGA) .surface(MB.of(Material.DIRT, 2), MB.of(Material.DIRT, 1)) - .tree(TreeType.TALL_REDWOOD, 0.7) - .tree(TreeType.MEGA_REDWOOD, 0.6) - .tree(TreeType.REDWOOD, 0.3) + .schematic("redwood_large", 0.87) + .schematic("cracked_pine", 0.03) + .schematic("boulder", 0.02) + .schematic("redwood", 3.5) .simplexSurface(); public static final IrisBiome REDWOOD_TAIGA_HILLS = new IrisBiome("Redwood Taiga Hills", Biome.REDWOOD_TAIGA_HILLS) .surface(MB.of(Material.DIRT, 2), MB.of(Material.DIRT, 1)) + .schematic("redwood_large", 0.87) + .schematic("cracked_pine", 0.03) + .schematic("boulder", 0.02) + .schematic("redwood", 3.5) .amp(0.75) .simplexSurface(); @@ -172,7 +230,7 @@ public class IrisBiome private Biome realBiome; private double height; private double amp; - private GMap treeChance; + private GList effects; private GList surface; private GList dirt; private GMap scatterChance; @@ -184,12 +242,12 @@ public class IrisBiome public IrisBiome(String name, Biome realBiome) { this.name = name; + effects = new GList<>(); this.realBiome = realBiome; this.height = 0.125; this.amp = 0.5; scatterChance = new GMap<>(); schematicGroups = new GMap<>(); - treeChance = new GMap<>(); surface(new MB(Material.GRASS)).dirt(new MB(Material.DIRT), new MB(Material.DIRT, 1)); } @@ -221,15 +279,8 @@ public class IrisBiome return this; } - - public IrisBiome tree(TreeType t, Double chance) - { - treeChance.put(t, chance); - - return this; - } - - public IrisBiome schematic(String t, Double chance) + + public IrisBiome schematic(String t, double chance) { schematicGroups.put(t, chance); @@ -344,6 +395,12 @@ public class IrisBiome { return scatterChance; } + + public IrisBiome addEffect(PotionEffect effect) + { + effects.add(effect); + return this; + } public MB getScatterChanceSingle() { @@ -358,41 +415,15 @@ public class IrisBiome return MB.of(Material.AIR); } - public GMap getTreeChance() - { - return treeChance; - } - - public TreeType getTreeChanceSingle() - { - for(TreeType i : getTreeChance().keySet()) - { - if(M.r(getTreeChance().get(i))) - { - return i; - } - } - - return null; - } - - public String getSchematicChanceSingle() - { - for(String i : schematicGroups.keySet()) - { - if(M.r(schematicGroups.get(i))) - { - return i; - } - } - - return null; - } - public static GList getBiomes() { return map.v().remove(IrisBiome.ROAD_GRASSY, IrisBiome.ROAD_GRAVEL, IrisBiome.BEACH, IrisBiome.LAKE, IrisBiome.RIVER); } + + public static GList getAllBiomes() + { + return map.v(); + } public static IrisBiome findByBiome(Biome biome) { @@ -408,4 +439,18 @@ public class IrisBiome { return schematicGroups; } + + public void applyEffects(Player j) + { + if(j.getLocation().getY() < 63) + { + return; + } + + for(PotionEffect i : effects) + { + j.getPlayer().removePotionEffect(i.getType()); + j.addPotionEffect(i); + } + } } diff --git a/src/main/java/ninja/bytecode/iris/generator/layer/GenLayerCaves.java b/src/main/java/ninja/bytecode/iris/generator/layer/GenLayerCaves.java index a23bd6286..3e8027671 100644 --- a/src/main/java/ninja/bytecode/iris/generator/layer/GenLayerCaves.java +++ b/src/main/java/ninja/bytecode/iris/generator/layer/GenLayerCaves.java @@ -30,7 +30,7 @@ public class GenLayerCaves extends GenLayer public void genCaves(double wxx, double wzx, int x, int z, int s, IrisGenerator g) { - for(double itr = 0; itr < 0.2; itr += 0.1) + for(double itr = 0; itr < 0.4; itr += 0.1) { double thickness = 0.25 + itr + (0.5 * caveClamp.noise(wxx, wzx)); double size = 3.88D * thickness; diff --git a/src/main/java/ninja/bytecode/iris/generator/layer/GenLayerOreCoal.java b/src/main/java/ninja/bytecode/iris/generator/layer/GenLayerOreCoal.java new file mode 100644 index 000000000..ac0b71386 --- /dev/null +++ b/src/main/java/ninja/bytecode/iris/generator/layer/GenLayerOreCoal.java @@ -0,0 +1,45 @@ +package ninja.bytecode.iris.generator.layer; + +import java.util.Random; + +import org.bukkit.Material; +import org.bukkit.World; + +import ninja.bytecode.iris.generator.IrisGenerator; +import ninja.bytecode.iris.generator.biome.IrisBiome; +import ninja.bytecode.iris.util.GenLayer; +import ninja.bytecode.iris.util.MB; +import ninja.bytecode.shuriken.math.CNG; +import ninja.bytecode.shuriken.math.RNG; + +public class GenLayerOreCoal extends GenLayer +{ + private CNG ore; + + public GenLayerOreCoal(IrisGenerator iris, World world, Random random, RNG rng, int shift) + { + //@builder + super(iris, world, random, rng); + ore = new CNG(rng.nextParallelRNG(281 + shift), 1D, 1).scale(0.1125).fractureWith(new CNG(rng.nextParallelRNG(412 + shift), 1D, 1) + .scale(0.015).fractureWith(new CNG(rng.nextParallelRNG(412 + shift), 1D, 1) + .scale(0.03), 33), 592); + + //@done + } + + public void genOre(double wxx, double wzx, int x, int z, int s, IrisGenerator g, IrisBiome b) + { + double orenoise = ore.noise(wxx, wzx); + + if(IrisGenerator.ROCK.contains(MB.of(g.getType(x, (int) (orenoise * 200D) - 15, z)))) + { + g.setBlock(x, (int) (orenoise * 200D) - 15, z, Material.COAL_ORE); + } + } + + @Override + public double generateLayer(double noise, double dx, double dz) + { + return noise; + } +} diff --git a/src/main/java/ninja/bytecode/iris/generator/layer/GenLayerOreDiamond.java b/src/main/java/ninja/bytecode/iris/generator/layer/GenLayerOreDiamond.java new file mode 100644 index 000000000..aa7d0414b --- /dev/null +++ b/src/main/java/ninja/bytecode/iris/generator/layer/GenLayerOreDiamond.java @@ -0,0 +1,49 @@ +package ninja.bytecode.iris.generator.layer; + +import java.util.Random; + +import org.bukkit.Material; +import org.bukkit.World; + +import ninja.bytecode.iris.generator.IrisGenerator; +import ninja.bytecode.iris.generator.biome.IrisBiome; +import ninja.bytecode.iris.util.GenLayer; +import ninja.bytecode.iris.util.MB; +import ninja.bytecode.shuriken.math.CNG; +import ninja.bytecode.shuriken.math.RNG; + +public class GenLayerOreDiamond extends GenLayer +{ + private CNG ore; + private CNG clamp; + + public GenLayerOreDiamond(IrisGenerator iris, World world, Random random, RNG rng, int shift) + { + //@builder + super(iris, world, random, rng); + ore = new CNG(rng.nextParallelRNG(281 + shift), 1D, 1).scale(0.08725).fractureWith(new CNG(rng.nextParallelRNG(412 + shift), 1D, 1) + .scale(0.015).fractureWith(new CNG(rng.nextParallelRNG(412 + shift), 1D, 1) + .scale(0.03), 33), 592); + clamp = new CNG(rng.nextParallelRNG(299 + shift), 1D, 1).scale(0.0325).fractureWith(new CNG(rng.nextParallelRNG(412 + shift), 1D, 1) + .scale(0.015).fractureWith(new CNG(rng.nextParallelRNG(412 + shift), 1D, 1) + .scale(0.03), 33), 592); + + //@done + } + + public void genOre(double wxx, double wzx, int x, int z, int s, IrisGenerator g, IrisBiome b) + { + double orenoise = ore.noise(wxx, wzx); + + if(clamp.noise(wxx, wzx) > 0.77 && IrisGenerator.ROCK.contains(MB.of(g.getType(x, (int) (orenoise * 12D), z)))) + { + g.setBlock(x, (int) (orenoise * 12D), z, Material.DIAMOND_ORE); + } + } + + @Override + public double generateLayer(double noise, double dx, double dz) + { + return noise; + } +} diff --git a/src/main/java/ninja/bytecode/iris/generator/layer/GenLayerOreEmerald.java b/src/main/java/ninja/bytecode/iris/generator/layer/GenLayerOreEmerald.java new file mode 100644 index 000000000..2f106db6e --- /dev/null +++ b/src/main/java/ninja/bytecode/iris/generator/layer/GenLayerOreEmerald.java @@ -0,0 +1,45 @@ +package ninja.bytecode.iris.generator.layer; + +import java.util.Random; + +import org.bukkit.Material; +import org.bukkit.World; + +import ninja.bytecode.iris.generator.IrisGenerator; +import ninja.bytecode.iris.generator.biome.IrisBiome; +import ninja.bytecode.iris.util.GenLayer; +import ninja.bytecode.iris.util.MB; +import ninja.bytecode.shuriken.math.CNG; +import ninja.bytecode.shuriken.math.RNG; + +public class GenLayerOreEmerald extends GenLayer +{ + private CNG ore; + + public GenLayerOreEmerald(IrisGenerator iris, World world, Random random, RNG rng, int shift) + { + //@builder + super(iris, world, random, rng); + ore = new CNG(rng.nextParallelRNG(281 + shift), 1D, 1).scale(0.1125).fractureWith(new CNG(rng.nextParallelRNG(412 + shift), 1D, 1) + .scale(0.015).fractureWith(new CNG(rng.nextParallelRNG(412 + shift), 1D, 1) + .scale(0.03), 33), 592); + + //@done + } + + public void genOre(double wxx, double wzx, int x, int z, int s, IrisGenerator g, IrisBiome b) + { + double orenoise = ore.noise(wxx, wzx); + + if(b.getScatterChanceSingle().material.equals(Material.LONG_GRASS) && b.getScatterChanceSingle().material.equals(Material.LONG_GRASS) && b.getScatterChanceSingle().material.equals(Material.LONG_GRASS) && IrisGenerator.ROCK.contains(MB.of(g.getType(x, (int) (orenoise * 32D), z)))) + { + g.setBlock(x, (int) (orenoise * 32D), z, Material.EMERALD_ORE); + } + } + + @Override + public double generateLayer(double noise, double dx, double dz) + { + return noise; + } +} diff --git a/src/main/java/ninja/bytecode/iris/generator/layer/GenLayerOreGold.java b/src/main/java/ninja/bytecode/iris/generator/layer/GenLayerOreGold.java new file mode 100644 index 000000000..f42fc25d2 --- /dev/null +++ b/src/main/java/ninja/bytecode/iris/generator/layer/GenLayerOreGold.java @@ -0,0 +1,48 @@ +package ninja.bytecode.iris.generator.layer; + +import java.util.Random; + +import org.bukkit.Material; +import org.bukkit.World; + +import ninja.bytecode.iris.generator.IrisGenerator; +import ninja.bytecode.iris.generator.biome.IrisBiome; +import ninja.bytecode.iris.util.GenLayer; +import ninja.bytecode.iris.util.MB; +import ninja.bytecode.shuriken.math.CNG; +import ninja.bytecode.shuriken.math.RNG; + +public class GenLayerOreGold extends GenLayer +{ + private CNG ore; + private CNG clamp; + + public GenLayerOreGold(IrisGenerator iris, World world, Random random, RNG rng, int shift) + { + //@builder + super(iris, world, random, rng); + ore = new CNG(rng.nextParallelRNG(281 + shift), 1D, 3).scale(0.0925).fractureWith(new CNG(rng.nextParallelRNG(412 + shift), 1D, 1) + .scale(0.0015).fractureWith(new CNG(rng.nextParallelRNG(412 + shift), 1D, 1) + .scale(0.03), 33), 592); + clamp = new CNG(rng.nextParallelRNG(299 + shift), 1D, 1).scale(0.0325).fractureWith(new CNG(rng.nextParallelRNG(412 + shift), 1D, 1) + .scale(0.015).fractureWith(new CNG(rng.nextParallelRNG(412 + shift), 1D, 1) + .scale(0.03), 33), 592); + //@done + } + + public void genOre(double wxx, double wzx, int x, int z, int s, IrisGenerator g, IrisBiome b) + { + double orenoise = ore.noise(wxx, wzx); + + if(clamp.noise(wxx, wzx) < 0.4 && (int) (orenoise * 200D) - 42 < 45 && b.getSurface().contains(new MB(Material.GRASS)) && IrisGenerator.ROCK.contains(MB.of(g.getType(x, (int) (orenoise * 200D) - 42, z)))) + { + g.setBlock(x, (int) (orenoise * 200D) - 42, z, Material.GOLD_ORE); + } + } + + @Override + public double generateLayer(double noise, double dx, double dz) + { + return noise; + } +} diff --git a/src/main/java/ninja/bytecode/iris/generator/layer/GenLayerOreIron.java b/src/main/java/ninja/bytecode/iris/generator/layer/GenLayerOreIron.java new file mode 100644 index 000000000..0d7aab0ed --- /dev/null +++ b/src/main/java/ninja/bytecode/iris/generator/layer/GenLayerOreIron.java @@ -0,0 +1,45 @@ +package ninja.bytecode.iris.generator.layer; + +import java.util.Random; + +import org.bukkit.Material; +import org.bukkit.World; + +import ninja.bytecode.iris.generator.IrisGenerator; +import ninja.bytecode.iris.generator.biome.IrisBiome; +import ninja.bytecode.iris.util.GenLayer; +import ninja.bytecode.iris.util.MB; +import ninja.bytecode.shuriken.math.CNG; +import ninja.bytecode.shuriken.math.RNG; + +public class GenLayerOreIron extends GenLayer +{ + private CNG ore; + + public GenLayerOreIron(IrisGenerator iris, World world, Random random, RNG rng, int shift) + { + //@builder + super(iris, world, random, rng); + ore = new CNG(rng.nextParallelRNG(281 + shift), 1D, 1).scale(0.1125).fractureWith(new CNG(rng.nextParallelRNG(412 + shift), 1D, 1) + .scale(0.015).fractureWith(new CNG(rng.nextParallelRNG(412 + shift), 1D, 1) + .scale(0.03), 33), 592); + + //@done + } + + public void genOre(double wxx, double wzx, int x, int z, int s, IrisGenerator g, IrisBiome b) + { + double orenoise = ore.noise(wxx, wzx); + + if(IrisGenerator.ROCK.contains(MB.of(g.getType(x, (int) (orenoise * 200D), z)))) + { + g.setBlock(x, (int) (orenoise * 200D), z, Material.IRON_ORE); + } + } + + @Override + public double generateLayer(double noise, double dx, double dz) + { + return noise; + } +} diff --git a/src/main/java/ninja/bytecode/iris/generator/layer/GenLayerOreLapis.java b/src/main/java/ninja/bytecode/iris/generator/layer/GenLayerOreLapis.java new file mode 100644 index 000000000..c9a0412fa --- /dev/null +++ b/src/main/java/ninja/bytecode/iris/generator/layer/GenLayerOreLapis.java @@ -0,0 +1,45 @@ +package ninja.bytecode.iris.generator.layer; + +import java.util.Random; + +import org.bukkit.Material; +import org.bukkit.World; + +import ninja.bytecode.iris.generator.IrisGenerator; +import ninja.bytecode.iris.generator.biome.IrisBiome; +import ninja.bytecode.iris.util.GenLayer; +import ninja.bytecode.iris.util.MB; +import ninja.bytecode.shuriken.math.CNG; +import ninja.bytecode.shuriken.math.RNG; + +public class GenLayerOreLapis extends GenLayer +{ + private CNG ore; + + public GenLayerOreLapis(IrisGenerator iris, World world, Random random, RNG rng, int shift) + { + //@builder + super(iris, world, random, rng); + ore = new CNG(rng.nextParallelRNG(281 + shift), 1D, 3).scale(0.4125).fractureWith(new CNG(rng.nextParallelRNG(412 + shift), 1D, 1) + .scale(0.0015).fractureWith(new CNG(rng.nextParallelRNG(412 + shift), 1D, 1) + .scale(0.03), 33), 592); + + //@done + } + + public void genOre(double wxx, double wzx, int x, int z, int s, IrisGenerator g, IrisBiome b) + { + double orenoise = ore.noise(wxx, wzx); + + if(b.getSurface().contains(new MB(Material.SAND)) && IrisGenerator.ROCK.contains(MB.of(g.getType(x, (int) (orenoise * 200D), z)))) + { + g.setBlock(x, (int) (orenoise * 200D), z, Material.LAPIS_ORE); + } + } + + @Override + public double generateLayer(double noise, double dx, double dz) + { + return noise; + } +} diff --git a/src/main/java/ninja/bytecode/iris/generator/populator/SurfaceBiasSchematicPopulator.java b/src/main/java/ninja/bytecode/iris/generator/populator/SurfaceBiasSchematicPopulator.java index 8e5b5c2df..fdab10a29 100644 --- a/src/main/java/ninja/bytecode/iris/generator/populator/SurfaceBiasSchematicPopulator.java +++ b/src/main/java/ninja/bytecode/iris/generator/populator/SurfaceBiasSchematicPopulator.java @@ -30,6 +30,11 @@ public class SurfaceBiasSchematicPopulator extends SchematicPopulator @Override public void doPopulate(World world, Random random, Chunk source, int wx, int wz) { + if(schematics.length == 0) + { + return; + } + Block b = world.getHighestBlockAt(wx, wz); for(Material i : bias) diff --git a/src/main/java/ninja/bytecode/iris/schematic/Schematic.java b/src/main/java/ninja/bytecode/iris/schematic/Schematic.java index b53886395..51f053ba2 100644 --- a/src/main/java/ninja/bytecode/iris/schematic/Schematic.java +++ b/src/main/java/ninja/bytecode/iris/schematic/Schematic.java @@ -12,9 +12,9 @@ import java.util.zip.GZIPInputStream; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; -import org.bukkit.block.Block; import org.bukkit.util.BlockVector; +import ninja.bytecode.iris.util.Catalyst12; import ninja.bytecode.iris.util.MB; import ninja.bytecode.shuriken.collections.GMap; import ninja.bytecode.shuriken.io.CustomOutputStream; @@ -108,7 +108,7 @@ public class Schematic for(int i = 0; i < l; i++) { - s.put(new BlockVector(din.readInt(), din.readInt(), din.readInt()), new MB(Material.getMaterial((int)din.readByte()), din.readByte())); + s.put(new BlockVector(din.readInt(), din.readInt(), din.readInt()), new MB(Material.getMaterial((int)din.readInt()), din.readInt())); } din.close(); @@ -132,8 +132,8 @@ public class Schematic dos.writeInt(i.getBlockX()); dos.writeInt(i.getBlockY()); dos.writeInt(i.getBlockZ()); - dos.writeByte(s.get(i).material.getId()); - dos.writeByte(s.get(i).data); + dos.writeInt(s.get(i).material.getId()); + dos.writeInt(s.get(i).data); } dos.close(); @@ -177,34 +177,39 @@ public class Schematic s.put(b); } - @SuppressWarnings("deprecation") public void place(World source, int wx, int wy, int wz) { - Location start = new Location(source, wx, wy, wz).clone().subtract(getOffset()); + Location start = new Location(source, wx, wy, wz).clone().subtract(w / 2, 0, d / 2); - for(BlockVector i : getSchematic().keySet()) + for(BlockVector i : getSchematic().k()) { MB b = getSchematic().get(i); - Block blk = start.clone().add(i).getBlock(); - - if(!blk.isEmpty() && !b.material.isOccluding()) + Location f = start.clone().add(i); + + if(b.material.equals(Material.SKULL)) { continue; } - blk.setTypeIdAndData(b.material.getId(), b.data, false); + try + { + Catalyst12.setBlock(source, f.getBlockX(), f.getBlockY(), f.getBlockZ(), b); + } + + catch(Throwable e) + { + e.printStackTrace(); + } } } - - public static Schematic load(File f) throws IOException { - L.i("Loading Schematic: " + f.getPath()); Schematic s = new Schematic(1, 1, 1, 1, 1, 1); FileInputStream fin = new FileInputStream(f); s.read(fin); - + + L.i("Loaded Schematic: " + f.getPath() + " Size: " + s.getSchematic().size()); return s; } } diff --git a/src/main/java/ninja/bytecode/iris/util/Catalyst12.java b/src/main/java/ninja/bytecode/iris/util/Catalyst12.java index bc91ef762..457ff0980 100644 --- a/src/main/java/ninja/bytecode/iris/util/Catalyst12.java +++ b/src/main/java/ninja/bytecode/iris/util/Catalyst12.java @@ -28,12 +28,9 @@ public class Catalyst12 } @SuppressWarnings("deprecation") - public static void setBlock(Location l, MB m) + public static void setBlock(World wo, int x, int y, int z, MB m) { - int x = l.getBlockX(); - int y = l.getBlockY(); - int z = l.getBlockZ(); - net.minecraft.server.v1_12_R1.World w = ((CraftWorld) l.getWorld()).getHandle(); + net.minecraft.server.v1_12_R1.World w = ((CraftWorld) wo).getHandle(); net.minecraft.server.v1_12_R1.Chunk chunk = w.getChunkAt(x >> 4, z >> 4); int combined = m.material.getId() + (m.data << 12); IBlockData ibd = net.minecraft.server.v1_12_R1.Block.getByCombinedId(combined); @@ -44,10 +41,6 @@ public class Catalyst12 } net.minecraft.server.v1_12_R1.ChunkSection sec = chunk.getSections()[y >> 4]; - - synchronized(sec) - { - sec.setType(x & 15, y & 15, z & 15, ibd); - } + sec.setType(x & 15, y & 15, z & 15, ibd); } } \ No newline at end of file diff --git a/src/main/java/ninja/bytecode/iris/util/ColoredEffect.java b/src/main/java/ninja/bytecode/iris/util/ColoredEffect.java new file mode 100644 index 000000000..03005f5f8 --- /dev/null +++ b/src/main/java/ninja/bytecode/iris/util/ColoredEffect.java @@ -0,0 +1,10 @@ +package ninja.bytecode.iris.util; + +import java.awt.Color; + +public interface ColoredEffect +{ + public ColoredEffect setColor(Color color); + + public Color getColor(); +} diff --git a/src/main/java/ninja/bytecode/iris/util/MB.java b/src/main/java/ninja/bytecode/iris/util/MB.java index 29fc172fc..d5e90e189 100644 --- a/src/main/java/ninja/bytecode/iris/util/MB.java +++ b/src/main/java/ninja/bytecode/iris/util/MB.java @@ -27,4 +27,31 @@ public class MB { return new MB(f, a); } + + @Override + public int hashCode() + { + final int prime = 31; + int result = 1; + result = prime * result + data; + result = prime * result + ((material == null) ? 0 : material.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) + { + if(this == obj) + return true; + if(obj == null) + return false; + if(getClass() != obj.getClass()) + return false; + MB other = (MB) obj; + if(data != other.data) + return false; + if(material != other.material) + return false; + return true; + } } diff --git a/src/main/java/ninja/bytecode/iris/util/ParticleBase.java b/src/main/java/ninja/bytecode/iris/util/ParticleBase.java new file mode 100644 index 000000000..aa20e1a97 --- /dev/null +++ b/src/main/java/ninja/bytecode/iris/util/ParticleBase.java @@ -0,0 +1,30 @@ +package ninja.bytecode.iris.util; + +import org.bukkit.Location; +import org.bukkit.entity.Player; + +import ninja.bytecode.shuriken.collections.GList; + +public abstract class ParticleBase implements VisualEffect +{ + @Override + public abstract void play(Location l, double range); + + @Override + public abstract void play(Location l, Player p); + + @Override + public void play(Location l) + { + play(l, 64); + } + + @Override + public void play(Location l, GList p) + { + for(Player i : p) + { + play(l, i); + } + } +} diff --git a/src/main/java/ninja/bytecode/iris/util/ParticleEffect.java b/src/main/java/ninja/bytecode/iris/util/ParticleEffect.java new file mode 100644 index 000000000..ba2f68f5a --- /dev/null +++ b/src/main/java/ninja/bytecode/iris/util/ParticleEffect.java @@ -0,0 +1,2101 @@ +package ninja.bytecode.iris.util; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.bukkit.Bukkit; +import org.bukkit.Color; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.util.Vector; + +import ninja.bytecode.iris.util.ParticleEffect.ParticleData; +import ninja.bytecode.iris.util.ReflectionUtils.PackageType; + +/** + * ParticleEffect Library + *

+ * This library was created by @DarkBlade12 and allows you to display all + * Minecraft particle effects on a Bukkit server + *

+ * You are welcome to use it, modify it and redistribute it under the following + * conditions: + *

    + *
  • Don't claim this class as your own + *
  • Don't remove this disclaimer + *
+ *

+ * Special thanks: + *

    + *
  • @microgeek (original idea, names and packet parameters) + *
  • @ShadyPotato (1.8 names, ids and packet parameters) + *
  • @RingOfStorms (particle behavior) + *
  • @Cybermaxke (particle behavior) + *
  • @JamieSinn (hosting a jenkins server and documentation for + * particleeffect) + *
+ *

+ * It would be nice if you provide credit to me if you use this class in a + * published project + * + * @author DarkBlade12 + * @version 1.7 + */ +@SuppressWarnings("unused") +public enum ParticleEffect +{ + /** + * A particle effect which is displayed by exploding tnt and creepers: + *

    + *
  • It looks like a white cloud + *
  • The speed value influences the velocity at which the particle flies off + *
+ */ + EXPLOSION_NORMAL("explode", 0, -1, ParticleProperty.DIRECTIONAL), + /** + * A particle effect which is displayed by exploding ghast fireballs and wither + * skulls: + *
    + *
  • It looks like a gray ball which is fading away + *
  • The speed value slightly influences the size of this particle effect + *
+ */ + EXPLOSION_LARGE("largeexplode", 1, -1), + /** + * A particle effect which is displayed by exploding tnt and creepers: + *
    + *
  • It looks like a crowd of gray balls which are fading away + *
  • The speed value has no influence on this particle effect + *
+ */ + EXPLOSION_HUGE("hugeexplosion", 2, -1), + /** + * A particle effect which is displayed by launching fireworks: + *
    + *
  • It looks like a white star which is sparkling + *
  • The speed value influences the velocity at which the particle flies off + *
+ */ + FIREWORKS_SPARK("fireworksSpark", 3, -1, ParticleProperty.DIRECTIONAL), + /** + * A particle effect which is displayed by swimming entities and arrows in + * water: + *
    + *
  • It looks like a bubble + *
  • The speed value influences the velocity at which the particle flies off + *
+ */ + WATER_BUBBLE("bubble", 4, -1, ParticleProperty.DIRECTIONAL, ParticleProperty.REQUIRES_WATER), + /** + * A particle effect which is displayed by swimming entities and shaking wolves: + *
    + *
  • It looks like a blue drop + *
  • The speed value has no influence on this particle effect + *
+ */ + WATER_SPLASH("splash", 5, -1, ParticleProperty.DIRECTIONAL), + /** + * A particle effect which is displayed on water when fishing: + *
    + *
  • It looks like a blue droplet + *
  • The speed value influences the velocity at which the particle flies off + *
+ */ + WATER_WAKE("wake", 6, 7, ParticleProperty.DIRECTIONAL), + /** + * A particle effect which is displayed by water: + *
    + *
  • It looks like a tiny blue square + *
  • The speed value has no influence on this particle effect + *
+ */ + SUSPENDED("suspended", 7, -1, ParticleProperty.REQUIRES_WATER), + /** + * A particle effect which is displayed by air when close to bedrock and the in + * the void: + *
    + *
  • It looks like a tiny gray square + *
  • The speed value has no influence on this particle effect + *
+ */ + SUSPENDED_DEPTH("depthSuspend", 8, -1, ParticleProperty.DIRECTIONAL), + /** + * A particle effect which is displayed when landing a critical hit and by + * arrows: + *
    + *
  • It looks like a light brown cross + *
  • The speed value influences the velocity at which the particle flies off + *
+ */ + CRIT("crit", 9, -1, ParticleProperty.DIRECTIONAL), + /** + * A particle effect which is displayed when landing a hit with an enchanted + * weapon: + *
    + *
  • It looks like a cyan star + *
  • The speed value influences the velocity at which the particle flies off + *
+ */ + CRIT_MAGIC("magicCrit", 10, -1, ParticleProperty.DIRECTIONAL), + /** + * A particle effect which is displayed by primed tnt, torches, droppers, + * dispensers, end portals, brewing stands and monster spawners: + *
    + *
  • It looks like a little gray cloud + *
  • The speed value influences the velocity at which the particle flies off + *
+ */ + SMOKE_NORMAL("smoke", 11, -1, ParticleProperty.DIRECTIONAL), + /** + * A particle effect which is displayed by fire, minecarts with furnace and + * blazes: + *
    + *
  • It looks like a large gray cloud + *
  • The speed value influences the velocity at which the particle flies off + *
+ */ + SMOKE_LARGE("largesmoke", 12, -1, ParticleProperty.DIRECTIONAL), + /** + * A particle effect which is displayed when splash potions or bottles o' + * enchanting hit something: + *
    + *
  • It looks like a white swirl + *
  • The speed value causes the particle to only move upwards when set to 0 + *
  • Only the motion on the y-axis can be controlled, the motion on the x- and + * z-axis are multiplied by 0.1 when setting the values to 0 + *
+ */ + SPELL("spell", 13, -1), + /** + * A particle effect which is displayed when instant splash potions hit + * something: + *
    + *
  • It looks like a white cross + *
  • The speed value causes the particle to only move upwards when set to 0 + *
  • Only the motion on the y-axis can be controlled, the motion on the x- and + * z-axis are multiplied by 0.1 when setting the values to 0 + *
+ */ + SPELL_INSTANT("instantSpell", 14, -1), + /** + * A particle effect which is displayed by entities with active potion effects: + *
    + *
  • It looks like a colored swirl + *
  • The speed value causes the particle to be colored black when set to 0 + *
  • The particle color gets lighter when increasing the speed and darker when + * decreasing the speed + *
+ */ + SPELL_MOB("mobSpell", 15, -1, ParticleProperty.COLORABLE), + /** + * A particle effect which is displayed by entities with active potion effects + * applied through a beacon: + *
    + *
  • It looks like a transparent colored swirl + *
  • The speed value causes the particle to be always colored black when set + * to 0 + *
  • The particle color gets lighter when increasing the speed and darker when + * decreasing the speed + *
+ */ + SPELL_MOB_AMBIENT("mobSpellAmbient", 16, -1, ParticleProperty.COLORABLE), + /** + * A particle effect which is displayed by witches: + *
    + *
  • It looks like a purple cross + *
  • The speed value causes the particle to only move upwards when set to 0 + *
  • Only the motion on the y-axis can be controlled, the motion on the x- and + * z-axis are multiplied by 0.1 when setting the values to 0 + *
+ */ + SPELL_WITCH("witchMagic", 17, -1), + /** + * A particle effect which is displayed by blocks beneath a water source: + *
    + *
  • It looks like a blue drip + *
  • The speed value has no influence on this particle effect + *
+ */ + DRIP_WATER("dripWater", 18, -1), + /** + * A particle effect which is displayed by blocks beneath a lava source: + *
    + *
  • It looks like an orange drip + *
  • The speed value has no influence on this particle effect + *
+ */ + DRIP_LAVA("dripLava", 19, -1), + /** + * A particle effect which is displayed when attacking a villager in a village: + *
    + *
  • It looks like a cracked gray heart + *
  • The speed value has no influence on this particle effect + *
+ */ + VILLAGER_ANGRY("angryVillager", 20, -1), + /** + * A particle effect which is displayed when using bone meal and trading with a + * villager in a village: + *
    + *
  • It looks like a green star + *
  • The speed value has no influence on this particle effect + *
+ */ + VILLAGER_HAPPY("happyVillager", 21, -1, ParticleProperty.DIRECTIONAL), + /** + * A particle effect which is displayed by mycelium: + *
    + *
  • It looks like a tiny gray square + *
  • The speed value has no influence on this particle effect + *
+ */ + TOWN_AURA("townaura", 22, -1, ParticleProperty.DIRECTIONAL), + /** + * A particle effect which is displayed by note blocks: + *
    + *
  • It looks like a colored note + *
  • The speed value causes the particle to be colored green when set to 0 + *
+ */ + NOTE("note", 23, -1, ParticleProperty.COLORABLE), + /** + * A particle effect which is displayed by nether portals, endermen, ender + * pearls, eyes of ender, ender chests and dragon eggs: + *
    + *
  • It looks like a purple cloud + *
  • The speed value influences the spread of this particle effect + *
+ */ + PORTAL("portal", 24, -1, ParticleProperty.DIRECTIONAL), + /** + * A particle effect which is displayed by enchantment tables which are nearby + * bookshelves: + *
    + *
  • It looks like a cryptic white letter + *
  • The speed value influences the spread of this particle effect + *
+ */ + ENCHANTMENT_TABLE("enchantmenttable", 25, -1, ParticleProperty.DIRECTIONAL), + /** + * A particle effect which is displayed by torches, active furnaces, magma cubes + * and monster spawners: + *
    + *
  • It looks like a tiny flame + *
  • The speed value influences the velocity at which the particle flies off + *
+ */ + FLAME("flame", 26, -1, ParticleProperty.DIRECTIONAL), + /** + * A particle effect which is displayed by lava: + *
    + *
  • It looks like a spark + *
  • The speed value has no influence on this particle effect + *
+ */ + LAVA("lava", 27, -1), + /** + * A particle effect which is currently unused: + *
    + *
  • It looks like a transparent gray square + *
  • The speed value has no influence on this particle effect + *
+ */ + FOOTSTEP("footstep", 28, -1), + /** + * A particle effect which is displayed when a mob dies: + *
    + *
  • It looks like a large white cloud + *
  • The speed value influences the velocity at which the particle flies off + *
+ */ + CLOUD("cloud", 29, -1, ParticleProperty.DIRECTIONAL), + /** + * A particle effect which is displayed by redstone ore, powered redstone, + * redstone torches and redstone repeaters: + *
    + *
  • It looks like a tiny colored cloud + *
  • The speed value causes the particle to be colored red when set to 0 + *
+ */ + REDSTONE("reddust", 30, -1, ParticleProperty.COLORABLE), + /** + * A particle effect which is displayed when snowballs hit a block: + *
    + *
  • It looks like a little piece with the snowball texture + *
  • The speed value has no influence on this particle effect + *
+ */ + SNOWBALL("snowballpoof", 31, -1), + /** + * A particle effect which is currently unused: + *
    + *
  • It looks like a tiny white cloud + *
  • The speed value influences the velocity at which the particle flies off + *
+ */ + SNOW_SHOVEL("snowshovel", 32, -1, ParticleProperty.DIRECTIONAL), + /** + * A particle effect which is displayed by slimes: + *
    + *
  • It looks like a tiny part of the slimeball icon + *
  • The speed value has no influence on this particle effect + *
+ */ + SLIME("slime", 33, -1), + /** + * A particle effect which is displayed when breeding and taming animals: + *
    + *
  • It looks like a red heart + *
  • The speed value has no influence on this particle effect + *
+ */ + HEART("heart", 34, -1), + /** + * A particle effect which is displayed by barriers: + *
    + *
  • It looks like a red box with a slash through it + *
  • The speed value has no influence on this particle effect + *
+ */ + BARRIER("barrier", 35, 8), + /** + * A particle effect which is displayed when breaking a tool or eggs hit a + * block: + *
    + *
  • It looks like a little piece with an item texture + *
+ */ + ITEM_CRACK("iconcrack", 36, -1, ParticleProperty.DIRECTIONAL, ParticleProperty.REQUIRES_DATA), + /** + * A particle effect which is displayed when breaking blocks or sprinting: + *
    + *
  • It looks like a little piece with a block texture + *
  • The speed value has no influence on this particle effect + *
+ */ + BLOCK_CRACK("blockcrack", 37, -1, ParticleProperty.REQUIRES_DATA), + /** + * A particle effect which is displayed when falling: + *
    + *
  • It looks like a little piece with a block texture + *
+ */ + BLOCK_DUST("blockdust", 38, 7, ParticleProperty.DIRECTIONAL, ParticleProperty.REQUIRES_DATA), + /** + * A particle effect which is displayed when rain hits the ground: + *
    + *
  • It looks like a blue droplet + *
  • The speed value has no influence on this particle effect + *
+ */ + WATER_DROP("droplet", 39, 8), + /** + * A particle effect which is currently unused: + *
    + *
  • It has no visual effect + *
+ */ + ITEM_TAKE("take", 40, 8), + + /** + * A particle effect which is displayed by elder guardians: + *
    + *
  • It looks like the shape of the elder guardian + *
  • The speed value has no influence on this particle effect + *
  • The offset values have no influence on this particle effect + *
+ */ + MOB_APPEARANCE("mobappearance", 41, 8), + + /** + * A particle effect which is displayed by enderdragons + */ + DRAGON_BREATH("dragonbreath", 42, 9), + + /** + * The end rod particle effect from end rods + */ + END_ROD("endrod", 43, 9), + + /** + * A damage indicator particle effect + */ + DAMAGE_INDICATOR("damageindicator", 44, 9), + + /** + * A swipe sword effect + */ + SWEEP_ATTACK("sweepttack", 45, 9); + + private static final Map NAME_MAP = new HashMap(); + private static final Map ID_MAP = new HashMap(); + private final String name; + private final int id; + private final int requiredVersion; + private final List properties; + + // Initialize map for quick name and id lookup + static + { + for(ParticleEffect effect : values()) + { + NAME_MAP.put(effect.name, effect); + ID_MAP.put(effect.id, effect); + } + } + + /** + * Construct a new particle effect + * + * @param name + * Name of this particle effect + * @param id + * Id of this particle effect + * @param requiredVersion + * Version which is required (1.x) + * @param properties + * Properties of this particle effect + */ + private ParticleEffect(String name, int id, int requiredVersion, ParticleProperty... properties) + { + this.name = name; + this.id = id; + this.requiredVersion = requiredVersion; + this.properties = Arrays.asList(properties); + } + + /** + * Returns the name of this particle effect + * + * @return The name + */ + public String getName() + { + return name; + } + + /** + * Returns the id of this particle effect + * + * @return The id + */ + public int getId() + { + return id; + } + + /** + * Returns the required version for this particle effect (1.x) + * + * @return The required version + */ + public int getRequiredVersion() + { + return requiredVersion; + } + + /** + * Determine if this particle effect has a specific property + * + * @return Whether it has the property or not + */ + public boolean hasProperty(ParticleProperty property) + { + return properties.contains(property); + } + + /** + * Determine if this particle effect is supported by your current server version + * + * @return Whether the particle effect is supported or not + */ + public boolean isSupported() + { + return true; + } + + /** + * Returns the particle effect with the given name + * + * @param name + * Name of the particle effect + * @return The particle effect + */ + public static ParticleEffect fromName(String name) + { + for(Entry entry : NAME_MAP.entrySet()) + { + if(!entry.getKey().equalsIgnoreCase(name)) + { + continue; + } + return entry.getValue(); + } + return null; + } + + /** + * Returns the particle effect with the given id + * + * @param id + * Id of the particle effect + * @return The particle effect + */ + public static ParticleEffect fromId(int id) + { + for(Entry entry : ID_MAP.entrySet()) + { + if(entry.getKey() != id) + { + continue; + } + return entry.getValue(); + } + return null; + } + + /** + * Determine if water is at a certain location + * + * @param location + * Location to check + * @return Whether water is at this location or not + */ + private static boolean isWater(Location location) + { + Material material = location.getBlock().getType(); + return false; + } + + /** + * Determine if the distance between @param location and one of the players + * exceeds 256 + * + * @param location + * Location to check + * @return Whether the distance exceeds 256 or not + */ + private static boolean isLongDistance(Location location, List players) + { + String world = location.getWorld().getName(); + for(Player player : players) + { + Location playerLocation = player.getLocation(); + if(!world.equals(playerLocation.getWorld().getName()) || playerLocation.distanceSquared(location) < 65536) + { + continue; + } + return true; + } + return false; + } + + /** + * Determine if the data type for a particle effect is correct + * + * @param effect + * Particle effect + * @param data + * Particle data + * @return Whether the data type is correct or not + */ + private static boolean isDataCorrect(ParticleEffect effect, ParticleData data) + { + return ((effect == BLOCK_CRACK || effect == BLOCK_DUST) && data instanceof BlockData) || (effect == ITEM_CRACK && data instanceof ItemData); + } + + /** + * Determine if the color type for a particle effect is correct + * + * @param effect + * Particle effect + * @param color + * Particle color + * @return Whether the color type is correct or not + */ + private static boolean isColorCorrect(ParticleEffect effect, ParticleColor color) + { + return ((effect == SPELL_MOB || effect == SPELL_MOB_AMBIENT || effect == REDSTONE) && color instanceof OrdinaryColor) || (effect == NOTE && color instanceof NoteColor); + } + + /** + * Displays a particle effect which is only visible for all players within a + * certain range in the world of @param center + * + * @param offsetX + * Maximum distance particles can fly away from the center on the + * x-axis + * @param offsetY + * Maximum distance particles can fly away from the center on the + * y-axis + * @param offsetZ + * Maximum distance particles can fly away from the center on the + * z-axis + * @param speed + * Display speed of the particles + * @param amount + * Amount of particles + * @param center + * Center location of the effect + * @param range + * Range of the visibility + * @throws ParticleVersionException + * If the particle effect is not supported by the server version + * @throws ParticleDataException + * If the particle effect requires additional data + * @throws IllegalArgumentException + * If the particle effect requires water and none is at the center + * location + * @see ParticlePacket + * @see ParticlePacket#sendTo(Location, double) + */ + public void display(float speed, int amount, Location center, double range) throws ParticleVersionException, ParticleDataException, IllegalArgumentException + { + if(!isSupported()) + { + return; + } + + if(hasProperty(ParticleProperty.REQUIRES_DATA)) + { + throw new ParticleDataException("This particle effect requires additional data"); + } + + if(hasProperty(ParticleProperty.REQUIRES_WATER) && !isWater(center)) + { + throw new IllegalArgumentException("There is no water at the center location"); + } + + new ParticlePacket(this, 0, 0, 0, speed, amount, range > 256, null).sendTo(center, range); + } + + /** + * Displays a particle effect which is only visible for the specified players + * + * @param offsetX + * Maximum distance particles can fly away from the center on the + * x-axis + * @param offsetY + * Maximum distance particles can fly away from the center on the + * y-axis + * @param offsetZ + * Maximum distance particles can fly away from the center on the + * z-axis + * @param speed + * Display speed of the particles + * @param amount + * Amount of particles + * @param center + * Center location of the effect + * @param players + * Receivers of the effect + * @throws ParticleVersionException + * If the particle effect is not supported by the server version + * @throws ParticleDataException + * If the particle effect requires additional data + * @throws IllegalArgumentException + * If the particle effect requires water and none is at the center + * location + * @see ParticlePacket + * @see ParticlePacket#sendTo(Location, List) + */ + public void display(float speed, int amount, Location center, List players) throws ParticleVersionException, ParticleDataException, IllegalArgumentException + { + if(!isSupported()) + { + throw new ParticleVersionException("This particle effect is not supported by your server version"); + } + if(hasProperty(ParticleProperty.REQUIRES_DATA)) + { + throw new ParticleDataException("This particle effect requires additional data"); + } + if(hasProperty(ParticleProperty.REQUIRES_WATER) && !isWater(center)) + { + throw new IllegalArgumentException("There is no water at the center location"); + } + new ParticlePacket(this, 0, 0, 0, speed, amount, isLongDistance(center, players), null).sendTo(center, players); + } + + /** + * Displays a particle effect which is only visible for the specified players + * + * @param offsetX + * Maximum distance particles can fly away from the center on the + * x-axis + * @param offsetY + * Maximum distance particles can fly away from the center on the + * y-axis + * @param offsetZ + * Maximum distance particles can fly away from the center on the + * z-axis + * @param speed + * Display speed of the particles + * @param amount + * Amount of particles + * @param center + * Center location of the effect + * @param players + * Receivers of the effect + * @throws ParticleVersionException + * If the particle effect is not supported by the server version + * @throws ParticleDataException + * If the particle effect requires additional data + * @throws IllegalArgumentException + * If the particle effect requires water and none is at the center + * location + * @see #display(float, float, float, float, int, Location, List) + */ + public void display(float speed, int amount, Location center, Player... players) throws ParticleVersionException, ParticleDataException, IllegalArgumentException + { + display(speed, amount, center, Arrays.asList(players)); + } + + /** + * Displays a single particle which flies into a determined direction and is + * only visible for all players within a certain range in the world of @param + * center + * + * @param direction + * Direction of the particle + * @param speed + * Display speed of the particle + * @param center + * Center location of the effect + * @param range + * Range of the visibility + * @throws ParticleVersionException + * If the particle effect is not supported by the server version + * @throws ParticleDataException + * If the particle effect requires additional data + * @throws IllegalArgumentException + * If the particle effect is not directional or if it requires water + * and none is at the center location + * @see ParticlePacket#ParticlePacket(ParticleEffect, Vector, float, boolean, + * ParticleData) + * @see ParticlePacket#sendTo(Location, double) + */ + public void display(Vector direction, float speed, Location center, double range) throws ParticleVersionException, ParticleDataException, IllegalArgumentException + { + if(!isSupported()) + { + throw new ParticleVersionException("This particle effect is not supported by your server version"); + } + if(hasProperty(ParticleProperty.REQUIRES_DATA)) + { + throw new ParticleDataException("This particle effect requires additional data"); + } + if(!hasProperty(ParticleProperty.DIRECTIONAL)) + { + throw new IllegalArgumentException("This particle effect is not directional"); + } + if(hasProperty(ParticleProperty.REQUIRES_WATER) && !isWater(center)) + { + throw new IllegalArgumentException("There is no water at the center location"); + } + new ParticlePacket(this, direction, speed, range > 256, null).sendTo(center, range); + } + + /** + * Displays a single particle which flies into a determined direction and is + * only visible for the specified players + * + * @param direction + * Direction of the particle + * @param speed + * Display speed of the particle + * @param center + * Center location of the effect + * @param players + * Receivers of the effect + * @throws ParticleVersionException + * If the particle effect is not supported by the server version + * @throws ParticleDataException + * If the particle effect requires additional data + * @throws IllegalArgumentException + * If the particle effect is not directional or if it requires water + * and none is at the center location + * @see ParticlePacket#ParticlePacket(ParticleEffect, Vector, float, boolean, + * ParticleData) + * @see ParticlePacket#sendTo(Location, List) + */ + public void display(Vector direction, float speed, Location center, List players) throws ParticleVersionException, ParticleDataException, IllegalArgumentException + { + if(!isSupported()) + { + throw new ParticleVersionException("This particle effect is not supported by your server version"); + } + if(hasProperty(ParticleProperty.REQUIRES_DATA)) + { + throw new ParticleDataException("This particle effect requires additional data"); + } + if(!hasProperty(ParticleProperty.DIRECTIONAL)) + { + throw new IllegalArgumentException("This particle effect is not directional"); + } + if(hasProperty(ParticleProperty.REQUIRES_WATER) && !isWater(center)) + { + throw new IllegalArgumentException("There is no water at the center location"); + } + new ParticlePacket(this, direction, speed, isLongDistance(center, players), null).sendTo(center, players); + } + + /** + * Displays a single particle which flies into a determined direction and is + * only visible for the specified players + * + * @param direction + * Direction of the particle + * @param speed + * Display speed of the particle + * @param center + * Center location of the effect + * @param players + * Receivers of the effect + * @throws ParticleVersionException + * If the particle effect is not supported by the server version + * @throws ParticleDataException + * If the particle effect requires additional data + * @throws IllegalArgumentException + * If the particle effect is not directional or if it requires water + * and none is at the center location + * @see #display(Vector, float, Location, List) + */ + public void display(Vector direction, float speed, Location center, Player... players) throws ParticleVersionException, ParticleDataException, IllegalArgumentException + { + display(direction, speed, center, Arrays.asList(players)); + } + + /** + * Displays a single particle which is colored and only visible for all players + * within a certain range in the world of @param center + * + * @param color + * Color of the particle + * @param center + * Center location of the effect + * @param range + * Range of the visibility + * @throws ParticleVersionException + * If the particle effect is not supported by the server version + * @throws ParticleColorException + * If the particle effect is not colorable or the color type is + * incorrect + * @see ParticlePacket#ParticlePacket(ParticleEffect, ParticleColor, boolean) + * @see ParticlePacket#sendTo(Location, double) + */ + public void display(ParticleColor color, Location center, double range) throws ParticleVersionException, ParticleColorException + { + if(!isSupported()) + { + throw new ParticleVersionException("This particle effect is not supported by your server version"); + } + if(!hasProperty(ParticleProperty.COLORABLE)) + { + throw new ParticleColorException("This particle effect is not colorable"); + } + if(!isColorCorrect(this, color)) + { + throw new ParticleColorException("The particle color type is incorrect"); + } + new ParticlePacket(this, color, range > 256).sendTo(center, range); + } + + /** + * Displays a single particle which is colored and only visible for the + * specified players + * + * @param color + * Color of the particle + * @param center + * Center location of the effect + * @param players + * Receivers of the effect + * @throws ParticleVersionException + * If the particle effect is not supported by the server version + * @throws ParticleColorException + * If the particle effect is not colorable or the color type is + * incorrect + * @see ParticlePacket#ParticlePacket(ParticleEffect, ParticleColor, boolean) + * @see ParticlePacket#sendTo(Location, List) + */ + public void display(ParticleColor color, Location center, List players) throws ParticleVersionException, ParticleColorException + { + if(!isSupported()) + { + throw new ParticleVersionException("This particle effect is not supported by your server version"); + } + if(!hasProperty(ParticleProperty.COLORABLE)) + { + throw new ParticleColorException("This particle effect is not colorable"); + } + if(!isColorCorrect(this, color)) + { + throw new ParticleColorException("The particle color type is incorrect"); + } + new ParticlePacket(this, color, isLongDistance(center, players)).sendTo(center, players); + } + + /** + * Displays a single particle which is colored and only visible for the + * specified players + * + * @param color + * Color of the particle + * @param center + * Center location of the effect + * @param players + * Receivers of the effect + * @throws ParticleVersionException + * If the particle effect is not supported by the server version + * @throws ParticleColorException + * If the particle effect is not colorable or the color type is + * incorrect + * @see #display(ParticleColor, Location, List) + */ + public void display(ParticleColor color, Location center, Player... players) throws ParticleVersionException, ParticleColorException + { + display(color, center, Arrays.asList(players)); + } + + /** + * Displays a particle effect which requires additional data and is only visible + * for all players within a certain range in the world of @param center + * + * @param data + * Data of the effect + * @param offsetX + * Maximum distance particles can fly away from the center on the + * x-axis + * @param offsetY + * Maximum distance particles can fly away from the center on the + * y-axis + * @param offsetZ + * Maximum distance particles can fly away from the center on the + * z-axis + * @param speed + * Display speed of the particles + * @param amount + * Amount of particles + * @param center + * Center location of the effect + * @param range + * Range of the visibility + * @throws ParticleVersionException + * If the particle effect is not supported by the server version + * @throws ParticleDataException + * If the particle effect does not require additional data or if the + * data type is incorrect + * @see ParticlePacket + * @see ParticlePacket#sendTo(Location, double) + */ + public void display(ParticleData data, float speed, int amount, Location center, double range) throws ParticleVersionException, ParticleDataException + { + if(!isSupported()) + { + throw new ParticleVersionException("This particle effect is not supported by your server version"); + } + + if(!hasProperty(ParticleProperty.REQUIRES_DATA)) + { + throw new ParticleDataException("This particle effect does not require additional data"); + } + + if(!isDataCorrect(this, data)) + { + throw new ParticleDataException("The particle data type is incorrect"); + } + + new ParticlePacket(this, 0, 0, 0, speed, amount, range > 256, data).sendTo(center, range); + } + + /** + * Displays a particle effect which requires additional data and is only visible + * for the specified players + * + * @param data + * Data of the effect + * @param offsetX + * Maximum distance particles can fly away from the center on the + * x-axis + * @param offsetY + * Maximum distance particles can fly away from the center on the + * y-axis + * @param offsetZ + * Maximum distance particles can fly away from the center on the + * z-axis + * @param speed + * Display speed of the particles + * @param amount + * Amount of particles + * @param center + * Center location of the effect + * @param players + * Receivers of the effect + * @throws ParticleVersionException + * If the particle effect is not supported by the server version + * @throws ParticleDataException + * If the particle effect does not require additional data or if the + * data type is incorrect + * @see ParticlePacket + * @see ParticlePacket#sendTo(Location, List) + */ + public void display(ParticleData data, float speed, int amount, Location center, List players) throws ParticleVersionException, ParticleDataException + { + if(!isSupported()) + { + throw new ParticleVersionException("This particle effect is not supported by your server version"); + } + if(!hasProperty(ParticleProperty.REQUIRES_DATA)) + { + throw new ParticleDataException("This particle effect does not require additional data"); + } + if(!isDataCorrect(this, data)) + { + throw new ParticleDataException("The particle data type is incorrect"); + } + new ParticlePacket(this, 0, 0, 0, speed, amount, isLongDistance(center, players), data).sendTo(center, players); + } + + /** + * Displays a particle effect which requires additional data and is only visible + * for the specified players + * + * @param data + * Data of the effect + * @param offsetX + * Maximum distance particles can fly away from the center on the + * x-axis + * @param offsetY + * Maximum distance particles can fly away from the center on the + * y-axis + * @param offsetZ + * Maximum distance particles can fly away from the center on the + * z-axis + * @param speed + * Display speed of the particles + * @param amount + * Amount of particles + * @param center + * Center location of the effect + * @param players + * Receivers of the effect + * @throws ParticleVersionException + * If the particle effect is not supported by the server version + * @throws ParticleDataException + * If the particle effect does not require additional data or if the + * data type is incorrect + * @see #display(ParticleData, float, float, float, float, int, Location, List) + */ + public void display(ParticleData data, float speed, int amount, Location center, Player... players) throws ParticleVersionException, ParticleDataException + { + display(data, speed, amount, center, Arrays.asList(players)); + } + + /** + * Displays a single particle which requires additional data that flies into a + * determined direction and is only visible for all players within a certain + * range in the world of @param center + * + * @param data + * Data of the effect + * @param direction + * Direction of the particle + * @param speed + * Display speed of the particles + * @param center + * Center location of the effect + * @param range + * Range of the visibility + * @throws ParticleVersionException + * If the particle effect is not supported by the server version + * @throws ParticleDataException + * If the particle effect does not require additional data or if the + * data type is incorrect + * @see ParticlePacket + * @see ParticlePacket#sendTo(Location, double) + */ + public void display(ParticleData data, Vector direction, float speed, Location center, double range) throws ParticleVersionException, ParticleDataException + { + if(!isSupported()) + { + throw new ParticleVersionException("This particle effect is not supported by your server version"); + } + if(!hasProperty(ParticleProperty.REQUIRES_DATA)) + { + throw new ParticleDataException("This particle effect does not require additional data"); + } + if(!isDataCorrect(this, data)) + { + throw new ParticleDataException("The particle data type is incorrect"); + } + new ParticlePacket(this, direction, speed, range > 256, data).sendTo(center, range); + } + + /** + * Displays a single particle which requires additional data that flies into a + * determined direction and is only visible for the specified players + * + * @param data + * Data of the effect + * @param direction + * Direction of the particle + * @param speed + * Display speed of the particles + * @param center + * Center location of the effect + * @param players + * Receivers of the effect + * @throws ParticleVersionException + * If the particle effect is not supported by the server version + * @throws ParticleDataException + * If the particle effect does not require additional data or if the + * data type is incorrect + * @see ParticlePacket + * @see ParticlePacket#sendTo(Location, List) + */ + public void display(ParticleData data, Vector direction, float speed, Location center, List players) throws ParticleVersionException, ParticleDataException + { + if(!isSupported()) + { + throw new ParticleVersionException("This particle effect is not supported by your server version"); + } + if(!hasProperty(ParticleProperty.REQUIRES_DATA)) + { + throw new ParticleDataException("This particle effect does not require additional data"); + } + if(!isDataCorrect(this, data)) + { + throw new ParticleDataException("The particle data type is incorrect"); + } + new ParticlePacket(this, direction, speed, isLongDistance(center, players), data).sendTo(center, players); + } + + /** + * Displays a single particle which requires additional data that flies into a + * determined direction and is only visible for the specified players + * + * @param data + * Data of the effect + * @param direction + * Direction of the particle + * @param speed + * Display speed of the particles + * @param center + * Center location of the effect + * @param players + * Receivers of the effect + * @throws ParticleVersionException + * If the particle effect is not supported by the server version + * @throws ParticleDataException + * If the particle effect does not require additional data or if the + * data type is incorrect + * @see #display(ParticleData, Vector, float, Location, List) + */ + public void display(ParticleData data, Vector direction, float speed, Location center, Player... players) throws ParticleVersionException, ParticleDataException + { + display(data, direction, speed, center, Arrays.asList(players)); + } + + /** + * Represents the property of a particle effect + *

+ * This class is part of the ParticleEffect Library and follows the same + * usage conditions + * + * @author DarkBlade12 + * @since 1.7 + */ + public static enum ParticleProperty + { + /** + * The particle effect requires water to be displayed + */ + REQUIRES_WATER, + /** + * The particle effect requires block or item data to be displayed + */ + REQUIRES_DATA, + /** + * The particle effect uses the offsets as direction values + */ + DIRECTIONAL, + /** + * The particle effect uses the offsets as color values + */ + COLORABLE; + } + + /** + * Represents the particle data for effects like + * {@link ParticleEffect#ITEM_CRACK}, {@link ParticleEffect#BLOCK_CRACK} and + * {@link ParticleEffect#BLOCK_DUST} + *

+ * This class is part of the ParticleEffect Library and follows the same + * usage conditions + * + * @author DarkBlade12 + * @since 1.6 + */ + public static abstract class ParticleData + { + private final Material material; + private final byte data; + private final int[] packetData; + + /** + * Construct a new particle data + * + * @param material + * Material of the item/block + * @param data + * Data value of the item/block + */ + @SuppressWarnings("deprecation") + public ParticleData(Material material, byte data) + { + this.material = material; + this.data = data; + this.packetData = new int[] {material.getId(), data}; + } + + /** + * Returns the material of this data + * + * @return The material + */ + public Material getMaterial() + { + return material; + } + + /** + * Returns the data value of this data + * + * @return The data value + */ + public byte getData() + { + return data; + } + + /** + * Returns the data as an int array for packet construction + * + * @return The data for the packet + */ + public int[] getPacketData() + { + return packetData; + } + + /** + * Returns the data as a string for pre 1.8 versions + * + * @return The data string for the packet + */ + public String getPacketDataString() + { + return "_" + packetData[0] + "_" + packetData[1]; + } + } + + /** + * Represents the item data for the {@link ParticleEffect#ITEM_CRACK} effect + *

+ * This class is part of the ParticleEffect Library and follows the same + * usage conditions + * + * @author DarkBlade12 + * @since 1.6 + */ + public static final class ItemData extends ParticleData + { + /** + * Construct a new item data + * + * @param material + * Material of the item + * @param data + * Data value of the item + * @see ParticleData#ParticleData(Material, byte) + */ + public ItemData(Material material, byte data) + { + super(material, data); + } + } + + /** + * Represents the block data for the {@link ParticleEffect#BLOCK_CRACK} and + * {@link ParticleEffect#BLOCK_DUST} effects + *

+ * This class is part of the ParticleEffect Library and follows the same + * usage conditions + * + * @author DarkBlade12 + * @since 1.6 + */ + public static final class BlockData extends ParticleData + { + /** + * Construct a new block data + * + * @param material + * Material of the block + * @param data + * Data value of the block + * @throws IllegalArgumentException + * If the material is not a block + * @see ParticleData#ParticleData(Material, byte) + */ + public BlockData(Material material, byte data) throws IllegalArgumentException + { + super(material, data); + if(!material.isBlock()) + { + throw new IllegalArgumentException("The material is not a block"); + } + } + } + + /** + * Represents the color for effects like {@link ParticleEffect#SPELL_MOB}, + * {@link ParticleEffect#SPELL_MOB_AMBIENT}, {@link ParticleEffect#REDSTONE} and + * {@link ParticleEffect#NOTE} + *

+ * This class is part of the ParticleEffect Library and follows the same + * usage conditions + * + * @author DarkBlade12 + * @since 1.7 + */ + public static abstract class ParticleColor + { + /** + * Returns the value for the offsetX field + * + * @return The offsetX value + */ + public abstract float getValueX(); + + /** + * Returns the value for the offsetY field + * + * @return The offsetY value + */ + public abstract float getValueY(); + + /** + * Returns the value for the offsetZ field + * + * @return The offsetZ value + */ + public abstract float getValueZ(); + } + + /** + * Represents the color for effects like {@link ParticleEffect#SPELL_MOB}, + * {@link ParticleEffect#SPELL_MOB_AMBIENT} and {@link ParticleEffect#NOTE} + *

+ * This class is part of the ParticleEffect Library and follows the same + * usage conditions + * + * @author DarkBlade12 + * @since 1.7 + */ + public static final class OrdinaryColor extends ParticleColor + { + private final int red; + private final int green; + private final int blue; + + /** + * Construct a new ordinary color + * + * @param red + * Red value of the RGB format + * @param green + * Green value of the RGB format + * @param blue + * Blue value of the RGB format + * @throws IllegalArgumentException + * If one of the values is lower than 0 or higher than 255 + */ + public OrdinaryColor(int red, int green, int blue) throws IllegalArgumentException + { + if(red < 0) + { + throw new IllegalArgumentException("The red value is lower than 0"); + } + if(red > 255) + { + throw new IllegalArgumentException("The red value is higher than 255"); + } + this.red = red; + if(green < 0) + { + throw new IllegalArgumentException("The green value is lower than 0"); + } + if(green > 255) + { + throw new IllegalArgumentException("The green value is higher than 255"); + } + this.green = green; + if(blue < 0) + { + throw new IllegalArgumentException("The blue value is lower than 0"); + } + if(blue > 255) + { + throw new IllegalArgumentException("The blue value is higher than 255"); + } + this.blue = blue; + } + + /** + * Construct a new ordinary color + * + * @param color + * Bukkit color + */ + public OrdinaryColor(Color color) + { + this(color.getRed(), color.getGreen(), color.getBlue()); + } + + /** + * Returns the red value of the RGB format + * + * @return The red value + */ + public int getRed() + { + return red; + } + + /** + * Returns the green value of the RGB format + * + * @return The green value + */ + public int getGreen() + { + return green; + } + + /** + * Returns the blue value of the RGB format + * + * @return The blue value + */ + public int getBlue() + { + return blue; + } + + /** + * Returns the red value divided by 255 + * + * @return The offsetX value + */ + @Override + public float getValueX() + { + return (float) red / 255F; + } + + /** + * Returns the green value divided by 255 + * + * @return The offsetY value + */ + @Override + public float getValueY() + { + return (float) green / 255F; + } + + /** + * Returns the blue value divided by 255 + * + * @return The offsetZ value + */ + @Override + public float getValueZ() + { + return (float) blue / 255F; + } + } + + /** + * Represents the color for the {@link ParticleEffect#NOTE} effect + *

+ * This class is part of the ParticleEffect Library and follows the same + * usage conditions + * + * @author DarkBlade12 + * @since 1.7 + */ + public static final class NoteColor extends ParticleColor + { + private final int note; + + /** + * Construct a new note color + * + * @param note + * Note id which determines color + * @throws IllegalArgumentException + * If the note value is lower than 0 or higher than 24 + */ + public NoteColor(int note) throws IllegalArgumentException + { + if(note < 0) + { + throw new IllegalArgumentException("The note value is lower than 0"); + } + if(note > 24) + { + throw new IllegalArgumentException("The note value is higher than 24"); + } + this.note = note; + } + + /** + * Returns the note value divided by 24 + * + * @return The offsetX value + */ + @Override + public float getValueX() + { + return (float) note / 24F; + } + + /** + * Returns zero because the offsetY value is unused + * + * @return zero + */ + @Override + public float getValueY() + { + return 0; + } + + /** + * Returns zero because the offsetZ value is unused + * + * @return zero + */ + @Override + public float getValueZ() + { + return 0; + } + + } + + /** + * Represents a runtime exception that is thrown either if the displayed + * particle effect requires data and has none or vice-versa or if the data type + * is incorrect + *

+ * This class is part of the ParticleEffect Library and follows the same + * usage conditions + * + * @author DarkBlade12 + * @since 1.6 + */ + private static final class ParticleDataException extends RuntimeException + { + private static final long serialVersionUID = 3203085387160737484L; + + /** + * Construct a new particle data exception + * + * @param message + * Message that will be logged + */ + public ParticleDataException(String message) + { + super(message); + } + } + + /** + * Represents a runtime exception that is thrown either if the displayed + * particle effect is not colorable or if the particle color type is incorrect + *

+ * This class is part of the ParticleEffect Library and follows the same + * usage conditions + * + * @author DarkBlade12 + * @since 1.7 + */ + private static final class ParticleColorException extends RuntimeException + { + private static final long serialVersionUID = 3203085387160737484L; + + /** + * Construct a new particle color exception + * + * @param message + * Message that will be logged + */ + public ParticleColorException(String message) + { + super(message); + } + } + + /** + * Represents a runtime exception that is thrown if the displayed particle + * effect requires a newer version + *

+ * This class is part of the ParticleEffect Library and follows the same + * usage conditions + * + * @author DarkBlade12 + * @since 1.6 + */ + private static final class ParticleVersionException extends RuntimeException + { + private static final long serialVersionUID = 3203085387160737484L; + + /** + * Construct a new particle version exception + * + * @param message + * Message that will be logged + */ + public ParticleVersionException(String message) + { + super(message); + } + } + + /** + * Represents a particle effect packet with all attributes which is used for + * sending packets to the players + *

+ * This class is part of the ParticleEffect Library and follows the same + * usage conditions + * + * @author DarkBlade12 + * @since 1.5 + */ + public static final class ParticlePacket + { + private static int version; + private static Class enumParticle; + private static Constructor packetConstructor; + private static Method getHandle; + private static Field playerConnection; + private static Method sendPacket; + private static boolean initialized; + private final ParticleEffect effect; + private float offsetX; + private final float offsetY; + private final float offsetZ; + private final float speed; + private final int amount; + private final boolean longDistance; + private final ParticleData data; + private Object packet; + + /** + * Construct a new particle packet + * + * @param effect + * Particle effect + * @param offsetX + * Maximum distance particles can fly away from the center on the + * x-axis + * @param offsetY + * Maximum distance particles can fly away from the center on the + * y-axis + * @param offsetZ + * Maximum distance particles can fly away from the center on the + * z-axis + * @param speed + * Display speed of the particles + * @param amount + * Amount of particles + * @param longDistance + * Indicates whether the maximum distance is increased from 256 to + * 65536 + * @param data + * Data of the effect + * @throws IllegalArgumentException + * If the speed or amount is lower than 0 + * @see #initialize() + */ + public ParticlePacket(ParticleEffect effect, float offsetX, float offsetY, float offsetZ, float speed, int amount, boolean longDistance, ParticleData data) throws IllegalArgumentException + { + initialize(); + if(speed < 0) + { + throw new IllegalArgumentException("The speed is lower than 0"); + } + if(amount < 0) + { + throw new IllegalArgumentException("The amount is lower than 0"); + } + this.effect = effect; + this.offsetX = offsetX; + this.offsetY = offsetY; + this.offsetZ = offsetZ; + this.speed = speed; + this.amount = amount; + this.longDistance = longDistance; + this.data = data; + } + + /** + * Construct a new particle packet of a single particle flying into a determined + * direction + * + * @param effect + * Particle effect + * @param direction + * Direction of the particle + * @param speed + * Display speed of the particle + * @param longDistance + * Indicates whether the maximum distance is increased from 256 to + * 65536 + * @param data + * Data of the effect + * @throws IllegalArgumentException + * If the speed is lower than 0 + * @see #ParticleEffect(ParticleEffect, float, float, float, float, int, + * boolean, ParticleData) + */ + public ParticlePacket(ParticleEffect effect, Vector direction, float speed, boolean longDistance, ParticleData data) throws IllegalArgumentException + { + this(effect, (float) direction.getX(), (float) direction.getY(), (float) direction.getZ(), speed, 0, longDistance, data); + } + + /** + * Construct a new particle packet of a single colored particle + * + * @param effect + * Particle effect + * @param color + * Color of the particle + * @param longDistance + * Indicates whether the maximum distance is increased from 256 to + * 65536 + * @see #ParticleEffect(ParticleEffect, float, float, float, float, int, + * boolean, ParticleData) + */ + public ParticlePacket(ParticleEffect effect, ParticleColor color, boolean longDistance) + { + this(effect, color.getValueX(), color.getValueY(), color.getValueZ(), 1, 0, longDistance, null); + if(effect == ParticleEffect.REDSTONE && color instanceof OrdinaryColor && ((OrdinaryColor) color).getRed() == 0) + { + offsetX = Float.MIN_NORMAL; + } + } + + /** + * Initializes {@link #packetConstructor}, {@link #getHandle}, + * {@link #playerConnection} and {@link #sendPacket} and sets + * {@link #initialized} to true if it succeeds + *

+ * Note: These fields only have to be initialized once, so it will return + * if {@link #initialized} is already set to true + * + * @throws VersionIncompatibleException + * if your bukkit version is not supported by this library + */ + public static void initialize() throws VersionIncompatibleException + { + if(initialized) + { + return; + } + + try + { + String ver = PackageType.getServerVersion(); + int un1 = ver.indexOf("_") + 1; + int un2 = ver.lastIndexOf("_"); + + version = Integer.parseInt(ver.substring(un1, un2)); + + if(version > 7) + { + enumParticle = PackageType.MINECRAFT_SERVER.getClass("EnumParticle"); + } + + Class packetClass = PackageType.MINECRAFT_SERVER.getClass(version < 7 ? "Packet63WorldParticles" : "PacketPlayOutWorldParticles"); + + packetConstructor = ReflectionUtils.getConstructor(packetClass); + getHandle = ReflectionUtils.getMethod("CraftPlayer", PackageType.CRAFTBUKKIT_ENTITY, "getHandle"); + playerConnection = ReflectionUtils.getField("EntityPlayer", PackageType.MINECRAFT_SERVER, false, "playerConnection"); + sendPacket = ReflectionUtils.getMethod(playerConnection.getType(), "sendPacket", PackageType.MINECRAFT_SERVER.getClass("Packet")); + } + + catch(Exception exception) + { + + } + + initialized = true; + + if(initialized) + { + return; + } + } + + /** + * Returns the version of your server (1.x) + * + * @return The version number + */ + public static int getVersion() + { + if(!initialized) + { + initialize(); + } + return version; + } + + /** + * Determine if {@link #packetConstructor}, {@link #getHandle}, + * {@link #playerConnection} and {@link #sendPacket} are initialized + * + * @return Whether these fields are initialized or not + * @see #initialize() + */ + public static boolean isInitialized() + { + return initialized; + } + + /** + * Initializes {@link #packet} with all set values + * + * @param center + * Center location of the effect + * @throws PacketInstantiationException + * If instantion fails due to an unknown error + */ + private void initializePacket(Location center) throws PacketInstantiationException + { + if(packet != null) + { + return; + } + try + { + packet = packetConstructor.newInstance(); + + if(version < 8) + { + String name = effect.getName(); + if(data != null) + { + name += data.getPacketDataString(); + } + ReflectionUtils.setValue(packet, true, "a", name); + } + else + { + ReflectionUtils.setValue(packet, true, "a", enumParticle.getEnumConstants()[effect.getId()]); + ReflectionUtils.setValue(packet, true, "j", longDistance); + if(data != null) + { + int[] packetData = data.getPacketData(); + ReflectionUtils.setValue(packet, true, "k", effect == ParticleEffect.ITEM_CRACK ? packetData : new int[] {packetData[0] | (packetData[1] << 12)}); + } + } + ReflectionUtils.setValue(packet, true, "b", (float) center.getX()); + ReflectionUtils.setValue(packet, true, "c", (float) center.getY()); + ReflectionUtils.setValue(packet, true, "d", (float) center.getZ()); + ReflectionUtils.setValue(packet, true, "e", offsetX); + ReflectionUtils.setValue(packet, true, "f", offsetY); + ReflectionUtils.setValue(packet, true, "g", offsetZ); + ReflectionUtils.setValue(packet, true, "h", speed); + ReflectionUtils.setValue(packet, true, "i", amount); + } + + catch(Exception exception) + { + + } + } + + /** + * Sends the packet to a single player and caches it + * + * @param center + * Center location of the effect + * @param player + * Receiver of the packet + * @throws PacketInstantiationException + * If instantion fails due to an unknown error + * @throws PacketSendingException + * If sending fails due to an unknown error + * @see #initializePacket(Location) + */ + public void sendTo(Location center, Player player) throws PacketInstantiationException, PacketSendingException + { + initializePacket(center); + try + { + sendPacket.invoke(playerConnection.get(getHandle.invoke(player)), packet); + } + + catch(Exception exception) + { + } + } + + /** + * Sends the packet to all players in the list + * + * @param center + * Center location of the effect + * @param players + * Receivers of the packet + * @throws IllegalArgumentException + * If the player list is empty + * @see #sendTo(Location center, Player player) + */ + public void sendTo(Location center, List players) throws IllegalArgumentException + { + if(players.isEmpty()) + { + throw new IllegalArgumentException("The player list is empty"); + } + for(Player player : players) + { + sendTo(center, player); + } + } + + /** + * Sends the packet to all players in a certain range + * + * @param center + * Center location of the effect + * @param range + * Range in which players will receive the packet (Maximum range for + * particles is usually 16, but it can differ for some types) + * @throws IllegalArgumentException + * If the range is lower than 1 + * @see #sendTo(Location center, Player player) + */ + public void sendTo(Location center, double range) throws IllegalArgumentException + { + if(range < 1) + { + throw new IllegalArgumentException("The range is lower than 1"); + } + String worldName = center.getWorld().getName(); + double squared = range * range; + for(Player player : Bukkit.getOnlinePlayers()) + { + if(!player.getWorld().getName().equals(worldName) || player.getLocation().distanceSquared(center) > squared) + { + continue; + } + sendTo(center, player); + } + } + + /** + * Represents a runtime exception that is thrown if a bukkit version is not + * compatible with this library + *

+ * This class is part of the ParticleEffect Library and follows the same + * usage conditions + * + * @author DarkBlade12 + * @since 1.5 + */ + private static final class VersionIncompatibleException extends RuntimeException + { + private static final long serialVersionUID = 3203085387160737484L; + + /** + * Construct a new version incompatible exception + * + * @param message + * Message that will be logged + * @param cause + * Cause of the exception + */ + public VersionIncompatibleException(String message, Throwable cause) + { + super(message, cause); + } + } + + /** + * Represents a runtime exception that is thrown if packet instantiation fails + *

+ * This class is part of the ParticleEffect Library and follows the same + * usage conditions + * + * @author DarkBlade12 + * @since 1.4 + */ + private static final class PacketInstantiationException extends RuntimeException + { + private static final long serialVersionUID = 3203085387160737484L; + + /** + * Construct a new packet instantiation exception + * + * @param message + * Message that will be logged + * @param cause + * Cause of the exception + */ + public PacketInstantiationException(String message, Throwable cause) + { + super(message, cause); + } + } + + /** + * Represents a runtime exception that is thrown if packet sending fails + *

+ * This class is part of the ParticleEffect Library and follows the same + * usage conditions + * + * @author DarkBlade12 + * @since 1.4 + */ + private static final class PacketSendingException extends RuntimeException + { + private static final long serialVersionUID = 3203085387160737484L; + + /** + * Construct a new packet sending exception + * + * @param message + * Message that will be logged + * @param cause + * Cause of the exception + */ + public PacketSendingException(String message, Throwable cause) + { + super(message, cause); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/ninja/bytecode/iris/util/ParticleRedstone.java b/src/main/java/ninja/bytecode/iris/util/ParticleRedstone.java new file mode 100644 index 000000000..369b0fb7c --- /dev/null +++ b/src/main/java/ninja/bytecode/iris/util/ParticleRedstone.java @@ -0,0 +1,56 @@ +package ninja.bytecode.iris.util; + +import java.awt.Color; + +import org.bukkit.Location; +import org.bukkit.entity.Player; + +import ninja.bytecode.iris.util.ParticleEffect.OrdinaryColor; + +public class ParticleRedstone extends ParticleBase implements ColoredEffect +{ + private Color color; + private float size; + + public ParticleRedstone() + { + this.color = Color.WHITE; + size = 1f; + } + + @Override + public void play(Location l, double range) + { + ParticleEffect.REDSTONE.display(new OrdinaryColor(getColor().getRed(), getColor().getGreen(), getColor().getBlue()), l , range); + } + + @Override + public void play(Location l, Player p) + { + ParticleEffect.REDSTONE.display(new OrdinaryColor(getColor().getRed(), getColor().getGreen(), getColor().getBlue()), l , p); + } + + @Override + public ParticleRedstone setColor(Color color) + { + this.color = color; + return this; + } + + @Override + public Color getColor() + { + return color; + } + + public ParticleRedstone setSize(float size) + { + this.size = size; + return this; + } + + public float getSize() + { + return size; + } +} diff --git a/src/main/java/ninja/bytecode/iris/util/ReflectionUtils.java b/src/main/java/ninja/bytecode/iris/util/ReflectionUtils.java new file mode 100644 index 000000000..8df919aea --- /dev/null +++ b/src/main/java/ninja/bytecode/iris/util/ReflectionUtils.java @@ -0,0 +1,822 @@ +package ninja.bytecode.iris.util; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +import org.bukkit.Bukkit; + +/** + * ReflectionUtils + *

+ * This class provides useful methods which makes dealing with reflection much + * easier, especially when working with Bukkit + *

+ * You are welcome to use it, modify it and redistribute it under the following + * conditions: + *

    + *
  • Don't claim this class as your own + *
  • Don't remove this disclaimer + *
+ *

+ * It would be nice if you provide credit to me if you use this class in a + * published project + * + * @author DarkBlade12 + * @version 1.1 + */ +public final class ReflectionUtils +{ + // Prevent accidental construction + private ReflectionUtils() + { + + } + + /** + * Returns the constructor of a given class with the given parameter types + * + * @param clazz + * Target class + * @param parameterTypes + * Parameter types of the desired constructor + * @return The constructor of the target class with the specified parameter + * types + * @throws NoSuchMethodException + * If the desired constructor with the specified parameter types + * cannot be found + * @see DataType + * @see DataType#getPrimitive(Class[]) + * @see DataType#compare(Class[], Class[]) + */ + public static Constructor getConstructor(Class clazz, Class... parameterTypes) throws NoSuchMethodException + { + Class[] primitiveTypes = DataType.getPrimitive(parameterTypes); + for(Constructor constructor : clazz.getConstructors()) + { + if(!DataType.compare(DataType.getPrimitive(constructor.getParameterTypes()), primitiveTypes)) + { + continue; + } + return constructor; + } + throw new NoSuchMethodException("There is no such constructor in this class with the specified parameter types"); + } + + /** + * Returns the constructor of a desired class with the given parameter types + * + * @param className + * Name of the desired target class + * @param packageType + * Package where the desired target class is located + * @param parameterTypes + * Parameter types of the desired constructor + * @return The constructor of the desired target class with the specified + * parameter types + * @throws NoSuchMethodException + * If the desired constructor with the specified parameter types + * cannot be found + * @throws ClassNotFoundException + * ClassNotFoundException If the desired target class with the + * specified name and package cannot be found + * @see #getConstructor(Class, Class...) + */ + public static Constructor getConstructor(String className, PackageType packageType, Class... parameterTypes) throws NoSuchMethodException, ClassNotFoundException + { + return getConstructor(packageType.getClass(className), parameterTypes); + } + + /** + * Returns an instance of a class with the given arguments + * + * @param clazz + * Target class + * @param arguments + * Arguments which are used to construct an object of the target + * class + * @return The instance of the target class with the specified arguments + * @throws InstantiationException + * If you cannot create an instance of the target class due to + * certain circumstances + * @throws IllegalAccessException + * If the desired constructor cannot be accessed due to certain + * circumstances + * @throws IllegalArgumentException + * If the types of the arguments do not match the parameter + * types of the constructor (this should not occur since it + * searches for a constructor with the types of the arguments) + * @throws InvocationTargetException + * If the desired constructor cannot be invoked + * @throws NoSuchMethodException + * If the desired constructor with the specified arguments + * cannot be found + */ + public static Object instantiateObject(Class clazz, Object... arguments) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException + { + return getConstructor(clazz, DataType.getPrimitive(arguments)).newInstance(arguments); + } + + /** + * Returns an instance of a desired class with the given arguments + * + * @param className + * Name of the desired target class + * @param packageType + * Package where the desired target class is located + * @param arguments + * Arguments which are used to construct an object of the desired + * target class + * @return The instance of the desired target class with the specified + * arguments + * @throws InstantiationException + * If you cannot create an instance of the desired target class + * due to certain circumstances + * @throws IllegalAccessException + * If the desired constructor cannot be accessed due to certain + * circumstances + * @throws IllegalArgumentException + * If the types of the arguments do not match the parameter + * types of the constructor (this should not occur since it + * searches for a constructor with the types of the arguments) + * @throws InvocationTargetException + * If the desired constructor cannot be invoked + * @throws NoSuchMethodException + * If the desired constructor with the specified arguments + * cannot be found + * @throws ClassNotFoundException + * If the desired target class with the specified name and + * package cannot be found + * @see #instantiateObject(Class, Object...) + */ + public static Object instantiateObject(String className, PackageType packageType, Object... arguments) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, ClassNotFoundException + { + return instantiateObject(packageType.getClass(className), arguments); + } + + /** + * Returns a method of a class with the given parameter types + * + * @param clazz + * Target class + * @param methodName + * Name of the desired method + * @param parameterTypes + * Parameter types of the desired method + * @return The method of the target class with the specified name and + * parameter types + * @throws NoSuchMethodException + * If the desired method of the target class with the specified + * name and parameter types cannot be found + * @see DataType#getPrimitive(Class[]) + * @see DataType#compare(Class[], Class[]) + */ + public static Method getMethod(Class clazz, String methodName, Class... parameterTypes) throws NoSuchMethodException + { + Class[] primitiveTypes = DataType.getPrimitive(parameterTypes); + for(Method method : clazz.getMethods()) + { + if(!method.getName().equals(methodName) || !DataType.compare(DataType.getPrimitive(method.getParameterTypes()), primitiveTypes)) + { + continue; + } + return method; + } + throw new NoSuchMethodException("There is no such method in this class with the specified name and parameter types"); + } + + /** + * Returns a method of a desired class with the given parameter types + * + * @param className + * Name of the desired target class + * @param packageType + * Package where the desired target class is located + * @param methodName + * Name of the desired method + * @param parameterTypes + * Parameter types of the desired method + * @return The method of the desired target class with the specified name + * and parameter types + * @throws NoSuchMethodException + * If the desired method of the desired target class with the + * specified name and parameter types cannot be found + * @throws ClassNotFoundException + * If the desired target class with the specified name and + * package cannot be found + * @see #getMethod(Class, String, Class...) + */ + public static Method getMethod(String className, PackageType packageType, String methodName, Class... parameterTypes) throws NoSuchMethodException, ClassNotFoundException + { + return getMethod(packageType.getClass(className), methodName, parameterTypes); + } + + /** + * Invokes a method on an object with the given arguments + * + * @param instance + * Target object + * @param methodName + * Name of the desired method + * @param arguments + * Arguments which are used to invoke the desired method + * @return The result of invoking the desired method on the target object + * @throws IllegalAccessException + * If the desired method cannot be accessed due to certain + * circumstances + * @throws IllegalArgumentException + * If the types of the arguments do not match the parameter + * types of the method (this should not occur since it searches + * for a method with the types of the arguments) + * @throws InvocationTargetException + * If the desired method cannot be invoked on the target object + * @throws NoSuchMethodException + * If the desired method of the class of the target object with + * the specified name and arguments cannot be found + * @see #getMethod(Class, String, Class...) + * @see DataType#getPrimitive(Object[]) + */ + public static Object invokeMethod(Object instance, String methodName, Object... arguments) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException + { + return getMethod(instance.getClass(), methodName, DataType.getPrimitive(arguments)).invoke(instance, arguments); + } + + /** + * Invokes a method of the target class on an object with the given + * arguments + * + * @param instance + * Target object + * @param clazz + * Target class + * @param methodName + * Name of the desired method + * @param arguments + * Arguments which are used to invoke the desired method + * @return The result of invoking the desired method on the target object + * @throws IllegalAccessException + * If the desired method cannot be accessed due to certain + * circumstances + * @throws IllegalArgumentException + * If the types of the arguments do not match the parameter + * types of the method (this should not occur since it searches + * for a method with the types of the arguments) + * @throws InvocationTargetException + * If the desired method cannot be invoked on the target object + * @throws NoSuchMethodException + * If the desired method of the target class with the specified + * name and arguments cannot be found + * @see #getMethod(Class, String, Class...) + * @see DataType#getPrimitive(Object[]) + */ + public static Object invokeMethod(Object instance, Class clazz, String methodName, Object... arguments) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException + { + return getMethod(clazz, methodName, DataType.getPrimitive(arguments)).invoke(instance, arguments); + } + + /** + * Invokes a method of a desired class on an object with the given arguments + * + * @param instance + * Target object + * @param className + * Name of the desired target class + * @param packageType + * Package where the desired target class is located + * @param methodName + * Name of the desired method + * @param arguments + * Arguments which are used to invoke the desired method + * @return The result of invoking the desired method on the target object + * @throws IllegalAccessException + * If the desired method cannot be accessed due to certain + * circumstances + * @throws IllegalArgumentException + * If the types of the arguments do not match the parameter + * types of the method (this should not occur since it searches + * for a method with the types of the arguments) + * @throws InvocationTargetException + * If the desired method cannot be invoked on the target object + * @throws NoSuchMethodException + * If the desired method of the desired target class with the + * specified name and arguments cannot be found + * @throws ClassNotFoundException + * If the desired target class with the specified name and + * package cannot be found + * @see #invokeMethod(Object, Class, String, Object...) + */ + public static Object invokeMethod(Object instance, String className, PackageType packageType, String methodName, Object... arguments) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, ClassNotFoundException + { + return invokeMethod(instance, packageType.getClass(className), methodName, arguments); + } + + /** + * Returns a field of the target class with the given name + * + * @param clazz + * Target class + * @param declared + * Whether the desired field is declared or not + * @param fieldName + * Name of the desired field + * @return The field of the target class with the specified name + * @throws NoSuchFieldException + * If the desired field of the given class cannot be found + * @throws SecurityException + * If the desired field cannot be made accessible + */ + public static Field getField(Class clazz, boolean declared, String fieldName) throws NoSuchFieldException, SecurityException + { + Field field = declared ? clazz.getDeclaredField(fieldName) : clazz.getField(fieldName); + field.setAccessible(true); + return field; + } + + /** + * Returns a field of a desired class with the given name + * + * @param className + * Name of the desired target class + * @param packageType + * Package where the desired target class is located + * @param declared + * Whether the desired field is declared or not + * @param fieldName + * Name of the desired field + * @return The field of the desired target class with the specified name + * @throws NoSuchFieldException + * If the desired field of the desired class cannot be found + * @throws SecurityException + * If the desired field cannot be made accessible + * @throws ClassNotFoundException + * If the desired target class with the specified name and + * package cannot be found + * @see #getField(Class, boolean, String) + */ + public static Field getField(String className, PackageType packageType, boolean declared, String fieldName) throws NoSuchFieldException, SecurityException, ClassNotFoundException + { + return getField(packageType.getClass(className), declared, fieldName); + } + + /** + * Returns the value of a field of the given class of an object + * + * @param instance + * Target object + * @param clazz + * Target class + * @param declared + * Whether the desired field is declared or not + * @param fieldName + * Name of the desired field + * @return The value of field of the target object + * @throws IllegalArgumentException + * If the target object does not feature the desired field + * @throws IllegalAccessException + * If the desired field cannot be accessed + * @throws NoSuchFieldException + * If the desired field of the target class cannot be found + * @throws SecurityException + * If the desired field cannot be made accessible + * @see #getField(Class, boolean, String) + */ + public static Object getValue(Object instance, Class clazz, boolean declared, String fieldName) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException + { + return getField(clazz, declared, fieldName).get(instance); + } + + /** + * Returns the value of a field of a desired class of an object + * + * @param instance + * Target object + * @param className + * Name of the desired target class + * @param packageType + * Package where the desired target class is located + * @param declared + * Whether the desired field is declared or not + * @param fieldName + * Name of the desired field + * @return The value of field of the target object + * @throws IllegalArgumentException + * If the target object does not feature the desired field + * @throws IllegalAccessException + * If the desired field cannot be accessed + * @throws NoSuchFieldException + * If the desired field of the desired class cannot be found + * @throws SecurityException + * If the desired field cannot be made accessible + * @throws ClassNotFoundException + * If the desired target class with the specified name and + * package cannot be found + * @see #getValue(Object, Class, boolean, String) + */ + public static Object getValue(Object instance, String className, PackageType packageType, boolean declared, String fieldName) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException, ClassNotFoundException + { + return getValue(instance, packageType.getClass(className), declared, fieldName); + } + + /** + * Returns the value of a field with the given name of an object + * + * @param instance + * Target object + * @param declared + * Whether the desired field is declared or not + * @param fieldName + * Name of the desired field + * @return The value of field of the target object + * @throws IllegalArgumentException + * If the target object does not feature the desired field + * (should not occur since it searches for a field with the + * given name in the class of the object) + * @throws IllegalAccessException + * If the desired field cannot be accessed + * @throws NoSuchFieldException + * If the desired field of the target object cannot be found + * @throws SecurityException + * If the desired field cannot be made accessible + * @see #getValue(Object, Class, boolean, String) + */ + public static Object getValue(Object instance, boolean declared, String fieldName) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException + { + return getValue(instance, instance.getClass(), declared, fieldName); + } + + /** + * Sets the value of a field of the given class of an object + * + * @param instance + * Target object + * @param clazz + * Target class + * @param declared + * Whether the desired field is declared or not + * @param fieldName + * Name of the desired field + * @param value + * New value + * @throws IllegalArgumentException + * If the type of the value does not match the type of the + * desired field + * @throws IllegalAccessException + * If the desired field cannot be accessed + * @throws NoSuchFieldException + * If the desired field of the target class cannot be found + * @throws SecurityException + * If the desired field cannot be made accessible + * @see #getField(Class, boolean, String) + */ + public static void setValue(Object instance, Class clazz, boolean declared, String fieldName, Object value) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException + { + getField(clazz, declared, fieldName).set(instance, value); + } + + /** + * Sets the value of a field of a desired class of an object + * + * @param instance + * Target object + * @param className + * Name of the desired target class + * @param packageType + * Package where the desired target class is located + * @param declared + * Whether the desired field is declared or not + * @param fieldName + * Name of the desired field + * @param value + * New value + * @throws IllegalArgumentException + * If the type of the value does not match the type of the + * desired field + * @throws IllegalAccessException + * If the desired field cannot be accessed + * @throws NoSuchFieldException + * If the desired field of the desired class cannot be found + * @throws SecurityException + * If the desired field cannot be made accessible + * @throws ClassNotFoundException + * If the desired target class with the specified name and + * package cannot be found + * @see #setValue(Object, Class, boolean, String, Object) + */ + public static void setValue(Object instance, String className, PackageType packageType, boolean declared, String fieldName, Object value) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException, ClassNotFoundException + { + setValue(instance, packageType.getClass(className), declared, fieldName, value); + } + + /** + * Sets the value of a field with the given name of an object + * + * @param instance + * Target object + * @param declared + * Whether the desired field is declared or not + * @param fieldName + * Name of the desired field + * @param value + * New value + * @throws IllegalArgumentException + * If the type of the value does not match the type of the + * desired field + * @throws IllegalAccessException + * If the desired field cannot be accessed + * @throws NoSuchFieldException + * If the desired field of the target object cannot be found + * @throws SecurityException + * If the desired field cannot be made accessible + * @see #setValue(Object, Class, boolean, String, Object) + */ + public static void setValue(Object instance, boolean declared, String fieldName, Object value) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException + { + setValue(instance, instance.getClass(), declared, fieldName, value); + } + + /** + * Represents an enumeration of dynamic packages of NMS and CraftBukkit + *

+ * This class is part of the ReflectionUtils and follows the same + * usage conditions + * + * @author DarkBlade12 + * @since 1.0 + */ + public enum PackageType + { + MINECRAFT_SERVER("net.minecraft.server." + getServerVersion()), CRAFTBUKKIT("org.bukkit.craftbukkit." + getServerVersion()), CRAFTBUKKIT_BLOCK(CRAFTBUKKIT, "block"), CRAFTBUKKIT_CHUNKIO(CRAFTBUKKIT, "chunkio"), CRAFTBUKKIT_COMMAND(CRAFTBUKKIT, "command"), CRAFTBUKKIT_CONVERSATIONS(CRAFTBUKKIT, "conversations"), CRAFTBUKKIT_ENCHANTMENS(CRAFTBUKKIT, "enchantments"), CRAFTBUKKIT_ENTITY(CRAFTBUKKIT, "entity"), CRAFTBUKKIT_EVENT(CRAFTBUKKIT, "event"), CRAFTBUKKIT_GENERATOR(CRAFTBUKKIT, "generator"), CRAFTBUKKIT_HELP(CRAFTBUKKIT, "help"), CRAFTBUKKIT_INVENTORY(CRAFTBUKKIT, "inventory"), CRAFTBUKKIT_MAP(CRAFTBUKKIT, "map"), CRAFTBUKKIT_METADATA(CRAFTBUKKIT, "metadata"), CRAFTBUKKIT_POTION(CRAFTBUKKIT, "potion"), CRAFTBUKKIT_PROJECTILES(CRAFTBUKKIT, "projectiles"), CRAFTBUKKIT_SCHEDULER(CRAFTBUKKIT, "scheduler"), CRAFTBUKKIT_SCOREBOARD(CRAFTBUKKIT, "scoreboard"), CRAFTBUKKIT_UPDATER(CRAFTBUKKIT, "updater"), CRAFTBUKKIT_UTIL(CRAFTBUKKIT, "util"); + + private final String path; + + /** + * Construct a new package type + * + * @param path + * Path of the package + */ + private PackageType(String path) + { + this.path = path; + } + + /** + * Construct a new package type + * + * @param parent + * Parent package of the package + * @param path + * Path of the package + */ + private PackageType(PackageType parent, String path) + { + this(parent + "." + path); + } + + /** + * Returns the path of this package type + * + * @return The path + */ + public String getPath() + { + return path; + } + + /** + * Returns the class with the given name + * + * @param className + * Name of the desired class + * @return The class with the specified name + * @throws ClassNotFoundException + * If the desired class with the specified name and package + * cannot be found + */ + public Class getClass(String className) throws ClassNotFoundException + { + return Class.forName(this + "." + className); + } + + // Override for convenience + @Override + public String toString() + { + return path; + } + + /** + * Returns the version of your server + * + * @return The server version + */ + public static String getServerVersion() + { + return Bukkit.getServer().getClass().getPackage().getName().substring(23); + } + } + + /** + * Represents an enumeration of Java data types with corresponding classes + *

+ * This class is part of the ReflectionUtils and follows the same + * usage conditions + * + * @author DarkBlade12 + * @since 1.0 + */ + public enum DataType + { + BYTE(byte.class, Byte.class), SHORT(short.class, Short.class), INTEGER(int.class, Integer.class), LONG(long.class, Long.class), CHARACTER(char.class, Character.class), FLOAT(float.class, Float.class), DOUBLE(double.class, Double.class), BOOLEAN(boolean.class, Boolean.class); + + private static final Map, DataType> CLASS_MAP = new HashMap, DataType>(); + private final Class primitive; + private final Class reference; + + // Initialize map for quick class lookup + static + { + for(DataType type : values()) + { + CLASS_MAP.put(type.primitive, type); + CLASS_MAP.put(type.reference, type); + } + } + + /** + * Construct a new data type + * + * @param primitive + * Primitive class of this data type + * @param reference + * Reference class of this data type + */ + private DataType(Class primitive, Class reference) + { + this.primitive = primitive; + this.reference = reference; + } + + /** + * Returns the primitive class of this data type + * + * @return The primitive class + */ + public Class getPrimitive() + { + return primitive; + } + + /** + * Returns the reference class of this data type + * + * @return The reference class + */ + public Class getReference() + { + return reference; + } + + /** + * Returns the data type with the given primitive/reference class + * + * @param clazz + * Primitive/Reference class of the data type + * @return The data type + */ + public static DataType fromClass(Class clazz) + { + return CLASS_MAP.get(clazz); + } + + /** + * Returns the primitive class of the data type with the given reference + * class + * + * @param clazz + * Reference class of the data type + * @return The primitive class + */ + public static Class getPrimitive(Class clazz) + { + DataType type = fromClass(clazz); + return type == null ? clazz : type.getPrimitive(); + } + + /** + * Returns the reference class of the data type with the given primitive + * class + * + * @param clazz + * Primitive class of the data type + * @return The reference class + */ + public static Class getReference(Class clazz) + { + DataType type = fromClass(clazz); + return type == null ? clazz : type.getReference(); + } + + /** + * Returns the primitive class array of the given class array + * + * @param classes + * Given class array + * @return The primitive class array + */ + public static Class[] getPrimitive(Class[] classes) + { + int length = classes == null ? 0 : classes.length; + Class[] types = new Class[length]; + for(int index = 0; index < length; index++) + { + types[index] = getPrimitive(classes[index]); + } + return types; + } + + /** + * Returns the reference class array of the given class array + * + * @param classes + * Given class array + * @return The reference class array + */ + public static Class[] getReference(Class[] classes) + { + int length = classes == null ? 0 : classes.length; + Class[] types = new Class[length]; + for(int index = 0; index < length; index++) + { + types[index] = getReference(classes[index]); + } + return types; + } + + /** + * Returns the primitive class array of the given object array + * + * @param objects + * Given object array + * @return The primitive class array + */ + public static Class[] getPrimitive(Object[] objects) + { + int length = objects == null ? 0 : objects.length; + Class[] types = new Class[length]; + for(int index = 0; index < length; index++) + { + types[index] = getPrimitive(objects[index].getClass()); + } + return types; + } + + /** + * Returns the reference class array of the given object array + * + * @param objects + * Given object array + * @return The reference class array + */ + public static Class[] getReference(Object[] objects) + { + int length = objects == null ? 0 : objects.length; + Class[] types = new Class[length]; + for(int index = 0; index < length; index++) + { + types[index] = getReference(objects[index].getClass()); + } + return types; + } + + /** + * Compares two class arrays on equivalence + * + * @param primary + * Primary class array + * @param secondary + * Class array which is compared to the primary array + * @return Whether these arrays are equal or not + */ + public static boolean compare(Class[] primary, Class[] secondary) + { + if(primary == null || secondary == null || primary.length != secondary.length) + { + return false; + } + for(int index = 0; index < primary.length; index++) + { + Class primaryClass = primary[index]; + Class secondaryClass = secondary[index]; + if(primaryClass.equals(secondaryClass) || primaryClass.isAssignableFrom(secondaryClass)) + { + continue; + } + return false; + } + return true; + } + } +} \ No newline at end of file diff --git a/src/main/java/ninja/bytecode/iris/util/VisualEffect.java b/src/main/java/ninja/bytecode/iris/util/VisualEffect.java new file mode 100644 index 000000000..1b47faa8f --- /dev/null +++ b/src/main/java/ninja/bytecode/iris/util/VisualEffect.java @@ -0,0 +1,17 @@ +package ninja.bytecode.iris.util; + +import org.bukkit.Location; +import org.bukkit.entity.Player; + +import ninja.bytecode.shuriken.collections.GList; + +public interface VisualEffect +{ + public void play(Location l); + + public void play(Location l, double r); + + public void play(Location l, Player p); + + public void play(Location l, GList p); +} diff --git a/src/main/java/ninja/bytecode/iris/util/WandUtil.java b/src/main/java/ninja/bytecode/iris/util/WandUtil.java index 3defb6f28..af3029914 100644 --- a/src/main/java/ninja/bytecode/iris/util/WandUtil.java +++ b/src/main/java/ninja/bytecode/iris/util/WandUtil.java @@ -19,17 +19,9 @@ import ninja.bytecode.shuriken.collections.GList; public class WandUtil { - @SuppressWarnings("deprecation") public static void pasteSchematic(Schematic s, Location at) { - Location start = at.clone().add(s.getOffset()); - - for(BlockVector i : s.getSchematic().keySet()) - { - MB b = s.getSchematic().get(i); - System.out.println("Pasted " + b.material + " @ " + start.clone().add(i)); - start.clone().add(i).getBlock().setTypeIdAndData(b.material.getId(), b.data, false); - } + s.place(at.getWorld(), at.getBlockX(), at.getBlockY(), at.getBlockZ()); } @SuppressWarnings("deprecation") @@ -39,7 +31,7 @@ public class WandUtil { return null; } - + try { Location[] f = getCuboid(wand); @@ -56,9 +48,11 @@ public class WandUtil continue; } + byte data = b.getData(); + BlockVector bv = b.getLocation().toVector().toBlockVector().subtract(c.getLowerNE().toVector().toBlockVector()).toBlockVector(); System.out.println("Load " + bv + " " + b.getType()); - s.put(bv.getBlockX(), bv.getBlockY(), bv.getBlockZ(), new MB(b.getType(), b.getData())); + s.put(bv.getBlockX(), bv.getBlockY(), bv.getBlockZ(), new MB(b.getType(), data)); } return s;