Parallax 2

This commit is contained in:
Daniel Mills 2020-08-22 09:51:54 -04:00
parent ccc7a947cd
commit 2500fa54e4
17 changed files with 1107 additions and 105 deletions

View File

@ -8,7 +8,7 @@ import org.bukkit.inventory.Inventory;
import com.volmit.iris.Iris;
import com.volmit.iris.object.InventorySlotType;
import com.volmit.iris.object.IrisLootTable;
import com.volmit.iris.util.KSet;
import com.volmit.iris.util.KList;
import com.volmit.iris.util.MortarCommand;
import com.volmit.iris.util.MortarSender;
import com.volmit.iris.util.O;
@ -30,9 +30,9 @@ public class CommandIrisLoot extends MortarCommand
if(sender.isPlayer())
{
Player p = sender.player();
KSet<IrisLootTable> tables = Iris.proj.getCurrentProject().getGlUpdate().getLootTables(p.getLocation().getBlock());
KList<IrisLootTable> tables = Iris.proj.getCurrentProject().getGlUpdate().getLootTables(RNG.r, p.getLocation().getBlock());
Inventory inv = Bukkit.createInventory(null, 27 * 2);
Iris.proj.getCurrentProject().getGlUpdate().addItems(true, inv, RNG.r, tables, InventorySlotType.STORAGE, p.getLocation().getBlockX(), p.getLocation().getBlockY(), p.getLocation().getBlockZ());
Iris.proj.getCurrentProject().getGlUpdate().addItems(true, inv, RNG.r, tables, InventorySlotType.STORAGE, p.getLocation().getBlockX(), p.getLocation().getBlockY(), p.getLocation().getBlockZ(), 1);
p.openInventory(inv);
for(IrisLootTable i : tables)
@ -74,7 +74,7 @@ public class CommandIrisLoot extends MortarCommand
inv.clear();
}
Iris.proj.getCurrentProject().getGlUpdate().addItems(true, inv, new RNG(RNG.r.imax()), tables, InventorySlotType.STORAGE, p.getLocation().getBlockX(), p.getLocation().getBlockY(), p.getLocation().getBlockZ());
Iris.proj.getCurrentProject().getGlUpdate().addItems(true, inv, new RNG(RNG.r.imax()), tables, InventorySlotType.STORAGE, p.getLocation().getBlockX(), p.getLocation().getBlockY(), p.getLocation().getBlockZ(), 1);
}, 0, fast ? 5 : 35));
return true;

View File

@ -17,7 +17,6 @@ import com.volmit.iris.object.IrisBiomeMutation;
import com.volmit.iris.object.IrisObjectPlacement;
import com.volmit.iris.object.IrisRegion;
import com.volmit.iris.object.IrisStructurePlacement;
import com.volmit.iris.object.TileResult;
import com.volmit.iris.util.BiomeMap;
import com.volmit.iris.util.CaveResult;
import com.volmit.iris.util.ChunkPosition;
@ -27,6 +26,7 @@ import com.volmit.iris.util.IrisLock;
import com.volmit.iris.util.IrisStructureResult;
import com.volmit.iris.util.KList;
import com.volmit.iris.util.KMap;
import com.volmit.iris.util.NBTInputStream;
import com.volmit.iris.util.NastyRunnable;
import com.volmit.iris.util.PrecisionStopwatch;
import com.volmit.iris.util.RNG;
@ -106,7 +106,7 @@ public abstract class ParallaxChunkGenerator extends TerrainChunkGenerator imple
return h;
}
NBTInputStream
return h;
}
@ -218,61 +218,7 @@ public abstract class ParallaxChunkGenerator extends TerrainChunkGenerator imple
public IrisStructureResult getStructure(int x, int y, int z)
{
IrisBiome b = sampleTrueBiome(x, z).getBiome();
IrisRegion r = sampleRegion(x, z);
RNG ro = getMasterRandom().nextParallelRNG(496888 + (x >> 4) + (z >> 4));
int h = (int) Math.round(getTerrainHeight(x, z));
KList<IrisStructurePlacement> p = new KList<>();
for(IrisStructurePlacement i : r.getStructures())
{
if(i.getHeight() > -1)
{
if(y >= i.getHeight() && y <= i.getHeight() + (i.getStructure(this).getGridHeight() * i.getStructure(this).getMaxLayers()))
{
p.add(i);
}
}
else if(y >= h && y <= i.getStructure(this).getGridHeight() + h)
{
p.add(i);
}
}
for(IrisStructurePlacement i : b.getStructures())
{
if(i.getHeight() > -1)
{
if(y >= i.getHeight() && y <= i.getHeight() + (i.getStructure(this).getGridHeight() * i.getStructure(this).getMaxLayers()))
{
p.add(i);
}
}
else if(y >= h && y <= i.getStructure(this).getGridHeight() + h)
{
p.add(i);
}
}
for(IrisStructurePlacement i : p)
{
if(!i.hasStructure(ro, x, y, z))
{
continue;
}
int hv = (i.getHeight() == -1 ? 0 : i.getHeight()) + (Math.floorDiv(y, i.getStructure(this).getGridHeight()) * i.getStructure(this).getGridHeight());
TileResult tile = i.getStructure(this).getTile(ro, Math.floorDiv(i.gridSize(this), x) * i.gridSize(this), hv, Math.floorDiv(i.gridSize(this), z) * i.gridSize(this));
if(tile != null && tile.getTile() != null)
{
return new IrisStructureResult(tile.getTile(), i.getStructure(this));
}
}
return null;
return getParallaxChunk(x >> 4, z >> 4).getStructure(this, y);
}
protected void onGenerateParallax(RNG random, int x, int z)

