Parallax Object Generation

This commit is contained in:
Daniel Mills 2020-01-20 14:38:07 -05:00
parent fd561cd45d
commit a4b571ccbc
42 changed files with 3190 additions and 297 deletions

View File

@ -9,7 +9,7 @@ public class Settings
public static class PerformanceSettings
{
public PerformanceMode performanceMode = PerformanceMode.UNLIMITED;
public PerformanceMode performanceMode = PerformanceMode.HALF_CPU;
public boolean fastDecoration = true;
public int threadPriority = Thread.MAX_PRIORITY;
public int threadCount = 4;
@ -17,6 +17,7 @@ public class Settings
public int decorationAccuracy = 2;
public boolean interpolation = true;
public boolean surfaceNoise = true;
public boolean noObjectFail = false;
public boolean verbose = false;
public int placeHistoryLimit = 8192;
}
@ -37,7 +38,7 @@ public class Settings
public double heightScale = 0.56;
public double baseHeight = 0.065;
public int seaLevel = 63;
public double caveDensity = 4;
public double caveDensity = 5;
public double caveScale = 1.45;
public double biomeScale = 0.65;
public boolean flatBedrock = true;

View File

@ -20,13 +20,16 @@ public class ExecutionController implements IrisController
@Override
public void onStop()
{
for(TaskExecutor i : executors.v())
{
i.close();
}
}
public TaskExecutor getExecutor(World world)
public TaskExecutor getExecutor(World world, String f)
{
TaskExecutor x = new TaskExecutor(getTC(), Iris.settings.performance.threadPriority, "Iris Generator (" + world.getName() + ")");
executors.put(world.getWorldFolder().getAbsolutePath() + " (" + world + ")", x);
TaskExecutor x = new TaskExecutor(getTC(), Iris.settings.performance.threadPriority, "Iris " + f);
executors.put(world.getWorldFolder().getAbsolutePath() + " (" + world + ") " + f, x);
return x;
}

View File

@ -142,6 +142,7 @@ public class PackController implements IrisController
for(String i : compiledDimensions.k())
{
CompiledDimension d = compiledDimensions.get(i);
d.computeObjectSize();
L.i(ChatColor.GREEN + i + ChatColor.WHITE + " (" + d.getEnvironment().toString().toLowerCase() + ")");
L.i(ChatColor.DARK_GREEN + " Biomes: " + ChatColor.GRAY + F.f(d.getBiomes().size()));
L.i(ChatColor.DARK_GREEN + " Objects: " + ChatColor.GRAY + F.f(d.countObjects()));

View File

@ -1,13 +1,11 @@
package ninja.bytecode.iris.generator;
import java.util.List;
import java.util.Random;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.generator.BlockPopulator;
import org.bukkit.util.NumberConversions;
import mortar.util.text.C;
@ -30,14 +28,15 @@ import ninja.bytecode.iris.util.AtomicChunkData;
import ninja.bytecode.iris.util.ChunkPlan;
import ninja.bytecode.iris.util.IrisInterpolation;
import ninja.bytecode.iris.util.MB;
import ninja.bytecode.iris.util.ParallelChunkGenerator;
import ninja.bytecode.iris.util.ParallaxWorldGenerator;
import ninja.bytecode.iris.util.SChunkVector;
import ninja.bytecode.shuriken.collections.GList;
import ninja.bytecode.shuriken.logging.L;
import ninja.bytecode.shuriken.math.CNG;
import ninja.bytecode.shuriken.math.M;
import ninja.bytecode.shuriken.math.RNG;
public class IrisGenerator extends ParallelChunkGenerator
public class IrisGenerator extends ParallaxWorldGenerator
{
//@builder
public static final GList<MB> ROCK = new GList<MB>().add(new MB[] {
@ -75,7 +74,6 @@ public class IrisGenerator extends ParallelChunkGenerator
private GenLayerCliffs glCliffs;
private RNG rTerrain;
private CompiledDimension dim;
private World world;
public IrisGenerator()
{
@ -113,7 +111,6 @@ public class IrisGenerator extends ParallelChunkGenerator
}
//@builder
this.world = world;
rTerrain = new RNG(world.getSeed());
glLNoise = new GenLayerLayeredNoise(this, world, random, rTerrain.nextParallelRNG(2));
glBiome = new GenLayerBiome(this, world, random, rTerrain.nextParallelRNG(4), dim.getBiomes());
@ -124,6 +121,7 @@ public class IrisGenerator extends ParallelChunkGenerator
glCliffs = new GenLayerCliffs(this, world, random, rTerrain.nextParallelRNG(9));
scatterCache = new double[16][][];
scatter = new CNG(rTerrain.nextParallelRNG(52), 1, 1).scale(10);
god = new GenObjectDecorator(this);
//@done
for(int i = 0; i < 16; i++)
{
@ -242,11 +240,25 @@ public class IrisGenerator extends ParallelChunkGenerator
}
@Override
public Biome genColumn(int wxxf, int wzxf, int x, int z, ChunkPlan plan)
public void onGenParallax(int x, int z, Random random)
{
try
{
god.decorateParallax(x, z, random);
}
catch(Throwable e)
{
e.printStackTrace();
}
}
@Override
public Biome onGenColumn(int wxxf, int wzxf, int x, int z, ChunkPlan plan, AtomicChunkData data)
{
if(disposed)
{
setBlock(x, 0, z, Material.MAGENTA_GLAZED_TERRACOTTA);
data.setBlock(x, 0, z, Material.MAGENTA_GLAZED_TERRACOTTA);
return Biome.VOID;
}
@ -296,7 +308,7 @@ public class IrisGenerator extends ParallelChunkGenerator
for(int j = 0; j < snowHeight; j++)
{
highest = j == snowHeight - 1 ? highest < j ? j : highest : highest < j + 1 ? j + 1 : highest;
setBlock(x, i + j + 1, z, j == snowHeight - 1 ? Material.SNOW : Material.SNOW_BLOCK, j == snowHeight - 1 ? (byte) layers : (byte) 0);
data.setBlock(x, i + j + 1, z, j == snowHeight - 1 ? Material.SNOW : Material.SNOW_BLOCK, j == snowHeight - 1 ? (byte) layers : (byte) 0);
}
}
@ -307,24 +319,24 @@ public class IrisGenerator extends ParallelChunkGenerator
if(!mbx.material.equals(Material.AIR))
{
highest = i > highest ? i : highest;
setBlock(x, i + 1, z, mbx.material, mbx.data);
data.setBlock(x, i + 1, z, mbx.material, mbx.data);
}
}
}
highest = i > highest ? i : highest;
setBlock(x, i, z, mb.material, mb.data);
data.setBlock(x, i, z, mb.material, mb.data);
}
glCaves.genCaves(wxx, wzx, x, z, height, this);
glCarving.genCarves(wxx, wzx, x, z, height, this, biome);
glCaverns.genCaverns(wxx, wzx, x, z, height, this, biome);
glCaves.genCaves(wxx, wzx, x, z, height, this, data);
glCarving.genCarves(wxx, wzx, x, z, height, this, biome, data);
glCaverns.genCaverns(wxx, wzx, x, z, height, this, biome, data);
int hw = 0;
int hl = 0;
for(int i = highest; i > 0; i--)
{
Material t = getType(x, i, z);
Material t = data.getType(x, i, z);
hw = i > seaLevel && hw == 0 && (t.equals(Material.WATER) || t.equals(Material.STATIONARY_WATER)) ? i : hw;
hl = hl == 0 && !t.equals(Material.AIR) ? i : hl;
}
@ -336,31 +348,12 @@ public class IrisGenerator extends ParallelChunkGenerator
return biome.getRealBiome();
}
@Override
public void decorateColumn(int wx, int wz, int x, int z, ChunkPlan plan)
{
}
@Override
public void onPostChunk(World world, int x, int z, Random random, AtomicChunkData data, ChunkPlan plan)
{
}
@Override
public List<BlockPopulator> getDefaultPopulators(World world)
{
GList<BlockPopulator> p = new GList<>();
if(Iris.settings.gen.genObjects)
{
p.add(god = new GenObjectDecorator(this));
}
return p;
}
private double getBiomedHeight(int x, int z, ChunkPlan plan)
{
double xh = plan.getHeight(x, z);
@ -377,11 +370,6 @@ public class IrisGenerator extends ParallelChunkGenerator
return xh;
}
public World getWorld()
{
return world;
}
public RNG getRTerrain()
{
return rTerrain;
@ -398,7 +386,7 @@ public class IrisGenerator extends ParallelChunkGenerator
{
return;
}
L.w(C.YELLOW + "Disposed Iris World " + C.RED + world.getName());
L.w(C.YELLOW + "Disposed Iris World " + C.RED + getWorld().getName());
disposed = true;
dim = null;
glLNoise = null;
@ -407,6 +395,7 @@ public class IrisGenerator extends ParallelChunkGenerator
glCaverns = null;
glSnow = null;
glCliffs = null;
god.dispose();
}
public boolean isDisposed()
@ -439,4 +428,16 @@ public class IrisGenerator extends ParallelChunkGenerator
{
return god.randomObject(string);
}
@Override
protected SChunkVector getParallaxSize()
{
return dim.getMaxChunkSize();
}
@Override
protected void onUnload()
{
dispose();
}
}

View File

