Merge remote-tracking branch 'upstream/master' into saplingOverrides

This commit is contained in:
CocoTheOwner 2021-07-18 11:10:42 +02:00
commit 20b3e95b4f
13 changed files with 283 additions and 163 deletions

View File

@ -5,7 +5,7 @@ plugins {
} }
group 'com.volmit.iris' group 'com.volmit.iris'
version '1.5.1' version '1.5.2'
def apiVersion = '1.17' def apiVersion = '1.17'
def name = 'Iris' def name = 'Iris'
def main = 'com.volmit.iris.Iris' def main = 'com.volmit.iris.Iris'

View File

@ -20,7 +20,7 @@ package com.volmit.iris.core;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.engine.data.DirectWorldWriter; import com.volmit.iris.engine.data.mca.NBTWorld;
import com.volmit.iris.engine.data.nbt.io.NBTUtil; import com.volmit.iris.engine.data.nbt.io.NBTUtil;
import com.volmit.iris.engine.data.nbt.io.NamedTag; import com.volmit.iris.engine.data.nbt.io.NamedTag;
import com.volmit.iris.engine.data.nbt.tag.CompoundTag; import com.volmit.iris.engine.data.nbt.tag.CompoundTag;
@ -151,7 +151,7 @@ public class ConversionManager {
@SuppressWarnings("unchecked") ListTag<CompoundTag> paletteList = (ListTag<CompoundTag>) compound.getListTag("palette"); @SuppressWarnings("unchecked") ListTag<CompoundTag> paletteList = (ListTag<CompoundTag>) compound.getListTag("palette");
for (int i = 0; i < paletteList.size(); i++) { for (int i = 0; i < paletteList.size(); i++) {
CompoundTag cp = paletteList.get(i); CompoundTag cp = paletteList.get(i);
palette.add(DirectWorldWriter.getBlockData(cp)); palette.add(NBTWorld.getBlockData(cp));
} }
IrisJigsawPiece piece = new IrisJigsawPiece(); IrisJigsawPiece piece = new IrisJigsawPiece();
IrisObject object = new IrisObject(w, h, d); IrisObject object = new IrisObject(w, h, d);
@ -171,7 +171,7 @@ public class ConversionManager {
CompoundTag finalState = new CompoundTag(); CompoundTag finalState = new CompoundTag();
finalState.putString("Name", nbt.getString("final_state")); finalState.putString("Name", nbt.getString("final_state"));
BlockData jd = bd.clone(); BlockData jd = bd.clone();
bd = DirectWorldWriter.getBlockData(finalState); bd = NBTWorld.getBlockData(finalState);
String joint = nbt.getString("joint"); String joint = nbt.getString("joint");
String pool = nbt.getString("pool"); String pool = nbt.getString("pool");
String poolId = toPoolName(pool); String poolId = toPoolName(pool);

View File

@ -21,8 +21,8 @@ package com.volmit.iris.core.gui;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings; import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.engine.IrisWorlds; import com.volmit.iris.engine.IrisWorlds;
import com.volmit.iris.engine.data.DirectWorldWriter;
import com.volmit.iris.engine.data.mca.MCAFile; import com.volmit.iris.engine.data.mca.MCAFile;
import com.volmit.iris.engine.data.mca.NBTWorld;
import com.volmit.iris.engine.framework.IrisAccess; import com.volmit.iris.engine.framework.IrisAccess;
import com.volmit.iris.engine.parallel.BurstExecutor; import com.volmit.iris.engine.parallel.BurstExecutor;
import com.volmit.iris.engine.parallel.MultiBurst; import com.volmit.iris.engine.parallel.MultiBurst;
@ -77,7 +77,7 @@ public class Pregenerator implements Listener {
private static final Color COLOR_MCA_DEFERRED = Color.decode("#3CB57A"); private static final Color COLOR_MCA_DEFERRED = Color.decode("#3CB57A");
private final World world; private final World world;
private int lowestBedrock; private int lowestBedrock;
private final DirectWorldWriter directWriter; private final NBTWorld directWriter;
private final AtomicBoolean active; private final AtomicBoolean active;
private final AtomicBoolean running; private final AtomicBoolean running;
private final KList<ChunkPosition> errors; private final KList<ChunkPosition> errors;
@ -89,6 +89,7 @@ public class Pregenerator implements Listener {
private final AtomicInteger generated; private final AtomicInteger generated;
private final AtomicInteger generatedLast; private final AtomicInteger generatedLast;
private final RollingSequence perSecond; private final RollingSequence perSecond;
private final RollingSequence perMinute;
private final AtomicInteger totalChunks; private final AtomicInteger totalChunks;
private final AtomicLong memory; private final AtomicLong memory;
private final AtomicReference<String> memoryMetric; private final AtomicReference<String> memoryMetric;
@ -125,16 +126,17 @@ public class Pregenerator implements Listener {
vmcaz = new AtomicInteger(); vmcaz = new AtomicInteger();
vcax = new AtomicInteger(); vcax = new AtomicInteger();
vcaz = new AtomicInteger(); vcaz = new AtomicInteger();
perMinute = new RollingSequence(200);
perSecond = new RollingSequence(20); perSecond = new RollingSequence(20);
generatedLast = new AtomicInteger(0); generatedLast = new AtomicInteger(0);
totalChunks = new AtomicInteger(0); totalChunks = new AtomicInteger(0);
generated = new AtomicInteger(0); generated = new AtomicInteger(0);
mcaDefer = new KList<>(); mcaDefer = new KList<>();
access = IrisWorlds.access(world); access = IrisWorlds.access(world);
this.directWriter = new DirectWorldWriter(world.getWorldFolder()); this.directWriter = new NBTWorld(world.getWorldFolder());
this.running = new AtomicBoolean(true); this.running = new AtomicBoolean(true);
this.active = new AtomicBoolean(true); this.active = new AtomicBoolean(true);
MultiBurst burst = new MultiBurst("Iris Pregenerator", 9, Runtime.getRuntime().availableProcessors() + 4); MultiBurst burst = new MultiBurst("Iris Pregenerator", 9, Runtime.getRuntime().availableProcessors());
int mcaSize = (((blockSize >> 4) + 2) >> 5) + 1; int mcaSize = (((blockSize >> 4) + 2) >> 5) + 1;
onComplete = new KList<>(); onComplete = new KList<>();
max = new ChunkPosition(0, 0); max = new ChunkPosition(0, 0);
@ -196,7 +198,7 @@ public class Pregenerator implements Listener {
} }
burst.shutdownNow(); burst.shutdownNow();
directWriter.flush(); directWriter.close();
flushWorld(); flushWorld();
onComplete.forEach(Runnable::run); onComplete.forEach(Runnable::run);
running.set(false); running.set(false);
@ -214,6 +216,7 @@ public class Pregenerator implements Listener {
int up = m - w; int up = m - w;
double dur = p.getMilliseconds(); double dur = p.getMilliseconds();
perSecond.put((int) (up / (dur / 1000D))); perSecond.put((int) (up / (dur / 1000D)));
perSecond.put((int) (up / (dur / 60000D)));
p.reset(); p.reset();
p.begin(); p.begin();
updateProgress(); updateProgress();
@ -239,8 +242,7 @@ public class Pregenerator implements Listener {
return false; return false;
} }
File mca = new File(world.getWorldFolder(), "region/r." + x + "." + z + ".mca"); File mca = directWriter.getRegionFile(x, z);
File mcg = directWriter.getMCAFile(x, z);
BurstExecutor e = burst.burst(1024); BurstExecutor e = burst.burst(1024);
int mcaox = x << 5; int mcaox = x << 5;
int mcaoz = z << 5; int mcaoz = z << 5;
@ -255,9 +257,8 @@ public class Pregenerator implements Listener {
vcaz.set(jj); vcaz.set(jj);
})); }));
e.complete(); e.complete();
verifyMCA(x, z, burst); //verifyMCA(x, z, burst);
directWriter.flush(); directWriter.save();
install(mcg, mca);
} else { } else {
totalChunks.getAndAdd(1024); totalChunks.getAndAdd(1024);
mcaDefer.add(new ChunkPosition(x, z)); mcaDefer.add(new ChunkPosition(x, z));
@ -299,27 +300,6 @@ public class Pregenerator implements Listener {
} }
} }
private boolean install(File from, File to) {
try {
Files.move(from.toPath(), to.toPath());
return true;
} catch (Throwable e) {
Iris.reportError(e);
}
try {
IO.copyFile(from, to);
from.delete();
return true;
} catch (IOException e) {
Iris.reportError(e);
}
return false;
}
public void updateProgress() { public void updateProgress() {
if (!latch.flip()) { if (!latch.flip()) {
return; return;
@ -335,7 +315,7 @@ public class Pregenerator implements Listener {
if (PaperLib.isPaper()) { if (PaperLib.isPaper()) {
method.set("PaperAsync (Slow)"); method.set("PaperAsync (Slow)");
while (wait.size() > 32) { while (wait.size() > 16) {
J.sleep(5); J.sleep(5);
} }
@ -509,7 +489,8 @@ public class Pregenerator implements Listener {
return new String[]{ return new String[]{
"Progress: " + Form.f(generated.get()) + " of " + Form.f(totalChunks.get()) + " (" + Form.pc((double) generated.get() / (double) totalChunks.get(), 0) + ")", "Progress: " + Form.f(generated.get()) + " of " + Form.f(totalChunks.get()) + " (" + Form.pc((double) generated.get() / (double) totalChunks.get(), 0) + ")",
"ETA: " + Form.duration(eta, 0), "ETA: " + Form.duration(eta, 0),
"Chunks/s: " + Form.f((int) perSecond.getAverage()), "Chunks/s: " + Form.f((int) perSecond.getAverage()) + " (" + Form.f((int)perSecond.getMax()) + " Peak)",
"Chunks/min: " + Form.f((int) perMinute.getAverage())+ " (" + Form.f((int)perMinute.getMax()) + " Peak)",
"Memory: " + memoryMetric.get(), "Memory: " + memoryMetric.get(),
"Cursor: " + "MCA(" + vmcax.get() + ", " + vmcaz.get() + ") @ (" + vcax.get() + ", " + vcaz.get() + ")", "Cursor: " + "MCA(" + vmcax.get() + ", " + vmcaz.get() + ") @ (" + vcax.get() + ", " + vcaz.get() + ")",
"Gen Mode: " + method.get(), "Gen Mode: " + method.get(),

View File

@ -197,10 +197,15 @@ public class IrisComplex implements DataProvider {
}, Interpolated.DOUBLE).cache2D(cacheSize); }, Interpolated.DOUBLE).cache2D(cacheSize);
slopeStream = heightStream.slope(3).interpolate().bilinear(3, 3).cache2D(cacheSize); slopeStream = heightStream.slope(3).interpolate().bilinear(3, 3).cache2D(cacheSize);
objectChanceStream = ProceduralStream.ofDouble((x, z) -> { objectChanceStream = ProceduralStream.ofDouble((x, z) -> {
AtomicDouble str = new AtomicDouble(1D); if(engine.getDimension().hasFeatures(engine))
engine.getFramework().getEngineParallax().forEachFeature(x, z, (i) {
-> str.set(Math.min(str.get(), i.getObjectChanceModifier(x, z)))); AtomicDouble str = new AtomicDouble(1D);
return str.get(); engine.getFramework().getEngineParallax().forEachFeature(x, z, (i)
-> str.set(Math.min(str.get(), i.getObjectChanceModifier(x, z))));
return str.get();
}
return 1D;
}); });
trueBiomeStream = focus != null ? ProceduralStream.of((x, y) -> focus, Interpolated.of(a -> 0D, trueBiomeStream = focus != null ? ProceduralStream.of((x, y) -> focus, Interpolated.of(a -> 0D,

View File

@ -162,22 +162,21 @@ public class IrisEngine extends BlockPopulator implements Engine {
public void generate(int x, int z, Hunk<BlockData> vblocks, Hunk<Biome> vbiomes) { public void generate(int x, int z, Hunk<BlockData> vblocks, Hunk<Biome> vbiomes) {
try { try {
PrecisionStopwatch p = PrecisionStopwatch.start(); PrecisionStopwatch p = PrecisionStopwatch.start();
Hunk<BlockData> blocks = vblocks;
switch (getDimension().getTerrainMode()) { switch (getDimension().getTerrainMode()) {
case NORMAL -> { case NORMAL -> {
getFramework().getEngineParallax().generateParallaxArea(x >> 4, z >> 4); getFramework().getEngineParallax().generateParallaxArea(x >> 4, z >> 4);
getFramework().getBiomeActuator().actuate(x, z, vbiomes); getFramework().getBiomeActuator().actuate(x, z, vbiomes);
getFramework().getTerrainActuator().actuate(x, z, blocks); getFramework().getTerrainActuator().actuate(x, z, vblocks);
getFramework().getCaveModifier().modify(x, z, blocks); getFramework().getCaveModifier().modify(x, z, vblocks);
getFramework().getRavineModifier().modify(x, z, blocks); getFramework().getRavineModifier().modify(x, z, vblocks);
getFramework().getPostModifier().modify(x, z, blocks); getFramework().getPostModifier().modify(x, z, vblocks);
getFramework().getDecorantActuator().actuate(x, z, blocks); getFramework().getDecorantActuator().actuate(x, z, vblocks);
getFramework().getEngineParallax().insertParallax(x, z, blocks); getFramework().getEngineParallax().insertParallax(x, z, vblocks);
getFramework().getDepositModifier().modify(x, z, blocks); getFramework().getDepositModifier().modify(x, z, vblocks);
} }
case ISLANDS -> { case ISLANDS -> {
getFramework().getTerrainActuator().actuate(x, z, blocks); getFramework().getTerrainActuator().actuate(x, z, vblocks);
} }
} }
getMetrics().getTotal().put(p.getMilliseconds()); getMetrics().getTotal().put(p.getMilliseconds());

View File

@ -22,6 +22,7 @@ import com.volmit.iris.engine.data.nbt.tag.CompoundTag;
import java.io.IOException; import java.io.IOException;
import java.io.RandomAccessFile; import java.io.RandomAccessFile;
import java.util.concurrent.atomic.AtomicReferenceArray;
@SuppressWarnings("ALL") @SuppressWarnings("ALL")
public class MCAFile { public class MCAFile {
@ -33,7 +34,7 @@ public class MCAFile {
private final int regionX; private final int regionX;
private final int regionZ; private final int regionZ;
private Chunk[] chunks; private AtomicReferenceArray<Chunk> chunks;
/** /**
* MCAFile represents a world save file used by Minecraft to store world * MCAFile represents a world save file used by Minecraft to store world
@ -69,7 +70,7 @@ public class MCAFile {
* @throws IOException If something went wrong during deserialization. * @throws IOException If something went wrong during deserialization.
*/ */
public void deserialize(RandomAccessFile raf, long loadFlags) throws IOException { public void deserialize(RandomAccessFile raf, long loadFlags) throws IOException {
chunks = new Chunk[1024]; chunks = new AtomicReferenceArray<>(1024);
for (int i = 0; i < 1024; i++) { for (int i = 0; i < 1024; i++) {
raf.seek(i * 4); raf.seek(i * 4);
int offset = raf.read() << 16; int offset = raf.read() << 16;
@ -83,11 +84,11 @@ public class MCAFile {
Chunk chunk = new Chunk(timestamp); Chunk chunk = new Chunk(timestamp);
raf.seek(4096L * offset + 4); //+4: skip data size raf.seek(4096L * offset + 4); //+4: skip data size
chunk.deserialize(raf, loadFlags); chunk.deserialize(raf, loadFlags);
chunks[i] = chunk; chunks.set(i, chunk);
} }
} }
public Chunk[] getChunks() { public AtomicReferenceArray<Chunk> getChunks() {
return chunks; return chunks;
} }
@ -128,7 +129,7 @@ public class MCAFile {
for (int cx = 0; cx < 32; cx++) { for (int cx = 0; cx < 32; cx++) {
for (int cz = 0; cz < 32; cz++) { for (int cz = 0; cz < 32; cz++) {
int index = getChunkIndex(cx, cz); int index = getChunkIndex(cx, cz);
Chunk chunk = chunks[index]; Chunk chunk = chunks.get(index);
if (chunk == null) { if (chunk == null) {
continue; continue;
} }
@ -175,9 +176,9 @@ public class MCAFile {
public void setChunk(int index, Chunk chunk) { public void setChunk(int index, Chunk chunk) {
checkIndex(index); checkIndex(index);
if (chunks == null) { if (chunks == null) {
chunks = new Chunk[1024]; chunks = new AtomicReferenceArray<>(1024);
} }
chunks[index] = chunk; chunks.set(index, chunk);
} }
/** /**
@ -203,7 +204,7 @@ public class MCAFile {
if (chunks == null) { if (chunks == null) {
return null; return null;
} }
return chunks[index]; return chunks.get(index);
} }
/** /**
@ -217,6 +218,11 @@ public class MCAFile {
return getChunk(getChunkIndex(chunkX, chunkZ)); return getChunk(getChunkIndex(chunkX, chunkZ));
} }
public boolean hasChunk(int chunkX, int chunkZ)
{
return getChunk(chunkX, chunkZ) != null;
}
/** /**
* Calculates the index of a chunk from its x- and z-coordinates in this region. * Calculates the index of a chunk from its x- and z-coordinates in this region.
* This works with absolute and relative coordinates. * This works with absolute and relative coordinates.
@ -319,15 +325,4 @@ public class MCAFile {
} }
return chunk.getBlockStateAt(blockX, blockY, blockZ); return chunk.getBlockStateAt(blockX, blockY, blockZ);
} }
/**
* Recalculates the Palette and the BlockStates of all chunks and sections of this region.
*/
public void cleanupPalettesAndBlockStates() {
for (Chunk chunk : chunks) {
if (chunk != null) {
chunk.cleanupPalettesAndBlockStates();
}
}
}
} }

View File

@ -16,75 +16,160 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.volmit.iris.engine.data; package com.volmit.iris.engine.data.mca;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.engine.cache.Cache; import com.volmit.iris.engine.cache.Cache;
import com.volmit.iris.engine.data.mca.Chunk; import com.volmit.iris.engine.data.B;
import com.volmit.iris.engine.data.mca.MCAFile;
import com.volmit.iris.engine.data.mca.MCAUtil;
import com.volmit.iris.engine.data.mca.Section;
import com.volmit.iris.engine.data.nbt.tag.CompoundTag; import com.volmit.iris.engine.data.nbt.tag.CompoundTag;
import com.volmit.iris.engine.data.nbt.tag.StringTag; import com.volmit.iris.engine.data.nbt.tag.StringTag;
import com.volmit.iris.engine.parallel.BurstExecutor;
import com.volmit.iris.engine.parallel.MultiBurst;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.scheduling.IrisLock;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.block.Biome; import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.jetbrains.annotations.NotNull;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.Map; import java.util.Map;
import java.util.concurrent.*;
@SuppressWarnings("EmptyMethod") public class NBTWorld {
public class DirectWorldWriter { private static final BlockData AIR = B.get("AIR");
private final File worldFolder;
private final Map<Long, MCAFile> writeBuffer;
private static final Map<String, CompoundTag> blockDataCache = new KMap<>(); private static final Map<String, CompoundTag> blockDataCache = new KMap<>();
private static final Map<Biome, Integer> biomeIds = computeBiomeIDs(); private static final Map<Biome, Integer> biomeIds = computeBiomeIDs();
private final IrisLock regionLock = new IrisLock("Region");
private final KMap<Long, MCAFile> loadedRegions;
private final KMap<Long, Long> lastUse;
private final File worldFolder;
private final ExecutorService saveQueue;
public DirectWorldWriter(File worldFolder) { public NBTWorld(File worldFolder)
{
this.worldFolder = worldFolder; this.worldFolder = worldFolder;
writeBuffer = new KMap<>(); this.loadedRegions = new KMap<>();
new File(worldFolder, "iris/mca-region").mkdirs(); this.lastUse = new KMap<>();
saveQueue = Executors.newSingleThreadExecutor(r -> {
Thread t = new Thread(r);
t.setName("Iris MCA Writer");
t.setPriority(Thread.MIN_PRIORITY);
return t;
});
} }
public void flush() { public void close()
BurstExecutor ex2 = MultiBurst.burst.burst(writeBuffer.size()); {
regionLock.lock();
for (Long i : new KList<>(writeBuffer.keySet())) { for(Long i : loadedRegions.k())
ex2.queue(() -> { {
int x = Cache.keyX(i); queueSaveUnload(Cache.keyX(i), Cache.keyZ(i));
int z = Cache.keyZ(i);
try {
File f = getMCAFile(x, z);
if (!f.exists()) {
f.getParentFile().mkdirs();
f.createNewFile();
}
MCAUtil.write(writeBuffer.get(i), f, true);
writeBuffer.remove(i);
} catch (Throwable e) {
Iris.reportError(e);
e.printStackTrace();
}
});
} }
ex2.complete(); regionLock.unlock();
saveQueue.shutdown();
try {
while(!saveQueue.awaitTermination(3, TimeUnit.SECONDS))
{
Iris.info("Still Waiting to save MCA Files...");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
} }
public void optimizeChunk(int x, int z) { public void queueSaveUnload(int x, int z)
getChunk(x, z).cleanupPalettesAndBlockStates(); {
saveQueue.submit(() -> {
MCAFile f = getMCAOrNull(x, z);
if(f != null)
{
unloadRegion(x, z);
}
saveRegion(x, z, f);
});
} }
public File getMCAFile(int x, int z) { public void save()
return new File(worldFolder, "iris/mca-region/r." + x + "." + z + ".mca"); {
regionLock.lock();
boolean saving = true;
for(Long i : loadedRegions.k())
{
int x = Cache.keyX(i);
int z = Cache.keyZ(i);
if(!lastUse.containsKey(i))
{
lastUse.put(i, M.ms());
}
if(shouldUnload(x, z))
{
queueSaveUnload(x, z);
}
}
Iris.debug("Regions: " + C.GOLD + loadedRegions.size() + C.LIGHT_PURPLE);
regionLock.unlock();
}
public void queueSave()
{
}
public synchronized void unloadRegion(int x, int z)
{
long key = Cache.key(x, z);
regionLock.lock();
loadedRegions.remove(key);
lastUse.remove(key);
regionLock.unlock();
Iris.debug("Unloaded Region " + C.GOLD + x + " " + z);
}
public void saveRegion(int x, int z)
{
long k = Cache.key(x, z);
MCAFile mca = getMCAOrNull(x, z);
try {
MCAUtil.write(mca, getRegionFile(x, z), true);
Iris.debug("Saved Region " + C.GOLD + x + " " + z);
} catch (IOException e) {
Iris.error("Failed to save region " + getRegionFile(x, z).getPath());
e.printStackTrace();
}
}
public void saveRegion(int x, int z, MCAFile mca)
{
try {
MCAUtil.write(mca, getRegionFile(x, z), true);
Iris.debug("Saved Region " + C.GOLD + x + " " + z);
} catch (IOException e) {
Iris.error("Failed to save region " + getRegionFile(x, z).getPath());
e.printStackTrace();
}
}
public boolean shouldUnload(int x, int z)
{
return getIdleDuration(x, z) > 60000;
}
public File getRegionFile(int x, int z) {
return new File(worldFolder, "region/r." + x + "." + z + ".mca");
} }
public static BlockData getBlockData(CompoundTag tag) { public static BlockData getBlockData(CompoundTag tag) {
@ -125,7 +210,6 @@ public class DirectWorldWriter {
NamespacedKey key = blockData.getMaterial().getKey(); NamespacedKey key = blockData.getMaterial().getKey();
s.putString("Name", key.getNamespace() + ":" + key.getKey()); s.putString("Name", key.getNamespace() + ":" + key.getKey());
if (data.contains("[")) { if (data.contains("[")) {
String raw = data.split("\\Q[\\E")[1].replaceAll("\\Q]\\E", ""); String raw = data.split("\\Q[\\E")[1].replaceAll("\\Q]\\E", "");
CompoundTag props = new CompoundTag(); CompoundTag props = new CompoundTag();
@ -154,7 +238,7 @@ public class DirectWorldWriter {
CompoundTag tag = getChunkSection(x >> 4, y >> 4, z >> 4).getBlockStateAt(x & 15, y & 15, z & 15); CompoundTag tag = getChunkSection(x >> 4, y >> 4, z >> 4).getBlockStateAt(x & 15, y & 15, z & 15);
if (tag == null) { if (tag == null) {
return B.get("AIR"); return AIR;
} }
return getBlockData(tag); return getBlockData(tag);
@ -162,7 +246,7 @@ public class DirectWorldWriter {
Iris.reportError(e); Iris.reportError(e);
} }
return B.get("AIR"); return AIR;
} }
public void setBlockData(int x, int y, int z, BlockData data) { public void setBlockData(int x, int y, int z, BlockData data) {
@ -185,10 +269,6 @@ public class DirectWorldWriter {
return s; return s;
} }
public void deleteChunk(int x, int z) {
}
public Chunk getChunk(int x, int z) { public Chunk getChunk(int x, int z) {
MCAFile mca = getMCA(x >> 5, z >> 5); MCAFile mca = getMCA(x >> 5, z >> 5);
Chunk c = mca.getChunk(x & 31, z & 31); Chunk c = mca.getChunk(x & 31, z & 31);
@ -201,28 +281,57 @@ public class DirectWorldWriter {
return c; return c;
} }
public long getIdleDuration(int x, int z)
{
Long l = lastUse.get(Cache.key(x, z));
return l == null ? 0 : (M.ms() - l);
}
public MCAFile getMCA(int x, int z) { public MCAFile getMCA(int x, int z) {
long key = Cache.key(x, z); long key = Cache.key(x, z);
MCAFile mca = writeBuffer.get(key);
if (mca != null) { regionLock.lock();
return mca; lastUse.put(key, M.ms());
MCAFile mcaf = loadedRegions.get(key);
regionLock.unlock();
if(mcaf == null)
{
File f = getRegionFile(x, z);
try {
mcaf = f.exists() ? MCAUtil.read(f) : new MCAFile(x, z);
} catch (IOException e) {
Iris.error("Failed to properly read MCA File " + f.getPath() + " Using a blank one.");
e.printStackTrace();
mcaf = new MCAFile(x, z);
}
regionLock.lock();
loadedRegions.put(key, mcaf);
regionLock.unlock();
} }
File f = getMCAFile(x, z); return mcaf;
try { }
mca = f.exists() ? MCAUtil.read(f) : new MCAFile(x, z);
} catch (IOException e) { public MCAFile getMCAOrNull(int x, int z) {
e.printStackTrace(); long key = Cache.key(x, z);
mca = new MCAFile(x, z); MCAFile ff = null;
regionLock.lock();
if(loadedRegions.containsKey(key))
{
lastUse.put(key, M.ms());
ff = loadedRegions.get(key);
} }
writeBuffer.put(key, mca); regionLock.unlock();
return mca; return ff;
} }
public int size() { public int size() {
return writeBuffer.size(); return loadedRegions.size();
} }
private static Map<Biome, Integer> computeBiomeIDs() { private static Map<Biome, Integer> computeBiomeIDs() {
@ -236,18 +345,4 @@ public class DirectWorldWriter {
return biomeIds; return biomeIds;
} }
public void verify(int mcaox, int mcaoz) {
MCAFile file = getMCA(mcaox, mcaoz);
for (int i = 0; i < 32; i++) {
for (int j = 0; j < 32; j++) {
Chunk c = file.getChunk(i, j);
if (c == null) {
Iris.warn("Chunk " + ((mcaox << 5) + i) + ", " + ((mcaoz << 5) + j) + " is null in MCA File " + mcaox + ", " + mcaoz);
}
}
}
}
} }

View File

@ -27,8 +27,8 @@ import com.volmit.iris.engine.IrisEngineCompound;
import com.volmit.iris.engine.IrisWorlds; import com.volmit.iris.engine.IrisWorlds;
import com.volmit.iris.engine.cache.Cache; import com.volmit.iris.engine.cache.Cache;
import com.volmit.iris.engine.data.B; import com.volmit.iris.engine.data.B;
import com.volmit.iris.engine.data.DirectWorldWriter;
import com.volmit.iris.engine.data.chunk.TerrainChunk; import com.volmit.iris.engine.data.chunk.TerrainChunk;
import com.volmit.iris.engine.data.mca.NBTWorld;
import com.volmit.iris.engine.hunk.Hunk; import com.volmit.iris.engine.hunk.Hunk;
import com.volmit.iris.engine.object.IrisBiome; import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisDimension; import com.volmit.iris.engine.object.IrisDimension;
@ -104,7 +104,7 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
populators = new KList<BlockPopulator>().qadd(new BlockPopulator() { populators = new KList<BlockPopulator>().qadd(new BlockPopulator() {
@Override @Override
public void populate(@NotNull World world, @NotNull Random random, @NotNull Chunk chunk) { public void populate(@NotNull World world, @NotNull Random random, @NotNull Chunk chunk) {
if (compound != null) { if (compound.get() != null) {
for (BlockPopulator i : compound.get().getPopulators()) { for (BlockPopulator i : compound.get().getPopulators()) {
i.populate(world, random, chunk); i.populate(world, random, chunk);
} }
@ -295,7 +295,7 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
} }
public synchronized void initialize(World world) { public synchronized void initialize(World world) {
if (!(world instanceof FakeWorld) && fake.get() && this.compound != null) { if (!(world instanceof FakeWorld) && fake.get() && this.compound.get() != null) {
fake.set(false); fake.set(false);
this.compound.get().updateWorld(world); this.compound.get().updateWorld(world);
getTarget().updateWorld(world); getTarget().updateWorld(world);
@ -469,7 +469,7 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
return tc.getRaw(); return tc.getRaw();
} }
public void directWriteMCA(World w, int x, int z, DirectWorldWriter writer, MultiBurst burst) { public void directWriteMCA(World w, int x, int z, NBTWorld writer, MultiBurst burst) {
BurstExecutor e = burst.burst(1024); BurstExecutor e = burst.burst(1024);
int mcaox = x << 5; int mcaox = x << 5;
int mcaoz = z << 5; int mcaoz = z << 5;
@ -485,7 +485,7 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
e.complete(); e.complete();
} }
public void directWriteChunk(World w, int x, int z, DirectWorldWriter writer) { public void directWriteChunk(World w, int x, int z, NBTWorld writer) {
int ox = x << 4; int ox = x << 4;
int oz = z << 4; int oz = z << 4;
com.volmit.iris.engine.data.mca.Chunk cc = writer.getChunk(x, z); com.volmit.iris.engine.data.mca.Chunk cc = writer.getChunk(x, z);
@ -543,7 +543,7 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
return; return;
} }
cc.setBlockStateAt(xx, y, zz, DirectWorldWriter.getCompound(blockData), false); cc.setBlockStateAt(xx, y, zz, NBTWorld.getCompound(blockData), false);
} }
@NotNull @NotNull
@ -557,7 +557,7 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
y = 0; y = 0;
} }
return DirectWorldWriter.getBlockData(cc.getBlockStateAt((x + ox) & 15, y, (z + oz) & 15)); return NBTWorld.getBlockData(cc.getBlockStateAt((x + ox) & 15, y, (z + oz) & 15));
} }
@Override @Override

View File

@ -199,6 +199,11 @@ public interface EngineParallaxManager extends DataProvider, IObjectPlacer {
IrisLock getFeatureLock(); IrisLock getFeatureLock();
default void forEachFeature(double x, double z, Consumer<IrisFeaturePositional> f) { default void forEachFeature(double x, double z, Consumer<IrisFeaturePositional> f) {
if(!getEngine().getDimension().hasFeatures(getEngine()))
{
return;
}
long key = Cache.key(((int) x) >> 4, ((int) z) >> 4); long key = Cache.key(((int) x) >> 4, ((int) z) >> 4);
for (IrisFeaturePositional ipf : getFeatureCache().compute(key, (ke, v) -> { for (IrisFeaturePositional ipf : getFeatureCache().compute(key, (ke, v) -> {
@ -225,17 +230,13 @@ public interface EngineParallaxManager extends DataProvider, IObjectPlacer {
ParallaxChunkMeta m = getParallaxAccess().getMetaR(i + cx, j + cz); ParallaxChunkMeta m = getParallaxAccess().getMetaR(i + cx, j + cz);
try { try {
synchronized (m.getFeatures()) { for (IrisFeaturePositional k : m.getFeatures()) {
for (IrisFeaturePositional k : m.getFeatures()) { if (k.shouldFilter(x, z)) {
if (k.shouldFilter(x, z)) { pos.add(k);
pos.add(k);
}
} }
} }
} catch (Throwable e) { } catch (Throwable e) {
Iris.reportError(e); Iris.reportError(e);
e.printStackTrace();
Iris.warn("Failed to read positional features in chunk " + (i + cx) + " " + (j + cz) + "(" + e.getClass().getSimpleName() + ")");
} }
} }
} }

View File

@ -22,7 +22,7 @@ import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisDataManager; import com.volmit.iris.core.IrisDataManager;
import com.volmit.iris.engine.IrisComplex; import com.volmit.iris.engine.IrisComplex;
import com.volmit.iris.engine.data.DataProvider; import com.volmit.iris.engine.data.DataProvider;
import com.volmit.iris.engine.data.DirectWorldWriter; import com.volmit.iris.engine.data.mca.NBTWorld;
import com.volmit.iris.engine.object.IrisBiome; import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisRegion; import com.volmit.iris.engine.object.IrisRegion;
import com.volmit.iris.engine.parallel.MultiBurst; import com.volmit.iris.engine.parallel.MultiBurst;
@ -44,9 +44,9 @@ import java.util.function.Consumer;
@SuppressWarnings("EmptyMethod") @SuppressWarnings("EmptyMethod")
public interface IrisAccess extends Hotloadable, DataProvider { public interface IrisAccess extends Hotloadable, DataProvider {
void directWriteMCA(World w, int x, int z, DirectWorldWriter writer, MultiBurst burst); void directWriteMCA(World w, int x, int z, NBTWorld writer, MultiBurst burst);
void directWriteChunk(World w, int x, int z, DirectWorldWriter writer); void directWriteChunk(World w, int x, int z, NBTWorld writer);
int getGenerated(); int getGenerated();

View File

@ -349,6 +349,7 @@ public class IrisDimension extends IrisRegistrant {
private final transient AtomicCache<Double> sinr = new AtomicCache<>(); private final transient AtomicCache<Double> sinr = new AtomicCache<>();
private final transient AtomicCache<Double> cosr = new AtomicCache<>(); private final transient AtomicCache<Double> cosr = new AtomicCache<>();
private final transient AtomicCache<Double> rad = new AtomicCache<>(); private final transient AtomicCache<Double> rad = new AtomicCache<>();
private final transient AtomicCache<Boolean> featuresUsed = new AtomicCache<>();
public boolean hasSky() { public boolean hasSky() {
return getSky() != null; return getSky() != null;
@ -517,4 +518,48 @@ public class IrisDimension extends IrisRegistrant {
return changed; return changed;
} }
public boolean hasFeatures(DataProvider data) {
return featuresUsed.aquire(() -> {
if(getFeatures().isNotEmpty() || getSpecificFeatures().isNotEmpty())
{
return true;
}
for(IrisRegion i : getAllRegions(data))
{
if(i.getFeatures().isNotEmpty())
{
return true;
}
for(IrisObjectPlacement j : i.getObjects())
{
if(j.isVacuum())
{
return true;
}
}
for(IrisBiome j : i.getAllBiomes(data))
{
if(j.getFeatures().isNotEmpty())
{
return true;
}
for(IrisObjectPlacement k : i.getObjects())
{
if(k.isVacuum())
{
return true;
}
}
}
}
Iris.verbose("Not using parallax noise features (they arent used in this dimension)");
return false;
});
}
} }

View File

@ -30,6 +30,7 @@ import lombok.Data;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Function; import java.util.function.Function;
@AllArgsConstructor @AllArgsConstructor
@ -56,9 +57,9 @@ public class ParallaxChunkMeta {
private int maxObject = -1; private int maxObject = -1;
private int minObject = -1; private int minObject = -1;
private int count; private int count;
private KList<IrisFeaturePositional> features; private CopyOnWriteArrayList<IrisFeaturePositional> features;
public ParallaxChunkMeta() { public ParallaxChunkMeta() {
this(false, false, false, false, false, false, -1, -1, 0, new KList<>()); this(false, false, false, false, false, false, -1, -1, 0, new CopyOnWriteArrayList<>());
} }
} }

View File

@ -156,7 +156,6 @@ public class ParallaxRegion extends HunkRegion {
} }
public synchronized void save() throws IOException { public synchronized void save() throws IOException {
PrecisionStopwatch p = PrecisionStopwatch.start();
blockSlice.save(); blockSlice.save();
objectSlice.save(); objectSlice.save();
entitySlice.save(); entitySlice.save();
@ -164,7 +163,6 @@ public class ParallaxRegion extends HunkRegion {
updateSlice.save(); updateSlice.save();
saveMetaHunk(); saveMetaHunk();
super.save(); super.save();
Iris.debug("Saved Parallax Region " + C.AQUA + getX() + "," + getZ() + C.LIGHT_PURPLE + " in " + C.RED + Form.duration(p.getMilliseconds(), 0));
} }
public int unload() { public int unload() {