minecraft-source/src/net/minecraft/util/worldupdate/WorldUpgrader.java

238 lines
10 KiB
Java
Raw Normal View History

2020-07-22 06:23:34 +01:00
package net.minecraft.util.worldupdate;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.apache.logging.log4j.LogManager;
import java.util.regex.Matcher;
import net.minecraft.world.level.chunk.storage.RegionFile;
import com.google.common.collect.Lists;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.UnmodifiableIterator;
import net.minecraft.nbt.CompoundTag;
import java.util.List;
import java.util.Iterator;
import net.minecraft.ReportedException;
import java.io.IOException;
import net.minecraft.SharedConstants;
import net.minecraft.world.level.chunk.storage.ChunkStorage;
import net.minecraft.world.level.ChunkPos;
import java.util.ListIterator;
import com.google.common.collect.ImmutableMap;
import net.minecraft.server.MinecraftServer;
import net.minecraft.network.chat.TranslatableComponent;
import it.unimi.dsi.fastutil.objects.Object2FloatMaps;
import it.unimi.dsi.fastutil.Hash;
import it.unimi.dsi.fastutil.objects.Object2FloatOpenCustomHashMap;
import net.minecraft.Util;
import net.minecraft.world.level.storage.LevelData;
import net.minecraft.world.level.storage.LevelStorageSource;
import net.minecraft.world.level.storage.DimensionDataStorage;
import java.util.regex.Pattern;
import net.minecraft.network.chat.Component;
import net.minecraft.world.level.dimension.DimensionType;
import it.unimi.dsi.fastutil.objects.Object2FloatMap;
import java.io.File;
import net.minecraft.world.level.storage.LevelStorage;
import java.util.concurrent.ThreadFactory;
import org.apache.logging.log4j.Logger;
public class WorldUpgrader {
private static final Logger LOGGER;
private static final ThreadFactory THREAD_FACTORY;
private final String levelName;
private final boolean eraseCache;
private final LevelStorage levelStorage;
private final Thread thread;
private final File pathToWorld;
private volatile boolean running;
private volatile boolean finished;
private volatile float progress;
private volatile int totalChunks;
private volatile int converted;
private volatile int skipped;
private final Object2FloatMap<DimensionType> progressMap;
private volatile Component status;
private static final Pattern REGEX;
private final DimensionDataStorage overworldDataStorage;
public WorldUpgrader(final String string, final LevelStorageSource coq, final LevelData com, final boolean boolean4) {
this.running = true;
this.progressMap = (Object2FloatMap<DimensionType>)Object2FloatMaps.synchronize((Object2FloatMap)new Object2FloatOpenCustomHashMap((Hash.Strategy)Util.identityStrategy()));
this.status = new TranslatableComponent("optimizeWorld.stage.counting", new Object[0]);
this.levelName = com.getLevelName();
this.eraseCache = boolean4;
(this.levelStorage = coq.selectLevel(string, null)).saveLevelData(com);
this.overworldDataStorage = new DimensionDataStorage(new File(DimensionType.OVERWORLD.getStorageFolder(this.levelStorage.getFolder()), "data"), this.levelStorage.getFixerUpper());
this.pathToWorld = this.levelStorage.getFolder();
(this.thread = WorldUpgrader.THREAD_FACTORY.newThread(this::work)).setUncaughtExceptionHandler((thread, throwable) -> {
WorldUpgrader.LOGGER.error("Error upgrading world", throwable);
this.status = new TranslatableComponent("optimizeWorld.stage.failed", new Object[0]);
return;
});
this.thread.start();
}
public void cancel() {
this.running = false;
try {
this.thread.join();
}
catch (InterruptedException ex) {}
}
private void work() {
final File file2 = this.levelStorage.getFolder();
this.totalChunks = 0;
final ImmutableMap.Builder<DimensionType, ListIterator<ChunkPos>> builder3 = ImmutableMap.<DimensionType, ListIterator<ChunkPos>>builder();
for (final DimensionType byn5 : DimensionType.getAllTypes()) {
final List<ChunkPos> list6 = this.getAllChunkPos(byn5);
builder3.put(byn5, list6.listIterator());
this.totalChunks += list6.size();
}
if (this.totalChunks == 0) {
this.finished = true;
return;
}
final float float4 = (float)this.totalChunks;
final ImmutableMap<DimensionType, ListIterator<ChunkPos>> immutableMap5 = builder3.build();
final ImmutableMap.Builder<DimensionType, ChunkStorage> builder4 = ImmutableMap.<DimensionType, ChunkStorage>builder();
for (final DimensionType byn6 : DimensionType.getAllTypes()) {
final File file3 = byn6.getStorageFolder(file2);
builder4.put(byn6, new ChunkStorage(new File(file3, "region"), this.levelStorage.getFixerUpper()));
}
final ImmutableMap<DimensionType, ChunkStorage> immutableMap6 = builder4.build();
long long8 = Util.getMillis();
this.status = new TranslatableComponent("optimizeWorld.stage.upgrading", new Object[0]);
while (this.running) {
boolean boolean10 = false;
float float5 = 0.0f;
for (final DimensionType byn7 : DimensionType.getAllTypes()) {
final ListIterator<ChunkPos> listIterator14 = immutableMap5.get(byn7);
final ChunkStorage byg15 = immutableMap6.get(byn7);
if (listIterator14.hasNext()) {
final ChunkPos bhd16 = listIterator14.next();
boolean boolean11 = false;
try {
final CompoundTag id18 = byg15.read(bhd16);
if (id18 != null) {
final int integer19 = ChunkStorage.getVersion(id18);
final CompoundTag id19 = byg15.upgradeChunkTag(byn7, () -> this.overworldDataStorage, id18);
boolean boolean12 = integer19 < SharedConstants.getCurrentVersion().getWorldVersion();
if (this.eraseCache) {
final CompoundTag id20 = id19.getCompound("Level");
boolean12 = (boolean12 || id20.contains("Heightmaps"));
id20.remove("Heightmaps");
boolean12 = (boolean12 || id20.contains("isLightOn"));
id20.remove("isLightOn");
}
if (boolean12) {
byg15.write(bhd16, id19);
boolean11 = true;
}
}
}
catch (ReportedException m18) {
final Throwable throwable19 = m18.getCause();
if (!(throwable19 instanceof IOException)) {
throw m18;
}
WorldUpgrader.LOGGER.error("Error upgrading chunk {}", bhd16, throwable19);
}
catch (IOException iOException18) {
WorldUpgrader.LOGGER.error("Error upgrading chunk {}", bhd16, iOException18);
}
if (boolean11) {
++this.converted;
}
else {
++this.skipped;
}
boolean10 = true;
}
final float float6 = listIterator14.nextIndex() / float4;
this.progressMap.put(byn7, float6);
float5 += float6;
}
this.progress = float5;
if (!boolean10) {
this.running = false;
}
}
this.status = new TranslatableComponent("optimizeWorld.stage.finished", new Object[0]);
for (final ChunkStorage byg16 : immutableMap6.values()) {
try {
byg16.close();
}
catch (IOException iOException19) {
WorldUpgrader.LOGGER.error("Error upgrading chunk", (Throwable)iOException19);
}
}
this.overworldDataStorage.save();
long8 = Util.getMillis() - long8;
WorldUpgrader.LOGGER.info("World optimizaton finished after {} ms", long8);
this.finished = true;
}
private List<ChunkPos> getAllChunkPos(final DimensionType byn) {
final File file3 = byn.getStorageFolder(this.pathToWorld);
final File file4 = new File(file3, "region");
final File[] arr5 = file4.listFiles((file, string) -> string.endsWith(".mca"));
if (arr5 == null) {
return ImmutableList.of();
}
final List<ChunkPos> list6 = Lists.newArrayList();
for (final File file5 : arr5) {
final Matcher matcher11 = WorldUpgrader.REGEX.matcher(file5.getName());
if (matcher11.matches()) {
final int integer12 = Integer.parseInt(matcher11.group(1)) << 5;
final int integer13 = Integer.parseInt(matcher11.group(2)) << 5;
try (final RegionFile byi14 = new RegionFile(file5)) {
for (int integer14 = 0; integer14 < 32; ++integer14) {
for (int integer15 = 0; integer15 < 32; ++integer15) {
final ChunkPos bhd18 = new ChunkPos(integer14 + integer12, integer15 + integer13);
if (byi14.doesChunkExist(bhd18)) {
list6.add(bhd18);
}
}
}
}
catch (Throwable t3) {}
}
}
return list6;
}
public boolean isFinished() {
return this.finished;
}
public float dimensionProgress(final DimensionType byn) {
return this.progressMap.getFloat(byn);
}
public float getProgress() {
return this.progress;
}
public int getTotalChunks() {
return this.totalChunks;
}
public int getConverted() {
return this.converted;
}
public int getSkipped() {
return this.skipped;
}
public Component getStatus() {
return this.status;
}
static {
LOGGER = LogManager.getLogger();
THREAD_FACTORY = new ThreadFactoryBuilder().setDaemon(true).build();
REGEX = Pattern.compile("^r\\.(-?[0-9]+)\\.(-?[0-9]+)\\.mca$");
}
}