@ -98,7 +98,7 @@ public class GenObject
}
mountHeight = avg(avy);
mount = new BlockVector(avg(avx), 0, avg(avz));
mount = new BlockVector(0, 0, 0);
}
private int avg(double[] v)
@ -255,7 +255,7 @@ public class GenObject
public Location place(int wx, int wy, int wz, IPlacer placer)
{
Location start = new Location(placer.getWorld(), wx, wy, wz).clone().add(sh(w), sh(h) + 1, sh(d));
Location start = new Location(placer.getWorld(), wx, wy, wz).clone().add(0, sh(h) + 1, 0);
if(mount == null)
{
@ -279,7 +279,10 @@ public class GenObject
MB b = getSchematic().get(i);
Location f = start.clone().add(i.toBlockVector());
if(!Iris.settings.performance.noObjectFail)
{
Material m = placer.get(f.clone().subtract(0, 1, 0)).material;
if(i.getY() == mountHeight && (m.equals(Material.WATER) || m.equals(Material.STATIONARY_WATER) || m.equals(Material.LAVA) || m.equals(Material.STATIONARY_LAVA)))
{
for(Location j : undo.k())
@ -295,6 +298,7 @@ public class GenObject
failures++;
return null;
}
}
try
{

View File

@ -2,41 +2,34 @@ package ninja.bytecode.iris.generator.genobject;
import java.util.Collections;
import java.util.Random;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.generator.BlockPopulator;
import mortar.logic.format.F;
import mortar.util.text.C;
import net.md_5.bungee.api.ChatColor;
import ninja.bytecode.iris.Iris;
import ninja.bytecode.iris.generator.IrisGenerator;
import ninja.bytecode.iris.generator.placer.BukkitPlacer;
import ninja.bytecode.iris.generator.placer.NMSPlacer;
import ninja.bytecode.iris.generator.placer.AtomicParallaxPlacer;
import ninja.bytecode.iris.pack.IrisBiome;
import ninja.bytecode.iris.util.IPlacer;
import ninja.bytecode.iris.util.MB;
import ninja.bytecode.iris.util.ParallaxCache;
import ninja.bytecode.iris.util.SMCAVector;
import ninja.bytecode.shuriken.collections.GList;
import ninja.bytecode.shuriken.collections.GMap;
import ninja.bytecode.shuriken.collections.GSet;
import ninja.bytecode.shuriken.execution.ChronoLatch;
import ninja.bytecode.shuriken.logging.L;
import ninja.bytecode.shuriken.math.M;
import ninja.bytecode.shuriken.math.RNG;
public class GenObjectDecorator extends BlockPopulator
public class GenObjectDecorator
{
private GList<PlacedObject> placeHistory;
private GMap<IrisBiome, GList<GenObjectGroup>> orderCache;
private GMap<IrisBiome, GMap<GenObjectGroup, Double>> populationCache;
private IPlacer placer;
private Executor ex;
private IrisGenerator g;
private ChronoLatch cl = new ChronoLatch(250);
@ -46,7 +39,6 @@ public class GenObjectDecorator extends BlockPopulator
placeHistory = new GList<>();
populationCache = new GMap<>();
orderCache = new GMap<>();
ex = Executors.newSingleThreadExecutor();
for(IrisBiome i : generator.getDimension().getBiomes())
{
@ -100,8 +92,9 @@ public class GenObjectDecorator extends BlockPopulator
L.i("Population Cache is " + populationCache.size());
}
@Override
public void populate(World world, Random rnotusingyou, Chunk source)
public void decorateParallax(int cx, int cz, Random random)
{
try
{
if(g.isDisposed())
{
@ -109,16 +102,14 @@ public class GenObjectDecorator extends BlockPopulator
return;
}
ex.execute(() ->
{
Random random = new Random(((source.getX() - 32) * (source.getZ() + 54)) + world.getSeed());
ParallaxCache cache = new ParallaxCache(g);
GSet<IrisBiome> hits = new GSet<>();
for(int i = 0; i < Iris.settings.performance.decorationAccuracy; i++)
{
int x = (source.getX() << 4) + random.nextInt(16);
int z = (source.getZ() << 4) + random.nextInt(16);
IrisBiome biome = g.getBiome((int) g.getOffsetX(x), (int) g.getOffsetX(z));
int x = (cx << 4) + random.nextInt(16);
int z = (cz << 4) + random.nextInt(16);
IrisBiome biome = cache.getBiome(x, z);
if(hits.contains(biome))
{
@ -133,20 +124,19 @@ public class GenObjectDecorator extends BlockPopulator
}
hits.add(biome);
populate(world, random, source, biome, orderCache.get(biome));
populate(cx, cz, random, biome, cache);
}
}
if(Iris.settings.performance.verbose)
catch(Throwable e)
{
L.flush();
e.printStackTrace();
}
});
}
private void populate(World world, Random random, Chunk source, IrisBiome biome, GList<GenObjectGroup> order)
private void populate(int cx, int cz, Random random, IrisBiome biome, ParallaxCache cache)
{
for(GenObjectGroup i : order)
for(GenObjectGroup i : orderCache.get(biome))
{
if(biome.getSchematicGroups().get(i.getName()) == null)
{
@ -158,49 +148,55 @@ public class GenObjectDecorator extends BlockPopulator
{
if(M.r(Iris.settings.gen.objectDensity))
{
int x = (source.getX() << 4) + random.nextInt(16);
int z = (source.getZ() << 4) + random.nextInt(16);
Block b = world.getHighestBlockAt(x, z).getRelative(BlockFace.DOWN);
Material t = b.getType();
GenObject go = i.getSchematics().get(random.nextInt(i.getSchematics().size()));
int x = (cx << 4) + random.nextInt(16);
int z = (cz << 4) + random.nextInt(16);
if(!t.isSolid() || !biome.isSurface(t))
if(i.getWorldChance() >= 0D)
{
int rngx = (int) Math.floor(x / (double) (i.getWorldRadius() == 0 ? 32 : i.getWorldRadius()));
int rngz = (int) Math.floor(z / (double) (i.getWorldRadius() == 0 ? 32 : i.getWorldRadius()));
if(new RNG(new SMCAVector(rngx, rngz).hashCode()).nextDouble() < i.getWorldChance())
{
if(Iris.settings.performance.verbose)
{
L.w(C.WHITE + "Object " + C.YELLOW + i.getName() + "/*" + C.WHITE + " failed to place in " + C.YELLOW + t.toString().toLowerCase() + C.WHITE + " at " + C.YELLOW + F.f(b.getX()) + " " + F.f(b.getY()) + " " + F.f(b.getZ()));
L.w(C.WHITE + "Object " + C.YELLOW + i.getName() + "/*" + C.WHITE + " failed to place due to a world chance.");
}
continue;
}
if(placer == null)
{
if(Iris.settings.performance.fastDecoration)
{
placer = new NMSPlacer(world);
}
else
{
placer = new BukkitPlacer(world, false);
break;
}
}
GenObject g = i.getSchematics().get(random.nextInt(i.getSchematics().size()));
Bukkit.getScheduler().scheduleSyncDelayedTask(Iris.instance, () ->
int by = cache.getHeight(x, z);
MB mb = cache.get(x, by, z);
if(!Iris.settings.performance.noObjectFail)
{
Location start = g.place(x, b.getY(), z, placer);
if(!mb.material.isSolid() || !biome.isSurface(mb.material))
{
if(Iris.settings.performance.verbose)
{
L.w(C.WHITE + "Object " + C.YELLOW + i.getName() + "/*" + C.WHITE + " failed to place in " + C.YELLOW + mb.material.toString().toLowerCase() + C.WHITE + " at " + C.YELLOW + F.f(x) + " " + F.f(by) + " " + F.f(z));
}
return;
}
}
placer = new AtomicParallaxPlacer(g, cache);
Location start = go.place(x, by, z, placer);
if(start != null)
{
if(Iris.settings.performance.verbose)
{
L.v(C.GRAY + "Placed " + C.DARK_GREEN + i.getName() + C.WHITE + "/" + C.DARK_GREEN + g.getName() + C.GRAY + " at " + C.DARK_GREEN + F.f(start.getBlockX()) + " " + F.f(start.getBlockY()) + " " + F.f(start.getBlockZ()));
L.v(C.GRAY + "Placed " + C.DARK_GREEN + i.getName() + C.WHITE + "/" + C.DARK_GREEN + go.getName() + C.GRAY + " at " + C.DARK_GREEN + F.f(start.getBlockX()) + " " + F.f(start.getBlockY()) + " " + F.f(start.getBlockZ()));
}
if(Iris.settings.performance.debugMode)
{
placeHistory.add(new PlacedObject(start.getBlockX(), start.getBlockY(), start.getBlockZ(), i.getName() + ":" + g.getName()));
placeHistory.add(new PlacedObject(start.getBlockX(), start.getBlockY(), start.getBlockZ(), i.getName() + ":" + go.getName()));
if(placeHistory.size() > Iris.settings.performance.placeHistoryLimit)
{
@ -211,7 +207,6 @@ public class GenObjectDecorator extends BlockPopulator
}
}
}
});
}
}
}
@ -249,6 +244,11 @@ public class GenObjectDecorator extends BlockPopulator
return placeHistory;
}
public void dispose()
{
}
public PlacedObject randomObject(String string)
{
GList<PlacedObject> v = new GList<>();

View File

@ -21,6 +21,8 @@ public class GenObjectGroup
private GList<String> flags;
private String name;
private int priority;
private double worldChance;
private int worldRad;
public GenObjectGroup(String name)
{
@ -28,6 +30,8 @@ public class GenObjectGroup
this.flags = new GList<>();
this.name = name;
priority = Integer.MIN_VALUE;
worldChance = Integer.MIN_VALUE;
worldRad = 32;
}
public void read(DataInputStream din) throws IOException
@ -295,4 +299,36 @@ public class GenObjectGroup
return true;
}
public double getWorldChance()
{
if(worldChance == Integer.MIN_VALUE)
{
for(String i : flags)
{
if(i.startsWith("world chance "))
{
worldChance = Double.valueOf(i.split("\\Q \\E")[2]);
}
}
}
return worldChance;
}
public double getWorldRadius()
{
if(worldRad == Integer.MIN_VALUE)
{
for(String i : flags)
{
if(i.startsWith("world radius "))
{
worldRad = Integer.valueOf(i.split("\\Q \\E")[2]);
}
}
}
return worldRad;
}
}

View File

@ -8,6 +8,7 @@ import org.bukkit.World;
import ninja.bytecode.iris.Iris;
import ninja.bytecode.iris.generator.IrisGenerator;
import ninja.bytecode.iris.pack.IrisBiome;
import ninja.bytecode.iris.util.AtomicChunkData;
import ninja.bytecode.iris.util.GenLayer;
import ninja.bytecode.iris.util.IrisInterpolation;
import ninja.bytecode.iris.util.MB;
@ -68,7 +69,7 @@ public class GenLayerCarving extends GenLayer
return carver.noise(x + fx, y - fy, z + fz);
}
public void genCarves(double wxx, double wzx, int x, int z, int s, IrisGenerator g, IrisBiome biome)
public void genCarves(double wxx, double wzx, int x, int z, int s, IrisGenerator g, IrisBiome biome, AtomicChunkData data)
{
if(!Iris.settings.gen.genCarving)
{
@ -103,7 +104,7 @@ public class GenLayerCarving extends GenLayer
if(carve(wxx, i, wzx) < IrisInterpolation.lerpBezier(0, ch, hill))
{
carved++;
g.setBlock(x, i, z, Material.AIR);
data.setBlock(x, i, z, Material.AIR);
}
}
@ -113,7 +114,7 @@ public class GenLayerCarving extends GenLayer
for(int i = Iris.settings.gen.maxCarvingHeight; i > Iris.settings.gen.minCarvingHeight; i--)
{
Material m = g.getType(x, i, z);
Material m = data.getType(x, i, z);
if(!m.equals(Material.AIR))
{
hit++;
@ -126,7 +127,7 @@ public class GenLayerCarving extends GenLayer
{
for(int j = i; j > i - 5; j--)
{
if(g.getType(x, j, z).equals(Material.AIR))
if(data.getType(x, j, z).equals(Material.AIR))
{
fail = true;
break;
@ -137,12 +138,12 @@ public class GenLayerCarving extends GenLayer
if(!fail)
{
MB mb = biome.getSurface(wxx, wzx, g.getRTerrain());
g.setBlock(x, i, z, mb.material, mb.data);
data.setBlock(x, i, z, mb.material, mb.data);
}
else
{
g.setBlock(x, i, z, Material.AIR);
data.setBlock(x, i, z, Material.AIR);
}
}
@ -151,12 +152,12 @@ public class GenLayerCarving extends GenLayer
if(!fail)
{
MB mb = biome.getSubSurface(wxx, i, wzx, g.getRTerrain());
g.setBlock(x, i, z, mb.material, mb.data);
data.setBlock(x, i, z, mb.material, mb.data);
}
else
{
g.setBlock(x, i, z, Material.AIR);
data.setBlock(x, i, z, Material.AIR);
}
}
}

View File

@ -8,6 +8,7 @@ import org.bukkit.World;
import ninja.bytecode.iris.Iris;
import ninja.bytecode.iris.generator.IrisGenerator;
import ninja.bytecode.iris.pack.IrisBiome;
import ninja.bytecode.iris.util.AtomicChunkData;
import ninja.bytecode.iris.util.GenLayer;
import ninja.bytecode.iris.util.IrisInterpolation;
import ninja.bytecode.iris.util.MB;
@ -68,7 +69,7 @@ public class GenLayerCaverns extends GenLayer
return carver.noise(x + fx, y - fy, z + fz);
}
public void genCaverns(double wxx, double wzx, int x, int z, int s, IrisGenerator g, IrisBiome biome)
public void genCaverns(double wxx, double wzx, int x, int z, int s, IrisGenerator g, IrisBiome biome, AtomicChunkData data)
{
if(!Iris.settings.gen.genCaverns)
{
@ -103,7 +104,7 @@ public class GenLayerCaverns extends GenLayer
if(cavern(wxx, i, wzx) < IrisInterpolation.lerpBezier(0, ch, hill))
{
carved++;
g.setBlock(x, i, z, Material.AIR);
data.setBlock(x, i, z, Material.AIR);
}
}
@ -113,7 +114,7 @@ public class GenLayerCaverns extends GenLayer
for(int i = Iris.settings.gen.maxCavernHeight; i > Iris.settings.gen.minCavernHeight; i--)
{
Material m = g.getType(x, i, z);
Material m = data.getType(x, i, z);
if(!m.equals(Material.AIR))
{
hit++;
@ -126,7 +127,7 @@ public class GenLayerCaverns extends GenLayer
{
for(int j = i; j > i - 5; j--)
{
if(g.getType(x, j, z).equals(Material.AIR))
if(data.getType(x, j, z).equals(Material.AIR))
{
fail = true;
break;
@ -137,12 +138,12 @@ public class GenLayerCaverns extends GenLayer
if(!fail)
{
MB mb = biome.getSurface(wxx, wzx, g.getRTerrain());
g.setBlock(x, i, z, mb.material, mb.data);
data.setBlock(x, i, z, mb.material, mb.data);
}
else
{
g.setBlock(x, i, z, Material.AIR);
data.setBlock(x, i, z, Material.AIR);
}
}
@ -151,12 +152,12 @@ public class GenLayerCaverns extends GenLayer
if(!fail)
{
MB mb = biome.getSubSurface(wxx, i, wzx, g.getRTerrain());
g.setBlock(x, i, z, mb.material, mb.data);
data.setBlock(x, i, z, mb.material, mb.data);
}
else
{
g.setBlock(x, i, z, Material.AIR);
data.setBlock(x, i, z, Material.AIR);
}
}
}

View File

@ -7,6 +7,7 @@ import org.bukkit.World;
import ninja.bytecode.iris.Iris;
import ninja.bytecode.iris.generator.IrisGenerator;
import ninja.bytecode.iris.util.AtomicChunkData;
import ninja.bytecode.iris.util.GenLayer;
import ninja.bytecode.iris.util.PolygonGenerator;
import ninja.bytecode.shuriken.math.CNG;
@ -28,7 +29,7 @@ public class GenLayerCaves extends GenLayer
caveVeins = new PolygonGenerator(rng.nextParallelRNG(-99999), 4, 0.002 * Iris.settings.gen.caveScale, 1, (g) -> g.fractureWith(new CNG(rng.nextParallelRNG(-5555), 1D, 4).scale(0.02), 70));
}
public void genCaves(double wxx, double wzx, int x, int z, int s, IrisGenerator g)
public void genCaves(double wxx, double wzx, int x, int z, int s, IrisGenerator g, AtomicChunkData data)
{
if(!Iris.settings.gen.genCaves)
{
@ -38,36 +39,36 @@ public class GenLayerCaves extends GenLayer
for(double itr = 0; itr < 0.1 * Iris.settings.gen.caveDensity; itr += 0.1)
{
double thickness = 0.25 + itr + (0.5 * caveClamp.noise(wxx, wzx));
double size = 3.88D * thickness;
double size = (3.88D * thickness);
double variance = 8.34D * thickness;
double w = size + (variance * caveGirth.noise(wxx, wzx));
double h = size + (variance * caveGirth.noise(wzx, wxx));
double width = 0;
double height = h;
double elevation = (caveHeight.noise(wxx + (19949D * itr), wzx - (19949D * itr)) * (350)) - 80;
while(width <= w && height > 1D)
{
width+=2;
height-=2;
width += 2;
height -= 2;
if(caveVeins.hasBorder(3, width, wxx - (19949D * itr), wzx + (19949D * itr)))
{
double r = (((caveGirth.noise(wxx, wzx, width)) * variance) + height) / 2D;
int f = 3;
for(int i = (int) -r; i < r && f >= 0; i++)
for(int i = (int) -r; i < r; i++)
{
if(i + height > s)
{
break;
}
Material t = g.getType(x, (int) (elevation + i) - 55, z);
Material t = data.getType(x, (int) (elevation + i) - 55, z);
if(t.equals(Material.BEDROCK) || t.equals(Material.WATER) || t.equals(Material.STATIONARY_WATER))
{
continue;
}
g.setBlock(x, (int) (elevation + i) - 55, z, Material.AIR);
data.setBlock(x, (int) (elevation + i) - 55, z, Material.AIR);
}
}
}

View File

@ -0,0 +1,41 @@
package ninja.bytecode.iris.generator.placer;
import org.bukkit.Location;
import ninja.bytecode.iris.generator.IrisGenerator;
import ninja.bytecode.iris.util.IrisWorldData;
import ninja.bytecode.iris.util.MB;
import ninja.bytecode.iris.util.ParallaxCache;
import ninja.bytecode.iris.util.Placer;
public class AtomicParallaxPlacer extends Placer
{
private IrisWorldData data;
private ParallaxCache cache;
public AtomicParallaxPlacer(IrisGenerator g, ParallaxCache cache)
{
super(g.getWorld());
this.data = g.getWorldData();
this.cache = cache;
}
@Override
public MB get(Location l)
{
return cache.get(l.getBlockX(), l.getBlockY(), l.getBlockZ());
}
@SuppressWarnings("deprecation")
@Override
public void set(Location l, MB mb)
{
data.setBlock(l.getBlockX(), l.getBlockY(), l.getBlockZ(), mb.material.getId(), mb.data);
}
@Override
public int getHighestY(Location l)
{
return cache.getHeight(l.getBlockX(), l.getBlockZ());
}
}

View File

@ -1,45 +0,0 @@
package ninja.bytecode.iris.generator.placer;
import org.bukkit.Location;
import org.bukkit.World;
import ninja.bytecode.iris.util.AtomicChunkData;
import ninja.bytecode.iris.util.ChunkPlan;
import ninja.bytecode.iris.util.MB;
import ninja.bytecode.iris.util.Placer;
public class AtomicPlacer extends Placer
{
private AtomicChunkData data;
private ChunkPlan plan;
public AtomicPlacer(World world)
{
super(world);
}
public void bind(AtomicChunkData data, ChunkPlan plan)
{
this.data = data;
this.plan = plan;
}
@Override
public MB get(Location l)
{
return MB.of(data.getType(l.getBlockX(), l.getBlockY(), l.getBlockZ()), data.getData(l.getBlockX(), l.getBlockY(), l.getBlockZ()));
}
@SuppressWarnings("deprecation")
@Override
public void set(Location l, MB mb)
{
data.setBlock(l.getBlockX(), l.getBlockY(), l.getBlockZ(), mb.material.getId(), mb.data);
}
@Override
public int getHighestY(Location l)
{
return plan.getRealHeight(l.getBlockX(), l.getBlockZ());
}
}

View File

@ -13,7 +13,10 @@ import org.bukkit.World.Environment;
import org.bukkit.block.Biome;
import net.md_5.bungee.api.ChatColor;
import ninja.bytecode.iris.generator.genobject.GenObject;
import ninja.bytecode.iris.generator.genobject.GenObjectGroup;
import ninja.bytecode.iris.util.SChunkVector;
import ninja.bytecode.iris.util.SBlockVector;
import ninja.bytecode.shuriken.collections.GList;
import ninja.bytecode.shuriken.collections.GMap;
import ninja.bytecode.shuriken.io.CustomOutputStream;
@ -29,6 +32,8 @@ public class CompiledDimension
private GList<IrisBiome> biomes;
private GMap<String, IrisBiome> biomeCache;
private GMap<String, GenObjectGroup> objects;
private SBlockVector maxSize;
private SChunkVector maxChunkSize;
public CompiledDimension(IrisDimension dimension)
{
@ -36,6 +41,8 @@ public class CompiledDimension
biomes = new GList<>();
biomeCache = new GMap<>();
objects = new GMap<>();
maxSize = new SBlockVector(0, 0, 0);
maxChunkSize = new SChunkVector(0, 0);
}
public void read(InputStream in) throws IOException
@ -182,4 +189,56 @@ public class CompiledDimension
objects.clear();
}
public void computeObjectSize()
{
int maxWidth = 0;
int maxHeight = 0;
int maxDepth = 0;
for(GenObjectGroup i : objects.values())
{
for(GenObject j : i.getSchematics().copy())
{
maxWidth = j.getW() > maxWidth ? j.getW() : maxWidth;
maxHeight = j.getH() > maxHeight ? j.getH() : maxHeight;
maxDepth = j.getD() > maxDepth ? j.getD() : maxDepth;
}
}
maxSize = new SBlockVector(maxWidth, maxHeight, maxDepth);
maxChunkSize = new SChunkVector(Math.ceil((double) (maxWidth) / 16D), Math.ceil((double) (maxDepth) / 16D));
L.i("Max Object Bound is " + maxWidth + ", " + maxHeight + ", " + maxDepth);
L.i("Max Object Region is " + maxChunkSize.getX() + " by " + maxChunkSize.getZ() + " Chunks");
}
public static IrisBiome getTheVoid()
{
return theVoid;
}
public IrisDimension getDimension()
{
return dimension;
}
public GMap<String, IrisBiome> getBiomeCache()
{
return biomeCache;
}
public GMap<String, GenObjectGroup> getObjects()
{
return objects;
}
public SBlockVector getMaxSize()
{
return maxSize;
}
public SChunkVector getMaxChunkSize()
{
return maxChunkSize;
}
}

View File

@ -1,5 +1,10 @@
package ninja.bytecode.iris.util;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.util.concurrent.locks.ReentrantLock;
@ -10,6 +15,8 @@ import org.bukkit.generator.ChunkGenerator;
import org.bukkit.generator.ChunkGenerator.ChunkData;
import org.bukkit.material.MaterialData;
import mortar.compute.math.M;
public final class AtomicChunkData implements ChunkGenerator.ChunkData
{
private static final Field t;
@ -35,11 +42,125 @@ public final class AtomicChunkData implements ChunkGenerator.ChunkData
private char[] s15;
private char[][] m;
private World w;
private long lastUse;
private int bits;
public AtomicChunkData(World world)
{
this.maxHeight = world.getMaxHeight();
this.w = world;
bits = 0;
lastUse = M.ms();
}
public long getTimeSinceLastUse()
{
return M.ms() - lastUse;
}
public void read(InputStream in) throws IOException
{
read(in, true);
}
public void read(InputStream in, boolean ignoreAir) throws IOException
{
DataInputStream din = new DataInputStream(in);
int bits = din.readInt();
for(int i = 0; i < 16; i++)
{
int bit = getBit(i);
if((bits & bit) == bit)
{
char[] section = getChunkSection(i << 4, true);
for(int j = 0; j < section.length; j++)
{
char c = din.readChar();
if(c == 0 && ignoreAir)
{
continue;
}
section[j] = c;
}
}
}
din.close();
}
public void write(OutputStream out) throws IOException
{
DataOutputStream dos = new DataOutputStream(out);
dos.writeInt(getDataBits());
for(int i = 0; i < 16; i++)
{
if(hasDataBit(i))
{
char[] section = getChunkSection(i << 4, false);
for(int j = 0; j < section.length; j++)
{
dos.writeChar(section[j]);
}
}
}
dos.close();
}
public boolean hasDataBit(int section)
{
int b = getBit(section);
return (bits & b) == b;
}
public void clearDataBits()
{
bits = 0;
}
public void addDataBit(int section)
{
bits |= getBit(section);
}
public void removeDataBit(int section)
{
bits ^= getBit(section);
}
public int getDataBits()
{
return bits;
}
public int getBit(int index)
{
return (int) (index < 0 ? -1 : Math.pow(2, index));
}
public int computeDataBits()
{
int bits = 0;
for(int i = 0; i < 16; i++)
{
try
{
bits |= sections[i].get(this) != null ? getBit(i) : 0;
}
catch(Throwable e)
{
}
}
return bits;
}
@Override
@ -80,6 +201,7 @@ public final class AtomicChunkData implements ChunkGenerator.ChunkData
@Override
public Material getType(int x, int y, int z)
{
lastUse = M.ms();
return Material.getMaterial(getTypeId(x, y, z));
}
@ -87,18 +209,27 @@ public final class AtomicChunkData implements ChunkGenerator.ChunkData
@Override
public MaterialData getTypeAndData(int x, int y, int z)
{
lastUse = M.ms();
return getType(x, y, z).getNewData(getData(x, y, z));
}
@SuppressWarnings("deprecation")
public void setBlock(int x, int y, int z, Material blockId, byte data)
{
setBlock(x, y, z, blockId.getId(), data);
}
@Override
public void setRegion(int xMin, int yMin, int zMin, int xMax, int yMax, int zMax, int blockId)
{
lastUse = M.ms();
setRegion(xMin, yMin, zMin, xMax, yMax, zMax, blockId, (byte) 0);
}
@Override
public void setRegion(int xMin, int yMin, int zMin, int xMax, int yMax, int zMax, int blockId, int data)
{
lastUse = M.ms();
throw new UnsupportedOperationException("AtomicChunkData does not support setting regions");
}
@ -114,6 +245,31 @@ public final class AtomicChunkData implements ChunkGenerator.ChunkData
setBlock(x, y, z, (char) (blockId << 4 | data));
}
@SuppressWarnings("deprecation")
public MB getMB(int x, int y, int z)
{
if(x != (x & 0xf) || y < 0 || y >= maxHeight || z != (z & 0xf))
{
lastUse = M.ms();
return MB.of(Material.AIR);
}
char[] section = getChunkSection(y, false);
if(section == null)
{
lastUse = M.ms();
return MB.of(Material.AIR);
}
else
{
lastUse = M.ms();
char xf = section[(y & 0xf) << 8 | z << 4 | x];
return MB.of(Material.getMaterial(xf >> 4), xf & 0xf);
}
}
@Override
public int getTypeId(int x, int y, int z)
{
@ -131,6 +287,7 @@ public final class AtomicChunkData implements ChunkGenerator.ChunkData
else
{
lastUse = M.ms();
return section[(y & 0xf) << 8 | z << 4 | x] >> 4;
}
}
@ -140,6 +297,7 @@ public final class AtomicChunkData implements ChunkGenerator.ChunkData
{
if(x != (x & 0xf) || y < 0 || y >= maxHeight || z != (z & 0xf))
{
lastUse = M.ms();
return (byte) 0;
}
@ -147,11 +305,13 @@ public final class AtomicChunkData implements ChunkGenerator.ChunkData
if(section == null)
{
lastUse = M.ms();
return (byte) 0;
}
else
{
lastUse = M.ms();
return (byte) (section[(y & 0xf) << 8 | z << 4 | x] & 0xf);
}
}
@ -163,6 +323,7 @@ public final class AtomicChunkData implements ChunkGenerator.ChunkData
return;
}
lastUse = M.ms();
ReentrantLock l = locks[y >> 4];
l.lock();
getChunkSection(y, true)[(y & 0xf) << 8 | z << 4 | x] = type;
@ -181,6 +342,7 @@ public final class AtomicChunkData implements ChunkGenerator.ChunkData
{
sf.set(this, new char[h]);
section = (char[]) sf.get(this);
addDataBit(s);
}
return section;
@ -263,4 +425,26 @@ public final class AtomicChunkData implements ChunkGenerator.ChunkData
t = x;
}
public void inject(AtomicChunkData data)
{
for(int i = 0; i < 16; i++)
{
if(hasDataBit(i))
{
char[] fromSection = getChunkSection(i << 4, false);
char[] toSection = data.getChunkSection(i << 4, true);
for(int j = 0; j < fromSection.length; j++)
{
char x = fromSection[j];
if(x != 0)
{
toSection[j] = x;
}
}
}
}
}
}

View File

@ -0,0 +1,80 @@
package ninja.bytecode.iris.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.bukkit.World;
import org.jnbt.ByteArrayTag;
import org.jnbt.CompoundTag;
import org.jnbt.NBTInputStream;
import org.jnbt.NBTOutputStream;
import org.jnbt.Tag;
import ninja.bytecode.shuriken.collections.GMap;
public class AtomicMCAData
{
private final World world;
private GMap<String, Tag> tag;
public AtomicMCAData(World world)
{
this.world = world;
tag = new GMap<>();
}
public void read(InputStream in) throws IOException
{
NBTInputStream nin = new NBTInputStream(in);
tag = new GMap<>();
tag.putAll(((CompoundTag) nin.readTag()).getValue());
nin.close();
}
public void write(OutputStream out) throws IOException
{
NBTOutputStream nos = new NBTOutputStream(out);
nos.writeTag(new CompoundTag("imca", tag));
nos.close();
}
public boolean contains(int rx, int rz)
{
return tag.containsKey(rx + "." + rz);
}
public void delete(int rx, int rz)
{
tag.remove(rx + "." + rz);
}
public void set(int rx, int rz, AtomicChunkData data) throws IOException
{
ByteArrayOutputStream boas = new ByteArrayOutputStream();
data.write(boas);
tag.put(rx + "." + rz, new ByteArrayTag(rx + "." + rz, boas.toByteArray()));
}
public AtomicChunkData get(int rx, int rz) throws IOException
{
if(!contains(rx, rz))
{
return null;
}
AtomicChunkData data = new AtomicChunkData(world);
ByteArrayTag btag = (ByteArrayTag) tag.get(rx + "." + rz);
ByteArrayInputStream in = new ByteArrayInputStream(btag.getValue());
data.read(in);
return data;
}
public World getWorld()
{
return world;
}
}

View File

@ -0,0 +1,157 @@
package ninja.bytecode.iris.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import org.bukkit.World;
import ninja.bytecode.shuriken.collections.GList;
import ninja.bytecode.shuriken.collections.GMap;
public class AtomicWorldData
{
private World world;
private GMap<SMCAVector, AtomicMCAData> loadedSections;
public AtomicWorldData(World world)
{
this.world = world;
loadedSections = new GMap<>();
getSubregionFolder().mkdirs();
}
public GList<SMCAVector> getLoadedRegions()
{
return loadedSections.k();
}
public AtomicMCAData getSubregion(int x, int z) throws IOException
{
if(!isSectionLoaded(x, z))
{
loadedSections.put(new SMCAVector(x, z), loadSection(x, z));
}
AtomicMCAData f = loadedSections.get(new SMCAVector(x, z));
return f;
}
public void saveAll() throws IOException
{
for(SMCAVector i : loadedSections.keySet())
{
saveSection(i);
}
}
public void unloadAll(boolean save) throws IOException
{
for(SMCAVector i : loadedSections.keySet())
{
unloadSection(i, save);
}
}
public void deleteSection(int x, int z) throws IOException
{
unloadSection(x, z, false);
getSubregionFile(x, z).delete();
}
public boolean isSectionLoaded(int x, int z)
{
return isSectionLoaded(new SMCAVector(x, z));
}
public boolean isSectionLoaded(SMCAVector s)
{
return loadedSections.containsKey(s);
}
public boolean unloadSection(int x, int z, boolean save) throws IOException
{
return unloadSection(new SMCAVector(x, z), save);
}
public boolean unloadSection(SMCAVector s, boolean save) throws IOException
{
if(!isSectionLoaded(s))
{
return false;
}
if(save)
{
saveSection(s);
}
loadedSections.remove(s);
return true;
}
public boolean saveSection(int x, int z) throws IOException
{
return saveSection(new SMCAVector(x, z));
}
public boolean saveSection(SMCAVector s) throws IOException
{
if(!isSectionLoaded(s.getX(), s.getZ()))
{
return false;
}
AtomicMCAData data = loadedSections.get(s);
FileOutputStream fos = new FileOutputStream(getSubregionFile(s.getX(), s.getZ()));
data.write(fos);
fos.close();
return true;
}
public AtomicMCAData loadSection(int x, int z) throws IOException
{
if(isSectionLoaded(x, z))
{
return loadedSections.get(new SMCAVector(x, z));
}
File file = getSubregionFile(x, z);
if(!file.exists())
{
return createSection(x, z);
}
FileInputStream fin = new FileInputStream(file);
AtomicMCAData data = new AtomicMCAData(world);
data.read(fin);
fin.close();
return data;
}
public AtomicMCAData createSection(int x, int z)
{
if(isSectionLoaded(x, z))
{
return loadedSections.get(new SMCAVector(x, z));
}
AtomicMCAData data = new AtomicMCAData(world);
loadedSections.put(new SMCAVector(x, z), data);
return data;
}
public File getSubregionFile(int x, int z)
{
return new File(getSubregionFolder(), "sr." + x + "." + z + ".smca");
}
public File getSubregionFolder()
{
return new File(world.getWorldFolder(), "subregion");
}
}

View File

@ -5,10 +5,10 @@ import ninja.bytecode.shuriken.collections.GMap;
public class ChunkPlan
{
private final GMap<ChunkedVector, Integer> realHeightCache;
private final GMap<ChunkedVector, Integer> realWaterHeightCache;
private final GMap<ChunkedVector, Double> heightCache;
private final GMap<ChunkedVector, IrisBiome> biomeCache;
private final GMap<SChunkVector, Integer> realHeightCache;
private final GMap<SChunkVector, Integer> realWaterHeightCache;
private final GMap<SChunkVector, Double> heightCache;
private final GMap<SChunkVector, IrisBiome> biomeCache;
public ChunkPlan()
{
@ -20,17 +20,17 @@ public class ChunkPlan
public IrisBiome getBiome(int x, int z)
{
return biomeCache.get(new ChunkedVector(x, z));
return biomeCache.get(new SChunkVector(x, z));
}
public void setBiome(int x, int z, IrisBiome cng)
{
biomeCache.put(new ChunkedVector(x, z), cng);
biomeCache.put(new SChunkVector(x, z), cng);
}
public double getHeight(int x, int z)
{
ChunkedVector c = new ChunkedVector(x, z);
SChunkVector c = new SChunkVector(x, z);
if(hasHeight(c))
{
return heightCache.get(c);
@ -41,7 +41,7 @@ public class ChunkPlan
public int getRealHeight(int x, int z)
{
ChunkedVector c = new ChunkedVector(x, z);
SChunkVector c = new SChunkVector(x, z);
if(realHeightCache.containsKey(c))
{
return realHeightCache.get(c);
@ -52,7 +52,7 @@ public class ChunkPlan
public int getRealWaterHeight(int x, int z)
{
ChunkedVector c = new ChunkedVector(x, z);
SChunkVector c = new SChunkVector(x, z);
if(realWaterHeightCache.containsKey(c))
{
@ -62,43 +62,43 @@ public class ChunkPlan
return 0;
}
public boolean hasHeight(ChunkedVector c)
public boolean hasHeight(SChunkVector c)
{
return heightCache.containsKey(c);
}
public boolean hasHeight(int x, int z)
{
return hasHeight(new ChunkedVector(x, z));
return hasHeight(new SChunkVector(x, z));
}
public void setHeight(ChunkedVector c, double h)
public void setHeight(SChunkVector c, double h)
{
heightCache.put(c, h);
}
public void setRealHeight(ChunkedVector c, int h)
public void setRealHeight(SChunkVector c, int h)
{
realHeightCache.put(c, h);
}
public void setRealHeight(int x, int z, int h)
{
setRealHeight(new ChunkedVector(x, z), h);
setRealHeight(new SChunkVector(x, z), h);
}
public void setRealWaterHeight(ChunkedVector c, int h)
public void setRealWaterHeight(SChunkVector c, int h)
{
realWaterHeightCache.put(c, h);
}
public void setRealWaterHeight(int x, int z, int h)
{
setRealWaterHeight(new ChunkedVector(x, z), h);
setRealWaterHeight(new SChunkVector(x, z), h);
}
public void setHeight(int x, int z, double h)
{
setHeight(new ChunkedVector(x, z), h);
setHeight(new SChunkVector(x, z), h);
}
}

View File

@ -10,7 +10,6 @@ import org.bukkit.util.Vector;
import mortar.api.nms.NMP;
import mortar.api.world.MaterialBlock;
import mortar.compute.math.M;
import mortar.util.text.C;
public class GlowingBlock
{

View File

@ -0,0 +1,253 @@
package ninja.bytecode.iris.util;
import java.io.IOException;
import org.bukkit.Bukkit;
import org.bukkit.World;
import mortar.logic.format.F;
import mortar.util.text.C;
import ninja.bytecode.iris.Iris;
import ninja.bytecode.shuriken.collections.GList;
import ninja.bytecode.shuriken.collections.GMap;
import ninja.bytecode.shuriken.execution.ChronoLatch;
import ninja.bytecode.shuriken.logging.L;
public class IrisWorldData
{
private final World world;
private final AtomicWorldData data;
private final GMap<SMCAVector, AtomicChunkData> loadedChunks;
public IrisWorldData(World world)
{
this.world = world;
data = new AtomicWorldData(world);
loadedChunks = new GMap<>();
Bukkit.getScheduler().scheduleSyncRepeatingTask(Iris.instance, this::softUnloadWorld, 200, 20);
}
private void softUnloadWorld()
{
L.i("Load: " + F.f(getLoadedChunks().size()) + " Chunks in " + F.f(getLoadedRegions().size()) + " Regions");
for(SMCAVector i : getLoadedChunks())
{
try
{
AtomicChunkData d = getChunk(i.getX(), i.getZ());
if(d.getTimeSinceLastUse() > 10000)
{
unloadChunk(i.getX(), i.getZ(), true);
}
}
catch(Throwable e)
{
e.printStackTrace();
}
}
for(SMCAVector i : getLoadedRegions())
{
softUnloadRegion(i.getX(), i.getZ());
}
}
private boolean softUnloadRegion(int rx, int rz)
{
for(SMCAVector i : loadedChunks.keySet())
{
if(i.getX() >> 5 == rx && i.getZ() >> 5 == rz)
{
return false;
}
}
try
{
data.unloadSection(rx, rz, true);
return true;
}
catch(IOException e)
{
e.printStackTrace();
L.f(C.RED + "Failed to save Iris Subregion " + C.YELLOW + rx + " " + rz);
}
return false;
}
public boolean deleteChunk(int x, int z)
{
if(isChunkLoaded(x, z))
{
unloadChunk(x, z, false);
}
try
{
AtomicMCAData region = data.getSubregion(x >> 5, z >> 5);
region.delete(x & 31, z & 31);
return true;
}
catch(IOException e)
{
L.f(C.RED + "Failed delete chunk " + C.YELLOW + x + " " + z + C.RED.toString() + " -> Failed to get Region " + C.YELLOW + (x >> 5) + " " + (z >> 5));
e.printStackTrace();
}
return false;
}
public boolean unloadChunk(int x, int z, boolean save)
{
if(!isChunkLoaded(x, z))
{
return false;
}
if(save)
{
saveChunk(x, z);
}
loadedChunks.remove(new SMCAVector(x, z));
return true;
}
public boolean saveChunk(int x, int z)
{
if(!isChunkLoaded(x, z))
{
return false;
}
try
{
AtomicMCAData region = data.getSubregion(x >> 5, z >> 5);
region.set(x & 31, z & 31, getChunk(x, z));
return true;
}
catch(IOException e)
{
L.f(C.RED + "Failed save chunk " + C.YELLOW + x + " " + z + C.RED.toString() + " -> Failed to get Region " + C.YELLOW + (x >> 5) + " " + (z >> 5));
e.printStackTrace();
}
return false;
}
public AtomicChunkData getOnly(int x, int z)
{
if(!isChunkLoaded(x, z))
{
return null;
}
return getChunk(x, z);
}
public AtomicChunkData getChunk(int x, int z)
{
if(!isChunkLoaded(x, z))
{
try
{
AtomicMCAData region = data.getSubregion(x >> 5, z >> 5);
if(region.contains(x & 31, z & 31))
{
AtomicChunkData chunk = region.get(x & 31, z & 31);
loadedChunks.put(new SMCAVector(x, z), chunk);
}
else
{
AtomicChunkData data = new AtomicChunkData(world);
loadedChunks.put(new SMCAVector(x, z), data);
}
}
catch(IOException e)
{
L.f(C.RED + "Failed load chunk " + C.YELLOW + x + " " + z + C.RED.toString() + " -> Failed to get Region " + C.YELLOW + (x >> 5) + " " + (z >> 5));
e.printStackTrace();
}
}
return loadedChunks.get(new SMCAVector(x, z));
}
public boolean isChunkLoaded(int x, int z)
{
return loadedChunks.containsKey(new SMCAVector(x, z));
}
public void inject(int x, int z, AtomicChunkData data)
{
getChunk(x, z).inject(data);
}
public boolean exists(int x, int z)
{
try
{
return isChunkLoaded(x, z) || data.getSubregion(x >> 5, z >> 5).contains(x & 31, z & 31);
}
catch(IOException e)
{
L.f(C.RED + "Failed check chunk " + C.YELLOW + x + " " + z + C.RED.toString() + " -> Failed to get Region " + C.YELLOW + (x >> 5) + " " + (z >> 5));
e.printStackTrace();
}
return false;
}
public GList<SMCAVector> getLoadedChunks()
{
return loadedChunks.k();
}
public GList<SMCAVector> getLoadedRegions()
{
return data.getLoadedRegions();
}
public void saveAll()
{
for(SMCAVector i : loadedChunks.k())
{
saveChunk(i.getX(), i.getZ());
}
try
{
data.saveAll();
}
catch(IOException e)
{
e.printStackTrace();
}
}
public void setBlock(int x, int y, int z, int id, byte data)
{
getChunk(x >> 4, z >> 4).setBlock(x & 15, y, z & 15, id, data);
}
public void dispose()
{
for(SMCAVector i : getLoadedChunks())
{
unloadChunk(i.getX(), i.getZ(), true);
}
softUnloadWorld();
}
}

View File

@ -0,0 +1,44 @@
package ninja.bytecode.iris.util;
import ninja.bytecode.iris.pack.IrisBiome;
public class ParallaxAnchor
{
private final int height;
private final int water;
private final IrisBiome biome;
private final AtomicChunkData data;
public ParallaxAnchor(int height, int water, IrisBiome biome, AtomicChunkData data)
{
this.height = height;
this.water = water;
this.biome = biome;
this.data = data;
}
public AtomicChunkData getData()
{
return data;
}
public int getWater()
{
return water;
}
public int getHeight()
{
return height;
}
public int getWaterHeight()
{
return water;
}
public IrisBiome getBiome()
{
return biome;
}
}

View File

@ -0,0 +1,98 @@
package ninja.bytecode.iris.util;
import ninja.bytecode.iris.generator.IrisGenerator;
import ninja.bytecode.iris.pack.IrisBiome;
import ninja.bytecode.shuriken.collections.GMap;
import ninja.bytecode.shuriken.collections.GSet;
public class ParallaxCache
{
private GMap<SMCAVector, ChunkPlan> cachePlan;
private GMap<SMCAVector, AtomicChunkData> cacheData;
private GSet<SMCAVector> contains;
private IrisGenerator gen;
public ParallaxCache(IrisGenerator gen)
{
this.gen = gen;
cacheData = new GMap<>();
cachePlan = new GMap<>();
contains = new GSet<>();
}
public MB get(int x, int y, int z)
{
SMCAVector s = new SMCAVector(x, z);
SMCAVector c = new SMCAVector(x >> 4, z >> 4);
if(contains.contains(s) && cacheData.containsKey(c) && cachePlan.containsKey(c) )
{
return cacheData.get(c).getMB(x & 15, y, z & 15);
}
createData(x, z, s, c);
return cacheData.get(c).getMB(x & 15, y, z & 15);
}
public IrisBiome getBiome(int x, int z)
{
SMCAVector s = new SMCAVector(x, z);
SMCAVector c = new SMCAVector(x >> 4, z >> 4);
if(contains.contains(s) && cacheData.containsKey(c) && cachePlan.containsKey(c) )
{
return cachePlan.get(c).getBiome(x & 15, z & 15);
}
createData(x, z, s, c);
return cachePlan.get(c).getBiome(x & 15, z & 15);
}
public int getWaterHeight(int x, int z)
{
SMCAVector s = new SMCAVector(x, z);
SMCAVector c = new SMCAVector(x >> 4, z >> 4);
if(contains.contains(s) && cacheData.containsKey(c) && cachePlan.containsKey(c) )
{
return cachePlan.get(c).getRealWaterHeight(x & 15, z & 15);
}
createData(x, z, s, c);
return cachePlan.get(c).getRealWaterHeight(x & 15, z & 15);
}
public int getHeight(int x, int z)
{
SMCAVector s = new SMCAVector(x, z);
SMCAVector c = new SMCAVector(x >> 4, z >> 4);
if(contains.contains(s) && cacheData.containsKey(c) && cachePlan.containsKey(c) )
{
return cachePlan.get(c).getRealHeight(x & 15, z & 15);
}
createData(x, z, s, c);
return cachePlan.get(c).getRealHeight(x & 15, z & 15);
}
private void createData(int x, int z, SMCAVector s, SMCAVector c)
{
if(!cacheData.containsKey(c))
{
cacheData.put(c, new AtomicChunkData(gen.getWorld()));
}
if(!cachePlan.containsKey(c))
{
cachePlan.put(c, new ChunkPlan());
}
gen.computeAnchor(x, z, cachePlan.get(c), cacheData.get(c));
contains.add(s);
}
}

View File

@ -0,0 +1,190 @@
package ninja.bytecode.iris.util;
import java.util.Random;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.world.ChunkLoadEvent;
import org.bukkit.event.world.WorldSaveEvent;
import org.bukkit.event.world.WorldUnloadEvent;
import mortar.api.nms.NMP;
import ninja.bytecode.iris.Iris;
import ninja.bytecode.iris.controller.TimingsController;
import ninja.bytecode.shuriken.bench.PrecisionStopwatch;
import ninja.bytecode.shuriken.collections.GSet;
import ninja.bytecode.shuriken.execution.ChronoLatch;
import ninja.bytecode.shuriken.execution.TaskExecutor.TaskGroup;
import ninja.bytecode.shuriken.format.F;
import ninja.bytecode.shuriken.math.RNG;
public abstract class ParallaxWorldGenerator extends ParallelChunkGenerator implements Listener
{
private World world;
private IrisWorldData data;
private RNG rMaster;
private AtomicChunkData buffer;
private GSet<Chunk> fix;
private ChronoLatch cl;
@Override
public final void init(World world, Random random)
{
this.world = world;
cl = new ChronoLatch(3000);
fix = new GSet<>();
buffer = new AtomicChunkData(world);
this.data = new IrisWorldData(world);
this.rMaster = new RNG(world.getSeed() + 1);
onInit(world, rMaster.nextParallelRNG(1));
Bukkit.getPluginManager().registerEvents(this, Iris.instance);
}
@EventHandler
public void on(ChunkLoadEvent e)
{
if(e.getWorld().equals(world))
{
NMP.host.relight(e.getChunk());
Bukkit.getScheduler().scheduleSyncDelayedTask(Iris.instance, () -> fix.add(e.getChunk()), 20);
if(cl.flip())
{
for(Chunk i : fix)
{
for(Player f : e.getWorld().getPlayers())
{
NMP.CHUNK.refreshIgnorePosition(f, i);
}
}
fix.clear();
}
}
}
@EventHandler
public void on(WorldUnloadEvent e)
{
if(e.getWorld().equals(world))
{
getWorldData().dispose();
onUnload();
}
}
@EventHandler
public void on(WorldSaveEvent e)
{
if(e.getWorld().equals(world))
{
getWorldData().saveAll();
}
}
public ParallaxAnchor computeAnchor(int wx, int wz, ChunkPlan heightBuffer, AtomicChunkData data)
{
onGenColumn(wx, wz, wx & 15, wz & 15, heightBuffer, data);
return new ParallaxAnchor(heightBuffer.getRealHeight(wx & 15, wz & 15), heightBuffer.getRealWaterHeight(wx & 15, wz & 15), heightBuffer.getBiome(wx & 15, wz & 15), data);
}
public ParallaxAnchor computeAnchor(int wx, int wz)
{
ChunkPlan heightBuffer = new ChunkPlan();
onGenColumn(wx, wz, wx & 15, wz & 15, heightBuffer, buffer);
return new ParallaxAnchor(heightBuffer.getRealHeight(wx & 15, wz & 15), heightBuffer.getRealWaterHeight(wx & 15, wz & 15), heightBuffer.getBiome(wx & 15, wz & 15), buffer);
}
@Override
public final ChunkPlan initChunk(World world, int x, int z, Random random)
{
PrecisionStopwatch ps = PrecisionStopwatch.start();
TaskGroup g = startWork();
int gg = 0;
int gx = 0;
for(int ii = -(getParallaxSize().getX() / 2) - 1; ii < (getParallaxSize().getX() / 2) + 1; ii++)
{
int i = ii;
for(int jj = -(getParallaxSize().getZ() / 2) - 1; jj < (getParallaxSize().getZ() / 2) + 1; jj++)
{
gx++;
int j = jj;
int cx = x + i;
int cz = z + j;
if(!getWorldData().exists(cx, cz))
{
g.queue(() ->
{
onGenParallax(cx, cz, getRMaster(cx, cz, -59328));
getWorldData().getChunk(cx, cz);
});
gg++;
}
}
}
double a = ps.getMilliseconds();
double b = g.execute().timeElapsed;
System.out.println("MS: " + F.duration(Iris.getController(TimingsController.class).getResult("terrain"), 2) + " \tQMS: " + F.duration(a, 2) + " " + " \tEMS: " + F.duration(b, 2) + "\tSCG: " + gg + " / " + gx + " (" + F.pc(((double) gg / (double) gx)) + ") " + " \tTC: " + F.f(getWorldData().getLoadedChunks().size()) + " \tTR: " + getWorldData().getLoadedRegions().size());
return onInitChunk(world, x, z, random);
}
@Override
public final void postChunk(World world, int x, int z, Random random, AtomicChunkData data, ChunkPlan plan)
{
getWorldData().inject(x, z, data);
onPostChunk(world, x, z, random, data, plan);
}
@Override
public final Biome genColumn(int wx, int wz, int x, int z, ChunkPlan plan, AtomicChunkData data)
{
return onGenColumn(wx, wz, x, z, plan, data);
}
public World getWorld()
{
return world;
}
public IrisWorldData getWorldData()
{
return data;
}
public RNG getRMaster()
{
return rMaster;
}
public RNG getRMaster(int x, int z, int signature)
{
return rMaster.nextParallelRNG((int) (signature + x * z + z + x * 2.12));
}
protected abstract void onUnload();
protected abstract SChunkVector getParallaxSize();
public abstract void onGenParallax(int x, int z, Random random);
public abstract void onInit(World world, Random random);
public abstract ChunkPlan onInitChunk(World world, int x, int z, Random random);
public abstract Biome onGenColumn(int wx, int wz, int x, int z, ChunkPlan plan, AtomicChunkData data2);
public abstract void onPostChunk(World world, int x, int z, Random random, AtomicChunkData data, ChunkPlan plan);
}

View File

@ -8,7 +8,6 @@ import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.generator.ChunkGenerator;
import mortar.logic.queue.ChronoLatch;
import ninja.bytecode.iris.Iris;
import ninja.bytecode.iris.controller.ExecutionController;
import ninja.bytecode.iris.controller.TimingsController;
@ -24,48 +23,64 @@ public abstract class ParallelChunkGenerator extends ChunkGenerator
private int j;
private int wx;
private int wz;
private AtomicChunkData data;
private ReentrantLock biomeLock;
private TaskGroup tg;
private ChronoLatch el = new ChronoLatch(5000);
private boolean ready = false;
int cg = 0;
private RollingSequence rs = new RollingSequence(512);
private World world;
private TaskExecutor genPool;
private TaskExecutor genPar;
public World getWorld()
{
return world;
}
public Biome generateFullColumn(int a, int b, int c, int d, ChunkPlan p)
public Biome generateFullColumn(int a, int b, int c, int d, ChunkPlan p, AtomicChunkData data)
{
return genColumn(a, b, c, d, p);
return genColumn(a, b, c, d, p, data);
}
public TaskGroup startParallaxWork()
{
if(genPar == null)
{
genPar = Iris.getController(ExecutionController.class).getExecutor(world, "Parallax");
}
return genPar.startWork();
}
public TaskGroup startWork()
{
if(genPool == null)
{
genPool = Iris.getController(ExecutionController.class).getExecutor(world, "Generator");
}
return genPool.startWork();
}
public ChunkData generateChunkData(World world, Random random, int x, int z, BiomeGrid biome)
{
AtomicChunkData data = new AtomicChunkData(world);
try
{
Iris.getController(TimingsController.class).started("terrain");
if(genPool == null)
{
genPool = Iris.getController(ExecutionController.class).getExecutor(world);
}
this.world = world;
data = new AtomicChunkData(world);
if(!ready)
{
biomeLock = new ReentrantLock();
onInit(world, random);
init(world, random);
ready = true;
}
tg = genPool.startWork();
tg = startWork();
O<ChunkPlan> plan = new O<ChunkPlan>();
for(i = 0; i < 16; i++)
{
wx = (x << 4) + i;
@ -79,7 +94,7 @@ public abstract class ParallelChunkGenerator extends ChunkGenerator
int d = j;
tg.queue(() ->
{
Biome f = generateFullColumn(a, b, c, d, plan.get());
Biome f = generateFullColumn(a, b, c, d, plan.get(), data);
biomeLock.lock();
biome.setBiome(c, d, f);
biomeLock.unlock();
@ -87,15 +102,17 @@ public abstract class ParallelChunkGenerator extends ChunkGenerator
}
}
plan.set(onInitChunk(world, x, z, random));
plan.set(initChunk(world, x, z, random));
TaskResult r = tg.execute();
onPostChunk(world, x, z, random, data, plan.get());
postChunk(world, x, z, random, data, plan.get());
rs.put(r.timeElapsed);
cg++;
Iris.getController(TimingsController.class).stopped("terrain");
}
catch(Throwable e)
{
try
{
for(int i = 0; i < 16; i++)
{
@ -104,54 +121,23 @@ public abstract class ParallelChunkGenerator extends ChunkGenerator
data.setBlock(i, 0, j, Material.RED_GLAZED_TERRACOTTA);
}
}
if(el.flip())
{
e.printStackTrace();
}
catch(Throwable ex)
{
}
e.printStackTrace();
}
return data.toChunkData();
}
public abstract void onInit(World world, Random random);
public abstract void init(World world, Random random);
public abstract ChunkPlan onInitChunk(World world, int x, int z, Random random);
public abstract ChunkPlan initChunk(World world, int x, int z, Random random);
public abstract void onPostChunk(World world, int x, int z, Random random, AtomicChunkData data, ChunkPlan plan);
public abstract void postChunk(World world, int x, int z, Random random, AtomicChunkData data, ChunkPlan plan);
public abstract Biome genColumn(int wx, int wz, int x, int z, ChunkPlan plan);
public abstract void decorateColumn(int wx, int wz, int x, int z, ChunkPlan plan);
public void setBlock(int x, int y, int z, Material b)
{
setBlock(x, y, z, b, (byte) 0);
}
@SuppressWarnings("deprecation")
public void setBlock(int x, int y, int z, Material b, byte d)
{
setBlock(x, y, z, b.getId(), d);
}
public void setBlock(int x, int y, int z, int b)
{
setBlock(x, y, z, b, (byte) 0);
}
public void setBlock(int x, int y, int z, int b, byte d)
{
data.setBlock(x, y, z, b, d);
}
public Material getType(int x, int y, int z)
{
return data.getType(x, y, z);
}
public byte getData(int x, int y, int z)
{
return data.getData(x, y, z);
}
public abstract Biome genColumn(int wx, int wz, int x, int z, ChunkPlan plan, AtomicChunkData data);
}

View File

@ -1,28 +1,28 @@
package ninja.bytecode.iris.util;
public class ChunkedVector
public class SChunkVector
{
private byte x;
private byte z;
public ChunkedVector(int x, int z)
public SChunkVector(int x, int z)
{
this.x = (byte) (x);
this.z = (byte) (z);
}
public ChunkedVector(byte x, byte z)
public SChunkVector(byte x, byte z)
{
this.x = x;
this.z = z;
}
public ChunkedVector(double x, double z)
public SChunkVector(double x, double z)
{
this((int) Math.round(x), (int) Math.round(z));
}
public ChunkedVector()
public SChunkVector()
{
this((byte) 0, (byte) 0);
}
@ -66,13 +66,11 @@ public class ChunkedVector
return false;
if(getClass() != obj.getClass())
return false;
ChunkedVector other = (ChunkedVector) obj;
SChunkVector other = (SChunkVector) obj;
if(x != other.x)
return false;
if(z != other.z)
return false;
return true;
}
}

View File

@ -0,0 +1,61 @@
package ninja.bytecode.iris.util;
import java.util.Objects;
public class SMCAVector
{
private int x;
private int z;
public SMCAVector(int x, int z)
{
this.x = x;
this.z = z;
}
public SMCAVector()
{
this(0, 0);
}
public int getX()
{
return x;
}
public void setX(int x)
{
this.x = x;
}
public int getZ()
{
return z;
}
public void setZ(int z)
{
this.z = z;
}
@Override
public int hashCode()
{
return Objects.hash(x, z);
}
@Override
public boolean equals(Object obj)
{
if(this == obj)
{
return true;
}
if(!(obj instanceof SMCAVector))
{
return false;
}
SMCAVector other = (SMCAVector) obj;
return x == other.x && z == other.z;
}
}

View File

@ -0,0 +1,82 @@
package org.jnbt;
/*
* JNBT License
*
* Copyright (c) 2010 Graham Edgecombe
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the JNBT team nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* The <code>TAG_Byte_Array</code> tag.
*
* @author Graham Edgecombe
*
*/
public final class ByteArrayTag extends Tag {
/**
* The value.
*/
private final byte[] value;
/**
* Creates the tag.
*
* @param name The name.
* @param value The value.
*/
public ByteArrayTag(String name, byte[] value) {
super(name);
this.value = value;
}
@Override
public byte[] getValue() {
return value;
}
@Override
public String toString() {
StringBuilder hex = new StringBuilder();
for (byte b : value) {
String hexDigits = Integer.toHexString(b).toUpperCase();
if (hexDigits.length() == 1) {
hex.append("0");
}
hex.append(hexDigits).append(" ");
}
String name = getName();
String append = "";
if (name != null && !name.equals("")) {
append = "(\"" + this.getName() + "\")";
}
return "TAG_Byte_Array" + append + ": " + hex.toString();
}
}

View File

@ -0,0 +1,74 @@
package org.jnbt;
/*
* JNBT License
*
* Copyright (c) 2010 Graham Edgecombe
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the JNBT team nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* The <code>TAG_Byte</code> tag.
*
* @author Graham Edgecombe
*
*/
public final class ByteTag extends Tag {
/**
* The value.
*/
private final byte value;
/**
* Creates the tag.
*
* @param name The name.
* @param value The value.
*/
public ByteTag(String name, byte value) {
super(name);
this.value = value;
}
@Override
public Byte getValue() {
return value;
}
@Override
public String toString() {
String name = getName();
String append = "";
if (name != null && !name.equals("")) {
append = "(\"" + this.getName() + "\")";
}
return "TAG_Byte" + append + ": " + value;
}
}

View File

@ -0,0 +1,83 @@
package org.jnbt;
/*
* JNBT License
*
* Copyright (c) 2010 Graham Edgecombe
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the JNBT team nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
import java.util.Collections;
import java.util.Map;
/**
* The <code>TAG_Compound</code> tag.
*
* @author Graham Edgecombe
*
*/
public final class CompoundTag extends Tag {
/**
* The value.
*/
private final Map<String, Tag> value;
/**
* Creates the tag.
*
* @param name The name.
* @param value The value.
*/
public CompoundTag(String name, Map<String, Tag> value) {
super(name);
this.value = Collections.unmodifiableMap(value);
}
@Override
public Map<String, Tag> getValue() {
return value;
}
@Override
public String toString() {
String name = getName();
String append = "";
if (name != null && !name.equals("")) {
append = "(\"" + this.getName() + "\")";
}
StringBuilder bldr = new StringBuilder();
bldr.append("TAG_Compound" + append + ": " + value.size() + " entries\r\n{\r\n");
for (Map.Entry<String, Tag> entry : value.entrySet()) {
bldr.append(" " + entry.getValue().toString().replaceAll("\r\n", "\r\n ") + "\r\n");
}
bldr.append("}");
return bldr.toString();
}
}

View File

@ -0,0 +1,74 @@
package org.jnbt;
/*
* JNBT License
*
* Copyright (c) 2010 Graham Edgecombe
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the JNBT team nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* The <code>TAG_Double</code> tag.
*
* @author Graham Edgecombe
*
*/
public final class DoubleTag extends Tag {
/**
* The value.
*/
private final double value;
/**
* Creates the tag.
*
* @param name The name.
* @param value The value.
*/
public DoubleTag(String name, double value) {
super(name);
this.value = value;
}
@Override
public Double getValue() {
return value;
}
@Override
public String toString() {
String name = getName();
String append = "";
if (name != null && !name.equals("")) {
append = "(\"" + this.getName() + "\")";
}
return "TAG_Double" + append + ": " + value;
}
}

View File

@ -0,0 +1,60 @@
package org.jnbt;
/*
* JNBT License
*
* Copyright (c) 2010 Graham Edgecombe
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the JNBT team nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* The <code>TAG_End</code> tag.
*
* @author Graham Edgecombe
*
*/
public final class EndTag extends Tag {
/**
* Creates the tag.
*/
public EndTag() {
super("");
}
@Override
public Object getValue() {
return null;
}
@Override
public String toString() {
return "TAG_End";
}
}

View File

@ -0,0 +1,74 @@
package org.jnbt;
/*
* JNBT License
*
* Copyright (c) 2010 Graham Edgecombe
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the JNBT team nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* The <code>TAG_Float</code> tag.
*
* @author Graham Edgecombe
*
*/
public final class FloatTag extends Tag {
/**
* The value.
*/
private final float value;
/**
* Creates the tag.
*
* @param name The name.
* @param value The value.
*/
public FloatTag(String name, float value) {
super(name);
this.value = value;
}
@Override
public Float getValue() {
return value;
}
@Override
public String toString() {
String name = getName();
String append = "";
if (name != null && !name.equals("")) {
append = "(\"" + this.getName() + "\")";
}
return "TAG_Float" + append + ": " + value;
}
}

View File

@ -0,0 +1,76 @@
package org.jnbt;
import java.util.Arrays;
/*
* JNBT License
*
* Copyright (c) 2015 Neil Wightman
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the JNBT team nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* The <code>TAG_Int_Array</code> tag.
*
* @author Neil Wightman
*
*/
public final class IntArrayTag extends Tag {
/**
* The value.
*/
private final int[] value;
/**
* Creates the tag.
*
* @param name The name.
* @param value The value.
*/
public IntArrayTag(String name, int[] value) {
super(name);
this.value = value;
}
@Override
public int[] getValue() {
return value;
}
@Override
public String toString() {
String name = getName();
String append = "";
if (name != null && !name.equals("")) {
append = "(\"" + this.getName() + "\")";
}
return "TAG_Int_Array" + append + ": " + Arrays.toString(value);
}
}

View File

@ -0,0 +1,74 @@
package org.jnbt;
/*
* JNBT License
*
* Copyright (c) 2010 Graham Edgecombe
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the JNBT team nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* The <code>TAG_Int</code> tag.
*
* @author Graham Edgecombe
*
*/
public final class IntTag extends Tag {
/**
* The value.
*/
private final int value;
/**
* Creates the tag.
*
* @param name The name.
* @param value The value.
*/
public IntTag(String name, int value) {
super(name);
this.value = value;
}
@Override
public Integer getValue() {
return value;
}
@Override
public String toString() {
String name = getName();
String append = "";
if (name != null && !name.equals("")) {
append = "(\"" + this.getName() + "\")";
}
return "TAG_Int" + append + ": " + value;
}
}

View File

@ -0,0 +1,99 @@
package org.jnbt;
/*
* JNBT License
*
* Copyright (c) 2010 Graham Edgecombe
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the JNBT team nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
import java.util.Collections;
import java.util.List;
/**
* The <code>TAG_List</code> tag.
*
* @author Graham Edgecombe
*
*/
public final class ListTag extends Tag {
/**
* The type.
*/
private final Class<? extends Tag> type;
/**
* The value.
*/
private final List<Tag> value;
/**
* Creates the tag.
*
* @param name The name.
* @param type The type of item in the list.
* @param value The value.
*/
public ListTag(String name, Class<? extends Tag> type, List<Tag> value) {
super(name);
this.type = type;
this.value = Collections.unmodifiableList(value);
}
/**
* Gets the type of item in this list.
*
* @return The type of item in this list.
*/
public Class<? extends Tag> getType() {
return type;
}
@Override
public List<Tag> getValue() {
return value;
}
@Override
public String toString() {
String name = getName();
String append = "";
if (name != null && !name.equals("")) {
append = "(\"" + this.getName() + "\")";
}
StringBuilder bldr = new StringBuilder();
bldr.append("TAG_List" + append + ": " + value.size() + " entries of type " + NBTUtils.getTypeName(type) + "\r\n{\r\n");
for (Tag t : value) {
bldr.append(" " + t.toString().replaceAll("\r\n", "\r\n ") + "\r\n");
}
bldr.append("}");
return bldr.toString();
}
}

View File

@ -0,0 +1,74 @@
package org.jnbt;
/*
* JNBT License
*
* Copyright (c) 2010 Graham Edgecombe
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the JNBT team nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* The <code>TAG_Long</code> tag.
*
* @author Graham Edgecombe
*
*/
public final class LongTag extends Tag {
/**
* The value.
*/
private final long value;
/**
* Creates the tag.
*
* @param name The name.
* @param value The value.
*/
public LongTag(String name, long value) {
super(name);
this.value = value;
}
@Override
public Long getValue() {
return value;
}
@Override
public String toString() {
String name = getName();
String append = "";
if (name != null && !name.equals("")) {
append = "(\"" + this.getName() + "\")";
}
return "TAG_Long" + append + ": " + value;
}
}

View File

@ -0,0 +1,77 @@
package org.jnbt;
/*
* JNBT License
*
* Copyright (c) 2015 Neil Wightman
* Copyright (c) 2010 Graham Edgecombe
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the JNBT team nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
import java.nio.charset.Charset;
/**
* Changes : Neil Wightman - Support 19133 Tag_Int_Array tag
*/
/**
* A class which holds constant values.
*
* @author Graham Edgecombe
*
*/
public final class NBTConstants {
/**
* The character set used by NBT (UTF-8).
*/
public static final Charset CHARSET = Charset.forName("UTF-8");
/**
* Tag type constants.
*/
public static final int TYPE_END = 0,
TYPE_BYTE = 1,
TYPE_SHORT = 2,
TYPE_INT = 3,
TYPE_LONG = 4,
TYPE_FLOAT = 5,
TYPE_DOUBLE = 6,
TYPE_BYTE_ARRAY = 7,
TYPE_STRING = 8,
TYPE_LIST = 9,
TYPE_COMPOUND = 10,
TYPE_INT_ARRAY = 11;
/**
* Default private constructor.
*/
private NBTConstants() {
}
}

View File

@ -0,0 +1,205 @@
package org.jnbt;
/*
* JNBT License
*
* Copyright (c) 2015 Neil Wightman
* Copyright (c) 2010 Graham Edgecombe
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the JNBT team nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
import java.io.Closeable;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.GZIPInputStream;
/**
* Changes :
* Neil Wightman - Support 19133 Tag_Int_Array tag
*/
/**
* <p>
* This class reads <strong>NBT</strong>, or
* <strong>Named Binary Tag</strong> streams, and produces an object graph of subclasses of the <code>Tag</code> object.</p>
*
* <p>
* The NBT format was created by Markus Persson, and the specification may be found at <a href="http://www.minecraft.net/docs/NBT.txt">
* http://www.minecraft.net/docs/NBT.txt</a>.</p>
*
* @author Graham Edgecombe
*
*/
public final class NBTInputStream implements Closeable {
/**
* The data input stream.
*/
private final DataInputStream is;
/**
* Create a new <code>NBTInputStream</code>, which will source its data from the specified input stream.
* @param is The output stream
*/
public NBTInputStream(DataInputStream is) {
this.is = is;
}
/**
* Creates a new <code>NBTInputStream</code>, which will source its data from the specified input stream.
* The stream will be decompressed using GZIP.
*
* @param is The input stream.
* @throws IOException if an I/O error occurs.
*/
public NBTInputStream(InputStream is) throws IOException {
this.is = new DataInputStream(new GZIPInputStream(is));
}
/**
* Reads an NBT tag from the stream.
*
* @return The tag that was read.
* @throws IOException if an I/O error occurs.
*/
public Tag readTag() throws IOException {
return readTag(0);
}
/**
* Reads an NBT from the stream.
*
* @param depth The depth of this tag.
* @return The tag that was read.
* @throws IOException if an I/O error occurs.
*/
private Tag readTag(int depth) throws IOException {
int type = is.readByte() & 0xFF;
String name;
if (type != NBTConstants.TYPE_END) {
int nameLength = is.readShort() & 0xFFFF;
byte[] nameBytes = new byte[nameLength];
is.readFully(nameBytes);
name = new String(nameBytes, NBTConstants.CHARSET);
} else {
name = "";
}
return readTagPayload(type, name, depth);
}
/**
* Reads the payload of a tag, given the name and type.
*
* @param type The type.
* @param name The name.
* @param depth The depth.
* @return The tag.
* @throws IOException if an I/O error occurs.
*/
private Tag readTagPayload(int type, String name, int depth) throws IOException {
switch (type) {
case NBTConstants.TYPE_END:
if (depth == 0) {
throw new IOException("TAG_End found without a TAG_Compound/TAG_List tag preceding it.");
} else {
return new EndTag();
}
case NBTConstants.TYPE_BYTE:
return new ByteTag(name, is.readByte());
case NBTConstants.TYPE_SHORT:
return new ShortTag(name, is.readShort());
case NBTConstants.TYPE_INT:
return new IntTag(name, is.readInt());
case NBTConstants.TYPE_LONG:
return new LongTag(name, is.readLong());
case NBTConstants.TYPE_FLOAT:
return new FloatTag(name, is.readFloat());
case NBTConstants.TYPE_DOUBLE:
return new DoubleTag(name, is.readDouble());
case NBTConstants.TYPE_BYTE_ARRAY:
int length = is.readInt();
byte[] bytes = new byte[length];
is.readFully(bytes);
return new ByteArrayTag(name, bytes);
case NBTConstants.TYPE_STRING:
length = is.readShort();
bytes = new byte[length];
is.readFully(bytes);
return new StringTag(name, new String(bytes, NBTConstants.CHARSET));
case NBTConstants.TYPE_LIST:
int childType = is.readByte();
length = is.readInt();
List<Tag> tagList = new ArrayList<Tag>();
for (int i = 0; i < length; i++) {
Tag tag = readTagPayload(childType, "", depth + 1);
if (tag instanceof EndTag) {
throw new IOException("TAG_End not permitted in a list.");
}
tagList.add(tag);
}
return new ListTag(name, NBTUtils.getTypeClass(childType), tagList);
case NBTConstants.TYPE_COMPOUND:
Map<String, Tag> tagMap = new HashMap<String, Tag>();
while (true) {
Tag tag = readTag(depth + 1);
if (tag instanceof EndTag) {
break;
} else {
tagMap.put(tag.getName(), tag);
}
}
return new CompoundTag(name, tagMap);
case NBTConstants.TYPE_INT_ARRAY:
length = is.readInt();
int[] value = new int[length];
for (int i = 0; i < length; i++) {
value[i] = is.readInt();
}
return new IntArrayTag(name, value);
default:
throw new IOException("Invalid tag type: " + type + ".");
}
}
@Override
public void close() throws IOException {
is.close();
}
}

View File

@ -0,0 +1,301 @@
package org.jnbt;
/*
* JNBT License
*
* Copyright (c) 2015 Neil Wightman
* Copyright (c) 2010 Graham Edgecombe
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the JNBT team nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
import java.io.Closeable;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import java.util.zip.GZIPOutputStream;
/**
* Changes : Neil Wightman - Support 19133 Tag_Int_Array tag
*/
/**
* <p>
* This class writes <strong>NBT</strong>, or
* <strong>Named Binary Tag</strong> <code>Tag</code> objects to an underlying <code>OutputStream</code>.</p>
*
* <p>
* The NBT format was created by Markus Persson, and the specification may be found at <a href="http://www.minecraft.net/docs/NBT.txt">
* http://www.minecraft.net/docs/NBT.txt</a>.</p>
*
* @author Graham Edgecombe
*
*/
public final class NBTOutputStream implements Closeable {
/**
* The output stream.
*/
private final DataOutputStream os;
/**
* Create a new <code>NBTOutputStream</code>, which will write data to the specified underlying output stream.
* @param os The output stream
*/
public NBTOutputStream(DataOutputStream os) {
this.os = os;
}
/**
* Creates a new <code>NBTOutputStream</code>, which will write data to the specified underlying output stream.
* the stream will be compressed using GZIP.
*
* @param os The output stream.
* @throws IOException if an I/O error occurs.
*/
public NBTOutputStream(OutputStream os) throws IOException {
this.os = new DataOutputStream(new GZIPOutputStream(os));
}
/**
* Writes a tag.
*
* @param tag The tag to write.
* @throws IOException if an I/O error occurs.
*/
public void writeTag(Tag tag) throws IOException {
int type = NBTUtils.getTypeCode(tag.getClass());
String name = tag.getName();
byte[] nameBytes = name.getBytes(NBTConstants.CHARSET);
os.writeByte(type);
os.writeShort(nameBytes.length);
os.write(nameBytes);
if (type == NBTConstants.TYPE_END) {
throw new IOException("Named TAG_End not permitted.");
}
writeTagPayload(tag);
}
/**
* Writes tag payload.
*
* @param tag The tag.
* @throws IOException if an I/O error occurs.
*/
private void writeTagPayload(Tag tag) throws IOException {
int type = NBTUtils.getTypeCode(tag.getClass());
switch (type) {
case NBTConstants.TYPE_END:
writeEndTagPayload((EndTag) tag);
break;
case NBTConstants.TYPE_BYTE:
writeByteTagPayload((ByteTag) tag);
break;
case NBTConstants.TYPE_SHORT:
writeShortTagPayload((ShortTag) tag);
break;
case NBTConstants.TYPE_INT:
writeIntTagPayload((IntTag) tag);
break;
case NBTConstants.TYPE_LONG:
writeLongTagPayload((LongTag) tag);
break;
case NBTConstants.TYPE_FLOAT:
writeFloatTagPayload((FloatTag) tag);
break;
case NBTConstants.TYPE_DOUBLE:
writeDoubleTagPayload((DoubleTag) tag);
break;
case NBTConstants.TYPE_BYTE_ARRAY:
writeByteArrayTagPayload((ByteArrayTag) tag);
break;
case NBTConstants.TYPE_STRING:
writeStringTagPayload((StringTag) tag);
break;
case NBTConstants.TYPE_LIST:
writeListTagPayload((ListTag) tag);
break;
case NBTConstants.TYPE_COMPOUND:
writeCompoundTagPayload((CompoundTag) tag);
break;
case NBTConstants.TYPE_INT_ARRAY:
writeIntArrayTagPayload((IntArrayTag) tag);
break;
default:
throw new IOException("Invalid tag type: " + type + ".");
}
}
/**
* Writes a <code>TAG_Byte</code> tag.
*
* @param tag The tag.
* @throws IOException if an I/O error occurs.
*/
private void writeByteTagPayload(ByteTag tag) throws IOException {
os.writeByte(tag.getValue());
}
/**
* Writes a <code>TAG_Byte_Array</code> tag.
*
* @param tag The tag.
* @throws IOException if an I/O error occurs.
*/
private void writeByteArrayTagPayload(ByteArrayTag tag) throws IOException {
byte[] bytes = tag.getValue();
os.writeInt(bytes.length);
os.write(bytes);
}
/**
* Writes a <code>TAG_Compound</code> tag.
*
* @param tag The tag.
* @throws IOException if an I/O error occurs.
*/
private void writeCompoundTagPayload(CompoundTag tag) throws IOException {
for (Tag childTag : tag.getValue().values()) {
writeTag(childTag);
}
os.writeByte((byte) 0); // end tag - better way?
}
/**
* Writes a <code>TAG_List</code> tag.
*
* @param tag The tag.
* @throws IOException if an I/O error occurs.
*/
private void writeListTagPayload(ListTag tag) throws IOException {
Class<? extends Tag> clazz = tag.getType();
List<Tag> tags = tag.getValue();
int size = tags.size();
os.writeByte(NBTUtils.getTypeCode(clazz));
os.writeInt(size);
for (int i = 0; i < size; i++) {
writeTagPayload(tags.get(i));
}
}
/**
* Writes a <code>TAG_String</code> tag.
*
* @param tag The tag.
* @throws IOException if an I/O error occurs.
*/
private void writeStringTagPayload(StringTag tag) throws IOException {
byte[] bytes = tag.getValue().getBytes(NBTConstants.CHARSET);
os.writeShort(bytes.length);
os.write(bytes);
}
/**
* Writes a <code>TAG_Double</code> tag.
*
* @param tag The tag.
* @throws IOException if an I/O error occurs.
*/
private void writeDoubleTagPayload(DoubleTag tag) throws IOException {
os.writeDouble(tag.getValue());
}
/**
* Writes a <code>TAG_Float</code> tag.
*
* @param tag The tag.
* @throws IOException if an I/O error occurs.
*/
private void writeFloatTagPayload(FloatTag tag) throws IOException {
os.writeFloat(tag.getValue());
}
/**
* Writes a <code>TAG_Long</code> tag.
*
* @param tag The tag.
* @throws IOException if an I/O error occurs.
*/
private void writeLongTagPayload(LongTag tag) throws IOException {
os.writeLong(tag.getValue());
}
/**
* Writes a <code>TAG_Int</code> tag.
*
* @param tag The tag.
* @throws IOException if an I/O error occurs.
*/
private void writeIntTagPayload(IntTag tag) throws IOException {
os.writeInt(tag.getValue());
}
/**
* Writes a <code>TAG_Short</code> tag.
*
* @param tag The tag.
* @throws IOException if an I/O error occurs.
*/
private void writeShortTagPayload(ShortTag tag) throws IOException {
os.writeShort(tag.getValue());
}
/**
* Writes a <code>TAG_Empty</code> tag.
*
* @param tag The tag.
* @throws IOException if an I/O error occurs.
*/
private void writeEndTagPayload(EndTag tag) {
/* empty */
}
/**
* Writes a <code>TAG_Int_Array</code> tag.
*
* @param tag The tag.
* @throws IOException if an I/O error occurs.
*/
private void writeIntArrayTagPayload(IntArrayTag tag) throws IOException {
final int[] values = tag.getValue();
os.writeInt(values.length);
for(final int value : values) {
os.writeInt(value);
}
}
@Override
public void close() throws IOException {
os.close();
}
}

View File

@ -0,0 +1,165 @@
package org.jnbt;
/*
* JNBT License
*
* Copyright (c) 2015 Neil Wightman
* Copyright (c) 2010 Graham Edgecombe
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the JNBT team nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* Changes : Neil Wightman - Support 19133 Tag_Int_Array tag
*/
/**
* A class which contains NBT-related utility methods. This currently supports reading 19133 but <b>only</b> writing 19132.
*
* @author Graham Edgecombe
*
*/
public final class NBTUtils {
/**
* Gets the type name of a tag.
*
* @param clazz The tag class.
* @return The type name.
*/
public static String getTypeName(Class<? extends Tag> clazz) {
if (clazz.equals(ByteArrayTag.class)) {
return "TAG_Byte_Array";
} else if (clazz.equals(ByteTag.class)) {
return "TAG_Byte";
} else if (clazz.equals(CompoundTag.class)) {
return "TAG_Compound";
} else if (clazz.equals(DoubleTag.class)) {
return "TAG_Double";
} else if (clazz.equals(EndTag.class)) {
return "TAG_End";
} else if (clazz.equals(FloatTag.class)) {
return "TAG_Float";
} else if (clazz.equals(IntTag.class)) {
return "TAG_Int";
} else if (clazz.equals(ListTag.class)) {
return "TAG_List";
} else if (clazz.equals(LongTag.class)) {
return "TAG_Long";
} else if (clazz.equals(ShortTag.class)) {
return "TAG_Short";
} else if (clazz.equals(StringTag.class)) {
return "TAG_String";
} else if (clazz.equals(IntArrayTag.class)) {
return "TAG_Int_Array";
} else {
throw new IllegalArgumentException("Invalid tag classs (" + clazz.getName() + ").");
}
}
/**
* Gets the type code of a tag class.
*
* @param clazz The tag class.
* @return The type code.
* @throws IllegalArgumentException if the tag class is invalid.
*/
public static int getTypeCode(Class<? extends Tag> clazz) {
if (clazz.equals(ByteArrayTag.class)) {
return NBTConstants.TYPE_BYTE_ARRAY;
} else if (clazz.equals(ByteTag.class)) {
return NBTConstants.TYPE_BYTE;
} else if (clazz.equals(CompoundTag.class)) {
return NBTConstants.TYPE_COMPOUND;
} else if (clazz.equals(DoubleTag.class)) {
return NBTConstants.TYPE_DOUBLE;
} else if (clazz.equals(EndTag.class)) {
return NBTConstants.TYPE_END;
} else if (clazz.equals(FloatTag.class)) {
return NBTConstants.TYPE_FLOAT;
} else if (clazz.equals(IntTag.class)) {
return NBTConstants.TYPE_INT;
} else if (clazz.equals(ListTag.class)) {
return NBTConstants.TYPE_LIST;
} else if (clazz.equals(LongTag.class)) {
return NBTConstants.TYPE_LONG;
} else if (clazz.equals(ShortTag.class)) {
return NBTConstants.TYPE_SHORT;
} else if (clazz.equals(StringTag.class)) {
return NBTConstants.TYPE_STRING;
} else if (clazz.equals(IntArrayTag.class)) {
return NBTConstants.TYPE_INT_ARRAY;
} else {
throw new IllegalArgumentException("Invalid tag classs (" + clazz.getName() + ").");
}
}
/**
* Gets the class of a type of tag.
*
* @param type The type.
* @return The class.
* @throws IllegalArgumentException if the tag type is invalid.
*/
public static Class<? extends Tag> getTypeClass(int type) {
switch (type) {
case NBTConstants.TYPE_END:
return EndTag.class;
case NBTConstants.TYPE_BYTE:
return ByteTag.class;
case NBTConstants.TYPE_SHORT:
return ShortTag.class;
case NBTConstants.TYPE_INT:
return IntTag.class;
case NBTConstants.TYPE_LONG:
return LongTag.class;
case NBTConstants.TYPE_FLOAT:
return FloatTag.class;
case NBTConstants.TYPE_DOUBLE:
return DoubleTag.class;
case NBTConstants.TYPE_BYTE_ARRAY:
return ByteArrayTag.class;
case NBTConstants.TYPE_STRING:
return StringTag.class;
case NBTConstants.TYPE_LIST:
return ListTag.class;
case NBTConstants.TYPE_COMPOUND:
return CompoundTag.class;
case NBTConstants.TYPE_INT_ARRAY:
return IntArrayTag.class;
default:
throw new IllegalArgumentException("Invalid tag type : " + type + ".");
}
}
/**
* Default private constructor.
*/
private NBTUtils() {
}
}

View File

@ -0,0 +1,74 @@
package org.jnbt;
/*
* JNBT License
*
* Copyright (c) 2010 Graham Edgecombe
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the JNBT team nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* The <code>TAG_Short</code> tag.
*
* @author Graham Edgecombe
*
*/
public final class ShortTag extends Tag {
/**
* The value.
*/
private final short value;
/**
* Creates the tag.
*
* @param name The name.
* @param value The value.
*/
public ShortTag(String name, short value) {
super(name);
this.value = value;
}
@Override
public Short getValue() {
return value;
}
@Override
public String toString() {
String name = getName();
String append = "";
if (name != null && !name.equals("")) {
append = "(\"" + this.getName() + "\")";
}
return "TAG_Short" + append + ": " + value;
}
}

View File

@ -0,0 +1,74 @@
package org.jnbt;
/*
* JNBT License
*
* Copyright (c) 2010 Graham Edgecombe
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the JNBT team nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* The <code>TAG_String</code> tag.
*
* @author Graham Edgecombe
*
*/
public final class StringTag extends Tag {
/**
* The value.
*/
private final String value;
/**
* Creates the tag.
*
* @param name The name.
* @param value The value.
*/
public StringTag(String name, String value) {
super(name);
this.value = value;
}
@Override
public String getValue() {
return value;
}
@Override
public String toString() {
String name = getName();
String append = "";
if (name != null && !name.equals("")) {
append = "(\"" + this.getName() + "\")";
}
return "TAG_String" + append + ": " + value;
}
}

View File

@ -0,0 +1,73 @@
package org.jnbt;
/*
* JNBT License
*
* Copyright (c) 2010 Graham Edgecombe
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the JNBT team nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* Represents a single NBT tag.
*
* @author Graham Edgecombe
*
*/
public abstract class Tag {
/**
* The name of this tag.
*/
private final String name;
/**
* Creates the tag with the specified name.
*
* @param name The name.
*/
public Tag(String name) {
this.name = name;
}
/**
* Gets the name of this tag.
*
* @return The name of this tag.
*/
public final String getName() {
return name;
}
/**
* Gets the value of this tag.
*
* @return The value of this tag.
*/
public abstract Object getValue();
}