mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2025-07-18 18:23:06 +00:00
PAr fixes
This commit is contained in:
parent
1b2ce750ca
commit
14e63bd47d
@ -1,25 +1,32 @@
|
||||
package ninja.bytecode.iris;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.WorldCreator;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.generator.ChunkGenerator;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import ninja.bytecode.iris.generator.IrisGenerator;
|
||||
import ninja.bytecode.iris.object.IrisBiome;
|
||||
import ninja.bytecode.iris.object.IrisDimension;
|
||||
import ninja.bytecode.iris.object.IrisObject;
|
||||
import ninja.bytecode.iris.util.BiomeResult;
|
||||
import ninja.bytecode.iris.util.BoardManager;
|
||||
import ninja.bytecode.iris.util.BoardProvider;
|
||||
@ -28,6 +35,7 @@ import ninja.bytecode.iris.util.CNG;
|
||||
import ninja.bytecode.iris.util.GroupedExecutor;
|
||||
import ninja.bytecode.iris.util.IO;
|
||||
import ninja.bytecode.iris.util.ScoreDirection;
|
||||
import ninja.bytecode.iris.wand.WandController;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
import ninja.bytecode.shuriken.execution.J;
|
||||
import ninja.bytecode.shuriken.format.Form;
|
||||
@ -39,8 +47,9 @@ public class Iris extends JavaPlugin implements BoardProvider
|
||||
public static KList<GroupedExecutor> executors = new KList<>();
|
||||
public static Iris instance;
|
||||
public static IrisDataManager data;
|
||||
private static String last = "";
|
||||
public static IrisHotloadManager hotloader;
|
||||
public static WandController wand;
|
||||
private static String last = "";
|
||||
private BoardManager manager;
|
||||
private RollingSequence hits = new RollingSequence(20);
|
||||
|
||||
@ -54,6 +63,7 @@ public class Iris extends JavaPlugin implements BoardProvider
|
||||
instance = this;
|
||||
hotloader = new IrisHotloadManager();
|
||||
data = new IrisDataManager(getDataFolder());
|
||||
wand = new WandController();
|
||||
manager = new BoardManager(this, BoardSettings.builder().boardProvider(this).scoreDirection(ScoreDirection.UP).build());
|
||||
}
|
||||
|
||||
@ -83,6 +93,9 @@ public class Iris extends JavaPlugin implements BoardProvider
|
||||
lines.add(ChatColor.GREEN + "Loss" + ChatColor.GRAY + ": " + ChatColor.BOLD + "" + ChatColor.GRAY + Form.duration(g.getMetrics().getLoss().getAverage(), 4) + "");
|
||||
lines.add(ChatColor.GREEN + "Generators" + ChatColor.GRAY + ": " + Form.f(CNG.creates));
|
||||
lines.add(ChatColor.GREEN + "Noise" + ChatColor.GRAY + ": " + Form.f((int) hits.getAverage()));
|
||||
lines.add(ChatColor.GREEN + "Parallax Regions" + ChatColor.GRAY + ": " + Form.f((int) g.getParallaxMap().getLoadedRegions().size()));
|
||||
lines.add(ChatColor.GREEN + "Parallax Chunks" + ChatColor.GRAY + ": " + Form.f((int) g.getParallaxMap().getLoadedChunks().size()));
|
||||
lines.add(ChatColor.GREEN + "Sliver Buffer" + ChatColor.GRAY + ": " + Form.f((int) g.getSliverBuffer()));
|
||||
|
||||
if(er != null && b != null)
|
||||
{
|
||||
@ -110,6 +123,8 @@ public class Iris extends JavaPlugin implements BoardProvider
|
||||
|
||||
executors.clear();
|
||||
manager.onDisable();
|
||||
Bukkit.getScheduler().cancelTasks(this);
|
||||
HandlerList.unregisterAll((Plugin) this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -120,10 +135,79 @@ public class Iris extends JavaPlugin implements BoardProvider
|
||||
if(args.length == 0)
|
||||
{
|
||||
imsg(sender, "/iris dev - Create a new dev world");
|
||||
imsg(sender, "/iris wand - Get a wand");
|
||||
}
|
||||
|
||||
if(args.length >= 1)
|
||||
{
|
||||
if(args[0].equalsIgnoreCase("wand"))
|
||||
{
|
||||
((Player) sender).getInventory().addItem(WandController.createWand());
|
||||
}
|
||||
|
||||
if(args[0].equalsIgnoreCase("save") && args.length >= 2)
|
||||
{
|
||||
ItemStack wand = ((Player) sender).getInventory().getItemInMainHand();
|
||||
IrisObject o = WandController.createSchematic(wand);
|
||||
try
|
||||
{
|
||||
o.write(new File(getDataFolder(), "objects/" + args[1] + ".iob"));
|
||||
imsg(sender, "Saved " + "objects/" + args[1] + ".iob");
|
||||
}
|
||||
|
||||
catch(IOException e)
|
||||
{
|
||||
imsg(sender, "Failed to save " + "objects/" + args[1] + ".iob");
|
||||
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if(args[0].equalsIgnoreCase("load") && args.length >= 2)
|
||||
{
|
||||
File file = new File(getDataFolder(), "objects/" + args[1] + ".iob");
|
||||
boolean intoWand = false;
|
||||
|
||||
for(String i : args)
|
||||
{
|
||||
if(i.equalsIgnoreCase("-edit"))
|
||||
{
|
||||
intoWand = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(!file.exists())
|
||||
{
|
||||
imsg(sender, "Can't find " + "objects/" + args[1] + ".iob");
|
||||
}
|
||||
|
||||
ItemStack wand = ((Player) sender).getInventory().getItemInMainHand();
|
||||
IrisObject o = new IrisObject(0, 0, 0);
|
||||
|
||||
try
|
||||
{
|
||||
o.read(new File(getDataFolder(), "objects/" + args[1] + ".iob"));
|
||||
imsg(sender, "Loaded " + "objects/" + args[1] + ".iob");
|
||||
Location block = ((Player) sender).getTargetBlock((Set<Material>) null, 256).getLocation().clone().add(0, 1, 0);
|
||||
|
||||
if(intoWand && WandController.isWand(wand))
|
||||
{
|
||||
wand = WandController.createWand(block.clone().subtract(o.getCenter()).add(o.getW() - 1, o.getH(), o.getD() - 1), block.clone().subtract(o.getCenter()));
|
||||
((Player) sender).getInventory().setItemInMainHand(wand);
|
||||
imsg(sender, "Updated wand for " + "objects/" + args[1] + ".iob");
|
||||
}
|
||||
|
||||
WandController.pasteSchematic(o, block);
|
||||
imsg(sender, "Placed " + "objects/" + args[1] + ".iob");
|
||||
}
|
||||
|
||||
catch(IOException e)
|
||||
{
|
||||
imsg(sender, "Failed to load " + "objects/" + args[1] + ".iob");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if(args[0].equalsIgnoreCase("dev"))
|
||||
{
|
||||
String dim = "Overworld";
|
||||
|
@ -10,6 +10,7 @@ import ninja.bytecode.iris.object.IrisBiome;
|
||||
import ninja.bytecode.iris.object.IrisDimension;
|
||||
import ninja.bytecode.iris.object.IrisRegion;
|
||||
import ninja.bytecode.iris.util.IO;
|
||||
import ninja.bytecode.iris.util.ObjectResourceLoader;
|
||||
import ninja.bytecode.iris.util.ResourceLoader;
|
||||
|
||||
@Data
|
||||
@ -17,10 +18,10 @@ public class IrisDataManager
|
||||
{
|
||||
private File dataFolder;
|
||||
private File packs;
|
||||
|
||||
private ResourceLoader<IrisBiome> biomeLoader;
|
||||
private ResourceLoader<IrisRegion> regionLoader;
|
||||
private ResourceLoader<IrisDimension> dimensionLoader;
|
||||
private ObjectResourceLoader objectLoader;
|
||||
|
||||
public void hotloaded()
|
||||
{
|
||||
@ -28,6 +29,7 @@ public class IrisDataManager
|
||||
this.regionLoader = new ResourceLoader<>(packs, "regions", "Region", IrisRegion.class);
|
||||
this.biomeLoader = new ResourceLoader<>(packs, "biomes", "Biome", IrisBiome.class);
|
||||
this.dimensionLoader = new ResourceLoader<>(packs, "dimensions", "Dimension", IrisDimension.class);
|
||||
this.objectLoader = new ObjectResourceLoader(packs, "objects", "Object");
|
||||
writeExamples();
|
||||
}
|
||||
|
||||
|
@ -250,11 +250,18 @@ public abstract class ContextualChunkGenerator extends ChunkGenerator implements
|
||||
CNG.hits = 0;
|
||||
Iris.instance.hit(hits);
|
||||
metrics.getLoss().put(sx.getMilliseconds() - s.getMilliseconds());
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
fail(e);
|
||||
}
|
||||
|
||||
return generateChunkDataFailure(world, no, x, z, biomeGrid);
|
||||
}
|
||||
|
||||
protected void fail(Throwable e)
|
||||
{
|
||||
failing = true;
|
||||
Iris.error("ERROR! Failed to generate chunk! Iris has entered a failed state!");
|
||||
@ -270,9 +277,6 @@ public abstract class ContextualChunkGenerator extends ChunkGenerator implements
|
||||
onFailure(e);
|
||||
}
|
||||
|
||||
return generateChunkDataFailure(world, no, x, z, biomeGrid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BlockPopulator> getDefaultPopulators(World world)
|
||||
{
|
||||
|
@ -5,6 +5,7 @@ import org.bukkit.entity.Player;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import ninja.bytecode.iris.Iris;
|
||||
import ninja.bytecode.iris.IrisContext;
|
||||
import ninja.bytecode.iris.object.IrisRegion;
|
||||
import ninja.bytecode.iris.util.BiomeResult;
|
||||
@ -39,13 +40,14 @@ public class IrisGenerator extends ParallaxChunkGenerator implements IrisContext
|
||||
@Override
|
||||
protected void onTick(int ticks)
|
||||
{
|
||||
|
||||
super.onTick(ticks);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onClose()
|
||||
{
|
||||
|
||||
super.onClose();
|
||||
Iris.info("Closing Iris Dimension " + getWorld().getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,22 +1,172 @@
|
||||
package ninja.bytecode.iris.generator;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import ninja.bytecode.iris.Iris;
|
||||
import ninja.bytecode.iris.object.IrisBiome;
|
||||
import ninja.bytecode.iris.object.IrisObjectPlacement;
|
||||
import ninja.bytecode.iris.object.atomics.AtomicSliver;
|
||||
import ninja.bytecode.iris.object.atomics.AtomicSliverMap;
|
||||
import ninja.bytecode.iris.object.atomics.AtomicWorldData;
|
||||
import ninja.bytecode.iris.util.BiomeMap;
|
||||
import ninja.bytecode.iris.util.ChunkPosition;
|
||||
import ninja.bytecode.iris.util.HeightMap;
|
||||
import ninja.bytecode.iris.util.IObjectPlacer;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
import ninja.bytecode.shuriken.collections.KMap;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public abstract class ParallaxChunkGenerator extends TerrainChunkGenerator
|
||||
public abstract class ParallaxChunkGenerator extends TerrainChunkGenerator implements IObjectPlacer
|
||||
{
|
||||
private KMap<ChunkPosition, AtomicSliver> sliverCache;
|
||||
protected AtomicWorldData parallaxMap;
|
||||
private int sliverBuffer = 0;
|
||||
|
||||
public ParallaxChunkGenerator(String dimensionName, int threads)
|
||||
{
|
||||
super(dimensionName, threads);
|
||||
sliverCache = new KMap<>();
|
||||
}
|
||||
|
||||
public void onInit(World world, RNG rng)
|
||||
{
|
||||
super.onInit(world, rng);
|
||||
parallaxMap = new AtomicWorldData(world);
|
||||
}
|
||||
|
||||
protected void onClose()
|
||||
{
|
||||
super.onClose();
|
||||
|
||||
try
|
||||
{
|
||||
parallaxMap.unloadAll(true);
|
||||
}
|
||||
|
||||
catch(IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid, HeightMap height)
|
||||
public int getHighest(int x, int z)
|
||||
{
|
||||
return sampleSliver(x, z).getHighestBlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(int x, int y, int z, BlockData d)
|
||||
{
|
||||
getParallaxSliver(x, z).set(y, d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockData get(int x, int y, int z)
|
||||
{
|
||||
BlockData b = sampleSliver(x, z).getBlock().get(y);
|
||||
return b == null ? AIR : b;
|
||||
}
|
||||
|
||||
public AtomicSliver getParallaxSliver(int wx, int wz)
|
||||
{
|
||||
return getParallaxChunk(wx >> 4, wz >> 4).getSliver(wx & 15, wz & 15);
|
||||
}
|
||||
|
||||
public boolean hasParallaxChunk(int x, int z)
|
||||
{
|
||||
try
|
||||
{
|
||||
return getParallaxMap().hasChunk(x, z);
|
||||
}
|
||||
|
||||
catch(IOException e)
|
||||
{
|
||||
fail(e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public AtomicSliverMap getParallaxChunk(int x, int z)
|
||||
{
|
||||
try
|
||||
{
|
||||
return getParallaxMap().loadChunk(x, z);
|
||||
}
|
||||
|
||||
catch(IOException e)
|
||||
{
|
||||
fail(e);
|
||||
}
|
||||
|
||||
return new AtomicSliverMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid, HeightMap height, BiomeMap biomeMap)
|
||||
{
|
||||
onGenerateParallax(random, x, z);
|
||||
getParallaxChunk(x, z).inject(data);
|
||||
sliverBuffer = sliverCache.size();
|
||||
sliverCache.clear();
|
||||
}
|
||||
|
||||
protected void onGenerateParallax(RNG random, int x, int z)
|
||||
{
|
||||
ChunkPosition pos = Iris.data.getObjectLoader().getParallaxSize();
|
||||
|
||||
for(int i = x - pos.getX() / 2; i <= x + pos.getX() / 2; i++)
|
||||
{
|
||||
for(int j = z - pos.getZ() / 2; j <= z + pos.getZ() / 2; j++)
|
||||
{
|
||||
IrisBiome b = sampleBiome((i * 16) + 7, (j * 16) + 7).getBiome();
|
||||
int g = 1;
|
||||
|
||||
for(IrisObjectPlacement k : b.getObjects())
|
||||
{
|
||||
placeObject(k, i, j, random.nextParallelRNG((i * 30) + (j * 30) + g++));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTick(int ticks)
|
||||
{
|
||||
if(ticks % 100 == 0)
|
||||
{
|
||||
parallaxMap.clean();
|
||||
}
|
||||
}
|
||||
|
||||
protected void placeObject(IrisObjectPlacement o, int x, int z, RNG rng)
|
||||
{
|
||||
for(int i = 0; i < o.getTriesForChunk(rng); i++)
|
||||
{
|
||||
o.getSchematic(rng).place((x * 16) * rng.nextInt(16), (z * 16) + rng.nextInt(16), this);
|
||||
}
|
||||
}
|
||||
|
||||
public AtomicSliver sampleSliver(int x, int z)
|
||||
{
|
||||
ChunkPosition key = new ChunkPosition(x, z);
|
||||
|
||||
if(sliverCache.containsKey(key))
|
||||
{
|
||||
return sliverCache.get(key);
|
||||
}
|
||||
|
||||
AtomicSliver s = new AtomicSliver(x & 15, z & 15);
|
||||
onGenerateColumn(x >> 4, z >> 4, x, z, x & 15, z & 15, s, null);
|
||||
sliverCache.put(key, s);
|
||||
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import lombok.EqualsAndHashCode;
|
||||
import ninja.bytecode.iris.Iris;
|
||||
import ninja.bytecode.iris.object.atomics.AtomicSliver;
|
||||
import ninja.bytecode.iris.object.atomics.AtomicSliverMap;
|
||||
import ninja.bytecode.iris.util.BiomeMap;
|
||||
import ninja.bytecode.iris.util.GroupedExecutor;
|
||||
import ninja.bytecode.iris.util.HeightMap;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
@ -37,11 +38,11 @@ public abstract class ParallelChunkGenerator extends BiomeChunkGenerator
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void onGenerateColumn(int cx, int cz, int wx, int wz, int x, int z, AtomicSliver sliver);
|
||||
protected abstract void onGenerateColumn(int cx, int cz, int wx, int wz, int x, int z, AtomicSliver sliver, BiomeMap biomeMap);
|
||||
|
||||
protected abstract int onSampleColumnHeight(int cx, int cz, int wx, int wz, int x, int z);
|
||||
|
||||
protected abstract void onPostGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid, HeightMap height);
|
||||
protected abstract void onPostGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid, HeightMap height, BiomeMap biomeMap);
|
||||
|
||||
protected int sampleHeight(int x, int z)
|
||||
{
|
||||
@ -53,6 +54,7 @@ public abstract class ParallelChunkGenerator extends BiomeChunkGenerator
|
||||
AtomicSliverMap map = new AtomicSliverMap();
|
||||
HeightMap height = new HeightMap();
|
||||
String key = "c" + x + "," + z;
|
||||
BiomeMap biomeMap = new BiomeMap();
|
||||
int ii, jj;
|
||||
|
||||
for(ii = 0; ii < 16; ii++)
|
||||
@ -68,14 +70,19 @@ public abstract class ParallelChunkGenerator extends BiomeChunkGenerator
|
||||
|
||||
tx.queue(key, () ->
|
||||
{
|
||||
onGenerateColumn(x, z, wx, wz, i, j, sliver);
|
||||
onGenerateColumn(x, z, wx, wz, i, j, sliver, biomeMap);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
tx.waitFor(key);
|
||||
map.write(data, grid, height);
|
||||
onPostGenerate(random, x, z, data, grid, height);
|
||||
onPostGenerate(random, x, z, data, grid, height, biomeMap);
|
||||
}
|
||||
|
||||
protected void onClose()
|
||||
{
|
||||
tx.close();
|
||||
}
|
||||
|
||||
public void onInit(World world, RNG rng)
|
||||
@ -87,6 +94,6 @@ public abstract class ParallelChunkGenerator extends BiomeChunkGenerator
|
||||
@Override
|
||||
public boolean isParallelCapable()
|
||||
{
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import lombok.EqualsAndHashCode;
|
||||
import ninja.bytecode.iris.object.IrisBiome;
|
||||
import ninja.bytecode.iris.object.IrisRegion;
|
||||
import ninja.bytecode.iris.object.atomics.AtomicSliver;
|
||||
import ninja.bytecode.iris.util.BiomeMap;
|
||||
import ninja.bytecode.iris.util.BiomeResult;
|
||||
import ninja.bytecode.iris.util.CNG;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
@ -18,6 +19,7 @@ import ninja.bytecode.shuriken.collections.KList;
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public abstract class TerrainChunkGenerator extends ParallelChunkGenerator
|
||||
{
|
||||
protected static final BlockData AIR = Material.AIR.createBlockData();
|
||||
protected static final BlockData STONE = Material.STONE.createBlockData();
|
||||
protected static final BlockData WATER = Material.WATER.createBlockData();
|
||||
protected CNG terrainNoise;
|
||||
@ -34,7 +36,7 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onGenerateColumn(int cx, int cz, int rx, int rz, int x, int z, AtomicSliver sliver)
|
||||
protected void onGenerateColumn(int cx, int cz, int rx, int rz, int x, int z, AtomicSliver sliver, BiomeMap biomeMap)
|
||||
{
|
||||
BlockData block;
|
||||
int fluidHeight = getDimension().getFluidHeight();
|
||||
@ -64,7 +66,12 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator
|
||||
for(int k = Math.max(height, fluidHeight); k >= 0; k--)
|
||||
{
|
||||
boolean underwater = k > height && k <= fluidHeight;
|
||||
|
||||
if(biomeMap != null)
|
||||
{
|
||||
sliver.set(k, biome.getDerivative());
|
||||
biomeMap.setBiome(x, z, biome);
|
||||
}
|
||||
|
||||
if(underwater)
|
||||
{
|
||||
@ -76,7 +83,6 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator
|
||||
block = layers.hasIndex(depth) ? layers.get(depth) : STONE;
|
||||
depth++;
|
||||
}
|
||||
|
||||
sliver.set(k, block);
|
||||
}
|
||||
}
|
||||
|
6
src/main/java/ninja/bytecode/iris/object/Blueprint.java
Normal file
6
src/main/java/ninja/bytecode/iris/object/Blueprint.java
Normal file
@ -0,0 +1,6 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
public class Blueprint
|
||||
{
|
||||
|
||||
}
|
@ -25,7 +25,7 @@ public class IrisBiome extends IrisRegisteredObject
|
||||
private KList<String> children = new KList<>();
|
||||
private KList<IrisBiomePaletteLayer> layers = new KList<IrisBiomePaletteLayer>().qadd(new IrisBiomePaletteLayer());
|
||||
private KList<IrisBiomeDecorator> decorators = new KList<IrisBiomeDecorator>();
|
||||
|
||||
private KList<IrisObjectPlacement> objects = new KList<IrisObjectPlacement>();
|
||||
private transient ReentrantLock lock = new ReentrantLock();
|
||||
private transient CellGenerator childrenCell;
|
||||
private transient InferredType inferredType;
|
||||
|
@ -1,32 +1,98 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.util.BlockVector;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import ninja.bytecode.iris.util.BlockDataTools;
|
||||
import ninja.bytecode.iris.util.IObjectPlacer;
|
||||
import ninja.bytecode.shuriken.collections.KMap;
|
||||
import ninja.bytecode.shuriken.collections.KSet;
|
||||
|
||||
public class IrisObject
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class IrisObject extends IrisRegisteredObject
|
||||
{
|
||||
private String name;
|
||||
private KMap<BlockVector, BlockData> blocks;
|
||||
private KSet<BlockVector> mount;
|
||||
private int w;
|
||||
private int d;
|
||||
private int h;
|
||||
private transient BlockVector center;
|
||||
|
||||
public IrisObject(String name, int w, int h, int d)
|
||||
public IrisObject(int w, int h, int d)
|
||||
{
|
||||
blocks = new KMap<>();
|
||||
mount = new KSet<>();
|
||||
this.w = w;
|
||||
this.h = h;
|
||||
this.d = d;
|
||||
this.name = name;
|
||||
center = new BlockVector(w / 2, h / 2, d / 2);
|
||||
}
|
||||
|
||||
public static BlockVector sampleSize(File file) throws IOException
|
||||
{
|
||||
FileInputStream in = new FileInputStream(file);
|
||||
DataInputStream din = new DataInputStream(in);
|
||||
BlockVector bv = new BlockVector(din.readInt(), din.readInt(), din.readInt());
|
||||
din.close();
|
||||
return bv;
|
||||
}
|
||||
|
||||
public void read(InputStream in) throws IOException
|
||||
{
|
||||
DataInputStream din = new DataInputStream(in);
|
||||
this.w = din.readInt();
|
||||
this.h = din.readInt();
|
||||
this.d = din.readInt();
|
||||
center = new BlockVector(w / 2, h / 2, d / 2);
|
||||
int s = din.readInt();
|
||||
|
||||
for(int i = 0; i < s; i++)
|
||||
{
|
||||
blocks.put(new BlockVector(din.readShort(), din.readShort(), din.readShort()), BlockDataTools.getBlockData(din.readUTF()));
|
||||
}
|
||||
}
|
||||
|
||||
public void read(File file) throws IOException
|
||||
{
|
||||
FileInputStream fin = new FileInputStream(file);
|
||||
read(fin);
|
||||
fin.close();
|
||||
}
|
||||
|
||||
public void write(File file) throws IOException
|
||||
{
|
||||
file.getParentFile().mkdirs();
|
||||
FileOutputStream out = new FileOutputStream(file);
|
||||
write(out);
|
||||
out.close();
|
||||
}
|
||||
|
||||
public void write(OutputStream o) throws IOException
|
||||
{
|
||||
DataOutputStream dos = new DataOutputStream(o);
|
||||
dos.writeInt(w);
|
||||
dos.writeInt(h);
|
||||
dos.writeInt(d);
|
||||
dos.writeInt(blocks.size());
|
||||
for(BlockVector i : blocks.k())
|
||||
{
|
||||
dos.writeShort(i.getBlockX());
|
||||
dos.writeShort(i.getBlockY());
|
||||
dos.writeShort(i.getBlockZ());
|
||||
dos.writeUTF(blocks.get(i).getAsString(true));
|
||||
}
|
||||
}
|
||||
|
||||
public void setUnsigned(int x, int y, int z, BlockData block)
|
||||
{
|
||||
if(x >= w || y >= h || z >= d)
|
||||
@ -46,4 +112,22 @@ public class IrisObject
|
||||
blocks.put(v, block);
|
||||
}
|
||||
}
|
||||
|
||||
public void place(int x, int z, IObjectPlacer placer)
|
||||
{
|
||||
int y = placer.getHighest(x, z) + getCenter().getBlockY();
|
||||
|
||||
for(BlockVector i : blocks.k())
|
||||
{
|
||||
placer.set(x + i.getBlockX(), y + i.getBlockY(), z + i.getBlockZ(), blocks.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
public void place(Location at)
|
||||
{
|
||||
for(BlockVector i : blocks.k())
|
||||
{
|
||||
at.clone().add(0, getCenter().getY(), 0).add(i).getBlock().setBlockData(blocks.get(i), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,42 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import ninja.bytecode.iris.Iris;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
|
||||
public class IrisObjectPlacement
|
||||
{
|
||||
private KList<String> place = new KList<>();
|
||||
private double chance = 1;
|
||||
private int density = 1;
|
||||
|
||||
public IrisObjectPlacement()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public IrisObject getSchematic(RNG random)
|
||||
{
|
||||
if(place.isEmpty())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return Iris.data.getObjectLoader().load(place.get(random.nextInt(place.size())));
|
||||
}
|
||||
|
||||
public int getTriesForChunk(RNG random)
|
||||
{
|
||||
if(chance <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(chance >= 1 || random.nextDouble() < chance)
|
||||
{
|
||||
return density;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
@ -53,6 +53,11 @@ public class AtomicRegionData
|
||||
|
||||
public void set(int rx, int rz, AtomicSliverMap data) throws IOException
|
||||
{
|
||||
if(data == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ByteArrayOutputStream boas = new ByteArrayOutputStream();
|
||||
data.write(boas);
|
||||
tag.put(rx + "." + rz, new ByteArrayTag(rx + "." + rz, boas.toByteArray()));
|
||||
@ -60,12 +65,13 @@ public class AtomicRegionData
|
||||
|
||||
public AtomicSliverMap get(int rx, int rz) throws IOException
|
||||
{
|
||||
AtomicSliverMap data = new AtomicSliverMap();
|
||||
|
||||
if(!contains(rx, rz))
|
||||
{
|
||||
return null;
|
||||
return data;
|
||||
}
|
||||
|
||||
AtomicSliverMap data = new AtomicSliverMap();
|
||||
ByteArrayTag btag = (ByteArrayTag) tag.get(rx + "." + rz);
|
||||
ByteArrayInputStream in = new ByteArrayInputStream(btag.getValue());
|
||||
data.read(in);
|
||||
|
@ -12,13 +12,14 @@ import org.bukkit.generator.ChunkGenerator.ChunkData;
|
||||
import lombok.Data;
|
||||
import ninja.bytecode.iris.util.BlockDataTools;
|
||||
import ninja.bytecode.iris.util.HeightMap;
|
||||
import ninja.bytecode.shuriken.collections.KMap;
|
||||
|
||||
@Data
|
||||
public class AtomicSliver
|
||||
{
|
||||
private static final BlockData AIR = BlockDataTools.getBlockData("AIR");
|
||||
private BlockData[] block;
|
||||
private Biome[] biome;
|
||||
private KMap<Integer, BlockData> block;
|
||||
private KMap<Integer, Biome> biome;
|
||||
private int highestBlock = 0;
|
||||
private int highestBiome = 0;
|
||||
private int x;
|
||||
@ -28,19 +29,19 @@ public class AtomicSliver
|
||||
{
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
this.block = new BlockData[256];
|
||||
this.biome = new Biome[256];
|
||||
this.block = new KMap<>();
|
||||
this.biome = new KMap<>();
|
||||
}
|
||||
|
||||
public void set(int h, BlockData d)
|
||||
{
|
||||
block[h] = d;
|
||||
block.put(h, d);
|
||||
highestBlock = h > highestBlock ? h : highestBlock;
|
||||
}
|
||||
|
||||
public void set(int h, Biome d)
|
||||
{
|
||||
biome[h] = d;
|
||||
biome.put(h, d);
|
||||
highestBiome = h > highestBiome ? h : highestBiome;
|
||||
}
|
||||
|
||||
@ -48,14 +49,14 @@ public class AtomicSliver
|
||||
{
|
||||
for(int i = 0; i <= highestBlock; i++)
|
||||
{
|
||||
if(block[i] == null)
|
||||
if(block.get(i) == null)
|
||||
{
|
||||
d.setBlock(x, i, z, AIR);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
d.setBlock(x, i, z, block[i]);
|
||||
d.setBlock(x, i, z, block.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -64,7 +65,10 @@ public class AtomicSliver
|
||||
{
|
||||
for(int i = 0; i <= highestBiome; i++)
|
||||
{
|
||||
d.setBiome(x, i, z, biome[i]);
|
||||
if(biome.get(i) != null)
|
||||
{
|
||||
d.setBiome(x, i, z, biome.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,11 +79,11 @@ public class AtomicSliver
|
||||
|
||||
public void read(DataInputStream din) throws IOException
|
||||
{
|
||||
this.block = new BlockData[256];
|
||||
this.block = new KMap<Integer, BlockData>();
|
||||
int h = din.readByte() - Byte.MIN_VALUE;
|
||||
for(int i = 0; i <= h; i++)
|
||||
{
|
||||
block[i] = BlockDataTools.getBlockData(din.readUTF());
|
||||
block.put(i, BlockDataTools.getBlockData(din.readUTF()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,7 +93,8 @@ public class AtomicSliver
|
||||
|
||||
for(int i = 0; i <= highestBlock; i++)
|
||||
{
|
||||
dos.writeUTF(block[i].getAsString(true));
|
||||
BlockData dat = block.get(i);
|
||||
dos.writeUTF((dat == null ? AIR : dat).getAsString(true));
|
||||
}
|
||||
}
|
||||
|
||||
@ -97,15 +102,27 @@ public class AtomicSliver
|
||||
{
|
||||
for(int i = 0; i < 256; i++)
|
||||
{
|
||||
if(block[i] == null || block[i].equals(AIR))
|
||||
if(block.get(i) == null || block.get(i).equals(AIR))
|
||||
{
|
||||
BlockData b = atomicSliver.block[i];
|
||||
BlockData b = atomicSliver.block.get(i);
|
||||
if(b == null || b.equals(AIR))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
block[i] = b;
|
||||
block.put(i, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void inject(ChunkData currentData)
|
||||
{
|
||||
for(int i = 0; i < getHighestBlock(); i++)
|
||||
{
|
||||
if(block.get(i) != null && !block.get(i).equals(AIR))
|
||||
{
|
||||
BlockData b = block.get(i);
|
||||
currentData.setBlock(x, i, z, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -73,4 +73,12 @@ public class AtomicSliverMap
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void inject(ChunkData currentData)
|
||||
{
|
||||
for(AtomicSliver i : slivers)
|
||||
{
|
||||
i.inject(currentData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,29 +7,36 @@ import java.io.IOException;
|
||||
|
||||
import org.bukkit.World;
|
||||
|
||||
import ninja.bytecode.iris.Iris;
|
||||
import ninja.bytecode.iris.util.ChunkPosition;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
import ninja.bytecode.shuriken.collections.KMap;
|
||||
import ninja.bytecode.shuriken.math.M;
|
||||
|
||||
public class AtomicWorldData
|
||||
{
|
||||
private World world;
|
||||
private KMap<ChunkPosition, AtomicSliverMap> loadedChunks;
|
||||
private KMap<ChunkPosition, AtomicRegionData> loadedSections;
|
||||
private KMap<ChunkPosition, Long> lastRegion;
|
||||
|
||||
public AtomicWorldData(World world)
|
||||
{
|
||||
this.world = world;
|
||||
loadedSections = new KMap<>();
|
||||
loadedChunks = new KMap<>();
|
||||
lastRegion = new KMap<>();
|
||||
getSubregionFolder().mkdirs();
|
||||
}
|
||||
|
||||
public KList<ChunkPosition> getLoadedRegions()
|
||||
public KMap<ChunkPosition, AtomicRegionData> getLoadedRegions()
|
||||
{
|
||||
return loadedSections.k();
|
||||
return loadedSections;
|
||||
}
|
||||
|
||||
public AtomicRegionData getSubregion(int x, int z) throws IOException
|
||||
{
|
||||
lastRegion.put(new ChunkPosition(x, z), M.ms());
|
||||
|
||||
if(!isSectionLoaded(x, z))
|
||||
{
|
||||
loadedSections.put(new ChunkPosition(x, z), loadSection(x, z));
|
||||
@ -42,6 +49,8 @@ public class AtomicWorldData
|
||||
|
||||
public void saveAll() throws IOException
|
||||
{
|
||||
saveChunks();
|
||||
|
||||
for(ChunkPosition i : loadedSections.keySet())
|
||||
{
|
||||
saveSection(i);
|
||||
@ -50,10 +59,16 @@ public class AtomicWorldData
|
||||
|
||||
public void unloadAll(boolean save) throws IOException
|
||||
{
|
||||
saveChunks();
|
||||
|
||||
for(ChunkPosition i : loadedSections.keySet())
|
||||
{
|
||||
unloadSection(i, save);
|
||||
}
|
||||
|
||||
loadedSections.clear();
|
||||
loadedChunks.clear();
|
||||
lastRegion.clear();
|
||||
}
|
||||
|
||||
public void deleteSection(int x, int z) throws IOException
|
||||
@ -105,6 +120,7 @@ public class AtomicWorldData
|
||||
return false;
|
||||
}
|
||||
|
||||
saveChunks(s);
|
||||
AtomicRegionData data = loadedSections.get(s);
|
||||
FileOutputStream fos = new FileOutputStream(getSubregionFile(s.getX(), s.getZ()));
|
||||
data.write(fos);
|
||||
@ -112,29 +128,84 @@ public class AtomicWorldData
|
||||
return true;
|
||||
}
|
||||
|
||||
public void saveChunks() throws IOException
|
||||
{
|
||||
for(ChunkPosition i : loadedChunks.k())
|
||||
{
|
||||
saveChunk(i);
|
||||
}
|
||||
}
|
||||
|
||||
public void saveChunks(ChunkPosition reg) throws IOException
|
||||
{
|
||||
for(ChunkPosition i : loadedChunks.k())
|
||||
{
|
||||
int x = i.getX();
|
||||
int z = i.getZ();
|
||||
|
||||
if(x >> 5 == reg.getX() && z >> 5 == reg.getZ())
|
||||
{
|
||||
saveChunk(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void saveChunk(ChunkPosition i) throws IOException
|
||||
{
|
||||
int x = i.getX();
|
||||
int z = i.getZ();
|
||||
AtomicRegionData dat = loadSection(x >> 5, z >> 5);
|
||||
dat.set(x & 31, z & 31, loadedChunks.get(i));
|
||||
loadedChunks.remove(i);
|
||||
}
|
||||
|
||||
public AtomicSliverMap loadChunk(int x, int z) throws IOException
|
||||
{
|
||||
return loadSection(x >> 5, z >> 5).get(x & 31, z & 31);
|
||||
ChunkPosition pos = new ChunkPosition(x, z);
|
||||
|
||||
if(loadedChunks.containsKey(pos))
|
||||
{
|
||||
return loadedChunks.get(pos);
|
||||
}
|
||||
|
||||
AtomicRegionData dat = loadSection(x >> 5, z >> 5);
|
||||
AtomicSliverMap m = dat.get(x & 31, z & 31);
|
||||
loadedChunks.put(pos, m);
|
||||
|
||||
Iris.info("Loaded chunk: sections: " + loadedSections.size());
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
public boolean hasChunk(int x, int z) throws IOException
|
||||
{
|
||||
return loadSection(x >> 5, z >> 5).contains(x & 31, z & 31);
|
||||
}
|
||||
|
||||
public AtomicRegionData loadSection(int x, int z) throws IOException
|
||||
{
|
||||
ChunkPosition pos = new ChunkPosition(x, z);
|
||||
lastRegion.put(pos, M.ms());
|
||||
|
||||
if(isSectionLoaded(x, z))
|
||||
{
|
||||
return loadedSections.get(new ChunkPosition(x, z));
|
||||
return loadedSections.get(pos);
|
||||
}
|
||||
|
||||
File file = getSubregionFile(x, z);
|
||||
|
||||
if(!file.exists())
|
||||
{
|
||||
return createSection(x, z);
|
||||
AtomicRegionData dat = createSection(x, z);
|
||||
loadedSections.put(pos, dat);
|
||||
return dat;
|
||||
}
|
||||
|
||||
FileInputStream fin = new FileInputStream(file);
|
||||
AtomicRegionData data = new AtomicRegionData(world);
|
||||
data.read(fin);
|
||||
fin.close();
|
||||
loadedSections.put(pos, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
@ -160,4 +231,30 @@ public class AtomicWorldData
|
||||
{
|
||||
return new File(world.getWorldFolder(), "subregion");
|
||||
}
|
||||
|
||||
public KMap<ChunkPosition, AtomicSliverMap> getLoadedChunks()
|
||||
{
|
||||
return loadedChunks;
|
||||
}
|
||||
|
||||
public void clean()
|
||||
{
|
||||
for(ChunkPosition i : lastRegion.k())
|
||||
{
|
||||
if(M.ms() - lastRegion.get(i) > 3000)
|
||||
{
|
||||
lastRegion.remove(i);
|
||||
|
||||
try
|
||||
{
|
||||
unloadSection(i, true);
|
||||
}
|
||||
|
||||
catch(IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
31
src/main/java/ninja/bytecode/iris/util/Axis.java
Normal file
31
src/main/java/ninja/bytecode/iris/util/Axis.java
Normal file
@ -0,0 +1,31 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
public enum Axis
|
||||
{
|
||||
X(1, 0, 0),
|
||||
Y(0, 1, 0),
|
||||
Z(0, 0, 1);
|
||||
|
||||
private int x;
|
||||
private int y;
|
||||
private int z;
|
||||
|
||||
private Axis(int x, int y, int z)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public Vector positive()
|
||||
{
|
||||
return new Vector(x, y, z);
|
||||
}
|
||||
|
||||
public Vector negative()
|
||||
{
|
||||
return VectorMath.reverse(positive());
|
||||
}
|
||||
}
|
23
src/main/java/ninja/bytecode/iris/util/BiomeMap.java
Normal file
23
src/main/java/ninja/bytecode/iris/util/BiomeMap.java
Normal file
@ -0,0 +1,23 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import ninja.bytecode.iris.object.IrisBiome;
|
||||
|
||||
public class BiomeMap
|
||||
{
|
||||
private final IrisBiome[] height;
|
||||
|
||||
public BiomeMap()
|
||||
{
|
||||
height = new IrisBiome[256];
|
||||
}
|
||||
|
||||
public void setBiome(int x, int z, IrisBiome h)
|
||||
{
|
||||
height[x * 16 + z] = h;
|
||||
}
|
||||
|
||||
public IrisBiome getBiome(int x, int z)
|
||||
{
|
||||
return height[x * 16 + z];
|
||||
}
|
||||
}
|
49
src/main/java/ninja/bytecode/iris/util/CDou.java
Normal file
49
src/main/java/ninja/bytecode/iris/util/CDou.java
Normal file
@ -0,0 +1,49 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
public class CDou
|
||||
{
|
||||
private double number;
|
||||
private double max;
|
||||
|
||||
public CDou(double max)
|
||||
{
|
||||
number = 0;
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
public CDou set(double n)
|
||||
{
|
||||
number = n;
|
||||
circ();
|
||||
return this;
|
||||
}
|
||||
|
||||
public CDou add(double a)
|
||||
{
|
||||
number += a;
|
||||
circ();
|
||||
return this;
|
||||
}
|
||||
|
||||
public CDou sub(double a)
|
||||
{
|
||||
number -= a;
|
||||
circ();
|
||||
return this;
|
||||
}
|
||||
|
||||
public double get()
|
||||
{
|
||||
return number;
|
||||
}
|
||||
|
||||
public void circ()
|
||||
{
|
||||
if(number < 0)
|
||||
{
|
||||
number = max - (Math.abs(number) > max ? max : Math.abs(number));
|
||||
}
|
||||
|
||||
number = number % (max);
|
||||
}
|
||||
}
|
884
src/main/java/ninja/bytecode/iris/util/Cuboid.java
Normal file
884
src/main/java/ninja/bytecode/iris/util/Cuboid.java
Normal file
@ -0,0 +1,884 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.configuration.serialization.ConfigurationSerializable;
|
||||
import org.bukkit.entity.Entity;
|
||||
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
|
||||
/**
|
||||
* Cuboids
|
||||
*
|
||||
* @author cyberpwn
|
||||
*/
|
||||
public class Cuboid implements Iterable<Block>, Cloneable, ConfigurationSerializable
|
||||
{
|
||||
protected final String worldName;
|
||||
protected int x1, y1, z1;
|
||||
protected int x2, y2, z2;
|
||||
|
||||
/**
|
||||
* Construct a Cuboid given two Location objects which represent any two corners
|
||||
* of the Cuboid.
|
||||
*
|
||||
* @param l1
|
||||
* one of the corners
|
||||
* @param l2
|
||||
* the other corner
|
||||
*/
|
||||
public Cuboid(Location l1, Location l2)
|
||||
{
|
||||
if(!l1.getWorld().equals(l2.getWorld()))
|
||||
{
|
||||
throw new IllegalArgumentException("locations must be on the same world");
|
||||
}
|
||||
|
||||
worldName = l1.getWorld().getName();
|
||||
x1 = Math.min(l1.getBlockX(), l2.getBlockX());
|
||||
y1 = Math.min(l1.getBlockY(), l2.getBlockY());
|
||||
z1 = Math.min(l1.getBlockZ(), l2.getBlockZ());
|
||||
x2 = Math.max(l1.getBlockX(), l2.getBlockX());
|
||||
y2 = Math.max(l1.getBlockY(), l2.getBlockY());
|
||||
z2 = Math.max(l1.getBlockZ(), l2.getBlockZ());
|
||||
}
|
||||
|
||||
public KList<Entity> getEntities()
|
||||
{
|
||||
KList<Entity> en = new KList<Entity>();
|
||||
|
||||
for(Chunk i : getChunks())
|
||||
{
|
||||
for(Entity j : i.getEntities())
|
||||
{
|
||||
if(contains(j.getLocation()))
|
||||
{
|
||||
en.add(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return en;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the locations
|
||||
*
|
||||
* @param l1
|
||||
* a
|
||||
* @param l2
|
||||
* b
|
||||
*/
|
||||
public void set(Location l1, Location l2)
|
||||
{
|
||||
x1 = Math.min(l1.getBlockX(), l2.getBlockX());
|
||||
y1 = Math.min(l1.getBlockY(), l2.getBlockY());
|
||||
z1 = Math.min(l1.getBlockZ(), l2.getBlockZ());
|
||||
x2 = Math.max(l1.getBlockX(), l2.getBlockX());
|
||||
y2 = Math.max(l1.getBlockY(), l2.getBlockY());
|
||||
z2 = Math.max(l1.getBlockZ(), l2.getBlockZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a one-block Cuboid at the given Location of the Cuboid.
|
||||
*
|
||||
* @param l1
|
||||
* location of the Cuboid
|
||||
*/
|
||||
public Cuboid(Location l1)
|
||||
{
|
||||
this(l1, l1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor.
|
||||
*
|
||||
* @param other
|
||||
* the Cuboid to copy
|
||||
*/
|
||||
public Cuboid(Cuboid other)
|
||||
{
|
||||
this(other.getWorld().getName(), other.x1, other.y1, other.z1, other.x2, other.y2, other.z2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a Cuboid in the given World and xyz co-ordinates
|
||||
*
|
||||
* @param world
|
||||
* the Cuboid's world
|
||||
* @param x1
|
||||
* X co-ordinate of corner 1
|
||||
* @param y1
|
||||
* Y co-ordinate of corner 1
|
||||
* @param z1
|
||||
* Z co-ordinate of corner 1
|
||||
* @param x2
|
||||
* X co-ordinate of corner 2
|
||||
* @param y2
|
||||
* Y co-ordinate of corner 2
|
||||
* @param z2
|
||||
* Z co-ordinate of corner 2
|
||||
*/
|
||||
public Cuboid(World world, int x1, int y1, int z1, int x2, int y2, int z2)
|
||||
{
|
||||
this.worldName = world.getName();
|
||||
this.x1 = Math.min(x1, x2);
|
||||
this.x2 = Math.max(x1, x2);
|
||||
this.y1 = Math.min(y1, y2);
|
||||
this.y2 = Math.max(y1, y2);
|
||||
this.z1 = Math.min(z1, z2);
|
||||
this.z2 = Math.max(z1, z2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a Cuboid in the given world name and xyz co-ordinates.
|
||||
*
|
||||
* @param worldName
|
||||
* the Cuboid's world name
|
||||
* @param x1
|
||||
* X co-ordinate of corner 1
|
||||
* @param y1
|
||||
* Y co-ordinate of corner 1
|
||||
* @param z1
|
||||
* Z co-ordinate of corner 1
|
||||
* @param x2
|
||||
* X co-ordinate of corner 2
|
||||
* @param y2
|
||||
* Y co-ordinate of corner 2
|
||||
* @param z2
|
||||
* Z co-ordinate of corner 2
|
||||
*/
|
||||
private Cuboid(String worldName, int x1, int y1, int z1, int x2, int y2, int z2)
|
||||
{
|
||||
this.worldName = worldName;
|
||||
this.x1 = Math.min(x1, x2);
|
||||
this.x2 = Math.max(x1, x2);
|
||||
this.y1 = Math.min(y1, y2);
|
||||
this.y2 = Math.max(y1, y2);
|
||||
this.z1 = Math.min(z1, z2);
|
||||
this.z2 = Math.max(z1, z2);
|
||||
}
|
||||
|
||||
public Cuboid(Map<String, Object> map)
|
||||
{
|
||||
worldName = (String) map.get("worldName");
|
||||
x1 = (Integer) map.get("x1");
|
||||
x2 = (Integer) map.get("x2");
|
||||
y1 = (Integer) map.get("y1");
|
||||
y2 = (Integer) map.get("y2");
|
||||
z1 = (Integer) map.get("z1");
|
||||
z2 = (Integer) map.get("z2");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> serialize()
|
||||
{
|
||||
Map<String, Object> map = new HashMap<String, Object>();
|
||||
map.put("worldName", worldName);
|
||||
map.put("x1", x1);
|
||||
map.put("y1", y1);
|
||||
map.put("z1", z1);
|
||||
map.put("x2", x2);
|
||||
map.put("y2", y2);
|
||||
map.put("z2", z2);
|
||||
return map;
|
||||
}
|
||||
|
||||
public Cuboid flatten(int level)
|
||||
{
|
||||
return new Cuboid(getWorld(), x1, level, z1, x2, level, z2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Location of the lower northeast corner of the Cuboid (minimum XYZ
|
||||
* co-ordinates).
|
||||
*
|
||||
* @return Location of the lower northeast corner
|
||||
*/
|
||||
public Location getLowerNE()
|
||||
{
|
||||
return new Location(getWorld(), x1, y1, z1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Location of the upper southwest corner of the Cuboid (maximum XYZ
|
||||
* co-ordinates).
|
||||
*
|
||||
* @return Location of the upper southwest corner
|
||||
*/
|
||||
public Location getUpperSW()
|
||||
{
|
||||
return new Location(getWorld(), x2, y2, z2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the the centre of the Cuboid
|
||||
*
|
||||
* @return Location at the centre of the Cuboid
|
||||
*/
|
||||
public Location getCenter()
|
||||
{
|
||||
int x1 = getUpperX() + 1;
|
||||
int y1 = getUpperY() + 1;
|
||||
int z1 = getUpperZ() + 1;
|
||||
return new Location(getWorld(), getLowerX() + (x1 - getLowerX()) / 2.0, getLowerY() + (y1 - getLowerY()) / 2.0, getLowerZ() + (z1 - getLowerZ()) / 2.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Cuboid's world.
|
||||
*
|
||||
* @return the World object representing this Cuboid's world
|
||||
* @throws IllegalStateException
|
||||
* if the world is not loaded
|
||||
*/
|
||||
public World getWorld()
|
||||
{
|
||||
World world = Bukkit.getWorld(worldName);
|
||||
if(world == null)
|
||||
{
|
||||
throw new IllegalStateException("world '" + worldName + "' is not loaded");
|
||||
}
|
||||
return world;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size of this Cuboid along the X axis
|
||||
*
|
||||
* @return Size of Cuboid along the X axis
|
||||
*/
|
||||
public int getSizeX()
|
||||
{
|
||||
return (x2 - x1) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size of this Cuboid along the Y axis
|
||||
*
|
||||
* @return Size of Cuboid along the Y axis
|
||||
*/
|
||||
public int getSizeY()
|
||||
{
|
||||
return (y2 - y1) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size of this Cuboid along the Z axis
|
||||
*
|
||||
* @return Size of Cuboid along the Z axis
|
||||
*/
|
||||
public int getSizeZ()
|
||||
{
|
||||
return (z2 - z1) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cuboid dimensions
|
||||
*
|
||||
* @return the dimensions
|
||||
*/
|
||||
public Dimension getDimension()
|
||||
{
|
||||
return new Dimension(getSizeX(), getSizeY(), getSizeZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the minimum X co-ordinate of this Cuboid
|
||||
*
|
||||
* @return the minimum X co-ordinate
|
||||
*/
|
||||
public int getLowerX()
|
||||
{
|
||||
return x1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the minimum Y co-ordinate of this Cuboid
|
||||
*
|
||||
* @return the minimum Y co-ordinate
|
||||
*/
|
||||
public int getLowerY()
|
||||
{
|
||||
return y1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the minimum Z co-ordinate of this Cuboid
|
||||
*
|
||||
* @return the minimum Z co-ordinate
|
||||
*/
|
||||
public int getLowerZ()
|
||||
{
|
||||
return z1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maximum X co-ordinate of this Cuboid
|
||||
*
|
||||
* @return the maximum X co-ordinate
|
||||
*/
|
||||
public int getUpperX()
|
||||
{
|
||||
return x2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maximum Y co-ordinate of this Cuboid
|
||||
*
|
||||
* @return the maximum Y co-ordinate
|
||||
*/
|
||||
public int getUpperY()
|
||||
{
|
||||
return y2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maximum Z co-ordinate of this Cuboid
|
||||
*
|
||||
* @return the maximum Z co-ordinate
|
||||
*/
|
||||
public int getUpperZ()
|
||||
{
|
||||
return z2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Blocks at the eight corners of the Cuboid.
|
||||
*
|
||||
* @return array of Block objects representing the Cuboid corners
|
||||
*/
|
||||
public Block[] corners()
|
||||
{
|
||||
Block[] res = new Block[8];
|
||||
World w = getWorld();
|
||||
res[0] = w.getBlockAt(x1, y1, z1);
|
||||
res[1] = w.getBlockAt(x1, y1, z2);
|
||||
res[2] = w.getBlockAt(x1, y2, z1);
|
||||
res[3] = w.getBlockAt(x1, y2, z2);
|
||||
res[4] = w.getBlockAt(x2, y1, z1);
|
||||
res[5] = w.getBlockAt(x2, y1, z2);
|
||||
res[6] = w.getBlockAt(x2, y2, z1);
|
||||
res[7] = w.getBlockAt(x2, y2, z2);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand the Cuboid in the given direction by the given amount. Negative
|
||||
* amounts will shrink the Cuboid in the given direction. Shrinking a cuboid's
|
||||
* face past the opposite face is not an error and will return a valid Cuboid.
|
||||
*
|
||||
* @param dir
|
||||
* the direction in which to expand
|
||||
* @param amount
|
||||
* the number of blocks by which to expand
|
||||
* @return a new Cuboid expanded by the given direction and amount
|
||||
*/
|
||||
public Cuboid expand(CuboidDirection dir, int amount)
|
||||
{
|
||||
switch(dir)
|
||||
{
|
||||
case North:
|
||||
return new Cuboid(worldName, x1 - amount, y1, z1, x2, y2, z2);
|
||||
case South:
|
||||
return new Cuboid(worldName, x1, y1, z1, x2 + amount, y2, z2);
|
||||
case East:
|
||||
return new Cuboid(worldName, x1, y1, z1 - amount, x2, y2, z2);
|
||||
case West:
|
||||
return new Cuboid(worldName, x1, y1, z1, x2, y2, z2 + amount);
|
||||
case Down:
|
||||
return new Cuboid(worldName, x1, y1 - amount, z1, x2, y2, z2);
|
||||
case Up:
|
||||
return new Cuboid(worldName, x1, y1, z1, x2, y2 + amount, z2);
|
||||
default:
|
||||
throw new IllegalArgumentException("invalid direction " + dir);
|
||||
}
|
||||
}
|
||||
|
||||
public Cuboid expand(Direction dir, int amount)
|
||||
{
|
||||
int ax = dir.toVector().getBlockX() == 1 ? amount : 0;
|
||||
int sx = dir.toVector().getBlockX() == -1 ? -amount : 0;
|
||||
int ay = dir.toVector().getBlockY() == 1 ? amount : 0;
|
||||
int sy = dir.toVector().getBlockY() == -1 ? -amount : 0;
|
||||
int az = dir.toVector().getBlockZ() == 1 ? amount : 0;
|
||||
int sz = dir.toVector().getBlockZ() == -1 ? -amount : 0;
|
||||
return new Cuboid(worldName, x1 + sx, y1 + sy, z1 + sz, x2 + ax, y2 + ay, z2 + az);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shift the Cuboid in the given direction by the given amount.
|
||||
*
|
||||
* @param dir
|
||||
* the direction in which to shift
|
||||
* @param amount
|
||||
* the number of blocks by which to shift
|
||||
* @return a new Cuboid shifted by the given direction and amount
|
||||
*/
|
||||
public Cuboid shift(CuboidDirection dir, int amount)
|
||||
{
|
||||
return expand(dir, amount).expand(dir.opposite(), -amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outset (grow) the Cuboid in the given direction by the given amount.
|
||||
*
|
||||
* @param dir
|
||||
* the direction in which to outset (must be Horizontal, Vertical, or
|
||||
* Both)
|
||||
* @param amount
|
||||
* the number of blocks by which to outset
|
||||
* @return a new Cuboid outset by the given direction and amount
|
||||
*/
|
||||
public Cuboid outset(CuboidDirection dir, int amount)
|
||||
{
|
||||
Cuboid c;
|
||||
switch(dir)
|
||||
{
|
||||
case Horizontal:
|
||||
c = expand(CuboidDirection.North, amount).expand(CuboidDirection.South, amount).expand(CuboidDirection.East, amount).expand(CuboidDirection.West, amount);
|
||||
break;
|
||||
case Vertical:
|
||||
c = expand(CuboidDirection.Down, amount).expand(CuboidDirection.Up, amount);
|
||||
break;
|
||||
case Both:
|
||||
c = outset(CuboidDirection.Horizontal, amount).outset(CuboidDirection.Vertical, amount);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("invalid direction " + dir);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inset (shrink) the Cuboid in the given direction by the given amount.
|
||||
* Equivalent to calling outset() with a negative amount.
|
||||
*
|
||||
* @param dir
|
||||
* the direction in which to inset (must be Horizontal, Vertical, or
|
||||
* Both)
|
||||
* @param amount
|
||||
* the number of blocks by which to inset
|
||||
* @return a new Cuboid inset by the given direction and amount
|
||||
*/
|
||||
public Cuboid inset(CuboidDirection dir, int amount)
|
||||
{
|
||||
return outset(dir, -amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the point at (x,y,z) is contained within this Cuboid.
|
||||
*
|
||||
* @param x
|
||||
* the X co-ordinate
|
||||
* @param y
|
||||
* the Y co-ordinate
|
||||
* @param z
|
||||
* the Z co-ordinate
|
||||
* @return true if the given point is within this Cuboid, false otherwise
|
||||
*/
|
||||
public boolean contains(int x, int y, int z)
|
||||
{
|
||||
return x >= x1 && x <= x2 && y >= y1 && y <= y2 && z >= z1 && z <= z2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given Block is contained within this Cuboid.
|
||||
*
|
||||
* @param b
|
||||
* the Block to check for
|
||||
* @return true if the Block is within this Cuboid, false otherwise
|
||||
*/
|
||||
public boolean contains(Block b)
|
||||
{
|
||||
return contains(b.getLocation());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given Location is contained within this Cuboid.
|
||||
*
|
||||
* @param l
|
||||
* the Location to check for
|
||||
* @return true if the Location is within this Cuboid, false otherwise
|
||||
*/
|
||||
public boolean contains(Location l)
|
||||
{
|
||||
return worldName.equals(l.getWorld().getName()) && contains(l.getBlockX(), l.getBlockY(), l.getBlockZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the volume of this Cuboid.
|
||||
*
|
||||
* @return the Cuboid volume, in blocks
|
||||
*/
|
||||
public int volume()
|
||||
{
|
||||
return getSizeX() * getSizeY() * getSizeZ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the average light level of all empty (air) blocks in the Cuboid. Returns
|
||||
* 0 if there are no empty blocks.
|
||||
*
|
||||
* @return the average light level of this Cuboid
|
||||
*/
|
||||
public byte averageLightLevel()
|
||||
{
|
||||
long total = 0;
|
||||
int n = 0;
|
||||
for(Block b : this)
|
||||
{
|
||||
if(b.isEmpty())
|
||||
{
|
||||
total += b.getLightLevel();
|
||||
++n;
|
||||
}
|
||||
}
|
||||
return n > 0 ? (byte) (total / n) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Contract the Cuboid, returning a Cuboid with any air around the edges
|
||||
* removed, just large enough to include all non-air blocks.
|
||||
*
|
||||
* @return a new Cuboid with no external air blocks
|
||||
*/
|
||||
public Cuboid contract()
|
||||
{
|
||||
return this.contract(CuboidDirection.Down).contract(CuboidDirection.South).contract(CuboidDirection.East).contract(CuboidDirection.Up).contract(CuboidDirection.North).contract(CuboidDirection.West);
|
||||
}
|
||||
|
||||
/**
|
||||
* Contract the Cuboid in the given direction, returning a new Cuboid which has
|
||||
* no exterior empty space. E.g. a direction of Down will push the top face
|
||||
* downwards as much as possible.
|
||||
*
|
||||
* @param dir
|
||||
* the direction in which to contract
|
||||
* @return a new Cuboid contracted in the given direction
|
||||
*/
|
||||
public Cuboid contract(CuboidDirection dir)
|
||||
{
|
||||
Cuboid face = getFace(dir.opposite());
|
||||
switch(dir)
|
||||
{
|
||||
case Down:
|
||||
while(face.containsOnly(Material.AIR) && face.getLowerY() > this.getLowerY())
|
||||
{
|
||||
face = face.shift(CuboidDirection.Down, 1);
|
||||
}
|
||||
return new Cuboid(worldName, x1, y1, z1, x2, face.getUpperY(), z2);
|
||||
case Up:
|
||||
while(face.containsOnly(Material.AIR) && face.getUpperY() < this.getUpperY())
|
||||
{
|
||||
face = face.shift(CuboidDirection.Up, 1);
|
||||
}
|
||||
return new Cuboid(worldName, x1, face.getLowerY(), z1, x2, y2, z2);
|
||||
case North:
|
||||
while(face.containsOnly(Material.AIR) && face.getLowerX() > this.getLowerX())
|
||||
{
|
||||
face = face.shift(CuboidDirection.North, 1);
|
||||
}
|
||||
return new Cuboid(worldName, x1, y1, z1, face.getUpperX(), y2, z2);
|
||||
case South:
|
||||
while(face.containsOnly(Material.AIR) && face.getUpperX() < this.getUpperX())
|
||||
{
|
||||
face = face.shift(CuboidDirection.South, 1);
|
||||
}
|
||||
return new Cuboid(worldName, face.getLowerX(), y1, z1, x2, y2, z2);
|
||||
case East:
|
||||
while(face.containsOnly(Material.AIR) && face.getLowerZ() > this.getLowerZ())
|
||||
{
|
||||
face = face.shift(CuboidDirection.East, 1);
|
||||
}
|
||||
return new Cuboid(worldName, x1, y1, z1, x2, y2, face.getUpperZ());
|
||||
case West:
|
||||
while(face.containsOnly(Material.AIR) && face.getUpperZ() < this.getUpperZ())
|
||||
{
|
||||
face = face.shift(CuboidDirection.West, 1);
|
||||
}
|
||||
return new Cuboid(worldName, x1, y1, face.getLowerZ(), x2, y2, z2);
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid direction " + dir);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Cuboid representing the face of this Cuboid. The resulting Cuboid
|
||||
* will be one block thick in the axis perpendicular to the requested face.
|
||||
*
|
||||
* @param dir
|
||||
* which face of the Cuboid to get
|
||||
* @return the Cuboid representing this Cuboid's requested face
|
||||
*/
|
||||
public Cuboid getFace(CuboidDirection dir)
|
||||
{
|
||||
switch(dir)
|
||||
{
|
||||
case Down:
|
||||
return new Cuboid(worldName, x1, y1, z1, x2, y1, z2);
|
||||
case Up:
|
||||
return new Cuboid(worldName, x1, y2, z1, x2, y2, z2);
|
||||
case North:
|
||||
return new Cuboid(worldName, x1, y1, z1, x1, y2, z2);
|
||||
case South:
|
||||
return new Cuboid(worldName, x2, y1, z1, x2, y2, z2);
|
||||
case East:
|
||||
return new Cuboid(worldName, x1, y1, z1, x2, y2, z1);
|
||||
case West:
|
||||
return new Cuboid(worldName, x1, y1, z2, x2, y2, z2);
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid direction " + dir);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the Cuboid contains only blocks of the given type
|
||||
*
|
||||
* @param material
|
||||
* the material to check for
|
||||
* @return true if this Cuboid contains only blocks of the given type
|
||||
*/
|
||||
public boolean containsOnly(Material material)
|
||||
{
|
||||
for(Block b : this)
|
||||
{
|
||||
if(b.getType() != material)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Cuboid big enough to hold both this Cuboid and the given one.
|
||||
*
|
||||
* @param other
|
||||
* the other Cuboid to include
|
||||
* @return a new Cuboid large enough to hold this Cuboid and the given Cuboid
|
||||
*/
|
||||
public Cuboid getBoundingCuboid(Cuboid other)
|
||||
{
|
||||
if(other == null)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
int xMin = Math.min(getLowerX(), other.getLowerX());
|
||||
int yMin = Math.min(getLowerY(), other.getLowerY());
|
||||
int zMin = Math.min(getLowerZ(), other.getLowerZ());
|
||||
int xMax = Math.max(getUpperX(), other.getUpperX());
|
||||
int yMax = Math.max(getUpperY(), other.getUpperY());
|
||||
int zMax = Math.max(getUpperZ(), other.getUpperZ());
|
||||
|
||||
return new Cuboid(worldName, xMin, yMin, zMin, xMax, yMax, zMax);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a block relative to the lower NE point of the Cuboid.
|
||||
*
|
||||
* @param x
|
||||
* the X co-ordinate
|
||||
* @param y
|
||||
* the Y co-ordinate
|
||||
* @param z
|
||||
* the Z co-ordinate
|
||||
* @return the block at the given position
|
||||
*/
|
||||
public Block getRelativeBlock(int x, int y, int z)
|
||||
{
|
||||
return getWorld().getBlockAt(x1 + x, y1 + y, z1 + z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a block relative to the lower NE point of the Cuboid in the given World.
|
||||
* This version of getRelativeBlock() should be used if being called many times,
|
||||
* to avoid excessive calls to getWorld().
|
||||
*
|
||||
* @param w
|
||||
* the World
|
||||
* @param x
|
||||
* the X co-ordinate
|
||||
* @param y
|
||||
* the Y co-ordinate
|
||||
* @param z
|
||||
* the Z co-ordinate
|
||||
* @return the block at the given position
|
||||
*/
|
||||
public Block getRelativeBlock(World w, int x, int y, int z)
|
||||
{
|
||||
return w.getBlockAt(x1 + x, y1 + y, z1 + z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of the chunks which are fully or partially contained in this
|
||||
* cuboid.
|
||||
*
|
||||
* @return a list of Chunk objects
|
||||
*/
|
||||
public List<Chunk> getChunks()
|
||||
{
|
||||
List<Chunk> res = new ArrayList<Chunk>();
|
||||
|
||||
World w = getWorld();
|
||||
int x1 = getLowerX() & ~0xf;
|
||||
int x2 = getUpperX() & ~0xf;
|
||||
int z1 = getLowerZ() & ~0xf;
|
||||
int z2 = getUpperZ() & ~0xf;
|
||||
for(int x = x1; x <= x2; x += 16)
|
||||
{
|
||||
for(int z = z1; z <= z2; z += 16)
|
||||
{
|
||||
res.add(w.getChunkAt(x >> 4, z >> 4));
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all the blocks within the Cuboid to the given MaterialData, using a
|
||||
* MassBlockUpdate object for fast updates.
|
||||
*
|
||||
* @param mat
|
||||
* the MaterialData to set
|
||||
* @param mbu
|
||||
* the MassBlockUpdate object
|
||||
*/
|
||||
|
||||
/**
|
||||
* Reset the light level of all blocks within this Cuboid.
|
||||
*/
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Iterable#iterator()
|
||||
*/
|
||||
@Override
|
||||
public Iterator<Block> iterator()
|
||||
{
|
||||
return new CuboidIterator(getWorld(), x1, y1, z1, x2, y2, z2);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#clone()
|
||||
*/
|
||||
@Override
|
||||
public Cuboid clone() throws CloneNotSupportedException
|
||||
{
|
||||
return new Cuboid(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "Cuboid: " + worldName + "," + x1 + "," + y1 + "," + z1 + "=>" + x2 + "," + y2 + "," + z2;
|
||||
}
|
||||
|
||||
public class CuboidIterator implements Iterator<Block>
|
||||
{
|
||||
private World w;
|
||||
private int baseX, baseY, baseZ;
|
||||
private int x, y, z;
|
||||
private int sizeX, sizeY, sizeZ;
|
||||
|
||||
public CuboidIterator(World w, int x1, int y1, int z1, int x2, int y2, int z2)
|
||||
{
|
||||
this.w = w;
|
||||
baseX = x1;
|
||||
baseY = y1;
|
||||
baseZ = z1;
|
||||
sizeX = Math.abs(x2 - x1) + 1;
|
||||
sizeY = Math.abs(y2 - y1) + 1;
|
||||
sizeZ = Math.abs(z2 - z1) + 1;
|
||||
x = y = z = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext()
|
||||
{
|
||||
return x < sizeX && y < sizeY && z < sizeZ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Block next()
|
||||
{
|
||||
Block b = w.getBlockAt(baseX + x, baseY + y, baseZ + z);
|
||||
if(++x >= sizeX)
|
||||
{
|
||||
x = 0;
|
||||
if(++y >= sizeY)
|
||||
{
|
||||
y = 0;
|
||||
++z;
|
||||
}
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove()
|
||||
{
|
||||
// nop
|
||||
}
|
||||
}
|
||||
|
||||
public enum CuboidDirection
|
||||
{
|
||||
|
||||
North,
|
||||
East,
|
||||
South,
|
||||
West,
|
||||
Up,
|
||||
Down,
|
||||
Horizontal,
|
||||
Vertical,
|
||||
Both,
|
||||
Unknown;
|
||||
|
||||
public CuboidDirection opposite()
|
||||
{
|
||||
switch(this)
|
||||
{
|
||||
case North:
|
||||
return South;
|
||||
case East:
|
||||
return West;
|
||||
case South:
|
||||
return North;
|
||||
case West:
|
||||
return East;
|
||||
case Horizontal:
|
||||
return Vertical;
|
||||
case Vertical:
|
||||
return Horizontal;
|
||||
case Up:
|
||||
return Down;
|
||||
case Down:
|
||||
return Up;
|
||||
case Both:
|
||||
return Both;
|
||||
default:
|
||||
return Unknown;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
16
src/main/java/ninja/bytecode/iris/util/CuboidException.java
Normal file
16
src/main/java/ninja/bytecode/iris/util/CuboidException.java
Normal file
@ -0,0 +1,16 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
/**
|
||||
* Represents a cuboid exception
|
||||
*
|
||||
* @author cyberpwn
|
||||
*/
|
||||
public class CuboidException extends Exception
|
||||
{
|
||||
public CuboidException(String string)
|
||||
{
|
||||
super(string);
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
20
src/main/java/ninja/bytecode/iris/util/DOP.java
Normal file
20
src/main/java/ninja/bytecode/iris/util/DOP.java
Normal file
@ -0,0 +1,20 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
public abstract class DOP
|
||||
{
|
||||
private String type;
|
||||
|
||||
public DOP(String type)
|
||||
{
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public abstract Vector op(Vector v);
|
||||
|
||||
public String getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
}
|
86
src/main/java/ninja/bytecode/iris/util/Dimension.java
Normal file
86
src/main/java/ninja/bytecode/iris/util/Dimension.java
Normal file
@ -0,0 +1,86 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
/**
|
||||
* Dimensions
|
||||
*
|
||||
* @author cyberpwn
|
||||
*/
|
||||
public class Dimension
|
||||
{
|
||||
private final int width;
|
||||
private final int height;
|
||||
private final int depth;
|
||||
|
||||
/**
|
||||
* Make a dimension
|
||||
*
|
||||
* @param width
|
||||
* width of this (X)
|
||||
* @param height
|
||||
* the height (Y)
|
||||
* @param depth
|
||||
* the depth (Z)
|
||||
*/
|
||||
public Dimension(int width, int height, int depth)
|
||||
{
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.depth = depth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a dimension
|
||||
*
|
||||
* @param width
|
||||
* width of this (X)
|
||||
* @param height
|
||||
* the height (Y)
|
||||
*/
|
||||
public Dimension(int width, int height)
|
||||
{
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.depth = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the direction of the flat part of this dimension (null if no thin
|
||||
* face)
|
||||
*
|
||||
* @return the direction of the flat pane or null
|
||||
*/
|
||||
public DimensionFace getPane()
|
||||
{
|
||||
if(width == 1)
|
||||
{
|
||||
return DimensionFace.X;
|
||||
}
|
||||
|
||||
if(height == 1)
|
||||
{
|
||||
return DimensionFace.Y;
|
||||
}
|
||||
|
||||
if(depth == 1)
|
||||
{
|
||||
return DimensionFace.Z;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getWidth()
|
||||
{
|
||||
return width;
|
||||
}
|
||||
|
||||
public int getHeight()
|
||||
{
|
||||
return height;
|
||||
}
|
||||
|
||||
public int getDepth()
|
||||
{
|
||||
return depth;
|
||||
}
|
||||
}
|
24
src/main/java/ninja/bytecode/iris/util/DimensionFace.java
Normal file
24
src/main/java/ninja/bytecode/iris/util/DimensionFace.java
Normal file
@ -0,0 +1,24 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
/**
|
||||
* Represents a dimension (coordinates not worlds)
|
||||
*
|
||||
* @author cyberpwn
|
||||
*/
|
||||
public enum DimensionFace
|
||||
{
|
||||
/**
|
||||
* The X dimension (width)
|
||||
*/
|
||||
X,
|
||||
|
||||
/**
|
||||
* The Y dimension (height)
|
||||
*/
|
||||
Y,
|
||||
|
||||
/**
|
||||
* The Z dimension (depth)
|
||||
*/
|
||||
Z
|
||||
}
|
535
src/main/java/ninja/bytecode/iris/util/Direction.java
Normal file
535
src/main/java/ninja/bytecode/iris/util/Direction.java
Normal file
@ -0,0 +1,535 @@
|
||||
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import org.bukkit.Axis;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import ninja.bytecode.iris.util.Cuboid.CuboidDirection;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
import ninja.bytecode.shuriken.collections.KMap;
|
||||
|
||||
/**
|
||||
* Directions
|
||||
*
|
||||
* @author cyberpwn
|
||||
*/
|
||||
public enum Direction
|
||||
{
|
||||
U(0, 1, 0, CuboidDirection.Up),
|
||||
D(0, -1, 0, CuboidDirection.Down),
|
||||
N(0, 0, -1, CuboidDirection.North),
|
||||
S(0, 0, 1, CuboidDirection.South),
|
||||
E(1, 0, 0, CuboidDirection.East),
|
||||
W(-1, 0, 0, CuboidDirection.West);
|
||||
|
||||
private static KMap<GBiset<Direction, Direction>, DOP> permute = null;
|
||||
|
||||
private int x;
|
||||
private int y;
|
||||
private int z;
|
||||
private CuboidDirection f;
|
||||
|
||||
public static Direction getDirection(BlockFace f)
|
||||
{
|
||||
switch(f)
|
||||
{
|
||||
case DOWN:
|
||||
return D;
|
||||
case EAST:
|
||||
return E;
|
||||
case EAST_NORTH_EAST:
|
||||
return E;
|
||||
case EAST_SOUTH_EAST:
|
||||
return E;
|
||||
case NORTH:
|
||||
return N;
|
||||
case NORTH_EAST:
|
||||
return N;
|
||||
case NORTH_NORTH_EAST:
|
||||
return N;
|
||||
case NORTH_NORTH_WEST:
|
||||
return N;
|
||||
case NORTH_WEST:
|
||||
return N;
|
||||
case SELF:
|
||||
return U;
|
||||
case SOUTH:
|
||||
return S;
|
||||
case SOUTH_EAST:
|
||||
return S;
|
||||
case SOUTH_SOUTH_EAST:
|
||||
return S;
|
||||
case SOUTH_SOUTH_WEST:
|
||||
return S;
|
||||
case SOUTH_WEST:
|
||||
return S;
|
||||
case UP:
|
||||
return U;
|
||||
case WEST:
|
||||
return W;
|
||||
case WEST_NORTH_WEST:
|
||||
return W;
|
||||
case WEST_SOUTH_WEST:
|
||||
return W;
|
||||
}
|
||||
|
||||
return D;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
switch(this)
|
||||
{
|
||||
case D:
|
||||
return "Down";
|
||||
case E:
|
||||
return "East";
|
||||
case N:
|
||||
return "North";
|
||||
case S:
|
||||
return "South";
|
||||
case U:
|
||||
return "Up";
|
||||
case W:
|
||||
return "West";
|
||||
}
|
||||
|
||||
return "?";
|
||||
}
|
||||
|
||||
public boolean isVertical()
|
||||
{
|
||||
return equals(D) || equals(U);
|
||||
}
|
||||
|
||||
public static Direction closest(Vector v)
|
||||
{
|
||||
double m = Double.MAX_VALUE;
|
||||
Direction s = null;
|
||||
|
||||
for(Direction i : values())
|
||||
{
|
||||
Vector x = i.toVector();
|
||||
double g = x.dot(v);
|
||||
|
||||
if(g < m)
|
||||
{
|
||||
m = g;
|
||||
s = i;
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
public static Direction closest(Vector v, Direction... d)
|
||||
{
|
||||
double m = Double.MAX_VALUE;
|
||||
Direction s = null;
|
||||
|
||||
for(Direction i : d)
|
||||
{
|
||||
Vector x = i.toVector();
|
||||
double g = x.distance(v);
|
||||
|
||||
if(g < m)
|
||||
{
|
||||
m = g;
|
||||
s = i;
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
public static Direction closest(Vector v, KList<Direction> d)
|
||||
{
|
||||
double m = Double.MAX_VALUE;
|
||||
Direction s = null;
|
||||
|
||||
for(Direction i : d)
|
||||
{
|
||||
Vector x = i.toVector();
|
||||
double g = x.distance(v);
|
||||
|
||||
if(g < m)
|
||||
{
|
||||
m = g;
|
||||
s = i;
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
public Vector toVector()
|
||||
{
|
||||
return new Vector(x, y, z);
|
||||
}
|
||||
|
||||
public boolean isCrooked(Direction to)
|
||||
{
|
||||
if(equals(to.reverse()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(equals(to))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private Direction(int x, int y, int z, CuboidDirection f)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.f = f;
|
||||
}
|
||||
|
||||
public Vector angle(Vector initial, Direction d)
|
||||
{
|
||||
calculatePermutations();
|
||||
|
||||
for(GBiset<Direction, Direction> i : permute.keySet())
|
||||
{
|
||||
if(i.getA().equals(this) && i.getB().equals(d))
|
||||
{
|
||||
return permute.get(i).op(initial);
|
||||
}
|
||||
}
|
||||
|
||||
return initial;
|
||||
}
|
||||
|
||||
public Direction reverse()
|
||||
{
|
||||
switch(this)
|
||||
{
|
||||
case D:
|
||||
return U;
|
||||
case E:
|
||||
return W;
|
||||
case N:
|
||||
return S;
|
||||
case S:
|
||||
return N;
|
||||
case U:
|
||||
return D;
|
||||
case W:
|
||||
return E;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public int x()
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
public int y()
|
||||
{
|
||||
return y;
|
||||
}
|
||||
|
||||
public int z()
|
||||
{
|
||||
return z;
|
||||
}
|
||||
|
||||
public CuboidDirection f()
|
||||
{
|
||||
return f;
|
||||
}
|
||||
|
||||
public static KList<Direction> news()
|
||||
{
|
||||
return new KList<Direction>().add(N, E, W, S);
|
||||
}
|
||||
|
||||
public static Direction getDirection(Vector v)
|
||||
{
|
||||
Vector k = VectorMath.triNormalize(v.clone().normalize());
|
||||
|
||||
for(Direction i : udnews())
|
||||
{
|
||||
if(i.x == k.getBlockX() && i.y == k.getBlockY() && i.z == k.getBlockZ())
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return Direction.N;
|
||||
}
|
||||
|
||||
public static KList<Direction> udnews()
|
||||
{
|
||||
return new KList<Direction>().add(U, D, N, E, W, S);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the directional value from the given byte from common directional blocks
|
||||
* (MUST BE BETWEEN 0 and 5 INCLUSIVE)
|
||||
*
|
||||
* @param b
|
||||
* the byte
|
||||
* @return the direction or null if the byte is outside of the inclusive range
|
||||
* 0-5
|
||||
*/
|
||||
public static Direction fromByte(byte b)
|
||||
{
|
||||
if(b > 5 || b < 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if(b == 0)
|
||||
{
|
||||
return D;
|
||||
}
|
||||
|
||||
else if(b == 1)
|
||||
{
|
||||
return U;
|
||||
}
|
||||
|
||||
else if(b == 2)
|
||||
{
|
||||
return N;
|
||||
}
|
||||
|
||||
else if(b == 3)
|
||||
{
|
||||
return S;
|
||||
}
|
||||
|
||||
else if(b == 4)
|
||||
{
|
||||
return W;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
return E;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the byte value represented in some directional blocks
|
||||
*
|
||||
* @return the byte value
|
||||
*/
|
||||
public byte byteValue()
|
||||
{
|
||||
switch(this)
|
||||
{
|
||||
case D:
|
||||
return 0;
|
||||
case E:
|
||||
return 5;
|
||||
case N:
|
||||
return 2;
|
||||
case S:
|
||||
return 3;
|
||||
case U:
|
||||
return 1;
|
||||
case W:
|
||||
return 4;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static void calculatePermutations()
|
||||
{
|
||||
if(permute != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
permute = new KMap<GBiset<Direction, Direction>, DOP>();
|
||||
|
||||
for(Direction i : udnews())
|
||||
{
|
||||
for(Direction j : udnews())
|
||||
{
|
||||
GBiset<Direction, Direction> b = new GBiset<Direction, Direction>(i, j);
|
||||
|
||||
if(i.equals(j))
|
||||
{
|
||||
permute.put(b, new DOP("DIRECT")
|
||||
{
|
||||
@Override
|
||||
public Vector op(Vector v)
|
||||
{
|
||||
return v;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
else if(i.reverse().equals(j))
|
||||
{
|
||||
if(i.isVertical())
|
||||
{
|
||||
permute.put(b, new DOP("R180CCZ")
|
||||
{
|
||||
@Override
|
||||
public Vector op(Vector v)
|
||||
{
|
||||
return VectorMath.rotate90CCZ(VectorMath.rotate90CCZ(v));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
permute.put(b, new DOP("R180CCY")
|
||||
{
|
||||
@Override
|
||||
public Vector op(Vector v)
|
||||
{
|
||||
return VectorMath.rotate90CCY(VectorMath.rotate90CCY(v));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
else if(getDirection(VectorMath.rotate90CX(i.toVector())).equals(j))
|
||||
{
|
||||
permute.put(b, new DOP("R90CX")
|
||||
{
|
||||
@Override
|
||||
public Vector op(Vector v)
|
||||
{
|
||||
return VectorMath.rotate90CX(v);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
else if(getDirection(VectorMath.rotate90CCX(i.toVector())).equals(j))
|
||||
{
|
||||
permute.put(b, new DOP("R90CCX")
|
||||
{
|
||||
@Override
|
||||
public Vector op(Vector v)
|
||||
{
|
||||
return VectorMath.rotate90CCX(v);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
else if(getDirection(VectorMath.rotate90CY(i.toVector())).equals(j))
|
||||
{
|
||||
permute.put(b, new DOP("R90CY")
|
||||
{
|
||||
@Override
|
||||
public Vector op(Vector v)
|
||||
{
|
||||
return VectorMath.rotate90CY(v);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
else if(getDirection(VectorMath.rotate90CCY(i.toVector())).equals(j))
|
||||
{
|
||||
permute.put(b, new DOP("R90CCY")
|
||||
{
|
||||
@Override
|
||||
public Vector op(Vector v)
|
||||
{
|
||||
return VectorMath.rotate90CCY(v);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
else if(getDirection(VectorMath.rotate90CZ(i.toVector())).equals(j))
|
||||
{
|
||||
permute.put(b, new DOP("R90CZ")
|
||||
{
|
||||
@Override
|
||||
public Vector op(Vector v)
|
||||
{
|
||||
return VectorMath.rotate90CZ(v);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
else if(getDirection(VectorMath.rotate90CCZ(i.toVector())).equals(j))
|
||||
{
|
||||
permute.put(b, new DOP("R90CCZ")
|
||||
{
|
||||
@Override
|
||||
public Vector op(Vector v)
|
||||
{
|
||||
return VectorMath.rotate90CCZ(v);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
permute.put(b, new DOP("FAIL")
|
||||
{
|
||||
@Override
|
||||
public Vector op(Vector v)
|
||||
{
|
||||
return v;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public BlockFace getFace()
|
||||
{
|
||||
switch(this)
|
||||
{
|
||||
case D:
|
||||
return BlockFace.DOWN;
|
||||
case E:
|
||||
return BlockFace.EAST;
|
||||
case N:
|
||||
return BlockFace.NORTH;
|
||||
case S:
|
||||
return BlockFace.SOUTH;
|
||||
case U:
|
||||
return BlockFace.UP;
|
||||
case W:
|
||||
return BlockFace.WEST;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Axis getAxis()
|
||||
{
|
||||
switch(this)
|
||||
{
|
||||
case D:
|
||||
return Axis.Y;
|
||||
case E:
|
||||
return Axis.X;
|
||||
case N:
|
||||
return Axis.Z;
|
||||
case S:
|
||||
return Axis.Z;
|
||||
case U:
|
||||
return Axis.Y;
|
||||
case W:
|
||||
return Axis.X;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
161
src/main/java/ninja/bytecode/iris/util/FastParticle.java
Normal file
161
src/main/java/ninja/bytecode/iris/util/FastParticle.java
Normal file
@ -0,0 +1,161 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
/**
|
||||
* Simple Bukkit Particles API with 1.7 to 1.13.2 support !
|
||||
* <p>
|
||||
* You can find the project on <a href="https://github.com/MrMicky-FR/FastParticles">GitHub</a>
|
||||
*
|
||||
* @author MrMicky
|
||||
*/
|
||||
public final class FastParticle {
|
||||
|
||||
private static final ParticleSender PARTICLE_SENDER;
|
||||
|
||||
static {
|
||||
if (FastReflection.optionalClass("org.bukkit.Particle$DustOptions").isPresent()) {
|
||||
PARTICLE_SENDER = new ParticleSender.ParticleSender1_13();
|
||||
} else if (FastReflection.optionalClass("org.bukkit.Particle").isPresent()) {
|
||||
PARTICLE_SENDER = new ParticleSender.ParticleSenderImpl();
|
||||
} else {
|
||||
PARTICLE_SENDER = new ParticleSenderLegacy();
|
||||
}
|
||||
}
|
||||
|
||||
private FastParticle() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/*
|
||||
* Worlds methods
|
||||
*/
|
||||
public static void spawnParticle(World world, ParticleType particle, Location location, int count) {
|
||||
spawnParticle(world, particle, location.getX(), location.getY(), location.getZ(), count);
|
||||
}
|
||||
|
||||
public static void spawnParticle(World world, ParticleType particle, double x, double y, double z, int count) {
|
||||
spawnParticle(world, particle, x, y, z, count, null);
|
||||
}
|
||||
|
||||
public static <T> void spawnParticle(World world, ParticleType particle, Location location, int count, T data) {
|
||||
spawnParticle(world, particle, location.getX(), location.getY(), location.getZ(), count, data);
|
||||
}
|
||||
|
||||
public static <T> void spawnParticle(World world, ParticleType particle, double x, double y, double z, int count,
|
||||
T data) {
|
||||
spawnParticle(world, particle, x, y, z, count, 0.0D, 0.0D, 0.0D, data);
|
||||
}
|
||||
|
||||
public static void spawnParticle(World world, ParticleType particle, Location location, int count, double offsetX,
|
||||
double offsetY, double offsetZ) {
|
||||
spawnParticle(world, particle, location.getX(), location.getY(), location.getZ(), count, offsetX, offsetY, offsetZ);
|
||||
}
|
||||
|
||||
public static void spawnParticle(World world, ParticleType particle, double x, double y, double z, int count,
|
||||
double offsetX, double offsetY, double offsetZ) {
|
||||
spawnParticle(world, particle, x, y, z, count, offsetX, offsetY, offsetZ, null);
|
||||
}
|
||||
|
||||
public static <T> void spawnParticle(World world, ParticleType particle, Location location, int count,
|
||||
double offsetX, double offsetY, double offsetZ, T data) {
|
||||
spawnParticle(world, particle, location.getX(), location.getY(), location.getZ(), count, offsetX, offsetY,
|
||||
offsetZ, data);
|
||||
}
|
||||
|
||||
public static <T> void spawnParticle(World world, ParticleType particle, double x, double y, double z, int count,
|
||||
double offsetX, double offsetY, double offsetZ, T data) {
|
||||
spawnParticle(world, particle, x, y, z, count, offsetX, offsetY, offsetZ, 1.0D, data);
|
||||
}
|
||||
|
||||
public static void spawnParticle(World world, ParticleType particle, Location location, int count, double offsetX,
|
||||
double offsetY, double offsetZ, double extra) {
|
||||
spawnParticle(world, particle, location.getX(), location.getY(), location.getZ(), count, offsetX, offsetY, offsetZ, extra);
|
||||
}
|
||||
|
||||
public static void spawnParticle(World world, ParticleType particle, double x, double y, double z, int count,
|
||||
double offsetX, double offsetY, double offsetZ, double extra) {
|
||||
spawnParticle(world, particle, x, y, z, count, offsetX, offsetY, offsetZ, extra, null);
|
||||
}
|
||||
|
||||
public static <T> void spawnParticle(World world, ParticleType particle, Location location, int count,
|
||||
double offsetX, double offsetY, double offsetZ, double extra, T data) {
|
||||
spawnParticle(world, particle, location.getX(), location.getY(), location.getZ(), count, offsetX, offsetY, offsetZ, extra, data);
|
||||
}
|
||||
|
||||
public static <T> void spawnParticle(World world, ParticleType particle, double x, double y, double z, int count,
|
||||
double offsetX, double offsetY, double offsetZ, double extra, T data) {
|
||||
sendParticle(world, particle, x, y, z, count, offsetX, offsetY, offsetZ, extra, data);
|
||||
}
|
||||
|
||||
/*
|
||||
* Player methods
|
||||
*/
|
||||
public static void spawnParticle(Player player, ParticleType particle, Location location, int count) {
|
||||
spawnParticle(player, particle, location.getX(), location.getY(), location.getZ(), count);
|
||||
}
|
||||
|
||||
public static void spawnParticle(Player player, ParticleType particle, double x, double y, double z, int count) {
|
||||
spawnParticle(player, particle, x, y, z, count, null);
|
||||
}
|
||||
|
||||
public static <T> void spawnParticle(Player player, ParticleType particle, Location location, int count, T data) {
|
||||
spawnParticle(player, particle, location.getX(), location.getY(), location.getZ(), count, data);
|
||||
}
|
||||
|
||||
public static <T> void spawnParticle(Player player, ParticleType particle, double x, double y, double z, int count,
|
||||
T data) {
|
||||
spawnParticle(player, particle, x, y, z, count, 0.0D, 0.0D, 0.0D, data);
|
||||
}
|
||||
|
||||
public static void spawnParticle(Player player, ParticleType particle, Location location, int count, double offsetX,
|
||||
double offsetY, double offsetZ) {
|
||||
spawnParticle(player, particle, location.getX(), location.getY(), location.getZ(), count, offsetX, offsetY, offsetZ);
|
||||
}
|
||||
|
||||
public static void spawnParticle(Player player, ParticleType particle, double x, double y, double z, int count,
|
||||
double offsetX, double offsetY, double offsetZ) {
|
||||
spawnParticle(player, particle, x, y, z, count, offsetX, offsetY, offsetZ, null);
|
||||
}
|
||||
|
||||
public static <T> void spawnParticle(Player player, ParticleType particle, Location location, int count,
|
||||
double offsetX, double offsetY, double offsetZ, T data) {
|
||||
spawnParticle(player, particle, location.getX(), location.getY(), location.getZ(), count, offsetX, offsetY, offsetZ, data);
|
||||
}
|
||||
|
||||
public static <T> void spawnParticle(Player player, ParticleType particle, double x, double y, double z, int count,
|
||||
double offsetX, double offsetY, double offsetZ, T data) {
|
||||
spawnParticle(player, particle, x, y, z, count, offsetX, offsetY, offsetZ, 1.0D, data);
|
||||
}
|
||||
|
||||
public static void spawnParticle(Player player, ParticleType particle, Location location, int count, double offsetX,
|
||||
double offsetY, double offsetZ, double extra) {
|
||||
spawnParticle(player, particle, location.getX(), location.getY(), location.getZ(), count, offsetX, offsetY, offsetZ, extra);
|
||||
}
|
||||
|
||||
public static void spawnParticle(Player player, ParticleType particle, double x, double y, double z, int count,
|
||||
double offsetX, double offsetY, double offsetZ, double extra) {
|
||||
spawnParticle(player, particle, x, y, z, count, offsetX, offsetY, offsetZ, extra, null);
|
||||
}
|
||||
|
||||
public static <T> void spawnParticle(Player player, ParticleType particle, Location location, int count,
|
||||
double offsetX, double offsetY, double offsetZ, double extra, T data) {
|
||||
spawnParticle(player, particle, location.getX(), location.getY(), location.getZ(), count, offsetX, offsetY, offsetZ, extra, data);
|
||||
}
|
||||
|
||||
public static <T> void spawnParticle(Player player, ParticleType particle, double x, double y, double z, int count,
|
||||
double offsetX, double offsetY, double offsetZ, double extra, T data) {
|
||||
sendParticle(player, particle, x, y, z, count, offsetX, offsetY, offsetZ, extra, data);
|
||||
}
|
||||
|
||||
private static void sendParticle(Object receiver, ParticleType particle, double x, double y, double z, int count,
|
||||
double offsetX, double offsetY, double offsetZ, double extra, Object data) {
|
||||
if (!particle.isSupported()) {
|
||||
throw new IllegalArgumentException("The particle '" + particle + "' is not compatible with your server version");
|
||||
}
|
||||
|
||||
PARTICLE_SENDER.spawnParticle(receiver, particle, x, y, z, count, offsetX, offsetY, offsetZ, extra, data);
|
||||
}
|
||||
}
|
59
src/main/java/ninja/bytecode/iris/util/FastReflection.java
Normal file
59
src/main/java/ninja/bytecode/iris/util/FastReflection.java
Normal file
@ -0,0 +1,59 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Small reflection class to use CraftBukkit and NMS
|
||||
*
|
||||
* @author MrMicky
|
||||
*/
|
||||
public final class FastReflection {
|
||||
|
||||
public static final String OBC_PACKAGE = "org.bukkit.craftbukkit";
|
||||
public static final String NMS_PACKAGE = "net.minecraft.server";
|
||||
|
||||
public static final String VERSION = Bukkit.getServer().getClass().getPackage().getName().substring(OBC_PACKAGE.length() + 1);
|
||||
|
||||
private FastReflection() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public static String nmsClassName(String className) {
|
||||
return NMS_PACKAGE + '.' + VERSION + '.' + className;
|
||||
}
|
||||
|
||||
public static Class<?> nmsClass(String className) throws ClassNotFoundException {
|
||||
return Class.forName(nmsClassName(className));
|
||||
}
|
||||
|
||||
public static Optional<Class<?>> nmsOptionalClass(String className) {
|
||||
return optionalClass(nmsClassName(className));
|
||||
}
|
||||
|
||||
public static String obcClassName(String className) {
|
||||
return OBC_PACKAGE + '.' + VERSION + '.' + className;
|
||||
}
|
||||
|
||||
public static Class<?> obcClass(String className) throws ClassNotFoundException {
|
||||
return Class.forName(obcClassName(className));
|
||||
}
|
||||
|
||||
public static Optional<Class<?>> obcOptionalClass(String className) {
|
||||
return optionalClass(obcClassName(className));
|
||||
}
|
||||
|
||||
public static Optional<Class<?>> optionalClass(String className) {
|
||||
try {
|
||||
return Optional.of(Class.forName(className));
|
||||
} catch (ClassNotFoundException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public static Object enumValueOf(Class<?> enumClass, String enumName) {
|
||||
return Enum.valueOf((Class<Enum>) enumClass, enumName.toUpperCase());
|
||||
}
|
||||
}
|
77
src/main/java/ninja/bytecode/iris/util/GBiset.java
Normal file
77
src/main/java/ninja/bytecode/iris/util/GBiset.java
Normal file
@ -0,0 +1,77 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* A Biset
|
||||
*
|
||||
* @author cyberpwn
|
||||
*
|
||||
* @param <A>
|
||||
* the first object type
|
||||
* @param <B>
|
||||
* the second object type
|
||||
*/
|
||||
@SuppressWarnings("hiding")
|
||||
public class GBiset<A, B> implements Serializable
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
private A a;
|
||||
private B b;
|
||||
|
||||
/**
|
||||
* Create a new Biset
|
||||
*
|
||||
* @param a
|
||||
* the first object
|
||||
* @param b
|
||||
* the second object
|
||||
*/
|
||||
public GBiset(A a, B b)
|
||||
{
|
||||
this.a = a;
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the object of the type A
|
||||
*
|
||||
* @return the first object
|
||||
*/
|
||||
public A getA()
|
||||
{
|
||||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the first object
|
||||
*
|
||||
* @param a
|
||||
* the first object A
|
||||
*/
|
||||
public void setA(A a)
|
||||
{
|
||||
this.a = a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the second object
|
||||
*
|
||||
* @return the second object
|
||||
*/
|
||||
public B getB()
|
||||
{
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the second object
|
||||
*
|
||||
* @param b
|
||||
*/
|
||||
public void setB(B b)
|
||||
{
|
||||
this.b = b;
|
||||
}
|
||||
}
|
51
src/main/java/ninja/bytecode/iris/util/GListAdapter.java
Normal file
51
src/main/java/ninja/bytecode/iris/util/GListAdapter.java
Normal file
@ -0,0 +1,51 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
|
||||
/**
|
||||
* Adapts a list of objects into a list of other objects
|
||||
*
|
||||
* @author cyberpwn
|
||||
* @param <FROM>
|
||||
* the from object in lists (the item INSIDE the list)
|
||||
* @param <TO>
|
||||
* the to object in lists (the item INSIDE the list)
|
||||
*/
|
||||
public abstract class GListAdapter<FROM, TO>
|
||||
{
|
||||
/**
|
||||
* Adapts a list of FROM to a list of TO
|
||||
*
|
||||
* @param from
|
||||
* the from list
|
||||
* @return the to list
|
||||
*/
|
||||
public List<TO> adapt(List<FROM> from)
|
||||
{
|
||||
List<TO> adapted = new KList<TO>();
|
||||
|
||||
for(FROM i : from)
|
||||
{
|
||||
TO t = onAdapt(i);
|
||||
|
||||
if(t != null)
|
||||
{
|
||||
adapted.add(onAdapt(i));
|
||||
}
|
||||
}
|
||||
|
||||
return adapted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapts a list object FROM to TO for use with the adapt method
|
||||
*
|
||||
* @param from
|
||||
* the from object
|
||||
* @return the to object
|
||||
*/
|
||||
public abstract TO onAdapt(FROM from);
|
||||
}
|
12
src/main/java/ninja/bytecode/iris/util/IObjectPlacer.java
Normal file
12
src/main/java/ninja/bytecode/iris/util/IObjectPlacer.java
Normal file
@ -0,0 +1,12 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
public interface IObjectPlacer
|
||||
{
|
||||
public int getHighest(int x, int z);
|
||||
|
||||
public void set(int x, int y, int z, BlockData d);
|
||||
|
||||
public BlockData get(int x, int y, int z);
|
||||
}
|
104
src/main/java/ninja/bytecode/iris/util/ObjectResourceLoader.java
Normal file
104
src/main/java/ninja/bytecode/iris/util/ObjectResourceLoader.java
Normal file
@ -0,0 +1,104 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.bukkit.util.BlockVector;
|
||||
|
||||
import ninja.bytecode.iris.Iris;
|
||||
import ninja.bytecode.iris.object.IrisObject;
|
||||
|
||||
public class ObjectResourceLoader extends ResourceLoader<IrisObject>
|
||||
{
|
||||
private ChunkPosition parallaxSize;
|
||||
|
||||
public ObjectResourceLoader(File root, String folderName, String resourceTypeName)
|
||||
{
|
||||
super(root, folderName, resourceTypeName, IrisObject.class);
|
||||
}
|
||||
|
||||
public ChunkPosition getParallaxSize()
|
||||
{
|
||||
lock.lock();
|
||||
if(parallaxSize == null)
|
||||
{
|
||||
int x = 0;
|
||||
int z = 0;
|
||||
|
||||
for(File i : getFolders())
|
||||
{
|
||||
for(File j : i.listFiles())
|
||||
{
|
||||
if(j.isFile() && j.getName().endsWith(".iob"))
|
||||
{
|
||||
try
|
||||
{
|
||||
BlockVector b = IrisObject.sampleSize(j);
|
||||
x = b.getBlockX() > x ? b.getBlockX() : x;
|
||||
z = b.getBlockZ() > z ? b.getBlockZ() : z;
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
x = (Math.max(x, 16) + 16) >> 4;
|
||||
z = (Math.max(z, 16) + 16) >> 4;
|
||||
x = x % 2 == 0 ? x + 1 : x;
|
||||
z = z % 2 == 0 ? z + 1 : z;
|
||||
parallaxSize = new ChunkPosition(x, z);
|
||||
Iris.info("Parallax View Distance: " + x + "x" + z);
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
|
||||
return parallaxSize;
|
||||
}
|
||||
|
||||
public IrisObject load(String name)
|
||||
{
|
||||
String key = name + "-" + objectClass.getCanonicalName();
|
||||
|
||||
if(loadCache.containsKey(key))
|
||||
{
|
||||
IrisObject t = loadCache.get(key);
|
||||
return t;
|
||||
}
|
||||
|
||||
lock.lock();
|
||||
for(File i : getFolders())
|
||||
{
|
||||
for(File j : i.listFiles())
|
||||
{
|
||||
if(j.isFile() && j.getName().endsWith(".iob") && j.getName().split("\\Q.\\E")[0].equals(name))
|
||||
{
|
||||
try
|
||||
{
|
||||
IrisObject t = new IrisObject(0, 0, 0);
|
||||
t.read(j);
|
||||
loadCache.put(key, t);
|
||||
Iris.hotloader.track(j);
|
||||
Iris.info("Loading " + resourceTypeName + ": " + j.getPath());
|
||||
t.setLoadKey(name);
|
||||
lock.unlock();
|
||||
return t;
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
lock.unlock();
|
||||
Iris.warn("Couldn't read " + resourceTypeName + " file: " + j.getPath() + ": " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Iris.warn("Couldn't find " + resourceTypeName + ": " + name);
|
||||
|
||||
lock.unlock();
|
||||
return null;
|
||||
}
|
||||
}
|
130
src/main/java/ninja/bytecode/iris/util/ParticleSender.java
Normal file
130
src/main/java/ninja/bytecode/iris/util/ParticleSender.java
Normal file
@ -0,0 +1,130 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Color;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.material.MaterialData;
|
||||
|
||||
/**
|
||||
* Particle sender using the Bukkit particles API for 1.9+ servers
|
||||
*
|
||||
* @author MrMicky
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
interface ParticleSender
|
||||
{
|
||||
|
||||
void spawnParticle(Object receiver, ParticleType particle, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, Object data);
|
||||
|
||||
Object getParticle(ParticleType particle);
|
||||
|
||||
boolean isValidData(Object particle, Object data);
|
||||
|
||||
default double color(double color)
|
||||
{
|
||||
return color / 255.0;
|
||||
}
|
||||
|
||||
class ParticleSenderImpl implements ParticleSender
|
||||
{
|
||||
|
||||
@Override
|
||||
public void spawnParticle(Object receiver, ParticleType particle, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, Object data)
|
||||
{
|
||||
Particle bukkitParticle = Particle.valueOf(particle.toString());
|
||||
|
||||
if(data instanceof Color)
|
||||
{
|
||||
if(particle.getDataType() == Color.class)
|
||||
{
|
||||
Color color = (Color) data;
|
||||
count = 0;
|
||||
offsetX = color(color.getRed());
|
||||
offsetY = color(color.getGreen());
|
||||
offsetZ = color(color.getBlue());
|
||||
extra = 1.0;
|
||||
}
|
||||
data = null;
|
||||
}
|
||||
|
||||
if(receiver instanceof World)
|
||||
{
|
||||
((World) receiver).spawnParticle(bukkitParticle, x, y, z, count, offsetX, offsetY, offsetZ, extra, data);
|
||||
}
|
||||
else if(receiver instanceof Player)
|
||||
{
|
||||
((Player) receiver).spawnParticle(bukkitParticle, x, y, z, count, offsetX, offsetY, offsetZ, extra, data);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Particle getParticle(ParticleType particle)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Particle.valueOf(particle.toString());
|
||||
}
|
||||
catch(IllegalArgumentException e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidData(Object particle, Object data)
|
||||
{
|
||||
return isValidDataBukkit((Particle) particle, data);
|
||||
}
|
||||
|
||||
public boolean isValidDataBukkit(Particle particle, Object data)
|
||||
{
|
||||
return particle.getDataType() == Void.class || particle.getDataType().isInstance(data);
|
||||
}
|
||||
}
|
||||
|
||||
class ParticleSender1_13 extends ParticleSenderImpl
|
||||
{
|
||||
@Override
|
||||
public void spawnParticle(Object receiver, ParticleType particle, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, Object data)
|
||||
{
|
||||
Particle bukkitParticle = Particle.valueOf(particle.toString());
|
||||
|
||||
if(bukkitParticle.getDataType() == Particle.DustOptions.class)
|
||||
{
|
||||
if(data instanceof Color)
|
||||
{
|
||||
data = new Particle.DustOptions((Color) data, 1);
|
||||
}
|
||||
else if(data == null)
|
||||
{
|
||||
data = new Particle.DustOptions(Color.RED, 1);
|
||||
}
|
||||
}
|
||||
else if(bukkitParticle.getDataType() == BlockData.class && data instanceof MaterialData)
|
||||
{
|
||||
data = Bukkit.createBlockData(((MaterialData) data).getItemType());
|
||||
}
|
||||
|
||||
super.spawnParticle(receiver, particle, x, y, z, count, offsetX, offsetY, offsetZ, extra, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidDataBukkit(Particle particle, Object data)
|
||||
{
|
||||
if(particle.getDataType() == Particle.DustOptions.class && data instanceof Color)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if(particle.getDataType() == BlockData.class && data instanceof MaterialData)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.isValidDataBukkit(particle, data);
|
||||
}
|
||||
}
|
||||
}
|
166
src/main/java/ninja/bytecode/iris/util/ParticleSenderLegacy.java
Normal file
166
src/main/java/ninja/bytecode/iris/util/ParticleSenderLegacy.java
Normal file
@ -0,0 +1,166 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import org.bukkit.Color;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.material.MaterialData;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Legacy particle sender with NMS for 1.7/1.8 servers
|
||||
*
|
||||
* @author MrMicky
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
class ParticleSenderLegacy implements ParticleSender {
|
||||
|
||||
private static final boolean SERVER_IS_1_8;
|
||||
|
||||
private static final Constructor<?> PACKET_PARTICLE;
|
||||
private static final Class<?> ENUM_PARTICLE;
|
||||
|
||||
private static final Method WORLD_GET_HANDLE;
|
||||
private static final Method WORLD_SEND_PARTICLE;
|
||||
|
||||
private static final Method PLAYER_GET_HANDLE;
|
||||
private static final Field PLAYER_CONNECTION;
|
||||
private static final Method SEND_PACKET;
|
||||
private static final int[] EMPTY = new int[0];
|
||||
|
||||
static {
|
||||
ENUM_PARTICLE = FastReflection.nmsOptionalClass("EnumParticle").orElse(null);
|
||||
SERVER_IS_1_8 = ENUM_PARTICLE != null;
|
||||
|
||||
try {
|
||||
Class<?> packetParticleClass = FastReflection.nmsClass("PacketPlayOutWorldParticles");
|
||||
Class<?> playerClass = FastReflection.nmsClass("EntityPlayer");
|
||||
Class<?> playerConnectionClass = FastReflection.nmsClass("PlayerConnection");
|
||||
Class<?> worldClass = FastReflection.nmsClass("WorldServer");
|
||||
Class<?> entityPlayerClass = FastReflection.nmsClass("EntityPlayer");
|
||||
|
||||
Class<?> craftPlayerClass = FastReflection.obcClass("entity.CraftPlayer");
|
||||
Class<?> craftWorldClass = FastReflection.obcClass("CraftWorld");
|
||||
|
||||
if (SERVER_IS_1_8) {
|
||||
PACKET_PARTICLE = packetParticleClass.getConstructor(ENUM_PARTICLE, boolean.class, float.class,
|
||||
float.class, float.class, float.class, float.class, float.class, float.class, int.class,
|
||||
int[].class);
|
||||
WORLD_SEND_PARTICLE = worldClass.getDeclaredMethod("sendParticles", entityPlayerClass, ENUM_PARTICLE,
|
||||
boolean.class, double.class, double.class, double.class, int.class, double.class, double.class,
|
||||
double.class, double.class, int[].class);
|
||||
} else {
|
||||
PACKET_PARTICLE = packetParticleClass.getConstructor(String.class, float.class, float.class, float.class,
|
||||
float.class, float.class, float.class, float.class, int.class);
|
||||
WORLD_SEND_PARTICLE = worldClass.getDeclaredMethod("a", String.class, double.class, double.class,
|
||||
double.class, int.class, double.class, double.class, double.class, double.class);
|
||||
}
|
||||
|
||||
WORLD_GET_HANDLE = craftWorldClass.getDeclaredMethod("getHandle");
|
||||
PLAYER_GET_HANDLE = craftPlayerClass.getDeclaredMethod("getHandle");
|
||||
PLAYER_CONNECTION = playerClass.getField("playerConnection");
|
||||
SEND_PACKET = playerConnectionClass.getMethod("sendPacket", FastReflection.nmsClass("Packet"));
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new ExceptionInInitializerError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void spawnParticle(Object receiver, ParticleType particle, double x, double y, double z, int count, double offsetX, double offsetY,
|
||||
double offsetZ, double extra, Object data) {
|
||||
try {
|
||||
int[] datas = toData(particle, data);
|
||||
|
||||
if (data instanceof Color) {
|
||||
if (particle.getDataType() == Color.class) {
|
||||
Color color = (Color) data;
|
||||
count = 0;
|
||||
offsetX = color(color.getRed());
|
||||
offsetY = color(color.getGreen());
|
||||
offsetZ = color(color.getBlue());
|
||||
extra = 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
if (receiver instanceof World) {
|
||||
Object worldServer = WORLD_GET_HANDLE.invoke(receiver);
|
||||
|
||||
if (SERVER_IS_1_8) {
|
||||
WORLD_SEND_PARTICLE.invoke(worldServer, null, getEnumParticle(particle), true, x, y, z, count, offsetX, offsetY, offsetZ, extra, datas);
|
||||
} else {
|
||||
String particleName = particle.getLegacyName() + (datas.length != 2 ? "" : "_" + datas[0] + "_" + datas[1]);
|
||||
WORLD_SEND_PARTICLE.invoke(worldServer, particleName, x, y, z, count, offsetX, offsetY, offsetZ, extra);
|
||||
}
|
||||
} else if (receiver instanceof Player) {
|
||||
Object packet;
|
||||
|
||||
if (SERVER_IS_1_8) {
|
||||
packet = PACKET_PARTICLE.newInstance(getEnumParticle(particle), true, (float) x, (float) y,
|
||||
(float) z, (float) offsetX, (float) offsetY, (float) offsetZ, (float) extra, count, datas);
|
||||
} else {
|
||||
String particleName = particle.getLegacyName() + (datas.length != 2 ? "" : "_" + datas[0] + "_" + datas[1]);
|
||||
packet = PACKET_PARTICLE.newInstance(particleName, (float) x, (float) y, (float) z,
|
||||
(float) offsetX, (float) offsetY, (float) offsetZ, (float) extra, count);
|
||||
}
|
||||
|
||||
Object entityPlayer = PLAYER_GET_HANDLE.invoke(receiver);
|
||||
Object playerConnection = PLAYER_CONNECTION.get(entityPlayer);
|
||||
SEND_PACKET.invoke(playerConnection, packet);
|
||||
}
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidData(Object particle, Object data) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getParticle(ParticleType particle) {
|
||||
if (!SERVER_IS_1_8) {
|
||||
return particle.getLegacyName();
|
||||
}
|
||||
|
||||
try {
|
||||
return getEnumParticle(particle);
|
||||
} catch (IllegalArgumentException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Object getEnumParticle(ParticleType particleType) {
|
||||
return FastReflection.enumValueOf(ENUM_PARTICLE, particleType.toString());
|
||||
}
|
||||
|
||||
private int[] toData(ParticleType particle, Object data) {
|
||||
Class<?> dataType = particle.getDataType();
|
||||
if (dataType == ItemStack.class) {
|
||||
if (!(data instanceof ItemStack)) {
|
||||
return SERVER_IS_1_8 ? new int[2] : new int[]{1, 0};
|
||||
}
|
||||
|
||||
ItemStack itemStack = (ItemStack) data;
|
||||
return new int[]{itemStack.getType().getId(), itemStack.getDurability()};
|
||||
}
|
||||
|
||||
if (dataType == MaterialData.class) {
|
||||
if (!(data instanceof MaterialData)) {
|
||||
return SERVER_IS_1_8 ? new int[1] : new int[]{1, 0};
|
||||
}
|
||||
|
||||
MaterialData materialData = (MaterialData) data;
|
||||
if (SERVER_IS_1_8) {
|
||||
return new int[]{materialData.getItemType().getId() + (materialData.getData() << 12)};
|
||||
} else {
|
||||
return new int[]{materialData.getItemType().getId(), materialData.getData()};
|
||||
}
|
||||
}
|
||||
|
||||
return EMPTY;
|
||||
}
|
||||
}
|
177
src/main/java/ninja/bytecode/iris/util/ParticleType.java
Normal file
177
src/main/java/ninja/bytecode/iris/util/ParticleType.java
Normal file
@ -0,0 +1,177 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import org.bukkit.Color;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.material.MaterialData;
|
||||
|
||||
/**
|
||||
* @author MrMicky
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public enum ParticleType {
|
||||
|
||||
// 1.7+
|
||||
EXPLOSION_NORMAL("explode", "poof"),
|
||||
EXPLOSION_LARGE("largeexplode", "explosion"),
|
||||
EXPLOSION_HUGE("hugeexplosion", "explosion_emitter"),
|
||||
FIREWORKS_SPARK("fireworksSpark", "firework"),
|
||||
WATER_BUBBLE("bubble", "bubble"),
|
||||
WATER_SPLASH("splash", "splash"),
|
||||
WATER_WAKE("wake", "fishing"),
|
||||
SUSPENDED("suspended", "underwater"),
|
||||
SUSPENDED_DEPTH("depthsuspend", "underwater"),
|
||||
CRIT("crit", "crit"),
|
||||
CRIT_MAGIC("magicCrit", "enchanted_hit"),
|
||||
SMOKE_NORMAL("smoke", "smoke"),
|
||||
SMOKE_LARGE("largesmoke", "large_smoke"),
|
||||
SPELL("spell", "effect"),
|
||||
SPELL_INSTANT("instantSpell", "instant_effect"),
|
||||
SPELL_MOB("mobSpell", "entity_effect"),
|
||||
SPELL_MOB_AMBIENT("mobSpellAmbient", "ambient_entity_effect"),
|
||||
SPELL_WITCH("witchMagic", "witch"),
|
||||
DRIP_WATER("dripWater", "dripping_water"),
|
||||
DRIP_LAVA("dripLava", "dripping_lava"),
|
||||
VILLAGER_ANGRY("angryVillager", "angry_villager"),
|
||||
VILLAGER_HAPPY("happyVillager", "happy_villager"),
|
||||
TOWN_AURA("townaura", "mycelium"),
|
||||
NOTE("note", "note"),
|
||||
PORTAL("portal", "portal"),
|
||||
ENCHANTMENT_TABLE("enchantmenttable", "enchant"),
|
||||
FLAME("flame", "flame"),
|
||||
LAVA("lava", "lava"),
|
||||
// FOOTSTEP("footstep", null),
|
||||
CLOUD("cloud", "cloud"),
|
||||
REDSTONE("reddust", "dust"),
|
||||
SNOWBALL("snowballpoof", "item_snowball"),
|
||||
SNOW_SHOVEL("snowshovel", "item_snowball"),
|
||||
SLIME("slime", "item_slime"),
|
||||
HEART("heart", "heart"),
|
||||
ITEM_CRACK("iconcrack", "item"),
|
||||
BLOCK_CRACK("blockcrack", "block"),
|
||||
BLOCK_DUST("blockdust", "block"),
|
||||
|
||||
// 1.8+
|
||||
BARRIER("barrier", "barrier", 8),
|
||||
WATER_DROP("droplet", "rain", 8),
|
||||
MOB_APPEARANCE("mobappearance", "elder_guardian", 8),
|
||||
// ITEM_TAKE("take", null, 8),
|
||||
|
||||
// 1.9+
|
||||
DRAGON_BREATH("dragonbreath", "dragon_breath", 9),
|
||||
END_ROD("endRod", "end_rod", 9),
|
||||
DAMAGE_INDICATOR("damageIndicator", "damage_indicator", 9),
|
||||
SWEEP_ATTACK("sweepAttack", "sweep_attack", 9),
|
||||
|
||||
// 1.10+
|
||||
FALLING_DUST("fallingdust", "falling_dust", 10),
|
||||
|
||||
// 1.11+
|
||||
TOTEM("totem", "totem_of_undying", 11),
|
||||
SPIT("spit", "spit", 11),
|
||||
|
||||
// 1.13+
|
||||
SQUID_INK(13),
|
||||
BUBBLE_POP(13),
|
||||
CURRENT_DOWN(13),
|
||||
BUBBLE_COLUMN_UP(13),
|
||||
NAUTILUS(13),
|
||||
DOLPHIN(13),
|
||||
|
||||
// 1.14+
|
||||
SNEEZE(14),
|
||||
CAMPFIRE_COSY_SMOKE(14),
|
||||
CAMPFIRE_SIGNAL_SMOKE(14),
|
||||
COMPOSTER(14),
|
||||
FLASH(14),
|
||||
FALLING_LAVA(14),
|
||||
LANDING_LAVA(14),
|
||||
FALLING_WATER(14),
|
||||
|
||||
// 1.15+
|
||||
DRIPPING_HONEY(15),
|
||||
FALLING_HONEY(15),
|
||||
LANDING_HONEY(15),
|
||||
FALLING_NECTAR(15);
|
||||
|
||||
private static final int SERVER_VERSION_ID;
|
||||
|
||||
static {
|
||||
String ver = FastReflection.VERSION;
|
||||
SERVER_VERSION_ID = ver.charAt(4) == '_' ? Character.getNumericValue(ver.charAt(3)) : Integer.parseInt(ver.substring(3, 5));
|
||||
}
|
||||
|
||||
private final String legacyName;
|
||||
private final String name;
|
||||
private final int minimumVersion;
|
||||
|
||||
// 1.7 particles
|
||||
ParticleType(String legacyName, String name) {
|
||||
this(legacyName, name, -1);
|
||||
}
|
||||
|
||||
// 1.13+ particles
|
||||
ParticleType(int minimumVersion) {
|
||||
this.legacyName = null;
|
||||
this.name = name().toLowerCase();
|
||||
this.minimumVersion = minimumVersion;
|
||||
}
|
||||
|
||||
// 1.8-1.12 particles
|
||||
ParticleType(String legacyName, String name, int minimumVersion) {
|
||||
this.legacyName = legacyName;
|
||||
this.name = name;
|
||||
this.minimumVersion = minimumVersion;
|
||||
}
|
||||
|
||||
public boolean hasLegacyName() {
|
||||
return legacyName != null;
|
||||
}
|
||||
|
||||
public String getLegacyName() {
|
||||
if (!hasLegacyName()) {
|
||||
throw new IllegalStateException("Particle " + name() + " don't have legacy name");
|
||||
}
|
||||
return legacyName;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public boolean isSupported() {
|
||||
return minimumVersion <= 0 || SERVER_VERSION_ID >= minimumVersion;
|
||||
}
|
||||
|
||||
public Class<?> getDataType() {
|
||||
switch (this) {
|
||||
case ITEM_CRACK:
|
||||
return ItemStack.class;
|
||||
case BLOCK_CRACK:
|
||||
case BLOCK_DUST:
|
||||
case FALLING_DUST:
|
||||
//noinspection deprecation
|
||||
return MaterialData.class;
|
||||
case REDSTONE:
|
||||
return Color.class;
|
||||
default:
|
||||
return Void.class;
|
||||
}
|
||||
}
|
||||
|
||||
public static ParticleType getParticle(String particleName) {
|
||||
try {
|
||||
return ParticleType.valueOf(particleName.toUpperCase());
|
||||
} catch (IllegalArgumentException e) {
|
||||
for (ParticleType particle : values()) {
|
||||
if (particle.getName().equalsIgnoreCase(particleName)) {
|
||||
return particle;
|
||||
}
|
||||
|
||||
if (particle.hasLegacyName() && particle.getLegacyName().equalsIgnoreCase(particleName)) {
|
||||
return particle;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -12,13 +12,13 @@ import ninja.bytecode.shuriken.collections.KMap;
|
||||
|
||||
public class ResourceLoader<T extends IrisRegisteredObject>
|
||||
{
|
||||
private File root;
|
||||
private String folderName;
|
||||
private String resourceTypeName;
|
||||
private KMap<String, T> loadCache;
|
||||
private KList<File> folderCache;
|
||||
private Class<? extends T> objectClass;
|
||||
private ReentrantLock lock;
|
||||
protected File root;
|
||||
protected String folderName;
|
||||
protected String resourceTypeName;
|
||||
protected KMap<String, T> loadCache;
|
||||
protected KList<File> folderCache;
|
||||
protected Class<? extends T> objectClass;
|
||||
protected ReentrantLock lock;
|
||||
|
||||
public ResourceLoader(File root, String folderName, String resourceTypeName, Class<? extends T> objectClass)
|
||||
{
|
||||
|
755
src/main/java/ninja/bytecode/iris/util/VectorMath.java
Normal file
755
src/main/java/ninja/bytecode/iris/util/VectorMath.java
Normal file
@ -0,0 +1,755 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import org.bukkit.Axis;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
import ninja.bytecode.shuriken.format.Form;
|
||||
|
||||
/**
|
||||
* Vector utilities
|
||||
*
|
||||
* @author cyberpwn
|
||||
*/
|
||||
public class VectorMath
|
||||
{
|
||||
public static Vector scaleStatic(Axis x, Vector v, double amt)
|
||||
{
|
||||
switch(x)
|
||||
{
|
||||
case X:
|
||||
return scaleX(v, amt);
|
||||
case Y:
|
||||
return scaleY(v, amt);
|
||||
case Z:
|
||||
return scaleZ(v, amt);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Vector scaleX(Vector v, double amt)
|
||||
{
|
||||
double x = v.getX();
|
||||
double y = v.getY();
|
||||
double z = v.getZ();
|
||||
double rx = x == 0 ? 1 : amt / x;
|
||||
|
||||
return new Vector(x * rx, y * rx, z * rx);
|
||||
}
|
||||
|
||||
public static Vector scaleY(Vector v, double amt)
|
||||
{
|
||||
double x = v.getX();
|
||||
double y = v.getY();
|
||||
double z = v.getZ();
|
||||
double rx = y == 0 ? 1 : amt / y;
|
||||
|
||||
return new Vector(x * rx, y * rx, z * rx);
|
||||
}
|
||||
|
||||
public static Vector scaleZ(Vector v, double amt)
|
||||
{
|
||||
double x = v.getX();
|
||||
double y = v.getY();
|
||||
double z = v.getZ();
|
||||
double rx = z == 0 ? 1 : amt / z;
|
||||
|
||||
return new Vector(x * rx, y * rx, z * rx);
|
||||
}
|
||||
|
||||
public static Vector reverseXZ(Vector v)
|
||||
{
|
||||
v.setX(-v.getX());
|
||||
v.setZ(-v.getZ());
|
||||
return v;
|
||||
}
|
||||
|
||||
public static boolean isLookingNear(Location a, Location b, double maxOff)
|
||||
{
|
||||
Vector perfect = VectorMath.direction(a, b);
|
||||
Vector actual = a.getDirection();
|
||||
|
||||
return perfect.distance(actual) <= maxOff;
|
||||
}
|
||||
|
||||
public static Vector rotate(Direction current, Direction to, Vector v)
|
||||
{
|
||||
if(current.equals(to))
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
else if(current.equals(to.reverse()))
|
||||
{
|
||||
if(current.isVertical())
|
||||
{
|
||||
return new Vector(v.getX(), -v.getY(), v.getZ());
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
return new Vector(-v.getX(), v.getY(), -v.getZ());
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
Vector c = current.toVector().clone().add(to.toVector());
|
||||
|
||||
if(c.getX() == 0)
|
||||
{
|
||||
if(c.getY() != c.getZ())
|
||||
{
|
||||
return rotate90CX(v);
|
||||
}
|
||||
|
||||
return rotate90CCX(v);
|
||||
}
|
||||
|
||||
else if(c.getY() == 0)
|
||||
{
|
||||
if(c.getX() != c.getZ())
|
||||
{
|
||||
return rotate90CY(v);
|
||||
}
|
||||
|
||||
return rotate90CCY(v);
|
||||
}
|
||||
|
||||
else if(c.getZ() == 0)
|
||||
{
|
||||
if(c.getX() != c.getY())
|
||||
{
|
||||
return rotate90CZ(v);
|
||||
}
|
||||
|
||||
return rotate90CCZ(v);
|
||||
}
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
// Y X 0 0
|
||||
// X Z 0 0
|
||||
|
||||
// 0 X Y 0
|
||||
// 0 Z X 0
|
||||
|
||||
public static Vector rotate(Direction current, Direction to, Vector v, int w, int h, int d)
|
||||
{
|
||||
if(current.equals(to))
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
else if(current.equals(to.reverse()))
|
||||
{
|
||||
if(current.isVertical())
|
||||
{
|
||||
return new Vector(v.getX(), -v.getY() + h, v.getZ());
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
return new Vector(-v.getX() + w, v.getY(), -v.getZ() + d);
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
Vector c = current.toVector().clone().add(to.toVector());
|
||||
|
||||
if(c.getX() == 0)
|
||||
{
|
||||
if(c.getY() != c.getZ())
|
||||
{
|
||||
return rotate90CX(v, d);
|
||||
}
|
||||
|
||||
return rotate90CCX(v, h);
|
||||
}
|
||||
|
||||
else if(c.getY() == 0)
|
||||
{
|
||||
if(c.getX() != c.getZ())
|
||||
{
|
||||
return rotate90CY(v, d);
|
||||
}
|
||||
|
||||
return rotate90CCY(v, w);
|
||||
}
|
||||
|
||||
else if(c.getZ() == 0)
|
||||
{
|
||||
if(c.getX() != c.getY())
|
||||
{
|
||||
return rotate90CZ(v, w);
|
||||
}
|
||||
|
||||
return rotate90CCZ(v, h);
|
||||
}
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
public static Vector rotate90CX(Vector v)
|
||||
{
|
||||
return new Vector(v.getX(), -v.getZ(), v.getY());
|
||||
}
|
||||
|
||||
public static Vector rotate90CCX(Vector v)
|
||||
{
|
||||
return new Vector(v.getX(), v.getZ(), -v.getY());
|
||||
}
|
||||
|
||||
public static Vector rotate90CY(Vector v)
|
||||
{
|
||||
return new Vector(-v.getZ(), v.getY(), v.getX());
|
||||
}
|
||||
|
||||
public static Vector rotate90CCY(Vector v)
|
||||
{
|
||||
return new Vector(v.getZ(), v.getY(), -v.getX());
|
||||
}
|
||||
|
||||
public static Vector rotate90CZ(Vector v)
|
||||
{
|
||||
return new Vector(v.getY(), -v.getX(), v.getZ());
|
||||
}
|
||||
|
||||
public static Vector rotate90CCZ(Vector v)
|
||||
{
|
||||
return new Vector(-v.getY(), v.getX(), v.getZ());
|
||||
}
|
||||
|
||||
public static Vector rotate90CX(Vector v, int s)
|
||||
{
|
||||
return new Vector(v.getX(), -v.getZ() + s, v.getY());
|
||||
}
|
||||
|
||||
public static Vector rotate90CCX(Vector v, int s)
|
||||
{
|
||||
return new Vector(v.getX(), v.getZ(), -v.getY() + s);
|
||||
}
|
||||
|
||||
public static Vector rotate90CY(Vector v, int s)
|
||||
{
|
||||
return new Vector(-v.getZ() + s, v.getY(), v.getX());
|
||||
}
|
||||
|
||||
public static Vector rotate90CCY(Vector v, int s)
|
||||
{
|
||||
return new Vector(v.getZ(), v.getY(), -v.getX() + s);
|
||||
}
|
||||
|
||||
public static Vector rotate90CZ(Vector v, int s)
|
||||
{
|
||||
return new Vector(v.getY(), -v.getX() + s, v.getZ());
|
||||
}
|
||||
|
||||
public static Vector rotate90CCZ(Vector v, int s)
|
||||
{
|
||||
return new Vector(-v.getY() + s, v.getX(), v.getZ());
|
||||
}
|
||||
|
||||
public static Vector getAxis(Direction current, Direction to)
|
||||
{
|
||||
if(current.equals(Direction.U) || current.equals(Direction.D))
|
||||
{
|
||||
if(to.equals(Direction.U) || to.equals(Direction.D))
|
||||
{
|
||||
return new Vector(1, 0, 0);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if(current.equals(Direction.N) || current.equals(Direction.S))
|
||||
{
|
||||
return Direction.E.toVector();
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
return Direction.S.toVector();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new Vector(0, 1, 0);
|
||||
}
|
||||
|
||||
private static double round(double value, int precision)
|
||||
{
|
||||
return Double.valueOf(Form.f(value, precision));
|
||||
}
|
||||
|
||||
public static Vector clip(Vector v, int decimals)
|
||||
{
|
||||
v.setX(round(v.getX(), decimals));
|
||||
v.setY(round(v.getY(), decimals));
|
||||
v.setZ(round(v.getZ(), decimals));
|
||||
return v;
|
||||
}
|
||||
|
||||
public static Vector rotateVectorCC(Vector vec, Vector axis, double deg)
|
||||
{
|
||||
double theta = Math.toRadians(deg);
|
||||
double x, y, z;
|
||||
double u, v, w;
|
||||
x = vec.getX();
|
||||
y = vec.getY();
|
||||
z = vec.getZ();
|
||||
u = axis.getX();
|
||||
v = axis.getY();
|
||||
w = axis.getZ();
|
||||
double xPrime = u * (u * x + v * y + w * z) * (1d - Math.cos(theta)) + x * Math.cos(theta) + (-w * y + v * z) * Math.sin(theta);
|
||||
double yPrime = v * (u * x + v * y + w * z) * (1d - Math.cos(theta)) + y * Math.cos(theta) + (w * x - u * z) * Math.sin(theta);
|
||||
double zPrime = w * (u * x + v * y + w * z) * (1d - Math.cos(theta)) + z * Math.cos(theta) + (-v * x + u * y) * Math.sin(theta);
|
||||
|
||||
return clip(new Vector(xPrime, yPrime, zPrime), 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all SIMPLE block faces from a more specific block face (SOUTH_EAST) =
|
||||
* (south, east)
|
||||
*
|
||||
* @param f
|
||||
* the block face
|
||||
* @return multiple faces, or one if the face is already simple
|
||||
*/
|
||||
public static KList<BlockFace> split(BlockFace f)
|
||||
{
|
||||
KList<BlockFace> faces = new KList<BlockFace>();
|
||||
|
||||
switch(f)
|
||||
{
|
||||
case DOWN:
|
||||
faces.add(BlockFace.DOWN);
|
||||
break;
|
||||
case EAST:
|
||||
faces.add(BlockFace.EAST);
|
||||
break;
|
||||
case EAST_NORTH_EAST:
|
||||
faces.add(BlockFace.EAST);
|
||||
faces.add(BlockFace.EAST);
|
||||
faces.add(BlockFace.NORTH);
|
||||
break;
|
||||
case EAST_SOUTH_EAST:
|
||||
faces.add(BlockFace.EAST);
|
||||
faces.add(BlockFace.EAST);
|
||||
faces.add(BlockFace.SOUTH);
|
||||
break;
|
||||
case NORTH:
|
||||
faces.add(BlockFace.NORTH);
|
||||
break;
|
||||
case NORTH_EAST:
|
||||
faces.add(BlockFace.NORTH);
|
||||
faces.add(BlockFace.EAST);
|
||||
break;
|
||||
case NORTH_NORTH_EAST:
|
||||
faces.add(BlockFace.NORTH);
|
||||
faces.add(BlockFace.NORTH);
|
||||
faces.add(BlockFace.EAST);
|
||||
break;
|
||||
case NORTH_NORTH_WEST:
|
||||
faces.add(BlockFace.NORTH);
|
||||
faces.add(BlockFace.NORTH);
|
||||
faces.add(BlockFace.WEST);
|
||||
break;
|
||||
case NORTH_WEST:
|
||||
faces.add(BlockFace.NORTH);
|
||||
faces.add(BlockFace.WEST);
|
||||
break;
|
||||
case SELF:
|
||||
faces.add(BlockFace.SELF);
|
||||
break;
|
||||
case SOUTH:
|
||||
faces.add(BlockFace.SOUTH);
|
||||
break;
|
||||
case SOUTH_EAST:
|
||||
faces.add(BlockFace.SOUTH);
|
||||
faces.add(BlockFace.EAST);
|
||||
break;
|
||||
case SOUTH_SOUTH_EAST:
|
||||
faces.add(BlockFace.SOUTH);
|
||||
faces.add(BlockFace.SOUTH);
|
||||
faces.add(BlockFace.EAST);
|
||||
break;
|
||||
case SOUTH_SOUTH_WEST:
|
||||
faces.add(BlockFace.SOUTH);
|
||||
faces.add(BlockFace.SOUTH);
|
||||
faces.add(BlockFace.WEST);
|
||||
break;
|
||||
case SOUTH_WEST:
|
||||
faces.add(BlockFace.SOUTH);
|
||||
faces.add(BlockFace.WEST);
|
||||
break;
|
||||
case UP:
|
||||
faces.add(BlockFace.UP);
|
||||
break;
|
||||
case WEST:
|
||||
faces.add(BlockFace.WEST);
|
||||
break;
|
||||
case WEST_NORTH_WEST:
|
||||
faces.add(BlockFace.WEST);
|
||||
faces.add(BlockFace.WEST);
|
||||
faces.add(BlockFace.NORTH);
|
||||
break;
|
||||
case WEST_SOUTH_WEST:
|
||||
faces.add(BlockFace.WEST);
|
||||
faces.add(BlockFace.WEST);
|
||||
faces.add(BlockFace.SOUTH);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return faces;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a normalized vector going from a location to another
|
||||
*
|
||||
* @param from
|
||||
* from here
|
||||
* @param to
|
||||
* to here
|
||||
* @return the normalized vector direction
|
||||
*/
|
||||
public static Vector direction(Location from, Location to)
|
||||
{
|
||||
return to.clone().subtract(from.clone()).toVector().normalize();
|
||||
}
|
||||
|
||||
public static Vector directionNoNormal(Location from, Location to)
|
||||
{
|
||||
return to.clone().subtract(from.clone()).toVector();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the vector direction from the yaw and pitch
|
||||
*
|
||||
* @param yaw
|
||||
* the yaw
|
||||
* @param pitch
|
||||
* the pitch
|
||||
* @return the vector
|
||||
*/
|
||||
public static Vector toVector(float yaw, float pitch)
|
||||
{
|
||||
return new Vector(Math.cos(pitch) * Math.cos(yaw), Math.sin(pitch), Math.cos(pitch) * Math.sin(-yaw));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an impulse (force) to an entity
|
||||
*
|
||||
* @param e
|
||||
* the entity
|
||||
* @param v
|
||||
* the vector
|
||||
*/
|
||||
public static void impulse(Entity e, Vector v)
|
||||
{
|
||||
impulse(e, v, 1.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an impulse (force) on an entity
|
||||
*
|
||||
* @param e
|
||||
* the entity
|
||||
* @param v
|
||||
* the vector
|
||||
* @param effectiveness
|
||||
* the effectiveness
|
||||
*/
|
||||
public static void impulse(Entity e, Vector v, double effectiveness)
|
||||
{
|
||||
Vector vx = e.getVelocity();
|
||||
vx.add(v.clone().multiply(effectiveness));
|
||||
e.setVelocity(vx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse a direction
|
||||
*
|
||||
* @param v
|
||||
* the direction
|
||||
* @return the reversed direction
|
||||
*/
|
||||
public static Vector reverse(Vector v)
|
||||
{
|
||||
if(v.getX() != 0)
|
||||
{
|
||||
v.setX(-v.getX());
|
||||
}
|
||||
|
||||
if(v.getY() != 0)
|
||||
{
|
||||
v.setY(-v.getY());
|
||||
}
|
||||
|
||||
if(v.getZ() != 0)
|
||||
{
|
||||
v.setZ(-v.getZ());
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a speed value from a vector (velocity)
|
||||
*
|
||||
* @param v
|
||||
* the vector
|
||||
* @return the speed
|
||||
*/
|
||||
public static double getSpeed(Vector v)
|
||||
{
|
||||
Vector vi = new Vector(0, 0, 0);
|
||||
Vector vt = new Vector(0, 0, 0).add(v);
|
||||
|
||||
return vi.distance(vt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shift all vectors based on the given vector
|
||||
*
|
||||
* @param vector
|
||||
* the vector direction to shift the vectors
|
||||
* @param vectors
|
||||
* the vectors to be shifted
|
||||
* @return the shifted vectors
|
||||
*/
|
||||
public static KList<Vector> shift(Vector vector, KList<Vector> vectors)
|
||||
{
|
||||
return new KList<Vector>(new GListAdapter<Vector, Vector>()
|
||||
{
|
||||
@Override
|
||||
public Vector onAdapt(Vector from)
|
||||
{
|
||||
return from.add(vector);
|
||||
}
|
||||
}.adapt(vectors));
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to get the blockFace for the vector (will be tri-normalized)
|
||||
*
|
||||
* @param v
|
||||
* the vector
|
||||
* @return the block face or null
|
||||
*/
|
||||
public static BlockFace getBlockFace(Vector v)
|
||||
{
|
||||
Vector p = triNormalize(v);
|
||||
|
||||
for(BlockFace i : BlockFace.values())
|
||||
{
|
||||
if(p.getX() == i.getModX() && p.getY() == i.getModY() && p.getZ() == i.getModZ())
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
for(BlockFace i : BlockFace.values())
|
||||
{
|
||||
if(p.getX() == i.getModX() && p.getZ() == i.getModZ())
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
for(BlockFace i : BlockFace.values())
|
||||
{
|
||||
if(p.getY() == i.getModY() && p.getZ() == i.getModZ())
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
for(BlockFace i : BlockFace.values())
|
||||
{
|
||||
if(p.getX() == i.getModX() || p.getY() == i.getModY())
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
for(BlockFace i : BlockFace.values())
|
||||
{
|
||||
if(p.getX() == i.getModX() || p.getY() == i.getModY() || p.getZ() == i.getModZ())
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Angle the vector in a self relative direction
|
||||
*
|
||||
* @param v
|
||||
* the initial direction
|
||||
* @param amt
|
||||
* the amount to shift in the direction
|
||||
* @return the shifted direction
|
||||
*/
|
||||
public static Vector angleLeft(Vector v, float amt)
|
||||
{
|
||||
Location l = new Location(Bukkit.getWorlds().get(0), 0, 0, 0);
|
||||
l.setDirection(v);
|
||||
float y = l.getYaw();
|
||||
float p = l.getPitch();
|
||||
CDou cy = new CDou(360);
|
||||
CDou cp = new CDou(180);
|
||||
cy.set(y);
|
||||
cp.set(p);
|
||||
cy.sub(amt);
|
||||
l.setYaw((float) cy.get());
|
||||
l.setPitch((float) cp.get());
|
||||
|
||||
return l.getDirection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Angle the vector in a self relative direction
|
||||
*
|
||||
* @param v
|
||||
* the initial direction
|
||||
* @param amt
|
||||
* the amount to shift in the direction
|
||||
* @return the shifted direction
|
||||
*/
|
||||
public static Vector angleRight(Vector v, float amt)
|
||||
{
|
||||
Location l = new Location(Bukkit.getWorlds().get(0), 0, 0, 0);
|
||||
l.setDirection(v);
|
||||
float y = l.getYaw();
|
||||
float p = l.getPitch();
|
||||
CDou cy = new CDou(360);
|
||||
CDou cp = new CDou(180);
|
||||
cy.set(y);
|
||||
cp.set(p);
|
||||
cy.add(amt);
|
||||
l.setYaw((float) cy.get());
|
||||
l.setPitch((float) cp.get());
|
||||
|
||||
return l.getDirection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Angle the vector in a self relative direction
|
||||
*
|
||||
* @param v
|
||||
* the initial direction
|
||||
* @param amt
|
||||
* the amount to shift in the direction
|
||||
* @return the shifted direction
|
||||
*/
|
||||
public static Vector angleUp(Vector v, float amt)
|
||||
{
|
||||
Location l = new Location(Bukkit.getWorlds().get(0), 0, 0, 0);
|
||||
l.setDirection(v);
|
||||
float y = l.getYaw();
|
||||
float p = l.getPitch();
|
||||
CDou cy = new CDou(360);
|
||||
cy.set(y);
|
||||
l.setYaw((float) cy.get());
|
||||
l.setPitch((float) Math.max(-90, p - amt));
|
||||
|
||||
return l.getDirection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Angle the vector in a self relative direction
|
||||
*
|
||||
* @param v
|
||||
* the initial direction
|
||||
* @param amt
|
||||
* the amount to shift in the direction
|
||||
* @return the shifted direction
|
||||
*/
|
||||
public static Vector angleDown(Vector v, float amt)
|
||||
{
|
||||
Location l = new Location(Bukkit.getWorlds().get(0), 0, 0, 0);
|
||||
l.setDirection(v);
|
||||
float y = l.getYaw();
|
||||
float p = l.getPitch();
|
||||
CDou cy = new CDou(360);
|
||||
cy.set(y);
|
||||
l.setYaw((float) cy.get());
|
||||
l.setPitch((float) Math.min(90, p + amt));
|
||||
|
||||
return l.getDirection();
|
||||
}
|
||||
|
||||
/**
|
||||
* (clone) Force normalize the vector into three points, 1, 0, or -1. If the
|
||||
* value is > 0.333 (1) if the value is less than -0.333 (-1) else 0
|
||||
*
|
||||
* @param direction
|
||||
* the direction
|
||||
* @return the vector
|
||||
*/
|
||||
public static Vector triNormalize(Vector direction)
|
||||
{
|
||||
Vector v = direction.clone();
|
||||
v.normalize();
|
||||
|
||||
if(v.getX() > 0.333)
|
||||
{
|
||||
v.setX(1);
|
||||
}
|
||||
|
||||
else if(v.getX() < -0.333)
|
||||
{
|
||||
v.setX(-1);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
v.setX(0);
|
||||
}
|
||||
|
||||
if(v.getY() > 0.333)
|
||||
{
|
||||
v.setY(1);
|
||||
}
|
||||
|
||||
else if(v.getY() < -0.333)
|
||||
{
|
||||
v.setY(-1);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
v.setY(0);
|
||||
}
|
||||
|
||||
if(v.getZ() > 0.333)
|
||||
{
|
||||
v.setZ(1);
|
||||
}
|
||||
|
||||
else if(v.getZ() < -0.333)
|
||||
{
|
||||
v.setZ(-1);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
v.setZ(0);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
}
|
307
src/main/java/ninja/bytecode/iris/wand/WandController.java
Normal file
307
src/main/java/ninja/bytecode/iris/wand/WandController.java
Normal file
@ -0,0 +1,307 @@
|
||||
package ninja.bytecode.iris.wand;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
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.PlayerInteractEvent;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.inventory.ItemFlag;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.util.BlockVector;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import ninja.bytecode.iris.Iris;
|
||||
import ninja.bytecode.iris.object.IrisObject;
|
||||
import ninja.bytecode.iris.util.Cuboid;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
import ninja.bytecode.shuriken.math.M;
|
||||
|
||||
public class WandController implements Listener
|
||||
{
|
||||
public WandController()
|
||||
{
|
||||
Bukkit.getScheduler().scheduleSyncRepeatingTask(Iris.instance, () ->
|
||||
{
|
||||
for(Player i : Bukkit.getOnlinePlayers())
|
||||
{
|
||||
tick(i);
|
||||
}
|
||||
}, 0, 0);
|
||||
Bukkit.getPluginManager().registerEvents(this, Iris.instance);
|
||||
}
|
||||
|
||||
public void tick(Player p)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(isWand(p.getInventory().getItemInMainHand()))
|
||||
{
|
||||
Location[] d = getCuboid(p.getInventory().getItemInMainHand());
|
||||
draw(d, p);
|
||||
}
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void draw(Location[] d, Player p)
|
||||
{
|
||||
Vector gx = Vector.getRandom().subtract(Vector.getRandom()).normalize().clone().multiply(0.65);
|
||||
d[0].getWorld().spawnParticle(Particle.CRIT_MAGIC, d[0], 1, 0.5 + gx.getX(), 0.5 + gx.getY(), 0.5 + gx.getZ(), 0, null, false);
|
||||
Vector gxx = Vector.getRandom().subtract(Vector.getRandom()).normalize().clone().multiply(0.65);
|
||||
d[1].getWorld().spawnParticle(Particle.CRIT, d[1], 1, 0.5 + gxx.getX(), 0.5 + gxx.getY(), 0.5 + gxx.getZ(), 0, null, false);
|
||||
|
||||
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)
|
||||
{
|
||||
if(M.r(0.2))
|
||||
{
|
||||
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);
|
||||
Color color = Color.getHSBColor((float) (0.5f + (Math.sin((aa + bb + cc + (p.getTicksLived() / 2)) / 20f) / 2)), 1, 1);
|
||||
int r = color.getRed();
|
||||
int g = color.getGreen();
|
||||
int b = color.getBlue();
|
||||
p.spawnParticle(Particle.REDSTONE, lv.getX(), lv.getY(), lv.getZ(), 1, 0, 0, 0, 0, new Particle.DustOptions(org.bukkit.Color.fromRGB(r, g, b), 0.75f));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void on(PlayerInteractEvent e)
|
||||
{
|
||||
if(e.getHand().equals(EquipmentSlot.HAND) && isWand(e.getPlayer().getInventory().getItemInMainHand()))
|
||||
{
|
||||
if(e.getAction().equals(Action.LEFT_CLICK_BLOCK))
|
||||
{
|
||||
e.setCancelled(true);
|
||||
e.getPlayer().getInventory().setItemInMainHand(update(true, e.getClickedBlock().getLocation(), e.getPlayer().getInventory().getItemInMainHand()));
|
||||
e.getPlayer().playSound(e.getClickedBlock().getLocation(), Sound.BLOCK_END_PORTAL_FRAME_FILL, 1f, 0.67f);
|
||||
e.getPlayer().updateInventory();
|
||||
}
|
||||
|
||||
else if(e.getAction().equals(Action.RIGHT_CLICK_BLOCK))
|
||||
{
|
||||
e.setCancelled(true);
|
||||
e.getPlayer().getInventory().setItemInMainHand(update(false, e.getClickedBlock().getLocation(), e.getPlayer().getInventory().getItemInMainHand()));
|
||||
e.getPlayer().playSound(e.getClickedBlock().getLocation(), Sound.BLOCK_END_PORTAL_FRAME_FILL, 1f, 1.17f);
|
||||
e.getPlayer().updateInventory();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void pasteSchematic(IrisObject s, Location at)
|
||||
{
|
||||
s.place(at);
|
||||
}
|
||||
|
||||
public static IrisObject createSchematic(ItemStack wand)
|
||||
{
|
||||
if(!isWand(wand))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Location[] f = getCuboid(wand);
|
||||
Cuboid c = new Cuboid(f[0], f[1]);
|
||||
IrisObject s = new IrisObject(c.getSizeX(), c.getSizeY(), c.getSizeZ());
|
||||
Iterator<Block> bb = c.iterator();
|
||||
while(bb.hasNext())
|
||||
{
|
||||
Block b = bb.next();
|
||||
|
||||
if(b.getType().equals(Material.AIR))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
BlockVector bv = b.getLocation().subtract(c.getLowerNE().toVector()).toVector().toBlockVector();
|
||||
s.setUnsigned(bv.getBlockX(), bv.getBlockY(), bv.getBlockZ(), b.getBlockData());
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Location stringToLocation(String s)
|
||||
{
|
||||
try
|
||||
{
|
||||
String[] f = s.split("\\Q in \\E");
|
||||
String[] g = f[0].split("\\Q,\\E");
|
||||
return new Location(Bukkit.getWorld(f[1]), Integer.valueOf(g[0]), Integer.valueOf(g[1]), Integer.valueOf(g[2]));
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String locationToString(Location s)
|
||||
{
|
||||
if(s == null)
|
||||
{
|
||||
return "<#>";
|
||||
}
|
||||
|
||||
return s.getBlockX() + "," + s.getBlockY() + "," + s.getBlockZ() + " in " + s.getWorld().getName();
|
||||
}
|
||||
|
||||
public static ItemStack createWand()
|
||||
{
|
||||
return createWand(null, null);
|
||||
}
|
||||
|
||||
public static ItemStack update(boolean left, Location a, ItemStack item)
|
||||
{
|
||||
if(!isWand(item))
|
||||
{
|
||||
return item;
|
||||
}
|
||||
|
||||
Location[] f = getCuboid(item);
|
||||
Location other = left ? f[1] : f[0];
|
||||
|
||||
if(other != null && !other.getWorld().getName().equals(a.getWorld().getName()))
|
||||
{
|
||||
other = null;
|
||||
}
|
||||
|
||||
return createWand(left ? a : other, left ? other : a);
|
||||
}
|
||||
|
||||
public static ItemStack createWand(Location a, Location b)
|
||||
{
|
||||
ItemStack is = new ItemStack(Material.BLAZE_ROD);
|
||||
is.addUnsafeEnchantment(Enchantment.ARROW_INFINITE, 1);
|
||||
ItemMeta im = is.getItemMeta();
|
||||
im.setDisplayName(ChatColor.BOLD + "" + ChatColor.GOLD + "Wand of Iris");
|
||||
im.setUnbreakable(true);
|
||||
im.addItemFlags(ItemFlag.HIDE_ATTRIBUTES, ItemFlag.HIDE_PLACED_ON, ItemFlag.HIDE_POTION_EFFECTS, ItemFlag.HIDE_DESTROYS, ItemFlag.HIDE_ENCHANTS);
|
||||
im.setLore(new KList<String>().add(locationToString(a), locationToString(b)));
|
||||
is.setItemMeta(im);
|
||||
|
||||
return is;
|
||||
}
|
||||
|
||||
public static boolean isWand(Player p)
|
||||
{
|
||||
ItemStack is = p.getInventory().getItemInMainHand();
|
||||
return !(is == null || !isWand(is));
|
||||
}
|
||||
|
||||
public static Location[] getCuboid(ItemStack is)
|
||||
{
|
||||
ItemMeta im = is.getItemMeta();
|
||||
return new Location[] {stringToLocation(im.getLore().get(0)), stringToLocation(im.getLore().get(1))};
|
||||
}
|
||||
|
||||
public static boolean isWand(ItemStack item)
|
||||
{
|
||||
if(!item.getType().equals(createWand().getType()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!item.getItemMeta().getEnchants().equals(createWand().getItemMeta().getEnchants()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!item.getItemMeta().getDisplayName().equals(createWand().getItemMeta().getDisplayName()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user