View File

@ -25,24 +25,24 @@ import lombok.Data;
public class AtomicSliver
{
public static final BlockData AIR = B.getBlockData("AIR");
private transient KMap<Integer, IrisBiome> truebiome;
private transient KMap<Integer, Biome> biome;
private transient IrisLock lock = new IrisLock("Sliver");
private transient int highestBiome = 0;
private transient long last = M.ms();
private transient int x;
private transient int z;
private transient boolean modified = false;
private KMap<Integer, BlockData> block;
private KMap<Integer, IrisBiome> truebiome;
private KMap<Integer, Biome> biome;
private KSet<Integer> update;
private IrisLock lock = new IrisLock("Sliver");
private KSet<Integer> blockUpdates;
private int highestBlock = 0;
private int highestBiome = 0;
private long last = M.ms();
private int x;
private int z;
boolean modified = false;
public AtomicSliver(int x, int z)
{
lock.setDisabled(true);
this.x = x;
this.z = z;
update = new KSet<>();
blockUpdates = new KSet<>();
this.block = new KMap<>();
this.biome = new KMap<>();
this.truebiome = new KMap<>();
@ -55,17 +55,17 @@ public class AtomicSliver
public KSet<Integer> getUpdatables()
{
return update;
return blockUpdates;
}
public void update(int y)
{
update.add(y);
blockUpdates.add(y);
}
public void dontUpdate(int y)
{
update.remove(y);
blockUpdates.remove(y);
}
public BlockData get(int h)
@ -81,6 +81,19 @@ public class AtomicSliver
return b;
}
public BlockData getOrNull(int h)
{
BlockData b = block.get(h);
last = M.ms();
if(b.getMaterial().equals(Material.AIR))
{
return null;
}
return b;
}
public void set(int h, BlockData d)
{
setSilently(h, d);
@ -190,6 +203,8 @@ public class AtomicSliver
{
lock.lock();
this.block = new KMap<Integer, BlockData>();
// Block Palette
int h = din.readByte() - Byte.MIN_VALUE;
int p = din.readByte() - Byte.MIN_VALUE;
int u = din.readByte() - Byte.MIN_VALUE;
@ -202,11 +217,13 @@ public class AtomicSliver
palette.add(B.getBlockData(din.readUTF()));
}
// Blocks
for(int i = 0; i <= h; i++)
{
block.put(i, palette.get(din.readByte() - Byte.MIN_VALUE).clone());
}
// Updates
for(int i = 0; i <= u; i++)
{
update(din.readByte() - Byte.MIN_VALUE);
@ -220,6 +237,8 @@ public class AtomicSliver
{
lock.lock();
dos.writeByte(highestBlock + Byte.MIN_VALUE);
// Block Palette
KList<String> palette = new KList<>();
for(int i = 0; i <= highestBlock; i++)
@ -234,13 +253,14 @@ public class AtomicSliver
}
dos.writeByte(palette.size() + Byte.MIN_VALUE);
dos.writeByte(update.size() + Byte.MIN_VALUE);
dos.writeByte(blockUpdates.size() + Byte.MIN_VALUE);
for(String i : palette)
{
dos.writeUTF(i);
}
// Blocks
for(int i = 0; i <= highestBlock; i++)
{
BlockData dat = block.get(i);
@ -248,6 +268,7 @@ public class AtomicSliver
dos.writeByte(palette.indexOf(d) + Byte.MIN_VALUE);
}
// Updates
for(Integer i : getUpdatables())
{
dos.writeByte(i + Byte.MIN_VALUE);
@ -296,6 +317,6 @@ public class AtomicSliver
public void inject(KSet<Integer> updatables)
{
update.addAll(updatables);
blockUpdates.addAll(updatables);
}
}

View File

@ -9,7 +9,13 @@ import java.io.OutputStream;
import org.bukkit.generator.ChunkGenerator.BiomeGrid;
import org.bukkit.generator.ChunkGenerator.ChunkData;
import com.volmit.iris.gen.DimensionChunkGenerator;
import com.volmit.iris.object.IrisStructure;
import com.volmit.iris.object.IrisStructureTile;
import com.volmit.iris.util.HeightMap;
import com.volmit.iris.util.IrisStructureResult;
import com.volmit.iris.util.KList;
import com.volmit.iris.util.KMap;
import lombok.Data;
@ -17,11 +23,13 @@ import lombok.Data;
public class AtomicSliverMap
{
private final AtomicSliver[] slivers;
private KMap<Integer, String> structures;
private boolean parallaxGenerated;
private boolean worldGenerated;
public AtomicSliverMap()
{
structures = new KMap<>();
parallaxGenerated = false;
worldGenerated = false;
slivers = new AtomicSliver[256];
@ -43,6 +51,32 @@ public class AtomicSliverMap
}
}
public void setStructure(int y, IrisStructure s, IrisStructureTile t)
{
structures.put(y, s.getLoadKey() + "." + s.getTiles().indexOf(t));
}
public IrisStructureResult getStructure(DimensionChunkGenerator g, int y)
{
String v = structures.get(y);
if(v == null)
{
return null;
}
String[] a = v.split("\\Q.\\E");
IrisStructure s = g.getData().getStructureLoader().load(a[0]);
if(s == null)
{
return null;
}
return new IrisStructureResult(s.getTiles().get(Integer.valueOf(a[1])), s);
}
public void write(OutputStream out) throws IOException
{
DataOutputStream dos = new DataOutputStream(out);
@ -53,6 +87,33 @@ public class AtomicSliverMap
slivers[i].write(dos);
}
KList<String> structurePalette = new KList<>();
for(Integer i : structures.k())
{
String struct = structures.get(i);
if(!structurePalette.contains(struct))
{
structurePalette.add(struct);
}
}
dos.writeByte(structurePalette.size() + Byte.MIN_VALUE);
for(String i : structurePalette)
{
dos.writeUTF(i);
}
dos.writeByte(structures.size() + Byte.MIN_VALUE);
for(Integer i : structures.k())
{
dos.writeByte(i + Byte.MIN_VALUE);
dos.writeByte(structurePalette.indexOf(structures.get(i)) + Byte.MIN_VALUE);
}
dos.flush();
}
@ -74,6 +135,21 @@ public class AtomicSliverMap
}
}
int spc = din.readByte() - Byte.MIN_VALUE;
KList<String> spal = new KList<>();
for(int i = 0; i < spc; i++)
{
spal.add(din.readUTF());
}
int smc = din.readByte() - Byte.MIN_VALUE;
structures.clear();
for(int i = 0; i < smc; i++)
{
structures.put(din.readByte() - Byte.MIN_VALUE, spal.get(din.readByte() - Byte.MIN_VALUE));
}
}
public AtomicSliver getSliver(int x, int z)

