mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2025-07-18 18:23:06 +00:00
Deps
This commit is contained in:
parent
5d7126f772
commit
eca3174214
5
pom.xml
5
pom.xml
@ -166,6 +166,11 @@
|
||||
<version>1.18.10</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ninja.bytecode</groupId>
|
||||
<artifactId>Shuriken</artifactId>
|
||||
<version>1.1.24</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bukkit</groupId>
|
||||
<artifactId>bukkit</artifactId>
|
||||
|
20
src/main/java/ninja/bytecode/iris/GeneratedChunk.java
Normal file
20
src/main/java/ninja/bytecode/iris/GeneratedChunk.java
Normal file
@ -0,0 +1,20 @@
|
||||
package ninja.bytecode.iris;
|
||||
|
||||
import org.bukkit.generator.ChunkGenerator.BiomeGrid;
|
||||
import org.bukkit.generator.ChunkGenerator.ChunkData;
|
||||
|
||||
import lombok.Data;
|
||||
import ninja.bytecode.iris.util.ChunkPosition;
|
||||
|
||||
@Data
|
||||
public class GeneratedChunk
|
||||
{
|
||||
private ChunkPosition pos;
|
||||
private ChunkData data;
|
||||
private BiomeGrid grid;
|
||||
|
||||
public GeneratedChunk(ChunkPosition pos)
|
||||
{
|
||||
this.pos = pos;
|
||||
}
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
package ninja.bytecode.iris;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
@ -15,14 +17,31 @@ import org.bukkit.entity.Player;
|
||||
import org.bukkit.generator.ChunkGenerator;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import ninja.bytecode.iris.object.IrisBiome;
|
||||
import ninja.bytecode.iris.object.IrisDimension;
|
||||
import ninja.bytecode.iris.util.BiomeResult;
|
||||
import ninja.bytecode.iris.util.BoardManager;
|
||||
import ninja.bytecode.iris.util.BoardProvider;
|
||||
import ninja.bytecode.iris.util.BoardSettings;
|
||||
import ninja.bytecode.iris.util.CNG;
|
||||
import ninja.bytecode.iris.util.GroupedExecutor;
|
||||
import ninja.bytecode.iris.util.IO;
|
||||
import ninja.bytecode.iris.util.KMap;
|
||||
import ninja.bytecode.iris.util.ScoreDirection;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
import ninja.bytecode.shuriken.execution.J;
|
||||
import ninja.bytecode.shuriken.format.Form;
|
||||
import ninja.bytecode.shuriken.math.RollingSequence;
|
||||
import ninja.bytecode.shuriken.reaction.O;
|
||||
|
||||
public class Iris extends JavaPlugin
|
||||
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;
|
||||
private BoardManager manager;
|
||||
private RollingSequence hits = new RollingSequence(20);
|
||||
|
||||
public Iris()
|
||||
{
|
||||
@ -34,42 +53,157 @@ public class Iris extends JavaPlugin
|
||||
instance = this;
|
||||
hotloader = new IrisHotloadManager();
|
||||
data = new IrisDataManager(getDataFolder());
|
||||
Bukkit.getScheduler().scheduleSyncDelayedTask(this, () ->
|
||||
manager = new BoardManager(this, BoardSettings.builder().boardProvider(this).scoreDirection(ScoreDirection.UP).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle(Player player)
|
||||
{
|
||||
return ChatColor.GREEN + "Iris";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getLines(Player player)
|
||||
{
|
||||
World world = player.getWorld();
|
||||
List<String> lines = new ArrayList<>();
|
||||
|
||||
if(world.getGenerator() instanceof IrisGenerator)
|
||||
{
|
||||
for(World i : Bukkit.getWorlds())
|
||||
IrisGenerator g = (IrisGenerator) world.getGenerator();
|
||||
int x = player.getLocation().getBlockX();
|
||||
int z = player.getLocation().getBlockZ();
|
||||
IrisDimension dim = g.getDimension();
|
||||
BiomeResult er = g.getBiome(x, z);
|
||||
IrisBiome b = er != null ? er.getBiome() : null;
|
||||
int fh = dim.getFluidHeight();
|
||||
lines.add("&7&m-----------------");
|
||||
lines.add(ChatColor.GREEN + "Speed" + ChatColor.GRAY + ": " + ChatColor.BOLD + "" + ChatColor.GRAY + Form.f(g.getMetrics().getPerSecond().getAverage(), 0) + "/s " + Form.duration(g.getMetrics().getTotal().getAverage(), 1) + "");
|
||||
lines.add(ChatColor.GREEN + "Loss" + ChatColor.GRAY + ": " + ChatColor.BOLD + "" + ChatColor.GRAY + Form.duration(g.getMetrics().getLoss().getAverage(), 4) + "");
|
||||
lines.add(ChatColor.GREEN + "Generators" + ChatColor.GRAY + ": " + Form.f(CNG.creates));
|
||||
lines.add(ChatColor.GREEN + "Noise" + ChatColor.GRAY + ": " + Form.f((int) hits.getAverage()));
|
||||
|
||||
if(er != null && b != null)
|
||||
{
|
||||
if(i.getName().startsWith("iris/"))
|
||||
{
|
||||
Bukkit.unloadWorld(i, false);
|
||||
}
|
||||
lines.add(ChatColor.GREEN + "Biome" + ChatColor.GRAY + ": " + b.getName());
|
||||
lines.add(ChatColor.GREEN + "File" + ChatColor.GRAY + ": " + b.getLoadKey() + ".json");
|
||||
lines.add(ChatColor.GREEN + "Height" + ChatColor.GRAY + ": " + (int) (b.getLowHeight() + fh) + " - " + (int) (b.getHighHeight() + fh) + " (" + (int) (b.getHighHeight() - b.getLowHeight()) + ")");
|
||||
}
|
||||
lines.add("&7&m-----------------");
|
||||
}
|
||||
|
||||
World world = Bukkit.createWorld(new WorldCreator("iris/" + UUID.randomUUID()).generator(new IrisGenerator("overworld")));
|
||||
|
||||
for(Player i : Bukkit.getOnlinePlayers())
|
||||
{
|
||||
i.teleport(new Location(world, 0, 100, 0));
|
||||
|
||||
Bukkit.getScheduler().scheduleSyncDelayedTask(this, () ->
|
||||
{
|
||||
i.setGameMode(GameMode.SPECTATOR);
|
||||
}, 5);
|
||||
}
|
||||
});
|
||||
else
|
||||
{
|
||||
lines.add(ChatColor.GREEN + "Join an Iris World!");
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
public void onDisable()
|
||||
{
|
||||
for(GroupedExecutor i : executors)
|
||||
{
|
||||
i.close();
|
||||
}
|
||||
|
||||
executors.clear();
|
||||
manager.onDisable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args)
|
||||
{
|
||||
if(command.getName().equals("iris"))
|
||||
{
|
||||
if(args.length == 0)
|
||||
{
|
||||
imsg(sender, "/iris dev - Create a new dev world");
|
||||
}
|
||||
|
||||
if(args.length >= 1)
|
||||
{
|
||||
if(args[0].equalsIgnoreCase("dev"))
|
||||
{
|
||||
String dim = "Overworld";
|
||||
|
||||
if(args.length > 1)
|
||||
{
|
||||
dim = args[1];
|
||||
}
|
||||
|
||||
String dimm = dim;
|
||||
|
||||
Bukkit.getScheduler().scheduleSyncDelayedTask(this, () ->
|
||||
{
|
||||
for(World i : Bukkit.getWorlds())
|
||||
{
|
||||
if(i.getName().startsWith("iris/"))
|
||||
{
|
||||
for(Player j : Bukkit.getOnlinePlayers())
|
||||
{
|
||||
imsg(j, "Unloading " + i.getName());
|
||||
}
|
||||
|
||||
Bukkit.unloadWorld(i, false);
|
||||
}
|
||||
}
|
||||
|
||||
for(Player i : Bukkit.getOnlinePlayers())
|
||||
{
|
||||
imsg(i, "Creating Iris " + dimm + "...");
|
||||
}
|
||||
|
||||
IrisGenerator gx = new IrisGenerator("overworld");
|
||||
|
||||
O<Boolean> done = new O<Boolean>();
|
||||
done.set(false);
|
||||
|
||||
J.a(() ->
|
||||
{
|
||||
int req = 740;
|
||||
while(!done.get())
|
||||
{
|
||||
for(Player i : Bukkit.getOnlinePlayers())
|
||||
{
|
||||
imsg(i, "Generating " + Form.pc((double) gx.getGenerated() / (double) req));
|
||||
}
|
||||
J.sleep(3000);
|
||||
}
|
||||
});
|
||||
World world = Bukkit.createWorld(new WorldCreator("iris/" + UUID.randomUUID()).generator(gx));
|
||||
done.set(true);
|
||||
|
||||
for(Player i : Bukkit.getOnlinePlayers())
|
||||
{
|
||||
imsg(i, "Generating 100%");
|
||||
}
|
||||
|
||||
for(Player i : Bukkit.getOnlinePlayers())
|
||||
{
|
||||
i.teleport(new Location(world, 0, 100, 0));
|
||||
|
||||
Bukkit.getScheduler().scheduleSyncDelayedTask(this, () ->
|
||||
{
|
||||
imsg(i, "Have Fun!");
|
||||
i.setGameMode(GameMode.SPECTATOR);
|
||||
}, 5);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void imsg(CommandSender s, String msg)
|
||||
{
|
||||
s.sendMessage(ChatColor.GREEN + "[" + ChatColor.DARK_GRAY + "Iris" + ChatColor.GREEN + "]" + ChatColor.GRAY + ": " + msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChunkGenerator getDefaultWorldGenerator(String worldName, String id)
|
||||
{
|
||||
@ -78,7 +212,16 @@ public class Iris extends JavaPlugin
|
||||
|
||||
public static void msg(String string)
|
||||
{
|
||||
Bukkit.getConsoleSender().sendMessage(ChatColor.GREEN + "[Iris]: " + ChatColor.GRAY + string);
|
||||
String msg = ChatColor.GREEN + "[Iris]: " + ChatColor.GRAY + string;
|
||||
|
||||
if(last.equals(msg))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
last = msg;
|
||||
|
||||
Bukkit.getConsoleSender().sendMessage(msg);
|
||||
}
|
||||
|
||||
public static void warn(String string)
|
||||
@ -105,4 +248,9 @@ public class Iris extends JavaPlugin
|
||||
{
|
||||
msg(ChatColor.WHITE + string);
|
||||
}
|
||||
|
||||
public void hit(long hits2)
|
||||
{
|
||||
hits.put(hits2);
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ package ninja.bytecode.iris;
|
||||
import org.bukkit.World;
|
||||
|
||||
import ninja.bytecode.iris.util.BiomeResult;
|
||||
import ninja.bytecode.iris.util.KMap;
|
||||
import ninja.bytecode.shuriken.collections.KMap;
|
||||
|
||||
public interface IrisContext
|
||||
{
|
||||
|
@ -2,6 +2,7 @@ package ninja.bytecode.iris;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
@ -9,43 +10,74 @@ import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||
import org.bukkit.event.world.WorldUnloadEvent;
|
||||
import org.bukkit.generator.BlockPopulator;
|
||||
import org.bukkit.generator.ChunkGenerator;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import ninja.bytecode.iris.layer.GenLayerBiome;
|
||||
import ninja.bytecode.iris.object.IrisBiome;
|
||||
import ninja.bytecode.iris.object.IrisDimension;
|
||||
import ninja.bytecode.iris.object.IrisRegion;
|
||||
import ninja.bytecode.iris.object.atomics.AtomicSliver;
|
||||
import ninja.bytecode.iris.util.BiomeResult;
|
||||
import ninja.bytecode.iris.util.BlockDataTools;
|
||||
import ninja.bytecode.iris.util.CNG;
|
||||
import ninja.bytecode.iris.util.ChronoLatch;
|
||||
import ninja.bytecode.iris.util.GroupedExecutor;
|
||||
import ninja.bytecode.iris.util.IrisInterpolation;
|
||||
import ninja.bytecode.iris.util.KList;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
import ninja.bytecode.shuriken.bench.PrecisionStopwatch;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
import ninja.bytecode.shuriken.format.Form;
|
||||
import ninja.bytecode.shuriken.logging.L;
|
||||
|
||||
public class IrisGenerator extends ChunkGenerator implements IrisContext
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class IrisGenerator extends ChunkGenerator implements IrisContext, Listener
|
||||
{
|
||||
// TODO REMOVE OR FIND A BETTER PLACE
|
||||
private BlockData STONE = Material.STONE.createBlockData();
|
||||
private BlockData WATER = Material.WATER.createBlockData();
|
||||
private String dimensionName;
|
||||
private GenLayerBiome glBiome;
|
||||
private CNG terrainNoise;
|
||||
private IrisMetrics metrics;
|
||||
private World world;
|
||||
private ChronoLatch perSecond;
|
||||
private ChronoLatch pushLatch;
|
||||
|
||||
private BlockData STONE = Material.STONE.createBlockData();
|
||||
private BlockData WATER = Material.WATER.createBlockData();
|
||||
private GenLayerBiome glBiome;
|
||||
private CNG terrainNoise;
|
||||
private RNG masterRandom;
|
||||
private GroupedExecutor tx;
|
||||
private boolean failing = false;
|
||||
private boolean initialized = false;
|
||||
private int generated = 0;
|
||||
private boolean pregenDone = false;
|
||||
private int task = -1;
|
||||
|
||||
public IrisGenerator(String dimensionName)
|
||||
{
|
||||
this.dimensionName = dimensionName;
|
||||
pushLatch = new ChronoLatch(3000);
|
||||
perSecond = new ChronoLatch(1000);
|
||||
CNG.creates = 0;
|
||||
}
|
||||
|
||||
public IrisDimension getDimension()
|
||||
{
|
||||
return Iris.data.getDimensionLoader().load(dimensionName);
|
||||
IrisDimension d = Iris.data.getDimensionLoader().load(dimensionName);
|
||||
|
||||
if(d == null)
|
||||
{
|
||||
Iris.error("Can't find dimension: " + dimensionName);
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
public void onInit(World world, RNG rng)
|
||||
@ -56,10 +88,61 @@ public class IrisGenerator extends ChunkGenerator implements IrisContext
|
||||
}
|
||||
|
||||
this.world = world;
|
||||
metrics = new IrisMetrics(1024);
|
||||
this.masterRandom = new RNG(world.getSeed());
|
||||
glBiome = new GenLayerBiome(this, masterRandom.nextParallelRNG(1));
|
||||
terrainNoise = CNG.signature(masterRandom.nextParallelRNG(2));
|
||||
metrics = new IrisMetrics(128);
|
||||
initialized = true;
|
||||
glBiome = new GenLayerBiome(this, rng.nextParallelRNG(1));
|
||||
terrainNoise = CNG.signature(rng.nextParallelRNG(2));
|
||||
tx = new GroupedExecutor(16, Thread.MIN_PRIORITY, "Iris Generator");
|
||||
Iris.executors.add(tx);
|
||||
Bukkit.getServer().getPluginManager().registerEvents(this, Iris.instance);
|
||||
task = Bukkit.getScheduler().scheduleSyncRepeatingTask(Iris.instance, this::tick, 0, 0);
|
||||
}
|
||||
|
||||
public void tick()
|
||||
{
|
||||
if(perSecond.flip())
|
||||
{
|
||||
if(generated > 770)
|
||||
{
|
||||
pregenDone = true;
|
||||
}
|
||||
|
||||
if(pregenDone)
|
||||
{
|
||||
metrics.getPerSecond().put(generated);
|
||||
generated = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void on(PlayerTeleportEvent e)
|
||||
{
|
||||
if(e.getFrom().getWorld().equals(world) && !e.getTo().getWorld().equals(world))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
if(!e.getFrom().getWorld().equals(world) && e.getTo().getWorld().equals(world))
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void on(WorldUnloadEvent e)
|
||||
{
|
||||
if(world != null && e.getWorld().equals(world))
|
||||
{
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
public void close()
|
||||
{
|
||||
HandlerList.unregisterAll(this);
|
||||
Bukkit.getScheduler().cancelTask(getTask());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -68,80 +151,164 @@ public class IrisGenerator extends ChunkGenerator implements IrisContext
|
||||
return super.canSpawn(world, x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChunkData generateChunkData(World world, Random no, int x, int z, BiomeGrid biomeGrid)
|
||||
public ChunkData generateChunkDataFailure(World world, Random no, int x, int z, BiomeGrid biomeGrid)
|
||||
{
|
||||
if(pushLatch.flip())
|
||||
{
|
||||
Iris.hotloader.check();
|
||||
IrisContext.pushContext(this);
|
||||
}
|
||||
ChunkData c = Bukkit.createChunkData(world);
|
||||
|
||||
int i, j, k, height, depth;
|
||||
double wx, wz, rx, rz, noise, ox, oz;
|
||||
boolean underwater;
|
||||
BlockData block;
|
||||
int fluidHeight = getDimension().getFluidHeight();
|
||||
BiomeResult biomeResult;
|
||||
IrisBiome biome;
|
||||
IrisRegion region;
|
||||
RNG random = new RNG(world.getSeed());
|
||||
onInit(world, random.nextParallelRNG(0));
|
||||
ChunkData data = Bukkit.createChunkData(world);
|
||||
|
||||
for(i = 0; i < 16; i++)
|
||||
for(int i = 0; i < 16; i++)
|
||||
{
|
||||
for(j = 0; j < 16; j++)
|
||||
for(int j = 0; j < 16; j++)
|
||||
{
|
||||
rx = (x * 16) + i;
|
||||
rz = (z * 16) + j;
|
||||
ox = (getDimension().cosRotate() * rx) + (-getDimension().sinRotate() * rz) + getDimension().getCoordFracture(random, 39392).fitDoubleD(-getDimension().getCoordFractureDistance() / 2, getDimension().getCoordFractureDistance() / 2, rx, rz);
|
||||
oz = (getDimension().sinRotate() * rx) + (getDimension().cosRotate() * rz) + getDimension().getCoordFracture(random, 39392).fitDoubleD(-getDimension().getCoordFractureDistance() / 2, getDimension().getCoordFractureDistance() / 2, rx, rz);
|
||||
wx = (double) (ox) / getDimension().getTerrainZoom();
|
||||
wz = (double) (oz) / getDimension().getTerrainZoom();
|
||||
depth = 0;
|
||||
region = glBiome.getRegion(wx, wz);
|
||||
biomeResult = glBiome.generateRegionData(wx, wz, region);
|
||||
biome = biomeResult.getBiome();
|
||||
double lo = interpolateHeight(ox, oz, (b) -> b.getLowHeight());
|
||||
double hi = interpolateSurface(ox, oz, (b) -> b.getHighHeight());
|
||||
noise = lo + (terrainNoise.fitDoubleD(0, hi - lo, wx, wz));
|
||||
height = (int) Math.round(noise) + fluidHeight;
|
||||
int h = 0;
|
||||
|
||||
// Remove Land biome surfaces from underwater
|
||||
if(height < fluidHeight + 1)
|
||||
if(j == i || j + i == 16)
|
||||
{
|
||||
if(biome.isLand())
|
||||
{
|
||||
biome = glBiome.generateShoreData(wx, wz, region).getBiome();
|
||||
}
|
||||
c.setBlock(i, h, j, BlockDataTools.getBlockData("RED_TERRACOTTA"));
|
||||
}
|
||||
|
||||
KList<BlockData> layers = biome.generateLayers(wx, wz, random, height);
|
||||
|
||||
for(k = Math.max(height, fluidHeight); k >= 0; k--)
|
||||
else
|
||||
{
|
||||
underwater = k > height && k <= fluidHeight;
|
||||
biomeGrid.setBiome(i, k, j, biome.getDerivative());
|
||||
|
||||
if(underwater)
|
||||
{
|
||||
block = WATER;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
block = layers.hasIndex(depth) ? layers.get(depth) : STONE;
|
||||
depth++;
|
||||
}
|
||||
|
||||
data.setBlock(i, k, j, block);
|
||||
c.setBlock(i, h, j, BlockDataTools.getBlockData("BLACK_TERRACOTTA"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Iris.verbose("Generated " + x + " " + z);
|
||||
return data;
|
||||
return c;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChunkData generateChunkData(World world, Random no, int x, int z, BiomeGrid biomeGrid)
|
||||
{
|
||||
PrecisionStopwatch sx = PrecisionStopwatch.start();
|
||||
|
||||
if(failing)
|
||||
{
|
||||
return generateChunkDataFailure(world, no, x, z, biomeGrid);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if(pushLatch.flip())
|
||||
{
|
||||
if(this.world == null)
|
||||
{
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
Iris.hotloader.check();
|
||||
IrisContext.pushContext(this);
|
||||
if(metrics != null)
|
||||
{
|
||||
Iris.info("Generating " + Form.f(1000D / metrics.getTotal().getAverage(), 0) + "/s (" + Form.duration(metrics.getTotal().getAverage(), 2) + ")");
|
||||
}
|
||||
}
|
||||
|
||||
String key = "c" + x + "," + z;
|
||||
PrecisionStopwatch s = PrecisionStopwatch.start();
|
||||
RNG random = new RNG(world.getSeed());
|
||||
onInit(world, random.nextParallelRNG(0));
|
||||
ChunkData c = Bukkit.createChunkData(world);
|
||||
int ii, jj;
|
||||
int fluidHeight = getDimension().getFluidHeight();
|
||||
KList<Runnable> collapse = new KList<>();
|
||||
ReentrantLock l = new ReentrantLock();
|
||||
|
||||
for(ii = 0; ii < 16; ii++)
|
||||
{
|
||||
int i = ii;
|
||||
for(jj = 0; jj < 16; jj++)
|
||||
{
|
||||
int j = jj;
|
||||
tx.queue(key, () ->
|
||||
{
|
||||
BlockData block;
|
||||
int rx = (x * 16) + i;
|
||||
int rz = (z * 16) + j;
|
||||
AtomicSliver sliver = new AtomicSliver(i, j);
|
||||
double ox = (getDimension().cosRotate() * rx) + (-getDimension().sinRotate() * rz) + getDimension().getCoordFracture(random, 39392).fitDoubleD(-getDimension().getCoordFractureDistance() / 2, getDimension().getCoordFractureDistance() / 2, rx, rz);
|
||||
double oz = (getDimension().sinRotate() * rx) + (getDimension().cosRotate() * rz) + getDimension().getCoordFracture(random, 39392).fitDoubleD(-getDimension().getCoordFractureDistance() / 2, getDimension().getCoordFractureDistance() / 2, rx, rz);
|
||||
double wx = (double) (ox) / getDimension().getTerrainZoom();
|
||||
double wz = (double) (oz) / getDimension().getTerrainZoom();
|
||||
int depth = 0;
|
||||
IrisRegion region = glBiome.getRegion(wx, wz);
|
||||
BiomeResult biomeResult = glBiome.generateRegionData(wx, wz, region);
|
||||
IrisBiome biome = biomeResult.getBiome();
|
||||
double lo = interpolateHeight(ox, oz, (b) -> b.getLowHeight());
|
||||
double hi = interpolateSurface(ox, oz, (b) -> b.getHighHeight());
|
||||
double noise = lo + (terrainNoise.fitDoubleD(0, hi - lo, wx, wz));
|
||||
int height = (int) Math.round(noise) + fluidHeight;
|
||||
|
||||
// Remove Land biome surfaces from underwater
|
||||
if(height < fluidHeight + 1)
|
||||
{
|
||||
if(biome.isLand())
|
||||
{
|
||||
biome = glBiome.generateShoreData(wx, wz, region).getBiome();
|
||||
}
|
||||
}
|
||||
|
||||
KList<BlockData> layers = biome.generateLayers(wx, wz, random, height);
|
||||
|
||||
for(int k = Math.max(height, fluidHeight); k >= 0; k--)
|
||||
{
|
||||
boolean underwater = k > height && k <= fluidHeight;
|
||||
sliver.set(k, biome.getDerivative());
|
||||
// biomeGrid.setBiome(i, k, j, biome.getDerivative());
|
||||
|
||||
if(underwater)
|
||||
{
|
||||
block = WATER;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
block = layers.hasIndex(depth) ? layers.get(depth) : STONE;
|
||||
depth++;
|
||||
}
|
||||
|
||||
sliver.set(k, block);
|
||||
// c.setBlock(i, k, j, block);
|
||||
}
|
||||
|
||||
l.lock();
|
||||
collapse.add(() ->
|
||||
{
|
||||
sliver.write(c);
|
||||
sliver.write(biomeGrid);
|
||||
});
|
||||
l.unlock();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
tx.waitFor(key);
|
||||
collapse.forEach((i) -> i.run());
|
||||
metrics.getTotal().put(s.getMilliseconds());
|
||||
generated++;
|
||||
long hits = CNG.hits;
|
||||
CNG.hits = 0;
|
||||
Iris.instance.hit(hits);
|
||||
metrics.getLoss().put(sx.getMilliseconds() - s.getMilliseconds());
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
failing = true;
|
||||
Iris.error("ERROR! Failed to generate chunk! Iris has entered a failed state!");
|
||||
|
||||
for(Player i : world.getPlayers())
|
||||
{
|
||||
Iris.instance.imsg(i, ChatColor.DARK_RED + "Iris Generator has entered a failed state!");
|
||||
Iris.instance.imsg(i, ChatColor.RED + "- Check the console for the error.");
|
||||
Iris.instance.imsg(i, ChatColor.RED + "- Then simply run /iris dev");
|
||||
}
|
||||
|
||||
L.ex(e);
|
||||
}
|
||||
|
||||
return generateChunkDataFailure(world, no, x, z, biomeGrid);
|
||||
}
|
||||
|
||||
public double interpolateHeight(double rx, double rz, Function<IrisBiome, Double> property)
|
||||
@ -174,12 +341,6 @@ public class IrisGenerator extends ChunkGenerator implements IrisContext
|
||||
return super.getFixedSpawnLocation(world, random);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeResult getBiome(int x, int z)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isParallelCapable()
|
||||
{
|
||||
@ -197,4 +358,16 @@ public class IrisGenerator extends ChunkGenerator implements IrisContext
|
||||
{
|
||||
return world;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeResult getBiome(int rx, int rz)
|
||||
{
|
||||
RNG random = new RNG(world.getSeed());
|
||||
double ox = (getDimension().cosRotate() * rx) + (-getDimension().sinRotate() * rz) + getDimension().getCoordFracture(random, 39392).fitDoubleD(-getDimension().getCoordFractureDistance() / 2, getDimension().getCoordFractureDistance() / 2, rx, rz);
|
||||
double oz = (getDimension().sinRotate() * rx) + (getDimension().cosRotate() * rz) + getDimension().getCoordFracture(random, 39392).fitDoubleD(-getDimension().getCoordFractureDistance() / 2, getDimension().getCoordFractureDistance() / 2, rx, rz);
|
||||
double wx = (double) (ox) / getDimension().getTerrainZoom();
|
||||
double wz = (double) (oz) / getDimension().getTerrainZoom();
|
||||
IrisRegion region = glBiome.getRegion(wx, wz);
|
||||
return glBiome.generateRegionData(wx, wz, region);
|
||||
}
|
||||
}
|
||||
|
@ -6,16 +6,16 @@ import org.bukkit.Bukkit;
|
||||
|
||||
import ninja.bytecode.iris.util.ChronoLatch;
|
||||
import ninja.bytecode.iris.util.FileWatcher;
|
||||
import ninja.bytecode.iris.util.KList;
|
||||
import ninja.bytecode.shuriken.collections.KSet;
|
||||
|
||||
public class IrisHotloadManager
|
||||
{
|
||||
private ChronoLatch latch;
|
||||
private KList<FileWatcher> watchers;
|
||||
private KSet<FileWatcher> watchers;
|
||||
|
||||
public IrisHotloadManager()
|
||||
{
|
||||
watchers = new KList<>();
|
||||
watchers = new KSet<>();
|
||||
latch = new ChronoLatch(3000);
|
||||
}
|
||||
|
||||
|
@ -1,15 +1,21 @@
|
||||
package ninja.bytecode.iris;
|
||||
|
||||
import lombok.Data;
|
||||
import ninja.bytecode.iris.util.RollingSequence;
|
||||
import ninja.bytecode.shuriken.math.RollingSequence;
|
||||
|
||||
@Data
|
||||
public class IrisMetrics
|
||||
{
|
||||
private final RollingSequence total;
|
||||
private final RollingSequence perSecond;
|
||||
private final RollingSequence loss;
|
||||
public int generators = 0;
|
||||
public int noiseHits = 0;
|
||||
|
||||
public IrisMetrics(int memory)
|
||||
{
|
||||
total = new RollingSequence(memory);
|
||||
perSecond = new RollingSequence(5);
|
||||
loss = new RollingSequence(memory);
|
||||
}
|
||||
}
|
||||
|
@ -8,8 +8,8 @@ import ninja.bytecode.iris.object.IrisRegion;
|
||||
import ninja.bytecode.iris.util.BiomeResult;
|
||||
import ninja.bytecode.iris.util.CellGenerator;
|
||||
import ninja.bytecode.iris.util.GenLayer;
|
||||
import ninja.bytecode.iris.util.KList;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
|
||||
public class GenLayerBiome extends GenLayer
|
||||
{
|
||||
|
@ -1,18 +1,21 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import ninja.bytecode.iris.util.CNG;
|
||||
import ninja.bytecode.iris.util.CellGenerator;
|
||||
import ninja.bytecode.iris.util.KList;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
|
||||
@Data
|
||||
public class IrisBiome
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class IrisBiome extends IrisRegisteredObject
|
||||
{
|
||||
private String name = "A Biome";
|
||||
private Biome derivative = Biome.THE_VOID;
|
||||
@ -23,6 +26,7 @@ public class IrisBiome
|
||||
private KList<IrisBiomePaletteLayer> layers = new KList<IrisBiomePaletteLayer>().qadd(new IrisBiomePaletteLayer());
|
||||
private KList<IrisBiomeDecorator> decorators = new KList<IrisBiomeDecorator>();
|
||||
|
||||
private transient ReentrantLock lock = new ReentrantLock();
|
||||
private transient CellGenerator childrenCell;
|
||||
private transient InferredType inferredType;
|
||||
private transient KList<CNG> layerHeightGenerators;
|
||||
@ -63,7 +67,15 @@ public class IrisBiome
|
||||
break;
|
||||
}
|
||||
|
||||
data.add(palette.get(sgen.fit(0, palette.size() - 1, (wx + j) / layers.get(i).getTerrainZoom(), (wz - j) / layers.get(i).getTerrainZoom())));
|
||||
try
|
||||
{
|
||||
data.add(palette.get(sgen.fit(0, palette.size() - 1, (wx + j) / layers.get(i).getTerrainZoom(), (wz - j) / layers.get(i).getTerrainZoom())));
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if(data.size() >= maxDepth)
|
||||
@ -77,6 +89,7 @@ public class IrisBiome
|
||||
|
||||
public KList<CNG> getLayerSurfaceGenerators(RNG rng)
|
||||
{
|
||||
lock.lock();
|
||||
if(layerSurfaceGenerators == null)
|
||||
{
|
||||
layerSurfaceGenerators = new KList<>();
|
||||
@ -88,12 +101,14 @@ public class IrisBiome
|
||||
layerSurfaceGenerators.add(i.getGenerator(rng.nextParallelRNG((m += 3) * m * m * m)));
|
||||
}
|
||||
}
|
||||
lock.unlock();
|
||||
|
||||
return layerSurfaceGenerators;
|
||||
}
|
||||
|
||||
public KList<CNG> getLayerHeightGenerators(RNG rng)
|
||||
{
|
||||
lock.lock();
|
||||
if(layerHeightGenerators == null)
|
||||
{
|
||||
layerHeightGenerators = new KList<>();
|
||||
@ -105,6 +120,7 @@ public class IrisBiome
|
||||
layerHeightGenerators.add(i.getGenerator(rng.nextParallelRNG((m++) * m * m * m)));
|
||||
}
|
||||
}
|
||||
lock.unlock();
|
||||
|
||||
return layerHeightGenerators;
|
||||
}
|
||||
|
@ -5,9 +5,9 @@ import org.bukkit.block.data.BlockData;
|
||||
|
||||
import lombok.Data;
|
||||
import ninja.bytecode.iris.util.CNG;
|
||||
import ninja.bytecode.iris.util.KList;
|
||||
import ninja.bytecode.iris.util.KMap;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
import ninja.bytecode.shuriken.collections.KMap;
|
||||
|
||||
@Data
|
||||
public class IrisBiomeDecorator
|
||||
|
@ -1,13 +1,15 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import lombok.Data;
|
||||
import ninja.bytecode.iris.util.BlockDataTools;
|
||||
import ninja.bytecode.iris.util.CNG;
|
||||
import ninja.bytecode.iris.util.KList;
|
||||
import ninja.bytecode.iris.util.KMap;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
import ninja.bytecode.shuriken.collections.KMap;
|
||||
|
||||
@Data
|
||||
public class IrisBiomePaletteLayer
|
||||
@ -18,6 +20,7 @@ public class IrisBiomePaletteLayer
|
||||
private double terrainZoom = 5;
|
||||
private KList<String> palette = new KList<String>().qadd("GRASS_BLOCK");
|
||||
|
||||
private transient ReentrantLock lock = new ReentrantLock();
|
||||
private transient KMap<Long, CNG> layerGenerators;
|
||||
private transient KList<BlockData> blockData;
|
||||
|
||||
@ -47,26 +50,20 @@ public class IrisBiomePaletteLayer
|
||||
|
||||
public KList<BlockData> getBlockData()
|
||||
{
|
||||
lock.lock();
|
||||
if(blockData == null)
|
||||
{
|
||||
blockData = new KList<>();
|
||||
for(String i : palette)
|
||||
for(String ix : palette)
|
||||
{
|
||||
try
|
||||
BlockData bx = BlockDataTools.getBlockData(ix);
|
||||
if(bx != null)
|
||||
{
|
||||
Material m = Material.valueOf(i);
|
||||
|
||||
if(m != null)
|
||||
{
|
||||
blockData.add(m.createBlockData());
|
||||
}
|
||||
}
|
||||
catch(Throwable e)
|
||||
{
|
||||
|
||||
blockData.add(bx);
|
||||
}
|
||||
}
|
||||
}
|
||||
lock.unlock();
|
||||
|
||||
return blockData;
|
||||
}
|
||||
|
@ -3,12 +3,14 @@ package ninja.bytecode.iris.object;
|
||||
import org.bukkit.World.Environment;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import ninja.bytecode.iris.util.CNG;
|
||||
import ninja.bytecode.iris.util.KList;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
|
||||
@Data
|
||||
public class IrisDimension
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class IrisDimension extends IrisRegisteredObject
|
||||
{
|
||||
private String name = "A Dimension";
|
||||
private InterpolationMethod interpolationFunction = InterpolationMethod.BICUBIC;
|
||||
|
@ -1,10 +1,12 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import lombok.Data;
|
||||
import ninja.bytecode.iris.util.KList;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
|
||||
@Data
|
||||
public class IrisRegion
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class IrisRegion extends IrisRegisteredObject
|
||||
{
|
||||
private String name = "A Region";
|
||||
private double shoreRatio = 0.13;
|
||||
|
@ -0,0 +1,9 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class IrisRegisteredObject
|
||||
{
|
||||
private String loadKey;
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package ninja.bytecode.iris.object.atomics;
|
||||
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.generator.ChunkGenerator.BiomeGrid;
|
||||
import org.bukkit.generator.ChunkGenerator.ChunkData;
|
||||
|
||||
public class AtomicSliver
|
||||
{
|
||||
private BlockData[] block;
|
||||
private Biome[] biome;
|
||||
private int highestBlock = 0;
|
||||
private int highestBiome = 0;
|
||||
private int x;
|
||||
private int z;
|
||||
|
||||
public AtomicSliver(int x, int z)
|
||||
{
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
this.block = new BlockData[256];
|
||||
this.biome = new Biome[256];
|
||||
}
|
||||
|
||||
public void set(int h, BlockData d)
|
||||
{
|
||||
block[h] = d;
|
||||
highestBlock = h > highestBlock ? h : highestBlock;
|
||||
}
|
||||
|
||||
public void set(int h, Biome d)
|
||||
{
|
||||
biome[h] = d;
|
||||
highestBiome = h > highestBiome ? h : highestBiome;
|
||||
}
|
||||
|
||||
public void write(ChunkData d)
|
||||
{
|
||||
for(int i = 0; i <= highestBlock; i++)
|
||||
{
|
||||
d.setBlock(x, i, z, block[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void write(BiomeGrid d)
|
||||
{
|
||||
for(int i = 0; i <= highestBiome; i++)
|
||||
{
|
||||
d.setBiome(x, i, z, biome[i]);
|
||||
}
|
||||
}
|
||||
}
|
72
src/main/java/ninja/bytecode/iris/util/BlockDataTools.java
Normal file
72
src/main/java/ninja/bytecode/iris/util/BlockDataTools.java
Normal file
@ -0,0 +1,72 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import ninja.bytecode.iris.Iris;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
import ninja.bytecode.shuriken.collections.KMap;
|
||||
|
||||
public class BlockDataTools
|
||||
{
|
||||
private static final KMap<String, BlockData> bdc = new KMap<>();
|
||||
private static final KList<String> nulls = new KList<>();
|
||||
|
||||
public static BlockData getBlockData(String bd)
|
||||
{
|
||||
if(bdc.containsKey(bd))
|
||||
{
|
||||
return bdc.get(bd).clone();
|
||||
}
|
||||
|
||||
BlockData bdx = parseBlockData(bd);
|
||||
|
||||
if(bdx == null)
|
||||
{
|
||||
Iris.warn("Unknown Block Data '" + bd + "'");
|
||||
nulls.add(bd);
|
||||
return bdx;
|
||||
}
|
||||
|
||||
bdc.put(bd, bdx);
|
||||
|
||||
return bdx;
|
||||
}
|
||||
|
||||
public static BlockData parseBlockData(String ix)
|
||||
{
|
||||
try
|
||||
{
|
||||
BlockData bx = Bukkit.createBlockData(ix);
|
||||
|
||||
if(bx != null)
|
||||
{
|
||||
return bx;
|
||||
}
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
String i = ix.toUpperCase().trim();
|
||||
i = i.equals("WOOL") ? "WHITE_WOOL" : i;
|
||||
i = i.equals("CONCRETE") ? "WHITE_CONCRETE" : i;
|
||||
|
||||
try
|
||||
{
|
||||
Material m = Material.valueOf(i);
|
||||
|
||||
return m.createBlockData();
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
131
src/main/java/ninja/bytecode/iris/util/Board.java
Normal file
131
src/main/java/ninja/bytecode/iris/util/Board.java
Normal file
@ -0,0 +1,131 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.scoreboard.DisplaySlot;
|
||||
import org.bukkit.scoreboard.Objective;
|
||||
import org.bukkit.scoreboard.Scoreboard;
|
||||
import org.bukkit.scoreboard.Team;
|
||||
|
||||
import lombok.NonNull;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author Missionary (missionarymc@gmail.com)
|
||||
* @since 3/23/2018
|
||||
*/
|
||||
public class Board {
|
||||
|
||||
private static final String[] CACHED_ENTRIES = new String[ChatColor.values().length];
|
||||
|
||||
private static final Function<String, String> APPLY_COLOR_TRANSLATION = s -> ChatColor.translateAlternateColorCodes('&', s);
|
||||
|
||||
static {
|
||||
IntStream.range(0, 15).forEach(i -> CACHED_ENTRIES[i] = ChatColor.values()[i].toString() + ChatColor.RESET);
|
||||
}
|
||||
|
||||
private final Player player;
|
||||
private final Objective objective;
|
||||
private final Team team;
|
||||
@Setter private BoardSettings boardSettings;
|
||||
private boolean ready;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public Board(@NonNull final Player player, final BoardSettings boardSettings) {
|
||||
this.player = player;
|
||||
this.boardSettings = boardSettings;
|
||||
this.objective = this.getScoreboard().getObjective("board") == null ? this.getScoreboard().registerNewObjective("board", "dummy") : this.getScoreboard().getObjective("board");
|
||||
this.objective.setDisplaySlot(DisplaySlot.SIDEBAR);
|
||||
this.team = this.getScoreboard().getTeam("board") == null ? this.getScoreboard().registerNewTeam("board") : this.getScoreboard().getTeam("board");
|
||||
this.team.setAllowFriendlyFire(true);
|
||||
this.team.setCanSeeFriendlyInvisibles(false);
|
||||
this.team.setPrefix("");
|
||||
this.team.setSuffix("");
|
||||
this.ready = true;
|
||||
}
|
||||
|
||||
public Scoreboard getScoreboard() {
|
||||
return (player != null) ? player.getScoreboard() : null;
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
this.resetScoreboard();
|
||||
}
|
||||
|
||||
public void update() {
|
||||
// Checking if we are ready to start updating the Scoreboard.
|
||||
if (!ready) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Making sure the player is connected.
|
||||
if (!player.isOnline()) {
|
||||
remove();
|
||||
return;
|
||||
}
|
||||
|
||||
// Making sure the Scoreboard Provider is set.
|
||||
if (boardSettings == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Getting their Scoreboard display from the Scoreboard Provider.
|
||||
final List<String> entries = boardSettings.getBoardProvider().getLines(player).stream().map(APPLY_COLOR_TRANSLATION).collect(Collectors.toList());
|
||||
|
||||
if (boardSettings.getScoreDirection() == ScoreDirection.UP) {
|
||||
Collections.reverse(entries);
|
||||
}
|
||||
|
||||
// Setting the Scoreboard title
|
||||
String title = boardSettings.getBoardProvider().getTitle(player);
|
||||
if (title.length() > 32) {
|
||||
Bukkit.getLogger().warning("The title " + title + " is over 32 characters in length, substringing to prevent errors.");
|
||||
title = title.substring(0, 32);
|
||||
}
|
||||
objective.setDisplayName(ChatColor.translateAlternateColorCodes('&', title));
|
||||
|
||||
// Clearing previous Scoreboard values if entry sizes don't match.
|
||||
if (this.getScoreboard().getEntries().size() != entries.size())
|
||||
this.getScoreboard().getEntries().forEach(this::removeEntry);
|
||||
|
||||
// Setting Scoreboard lines.
|
||||
for (int i = 0; i < entries.size(); i++) {
|
||||
String str = entries.get(i);
|
||||
BoardEntry entry = BoardEntry.translateToEntry(str);
|
||||
Team team = getScoreboard().getTeam(CACHED_ENTRIES[i]);
|
||||
|
||||
if (team == null) {
|
||||
team = this.getScoreboard().registerNewTeam(CACHED_ENTRIES[i]);
|
||||
team.addEntry(team.getName());
|
||||
}
|
||||
|
||||
team.setPrefix(entry.getPrefix());
|
||||
team.setSuffix(entry.getSuffix());
|
||||
|
||||
switch (boardSettings.getScoreDirection()) {
|
||||
case UP:
|
||||
objective.getScore(team.getName()).setScore(1 + i);
|
||||
break;
|
||||
case DOWN:
|
||||
objective.getScore(team.getName()).setScore(15 - i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeEntry(String id) {
|
||||
this.getScoreboard().resetScores(id);
|
||||
}
|
||||
|
||||
public void resetScoreboard() {
|
||||
ready = false;
|
||||
player.setScoreboard(Bukkit.getScoreboardManager().getMainScoreboard());
|
||||
}
|
||||
}
|
40
src/main/java/ninja/bytecode/iris/util/BoardEntry.java
Normal file
40
src/main/java/ninja/bytecode/iris/util/BoardEntry.java
Normal file
@ -0,0 +1,40 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.bukkit.ChatColor;
|
||||
|
||||
/**
|
||||
* @author Missionary (missionarymc@gmail.com)
|
||||
* @since 3/29/2018
|
||||
*/
|
||||
public class BoardEntry {
|
||||
|
||||
@Getter
|
||||
private final String prefix, suffix;
|
||||
|
||||
private BoardEntry(final String prefix, final String suffix) {
|
||||
this.prefix = prefix;
|
||||
this.suffix = suffix;
|
||||
}
|
||||
|
||||
public static BoardEntry translateToEntry(String input) {
|
||||
if (input.isEmpty()) {
|
||||
return new BoardEntry("", "");
|
||||
}
|
||||
if (input.length() <= 16) {
|
||||
return new BoardEntry(input, "");
|
||||
} else {
|
||||
String prefix = input.substring(0, 16);
|
||||
String suffix = "";
|
||||
|
||||
if (prefix.endsWith("\u00a7")) {
|
||||
prefix = prefix.substring(0, prefix.length() - 1);
|
||||
suffix = "\u00a7" + suffix;
|
||||
}
|
||||
|
||||
suffix = StringUtils.left(ChatColor.getLastColors(prefix) + suffix + input.substring(16), 16);
|
||||
return new BoardEntry(prefix, suffix);
|
||||
}
|
||||
}
|
||||
}
|
86
src/main/java/ninja/bytecode/iris/util/BoardManager.java
Normal file
86
src/main/java/ninja/bytecode/iris/util/BoardManager.java
Normal file
@ -0,0 +1,86 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* @author Missionary (missionarymc@gmail.com)
|
||||
* @since 3/23/2018
|
||||
*/
|
||||
public class BoardManager implements Listener {
|
||||
|
||||
private final JavaPlugin plugin;
|
||||
private BoardSettings boardSettings;
|
||||
private Map<UUID, Board> scoreboards;
|
||||
private BukkitTask updateTask;
|
||||
|
||||
public BoardManager(JavaPlugin plugin, BoardSettings boardSettings) {
|
||||
this.plugin = plugin;
|
||||
this.boardSettings = boardSettings;
|
||||
this.scoreboards = new ConcurrentHashMap<>();
|
||||
this.updateTask = new BoardUpdateTask(this).runTaskTimer(plugin, 2L, 2L);
|
||||
plugin.getServer().getPluginManager().registerEvents(this, plugin);
|
||||
plugin.getServer().getOnlinePlayers().forEach(this::setup);
|
||||
}
|
||||
|
||||
public void setBoardSettings(BoardSettings boardSettings) {
|
||||
this.boardSettings = boardSettings;
|
||||
scoreboards.values().forEach(board -> board.setBoardSettings(boardSettings));
|
||||
}
|
||||
|
||||
public boolean hasBoard(Player player) {
|
||||
return scoreboards.containsKey(player.getUniqueId());
|
||||
}
|
||||
|
||||
public Optional<Board> getBoard(Player player) {
|
||||
return Optional.ofNullable(scoreboards.get(player.getUniqueId()));
|
||||
}
|
||||
|
||||
private void setup(Player player) {
|
||||
Optional.ofNullable(scoreboards.remove(player.getUniqueId())).ifPresent(Board::resetScoreboard);
|
||||
if (player.getScoreboard() == Bukkit.getScoreboardManager().getMainScoreboard()) {
|
||||
player.setScoreboard(Bukkit.getScoreboardManager().getNewScoreboard());
|
||||
}
|
||||
scoreboards.put(player.getUniqueId(), new Board(player, boardSettings));
|
||||
}
|
||||
|
||||
private void remove(Player player) {
|
||||
Optional.ofNullable(scoreboards.remove(player.getUniqueId())).ifPresent(Board::remove);
|
||||
}
|
||||
|
||||
public Map<UUID, Board> getScoreboards() {
|
||||
return Collections.unmodifiableMap(scoreboards);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onJoin(final PlayerJoinEvent e) {
|
||||
plugin.getServer().getScheduler().runTaskLater(plugin, () -> {
|
||||
if (e.getPlayer().isOnline()) { // Set this up 2 ticks later.
|
||||
setup(e.getPlayer());
|
||||
}
|
||||
}, 2L);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onQuit(final PlayerQuitEvent e) {
|
||||
this.remove(e.getPlayer());
|
||||
}
|
||||
|
||||
public void onDisable() {
|
||||
updateTask.cancel();
|
||||
plugin.getServer().getOnlinePlayers().forEach(this::remove);
|
||||
scoreboards.clear();
|
||||
}
|
||||
}
|
25
src/main/java/ninja/bytecode/iris/util/BoardProvider.java
Normal file
25
src/main/java/ninja/bytecode/iris/util/BoardProvider.java
Normal file
@ -0,0 +1,25 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.scoreboard.Objective;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface BoardProvider {
|
||||
|
||||
/**
|
||||
* Gets the title for {@link Objective#getDisplayName()}
|
||||
*
|
||||
* @param player The {@link Player} to supply
|
||||
* @return The title for the objective
|
||||
*/
|
||||
String getTitle(Player player);
|
||||
|
||||
/**
|
||||
* Gets the contents to be displayed on the {@link Board}
|
||||
*
|
||||
* @param player The {@link Player} to supply
|
||||
* @return The {@link List} of contents
|
||||
*/
|
||||
List<String> getLines(Player player);
|
||||
}
|
18
src/main/java/ninja/bytecode/iris/util/BoardSettings.java
Normal file
18
src/main/java/ninja/bytecode/iris/util/BoardSettings.java
Normal file
@ -0,0 +1,18 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author Missionary (missionarymc@gmail.com)
|
||||
* @since 5/31/2018
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
public class BoardSettings {
|
||||
|
||||
private BoardProvider boardProvider;
|
||||
|
||||
private ScoreDirection scoreDirection;
|
||||
|
||||
}
|
26
src/main/java/ninja/bytecode/iris/util/BoardUpdateTask.java
Normal file
26
src/main/java/ninja/bytecode/iris/util/BoardUpdateTask.java
Normal file
@ -0,0 +1,26 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* @author Missionary (missionarymc@gmail.com)
|
||||
* @since 5/31/2018
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class BoardUpdateTask extends BukkitRunnable {
|
||||
|
||||
private static final Predicate<UUID> PLAYER_IS_ONLINE = uuid -> Bukkit.getPlayer(uuid) != null;
|
||||
|
||||
private final BoardManager boardManager;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
boardManager.getScoreboards().entrySet().stream().filter(entrySet -> PLAYER_IS_ONLINE.test(entrySet.getKey())).forEach(entrySet -> entrySet.getValue().update());
|
||||
}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
|
||||
public class CNG
|
||||
{
|
||||
public static long hits = 0;
|
||||
@ -33,13 +35,13 @@ public class CNG
|
||||
public static CNG signature(RNG rng)
|
||||
{
|
||||
//@builder
|
||||
return new CNG(rng.nextParallelRNG(17), 1D, 8)
|
||||
return new CNG(rng.nextParallelRNG(17), 1D, 3)
|
||||
.scale(0.012)
|
||||
.fractureWith(new CNG(rng.nextParallelRNG(18), 1, 5)
|
||||
.fractureWith(new CNG(rng.nextParallelRNG(18), 1, 2)
|
||||
.scale(0.018)
|
||||
.child(new CNG(rng.nextParallelRNG(19), 1, 2)
|
||||
.scale(0.1))
|
||||
.fractureWith(new CNG(rng.nextParallelRNG(20), 1, 3)
|
||||
.fractureWith(new CNG(rng.nextParallelRNG(20), 1, 2)
|
||||
.scale(0.15), 24), 44).down(0.3).patch(2.5);
|
||||
//@done
|
||||
}
|
||||
|
16
src/main/java/ninja/bytecode/iris/util/ChunkPosition.java
Normal file
16
src/main/java/ninja/bytecode/iris/util/ChunkPosition.java
Normal file
@ -0,0 +1,16 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ChunkPosition
|
||||
{
|
||||
private int x;
|
||||
private int z;
|
||||
|
||||
public ChunkPosition(int x, int z)
|
||||
{
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
}
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class Chunker<T>
|
||||
{
|
||||
private ExecutorService executor;
|
||||
private int threads;
|
||||
private int workload;
|
||||
private KList<T> q;
|
||||
|
||||
public Chunker(KList<T> q)
|
||||
{
|
||||
this.q = q;
|
||||
}
|
||||
|
||||
public Chunker<T> threads(int threads)
|
||||
{
|
||||
this.threads = threads;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Chunker<T> workload(int workload)
|
||||
{
|
||||
this.workload = workload;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void execute(Consumer<T> consumer, Callback<Double> progress, int progressInterval)
|
||||
{
|
||||
ChronoLatch cl = new ChronoLatch(progressInterval);
|
||||
Contained<Integer> consumed = new Contained<Integer>(0);
|
||||
executor = Executors.newFixedThreadPool(threads);
|
||||
int length = q.size();
|
||||
int remaining = length;
|
||||
|
||||
while(remaining > 0)
|
||||
{
|
||||
int at = remaining;
|
||||
remaining -= (remaining > workload ? workload : remaining);
|
||||
int to = remaining;
|
||||
|
||||
executor.submit(() ->
|
||||
{
|
||||
J.dofor(at, (i) -> i >= to, -1, (i) -> J.attempt(() -> consumer.accept(q.get(i))));
|
||||
consumed.mod((c) -> c += workload);
|
||||
J.doif(() -> progress != null && cl.flip(), () -> progress.run((double) consumed.get() / (double) length));
|
||||
});
|
||||
}
|
||||
|
||||
executor.shutdown();
|
||||
J.attempt(() -> executor.awaitTermination(100, TimeUnit.HOURS));
|
||||
}
|
||||
}
|
@ -2,8 +2,10 @@ package ninja.bytecode.iris.util;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
|
||||
@Data
|
||||
public class FileWatcher
|
||||
{
|
||||
@Getter
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,50 +0,0 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import javax.script.ScriptException;
|
||||
|
||||
/**
|
||||
* Evaluates an expression using javascript engine and returns the double
|
||||
* result. This can take variable parameters, so you need to define them.
|
||||
* Parameters are defined as $[0-9]. For example evaluate("4$0/$1", 1, 2); This
|
||||
* makes the expression (4x1)/2 == 2. Keep note that you must use 0-9, you
|
||||
* cannot skip, or start at a number other than 0.
|
||||
*
|
||||
* @author cyberpwn
|
||||
*/
|
||||
public class Formula
|
||||
{
|
||||
private String expression;
|
||||
|
||||
/**
|
||||
* Evaluates an expression using javascript engine and returns the double
|
||||
* result. This can take variable parameters, so you need to define them.
|
||||
* Parameters are defined as $[0-9]. For example evaluate("4$0/$1", 1, 2); This
|
||||
* makes the expression (4x1)/2 == 2. Keep note that you must use 0-9, you
|
||||
* cannot skip, or start at a number other than 0.
|
||||
*
|
||||
* @param expression
|
||||
* the expression with variables
|
||||
* @param args
|
||||
* the arguments/variables
|
||||
*/
|
||||
public Formula(String expression)
|
||||
{
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the given args
|
||||
*
|
||||
* @param args
|
||||
* the args
|
||||
* @return the return result
|
||||
* @throws IndexOutOfBoundsException
|
||||
* invalid number of args
|
||||
* @throws ScriptException
|
||||
* syntax issue
|
||||
*/
|
||||
public double evaluate(Double... args) throws IndexOutOfBoundsException, ScriptException
|
||||
{
|
||||
return M.evaluate(expression, args);
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Function2<A, B, R>
|
||||
{
|
||||
public R apply(A a, B b);
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Function3<A, B, C, R>
|
||||
{
|
||||
public R apply(A a, B b, C c);
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Function4<A, B, C, D, R>
|
||||
{
|
||||
public R apply(A a, B b, C c, D d);
|
||||
}
|
122
src/main/java/ninja/bytecode/iris/util/GroupedExecutor.java
Normal file
122
src/main/java/ninja/bytecode/iris/util/GroupedExecutor.java
Normal file
@ -0,0 +1,122 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory;
|
||||
import java.util.concurrent.ForkJoinWorkerThread;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import ninja.bytecode.shuriken.collections.KMap;
|
||||
import ninja.bytecode.shuriken.execution.J;
|
||||
import ninja.bytecode.shuriken.execution.NastyRunnable;
|
||||
|
||||
public class GroupedExecutor
|
||||
{
|
||||
private int xc;
|
||||
private ExecutorService service;
|
||||
private ReentrantLock lock;
|
||||
private KMap<String, Integer> mirror;
|
||||
|
||||
public GroupedExecutor(int threadLimit, int priority, String name)
|
||||
{
|
||||
xc = 1;
|
||||
lock = new ReentrantLock();
|
||||
mirror = new KMap<String, Integer>();
|
||||
|
||||
if(threadLimit == 1)
|
||||
{
|
||||
service = Executors.newSingleThreadExecutor((r) ->
|
||||
{
|
||||
Thread t = new Thread(r);
|
||||
t.setName(name);
|
||||
t.setPriority(priority);
|
||||
|
||||
return t;
|
||||
});
|
||||
}
|
||||
|
||||
else if(threadLimit > 1)
|
||||
{
|
||||
final ForkJoinWorkerThreadFactory factory = new ForkJoinWorkerThreadFactory()
|
||||
{
|
||||
@Override
|
||||
public ForkJoinWorkerThread newThread(ForkJoinPool pool)
|
||||
{
|
||||
final ForkJoinWorkerThread worker = ForkJoinPool.defaultForkJoinWorkerThreadFactory.newThread(pool);
|
||||
worker.setName(name + " " + xc++);
|
||||
worker.setPriority(priority);
|
||||
return worker;
|
||||
}
|
||||
};
|
||||
|
||||
service = new ForkJoinPool(threadLimit, factory, null, false);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
service = Executors.newCachedThreadPool((r) ->
|
||||
{
|
||||
Thread t = new Thread(r);
|
||||
t.setName(name + " " + xc++);
|
||||
t.setPriority(priority);
|
||||
|
||||
return t;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void waitFor(String g)
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
J.sleep(1);
|
||||
|
||||
if(mirror.get(g) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void queue(String q, NastyRunnable r)
|
||||
{
|
||||
lock.lock();
|
||||
if(!mirror.containsKey(q))
|
||||
{
|
||||
mirror.put(q, 0);
|
||||
}
|
||||
mirror.put(q, mirror.get(q) + 1);
|
||||
lock.unlock();
|
||||
service.execute(() ->
|
||||
{
|
||||
try
|
||||
{
|
||||
r.run();
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
lock.lock();
|
||||
mirror.put(q, mirror.get(q) - 1);
|
||||
lock.unlock();
|
||||
});
|
||||
}
|
||||
|
||||
public void close()
|
||||
{
|
||||
J.a(() ->
|
||||
{
|
||||
J.sleep(10000);
|
||||
service.shutdown();
|
||||
});
|
||||
}
|
||||
|
||||
public void closeNow()
|
||||
{
|
||||
service.shutdown();
|
||||
}
|
||||
}
|
@ -1,201 +0,0 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
|
||||
/*
|
||||
Copyright (c) 2002 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* Convert an HTTP header to a JSONObject and back.
|
||||
*
|
||||
* @author JSON.org
|
||||
* @version 2014-05-03
|
||||
*/
|
||||
public class HTTP
|
||||
{
|
||||
|
||||
/** Carriage return/line feed. */
|
||||
public static final String CRLF = "\r\n";
|
||||
|
||||
/**
|
||||
* Convert an HTTP header string into a JSONObject. It can be a request
|
||||
* header or a response header. A request header will contain
|
||||
*
|
||||
* <pre>
|
||||
* {
|
||||
* Method: "POST" (for example),
|
||||
* "Request-URI": "/" (for example),
|
||||
* "HTTP-Version": "HTTP/1.1" (for example)
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* A response header will contain
|
||||
*
|
||||
* <pre>
|
||||
* {
|
||||
* "HTTP-Version": "HTTP/1.1" (for example),
|
||||
* "Status-Code": "200" (for example),
|
||||
* "Reason-Phrase": "OK" (for example)
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* In addition, the other parameters in the header will be captured, using
|
||||
* the HTTP field names as JSON names, so that
|
||||
*
|
||||
* <pre>
|
||||
* Date: Sun, 26 May 2002 18:06:04 GMT
|
||||
* Cookie: Q=q2=PPEAsg--; B=677gi6ouf29bn&b=2&f=s
|
||||
* Cache-Control: no-cache
|
||||
* </pre>
|
||||
*
|
||||
* become
|
||||
*
|
||||
* <pre>
|
||||
* {...
|
||||
* Date: "Sun, 26 May 2002 18:06:04 GMT",
|
||||
* Cookie: "Q=q2=PPEAsg--; B=677gi6ouf29bn&b=2&f=s",
|
||||
* "Cache-Control": "no-cache",
|
||||
* ...}
|
||||
* </pre>
|
||||
*
|
||||
* It does no further checking or conversion. It does not parse dates. It
|
||||
* does not do '%' transforms on URLs.
|
||||
*
|
||||
* @param string
|
||||
* An HTTP header string.
|
||||
* @return A JSONObject containing the elements and attributes of the XML
|
||||
* string.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static JSONObject toJSONObject(String string) throws JSONException
|
||||
{
|
||||
JSONObject jo = new JSONObject();
|
||||
HTTPTokener x = new HTTPTokener(string);
|
||||
String token;
|
||||
|
||||
token = x.nextToken();
|
||||
if(token.toUpperCase().startsWith("HTTP"))
|
||||
{
|
||||
|
||||
// Response
|
||||
|
||||
jo.put("HTTP-Version", token);
|
||||
jo.put("Status-Code", x.nextToken());
|
||||
jo.put("Reason-Phrase", x.nextTo('\0'));
|
||||
x.next();
|
||||
|
||||
} else
|
||||
{
|
||||
|
||||
// Request
|
||||
|
||||
jo.put("Method", token);
|
||||
jo.put("Request-URI", x.nextToken());
|
||||
jo.put("HTTP-Version", x.nextToken());
|
||||
}
|
||||
|
||||
// Fields
|
||||
|
||||
while(x.more())
|
||||
{
|
||||
String name = x.nextTo(':');
|
||||
x.next(':');
|
||||
jo.put(name, x.nextTo('\0'));
|
||||
x.next();
|
||||
}
|
||||
return jo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a JSONObject into an HTTP header. A request header must contain
|
||||
*
|
||||
* <pre>
|
||||
* {
|
||||
* Method: "POST" (for example),
|
||||
* "Request-URI": "/" (for example),
|
||||
* "HTTP-Version": "HTTP/1.1" (for example)
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* A response header must contain
|
||||
*
|
||||
* <pre>
|
||||
* {
|
||||
* "HTTP-Version": "HTTP/1.1" (for example),
|
||||
* "Status-Code": "200" (for example),
|
||||
* "Reason-Phrase": "OK" (for example)
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* Any other members of the JSONObject will be output as HTTP fields. The
|
||||
* result will end with two CRLF pairs.
|
||||
*
|
||||
* @param jo
|
||||
* A JSONObject
|
||||
* @return An HTTP header string.
|
||||
* @throws JSONException
|
||||
* if the object does not contain enough information.
|
||||
*/
|
||||
public static String toString(JSONObject jo) throws JSONException
|
||||
{
|
||||
Iterator<String> keys = jo.keys();
|
||||
String string;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if(jo.has("Status-Code") && jo.has("Reason-Phrase"))
|
||||
{
|
||||
sb.append(jo.getString("HTTP-Version"));
|
||||
sb.append(' ');
|
||||
sb.append(jo.getString("Status-Code"));
|
||||
sb.append(' ');
|
||||
sb.append(jo.getString("Reason-Phrase"));
|
||||
} else if(jo.has("Method") && jo.has("Request-URI"))
|
||||
{
|
||||
sb.append(jo.getString("Method"));
|
||||
sb.append(' ');
|
||||
sb.append('"');
|
||||
sb.append(jo.getString("Request-URI"));
|
||||
sb.append('"');
|
||||
sb.append(' ');
|
||||
sb.append(jo.getString("HTTP-Version"));
|
||||
} else
|
||||
{
|
||||
throw new JSONException("Not enough material for an HTTP header.");
|
||||
}
|
||||
sb.append(CRLF);
|
||||
while(keys.hasNext())
|
||||
{
|
||||
string = keys.next();
|
||||
if(!"HTTP-Version".equals(string) && !"Status-Code".equals(string) && !"Reason-Phrase".equals(string) && !"Method".equals(string) && !"Request-URI".equals(string) && !jo.isNull(string))
|
||||
{
|
||||
sb.append(string);
|
||||
sb.append(": ");
|
||||
sb.append(jo.getString(string));
|
||||
sb.append(CRLF);
|
||||
}
|
||||
}
|
||||
sb.append(CRLF);
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
@ -1,91 +0,0 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
|
||||
/*
|
||||
Copyright (c) 2002 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The HTTPTokener extends the JSONTokener to provide additional methods for the
|
||||
* parsing of HTTP headers.
|
||||
*
|
||||
* @author JSON.org
|
||||
* @version 2014-05-03
|
||||
*/
|
||||
public class HTTPTokener extends JSONTokener
|
||||
{
|
||||
|
||||
/**
|
||||
* Construct an HTTPTokener from a string.
|
||||
*
|
||||
* @param string
|
||||
* A source string.
|
||||
*/
|
||||
public HTTPTokener(String string)
|
||||
{
|
||||
super(string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next token or string. This is used in parsing HTTP headers.
|
||||
*
|
||||
* @throws JSONException
|
||||
* @return A String.
|
||||
*/
|
||||
public String nextToken() throws JSONException
|
||||
{
|
||||
char c;
|
||||
char q;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
do
|
||||
{
|
||||
c = next();
|
||||
} while(Character.isWhitespace(c));
|
||||
if(c == '"' || c == '\'')
|
||||
{
|
||||
q = c;
|
||||
for(;;)
|
||||
{
|
||||
c = next();
|
||||
if(c < ' ')
|
||||
{
|
||||
throw syntaxError("Unterminated string.");
|
||||
}
|
||||
if(c == q)
|
||||
{
|
||||
return sb.toString();
|
||||
}
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
for(;;)
|
||||
{
|
||||
if(c == 0 || Character.isWhitespace(c))
|
||||
{
|
||||
return sb.toString();
|
||||
}
|
||||
sb.append(c);
|
||||
c = next();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import ninja.bytecode.iris.object.InterpolationMethod;
|
||||
import ninja.bytecode.iris.object.IrisDimension;
|
||||
|
||||
public class IrisInterpolation
|
||||
{
|
||||
|
@ -1,133 +0,0 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class J
|
||||
{
|
||||
private static int tid = 0;
|
||||
private static final ExecutorService e = Executors.newCachedThreadPool(new ThreadFactory()
|
||||
{
|
||||
@Override
|
||||
public Thread newThread(Runnable r)
|
||||
{
|
||||
tid++;
|
||||
Thread t = new Thread(r);
|
||||
t.setName("Actuator " + tid);
|
||||
t.setPriority(Thread.MIN_PRIORITY);
|
||||
t.setUncaughtExceptionHandler((et, e) -> {
|
||||
e.printStackTrace();
|
||||
});
|
||||
|
||||
return t;
|
||||
}
|
||||
});
|
||||
|
||||
public static void dofor(int a, Function<Integer, Boolean> c, int ch, Consumer<Integer> d)
|
||||
{
|
||||
for(int i = a; c.apply(i); i+=ch)
|
||||
{
|
||||
c.apply(i);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean doif(Supplier<Boolean> c, Runnable g)
|
||||
{
|
||||
if(c.get())
|
||||
{
|
||||
g.run();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void a(Runnable a)
|
||||
{
|
||||
e.submit(a);
|
||||
}
|
||||
|
||||
public static <T> Future<T> a(Callable<T> a)
|
||||
{
|
||||
return e.submit(a);
|
||||
}
|
||||
|
||||
public static void attemptAsync(NastyRunnable r)
|
||||
{
|
||||
J.a(() -> J.attempt(r));
|
||||
}
|
||||
|
||||
public static <R> R attemptResult(NastyFuture<R> r, R onError)
|
||||
{
|
||||
try
|
||||
{
|
||||
return r.run();
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return onError;
|
||||
}
|
||||
|
||||
public static <T, R> R attemptFunction(NastyFunction<T, R> r, T param, R onError)
|
||||
{
|
||||
try
|
||||
{
|
||||
return r.run(param);
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return onError;
|
||||
}
|
||||
|
||||
public static boolean sleep(long ms)
|
||||
{
|
||||
return J.attempt(() -> Thread.sleep(ms));
|
||||
}
|
||||
|
||||
public static boolean attempt(NastyRunnable r)
|
||||
{
|
||||
return attemptCatch(r) == null;
|
||||
}
|
||||
|
||||
public static Throwable attemptCatch(NastyRunnable r)
|
||||
{
|
||||
try
|
||||
{
|
||||
r.run();
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
return e;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static <T> T attempt(Supplier<T> t, T i)
|
||||
{
|
||||
try
|
||||
{
|
||||
return t.get();
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,50 +0,0 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
|
||||
/**
|
||||
* The JSONException is thrown by the JSON.org classes when things are amiss.
|
||||
*
|
||||
* @author JSON.org
|
||||
* @version 2014-05-03
|
||||
*/
|
||||
public class JSONException extends RuntimeException
|
||||
{
|
||||
private static final long serialVersionUID = 0;
|
||||
private Throwable cause;
|
||||
|
||||
/**
|
||||
* Constructs a JSONException with an explanatory message.
|
||||
*
|
||||
* @param message
|
||||
* Detail about the reason for the exception.
|
||||
*/
|
||||
public JSONException(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new JSONException with the specified cause.
|
||||
*
|
||||
* @param cause
|
||||
* The cause.
|
||||
*/
|
||||
public JSONException(Throwable cause)
|
||||
{
|
||||
super(cause.getMessage());
|
||||
this.cause = cause;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cause of this exception or null if the cause is nonexistent
|
||||
* or unknown.
|
||||
*
|
||||
* @return the cause of this exception or null if the cause is nonexistent
|
||||
* or unknown.
|
||||
*/
|
||||
@Override
|
||||
public Throwable getCause()
|
||||
{
|
||||
return this.cause;
|
||||
}
|
||||
}
|
@ -1,555 +0,0 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
|
||||
/*
|
||||
Copyright (c) 2008 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* This provides static methods to convert an XML text into a JSONArray or
|
||||
* JSONObject, and to covert a JSONArray or JSONObject into an XML text using
|
||||
* the JsonML transform.
|
||||
*
|
||||
* @author JSON.org
|
||||
* @version 2014-05-03
|
||||
*/
|
||||
public class JSONML
|
||||
{
|
||||
|
||||
/**
|
||||
* Parse XML values and store them in a JSONArray.
|
||||
*
|
||||
* @param x
|
||||
* The XMLTokener containing the source string.
|
||||
* @param arrayForm
|
||||
* true if array form, false if object form.
|
||||
* @param ja
|
||||
* The JSONArray that is containing the current tag or null if we
|
||||
* are at the outermost level.
|
||||
* @return A JSONArray if the value is the outermost tag, otherwise null.
|
||||
* @throws JSONException
|
||||
*/
|
||||
private static Object parse(XMLTokener x, boolean arrayForm, JSONArray ja) throws JSONException
|
||||
{
|
||||
String attribute;
|
||||
char c;
|
||||
String closeTag = null;
|
||||
int i;
|
||||
JSONArray newja = null;
|
||||
JSONObject newjo = null;
|
||||
Object token;
|
||||
String tagName = null;
|
||||
|
||||
// Test for and skip past these forms:
|
||||
// <!-- ... -->
|
||||
// <![ ... ]]>
|
||||
// <! ... >
|
||||
// <? ... ?>
|
||||
|
||||
while(true)
|
||||
{
|
||||
if(!x.more())
|
||||
{
|
||||
throw x.syntaxError("Bad XML");
|
||||
}
|
||||
token = x.nextContent();
|
||||
if(token == XML.LT)
|
||||
{
|
||||
token = x.nextToken();
|
||||
if(token instanceof Character)
|
||||
{
|
||||
if(token == XML.SLASH)
|
||||
{
|
||||
|
||||
// Close tag </
|
||||
|
||||
token = x.nextToken();
|
||||
if(!(token instanceof String))
|
||||
{
|
||||
throw new JSONException("Expected a closing name instead of '" + token + "'.");
|
||||
}
|
||||
if(x.nextToken() != XML.GT)
|
||||
{
|
||||
throw x.syntaxError("Misshaped close tag");
|
||||
}
|
||||
return token;
|
||||
} else if(token == XML.BANG)
|
||||
{
|
||||
|
||||
// <!
|
||||
|
||||
c = x.next();
|
||||
if(c == '-')
|
||||
{
|
||||
if(x.next() == '-')
|
||||
{
|
||||
x.skipPast("-->");
|
||||
} else
|
||||
{
|
||||
x.back();
|
||||
}
|
||||
} else if(c == '[')
|
||||
{
|
||||
token = x.nextToken();
|
||||
if(token.equals("CDATA") && x.next() == '[')
|
||||
{
|
||||
if(ja != null)
|
||||
{
|
||||
ja.put(x.nextCDATA());
|
||||
}
|
||||
} else
|
||||
{
|
||||
throw x.syntaxError("Expected 'CDATA['");
|
||||
}
|
||||
} else
|
||||
{
|
||||
i = 1;
|
||||
do
|
||||
{
|
||||
token = x.nextMeta();
|
||||
if(token == null)
|
||||
{
|
||||
throw x.syntaxError("Missing '>' after '<!'.");
|
||||
} else if(token == XML.LT)
|
||||
{
|
||||
i += 1;
|
||||
} else if(token == XML.GT)
|
||||
{
|
||||
i -= 1;
|
||||
}
|
||||
} while(i > 0);
|
||||
}
|
||||
} else if(token == XML.QUEST)
|
||||
{
|
||||
|
||||
// <?
|
||||
|
||||
x.skipPast("?>");
|
||||
} else
|
||||
{
|
||||
throw x.syntaxError("Misshaped tag");
|
||||
}
|
||||
|
||||
// Open tag <
|
||||
|
||||
} else
|
||||
{
|
||||
if(!(token instanceof String))
|
||||
{
|
||||
throw x.syntaxError("Bad tagName '" + token + "'.");
|
||||
}
|
||||
tagName = (String) token;
|
||||
newja = new JSONArray();
|
||||
newjo = new JSONObject();
|
||||
if(arrayForm)
|
||||
{
|
||||
newja.put(tagName);
|
||||
if(ja != null)
|
||||
{
|
||||
ja.put(newja);
|
||||
}
|
||||
} else
|
||||
{
|
||||
newjo.put("tagName", tagName);
|
||||
if(ja != null)
|
||||
{
|
||||
ja.put(newjo);
|
||||
}
|
||||
}
|
||||
token = null;
|
||||
for(;;)
|
||||
{
|
||||
if(token == null)
|
||||
{
|
||||
token = x.nextToken();
|
||||
}
|
||||
if(token == null)
|
||||
{
|
||||
throw x.syntaxError("Misshaped tag");
|
||||
}
|
||||
if(!(token instanceof String))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// attribute = value
|
||||
|
||||
attribute = (String) token;
|
||||
if(!arrayForm && ("tagName".equals(attribute) || "childNode".equals(attribute)))
|
||||
{
|
||||
throw x.syntaxError("Reserved attribute.");
|
||||
}
|
||||
token = x.nextToken();
|
||||
if(token == XML.EQ)
|
||||
{
|
||||
token = x.nextToken();
|
||||
if(!(token instanceof String))
|
||||
{
|
||||
throw x.syntaxError("Missing value");
|
||||
}
|
||||
newjo.accumulate(attribute, XML.stringToValue((String) token));
|
||||
token = null;
|
||||
} else
|
||||
{
|
||||
newjo.accumulate(attribute, "");
|
||||
}
|
||||
}
|
||||
if(arrayForm && newjo.length() > 0)
|
||||
{
|
||||
newja.put(newjo);
|
||||
}
|
||||
|
||||
// Empty tag <.../>
|
||||
|
||||
if(token == XML.SLASH)
|
||||
{
|
||||
if(x.nextToken() != XML.GT)
|
||||
{
|
||||
throw x.syntaxError("Misshaped tag");
|
||||
}
|
||||
if(ja == null)
|
||||
{
|
||||
if(arrayForm)
|
||||
{
|
||||
return newja;
|
||||
} else
|
||||
{
|
||||
return newjo;
|
||||
}
|
||||
}
|
||||
|
||||
// Content, between <...> and </...>
|
||||
|
||||
} else
|
||||
{
|
||||
if(token != XML.GT)
|
||||
{
|
||||
throw x.syntaxError("Misshaped tag");
|
||||
}
|
||||
closeTag = (String) parse(x, arrayForm, newja);
|
||||
if(closeTag != null)
|
||||
{
|
||||
if(!closeTag.equals(tagName))
|
||||
{
|
||||
throw x.syntaxError("Mismatched '" + tagName + "' and '" + closeTag + "'");
|
||||
}
|
||||
tagName = null;
|
||||
if(!arrayForm && newja.length() > 0)
|
||||
{
|
||||
newjo.put("childNodes", newja);
|
||||
}
|
||||
if(ja == null)
|
||||
{
|
||||
if(arrayForm)
|
||||
{
|
||||
return newja;
|
||||
} else
|
||||
{
|
||||
return newjo;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else
|
||||
{
|
||||
if(ja != null)
|
||||
{
|
||||
ja.put(token instanceof String ? XML.stringToValue((String) token) : token);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a well-formed (but not necessarily valid) XML string into a
|
||||
* JSONArray using the JsonML transform. Each XML tag is represented as a
|
||||
* JSONArray in which the first element is the tag name. If the tag has
|
||||
* attributes, then the second element will be JSONObject containing the
|
||||
* name/value pairs. If the tag contains children, then strings and
|
||||
* JSONArrays will represent the child tags. Comments, prologs, DTDs, and
|
||||
* <code><[ [ ]]></code> are ignored.
|
||||
*
|
||||
* @param string
|
||||
* The source string.
|
||||
* @return A JSONArray containing the structured data from the XML string.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static JSONArray toJSONArray(String string) throws JSONException
|
||||
{
|
||||
return toJSONArray(new XMLTokener(string));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a well-formed (but not necessarily valid) XML string into a
|
||||
* JSONArray using the JsonML transform. Each XML tag is represented as a
|
||||
* JSONArray in which the first element is the tag name. If the tag has
|
||||
* attributes, then the second element will be JSONObject containing the
|
||||
* name/value pairs. If the tag contains children, then strings and
|
||||
* JSONArrays will represent the child content and tags. Comments, prologs,
|
||||
* DTDs, and <code><[ [ ]]></code> are ignored.
|
||||
*
|
||||
* @param x
|
||||
* An XMLTokener.
|
||||
* @return A JSONArray containing the structured data from the XML string.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static JSONArray toJSONArray(XMLTokener x) throws JSONException
|
||||
{
|
||||
return (JSONArray) parse(x, true, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a well-formed (but not necessarily valid) XML string into a
|
||||
* JSONObject using the JsonML transform. Each XML tag is represented as a
|
||||
* JSONObject with a "tagName" property. If the tag has attributes, then the
|
||||
* attributes will be in the JSONObject as properties. If the tag contains
|
||||
* children, the object will have a "childNodes" property which will be an
|
||||
* array of strings and JsonML JSONObjects.
|
||||
*
|
||||
* Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored.
|
||||
*
|
||||
* @param x
|
||||
* An XMLTokener of the XML source text.
|
||||
* @return A JSONObject containing the structured data from the XML string.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static JSONObject toJSONObject(XMLTokener x) throws JSONException
|
||||
{
|
||||
return (JSONObject) parse(x, false, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a well-formed (but not necessarily valid) XML string into a
|
||||
* JSONObject using the JsonML transform. Each XML tag is represented as a
|
||||
* JSONObject with a "tagName" property. If the tag has attributes, then the
|
||||
* attributes will be in the JSONObject as properties. If the tag contains
|
||||
* children, the object will have a "childNodes" property which will be an
|
||||
* array of strings and JsonML JSONObjects.
|
||||
*
|
||||
* Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored.
|
||||
*
|
||||
* @param string
|
||||
* The XML source text.
|
||||
* @return A JSONObject containing the structured data from the XML string.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static JSONObject toJSONObject(String string) throws JSONException
|
||||
{
|
||||
return toJSONObject(new XMLTokener(string));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the JSONML transformation, making an XML text from a JSONArray.
|
||||
*
|
||||
* @param ja
|
||||
* A JSONArray.
|
||||
* @return An XML string.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static String toString(JSONArray ja) throws JSONException
|
||||
{
|
||||
int i;
|
||||
JSONObject jo;
|
||||
String key;
|
||||
Iterator<String> keys;
|
||||
int length;
|
||||
Object object;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String tagName;
|
||||
String value;
|
||||
|
||||
// Emit <tagName
|
||||
|
||||
tagName = ja.getString(0);
|
||||
XML.noSpace(tagName);
|
||||
tagName = XML.escape(tagName);
|
||||
sb.append('<');
|
||||
sb.append(tagName);
|
||||
|
||||
object = ja.opt(1);
|
||||
if(object instanceof JSONObject)
|
||||
{
|
||||
i = 2;
|
||||
jo = (JSONObject) object;
|
||||
|
||||
// Emit the attributes
|
||||
|
||||
keys = jo.keys();
|
||||
while(keys.hasNext())
|
||||
{
|
||||
key = keys.next();
|
||||
XML.noSpace(key);
|
||||
value = jo.optString(key);
|
||||
if(value != null)
|
||||
{
|
||||
sb.append(' ');
|
||||
sb.append(XML.escape(key));
|
||||
sb.append('=');
|
||||
sb.append('"');
|
||||
sb.append(XML.escape(value));
|
||||
sb.append('"');
|
||||
}
|
||||
}
|
||||
} else
|
||||
{
|
||||
i = 1;
|
||||
}
|
||||
|
||||
// Emit content in body
|
||||
|
||||
length = ja.length();
|
||||
if(i >= length)
|
||||
{
|
||||
sb.append('/');
|
||||
sb.append('>');
|
||||
} else
|
||||
{
|
||||
sb.append('>');
|
||||
do
|
||||
{
|
||||
object = ja.get(i);
|
||||
i += 1;
|
||||
if(object != null)
|
||||
{
|
||||
if(object instanceof String)
|
||||
{
|
||||
sb.append(XML.escape(object.toString()));
|
||||
} else if(object instanceof JSONObject)
|
||||
{
|
||||
sb.append(toString((JSONObject) object));
|
||||
} else if(object instanceof JSONArray)
|
||||
{
|
||||
sb.append(toString((JSONArray) object));
|
||||
} else
|
||||
{
|
||||
sb.append(object.toString());
|
||||
}
|
||||
}
|
||||
} while(i < length);
|
||||
sb.append('<');
|
||||
sb.append('/');
|
||||
sb.append(tagName);
|
||||
sb.append('>');
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the JSONML transformation, making an XML text from a JSONObject.
|
||||
* The JSONObject must contain a "tagName" property. If it has children,
|
||||
* then it must have a "childNodes" property containing an array of objects.
|
||||
* The other properties are attributes with string values.
|
||||
*
|
||||
* @param jo
|
||||
* A JSONObject.
|
||||
* @return An XML string.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static String toString(JSONObject jo) throws JSONException
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int i;
|
||||
JSONArray ja;
|
||||
String key;
|
||||
Iterator<String> keys;
|
||||
int length;
|
||||
Object object;
|
||||
String tagName;
|
||||
String value;
|
||||
|
||||
// Emit <tagName
|
||||
|
||||
tagName = jo.optString("tagName");
|
||||
if(tagName == null)
|
||||
{
|
||||
return XML.escape(jo.toString());
|
||||
}
|
||||
XML.noSpace(tagName);
|
||||
tagName = XML.escape(tagName);
|
||||
sb.append('<');
|
||||
sb.append(tagName);
|
||||
|
||||
// Emit the attributes
|
||||
|
||||
keys = jo.keys();
|
||||
while(keys.hasNext())
|
||||
{
|
||||
key = keys.next();
|
||||
if(!"tagName".equals(key) && !"childNodes".equals(key))
|
||||
{
|
||||
XML.noSpace(key);
|
||||
value = jo.optString(key);
|
||||
if(value != null)
|
||||
{
|
||||
sb.append(' ');
|
||||
sb.append(XML.escape(key));
|
||||
sb.append('=');
|
||||
sb.append('"');
|
||||
sb.append(XML.escape(value));
|
||||
sb.append('"');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Emit content in body
|
||||
|
||||
ja = jo.optJSONArray("childNodes");
|
||||
if(ja == null)
|
||||
{
|
||||
sb.append('/');
|
||||
sb.append('>');
|
||||
} else
|
||||
{
|
||||
sb.append('>');
|
||||
length = ja.length();
|
||||
for(i = 0; i < length; i += 1)
|
||||
{
|
||||
object = ja.get(i);
|
||||
if(object != null)
|
||||
{
|
||||
if(object instanceof String)
|
||||
{
|
||||
sb.append(XML.escape(object.toString()));
|
||||
} else if(object instanceof JSONObject)
|
||||
{
|
||||
sb.append(toString((JSONObject) object));
|
||||
} else if(object instanceof JSONArray)
|
||||
{
|
||||
sb.append(toString((JSONArray) object));
|
||||
} else
|
||||
{
|
||||
sb.append(object.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
sb.append('<');
|
||||
sb.append('/');
|
||||
sb.append(tagName);
|
||||
sb.append('>');
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,21 +0,0 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
|
||||
/**
|
||||
* The <code>JSONString</code> interface allows a <code>toJSONString()</code>
|
||||
* method so that a class can change the behavior of
|
||||
* <code>JSONObject.toString()</code>, <code>JSONArray.toString()</code>, and
|
||||
* <code>JSONWriter.value(</code>Object<code>)</code>. The
|
||||
* <code>toJSONString</code> method will be used instead of the default behavior
|
||||
* of using the Object's <code>toString()</code> method and quoting the result.
|
||||
*/
|
||||
public interface JSONString
|
||||
{
|
||||
/**
|
||||
* The <code>toJSONString</code> method allows a class to produce its own
|
||||
* JSON serialization.
|
||||
*
|
||||
* @return A strictly syntactically correct JSON text.
|
||||
*/
|
||||
public String toJSONString();
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
|
||||
/*
|
||||
Copyright (c) 2006 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
import java.io.StringWriter;
|
||||
|
||||
/**
|
||||
* JSONStringer provides a quick and convenient way of producing JSON text. The
|
||||
* texts produced strictly conform to JSON syntax rules. No whitespace is added,
|
||||
* so the results are ready for transmission or storage. Each instance of
|
||||
* JSONStringer can produce one JSON text.
|
||||
* <p>
|
||||
* A JSONStringer instance provides a <code>value</code> method for appending
|
||||
* values to the text, and a <code>key</code> method for adding keys before
|
||||
* values in objects. There are <code>array</code> and <code>endArray</code>
|
||||
* methods that make and bound array values, and <code>object</code> and
|
||||
* <code>endObject</code> methods which make and bound object values. All of
|
||||
* these methods return the JSONWriter instance, permitting cascade style. For
|
||||
* example,
|
||||
*
|
||||
* <pre>
|
||||
* myString = new JSONStringer().object().key("JSON").value("Hello, World!").endObject().toString();
|
||||
* </pre>
|
||||
*
|
||||
* which produces the string
|
||||
*
|
||||
* <pre>
|
||||
* {"JSON":"Hello, World!"}
|
||||
* </pre>
|
||||
* <p>
|
||||
* The first method called must be <code>array</code> or <code>object</code>.
|
||||
* There are no methods for adding commas or colons. JSONStringer adds them for
|
||||
* you. Objects and arrays can be nested up to 20 levels deep.
|
||||
* <p>
|
||||
* This can sometimes be easier than using a JSONObject to build a string.
|
||||
*
|
||||
* @author JSON.org
|
||||
* @version 2008-09-18
|
||||
*/
|
||||
public class JSONStringer extends JSONWriter
|
||||
{
|
||||
/**
|
||||
* Make a fresh JSONStringer. It can be used to build one JSON text.
|
||||
*/
|
||||
public JSONStringer()
|
||||
{
|
||||
super(new StringWriter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JSON text. This method is used to obtain the product of the
|
||||
* JSONStringer instance. It will return <code>null</code> if there was a
|
||||
* problem in the construction of the JSON text (such as the calls to
|
||||
* <code>array</code> were not properly balanced with calls to
|
||||
* <code>endArray</code>).
|
||||
*
|
||||
* @return The JSON text.
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
return this.mode == 'd' ? this.writer.toString() : null;
|
||||
}
|
||||
}
|
@ -1,504 +0,0 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
|
||||
/*
|
||||
Copyright (c) 2002 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A JSONTokener takes a source string and extracts characters and tokens from
|
||||
* it. It is used by the JSONObject and JSONArray constructors to parse JSON
|
||||
* source strings.
|
||||
*
|
||||
* @author JSON.org
|
||||
* @version 2014-05-03
|
||||
*/
|
||||
public class JSONTokener
|
||||
{
|
||||
|
||||
private long character;
|
||||
private boolean eof;
|
||||
private long index;
|
||||
private long line;
|
||||
private char previous;
|
||||
private Reader reader;
|
||||
private boolean usePrevious;
|
||||
|
||||
/**
|
||||
* Construct a JSONTokener from a Reader.
|
||||
*
|
||||
* @param reader
|
||||
* A reader.
|
||||
*/
|
||||
public JSONTokener(Reader reader)
|
||||
{
|
||||
this.reader = reader.markSupported() ? reader : new BufferedReader(reader);
|
||||
this.eof = false;
|
||||
this.usePrevious = false;
|
||||
this.previous = 0;
|
||||
this.index = 0;
|
||||
this.character = 1;
|
||||
this.line = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a JSONTokener from an InputStream.
|
||||
*
|
||||
* @param inputStream
|
||||
* The source.
|
||||
*/
|
||||
public JSONTokener(InputStream inputStream) throws JSONException
|
||||
{
|
||||
this(new InputStreamReader(inputStream));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a JSONTokener from a string.
|
||||
*
|
||||
* @param s
|
||||
* A source string.
|
||||
*/
|
||||
public JSONTokener(String s)
|
||||
{
|
||||
this(new StringReader(s));
|
||||
}
|
||||
|
||||
/**
|
||||
* Back up one character. This provides a sort of lookahead capability, so
|
||||
* that you can test for a digit or letter before attempting to parse the
|
||||
* next number or identifier.
|
||||
*/
|
||||
public void back() throws JSONException
|
||||
{
|
||||
if(this.usePrevious || this.index <= 0)
|
||||
{
|
||||
throw new JSONException("Stepping back two steps is not supported");
|
||||
}
|
||||
this.index -= 1;
|
||||
this.character -= 1;
|
||||
this.usePrevious = true;
|
||||
this.eof = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the hex value of a character (base16).
|
||||
*
|
||||
* @param c
|
||||
* A character between '0' and '9' or between 'A' and 'F' or
|
||||
* between 'a' and 'f'.
|
||||
* @return An int between 0 and 15, or -1 if c was not a hex digit.
|
||||
*/
|
||||
public static int dehexchar(char c)
|
||||
{
|
||||
if(c >= '0' && c <= '9')
|
||||
{
|
||||
return c - '0';
|
||||
}
|
||||
if(c >= 'A' && c <= 'F')
|
||||
{
|
||||
return c - ('A' - 10);
|
||||
}
|
||||
if(c >= 'a' && c <= 'f')
|
||||
{
|
||||
return c - ('a' - 10);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public boolean end()
|
||||
{
|
||||
return this.eof && !this.usePrevious;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the source string still contains characters that next() can
|
||||
* consume.
|
||||
*
|
||||
* @return true if not yet at the end of the source.
|
||||
*/
|
||||
public boolean more() throws JSONException
|
||||
{
|
||||
this.next();
|
||||
if(this.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
this.back();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next character in the source string.
|
||||
*
|
||||
* @return The next character, or 0 if past the end of the source string.
|
||||
*/
|
||||
public char next() throws JSONException
|
||||
{
|
||||
int c;
|
||||
if(this.usePrevious)
|
||||
{
|
||||
this.usePrevious = false;
|
||||
c = this.previous;
|
||||
} else
|
||||
{
|
||||
try
|
||||
{
|
||||
c = this.reader.read();
|
||||
} catch(IOException exception)
|
||||
{
|
||||
throw new JSONException(exception);
|
||||
}
|
||||
|
||||
if(c <= 0)
|
||||
{ // End of stream
|
||||
this.eof = true;
|
||||
c = 0;
|
||||
}
|
||||
}
|
||||
this.index += 1;
|
||||
if(this.previous == '\r')
|
||||
{
|
||||
this.line += 1;
|
||||
this.character = c == '\n' ? 0 : 1;
|
||||
} else if(c == '\n')
|
||||
{
|
||||
this.line += 1;
|
||||
this.character = 0;
|
||||
} else
|
||||
{
|
||||
this.character += 1;
|
||||
}
|
||||
this.previous = (char) c;
|
||||
return this.previous;
|
||||
}
|
||||
|
||||
/**
|
||||
* Consume the next character, and check that it matches a specified
|
||||
* character.
|
||||
*
|
||||
* @param c
|
||||
* The character to match.
|
||||
* @return The character.
|
||||
* @throws JSONException
|
||||
* if the character does not match.
|
||||
*/
|
||||
public char next(char c) throws JSONException
|
||||
{
|
||||
char n = this.next();
|
||||
if(n != c)
|
||||
{
|
||||
throw this.syntaxError("Expected '" + c + "' and instead saw '" + n + "'");
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next n characters.
|
||||
*
|
||||
* @param n
|
||||
* The number of characters to take.
|
||||
* @return A string of n characters.
|
||||
* @throws JSONException
|
||||
* Substring bounds error if there are not n characters
|
||||
* remaining in the source string.
|
||||
*/
|
||||
public String next(int n) throws JSONException
|
||||
{
|
||||
if(n == 0)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
char[] chars = new char[n];
|
||||
int pos = 0;
|
||||
|
||||
while(pos < n)
|
||||
{
|
||||
chars[pos] = this.next();
|
||||
if(this.end())
|
||||
{
|
||||
throw this.syntaxError("Substring bounds error");
|
||||
}
|
||||
pos += 1;
|
||||
}
|
||||
return new String(chars);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next char in the string, skipping whitespace.
|
||||
*
|
||||
* @throws JSONException
|
||||
* @return A character, or 0 if there are no more characters.
|
||||
*/
|
||||
public char nextClean() throws JSONException
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
char c = this.next();
|
||||
if(c == 0 || c > ' ')
|
||||
{
|
||||
return c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the characters up to the next close quote character. Backslash
|
||||
* processing is done. The formal JSON format does not allow strings in
|
||||
* single quotes, but an implementation is allowed to accept them.
|
||||
*
|
||||
* @param quote
|
||||
* The quoting character, either <code>"</code>
|
||||
* <small>(double quote)</small> or <code>'</code>
|
||||
* <small>(single quote)</small>.
|
||||
* @return A String.
|
||||
* @throws JSONException
|
||||
* Unterminated string.
|
||||
*/
|
||||
public String nextString(char quote) throws JSONException
|
||||
{
|
||||
char c;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for(;;)
|
||||
{
|
||||
c = this.next();
|
||||
switch(c)
|
||||
{
|
||||
case 0:
|
||||
case '\n':
|
||||
case '\r':
|
||||
throw this.syntaxError("Unterminated string");
|
||||
case '\\':
|
||||
c = this.next();
|
||||
switch(c)
|
||||
{
|
||||
case 'b':
|
||||
sb.append('\b');
|
||||
break;
|
||||
case 't':
|
||||
sb.append('\t');
|
||||
break;
|
||||
case 'n':
|
||||
sb.append('\n');
|
||||
break;
|
||||
case 'f':
|
||||
sb.append('\f');
|
||||
break;
|
||||
case 'r':
|
||||
sb.append('\r');
|
||||
break;
|
||||
case 'u':
|
||||
sb.append((char) Integer.parseInt(this.next(4), 16));
|
||||
break;
|
||||
case '"':
|
||||
case '\'':
|
||||
case '\\':
|
||||
case '/':
|
||||
sb.append(c);
|
||||
break;
|
||||
default:
|
||||
throw this.syntaxError("Illegal escape.");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if(c == quote)
|
||||
{
|
||||
return sb.toString();
|
||||
}
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the text up but not including the specified character or the end of
|
||||
* line, whichever comes first.
|
||||
*
|
||||
* @param delimiter
|
||||
* A delimiter character.
|
||||
* @return A string.
|
||||
*/
|
||||
public String nextTo(char delimiter) throws JSONException
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for(;;)
|
||||
{
|
||||
char c = this.next();
|
||||
if(c == delimiter || c == 0 || c == '\n' || c == '\r')
|
||||
{
|
||||
if(c != 0)
|
||||
{
|
||||
this.back();
|
||||
}
|
||||
return sb.toString().trim();
|
||||
}
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the text up but not including one of the specified delimiter
|
||||
* characters or the end of line, whichever comes first.
|
||||
*
|
||||
* @param delimiters
|
||||
* A set of delimiter characters.
|
||||
* @return A string, trimmed.
|
||||
*/
|
||||
public String nextTo(String delimiters) throws JSONException
|
||||
{
|
||||
char c;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for(;;)
|
||||
{
|
||||
c = this.next();
|
||||
if(delimiters.indexOf(c) >= 0 || c == 0 || c == '\n' || c == '\r')
|
||||
{
|
||||
if(c != 0)
|
||||
{
|
||||
this.back();
|
||||
}
|
||||
return sb.toString().trim();
|
||||
}
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next value. The value can be a Boolean, Double, Integer,
|
||||
* JSONArray, JSONObject, Long, or String, or the JSONObject.NULL object.
|
||||
*
|
||||
* @throws JSONException
|
||||
* If syntax error.
|
||||
*
|
||||
* @return An object.
|
||||
*/
|
||||
public Object nextValue() throws JSONException
|
||||
{
|
||||
char c = this.nextClean();
|
||||
String string;
|
||||
|
||||
switch(c)
|
||||
{
|
||||
case '"':
|
||||
case '\'':
|
||||
return this.nextString(c);
|
||||
case '{':
|
||||
this.back();
|
||||
return new JSONObject(this);
|
||||
case '[':
|
||||
this.back();
|
||||
return new JSONArray(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle unquoted text. This could be the values true, false, or null,
|
||||
* or it can be a number. An implementation (such as this one) is
|
||||
* allowed to also accept non-standard forms.
|
||||
*
|
||||
* Accumulate characters until we reach the end of the text or a
|
||||
* formatting character.
|
||||
*/
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
while(c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0)
|
||||
{
|
||||
sb.append(c);
|
||||
c = this.next();
|
||||
}
|
||||
this.back();
|
||||
|
||||
string = sb.toString().trim();
|
||||
if("".equals(string))
|
||||
{
|
||||
throw this.syntaxError("Missing value");
|
||||
}
|
||||
return JSONObject.stringToValue(string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip characters until the next character is the requested character. If
|
||||
* the requested character is not found, no characters are skipped.
|
||||
*
|
||||
* @param to
|
||||
* A character to skip to.
|
||||
* @return The requested character, or zero if the requested character is
|
||||
* not found.
|
||||
*/
|
||||
public char skipTo(char to) throws JSONException
|
||||
{
|
||||
char c;
|
||||
try
|
||||
{
|
||||
long startIndex = this.index;
|
||||
long startCharacter = this.character;
|
||||
long startLine = this.line;
|
||||
this.reader.mark(1000000);
|
||||
do
|
||||
{
|
||||
c = this.next();
|
||||
if(c == 0)
|
||||
{
|
||||
this.reader.reset();
|
||||
this.index = startIndex;
|
||||
this.character = startCharacter;
|
||||
this.line = startLine;
|
||||
return c;
|
||||
}
|
||||
} while(c != to);
|
||||
} catch(IOException exception)
|
||||
{
|
||||
throw new JSONException(exception);
|
||||
}
|
||||
this.back();
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a JSONException to signal a syntax error.
|
||||
*
|
||||
* @param message
|
||||
* The error message.
|
||||
* @return A JSONException object, suitable for throwing
|
||||
*/
|
||||
public JSONException syntaxError(String message)
|
||||
{
|
||||
return new JSONException(message + this.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a printable string of this JSONTokener.
|
||||
*
|
||||
* @return " at {index} [character {character} line {line}]"
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
return " at " + this.index + " [character " + this.character + " line " + this.line + "]";
|
||||
}
|
||||
}
|
@ -1,388 +0,0 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
|
||||
/*
|
||||
Copyright (c) 2006 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JSONWriter provides a quick and convenient way of producing JSON text. The
|
||||
* texts produced strictly conform to JSON syntax rules. No whitespace is added,
|
||||
* so the results are ready for transmission or storage. Each instance of
|
||||
* JSONWriter can produce one JSON text.
|
||||
* <p>
|
||||
* A JSONWriter instance provides a <code>value</code> method for appending
|
||||
* values to the text, and a <code>key</code> method for adding keys before
|
||||
* values in objects. There are <code>array</code> and <code>endArray</code>
|
||||
* methods that make and bound array values, and <code>object</code> and
|
||||
* <code>endObject</code> methods which make and bound object values. All of
|
||||
* these methods return the JSONWriter instance, permitting a cascade style. For
|
||||
* example,
|
||||
*
|
||||
* <pre>
|
||||
* new JSONWriter(myWriter).object().key("JSON").value("Hello, World!").endObject();
|
||||
* </pre>
|
||||
*
|
||||
* which writes
|
||||
*
|
||||
* <pre>
|
||||
* {"JSON":"Hello, World!"}
|
||||
* </pre>
|
||||
* <p>
|
||||
* The first method called must be <code>array</code> or <code>object</code>.
|
||||
* There are no methods for adding commas or colons. JSONWriter adds them for
|
||||
* you. Objects and arrays can be nested up to 20 levels deep.
|
||||
* <p>
|
||||
* This can sometimes be easier than using a JSONObject to build a string.
|
||||
*
|
||||
* @author JSON.org
|
||||
* @version 2011-11-24
|
||||
*/
|
||||
public class JSONWriter
|
||||
{
|
||||
private static final int maxdepth = 200;
|
||||
|
||||
/**
|
||||
* The comma flag determines if a comma should be output before the next
|
||||
* value.
|
||||
*/
|
||||
private boolean comma;
|
||||
|
||||
/**
|
||||
* The current mode. Values: 'a' (array), 'd' (done), 'i' (initial), 'k'
|
||||
* (key), 'o' (object).
|
||||
*/
|
||||
protected char mode;
|
||||
|
||||
/**
|
||||
* The object/array stack.
|
||||
*/
|
||||
private final JSONObject stack[];
|
||||
|
||||
/**
|
||||
* The stack top index. A value of 0 indicates that the stack is empty.
|
||||
*/
|
||||
private int top;
|
||||
|
||||
/**
|
||||
* The writer that will receive the output.
|
||||
*/
|
||||
protected Writer writer;
|
||||
|
||||
/**
|
||||
* Make a fresh JSONWriter. It can be used to build one JSON text.
|
||||
*/
|
||||
public JSONWriter(Writer w)
|
||||
{
|
||||
this.comma = false;
|
||||
this.mode = 'i';
|
||||
this.stack = new JSONObject[maxdepth];
|
||||
this.top = 0;
|
||||
this.writer = w;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a value.
|
||||
*
|
||||
* @param string
|
||||
* A string value.
|
||||
* @return this
|
||||
* @throws JSONException
|
||||
* If the value is out of sequence.
|
||||
*/
|
||||
private JSONWriter append(String string) throws JSONException
|
||||
{
|
||||
if(string == null)
|
||||
{
|
||||
throw new JSONException("Null pointer");
|
||||
}
|
||||
if(this.mode == 'o' || this.mode == 'a')
|
||||
{
|
||||
try
|
||||
{
|
||||
if(this.comma && this.mode == 'a')
|
||||
{
|
||||
this.writer.write(',');
|
||||
}
|
||||
this.writer.write(string);
|
||||
} catch(IOException e)
|
||||
{
|
||||
throw new JSONException(e);
|
||||
}
|
||||
if(this.mode == 'o')
|
||||
{
|
||||
this.mode = 'k';
|
||||
}
|
||||
this.comma = true;
|
||||
return this;
|
||||
}
|
||||
throw new JSONException("Value out of sequence.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin appending a new array. All values until the balancing
|
||||
* <code>endArray</code> will be appended to this array. The
|
||||
* <code>endArray</code> method must be called to mark the array's end.
|
||||
*
|
||||
* @return this
|
||||
* @throws JSONException
|
||||
* If the nesting is too deep, or if the object is started in
|
||||
* the wrong place (for example as a key or after the end of the
|
||||
* outermost array or object).
|
||||
*/
|
||||
public JSONWriter array() throws JSONException
|
||||
{
|
||||
if(this.mode == 'i' || this.mode == 'o' || this.mode == 'a')
|
||||
{
|
||||
this.push(null);
|
||||
this.append("[");
|
||||
this.comma = false;
|
||||
return this;
|
||||
}
|
||||
throw new JSONException("Misplaced array.");
|
||||
}
|
||||
|
||||
/**
|
||||
* End something.
|
||||
*
|
||||
* @param mode
|
||||
* Mode
|
||||
* @param c
|
||||
* Closing character
|
||||
* @return this
|
||||
* @throws JSONException
|
||||
* If unbalanced.
|
||||
*/
|
||||
private JSONWriter end(char mode, char c) throws JSONException
|
||||
{
|
||||
if(this.mode != mode)
|
||||
{
|
||||
throw new JSONException(mode == 'a' ? "Misplaced endArray." : "Misplaced endObject.");
|
||||
}
|
||||
this.pop(mode);
|
||||
try
|
||||
{
|
||||
this.writer.write(c);
|
||||
} catch(IOException e)
|
||||
{
|
||||
throw new JSONException(e);
|
||||
}
|
||||
this.comma = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* End an array. This method most be called to balance calls to
|
||||
* <code>array</code>.
|
||||
*
|
||||
* @return this
|
||||
* @throws JSONException
|
||||
* If incorrectly nested.
|
||||
*/
|
||||
public JSONWriter endArray() throws JSONException
|
||||
{
|
||||
return this.end('a', ']');
|
||||
}
|
||||
|
||||
/**
|
||||
* End an object. This method most be called to balance calls to
|
||||
* <code>object</code>.
|
||||
*
|
||||
* @return this
|
||||
* @throws JSONException
|
||||
* If incorrectly nested.
|
||||
*/
|
||||
public JSONWriter endObject() throws JSONException
|
||||
{
|
||||
return this.end('k', '}');
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a key. The key will be associated with the next value. In an
|
||||
* object, every value must be preceded by a key.
|
||||
*
|
||||
* @param string
|
||||
* A key string.
|
||||
* @return this
|
||||
* @throws JSONException
|
||||
* If the key is out of place. For example, keys do not belong
|
||||
* in arrays or if the key is null.
|
||||
*/
|
||||
public JSONWriter key(String string) throws JSONException
|
||||
{
|
||||
if(string == null)
|
||||
{
|
||||
throw new JSONException("Null key.");
|
||||
}
|
||||
if(this.mode == 'k')
|
||||
{
|
||||
try
|
||||
{
|
||||
this.stack[this.top - 1].putOnce(string, Boolean.TRUE);
|
||||
if(this.comma)
|
||||
{
|
||||
this.writer.write(',');
|
||||
}
|
||||
this.writer.write(JSONObject.quote(string));
|
||||
this.writer.write(':');
|
||||
this.comma = false;
|
||||
this.mode = 'o';
|
||||
return this;
|
||||
} catch(IOException e)
|
||||
{
|
||||
throw new JSONException(e);
|
||||
}
|
||||
}
|
||||
throw new JSONException("Misplaced key.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin appending a new object. All keys and values until the balancing
|
||||
* <code>endObject</code> will be appended to this object. The
|
||||
* <code>endObject</code> method must be called to mark the object's end.
|
||||
*
|
||||
* @return this
|
||||
* @throws JSONException
|
||||
* If the nesting is too deep, or if the object is started in
|
||||
* the wrong place (for example as a key or after the end of the
|
||||
* outermost array or object).
|
||||
*/
|
||||
public JSONWriter object() throws JSONException
|
||||
{
|
||||
if(this.mode == 'i')
|
||||
{
|
||||
this.mode = 'o';
|
||||
}
|
||||
if(this.mode == 'o' || this.mode == 'a')
|
||||
{
|
||||
this.append("{");
|
||||
this.push(new JSONObject());
|
||||
this.comma = false;
|
||||
return this;
|
||||
}
|
||||
throw new JSONException("Misplaced object.");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Pop an array or object scope.
|
||||
*
|
||||
* @param c
|
||||
* The scope to close.
|
||||
* @throws JSONException
|
||||
* If nesting is wrong.
|
||||
*/
|
||||
private void pop(char c) throws JSONException
|
||||
{
|
||||
if(this.top <= 0)
|
||||
{
|
||||
throw new JSONException("Nesting error.");
|
||||
}
|
||||
char m = this.stack[this.top - 1] == null ? 'a' : 'k';
|
||||
if(m != c)
|
||||
{
|
||||
throw new JSONException("Nesting error.");
|
||||
}
|
||||
this.top -= 1;
|
||||
this.mode = this.top == 0 ? 'd' : this.stack[this.top - 1] == null ? 'a' : 'k';
|
||||
}
|
||||
|
||||
/**
|
||||
* Push an array or object scope.
|
||||
*
|
||||
* @param jo
|
||||
* The scope to open.
|
||||
* @throws JSONException
|
||||
* If nesting is too deep.
|
||||
*/
|
||||
private void push(JSONObject jo) throws JSONException
|
||||
{
|
||||
if(this.top >= maxdepth)
|
||||
{
|
||||
throw new JSONException("Nesting too deep.");
|
||||
}
|
||||
this.stack[this.top] = jo;
|
||||
this.mode = jo == null ? 'a' : 'k';
|
||||
this.top += 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append either the value <code>true</code> or the value <code>false</code>
|
||||
* .
|
||||
*
|
||||
* @param b
|
||||
* A boolean.
|
||||
* @return this
|
||||
* @throws JSONException
|
||||
*/
|
||||
public JSONWriter value(boolean b) throws JSONException
|
||||
{
|
||||
return this.append(b ? "true" : "false");
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a double value.
|
||||
*
|
||||
* @param d
|
||||
* A double.
|
||||
* @return this
|
||||
* @throws JSONException
|
||||
* If the number is not finite.
|
||||
*/
|
||||
public JSONWriter value(double d) throws JSONException
|
||||
{
|
||||
return this.value(new Double(d));
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a long value.
|
||||
*
|
||||
* @param l
|
||||
* A long.
|
||||
* @return this
|
||||
* @throws JSONException
|
||||
*/
|
||||
public JSONWriter value(long l) throws JSONException
|
||||
{
|
||||
return this.append(Long.toString(l));
|
||||
}
|
||||
|
||||
/**
|
||||
* Append an object value.
|
||||
*
|
||||
* @param object
|
||||
* The object to append. It can be null, or a Boolean, Number,
|
||||
* String, JSONObject, or JSONArray, or an object that implements
|
||||
* JSONString.
|
||||
* @return this
|
||||
* @throws JSONException
|
||||
* If the value is out of sequence.
|
||||
*/
|
||||
public JSONWriter value(Object object) throws JSONException
|
||||
{
|
||||
return this.append(JSONObject.valueToString(object));
|
||||
}
|
||||
}
|
@ -1,648 +0,0 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class KList<T> extends ArrayList<T> implements List<T>
|
||||
{
|
||||
private static final long serialVersionUID = -2892550695744823337L;
|
||||
|
||||
@SafeVarargs
|
||||
public KList(T... ts)
|
||||
{
|
||||
super();
|
||||
add(ts);
|
||||
}
|
||||
|
||||
public KList()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public KList(Collection<T> values)
|
||||
{
|
||||
super();
|
||||
add(values);
|
||||
}
|
||||
|
||||
public KList(Enumeration<T> e)
|
||||
{
|
||||
super();
|
||||
add(e);
|
||||
}
|
||||
|
||||
public Chunker<T> chunk()
|
||||
{
|
||||
return new Chunker<T>(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the last element
|
||||
*/
|
||||
public KList<T> removeLast()
|
||||
{
|
||||
remove(last());
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public Queue<T> enqueue()
|
||||
{
|
||||
return Queue.create(this);
|
||||
}
|
||||
|
||||
private KList<T> add(Enumeration<T> e)
|
||||
{
|
||||
while(e.hasMoreElements())
|
||||
{
|
||||
add(e.nextElement());
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public KList<T> add(Collection<T> values)
|
||||
{
|
||||
addAll(values);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Map out of this list where this list becomes the values of the
|
||||
* returned map. You must specify each key for each value in this list. In the
|
||||
* function, returning null will not add the keyval pair.
|
||||
*
|
||||
* @param <K>
|
||||
* the inferred key type
|
||||
* @param f
|
||||
* the function
|
||||
* @return the new map
|
||||
*/
|
||||
public <K> KMap<K, T> asValues(Function<T, K> f)
|
||||
{
|
||||
KMap<K, T> m = new KMap<K, T>();
|
||||
forEach((i) -> m.putNonNull(f.apply(i), i));
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Map out of this list where this list becomes the keys of the
|
||||
* returned map. You must specify each value for each key in this list. In the
|
||||
* function, returning null will not add the keyval pair.
|
||||
*
|
||||
* @param <V>
|
||||
* the inferred value type
|
||||
* @param f
|
||||
* the function
|
||||
* @return the new map
|
||||
*/
|
||||
public <V> KMap<T, V> asKeys(Function<T, V> f)
|
||||
{
|
||||
KMap<T, V> m = new KMap<T, V>();
|
||||
forEach((i) -> m.putNonNull(i, f.apply(i)));
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cut this list into targetCount sublists
|
||||
*
|
||||
* @param targetCount
|
||||
* the target count of sublists
|
||||
* @return the list of sublists
|
||||
*/
|
||||
public KList<KList<T>> divide(int targetCount)
|
||||
{
|
||||
return split(size() / targetCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Split this list into a list of sublists with roughly targetSize elements of T
|
||||
* per sublist
|
||||
*
|
||||
* @param targetSize
|
||||
* the target size
|
||||
* @return the list of sublists
|
||||
*/
|
||||
public KList<KList<T>> split(int targetSize)
|
||||
{
|
||||
targetSize = targetSize < 1 ? 1 : targetSize;
|
||||
KList<KList<T>> gg = new KList<>();
|
||||
KList<T> b = new KList<>();
|
||||
|
||||
for(T i : this)
|
||||
{
|
||||
if(b.size() >= targetSize)
|
||||
{
|
||||
gg.add(b.copy());
|
||||
b.clear();
|
||||
}
|
||||
|
||||
b.add(i);
|
||||
}
|
||||
|
||||
if(!b.isEmpty())
|
||||
{
|
||||
gg.add(b);
|
||||
}
|
||||
|
||||
return gg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewrite this list by checking each value and changing the value (or not).
|
||||
* Return null to remove the element in the function
|
||||
*
|
||||
* @param t
|
||||
* the function
|
||||
* @return the same list (not a copy)
|
||||
*/
|
||||
public KList<T> rewrite(Function<T, T> t)
|
||||
{
|
||||
KList<T> m = copy();
|
||||
clear();
|
||||
|
||||
for(T i : m)
|
||||
{
|
||||
addNonNull(t.apply(i));
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* To array
|
||||
*
|
||||
* @return the array
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public T[] array()
|
||||
{
|
||||
return (T[]) toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of this list
|
||||
*
|
||||
* @return the copy
|
||||
*/
|
||||
public KList<T> copy()
|
||||
{
|
||||
return new KList<T>().add(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shuffle the list
|
||||
*
|
||||
* @return the same list
|
||||
*/
|
||||
public KList<T> shuffle()
|
||||
{
|
||||
Collections.shuffle(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort the list (based on toString comparison)
|
||||
*
|
||||
* @return the same list
|
||||
*/
|
||||
public KList<T> sort()
|
||||
{
|
||||
Collections.sort(this, (a, b) -> a.toString().compareTo(b.toString()));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse this list
|
||||
*
|
||||
* @return the same list
|
||||
*/
|
||||
public KList<T> reverse()
|
||||
{
|
||||
Collections.reverse(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "[" + toString(", ") + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Tostring with a seperator for each item in the list
|
||||
*
|
||||
* @param split
|
||||
* the seperator
|
||||
* @return the string representing this object
|
||||
*/
|
||||
public String toString(String split)
|
||||
{
|
||||
if(isEmpty())
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
if(size() == 1)
|
||||
{
|
||||
return get(0).toString();
|
||||
}
|
||||
|
||||
StringBuilder b = new StringBuilder();
|
||||
|
||||
for(String i : toStringList())
|
||||
{
|
||||
b.append(split + i);
|
||||
}
|
||||
|
||||
return b.toString().substring(split.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke tostring on each value in the list into a string list
|
||||
*
|
||||
* @return the string list
|
||||
*/
|
||||
public KList<String> toStringList()
|
||||
{
|
||||
return convert((t) -> t.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a list into another list type. Such as GList<Integer> to
|
||||
* GList<String>. list.convert((i) -> "" + i);
|
||||
*
|
||||
* @param <V>
|
||||
* @param converter
|
||||
* @return
|
||||
*/
|
||||
public <V> KList<V> convert(Function<T, V> converter)
|
||||
{
|
||||
KList<V> v = new KList<V>();
|
||||
forEach((t) -> v.addNonNull(converter.apply(t)));
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds T to the list, ignores if null
|
||||
*
|
||||
* @param t
|
||||
* the value to add
|
||||
* @return the same list
|
||||
*/
|
||||
public KList<T> addNonNull(T t)
|
||||
{
|
||||
if(t != null)
|
||||
{
|
||||
super.add(t);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Swaps the values of index a and b. For example "hello", "world", "!" swap(1,
|
||||
* 2) would change the list to "hello", "!", "world"
|
||||
*
|
||||
* @param a
|
||||
* the first index
|
||||
* @param b
|
||||
* the second index
|
||||
* @return the same list (builder), not a copy
|
||||
*/
|
||||
public KList<T> swapIndexes(int a, int b)
|
||||
{
|
||||
T aa = remove(a);
|
||||
T bb = get(b);
|
||||
add(a, bb);
|
||||
remove(b);
|
||||
add(b, aa);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a number of elements from the list
|
||||
*
|
||||
* @param t
|
||||
* the elements
|
||||
* @return this list
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public KList<T> remove(T... t)
|
||||
{
|
||||
for(T i : t)
|
||||
{
|
||||
super.remove(i);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add another glist's contents to this one (addall builder)
|
||||
*
|
||||
* @param t
|
||||
* the list
|
||||
* @return the same list
|
||||
*/
|
||||
public KList<T> add(KList<T> t)
|
||||
{
|
||||
super.addAll(t);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a number of values to this list
|
||||
*
|
||||
* @param t
|
||||
* the list
|
||||
* @return this list
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public KList<T> add(T... t)
|
||||
{
|
||||
for(T i : t)
|
||||
{
|
||||
super.add(i);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this list has an index at the given index
|
||||
*
|
||||
* @param index
|
||||
* the given index
|
||||
* @return true if size > index
|
||||
*/
|
||||
public boolean hasIndex(int index)
|
||||
{
|
||||
return size() > index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last index of this list (size - 1)
|
||||
*
|
||||
* @return the last index of this list
|
||||
*/
|
||||
public int last()
|
||||
{
|
||||
return size() - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deduplicate this list by converting to linked hash set and back
|
||||
*
|
||||
* @return the deduplicated list
|
||||
*/
|
||||
public KList<T> dedupe()
|
||||
{
|
||||
return qclear().add(new LinkedHashSet<T>(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear this list (and return it)
|
||||
*
|
||||
* @return the same list
|
||||
*/
|
||||
public KList<T> qclear()
|
||||
{
|
||||
super.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simply !isEmpty()
|
||||
*
|
||||
* @return true if this list has 1 or more element(s)
|
||||
*/
|
||||
public boolean hasElements()
|
||||
{
|
||||
return !isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pop the first item off this list and return it
|
||||
*
|
||||
* @return the popped off item or null if the list is empty
|
||||
*/
|
||||
public T pop()
|
||||
{
|
||||
if(isEmpty())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return remove(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pop the last item off this list and return it
|
||||
*
|
||||
* @return the popped off item or null if the list is empty
|
||||
*/
|
||||
public T popLast()
|
||||
{
|
||||
if(isEmpty())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return remove(last());
|
||||
}
|
||||
|
||||
public T popRandom()
|
||||
{
|
||||
if(isEmpty())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if(size() == 1)
|
||||
{
|
||||
return pop();
|
||||
}
|
||||
|
||||
return remove(M.irand(0, last()));
|
||||
}
|
||||
|
||||
public static KList<String> fromJSONAny(JSONArray oo)
|
||||
{
|
||||
KList<String> s = new KList<String>();
|
||||
|
||||
for(int i = 0; i < oo.length(); i++)
|
||||
{
|
||||
s.add(oo.get(i).toString());
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
public KList<T> sub(int f, int t)
|
||||
{
|
||||
KList<T> g = new KList<>();
|
||||
|
||||
for(int i = f; i < M.min(size(), t); i++)
|
||||
{
|
||||
g.add(get(i));
|
||||
}
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
public JSONArray toJSONStringArray()
|
||||
{
|
||||
JSONArray j = new JSONArray();
|
||||
|
||||
for(Object i : this)
|
||||
{
|
||||
j.put(i.toString());
|
||||
}
|
||||
|
||||
return j;
|
||||
}
|
||||
|
||||
public static KList<String> asStringList(List<?> oo)
|
||||
{
|
||||
KList<String> s = new KList<String>();
|
||||
|
||||
for(Object i : oo)
|
||||
{
|
||||
s.add(i.toString());
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public KList<T> forceAdd(Object[] values)
|
||||
{
|
||||
for(Object i : values)
|
||||
{
|
||||
add((T) i);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public KList<T> forceAdd(int[] values)
|
||||
{
|
||||
for(Object i : values)
|
||||
{
|
||||
add((T) i);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public KList<T> forceAdd(double[] values)
|
||||
{
|
||||
for(Object i : values)
|
||||
{
|
||||
add((T) i);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public KList<T> forceAdd(float[] values)
|
||||
{
|
||||
for(Object i : values)
|
||||
{
|
||||
add((T) i);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public KList<T> forceAdd(byte[] values)
|
||||
{
|
||||
for(Object i : values)
|
||||
{
|
||||
add((T) i);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public KList<T> forceAdd(short[] values)
|
||||
{
|
||||
for(Object i : values)
|
||||
{
|
||||
add((T) i);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public KList<T> forceAdd(long[] values)
|
||||
{
|
||||
for(Object i : values)
|
||||
{
|
||||
add((T) i);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public KList<T> forceAdd(boolean[] values)
|
||||
{
|
||||
for(Object i : values)
|
||||
{
|
||||
add((T) i);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public T middleValue()
|
||||
{
|
||||
return get(middleIndex());
|
||||
}
|
||||
|
||||
private int middleIndex()
|
||||
{
|
||||
return size() % 2 == 0 ? (size() / 2) : ((size() / 2) + 1);
|
||||
}
|
||||
|
||||
public T getRandom()
|
||||
{
|
||||
if(isEmpty())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if(size() == 1)
|
||||
{
|
||||
return get(0);
|
||||
}
|
||||
|
||||
return get(M.irand(0, last()));
|
||||
}
|
||||
|
||||
public KList<T> qdel(T t)
|
||||
{
|
||||
remove(t);
|
||||
return this;
|
||||
}
|
||||
|
||||
public KList<T> qadd(T t)
|
||||
{
|
||||
add(t);
|
||||
return this;
|
||||
}
|
||||
}
|
@ -1,424 +0,0 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class KMap<K, V> extends ConcurrentHashMap<K, V>
|
||||
{
|
||||
private static final long serialVersionUID = 7288942695300448163L;
|
||||
|
||||
public KMap()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public KMap(KMap<K, V> gMap)
|
||||
{
|
||||
this();
|
||||
put(gMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a value into a map-value-list based on the key such that if GMap<K,
|
||||
* GList<S>> where V is GList<S>
|
||||
*
|
||||
* @param <S>
|
||||
* the list type in the value type
|
||||
* @param k
|
||||
* the key to look for
|
||||
* @param vs
|
||||
* the values to put into the list of the given key
|
||||
* @return the same list (builder)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <S> KMap<K, V> putValueList(K k, S... vs)
|
||||
{
|
||||
try
|
||||
{
|
||||
KMap<K, KList<S>> s = (KMap<K, KList<S>>) this;
|
||||
|
||||
if(!s.containsKey(k))
|
||||
{
|
||||
s.put(k, new KList<S>());
|
||||
}
|
||||
|
||||
s.get(k).add(vs);
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a sorted list of keys from this map, based on the sorting order of
|
||||
* the values.
|
||||
*
|
||||
* @return the value-sorted key list
|
||||
*/
|
||||
public KList<K> sortK()
|
||||
{
|
||||
KList<K> k = new KList<K>();
|
||||
KList<V> v = v();
|
||||
|
||||
Collections.sort(v, new Comparator<V>()
|
||||
{
|
||||
@Override
|
||||
public int compare(V v, V t1)
|
||||
{
|
||||
return v.toString().compareTo(t1.toString());
|
||||
}
|
||||
});
|
||||
|
||||
for(V i : v)
|
||||
{
|
||||
for(K j : k())
|
||||
{
|
||||
if(get(j).equals(i))
|
||||
{
|
||||
k.add(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
k.dedupe();
|
||||
return k;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a sorted list of keys from this map, based on the sorting order of
|
||||
* the values. Sorting is based on numerical values
|
||||
*
|
||||
* @return the value-sorted key list
|
||||
*/
|
||||
public KList<K> sortKNumber()
|
||||
{
|
||||
KList<K> k = new KList<K>();
|
||||
KList<V> v = v();
|
||||
|
||||
Collections.sort(v, new Comparator<V>()
|
||||
{
|
||||
@Override
|
||||
public int compare(V v, V t1)
|
||||
{
|
||||
Number n1 = (Number) v;
|
||||
Number n2 = (Number) t1;
|
||||
|
||||
return (int) ((n1.doubleValue() - n2.doubleValue()) * 1000);
|
||||
}
|
||||
});
|
||||
|
||||
for(V i : v)
|
||||
{
|
||||
for(K j : k())
|
||||
{
|
||||
if(get(j).equals(i))
|
||||
{
|
||||
k.add(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
k.dedupe();
|
||||
return k;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put another map's values into this map
|
||||
*
|
||||
* @param m
|
||||
* the map to insert
|
||||
* @return this map (builder)
|
||||
*/
|
||||
public KMap<K, V> put(Map<K, V> m)
|
||||
{
|
||||
putAll(m);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of this map
|
||||
*
|
||||
* @return the copied map
|
||||
*/
|
||||
public KMap<K, V> copy()
|
||||
{
|
||||
return new KMap<K, V>(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loop through each keyvalue set (copy of it) with the map parameter
|
||||
*
|
||||
* @param f
|
||||
* the function
|
||||
* @return the same gmap
|
||||
*/
|
||||
public KMap<K, V> rewrite(Consumer3<K, V, KMap<K, V>> f)
|
||||
{
|
||||
KMap<K, V> m = copy();
|
||||
|
||||
for(K i : m.k())
|
||||
{
|
||||
f.accept(i, get(i), this);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loop through each keyvalue set (copy of it)
|
||||
*
|
||||
* @param f
|
||||
* the function
|
||||
* @return the same gmap
|
||||
*/
|
||||
public KMap<K, V> each(Consumer2<K, V> f)
|
||||
{
|
||||
for(K i : k())
|
||||
{
|
||||
f.accept(i, get(i));
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flip the hashmap and flatten the value list even if there are multiple keys
|
||||
*
|
||||
* @return the flipped and flattened hashmap
|
||||
*/
|
||||
public KMap<V, K> flipFlatten()
|
||||
{
|
||||
KMap<V, KList<K>> f = flip();
|
||||
KMap<V, K> m = new KMap<>();
|
||||
|
||||
for(V i : f.k())
|
||||
{
|
||||
m.putNonNull(i, m.isEmpty() ? null : m.get(0));
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flip the hashmap so keys are now list-keys in the value position
|
||||
*
|
||||
* @return the flipped hashmap
|
||||
*/
|
||||
public KMap<V, KList<K>> flip()
|
||||
{
|
||||
KMap<V, KList<K>> flipped = new KMap<V, KList<K>>();
|
||||
|
||||
for(K i : keySet())
|
||||
{
|
||||
if(i == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!flipped.containsKey(get(i)))
|
||||
{
|
||||
flipped.put(get(i), new KList<K>());
|
||||
}
|
||||
|
||||
flipped.get(get(i)).add(i);
|
||||
}
|
||||
|
||||
return flipped;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort values based on the keys sorting order
|
||||
*
|
||||
* @return the values (sorted)
|
||||
*/
|
||||
public KList<V> sortV()
|
||||
{
|
||||
KList<V> v = new KList<V>();
|
||||
KList<K> k = k();
|
||||
|
||||
Collections.sort(k, new Comparator<K>()
|
||||
{
|
||||
@Override
|
||||
public int compare(K v, K t1)
|
||||
{
|
||||
return v.toString().compareTo(t1.toString());
|
||||
}
|
||||
});
|
||||
|
||||
for(K i : k)
|
||||
{
|
||||
for(V j : v())
|
||||
{
|
||||
if(get(i).equals(j))
|
||||
{
|
||||
v.add(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
v.dedupe();
|
||||
return v;
|
||||
}
|
||||
|
||||
public KList<V> sortVNoDedupe()
|
||||
{
|
||||
KList<V> v = new KList<V>();
|
||||
KList<K> k = k();
|
||||
|
||||
Collections.sort(k, new Comparator<K>()
|
||||
{
|
||||
@Override
|
||||
public int compare(K v, K t1)
|
||||
{
|
||||
return v.toString().compareTo(t1.toString());
|
||||
}
|
||||
});
|
||||
|
||||
for(K i : k)
|
||||
{
|
||||
for(V j : v())
|
||||
{
|
||||
if(get(i).equals(j))
|
||||
{
|
||||
v.add(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a copy of this maps keys
|
||||
*
|
||||
* @return the keys
|
||||
*/
|
||||
public KList<K> k()
|
||||
{
|
||||
KList<K> k = new KList<K>();
|
||||
Enumeration<K> kk = keys();
|
||||
|
||||
while(kk.hasMoreElements())
|
||||
{
|
||||
K kkk = kk.nextElement();
|
||||
k.add(kkk);
|
||||
}
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a copy of this maps values
|
||||
*
|
||||
* @return the values
|
||||
*/
|
||||
public KList<V> v()
|
||||
{
|
||||
return new KList<V>(values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Still works as it normally should except it returns itself (builder)
|
||||
*
|
||||
* @param key
|
||||
* the key
|
||||
* @param value
|
||||
* the value (single only supported)
|
||||
* @return
|
||||
*/
|
||||
public KMap<K, V> qput(K key, V value)
|
||||
{
|
||||
super.put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Works just like put, except it wont put anything unless the key and value are
|
||||
* nonnull
|
||||
*
|
||||
* @param key
|
||||
* the nonnull key
|
||||
* @param value
|
||||
* the nonnull value
|
||||
* @return the same map
|
||||
*/
|
||||
public KMap<K, V> putNonNull(K key, V value)
|
||||
{
|
||||
if(key != null || value != null)
|
||||
{
|
||||
put(key, value);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public V putThen(K key, V valueIfKeyNotPresent)
|
||||
{
|
||||
if(!containsKey(key))
|
||||
{
|
||||
put(key, valueIfKeyNotPresent);
|
||||
}
|
||||
|
||||
return get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear this map and return it
|
||||
*
|
||||
* @return the cleared map
|
||||
*/
|
||||
public KMap<K, V> qclear()
|
||||
{
|
||||
super.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert this map to keypairs
|
||||
*
|
||||
* @return the keypair list
|
||||
*/
|
||||
public KList<KeyPair<K, V>> keypair()
|
||||
{
|
||||
KList<KeyPair<K, V>> g = new KList<>();
|
||||
each((k, v) -> g.add(new KeyPair<K, V>(k, v)));
|
||||
return g;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a keypair queue
|
||||
*
|
||||
* @return the queue
|
||||
*/
|
||||
public Queue<KeyPair<K, V>> enqueue()
|
||||
{
|
||||
return Queue.create(keypair());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a key queue
|
||||
*
|
||||
* @return the queue
|
||||
*/
|
||||
public Queue<K> enqueueKeys()
|
||||
{
|
||||
return Queue.create(k());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a value queue
|
||||
*
|
||||
* @return the queue
|
||||
*/
|
||||
public Queue<V> enqueueValues()
|
||||
{
|
||||
return Queue.create(v());
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
|
||||
public class KSet<T> extends HashSet<T>
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public KSet()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public KSet(Collection<? extends T> c)
|
||||
{
|
||||
super(c);
|
||||
}
|
||||
|
||||
public KSet(int initialCapacity, float loadFactor)
|
||||
{
|
||||
super(initialCapacity, loadFactor);
|
||||
}
|
||||
|
||||
public KSet(int initialCapacity)
|
||||
{
|
||||
super(initialCapacity);
|
||||
}
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
/**
|
||||
* Represents a keypair
|
||||
* @author cyberpwn
|
||||
*
|
||||
* @param <K> the key type
|
||||
* @param <V> the value type
|
||||
*/
|
||||
public class KeyPair<K, V>
|
||||
{
|
||||
private K k;
|
||||
private V v;
|
||||
|
||||
/**
|
||||
* Create a keypair
|
||||
* @param k the key
|
||||
* @param v the value
|
||||
*/
|
||||
public KeyPair(K k, V v)
|
||||
{
|
||||
this.k = k;
|
||||
this.v = v;
|
||||
}
|
||||
|
||||
public K getK()
|
||||
{
|
||||
return k;
|
||||
}
|
||||
|
||||
public void setK(K k)
|
||||
{
|
||||
this.k = k;
|
||||
}
|
||||
|
||||
public V getV()
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
public void setV(V v)
|
||||
{
|
||||
this.v = v;
|
||||
}
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
public abstract class Looper extends Thread
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
while(!interrupted())
|
||||
{
|
||||
try
|
||||
{
|
||||
long m = loop();
|
||||
|
||||
if(m < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
Thread.sleep(m);
|
||||
}
|
||||
|
||||
catch(InterruptedException e)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract long loop();
|
||||
}
|
@ -1,448 +0,0 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineManager;
|
||||
import javax.script.ScriptException;
|
||||
|
||||
/**
|
||||
* Math
|
||||
*
|
||||
* @author cyberpwn
|
||||
*/
|
||||
public class M
|
||||
{
|
||||
private static final int precision = 128;
|
||||
private static final int modulus = 360 * precision;
|
||||
private static final float[] sin = new float[modulus];
|
||||
|
||||
/**
|
||||
* Scales B by an external range change so that <br/>
|
||||
* <br/>
|
||||
* BMIN < B < BMAX <br/>
|
||||
* AMIN < RESULT < AMAX <br/>
|
||||
* <br/>
|
||||
* So Given rangeScale(0, 20, 0, 10, 5) -> 10 <br/>
|
||||
* 0 < 5 < 10 <br/>
|
||||
* 0 < ? < 20 <br/>
|
||||
* <br/>
|
||||
* would return 10
|
||||
*
|
||||
* @param amin
|
||||
* the resulting minimum
|
||||
* @param amax
|
||||
* the resulting maximum
|
||||
* @param bmin
|
||||
* the initial minimum
|
||||
* @param bmax
|
||||
* the initial maximum
|
||||
* @param b
|
||||
* the initial value
|
||||
* @return the resulting value
|
||||
*/
|
||||
public static double rangeScale(double amin, double amax, double bmin, double bmax, double b)
|
||||
{
|
||||
return amin + ((amax - amin) * ((b - bmin) / (bmax - bmin)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the percent (inverse lerp) from "from" to "to" where "at".
|
||||
*
|
||||
* If from = 0 and to = 100 and at = 25 then it would return 0.25
|
||||
*
|
||||
* @param from
|
||||
* the from
|
||||
* @param to
|
||||
* the to
|
||||
* @param at
|
||||
* the at
|
||||
* @return the percent
|
||||
*/
|
||||
public static double lerpInverse(double from, double to, double at)
|
||||
{
|
||||
return M.rangeScale(0, 1, from, to, at);
|
||||
}
|
||||
|
||||
/**
|
||||
* Linear interpolation from a to b where f is the percent across
|
||||
*
|
||||
* @param a
|
||||
* the first pos (0)
|
||||
* @param b
|
||||
* the second pos (1)
|
||||
* @param f
|
||||
* the percent
|
||||
* @return the value
|
||||
*/
|
||||
public static double lerp(double a, double b, double f)
|
||||
{
|
||||
return a + (f * (b - a));
|
||||
}
|
||||
|
||||
/**
|
||||
* Bilinear interpolation
|
||||
*
|
||||
* @param a
|
||||
* the first point (0, 0)
|
||||
* @param b
|
||||
* the second point (1, 0)
|
||||
* @param c
|
||||
* the third point (0, 1)
|
||||
* @param d
|
||||
* the fourth point (1, 1)
|
||||
* @param tx
|
||||
* the x
|
||||
* @param ty
|
||||
* the y
|
||||
* @return the bilerped value
|
||||
*/
|
||||
public static double bilerp(double a, double b, double c, double d, double x, double y)
|
||||
{
|
||||
return lerp(lerp(a, b, x), lerp(c, d, x), y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Trilinear interpolation
|
||||
*
|
||||
* @param a
|
||||
* the first point (0, 0, 0)
|
||||
* @param b
|
||||
* the second point (1, 0, 0)
|
||||
* @param c
|
||||
* the third point (0, 0, 1)
|
||||
* @param d
|
||||
* the fourth point (1, 0, 1)
|
||||
* @param e
|
||||
* the fifth point (0, 1, 0)
|
||||
* @param f
|
||||
* the sixth point (1, 1, 0)
|
||||
* @param g
|
||||
* the seventh point (0, 1, 1)
|
||||
* @param h
|
||||
* the eighth point (1, 1, 1)
|
||||
* @param x
|
||||
* the x
|
||||
* @param y
|
||||
* the y
|
||||
* @param z
|
||||
* the z
|
||||
* @return the trilerped value
|
||||
*/
|
||||
public static double trilerp(double a, double b, double c, double d, double e, double f, double g, double h, double x, double y, double z)
|
||||
{
|
||||
return lerp(bilerp(a, b, c, d, x, y), bilerp(e, f, g, h, x, y), z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clip a value
|
||||
*
|
||||
* @param value
|
||||
* the value
|
||||
* @param min
|
||||
* the min
|
||||
* @param max
|
||||
* the max
|
||||
* @return the clipped value
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T extends Number> T clip(T value, T min, T max)
|
||||
{
|
||||
return (T) Double.valueOf(Math.min(max.doubleValue(), Math.max(min.doubleValue(), value.doubleValue())));
|
||||
}
|
||||
|
||||
public static int iclip(int value, int min, int max)
|
||||
{
|
||||
return Math.min(max, Math.max(min, value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get true or false based on random percent
|
||||
*
|
||||
* @param d
|
||||
* between 0 and 1
|
||||
* @return true if true
|
||||
*/
|
||||
public static boolean r(Double d)
|
||||
{
|
||||
if(d == null)
|
||||
{
|
||||
return Math.random() < 0.5;
|
||||
}
|
||||
|
||||
return Math.random() < d;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ticks per second from a time in nanoseconds, the rad can be used for
|
||||
* multiple ticks
|
||||
*
|
||||
* @param ns
|
||||
* the time in nanoseconds
|
||||
* @param rad
|
||||
* the radius of the time
|
||||
* @return the ticks per second in double form
|
||||
*/
|
||||
public static double tps(long ns, int rad)
|
||||
{
|
||||
return (20.0 * (ns / 50000000.0)) / rad;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of ticks from a time in nanoseconds
|
||||
*
|
||||
* @param ns
|
||||
* the nanoseconds
|
||||
* @return the amount of ticks
|
||||
*/
|
||||
public static double ticksFromNS(long ns)
|
||||
{
|
||||
return (ns / 50000000.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a random int from to (inclusive)
|
||||
*
|
||||
* @param f
|
||||
* the from
|
||||
* @param t
|
||||
* the to
|
||||
* @return the value
|
||||
*/
|
||||
public static int irand(int f, int t)
|
||||
{
|
||||
return f + (int) (Math.random() * ((t - f) + 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a random float from to (inclusive)
|
||||
*
|
||||
* @param f
|
||||
* the from
|
||||
* @param t
|
||||
* the to
|
||||
* @return the value
|
||||
*/
|
||||
public static float frand(float f, float t)
|
||||
{
|
||||
return f + (float) (Math.random() * ((t - f) + 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a random double from to (inclusive)
|
||||
*
|
||||
* @param f
|
||||
* the from
|
||||
* @param t
|
||||
* the to
|
||||
* @return the value
|
||||
*/
|
||||
public static double drand(double f, double t)
|
||||
{
|
||||
return f + (Math.random() * ((t - f) + 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get system Nanoseconds
|
||||
*
|
||||
* @return nanoseconds (current)
|
||||
*/
|
||||
public static long ns()
|
||||
{
|
||||
return System.nanoTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current millisecond time
|
||||
*
|
||||
* @return milliseconds
|
||||
*/
|
||||
public static long ms()
|
||||
{
|
||||
return System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fast sin function
|
||||
*
|
||||
* @param a
|
||||
* the number
|
||||
* @return the sin
|
||||
*/
|
||||
public static float sin(float a)
|
||||
{
|
||||
return sinLookup((int) (a * precision + 0.5f));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fast cos function
|
||||
*
|
||||
* @param a
|
||||
* the number
|
||||
* @return the cos
|
||||
*/
|
||||
public static float cos(float a)
|
||||
{
|
||||
return sinLookup((int) ((a + 90f) * precision + 0.5f));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fast tan function
|
||||
*
|
||||
* @param a
|
||||
* the number
|
||||
* @return the tan
|
||||
*/
|
||||
public static float tan(float a)
|
||||
{
|
||||
float c = cos(a);
|
||||
return sin(a) / (c == 0 ? 0.0000001f : c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Biggest number
|
||||
*
|
||||
* @param numbers
|
||||
* the numbers
|
||||
* @return the biggest one
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T extends Number> T max(T... doubles)
|
||||
{
|
||||
double max = Double.MIN_VALUE;
|
||||
|
||||
for(T i : doubles)
|
||||
{
|
||||
if(i.doubleValue() > max)
|
||||
{
|
||||
max = i.doubleValue();
|
||||
}
|
||||
}
|
||||
|
||||
return (T) Double.valueOf(max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Smallest number
|
||||
*
|
||||
* @param doubles
|
||||
* the numbers
|
||||
* @return the smallest one
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T extends Number> T min(T... doubles)
|
||||
{
|
||||
double min = Double.MAX_VALUE;
|
||||
|
||||
for(T i : doubles)
|
||||
{
|
||||
if(i.doubleValue() < min)
|
||||
{
|
||||
min = i.doubleValue();
|
||||
}
|
||||
}
|
||||
|
||||
return (T) Double.valueOf(min);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates an expression using javascript engine and returns the double
|
||||
* result. This can take variable parameters, so you need to define them.
|
||||
* Parameters are defined as $[0-9]. For example evaluate("4$0/$1", 1, 2); This
|
||||
* makes the expression (4x1)/2 == 2. Keep note that you must use 0-9, you
|
||||
* cannot skip, or start at a number other than 0.
|
||||
*
|
||||
* @param expression
|
||||
* the expression with variables
|
||||
* @param args
|
||||
* the arguments/variables
|
||||
* @return the resulting double value
|
||||
* @throws ScriptException
|
||||
* ... gg
|
||||
* @throws IndexOutOfBoundsException
|
||||
* learn to count
|
||||
*/
|
||||
public static double evaluate(String expression, Double... args) throws ScriptException, IndexOutOfBoundsException
|
||||
{
|
||||
for(int i = 0; i < args.length; i++)
|
||||
{
|
||||
String current = "$" + i;
|
||||
|
||||
if(expression.contains(current))
|
||||
{
|
||||
expression = expression.replaceAll(Matcher.quoteReplacement(current), args[i] + "");
|
||||
}
|
||||
}
|
||||
|
||||
return evaluate(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates an expression using javascript engine and returns the double
|
||||
*
|
||||
* @param expression
|
||||
* the mathimatical expression
|
||||
* @return the double result
|
||||
* @throws ScriptException
|
||||
* ... gg
|
||||
*/
|
||||
public static double evaluate(String expression) throws ScriptException
|
||||
{
|
||||
ScriptEngineManager mgr = new ScriptEngineManager();
|
||||
ScriptEngine scriptEngine = mgr.getEngineByName("JavaScript");
|
||||
|
||||
return Double.valueOf(scriptEngine.eval(expression).toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* is the number "is" within from-to
|
||||
*
|
||||
* @param from
|
||||
* the lower end
|
||||
* @param to
|
||||
* the upper end
|
||||
* @param is
|
||||
* the check
|
||||
* @return true if its within
|
||||
*/
|
||||
public static boolean within(int from, int to, int is)
|
||||
{
|
||||
return is >= from && is <= to;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the amount of days past since the epoch time (1970 jan 1 utc)
|
||||
*
|
||||
* @return the epoch days
|
||||
*/
|
||||
public static long epochDays()
|
||||
{
|
||||
return epochDays(M.ms());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the amount of days past since the epoch time (1970 jan 1 utc)
|
||||
*
|
||||
* @param ms
|
||||
* the time in milliseconds
|
||||
* @return the epoch days
|
||||
*/
|
||||
private static long epochDays(long ms)
|
||||
{
|
||||
return ms / 1000 / 60 / 60 / 24;
|
||||
}
|
||||
|
||||
static
|
||||
{
|
||||
for(int i = 0; i < sin.length; i++)
|
||||
{
|
||||
sin[i] = (float) Math.sin((i * Math.PI) / (precision * 180));
|
||||
}
|
||||
}
|
||||
|
||||
private static float sinLookup(int a)
|
||||
{
|
||||
return a >= 0 ? sin[a % (modulus)] : -sin[-a % (modulus)];
|
||||
}
|
||||
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
public interface NastyFunction<T, R>
|
||||
{
|
||||
public R run(T t) throws Throwable;
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
public interface NastyFuture<R>
|
||||
{
|
||||
public R run() throws Throwable;
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
public interface NastyRunnable
|
||||
{
|
||||
public void run() throws Throwable;
|
||||
}
|
@ -2,6 +2,10 @@ package ninja.bytecode.iris.util;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
import ninja.bytecode.shuriken.collections.KMap;
|
||||
import ninja.bytecode.shuriken.math.M;
|
||||
|
||||
public class PolygonGenerator
|
||||
{
|
||||
private double[] rarity;
|
||||
|
@ -1,101 +0,0 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
public class PrecisionStopwatch {
|
||||
private long nanos;
|
||||
private long startNano;
|
||||
private long millis;
|
||||
private long startMillis;
|
||||
private double time;
|
||||
private boolean profiling;
|
||||
|
||||
public static PrecisionStopwatch start() {
|
||||
PrecisionStopwatch p = new PrecisionStopwatch();
|
||||
p.begin();
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
public PrecisionStopwatch() {
|
||||
reset();
|
||||
profiling = false;
|
||||
}
|
||||
|
||||
public void begin() {
|
||||
profiling = true;
|
||||
startNano = System.nanoTime();
|
||||
startMillis = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public void end() {
|
||||
if (!profiling) {
|
||||
return;
|
||||
}
|
||||
|
||||
profiling = false;
|
||||
nanos = System.nanoTime() - startNano;
|
||||
millis = System.currentTimeMillis() - startMillis;
|
||||
time = (double) nanos / 1000000.0;
|
||||
time = (double) millis - time > 1.01 ? millis : time;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
nanos = -1;
|
||||
millis = -1;
|
||||
startNano = -1;
|
||||
startMillis = -1;
|
||||
time = -0;
|
||||
profiling = false;
|
||||
}
|
||||
|
||||
public double getTicks() {
|
||||
return getMilliseconds() / 50.0;
|
||||
}
|
||||
|
||||
public double getSeconds() {
|
||||
return getMilliseconds() / 1000.0;
|
||||
}
|
||||
|
||||
public double getMinutes() {
|
||||
return getSeconds() / 60.0;
|
||||
}
|
||||
|
||||
public double getHours() {
|
||||
return getMinutes() / 60.0;
|
||||
}
|
||||
|
||||
public double getMilliseconds() {
|
||||
nanos = System.nanoTime() - startNano;
|
||||
millis = System.currentTimeMillis() - startMillis;
|
||||
time = (double) nanos / 1000000.0;
|
||||
time = (double) millis - time > 1.01 ? millis : time;
|
||||
return time;
|
||||
}
|
||||
|
||||
public long getNanoseconds() {
|
||||
return (long) (time * 1000000.0);
|
||||
}
|
||||
|
||||
public long getNanos() {
|
||||
return nanos;
|
||||
}
|
||||
|
||||
public long getStartNano() {
|
||||
return startNano;
|
||||
}
|
||||
|
||||
public long getMillis() {
|
||||
return millis;
|
||||
}
|
||||
|
||||
public long getStartMillis() {
|
||||
return startMillis;
|
||||
}
|
||||
|
||||
public double getTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
public boolean isProfiling() {
|
||||
return profiling;
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
public interface Queue<T>
|
||||
{
|
||||
public Queue<T> queue(T t);
|
||||
|
||||
public Queue<T> queue(KList<T> t);
|
||||
|
||||
public boolean hasNext(int amt);
|
||||
|
||||
public boolean hasNext();
|
||||
|
||||
public T next();
|
||||
|
||||
public KList<T> next(int amt);
|
||||
|
||||
public Queue<T> clear();
|
||||
|
||||
public int size();
|
||||
|
||||
public static <T> Queue<T> create(KList<T> t)
|
||||
{
|
||||
return new ShurikenQueue<T>().queue(t);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> Queue<T> create(T... t)
|
||||
{
|
||||
return new ShurikenQueue<T>().queue(new KList<T>().add(t));
|
||||
}
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
public class QueueExecutor extends Looper
|
||||
{
|
||||
private Queue<Runnable> queue;
|
||||
private boolean shutdown;
|
||||
|
||||
public QueueExecutor()
|
||||
{
|
||||
queue = new ShurikenQueue<Runnable>();
|
||||
shutdown = false;
|
||||
}
|
||||
|
||||
public Queue<Runnable> queue()
|
||||
{
|
||||
return queue;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long loop()
|
||||
{
|
||||
|
||||
while(queue.hasNext())
|
||||
{
|
||||
try
|
||||
{
|
||||
queue.next().run();
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if(shutdown && !queue.hasNext())
|
||||
{
|
||||
interrupt();
|
||||
return -1;
|
||||
}
|
||||
|
||||
return Math.max(500, (long) getRunTime() * 10);
|
||||
}
|
||||
|
||||
public double getRunTime()
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
public void shutdown()
|
||||
{
|
||||
shutdown = true;
|
||||
}
|
||||
}
|
@ -1,12 +1,16 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import ninja.bytecode.iris.Iris;
|
||||
import ninja.bytecode.iris.object.IrisRegisteredObject;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
import ninja.bytecode.shuriken.collections.KMap;
|
||||
|
||||
public class ResourceLoader<T>
|
||||
public class ResourceLoader<T extends IrisRegisteredObject>
|
||||
{
|
||||
private File root;
|
||||
private String folderName;
|
||||
@ -14,9 +18,11 @@ public class ResourceLoader<T>
|
||||
private KMap<String, T> loadCache;
|
||||
private KList<File> folderCache;
|
||||
private Class<? extends T> objectClass;
|
||||
private ReentrantLock lock;
|
||||
|
||||
public ResourceLoader(File root, String folderName, String resourceTypeName, Class<? extends T> objectClass)
|
||||
{
|
||||
lock = new ReentrantLock();
|
||||
this.objectClass = objectClass;
|
||||
this.resourceTypeName = resourceTypeName;
|
||||
this.root = root;
|
||||
@ -30,9 +36,11 @@ public class ResourceLoader<T>
|
||||
|
||||
if(loadCache.containsKey(key))
|
||||
{
|
||||
return loadCache.get(key);
|
||||
T t = loadCache.get(key);
|
||||
return t;
|
||||
}
|
||||
|
||||
lock.lock();
|
||||
for(File i : getFolders())
|
||||
{
|
||||
for(File j : i.listFiles())
|
||||
@ -45,12 +53,14 @@ public class ResourceLoader<T>
|
||||
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());
|
||||
}
|
||||
}
|
||||
@ -59,6 +69,7 @@ public class ResourceLoader<T>
|
||||
|
||||
Iris.warn("Couldn't find " + resourceTypeName + ": " + name);
|
||||
|
||||
lock.unlock();
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -1,101 +0,0 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
public class RollingSequence extends Average
|
||||
{
|
||||
private double median;
|
||||
private double max;
|
||||
private double min;
|
||||
private boolean dirtyMedian;
|
||||
private int dirtyExtremes;
|
||||
private boolean precision;
|
||||
|
||||
public RollingSequence(int size)
|
||||
{
|
||||
super(size);
|
||||
median = 0;
|
||||
min = 0;
|
||||
max = 0;
|
||||
setPrecision(false);
|
||||
}
|
||||
|
||||
public double addLast(int amt)
|
||||
{
|
||||
double f = 0;
|
||||
|
||||
for(int i = 0; i < Math.min(values.length, amt); i++)
|
||||
{
|
||||
f += values[i];
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
public void setPrecision(boolean p)
|
||||
{
|
||||
this.precision = p;
|
||||
}
|
||||
|
||||
public boolean isPrecision()
|
||||
{
|
||||
return precision;
|
||||
}
|
||||
|
||||
public double getMin()
|
||||
{
|
||||
if(dirtyExtremes > (isPrecision() ? 0 : values.length))
|
||||
{
|
||||
resetExtremes();
|
||||
}
|
||||
|
||||
return min;
|
||||
}
|
||||
|
||||
public double getMax()
|
||||
{
|
||||
if(dirtyExtremes > (isPrecision() ? 0 : values.length))
|
||||
{
|
||||
resetExtremes();
|
||||
}
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
public double getMedian()
|
||||
{
|
||||
if(dirtyMedian)
|
||||
{
|
||||
recalculateMedian();
|
||||
}
|
||||
|
||||
return median;
|
||||
}
|
||||
|
||||
private void recalculateMedian()
|
||||
{
|
||||
median = new KList<Double>().forceAdd(values).sort().middleValue();
|
||||
dirtyMedian = false;
|
||||
}
|
||||
|
||||
public void resetExtremes()
|
||||
{
|
||||
max = Integer.MIN_VALUE;
|
||||
min = Integer.MAX_VALUE;
|
||||
|
||||
for(double i : values)
|
||||
{
|
||||
max = M.max(max, i);
|
||||
min = M.min(min, i);
|
||||
}
|
||||
|
||||
dirtyExtremes = 0;
|
||||
}
|
||||
|
||||
public void put(double i)
|
||||
{
|
||||
super.put(i);
|
||||
dirtyMedian = true;
|
||||
dirtyExtremes++;
|
||||
max = M.max(max, i);
|
||||
min = M.min(min, i);
|
||||
}
|
||||
}
|
10
src/main/java/ninja/bytecode/iris/util/ScoreDirection.java
Normal file
10
src/main/java/ninja/bytecode/iris/util/ScoreDirection.java
Normal file
@ -0,0 +1,10 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
/**
|
||||
* @author Missionary (missionarymc@gmail.com)
|
||||
* @since 5/31/2018
|
||||
*/
|
||||
public enum ScoreDirection {
|
||||
UP,
|
||||
DOWN
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
public class ShurikenQueue<T> implements Queue<T>
|
||||
{
|
||||
private KList<T> queue;
|
||||
private boolean randomPop;
|
||||
private boolean reversePop;
|
||||
|
||||
public ShurikenQueue()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
public ShurikenQueue<T> responsiveMode()
|
||||
{
|
||||
reversePop = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ShurikenQueue<T> randomMode()
|
||||
{
|
||||
randomPop = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShurikenQueue<T> queue(T t)
|
||||
{
|
||||
queue.add(t);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShurikenQueue<T> queue(KList<T> t)
|
||||
{
|
||||
queue.add(t);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext(int amt)
|
||||
{
|
||||
return queue.size() >= amt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext()
|
||||
{
|
||||
return !queue.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next()
|
||||
{
|
||||
return reversePop ? queue.popLast() : randomPop ? queue.popRandom() : queue.pop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public KList<T> next(int amt)
|
||||
{
|
||||
KList<T> t = new KList<>();
|
||||
|
||||
for(int i = 0; i < amt; i++)
|
||||
{
|
||||
if(!hasNext())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
t.add(next());
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShurikenQueue<T> clear()
|
||||
{
|
||||
queue = new KList<T>();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size()
|
||||
{
|
||||
return queue.size();
|
||||
}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
import ninja.bytecode.shuriken.collections.KMap;
|
||||
|
||||
public class WeightMap<T> extends KMap<T, Double>
|
||||
{
|
||||
private static final long serialVersionUID = 87558033900969389L;
|
||||
|
@ -1,584 +0,0 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
|
||||
/*
|
||||
Copyright (c) 2002 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* This provides static methods to convert an XML text into a JSONObject, and to
|
||||
* covert a JSONObject into an XML text.
|
||||
*
|
||||
* @author JSON.org
|
||||
* @version 2014-05-03
|
||||
*/
|
||||
public class XML
|
||||
{
|
||||
|
||||
/** The Character '&'. */
|
||||
public static final Character AMP = '&';
|
||||
|
||||
/** The Character '''. */
|
||||
public static final Character APOS = '\'';
|
||||
|
||||
/** The Character '!'. */
|
||||
public static final Character BANG = '!';
|
||||
|
||||
/** The Character '='. */
|
||||
public static final Character EQ = '=';
|
||||
|
||||
/** The Character '>'. */
|
||||
public static final Character GT = '>';
|
||||
|
||||
/** The Character '<'. */
|
||||
public static final Character LT = '<';
|
||||
|
||||
/** The Character '?'. */
|
||||
public static final Character QUEST = '?';
|
||||
|
||||
/** The Character '"'. */
|
||||
public static final Character QUOT = '"';
|
||||
|
||||
/** The Character '/'. */
|
||||
public static final Character SLASH = '/';
|
||||
|
||||
/**
|
||||
* Replace special characters with XML escapes:
|
||||
*
|
||||
* <pre>
|
||||
* & <small>(ampersand)</small> is replaced by &amp;
|
||||
* < <small>(less than)</small> is replaced by &lt;
|
||||
* > <small>(greater than)</small> is replaced by &gt;
|
||||
* " <small>(double quote)</small> is replaced by &quot;
|
||||
* </pre>
|
||||
*
|
||||
* @param string
|
||||
* The string to be escaped.
|
||||
* @return The escaped string.
|
||||
*/
|
||||
public static String escape(String string)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder(string.length());
|
||||
for(int i = 0, length = string.length(); i < length; i++)
|
||||
{
|
||||
char c = string.charAt(i);
|
||||
switch(c)
|
||||
{
|
||||
case '&':
|
||||
sb.append("&");
|
||||
break;
|
||||
case '<':
|
||||
sb.append("<");
|
||||
break;
|
||||
case '>':
|
||||
sb.append(">");
|
||||
break;
|
||||
case '"':
|
||||
sb.append(""");
|
||||
break;
|
||||
case '\'':
|
||||
sb.append("'");
|
||||
break;
|
||||
default:
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw an exception if the string contains whitespace. Whitespace is not
|
||||
* allowed in tagNames and attributes.
|
||||
*
|
||||
* @param string
|
||||
* A string.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static void noSpace(String string) throws JSONException
|
||||
{
|
||||
int i, length = string.length();
|
||||
if(length == 0)
|
||||
{
|
||||
throw new JSONException("Empty string.");
|
||||
}
|
||||
for(i = 0; i < length; i += 1)
|
||||
{
|
||||
if(Character.isWhitespace(string.charAt(i)))
|
||||
{
|
||||
throw new JSONException("'" + string + "' contains a space character.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan the content following the named tag, attaching it to the context.
|
||||
*
|
||||
* @param x
|
||||
* The XMLTokener containing the source string.
|
||||
* @param context
|
||||
* The JSONObject that will include the new material.
|
||||
* @param name
|
||||
* The tag name.
|
||||
* @return true if the close tag is processed.
|
||||
* @throws JSONException
|
||||
*/
|
||||
private static boolean parse(XMLTokener x, JSONObject context, String name) throws JSONException
|
||||
{
|
||||
char c;
|
||||
int i;
|
||||
JSONObject jsonobject = null;
|
||||
String string;
|
||||
String tagName;
|
||||
Object token;
|
||||
|
||||
// Test for and skip past these forms:
|
||||
// <!-- ... -->
|
||||
// <! ... >
|
||||
// <![ ... ]]>
|
||||
// <? ... ?>
|
||||
// Report errors for these forms:
|
||||
// <>
|
||||
// <=
|
||||
// <<
|
||||
|
||||
token = x.nextToken();
|
||||
|
||||
// <!
|
||||
|
||||
if(token == BANG)
|
||||
{
|
||||
c = x.next();
|
||||
if(c == '-')
|
||||
{
|
||||
if(x.next() == '-')
|
||||
{
|
||||
x.skipPast("-->");
|
||||
return false;
|
||||
}
|
||||
x.back();
|
||||
} else if(c == '[')
|
||||
{
|
||||
token = x.nextToken();
|
||||
if("CDATA".equals(token))
|
||||
{
|
||||
if(x.next() == '[')
|
||||
{
|
||||
string = x.nextCDATA();
|
||||
if(string.length() > 0)
|
||||
{
|
||||
context.accumulate("content", string);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
throw x.syntaxError("Expected 'CDATA['");
|
||||
}
|
||||
i = 1;
|
||||
do
|
||||
{
|
||||
token = x.nextMeta();
|
||||
if(token == null)
|
||||
{
|
||||
throw x.syntaxError("Missing '>' after '<!'.");
|
||||
} else if(token == LT)
|
||||
{
|
||||
i += 1;
|
||||
} else if(token == GT)
|
||||
{
|
||||
i -= 1;
|
||||
}
|
||||
} while(i > 0);
|
||||
return false;
|
||||
} else if(token == QUEST)
|
||||
{
|
||||
|
||||
// <?
|
||||
|
||||
x.skipPast("?>");
|
||||
return false;
|
||||
} else if(token == SLASH)
|
||||
{
|
||||
|
||||
// Close tag </
|
||||
|
||||
token = x.nextToken();
|
||||
if(name == null)
|
||||
{
|
||||
throw x.syntaxError("Mismatched close tag " + token);
|
||||
}
|
||||
if(!token.equals(name))
|
||||
{
|
||||
throw x.syntaxError("Mismatched " + name + " and " + token);
|
||||
}
|
||||
if(x.nextToken() != GT)
|
||||
{
|
||||
throw x.syntaxError("Misshaped close tag");
|
||||
}
|
||||
return true;
|
||||
|
||||
} else if(token instanceof Character)
|
||||
{
|
||||
throw x.syntaxError("Misshaped tag");
|
||||
|
||||
// Open tag <
|
||||
|
||||
} else
|
||||
{
|
||||
tagName = (String) token;
|
||||
token = null;
|
||||
jsonobject = new JSONObject();
|
||||
for(;;)
|
||||
{
|
||||
if(token == null)
|
||||
{
|
||||
token = x.nextToken();
|
||||
}
|
||||
|
||||
// attribute = value
|
||||
|
||||
if(token instanceof String)
|
||||
{
|
||||
string = (String) token;
|
||||
token = x.nextToken();
|
||||
if(token == EQ)
|
||||
{
|
||||
token = x.nextToken();
|
||||
if(!(token instanceof String))
|
||||
{
|
||||
throw x.syntaxError("Missing value");
|
||||
}
|
||||
jsonobject.accumulate(string, XML.stringToValue((String) token));
|
||||
token = null;
|
||||
} else
|
||||
{
|
||||
jsonobject.accumulate(string, "");
|
||||
}
|
||||
|
||||
// Empty tag <.../>
|
||||
|
||||
} else if(token == SLASH)
|
||||
{
|
||||
if(x.nextToken() != GT)
|
||||
{
|
||||
throw x.syntaxError("Misshaped tag");
|
||||
}
|
||||
if(jsonobject.length() > 0)
|
||||
{
|
||||
context.accumulate(tagName, jsonobject);
|
||||
} else
|
||||
{
|
||||
context.accumulate(tagName, "");
|
||||
}
|
||||
return false;
|
||||
|
||||
// Content, between <...> and </...>
|
||||
|
||||
} else if(token == GT)
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
token = x.nextContent();
|
||||
if(token == null)
|
||||
{
|
||||
if(tagName != null)
|
||||
{
|
||||
throw x.syntaxError("Unclosed tag " + tagName);
|
||||
}
|
||||
return false;
|
||||
} else if(token instanceof String)
|
||||
{
|
||||
string = (String) token;
|
||||
if(string.length() > 0)
|
||||
{
|
||||
jsonobject.accumulate("content", XML.stringToValue(string));
|
||||
}
|
||||
|
||||
// Nested element
|
||||
|
||||
} else if(token == LT)
|
||||
{
|
||||
if(parse(x, jsonobject, tagName))
|
||||
{
|
||||
if(jsonobject.length() == 0)
|
||||
{
|
||||
context.accumulate(tagName, "");
|
||||
} else if(jsonobject.length() == 1 && jsonobject.opt("content") != null)
|
||||
{
|
||||
context.accumulate(tagName, jsonobject.opt("content"));
|
||||
} else
|
||||
{
|
||||
context.accumulate(tagName, jsonobject);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else
|
||||
{
|
||||
throw x.syntaxError("Misshaped tag");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to convert a string into a number, boolean, or null. If the string
|
||||
* can't be converted, return the string. This is much less ambitious than
|
||||
* JSONObject.stringToValue, especially because it does not attempt to
|
||||
* convert plus forms, octal forms, hex forms, or E forms lacking decimal
|
||||
* points.
|
||||
*
|
||||
* @param string
|
||||
* A String.
|
||||
* @return A simple JSON value.
|
||||
*/
|
||||
public static Object stringToValue(String string)
|
||||
{
|
||||
if("true".equalsIgnoreCase(string))
|
||||
{
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
if("false".equalsIgnoreCase(string))
|
||||
{
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
if("null".equalsIgnoreCase(string))
|
||||
{
|
||||
return JSONObject.NULL;
|
||||
}
|
||||
|
||||
// If it might be a number, try converting it, first as a Long, and then
|
||||
// as a
|
||||
// Double. If that doesn't work, return the string.
|
||||
|
||||
try
|
||||
{
|
||||
char initial = string.charAt(0);
|
||||
if(initial == '-' || (initial >= '0' && initial <= '9'))
|
||||
{
|
||||
Long value = new Long(string);
|
||||
if(value.toString().equals(string))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
} catch(Exception ignore)
|
||||
{
|
||||
try
|
||||
{
|
||||
Double value = new Double(string);
|
||||
if(value.toString().equals(string))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
} catch(Exception ignoreAlso)
|
||||
{
|
||||
}
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a well-formed (but not necessarily valid) XML string into a
|
||||
* JSONObject. Some information may be lost in this transformation because
|
||||
* JSON is a data format and XML is a document format. XML uses elements,
|
||||
* attributes, and content text, while JSON uses unordered collections of
|
||||
* name/value pairs and arrays of values. JSON does not does not like to
|
||||
* distinguish between elements and attributes. Sequences of similar
|
||||
* elements are represented as JSONArrays. Content text may be placed in a
|
||||
* "content" member. Comments, prologs, DTDs, and <code><[ [ ]]></code>
|
||||
* are ignored.
|
||||
*
|
||||
* @param string
|
||||
* The source string.
|
||||
* @return A JSONObject containing the structured data from the XML string.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static JSONObject toJSONObject(String string) throws JSONException
|
||||
{
|
||||
JSONObject jo = new JSONObject();
|
||||
XMLTokener x = new XMLTokener(string);
|
||||
while(x.more() && x.skipPast("<"))
|
||||
{
|
||||
parse(x, jo, null);
|
||||
}
|
||||
return jo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a JSONObject into a well-formed, element-normal XML string.
|
||||
*
|
||||
* @param object
|
||||
* A JSONObject.
|
||||
* @return A string.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static String toString(Object object) throws JSONException
|
||||
{
|
||||
return toString(object, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a JSONObject into a well-formed, element-normal XML string.
|
||||
*
|
||||
* @param object
|
||||
* A JSONObject.
|
||||
* @param tagName
|
||||
* The optional name of the enclosing tag.
|
||||
* @return A string.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static String toString(Object object, String tagName) throws JSONException
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int i;
|
||||
JSONArray ja;
|
||||
JSONObject jo;
|
||||
String key;
|
||||
Iterator<String> keys;
|
||||
int length;
|
||||
String string;
|
||||
Object value;
|
||||
if(object instanceof JSONObject)
|
||||
{
|
||||
|
||||
// Emit <tagName>
|
||||
|
||||
if(tagName != null)
|
||||
{
|
||||
sb.append('<');
|
||||
sb.append(tagName);
|
||||
sb.append('>');
|
||||
}
|
||||
|
||||
// Loop thru the keys.
|
||||
|
||||
jo = (JSONObject) object;
|
||||
keys = jo.keys();
|
||||
while(keys.hasNext())
|
||||
{
|
||||
key = keys.next();
|
||||
value = jo.opt(key);
|
||||
if(value == null)
|
||||
{
|
||||
value = "";
|
||||
}
|
||||
string = value instanceof String ? (String) value : null;
|
||||
|
||||
// Emit content in body
|
||||
|
||||
if("content".equals(key))
|
||||
{
|
||||
if(value instanceof JSONArray)
|
||||
{
|
||||
ja = (JSONArray) value;
|
||||
length = ja.length();
|
||||
for(i = 0; i < length; i += 1)
|
||||
{
|
||||
if(i > 0)
|
||||
{
|
||||
sb.append('\n');
|
||||
}
|
||||
sb.append(escape(ja.get(i).toString()));
|
||||
}
|
||||
} else
|
||||
{
|
||||
sb.append(escape(value.toString()));
|
||||
}
|
||||
|
||||
// Emit an array of similar keys
|
||||
|
||||
} else if(value instanceof JSONArray)
|
||||
{
|
||||
ja = (JSONArray) value;
|
||||
length = ja.length();
|
||||
for(i = 0; i < length; i += 1)
|
||||
{
|
||||
value = ja.get(i);
|
||||
if(value instanceof JSONArray)
|
||||
{
|
||||
sb.append('<');
|
||||
sb.append(key);
|
||||
sb.append('>');
|
||||
sb.append(toString(value));
|
||||
sb.append("</");
|
||||
sb.append(key);
|
||||
sb.append('>');
|
||||
} else
|
||||
{
|
||||
sb.append(toString(value, key));
|
||||
}
|
||||
}
|
||||
} else if("".equals(value))
|
||||
{
|
||||
sb.append('<');
|
||||
sb.append(key);
|
||||
sb.append("/>");
|
||||
|
||||
// Emit a new tag <k>
|
||||
|
||||
} else
|
||||
{
|
||||
sb.append(toString(value, key));
|
||||
}
|
||||
}
|
||||
if(tagName != null)
|
||||
{
|
||||
|
||||
// Emit the </tagname> close tag
|
||||
|
||||
sb.append("</");
|
||||
sb.append(tagName);
|
||||
sb.append('>');
|
||||
}
|
||||
return sb.toString();
|
||||
|
||||
// XML does not have good support for arrays. If an array appears in
|
||||
// a place
|
||||
// where XML is lacking, synthesize an <array> element.
|
||||
|
||||
} else
|
||||
{
|
||||
if(object.getClass().isArray())
|
||||
{
|
||||
object = new JSONArray(object);
|
||||
}
|
||||
if(object instanceof JSONArray)
|
||||
{
|
||||
ja = (JSONArray) object;
|
||||
length = ja.length();
|
||||
for(i = 0; i < length; i += 1)
|
||||
{
|
||||
sb.append(toString(ja.opt(i), tagName == null ? "array" : tagName));
|
||||
}
|
||||
return sb.toString();
|
||||
} else
|
||||
{
|
||||
string = (object == null) ? "null" : escape(object.toString());
|
||||
return (tagName == null) ? "\"" + string + "\"" : (string.length() == 0) ? "<" + tagName + "/>" : "<" + tagName + ">" + string + "</" + tagName + ">";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,425 +0,0 @@
|
||||
package ninja.bytecode.iris.util;
|
||||
|
||||
|
||||
/*
|
||||
Copyright (c) 2002 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The XMLTokener extends the JSONTokener to provide additional methods for the
|
||||
* parsing of XML texts.
|
||||
*
|
||||
* @author JSON.org
|
||||
* @version 2014-05-03
|
||||
*/
|
||||
public class XMLTokener extends JSONTokener
|
||||
{
|
||||
|
||||
/**
|
||||
* The table of entity values. It initially contains Character values for
|
||||
* amp, apos, gt, lt, quot.
|
||||
*/
|
||||
public static final java.util.HashMap<String, Character> entity;
|
||||
|
||||
static
|
||||
{
|
||||
entity = new java.util.HashMap<String, Character>(8);
|
||||
entity.put("amp", XML.AMP);
|
||||
entity.put("apos", XML.APOS);
|
||||
entity.put("gt", XML.GT);
|
||||
entity.put("lt", XML.LT);
|
||||
entity.put("quot", XML.QUOT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an XMLTokener from a string.
|
||||
*
|
||||
* @param s
|
||||
* A source string.
|
||||
*/
|
||||
public XMLTokener(String s)
|
||||
{
|
||||
super(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the text in the CDATA block.
|
||||
*
|
||||
* @return The string up to the <code>]]></code>.
|
||||
* @throws JSONException
|
||||
* If the <code>]]></code> is not found.
|
||||
*/
|
||||
public String nextCDATA() throws JSONException
|
||||
{
|
||||
char c;
|
||||
int i;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for(;;)
|
||||
{
|
||||
c = next();
|
||||
if(end())
|
||||
{
|
||||
throw syntaxError("Unclosed CDATA");
|
||||
}
|
||||
sb.append(c);
|
||||
i = sb.length() - 3;
|
||||
if(i >= 0 && sb.charAt(i) == ']' && sb.charAt(i + 1) == ']' && sb.charAt(i + 2) == '>')
|
||||
{
|
||||
sb.setLength(i);
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next XML outer token, trimming whitespace. There are two kinds of
|
||||
* tokens: the '<' character which begins a markup tag, and the content text
|
||||
* between markup tags.
|
||||
*
|
||||
* @return A string, or a '<' Character, or null if there is no more source
|
||||
* text.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public Object nextContent() throws JSONException
|
||||
{
|
||||
char c;
|
||||
StringBuilder sb;
|
||||
do
|
||||
{
|
||||
c = next();
|
||||
} while(Character.isWhitespace(c));
|
||||
if(c == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if(c == '<')
|
||||
{
|
||||
return XML.LT;
|
||||
}
|
||||
sb = new StringBuilder();
|
||||
for(;;)
|
||||
{
|
||||
if(c == '<' || c == 0)
|
||||
{
|
||||
back();
|
||||
return sb.toString().trim();
|
||||
}
|
||||
if(c == '&')
|
||||
{
|
||||
sb.append(nextEntity(c));
|
||||
} else
|
||||
{
|
||||
sb.append(c);
|
||||
}
|
||||
c = next();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the next entity. These entities are translated to Characters:
|
||||
* <code>& ' > < "</code>.
|
||||
*
|
||||
* @param ampersand
|
||||
* An ampersand character.
|
||||
* @return A Character or an entity String if the entity is not recognized.
|
||||
* @throws JSONException
|
||||
* If missing ';' in XML entity.
|
||||
*/
|
||||
public Object nextEntity(char ampersand) throws JSONException
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for(;;)
|
||||
{
|
||||
char c = next();
|
||||
if(Character.isLetterOrDigit(c) || c == '#')
|
||||
{
|
||||
sb.append(Character.toLowerCase(c));
|
||||
} else if(c == ';')
|
||||
{
|
||||
break;
|
||||
} else
|
||||
{
|
||||
throw syntaxError("Missing ';' in XML entity: &" + sb);
|
||||
}
|
||||
}
|
||||
String string = sb.toString();
|
||||
Object object = entity.get(string);
|
||||
return object != null ? object : ampersand + string + ";";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next XML meta token. This is used for skipping over
|
||||
* <!...> and <?...?> structures.
|
||||
*
|
||||
* @return Syntax characters (<code>< > / = ! ?</code>) are returned as
|
||||
* Character, and strings and names are returned as Boolean. We
|
||||
* don't care what the values actually are.
|
||||
* @throws JSONException
|
||||
* If a string is not properly closed or if the XML is badly
|
||||
* structured.
|
||||
*/
|
||||
public Object nextMeta() throws JSONException
|
||||
{
|
||||
char c;
|
||||
char q;
|
||||
do
|
||||
{
|
||||
c = next();
|
||||
} while(Character.isWhitespace(c));
|
||||
switch(c)
|
||||
{
|
||||
case 0:
|
||||
throw syntaxError("Misshaped meta tag");
|
||||
case '<':
|
||||
return XML.LT;
|
||||
case '>':
|
||||
return XML.GT;
|
||||
case '/':
|
||||
return XML.SLASH;
|
||||
case '=':
|
||||
return XML.EQ;
|
||||
case '!':
|
||||
return XML.BANG;
|
||||
case '?':
|
||||
return XML.QUEST;
|
||||
case '"':
|
||||
case '\'':
|
||||
q = c;
|
||||
for(;;)
|
||||
{
|
||||
c = next();
|
||||
if(c == 0)
|
||||
{
|
||||
throw syntaxError("Unterminated string");
|
||||
}
|
||||
if(c == q)
|
||||
{
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
}
|
||||
default:
|
||||
for(;;)
|
||||
{
|
||||
c = next();
|
||||
if(Character.isWhitespace(c))
|
||||
{
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
switch(c)
|
||||
{
|
||||
case 0:
|
||||
case '<':
|
||||
case '>':
|
||||
case '/':
|
||||
case '=':
|
||||
case '!':
|
||||
case '?':
|
||||
case '"':
|
||||
case '\'':
|
||||
back();
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next XML Token. These tokens are found inside of angle brackets.
|
||||
* It may be one of these characters: <code>/ > = ! ?</code> or it may be a
|
||||
* string wrapped in single quotes or double quotes, or it may be a name.
|
||||
*
|
||||
* @return a String or a Character.
|
||||
* @throws JSONException
|
||||
* If the XML is not well formed.
|
||||
*/
|
||||
public Object nextToken() throws JSONException
|
||||
{
|
||||
char c;
|
||||
char q;
|
||||
StringBuilder sb;
|
||||
do
|
||||
{
|
||||
c = next();
|
||||
} while(Character.isWhitespace(c));
|
||||
switch(c)
|
||||
{
|
||||
case 0:
|
||||
throw syntaxError("Misshaped element");
|
||||
case '<':
|
||||
throw syntaxError("Misplaced '<'");
|
||||
case '>':
|
||||
return XML.GT;
|
||||
case '/':
|
||||
return XML.SLASH;
|
||||
case '=':
|
||||
return XML.EQ;
|
||||
case '!':
|
||||
return XML.BANG;
|
||||
case '?':
|
||||
return XML.QUEST;
|
||||
|
||||
// Quoted string
|
||||
|
||||
case '"':
|
||||
case '\'':
|
||||
q = c;
|
||||
sb = new StringBuilder();
|
||||
for(;;)
|
||||
{
|
||||
c = next();
|
||||
if(c == 0)
|
||||
{
|
||||
throw syntaxError("Unterminated string");
|
||||
}
|
||||
if(c == q)
|
||||
{
|
||||
return sb.toString();
|
||||
}
|
||||
if(c == '&')
|
||||
{
|
||||
sb.append(nextEntity(c));
|
||||
} else
|
||||
{
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
default:
|
||||
|
||||
// Name
|
||||
|
||||
sb = new StringBuilder();
|
||||
for(;;)
|
||||
{
|
||||
sb.append(c);
|
||||
c = next();
|
||||
if(Character.isWhitespace(c))
|
||||
{
|
||||
return sb.toString();
|
||||
}
|
||||
switch(c)
|
||||
{
|
||||
case 0:
|
||||
return sb.toString();
|
||||
case '>':
|
||||
case '/':
|
||||
case '=':
|
||||
case '!':
|
||||
case '?':
|
||||
case '[':
|
||||
case ']':
|
||||
back();
|
||||
return sb.toString();
|
||||
case '<':
|
||||
case '"':
|
||||
case '\'':
|
||||
throw syntaxError("Bad character in a name");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip characters until past the requested string. If it is not found, we
|
||||
* are left at the end of the source with a result of false.
|
||||
*
|
||||
* @param to
|
||||
* A string to skip past.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public boolean skipPast(String to) throws JSONException
|
||||
{
|
||||
boolean b;
|
||||
char c;
|
||||
int i;
|
||||
int j;
|
||||
int offset = 0;
|
||||
int length = to.length();
|
||||
char[] circle = new char[length];
|
||||
|
||||
/*
|
||||
* First fill the circle buffer with as many characters as are in the to
|
||||
* string. If we reach an early end, bail.
|
||||
*/
|
||||
|
||||
for(i = 0; i < length; i += 1)
|
||||
{
|
||||
c = next();
|
||||
if(c == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
circle[i] = c;
|
||||
}
|
||||
|
||||
/* We will loop, possibly for all of the remaining characters. */
|
||||
|
||||
for(;;)
|
||||
{
|
||||
j = offset;
|
||||
b = true;
|
||||
|
||||
/* Compare the circle buffer with the to string. */
|
||||
|
||||
for(i = 0; i < length; i += 1)
|
||||
{
|
||||
if(circle[j] != to.charAt(i))
|
||||
{
|
||||
b = false;
|
||||
break;
|
||||
}
|
||||
j += 1;
|
||||
if(j >= length)
|
||||
{
|
||||
j -= length;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we exit the loop with b intact, then victory is ours. */
|
||||
|
||||
if(b)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the next character. If there isn't one, then defeat is ours.
|
||||
*/
|
||||
|
||||
c = next();
|
||||
if(c == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
/*
|
||||
* Shove the character in the circle buffer and advance the circle
|
||||
* offset. The offset is mod n.
|
||||
*/
|
||||
circle[offset] = c;
|
||||
offset += 1;
|
||||
if(offset >= length)
|
||||
{
|
||||
offset -= length;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -2,5 +2,7 @@ name: ${project.name}
|
||||
version: ${project.version}
|
||||
main: ninja.bytecode.iris.Iris
|
||||
load: STARTUP
|
||||
commands:
|
||||
iris:
|
||||
api-version: 1.15
|
||||
hotload-dependencies: false
|
Loading…
x
Reference in New Issue
Block a user