Optimizations

This commit is contained in:
Daniel Mills 2020-12-28 06:10:46 -05:00
parent 4f3b6e4029
commit 540656870a
9 changed files with 126 additions and 52 deletions

View File

@ -155,9 +155,9 @@
</repositories> </repositories>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>com.github.Querz</groupId> <groupId>io.timeandspace</groupId>
<artifactId>NBT</artifactId> <artifactId>smoothie-map</artifactId>
<version>5.5</version> <version>2.0.2</version>
</dependency> </dependency>
<!-- Spigot API --> <!-- Spigot API -->
<dependency> <dependency>

View File

@ -5,9 +5,7 @@ import com.volmit.iris.nms.INMS;
import com.volmit.iris.scaffold.cache.Cache; import com.volmit.iris.scaffold.cache.Cache;
import com.volmit.iris.scaffold.parallel.BurstExecutor; import com.volmit.iris.scaffold.parallel.BurstExecutor;
import com.volmit.iris.scaffold.parallel.MultiBurst; import com.volmit.iris.scaffold.parallel.MultiBurst;
import com.volmit.iris.util.B; import com.volmit.iris.util.*;
import com.volmit.iris.util.KList;
import com.volmit.iris.util.KMap;
import net.querz.mca.Chunk; import net.querz.mca.Chunk;
import net.querz.mca.MCAFile; import net.querz.mca.MCAFile;
import net.querz.mca.MCAUtil; import net.querz.mca.MCAUtil;
@ -24,41 +22,64 @@ import java.io.IOException;
public class DirectWorldWriter { public class DirectWorldWriter {
private final File worldFolder; private final File worldFolder;
private final KMap<Long, MCAFile> writeBuffer; private final KMap<Long, MCAFile> writeBuffer;
private final KMap<Long, Long> lastUse;
private static final KMap<String, CompoundTag> blockDataCache = new KMap<>();
private static final KMap<Biome, Integer> biomeIds = computeBiomeIDs();
public DirectWorldWriter(File worldFolder) public DirectWorldWriter(File worldFolder)
{ {
this.worldFolder = worldFolder; this.worldFolder = worldFolder;
lastUse = new KMap<>();
writeBuffer = new KMap<>(); writeBuffer = new KMap<>();
new File(worldFolder, "region").mkdirs(); new File(worldFolder, "region").mkdirs();
} }
public void flush() public void flush()
{ {
BurstExecutor ex = MultiBurst.burst.burst(writeBuffer.size());
writeBuffer.v().forEach((i) -> ex.queue(i::cleanupPalettesAndBlockStates));
ex.complete();
BurstExecutor ex2 = MultiBurst.burst.burst(writeBuffer.size()); BurstExecutor ex2 = MultiBurst.burst.burst(writeBuffer.size());
for(Long i : writeBuffer.k()) for(Long i : writeBuffer.k())
{ {
int x = Cache.keyX(i); if(M.ms() - lastUse.get(i) < 15000)
int z = Cache.keyZ(i); {
try { continue;
File f = getMCAFile(x, z);
if(!f.exists())
{
f.getParentFile().mkdirs();
f.createNewFile();
}
MCAUtil.write(writeBuffer.get(i), f, true);
} catch (Throwable e) {
e.printStackTrace();
} }
}
writeBuffer.clear(); ex2.queue(() -> {
int x = Cache.keyX(i);
int z = Cache.keyZ(i);
try {
File f = getMCAFile(x, z);
if(!f.exists())
{
f.getParentFile().mkdirs();
f.createNewFile();
}
try
{
writeBuffer.get(i).cleanupPalettesAndBlockStates();
}
catch(Throwable e)
{
}
lastUse.remove(i);
MCAUtil.write(writeBuffer.get(i), f, true);
writeBuffer.remove(i);
} catch (Throwable e) {
e.printStackTrace();
}
});
}
}
public void optimizeChunk(int x, int z)
{
getChunk(x, z).cleanupPalettesAndBlockStates();
} }
public File getMCAFile(int x, int z) public File getMCAFile(int x, int z)
@ -66,8 +87,12 @@ public class DirectWorldWriter {
return new File(worldFolder, "region/r." + x + "." + z + ".mca"); return new File(worldFolder, "region/r." + x + "." + z + ".mca");
} }
public BlockData getBlockData(CompoundTag tag) public BlockData getBlockData(CompoundTag tag) {
{ if (tag == null)
{
return B.getAir();
}
String p = tag.getString("Name"); String p = tag.getString("Name");
if(tag.containsKey("Properties")) if(tag.containsKey("Properties"))
@ -84,16 +109,29 @@ public class DirectWorldWriter {
p += m.toString(",") + "]"; p += m.toString(",") + "]";
} }
return B.get(p); BlockData b = B.getOrNull(p);
if(b == null)
{
return B.getAir();
}
return b;
} }
public CompoundTag getCompound(BlockData blockData) public CompoundTag getCompound(BlockData blockData)
{ {
String data = blockData.getAsString(true);
if(blockDataCache.containsKey(data))
{
return blockDataCache.get(data).clone();
}
CompoundTag s = new CompoundTag(); CompoundTag s = new CompoundTag();
NamespacedKey key = blockData.getMaterial().getKey(); NamespacedKey key = blockData.getMaterial().getKey();
s.putString("Name", key.getNamespace() + ":" + key.getKey()); s.putString("Name", key.getNamespace() + ":" + key.getKey());
String data = blockData.getAsString(true);
if(data.contains("[")) if(data.contains("["))
{ {
@ -120,6 +158,7 @@ public class DirectWorldWriter {
s.put("Properties", props); s.put("Properties", props);
} }
blockDataCache.put(data, s.clone());
return s; return s;
} }
@ -151,7 +190,7 @@ public class DirectWorldWriter {
public void setBiome(int x, int y, int z, Biome biome) public void setBiome(int x, int y, int z, Biome biome)
{ {
getChunk(x>>4, z>>4).setBiomeAt(x&15, y, z &15, INMS.get().getBiomeId(biome)); getChunk(x>>4, z>>4).setBiomeAt(x&15, y, z &15, biomeIds.get(biome));
} }
public Section getChunkSection(int x, int y, int z) public Section getChunkSection(int x, int y, int z)
@ -176,6 +215,7 @@ public class DirectWorldWriter {
if(c == null) if(c == null)
{ {
c = Chunk.newChunk(); c = Chunk.newChunk();
lastUse.put(Cache.key(x >> 5, z >> 5), M.ms());
mca.setChunk(x&31, z&31, c); mca.setChunk(x&31, z&31, c);
} }
@ -204,7 +244,23 @@ public class DirectWorldWriter {
} }
} }
lastUse.put(key, M.ms());
writeBuffer.put(key, mca); writeBuffer.put(key, mca);
return mca; return mca;
} }
public int size() {
return writeBuffer.size();
}
private static KMap<Biome, Integer> computeBiomeIDs() {
KMap<Biome, Integer> biomeIds = new KMap<>();
for(Biome i : Biome.values())
{
biomeIds.put(i, INMS.get().getBiomeId(i));
}
return biomeIds;
}
} }