View File

@ -24,7 +24,6 @@ import com.volmit.iris.object.LootMode;
import com.volmit.iris.util.B;
import com.volmit.iris.util.IrisStructureResult;
import com.volmit.iris.util.KList;
import com.volmit.iris.util.KSet;
import com.volmit.iris.util.PrecisionStopwatch;
import com.volmit.iris.util.RNG;
@ -81,7 +80,7 @@ public class GenLayerUpdate extends BlockPopulator
}
}
public void injectTables(KSet<IrisLootTable> list, IrisLootReference r)
public void injectTables(KList<IrisLootTable> list, IrisLootReference r)
{
if(r.getMode().equals(LootMode.CLEAR) || r.getMode().equals(LootMode.REPLACE))
{
@ -91,15 +90,16 @@ public class GenLayerUpdate extends BlockPopulator
list.addAll(r.getLootTables(gen));
}
public KSet<IrisLootTable> getLootTables(Block b)
public KList<IrisLootTable> getLootTables(RNG rng, Block b)
{
int rx = b.getX();
int rz = b.getZ();
IrisRegion region = gen.sampleRegion(rx, rz);
IrisBiome biomeSurface = gen.sampleTrueBiome(rx, rz).getBiome();
IrisBiome biomeUnder = gen.sampleTrueBiome(rx, b.getY(), rz).getBiome();
KSet<IrisLootTable> tables = new KSet<>();
KList<IrisLootTable> tables = new KList<IrisLootTable>();
IrisStructureResult structure = gen.getStructure(rx, b.getY(), rz);
double multiplier = 1D * gen.getDimension().getLoot().getMultiplier() * region.getLoot().getMultiplier() * biomeSurface.getLoot().getMultiplier() * biomeUnder.getLoot().getMultiplier();
injectTables(tables, gen.getDimension().getLoot());
injectTables(tables, region.getLoot());
injectTables(tables, biomeSurface.getLoot());
@ -109,20 +109,38 @@ public class GenLayerUpdate extends BlockPopulator
{
injectTables(tables, structure.getStructure().getLoot());
injectTables(tables, structure.getTile().getLoot());
multiplier *= structure.getStructure().getLoot().getMultiplier() * structure.getTile().getLoot().getMultiplier();
}
if(tables.isNotEmpty())
{
int target = (int) Math.round(tables.size() * multiplier);
while(tables.size() < target && tables.isNotEmpty())
{
tables.add(tables.get(rng.i(tables.size() - 1)));
}
while(tables.size() > target && tables.isNotEmpty())
{
tables.remove(rng.i(tables.size() - 1));
}
}
return tables;
}
public void addItems(boolean debug, Inventory inv, RNG rng, KSet<IrisLootTable> tables, InventorySlotType slot, int x, int y, int z)
public void addItems(boolean debug, Inventory inv, RNG rng, KList<IrisLootTable> tables, InventorySlotType slot, int x, int y, int z, int mgf)
{
KList<ItemStack> items = new KList<>();
for(int t = 0; t < gen.getDimension().getLootTries(); t++)
{
int b = 4;
for(IrisLootTable i : tables)
{
items.addAll(i.getLoot(debug, rng.nextParallelRNG(345911 * -t), slot, x, y, z));
b++;
items.addAll(i.getLoot(debug, rng.nextParallelRNG(345911 * -t), slot, x, y, z, t + b + b, mgf + b));
}
for(ItemStack i : items)
@ -135,6 +153,8 @@ public class GenLayerUpdate extends BlockPopulator
break;
}
}
scramble(inv, rng);
}
public void updateStorage(Block b, BlockData data, int rx, int rz, RNG rng)
@ -148,12 +168,12 @@ public class GenLayerUpdate extends BlockPopulator
if(slot != null)
{
KSet<IrisLootTable> tables = getLootTables(b);
KList<IrisLootTable> tables = getLootTables(rng.nextParallelRNG(4568111), b);
try
{
InventoryHolder m = (InventoryHolder) b.getState();
addItems(false, m.getInventory(), rng, tables, slot, rx, b.getY(), rz);
addItems(false, m.getInventory(), rng, tables, slot, rx, b.getY(), rz, 15);
}
catch(Throwable e)
@ -164,6 +184,68 @@ public class GenLayerUpdate extends BlockPopulator
}
}
private void scramble(Inventory inventory, RNG rng)
{
KList<ItemStack> v = new KList<>();
for(ItemStack i : inventory.getContents())
{
if(i == null)
{
continue;
}
v.add(i);
}
inventory.clear();
int sz = inventory.getSize();
int tr = 5;
while(v.isNotEmpty())
{
int slot = rng.i(0, sz - 1);
if(inventory.getItem(slot) == null)
{
tr = tr < 5 ? tr + 1 : tr;
int pick = rng.i(0, v.size() - 1);
ItemStack g = v.get(pick);
if(g.getAmount() == 1)
{
v.remove(pick);
inventory.setItem(pick, g);
}
else
{
int portion = rng.i(1, g.getAmount() - 1);
ItemStack port = g.clone();
port.setAmount(portion);
g.setAmount(g.getAmount() - portion);
v.add(g);
inventory.setItem(slot, port);
}
}
else
{
tr--;
}
if(tr <= 0)
{
break;
}
}
for(ItemStack i : v)
{
inventory.addItem(i);
}
}
public void updateLight(Block b, BlockData data)
{
b.setType(Material.AIR, false);

View File

@ -0,0 +1,157 @@
package com.volmit.iris.gen.parallax;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import org.bukkit.Material;
import org.bukkit.block.data.BlockData;
import org.bukkit.generator.ChunkGenerator.ChunkData;
import com.volmit.iris.Iris;
import com.volmit.iris.gen.atomics.AtomicSliver;
import com.volmit.iris.util.Writable;
public class ParallaxChunk implements Writable
{
private static final ParallaxSection EMPTY = new ParallaxSection();
private final ParallaxSection[] sections;
private boolean parallaxGenerated;
private boolean worldGenerated;
public ParallaxChunk(DataInputStream in) throws IOException
{
this();
read(in);
}
public ParallaxChunk()
{
parallaxGenerated = false;
worldGenerated = false;
sections = new ParallaxSection[16];
}
public boolean isParallaxGenerated()
{
return parallaxGenerated;
}
public void setParallaxGenerated(boolean parallaxGenerated)
{
this.parallaxGenerated = parallaxGenerated;
}
public boolean isWorldGenerated()
{
return worldGenerated;
}
public void setWorldGenerated(boolean worldGenerated)
{
this.worldGenerated = worldGenerated;
}
public void export(ChunkData d)
{
for(ParallaxSection i : sections)
{
if(i != null)
{
for(int x = 0; x < 16; x++)
{
for(int y = 0; y < 16; y++)
{
for(int z = 0; z < 16; z++)
{
BlockData b = get(x, y, z);
if(b == null || b.getMaterial().equals(Material.AIR))
{
continue;
}
d.setBlock(x, y, z, b);
}
}
}
}
}
}
public void injectUpdates(AtomicSliver sliver, int x, int z)
{
for(Integer i : sliver.getUpdatables())
{
if(i > 255 || i < 0)
{
Iris.warn("Block Update out of bounds: " + i);
}
getSection(i >> 4, true).update(x, i, z);
}
}
@Override
public void write(DataOutputStream o) throws IOException
{
o.writeBoolean(isParallaxGenerated());
o.writeBoolean(isWorldGenerated());
for(int i = 15; i > 0; i--)
{
ParallaxSection c = sections[i];
if(c != null)
{
o.writeBoolean(true);
c.write(o);
}
else
{
o.writeBoolean(false);
}
}
}
@Override
public void read(DataInputStream i) throws IOException
{
setParallaxGenerated(i.readBoolean());
setWorldGenerated(i.readBoolean());
for(int iv = 15; iv > 0; iv--)
{
if(i.readBoolean())
{
sections[iv] = new ParallaxSection(i);
}
}
}
public BlockData get(int x, int y, int z)
{
return getSection(y >> 4, false).getBlock(x, y & 15, z);
}
public void set(int x, int y, int z, BlockData d)
{
getSection(y >> 4, true).setBlock(x, y & 15, z, d);
}
private final ParallaxSection getSection(int y, boolean create)
{
if(sections[y] == null)
{
if(create)
{
sections[y] = new ParallaxSection();
}
return EMPTY;
}
return sections[y];
}
}

View File

@ -0,0 +1,128 @@
package com.volmit.iris.gen.parallax;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.GZIPInputStream;
import org.bukkit.block.data.BlockData;
import com.volmit.iris.IrisSettings;
import com.volmit.iris.util.CustomOutputStream;
import com.volmit.iris.util.M;
import com.volmit.iris.util.Writable;
public class ParallaxRegion implements Writable
{
private static final ParallaxChunk EMPTY = new ParallaxChunk();
private ParallaxChunk[] chunks;
private transient long last;
public ParallaxRegion(File i) throws IOException
{
this();
if(i.exists())
{
FileInputStream in = new FileInputStream(i);
GZIPInputStream vin = new GZIPInputStream(in);
DataInputStream min = new DataInputStream(vin);
read(min);
min.close();
}
}
public ParallaxRegion(DataInputStream i) throws IOException
{
this();
read(i);
}
public ParallaxRegion()
{
last = M.ms();
chunks = new ParallaxChunk[1024];
}
@Override
public void write(DataOutputStream o) throws IOException
{
int c = 0;
for(ParallaxChunk i : chunks)
{
if(i != null)
{
c++;
}
}
o.writeShort(c);
for(int i = 0; i < 1024; i++)
{
ParallaxChunk ch = chunks[i];
if(ch != null)
{
ch.write(o);
}
}
}
public void write(File file) throws IOException
{
file.getParentFile().mkdirs();
FileOutputStream o = new FileOutputStream(file);
CustomOutputStream g = new CustomOutputStream(o, IrisSettings.get().parallaxCompressionLevel);
DataOutputStream d = new DataOutputStream(g);
write(d);
d.close();
}
@Override
public void read(DataInputStream i) throws IOException
{
int v = i.readShort();
for(int b = 0; b < v; b++)
{
chunks[b] = new ParallaxChunk(i);
}
}
public boolean isOlderThan(long time)
{
return M.ms() - time > last;
}
public void set(int x, int y, int z, BlockData d)
{
getChunk(x >> 4, z >> 4, true).set(x & 15, y, z & 15, d);
}
public BlockData get(int x, int y, int z)
{
return getChunk(x >> 4, z >> 4, false).get(x & 15, y, z & 15);
}
private final ParallaxChunk getChunk(int x, int z, boolean create)
{
last = M.ms();
int v = (z << 5) | x;
if(chunks[v] == null)
{
if(create)
{
chunks[v] = new ParallaxChunk();
}
return EMPTY;
}
return chunks[v];
}
}

View File

@ -0,0 +1,103 @@
package com.volmit.iris.gen.parallax;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import org.bukkit.block.data.BlockData;
import com.volmit.iris.util.B;
import com.volmit.iris.util.DataPalette;
import com.volmit.iris.util.KSet;
import com.volmit.iris.util.Writable;
public class ParallaxSection implements Writable
{
private final DataPalette<BlockData> block;
private final KSet<Short> updates;
public ParallaxSection(DataInputStream in) throws IOException
{
this();
read(in);
}
public ParallaxSection()
{
updates = new KSet<Short>();
this.block = new DataPalette<BlockData>(B.get("AIR"))
{
@Override
public void writeType(BlockData t, DataOutputStream o) throws IOException
{
o.writeUTF(t.getAsString(true));
}
@Override
public BlockData readType(DataInputStream i) throws IOException
{
return B.get(i.readUTF());
}
};
}
public void clearUpdates()
{
updates.clear();
}
public void update(int x, int y, int z)
{
updates.add((short) (y << 8 | z << 4 | x));
}
public void dontUpdate(int x, int y, int z)
{
updates.remove((short) (y << 8 | z << 4 | x));
}
public void setBlock(int x, int y, int z, BlockData d)
{
block.set(x, y, z, d);
if(B.isUpdatable(d))
{
update(x, y, z);
}
else
{
dontUpdate(x, y, z);
}
}
public BlockData getBlock(int x, int y, int z)
{
return block.get(x, y, z);
}
@Override
public void write(DataOutputStream o) throws IOException
{
block.write(o);
o.writeShort(updates.size());
for(Short i : updates)
{
o.writeShort(i);
}
}
@Override
public void read(DataInputStream i) throws IOException
{
block.read(i);
updates.clear();
int m = i.readShort();
for(int v = 0; v < m; v++)
{
updates.add(i.readShort());
}
}
}

View File

@ -0,0 +1,121 @@
package com.volmit.iris.gen.parallax;
import java.io.File;
import java.io.IOException;
import org.bukkit.block.data.BlockData;
import com.volmit.iris.Iris;
import com.volmit.iris.util.KMap;
public class ParallaxWorld
{
private final KMap<Long, ParallaxRegion> loadedRegions;
private final File dataFolder;
public ParallaxWorld(File dataFolder)
{
loadedRegions = new KMap<>();
this.dataFolder = dataFolder;
}
public void unloadAll()
{
for(long i : loadedRegions.k())
{
try
{
unload(i);
}
catch(IOException e)
{
Iris.error("Failed to save region " + i);
e.printStackTrace();
}
}
}
public void clean(long time)
{
for(long i : loadedRegions.k())
{
ParallaxRegion r = loadedRegions.get(i);
if(r.isOlderThan(time))
{
try
{
unload(i);
}
catch(IOException e)
{
Iris.error("Failed to save region " + i);
e.printStackTrace();
}
break;
}
}
}
private void unload(long i) throws IOException
{
ParallaxRegion r = loadedRegions.get(i);
r.write(new File(dataFolder, i + ".plx"));
loadedRegions.remove(i);
}
public BlockData getBlock(int x, int y, int z)
{
if(y > 255 || y < 0)
{
throw new IllegalArgumentException(y + " exceeds 0-255");
}
return getRegion(x >> 5, z >> 5).get(x & 511, y, z & 511);
}
public void setBlock(int x, int y, int z, BlockData d)
{
if(d == null)
{
throw new IllegalArgumentException("Block data cannot be null");
}
if(y > 255 || y < 0)
{
throw new IllegalArgumentException(y + " exceeds 0-255");
}
getRegion(x >> 5, z >> 5).set(x & 511, y, z & 511, d);
}
public ParallaxRegion getRegion(int x, int z)
{
Long vb = (((long) x) << 32) | (z & 0xffffffffL);
File ff = new File(dataFolder, vb + ".plx");
return loadedRegions.compute(vb, (k, v) ->
{
if(k == null || v == null)
{
try
{
return new ParallaxRegion(ff);
}
catch(IOException e)
{
Iris.error("Failed to load parallax file: " + ff.getAbsolutePath() + " Assuming empty region!");
ff.deleteOnExit();
ff.delete();
return new ParallaxRegion();
}
}
return v;
});
}
}

View File

@ -6,6 +6,7 @@ import com.volmit.iris.util.ArrayType;
import com.volmit.iris.util.Desc;
import com.volmit.iris.util.DontObfuscate;
import com.volmit.iris.util.KList;
import com.volmit.iris.util.MinNumber;
import com.volmit.iris.util.RegistryListLoot;
import lombok.Data;
@ -24,6 +25,11 @@ public class IrisLootReference
@Desc("Add loot table registries here")
private KList<String> tables = new KList<>();
@MinNumber(0)
@DontObfuscate
@Desc("Increase the chance of loot in this area")
private double multiplier = 1D;
private transient AtomicCache<KList<IrisLootTable>> tt = new AtomicCache<>();
public IrisLootReference()

View File

@ -27,12 +27,17 @@ public class IrisLootTable extends IrisRegistrant
@Desc("The rarity as in 1 in X chance")
private int rarity = 1;
@MinNumber(1)
@DontObfuscate
@Desc("The maximum amount of loot that can be picked in this table at a time.")
private int maxPicked = 3;
@DontObfuscate
@Desc("The loot in this table")
@ArrayType(min = 1, type = IrisLoot.class)
private KList<IrisLoot> loot = new KList<>();
public KList<ItemStack> getLoot(boolean debug, RNG rng, InventorySlotType slot, int x, int y, int z)
public KList<ItemStack> getLoot(boolean debug, RNG rng, InventorySlotType slot, int x, int y, int z, int gg, int ffs)
{
KList<ItemStack> lootf = new KList<>();
@ -42,7 +47,7 @@ public class IrisLootTable extends IrisRegistrant
{
if(i.getSlotTypes().equals(slot))
{
ItemStack item = i.get(debug, this, rng.nextParallelRNG(294788 + x + y - z * z + (m * -4125)), x, y, z);
ItemStack item = i.get(debug, this, rng, x, y, z);
if(item != null)
{
@ -51,6 +56,11 @@ public class IrisLootTable extends IrisRegistrant
}
m++;
if(m > maxPicked)
{
break;
}
}
return lootf;

View File

@ -8,6 +8,7 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.function.Consumer;
import org.bukkit.Location;
import org.bukkit.Material;
@ -17,6 +18,7 @@ import org.bukkit.block.data.type.Leaves;
import org.bukkit.util.BlockVector;
import com.volmit.iris.util.B;
import com.volmit.iris.util.BlockPosition;
import com.volmit.iris.util.ChunkPosition;
import com.volmit.iris.util.IObjectPlacer;
import com.volmit.iris.util.KMap;
@ -127,7 +129,12 @@ public class IrisObject extends IrisRegistrant
place(x, -1, z, placer, config, rng);
}
public void place(int x, int yv, int z, IObjectPlacer placer, IrisObjectPlacement config, RNG rng)
public int place(int x, int yv, int z, IObjectPlacer placer, IrisObjectPlacement config, RNG rng)
{
return place(x, yv, z, placer, config, rng, null);
}
public int place(int x, int yv, int z, IObjectPlacer placer, IrisObjectPlacement config, RNG rng, Consumer<BlockPosition> listener)
{
int spinx = rng.imax() / 1000;
int spiny = rng.imax() / 1000;
@ -135,7 +142,6 @@ public class IrisObject extends IrisRegistrant
int rty = config.getRotation().rotate(new BlockVector(0, getCenter().getBlockY(), 0), spinx, spiny, spinz).getBlockY();
int ty = config.getTranslate().translate(new BlockVector(0, getCenter().getBlockY(), 0), config.getRotation(), spinx, spiny, spinz).getBlockY();
int y = -1;
KMap<ChunkPosition, Integer> paintmap = null;
if(yv < 0)
{
@ -233,7 +239,6 @@ public class IrisObject extends IrisRegistrant
else if(config.getMode().equals(ObjectPlaceMode.PAINT))
{
y = placer.getHighest(x, z, config.isUnderwater()) + rty;
paintmap = new KMap<>();
}
}
@ -253,18 +258,18 @@ public class IrisObject extends IrisRegistrant
{
if(!config.isUnderwater() && !config.isOnwater() && placer.isUnderwater(x, z))
{
return;
return -1;
}
}
if(config.isUnderwater() && y + rty + ty >= placer.getFluidHeight())
{
return;
return -1;
}
if(!config.getClamp().canPlace(y + rty + ty, y - rty + ty))
{
return;
return -1;
}
if(config.isBore())
@ -309,17 +314,9 @@ public class IrisObject extends IrisRegistrant
int yy = y + (int) Math.round(i.getY());
int zz = z + (int) Math.round(i.getZ());
if(config.getMode().equals(ObjectPlaceMode.PAINT))
if(yv < 0 && config.getMode().equals(ObjectPlaceMode.PAINT))
{
yy = (int) Math.round(i.getY()) + Math.floorDiv(h, 2) + paintmap.compute(new ChunkPosition(xx, zz), (k, v) ->
{
if(k == null || v == null)
{
return placer.getHighest(xx, zz, config.isUnderwater());
}
return v;
});
yy = (int) Math.round(i.getY()) + Math.floorDiv(h, 2) + placer.getHighest(xx, zz, config.isUnderwater());
}
if(heightmap != null)
@ -347,6 +344,11 @@ public class IrisObject extends IrisRegistrant
((Waterlogged) data).setWaterlogged(true);
}
if(listener != null)
{
listener.accept(new BlockPosition(xx, yy, zz));
}
placer.set(xx, yy, zz, data);
}
@ -373,6 +375,8 @@ public class IrisObject extends IrisRegistrant
}
}
}
return y;
}
public void place(Location at)

