diff --git a/.idea/workspace.xml b/.idea/workspace.xml index d396dbfb4..74dc108f7 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -14,8 +14,8 @@ @@ -48,6 +48,7 @@ + @@ -113,14 +114,14 @@ - + - - + + - + @@ -141,9 +142,9 @@ - + - + \ No newline at end of file diff --git a/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/io/HunkCompoundRegion.java b/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/io/HunkCompoundRegion.java deleted file mode 100644 index 9efe846cf..000000000 --- a/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/io/HunkCompoundRegion.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.volmit.iris.gen.v2.scaffold.hunk.io; - -import java.io.File; -import java.io.IOException; - -import org.bukkit.block.data.BlockData; - -import com.volmit.iris.util.CompoundTag; - -import lombok.Getter; - -public class HunkCompoundRegion extends HunkRegion -{ - @Getter - private HunkRegionSlice blockSlice; - @Getter - private HunkRegionSlice objectSlice; - @Getter - private HunkRegionSlice updateSlice; - - private final int height; - - public HunkCompoundRegion(int height, File folder, int x, int z, CompoundTag compound) - { - super(folder, x, z, compound); - this.height = height; - setupSlices(); - } - - public HunkCompoundRegion(int height, File folder, int x, int z) - { - super(folder, x, z); - this.height = height; - setupSlices(); - } - - private void setupSlices() - { - blockSlice = HunkRegionSlice.BLOCKDATA.apply(height, getCompound()); - objectSlice = HunkRegionSlice.STRING.apply(height, getCompound(), "objects"); - updateSlice = HunkRegionSlice.BOOLEAN.apply(height, getCompound(), "updates"); - } - - public void save() throws IOException - { - blockSlice.save(); - objectSlice.save(); - updateSlice.save(); - super.save(); - } - - public void unload() - { - blockSlice.unloadAll(); - objectSlice.unloadAll(); - updateSlice.unloadAll(); - } -} diff --git a/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/io/HunkRegion.java b/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/io/HunkRegion.java index c8b30e7b6..c0b91cbd5 100644 --- a/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/io/HunkRegion.java +++ b/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/io/HunkRegion.java @@ -15,7 +15,6 @@ import com.volmit.iris.util.Tag; import lombok.Data; -@Data public class HunkRegion { private final File folder; @@ -53,6 +52,10 @@ public class HunkRegion } } + public CompoundTag getCompound() { + return compound; + } + private CompoundTag fix(CompoundTag readTag) { Map v = readTag.getValue(); @@ -82,4 +85,12 @@ public class HunkRegion Iris.verbose("Saved Region: " + getX() + " " + getZ()); } } + + public int getX() { + return x; + } + public int getZ() { + return z; + } + } diff --git a/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/io/HunkRegionSlice.java b/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/io/HunkRegionSlice.java index cb85b9ced..5e647934c 100644 --- a/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/io/HunkRegionSlice.java +++ b/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/io/HunkRegionSlice.java @@ -2,17 +2,11 @@ package com.volmit.iris.gen.v2.scaffold.hunk.io; import java.io.IOException; +import com.volmit.iris.util.*; import org.bukkit.block.data.BlockData; import com.volmit.iris.Iris; import com.volmit.iris.gen.v2.scaffold.hunk.Hunk; -import com.volmit.iris.util.ByteArrayTag; -import com.volmit.iris.util.CompoundTag; -import com.volmit.iris.util.Function2; -import com.volmit.iris.util.Function3; -import com.volmit.iris.util.KList; -import com.volmit.iris.util.KMap; -import com.volmit.iris.util.Tag; public class HunkRegionSlice { @@ -24,6 +18,7 @@ public class HunkRegionSlice private final CompoundTag compound; private final String key; private final KMap> loadedChunks; + private final KMap lastUse; private final KList save; private final int height; @@ -36,6 +31,23 @@ public class HunkRegionSlice this.compound = compound; this.save = new KList<>(); this.key = key; + this.lastUse = new KMap<>(); + } + + public void cleanup(long t) + { + if(loadedChunks.size() != lastUse.size()) + { + Iris.warn("Incorrect chunk use counts in " + key); + } + + for(Short i : lastUse.k()) + { + if(M.ms() - lastUse.get(i) > t) + { + unload((byte) (i & 0xFF), (byte) ((i >> 8) & 0xFF)); + } + } } public void clear() @@ -99,6 +111,7 @@ public class HunkRegionSlice save.clear(); loadedChunks.clear(); + lastUse.clear(); } public synchronized void save(Hunk region, int x, int z) @@ -138,6 +151,7 @@ public class HunkRegionSlice save.remove(key); } + lastUse.remove(key); loadedChunks.remove(key); } } @@ -168,6 +182,7 @@ public class HunkRegionSlice { v = factory.apply(16, height, 16); } + loadedChunks.put(ikey(x, z), v); return v; @@ -184,6 +199,8 @@ public class HunkRegionSlice c = load(x, z); } + lastUse.put(ikey(x,z), M.ms()); + return c; } diff --git a/src/main/java/com/volmit/iris/gen/v2/scaffold/parallax/ParallaxAccess.java b/src/main/java/com/volmit/iris/gen/v2/scaffold/parallax/ParallaxAccess.java index 1bd20bbc4..437821836 100644 --- a/src/main/java/com/volmit/iris/gen/v2/scaffold/parallax/ParallaxAccess.java +++ b/src/main/java/com/volmit/iris/gen/v2/scaffold/parallax/ParallaxAccess.java @@ -40,6 +40,31 @@ public interface ParallaxAccess getUpdatesRW(x>>4, z>>4).set(x&15, y, z&15, d); } + default boolean isParallaxGenerated(int x, int z) + { + return getMetaR(x,z).isParallaxGenerated(); + } + + default boolean isChunkGenerated(int x, int z) { + return getMetaR(x, z).isGenerated(); + } + + default void setParallaxGenerated(int x, int z) { + setParallaxGenerated(x,z,true); + } + + default void setChunkGenerated(int x, int z) { + setChunkGenerated(x,z,true); + } + + default void setParallaxGenerated(int x, int z, boolean v) { + getMetaRW(x, z).setParallaxGenerated(v); + } + + default void setChunkGenerated(int x, int z, boolean v) { + getMetaRW(x, z).setGenerated(v); + } + public Hunk getBlocksR(int x, int z); public Hunk getBlocksRW(int x, int z); @@ -51,4 +76,16 @@ public interface ParallaxAccess public Hunk getUpdatesR(int x, int z); public Hunk getUpdatesRW(int x, int z); + + public ParallaxChunkMeta getMetaR(int x, int z); + + public ParallaxChunkMeta getMetaRW(int x, int z); + + public void cleanup(long regionIdle, long chunkIdle); + + public void cleanup(); + + public void saveAll(); + + public void saveAllNOW(); } diff --git a/src/main/java/com/volmit/iris/gen/v2/scaffold/parallax/ParallaxChunkMeta.java b/src/main/java/com/volmit/iris/gen/v2/scaffold/parallax/ParallaxChunkMeta.java new file mode 100644 index 000000000..f875ad65b --- /dev/null +++ b/src/main/java/com/volmit/iris/gen/v2/scaffold/parallax/ParallaxChunkMeta.java @@ -0,0 +1,37 @@ +package com.volmit.iris.gen.v2.scaffold.parallax; + +import com.sun.tools.javac.code.Attribute; +import com.volmit.iris.gen.v2.scaffold.hunk.io.HunkIOAdapter; +import com.volmit.iris.gen.v2.scaffold.hunk.io.PaletteHunkIOAdapter; +import com.volmit.iris.util.CompoundTag; +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.function.Function; + +@AllArgsConstructor +@Data +public class ParallaxChunkMeta { + public static final Function> adapter = (c) -> new PaletteHunkIOAdapter() { + @Override + public void write(ParallaxChunkMeta parallaxChunkMeta, DataOutputStream dos) throws IOException { + dos.writeBoolean(parallaxChunkMeta.isGenerated()); + dos.writeBoolean(parallaxChunkMeta.isParallaxGenerated()); + } + + @Override + public ParallaxChunkMeta read(DataInputStream din) throws IOException { + return new ParallaxChunkMeta(din.readBoolean(), din.readBoolean()); + } + }; + private boolean generated; + private boolean parallaxGenerated; + + public ParallaxChunkMeta() + { + this(false, false); + } +} diff --git a/src/main/java/com/volmit/iris/gen/v2/scaffold/parallax/ParallaxRegion.java b/src/main/java/com/volmit/iris/gen/v2/scaffold/parallax/ParallaxRegion.java new file mode 100644 index 000000000..c9766275d --- /dev/null +++ b/src/main/java/com/volmit/iris/gen/v2/scaffold/parallax/ParallaxRegion.java @@ -0,0 +1,179 @@ +package com.volmit.iris.gen.v2.scaffold.parallax; + +import java.io.File; +import java.io.IOException; + +import com.volmit.iris.gen.v2.scaffold.hunk.Hunk; +import com.volmit.iris.gen.v2.scaffold.hunk.io.HunkIOAdapter; +import com.volmit.iris.gen.v2.scaffold.hunk.io.HunkRegion; +import com.volmit.iris.gen.v2.scaffold.hunk.io.HunkRegionSlice; +import com.volmit.iris.util.*; +import javassist.bytecode.ByteArray; +import org.bukkit.block.data.BlockData; + +import lombok.Getter; + +public class ParallaxRegion extends HunkRegion +{ + private boolean dirtyMeta; + private Hunk meta; + private HunkIOAdapter metaAdapter; + private HunkRegionSlice blockSlice; + private HunkRegionSlice objectSlice; + private HunkRegionSlice updateSlice; + private long lastUse; + private final int height; + + public ParallaxRegion(int height, File folder, int x, int z, CompoundTag compound) + { + super(folder, x, z, compound); + this.height = height; + setupSlices(); + } + + public ParallaxRegion(int height, File folder, int x, int z) + { + super(folder, x, z); + this.height = height; + setupSlices(); + } + + private void setupSlices() + { + blockSlice = HunkRegionSlice.BLOCKDATA.apply(height, getCompound()); + objectSlice = HunkRegionSlice.STRING.apply(height, getCompound(), "objects"); + updateSlice = HunkRegionSlice.BOOLEAN.apply(height, getCompound(), "updates"); + metaAdapter = ParallaxChunkMeta.adapter.apply(getCompound()); + dirtyMeta = false; + meta = null; + lastUse = M.ms(); + } + + public boolean hasBeenIdleLongerThan(long time) + { + return M.ms() - lastUse > time; + } + + public ParallaxChunkMeta getMetaR(int x, int z) + { + lastUse = M.ms(); + return getMetaHunkR().getOr(x, 0, z, new ParallaxChunkMeta()); + } + + public ParallaxChunkMeta getMetaRW(int x, int z) + { + lastUse = M.ms(); + dirtyMeta = true; + ParallaxChunkMeta p = getMetaHunkRW().get(x, 0, z); + if(p == null) + { + p = new ParallaxChunkMeta(); + getMetaHunkRW().set(x,0,z,p); + } + + return p; + } + + private Hunk getMetaHunkR() + { + if(meta == null) + { + meta = loadMetaHunk(); + } + + return meta; + } + + private Hunk getMetaHunkRW() + { + dirtyMeta = true; + return getMetaHunkR(); + } + + public synchronized Hunk loadMetaHunk() + { + lastUse = M.ms(); + if(meta == null) + { + Tag t = getCompound().getValue().get("meta"); + + if((t instanceof ByteArrayTag)) + { + try { + meta = metaAdapter.read((x,y,z) -> Hunk.newArrayHunk(32, 1, 32), (ByteArrayTag)t); + } catch (IOException e) { + e.printStackTrace(); + } + } + + if(meta == null) + { + meta = Hunk.newArrayHunk(32, 1, 32); + } + } + + return meta; + } + + public synchronized void unloadMetaHunk() + { + if(dirtyMeta) + { + saveMetaHunk(); + dirtyMeta = false; + } + + meta = null; + } + + public synchronized void saveMetaHunk() + { + if(meta != null && dirtyMeta) + { + try { + getCompound().getValue().put("meta", meta.writeByteArrayTag(metaAdapter, "meta")); + dirtyMeta = false; + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + public void save() throws IOException + { + blockSlice.save(); + objectSlice.save(); + updateSlice.save(); + saveMetaHunk(); + super.save(); + } + + public void unload() + { + blockSlice.unloadAll(); + objectSlice.unloadAll(); + updateSlice.unloadAll(); + unloadMetaHunk(); + } + + public HunkRegionSlice getBlockSlice() { + lastUse = M.ms(); + return blockSlice; + } + + public HunkRegionSlice getObjectSlice() { + lastUse = M.ms(); + return objectSlice; + } + + public HunkRegionSlice getUpdateSlice() { + lastUse = M.ms(); + return updateSlice; + } + + public void cleanup(long c) { + blockSlice.cleanup(c); + objectSlice.cleanup(c); + updateSlice.cleanup(c); + } +} diff --git a/src/main/java/com/volmit/iris/gen/v2/scaffold/parallax/ParallaxWorld.java b/src/main/java/com/volmit/iris/gen/v2/scaffold/parallax/ParallaxWorld.java index 78f81e3c9..eaaaec11e 100644 --- a/src/main/java/com/volmit/iris/gen/v2/scaffold/parallax/ParallaxWorld.java +++ b/src/main/java/com/volmit/iris/gen/v2/scaffold/parallax/ParallaxWorld.java @@ -3,19 +3,18 @@ package com.volmit.iris.gen.v2.scaffold.parallax; import java.io.File; import java.io.IOException; +import com.volmit.iris.util.*; import org.bukkit.block.data.BlockData; import com.volmit.iris.gen.v2.scaffold.hunk.Hunk; -import com.volmit.iris.gen.v2.scaffold.hunk.io.HunkCompoundRegion; -import com.volmit.iris.util.KList; -import com.volmit.iris.util.KMap; public class ParallaxWorld implements ParallaxAccess { - private final KMap loadedRegions; + private final KMap loadedRegions; private final KList save; private final File folder; private final int height; + private final ChronoLatch cleanup; public ParallaxWorld(int height, File folder) { @@ -23,12 +22,13 @@ public class ParallaxWorld implements ParallaxAccess this.folder = folder; save = new KList<>(); loadedRegions = new KMap<>(); + cleanup = new ChronoLatch(10000); folder.mkdirs(); } public synchronized void close() { - for(HunkCompoundRegion i : loadedRegions.v()) + for(ParallaxRegion i : loadedRegions.v()) { unload(i.getX(), i.getZ()); } @@ -37,7 +37,7 @@ public class ParallaxWorld implements ParallaxAccess loadedRegions.clear(); } - public synchronized void save(HunkCompoundRegion region) + public synchronized void save(ParallaxRegion region) { try { @@ -79,23 +79,29 @@ public class ParallaxWorld implements ParallaxAccess } } - public synchronized HunkCompoundRegion load(int x, int z) + public synchronized ParallaxRegion load(int x, int z) { if(isLoaded(x, z)) { return loadedRegions.get(key(x, z)); } - HunkCompoundRegion v = new HunkCompoundRegion(height, folder, x, z); + ParallaxRegion v = new ParallaxRegion(height, folder, x, z); loadedRegions.put(key(x, z), v); + + if(cleanup.flip()) + { + cleanup(); + } + return v; } - public HunkCompoundRegion getR(int x, int z) + public ParallaxRegion getR(int x, int z) { long key = key(x, z); - HunkCompoundRegion region = loadedRegions.get(key); + ParallaxRegion region = loadedRegions.get(key); if(region == null) { @@ -105,7 +111,7 @@ public class ParallaxWorld implements ParallaxAccess return region; } - public HunkCompoundRegion getRW(int x, int z) + public ParallaxRegion getRW(int x, int z) { save.addIfMissing(key(x, z)); return getR(x, z); @@ -151,4 +157,64 @@ public class ParallaxWorld implements ParallaxAccess { return getRW(x >> 5, z >> 5).getUpdateSlice().getRW(x & 31, z & 31); } + + @Override + public ParallaxChunkMeta getMetaR(int x, int z) + { + return getR(x >> 5, z >> 5).getMetaR(x & 31, z & 31); + } + + @Override + public ParallaxChunkMeta getMetaRW(int x, int z) + { + return getRW(x >> 5, z >> 5).getMetaRW(x & 31, z & 31); + } + + public void cleanup() + { + cleanup(30000, 10000); + } + + @Override + public void cleanup(long r, long c) { + J.a(() -> { + synchronized (loadedRegions) + { + for(ParallaxRegion i : loadedRegions.v()) + { + if(i.hasBeenIdleLongerThan(r)) + { + unload(i.getX(), i.getZ()); + } + + else + { + i.cleanup(c); + } + } + } + }); + } + + @Override + public void saveAll() { + J.a(this::saveAllNOW); + } + + @Override + public synchronized void saveAllNOW() { + synchronized (loadedRegions) + { + for(ParallaxRegion i : loadedRegions.v()) + { + synchronized (save) + { + if(save.contains(key(i.getX(), i.getZ()))) + { + save(i.getX(), i.getZ()); + } + } + } + } + } }