View File

@ -338,6 +338,7 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
{ {
int ox = x << 4; int ox = x << 4;
int oz = z << 4; int oz = z << 4;
net.querz.mca.Chunk cc = writer.getChunk(x, z);
generateChunkRawData(w, x, z, new TerrainChunk() { generateChunkRawData(w, x, z, new TerrainChunk() {
@Override @Override
public void setRaw(ChunkData data) { public void setRaw(ChunkData data) {
@ -356,12 +357,12 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
@Override @Override
public void setBiome(int x, int z, Biome bio) { public void setBiome(int x, int z, Biome bio) {
writer.setBiome(ox + x, 0, oz + z, bio); setBiome(ox + x, 0, oz + z, bio);
} }
@Override @Override
public void setBiome(int x, int y, int z, Biome bio) { public void setBiome(int x, int y, int z, Biome bio) {
writer.setBiome(ox + x, y, oz + z, bio); writer.setBiome((ox + x), y, oz + z, bio);
} }
@Override @Override
@ -371,12 +372,22 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
@Override @Override
public void setBlock(int x, int y, int z, BlockData blockData) { public void setBlock(int x, int y, int z, BlockData blockData) {
writer.setBlockData(x+ox, y, z+oz, blockData); cc.setBlockStateAt((x+ox)&15, y, (z+oz)&15, writer.getCompound(blockData), false);
} }
@Override @Override
public BlockData getBlockData(int x, int y, int z) { public BlockData getBlockData(int x, int y, int z) {
return writer.getBlockData(x + ox, y, z + oz); if(y > getMaxHeight())
{
y = getMaxHeight();
}
if(y < 0)
{
y = 0;
}
return writer.getBlockData(cc.getBlockStateAt((x+ox)&15, y, (z+oz)&15));
} }
@Override @Override
@ -431,6 +442,7 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
return 0; return 0;
} }
}).run(); }).run();
writer.optimizeChunk(x, z);
} }
public Chunk generatePaper(World world, int x, int z) public Chunk generatePaper(World world, int x, int z)

View File

@ -147,6 +147,7 @@ public class PregenJob implements Listener
{ {
try try
{ {
instance.writer.flush();
Bukkit.getScheduler().cancelTask(task); Bukkit.getScheduler().cancelTask(task);
if(consumer != null) if(consumer != null)
@ -172,6 +173,7 @@ public class PregenJob implements Listener
instance.pms = instance.s.getMilliseconds(); instance.pms = instance.s.getMilliseconds();
instance.paused = true; instance.paused = true;
instance.pausedAt = M.ms(); instance.pausedAt = M.ms();
instance.writer.flush();
} }
public static void resume() public static void resume()
@ -207,6 +209,8 @@ public class PregenJob implements Listener
tick(skip); tick(skip);
} }
Iris.warn("Size: " + writer.size());
PrecisionStopwatch p = PrecisionStopwatch.start(); PrecisionStopwatch p = PrecisionStopwatch.start();
if(PaperLib.isPaper()) if(PaperLib.isPaper())