View File

@ -147,7 +147,7 @@ public class IrisStructurePlacement
}
o = o != null ? o : load(g, t.getTile().getObjects().get(rnp.nextInt(t.getTile().getObjects().size())));
o.place(Math.floorDiv(i, s) * s, height == -1 ? -1 : h, Math.floorDiv(j, s) * s, g, t.getPlacement(), rng);
o.place(Math.floorDiv(i, s) * s, height == -1 ? -1 : h, Math.floorDiv(j, s) * s, g, t.getPlacement(), rng, (gg) -> g.getParallaxChunk(gg.getChunkX(), gg.getChunkZ()).setStructure(gg.getY(), t.getStructure(), t.getTile()));
}
}

View File

@ -63,7 +63,6 @@ public class IrisStructureTile
private KList<String> objects = new KList<>();
@RegistryListObject
@Required
@ArrayType(min = 1, type = IrisRareObject.class)
@DontObfuscate
@Desc("List of objects to place centered in this tile but with rarity. These items only place some of the time so specify objects for common stuff too.")

View File

@ -0,0 +1,125 @@
package com.volmit.iris.util;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public abstract class DataPalette<T> implements Writable
{
private static final int DEFAULT_BITS_PER_BLOCK = 4;
private static final int CAPACITY = 4096;
private int bpb;
private NibbleArray data;
private KList<T> palette;
public DataPalette(T defaultValue)
{
palette = new KList<>();
bpb = DEFAULT_BITS_PER_BLOCK;
data = new NibbleArray(bpb, CAPACITY);
data.setAll(Byte.MIN_VALUE);
getPaletteId(defaultValue);
}
public abstract T readType(DataInputStream i) throws IOException;
public abstract void writeType(T t, DataOutputStream o) throws IOException;
@Override
public void write(DataOutputStream o) throws IOException
{
o.writeByte(bpb + Byte.MIN_VALUE);
o.writeByte(palette.size() + Byte.MIN_VALUE);
for(T i : palette)
{
writeType(i, o);
}
data.write(o);
}
@Override
public void read(DataInputStream i) throws IOException
{
bpb = i.readByte() - Byte.MIN_VALUE;
palette = new KList<>();
int v = i.readByte() - Byte.MIN_VALUE;
for(int j = 0; j < v; j++)
{
palette.add(readType(i));
}
data = new NibbleArray(CAPACITY, i);
}
private final void expand()
{
if(bpb < 8)
{
changeBitsPerBlock(bpb + 1);
}
else
{
throw new IndexOutOfBoundsException("The Data Palette can only handle at most 256 block types per 16x16x16 region. We cannot use more than 8 bits per block!");
}
}
public final void optimize()
{
int targetBits = bpb;
int needed = palette.size();
for(int i = 1; i < bpb; i++)
{
if(Math.pow(2, i) > needed)
{
targetBits = i;
break;
}
}
changeBitsPerBlock(targetBits);
}
private final void changeBitsPerBlock(int bits)
{
bpb = bits;
data = new NibbleArray(bpb, CAPACITY, data);
}
public final void set(int x, int y, int z, T d)
{
data.set(getCoordinateIndex(x, y, z), getPaletteId(d));
}
public final T get(int x, int y, int z)
{
return palette.get(data.get(getCoordinateIndex(x, y, z)));
}
private final int getPaletteId(T d)
{
int index = palette.indexOf(d);
if(index == -1)
{
index = palette.size();
palette.add(d);
if(palette.size() > Math.pow(2, bpb))
{
expand();
}
}
return index + Byte.MIN_VALUE;
}
private final int getCoordinateIndex(int x, int y, int z)
{
return y << 8 | z << 4 | x;
}
}

View File

@ -0,0 +1,212 @@
package com.volmit.iris.util;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.ByteOrder;
import java.util.Arrays;
import java.util.StringJoiner;
public class NibbleArray implements Writable
{
private byte[] data;
private int depth;
private final int size;
private byte mask;
private final Object lock = new Object();
public NibbleArray(int capacity, DataInputStream in) throws IOException
{
size = capacity;
read(in);
}
public NibbleArray(int nibbleDepth, int capacity)
{
if(nibbleDepth > 8 || nibbleDepth < 1)
{
throw new IllegalArgumentException();
}
int neededBits = nibbleDepth * capacity;
size = capacity;
depth = nibbleDepth;
data = new byte[(neededBits + neededBits % 8) / 8];
mask = (byte) maskFor(nibbleDepth);
}
public NibbleArray(int nibbleDepth, int capacity, NibbleArray existing)
{
if(nibbleDepth > 8 || nibbleDepth < 1)
{
throw new IllegalArgumentException();
}
int neededBits = nibbleDepth * capacity;
size = capacity;
depth = nibbleDepth;
data = new byte[(neededBits + neededBits % 8) / 8];
mask = (byte) maskFor(nibbleDepth);
for(int i = 0; i < Math.min(size, existing.size()); i++)
{
set(i, existing.get(i));
}
}
@Override
public void write(DataOutputStream o) throws IOException
{
o.writeByte(depth + Byte.MIN_VALUE);
o.write(data);
}
@Override
public void read(DataInputStream i) throws IOException
{
depth = i.readByte() - Byte.MIN_VALUE;
int neededBits = depth * size;
data = new byte[(neededBits + neededBits % 8) / 8];
mask = (byte) maskFor(depth);
i.read(data);
}
public int size()
{
return size;
}
public byte get(int index)
{
synchronized(lock)
{
bitIndex = index * depth;
byteIndex = bitIndex >> 3;
bitInByte = bitIndex & 7;
int value = data[byteIndex] >> bitInByte;
if(bitInByte + depth > 8)
{
value |= data[byteIndex + 1] << bitInByte;
}
return (byte) (value & mask);
}
}
public byte getAsync(int index)
{
int bitIndex = index * depth;
int byteIndex = bitIndex >> 3;
int bitInByte = bitIndex & 7;
int value = data[byteIndex] >> bitInByte;
if(bitInByte + depth > 8)
{
value |= data[byteIndex + 1] << bitInByte;
}
return (byte) (value & mask);
}
private transient int bitIndex, byteIndex, bitInByte;
public void set(int index, int nibble)
{
set(index, (byte) nibble);
}
public void set(int index, byte nybble)
{
synchronized(lock)
{
bitIndex = index * depth;
byteIndex = bitIndex >> 3;
bitInByte = bitIndex & 7;
data[byteIndex] = (byte) (((~(data[byteIndex] & (mask << bitInByte)) & data[byteIndex]) | ((nybble & mask) << bitInByte)) & 0xff);
if(bitInByte + depth > 8)
{
data[byteIndex + 1] = (byte) (((~(data[byteIndex + 1] & MASKS[bitInByte + depth - 8]) & data[byteIndex + 1]) | ((nybble & mask) >> (8 - bitInByte))) & 0xff);
}
}
}
public String toBitsString()
{
return toBitsString(ByteOrder.BIG_ENDIAN);
}
public String toBitsString(ByteOrder byteOrder)
{
StringJoiner joiner = new StringJoiner(" ");
for(int i = 0; i < data.length; i++)
{
joiner.add(binaryString(data[i], byteOrder));
}
return joiner.toString();
}
public void clear()
{
Arrays.fill(data, (byte) 0);
}
public void setAll(byte nibble)
{
for(int i = 0; i < size; i++)
{
set(i, nibble);
}
}
public void setAll(int nibble)
{
for(int i = 0; i < size; i++)
{
set(i, (byte) nibble);
}
}
public static int maskFor(int amountOfBits)
{
return powerOfTwo(amountOfBits) - 1;
}
public static int powerOfTwo(int power)
{
int result = 1;
for(int i = 0; i < power; i++)
{
result *= 2;
}
return result;
}
private static final int[] MASKS = new int[8];
static
{
for(int i = 0; i < MASKS.length; i++)
{
MASKS[i] = maskFor(i);
}
}
public static String binaryString(byte b, ByteOrder byteOrder)
{
String str = String.format("%8s", Integer.toBinaryString(b & 0xff)).replace(' ', '0');
return byteOrder.equals(ByteOrder.BIG_ENDIAN) ? str : reverse(str);
}
public static String reverse(String str)
{
return new StringBuilder(str).reverse().toString();
}
}

View File

@ -0,0 +1,12 @@
package com.volmit.iris.util;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public interface Writable
{
public void write(DataOutputStream o) throws IOException;
public void read(DataInputStream i) throws IOException;
}