View File

@ -30,7 +30,7 @@ public class Chunk {
private int[] biomes; private int[] biomes;
private CompoundTag heightMaps; private CompoundTag heightMaps;
private CompoundTag carvingMasks; private CompoundTag carvingMasks;
private Section[] sections = new Section[16]; //always initialized with size = 16 for fast access private final Section[] sections = new Section[16];
private ListTag<CompoundTag> entities; private ListTag<CompoundTag> entities;
private ListTag<CompoundTag> tileEntities; private ListTag<CompoundTag> tileEntities;
private ListTag<CompoundTag> tileTicks; private ListTag<CompoundTag> tileTicks;

View File

@ -63,6 +63,11 @@ public class MCAFile {
} }
} }
public Chunk[] getChunks()
{
return chunks;
}
/** /**
* Calls {@link MCAFile#serialize(RandomAccessFile, boolean)} without updating any timestamps. * Calls {@link MCAFile#serialize(RandomAccessFile, boolean)} without updating any timestamps.
* @see MCAFile#serialize(RandomAccessFile, boolean) * @see MCAFile#serialize(RandomAccessFile, boolean)

View File

@ -1,19 +1,24 @@
package net.querz.mca; package net.querz.mca;
import static net.querz.mca.LoadFlags.*; import io.timeandspace.smoothie.OptimizationObjective;
import io.timeandspace.smoothie.SmoothieMap;
import net.querz.nbt.tag.ByteArrayTag; import net.querz.nbt.tag.ByteArrayTag;
import net.querz.nbt.tag.CompoundTag; import net.querz.nbt.tag.CompoundTag;
import net.querz.nbt.tag.ListTag; import net.querz.nbt.tag.ListTag;
import net.querz.nbt.tag.LongArrayTag; import net.querz.nbt.tag.LongArrayTag;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import static net.querz.mca.LoadFlags.*;
public class Section { public class Section {
private CompoundTag data; private CompoundTag data;
private Map<String, List<PaletteIndex>> valueIndexedPalette = new HashMap<>(); private Map<String, List<PaletteIndex>> valueIndexedPalette = SmoothieMap.<String, List<PaletteIndex>>newBuilder()
.optimizeFor(OptimizationObjective.FOOTPRINT).build();
private ListTag<CompoundTag> palette; private ListTag<CompoundTag> palette;
private byte[] blockLight; private byte[] blockLight;
private long[] blockStates; private long[] blockStates;

View File

@ -1,13 +1,9 @@
package net.querz.nbt.tag; package net.querz.nbt.tag;
import com.volmit.iris.util.KMap;
import net.querz.io.MaxDepthIO; import net.querz.io.MaxDepthIO;
import java.util.Collection; import java.util.*;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
public class CompoundTag extends Tag<Map<String, Tag<?>>> implements Iterable<Map.Entry<String, Tag<?>>>, Comparable<CompoundTag>, MaxDepthIO { public class CompoundTag extends Tag<Map<String, Tag<?>>> implements Iterable<Map.Entry<String, Tag<?>>>, Comparable<CompoundTag>, MaxDepthIO {
@ -24,7 +20,7 @@ public class CompoundTag extends Tag<Map<String, Tag<?>>> implements Iterable<Ma
} }
private static Map<String, Tag<?>> createEmptyValue() { private static Map<String, Tag<?>> createEmptyValue() {
return new HashMap<>(8); return new KMap<>();
} }
public int size() { public int size() {

View File

@ -1,13 +1,9 @@
package net.querz.nbt.tag; package net.querz.nbt.tag;
import com.volmit.iris.util.KList;
import net.querz.io.MaxDepthIO; import net.querz.io.MaxDepthIO;
import java.util.ArrayList; import java.util.*;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer; import java.util.function.Consumer;
/** /**
@ -52,10 +48,10 @@ public class ListTag<T extends Tag<?>> extends Tag<List<T>> implements Iterable<
* *
* @param <T> Type of the list elements * @param <T> Type of the list elements
* @param initialCapacity The initial capacity of the returned List * @param initialCapacity The initial capacity of the returned List
* @return An instance of {@link java.util.List} with an initial capacity of 3 * @return An instance of {@link List} with an initial capacity of 3
* */ * */
private static <T> List<T> createEmptyValue(int initialCapacity) { private static <T> List<T> createEmptyValue(int initialCapacity) {
return new ArrayList<>(initialCapacity); return new KList<>(initialCapacity);
} }
/** /**