Added progress Screen for DataFixer
This commit is contained in:
parent
11926ac63c
commit
d1ef3b5807
5 changed files with 138 additions and 61 deletions
|
@ -13,7 +13,7 @@ import net.minecraft.nbt.NbtIo;
|
||||||
import net.minecraft.nbt.StringTag;
|
import net.minecraft.nbt.StringTag;
|
||||||
import net.minecraft.nbt.Tag;
|
import net.minecraft.nbt.Tag;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.util.ProgressListener;
|
import net.minecraft.network.chat.TranslatableComponent;
|
||||||
import net.minecraft.world.level.ChunkPos;
|
import net.minecraft.world.level.ChunkPos;
|
||||||
import net.minecraft.world.level.chunk.storage.RegionFile;
|
import net.minecraft.world.level.chunk.storage.RegionFile;
|
||||||
import net.minecraft.world.level.storage.LevelResource;
|
import net.minecraft.world.level.storage.LevelResource;
|
||||||
|
@ -23,7 +23,9 @@ import org.jetbrains.annotations.NotNull;
|
||||||
import ru.bclib.BCLib;
|
import ru.bclib.BCLib;
|
||||||
import ru.bclib.api.WorldDataAPI;
|
import ru.bclib.api.WorldDataAPI;
|
||||||
import ru.bclib.config.Configs;
|
import ru.bclib.config.Configs;
|
||||||
|
import ru.bclib.gui.screens.AtomicProgressListener;
|
||||||
import ru.bclib.gui.screens.ConfirmFixScreen;
|
import ru.bclib.gui.screens.ConfirmFixScreen;
|
||||||
|
import ru.bclib.gui.screens.ProgressScreen;
|
||||||
import ru.bclib.util.Logger;
|
import ru.bclib.util.Logger;
|
||||||
|
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
|
@ -32,6 +34,8 @@ import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
@ -149,41 +153,76 @@ public class DataFixerAPI {
|
||||||
WorldDataAPI.saveFile(BCLib.MOD_ID);
|
WorldDataAPI.saveFile(BCLib.MOD_ID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Environment(EnvType.CLIENT)
|
||||||
|
private static AtomicProgressListener showProgressScreen(){
|
||||||
|
ProgressScreen ps = new ProgressScreen(Minecraft.getInstance().screen, new TranslatableComponent("title.bclib.datafixer.progress"), new TranslatableComponent("message.bclib.datafixer.progress"));
|
||||||
|
Minecraft.getInstance().setScreen(ps);
|
||||||
|
return ps;
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean fixData(File dir, String levelID, boolean showUI, Consumer<Boolean> onResume) {
|
private static boolean fixData(File dir, String levelID, boolean showUI, Consumer<Boolean> onResume) {
|
||||||
MigrationProfile profile = loadProfileIfNeeded(dir);
|
MigrationProfile profile = loadProfileIfNeeded(dir);
|
||||||
|
|
||||||
Consumer<Boolean> runFixes = (applyFixes) -> {
|
BiConsumer<Boolean, Boolean> runFixes = (createBackup, applyFixes) -> {
|
||||||
|
final AtomicProgressListener progress;
|
||||||
if (applyFixes) {
|
if (applyFixes) {
|
||||||
runDataFixes(dir, profile, new ProgressListener() {
|
if (showUI) {
|
||||||
private long timeStamp = Util.getMillis();
|
progress = showProgressScreen();
|
||||||
|
} else {
|
||||||
|
progress = new AtomicProgressListener() {
|
||||||
|
private long timeStamp = Util.getMillis();
|
||||||
|
private AtomicInteger counter = new AtomicInteger(0);
|
||||||
|
|
||||||
public void progressStartNoAbort(Component component) {
|
@Override
|
||||||
}
|
public void incAtomic(int maxProgress) {
|
||||||
|
int percentage = (100 * counter.incrementAndGet()) / maxProgress;
|
||||||
public void progressStart(Component component) {
|
if (Util.getMillis() - this.timeStamp >= 1000L) {
|
||||||
}
|
this.timeStamp = Util.getMillis();
|
||||||
|
BCLib.LOGGER.info((String) "Patching... {}%", percentage);
|
||||||
public void progressStagePercentage(int i) {
|
}
|
||||||
if (Util.getMillis() - this.timeStamp >= 1000L) {
|
|
||||||
this.timeStamp = Util.getMillis();
|
|
||||||
BCLib.LOGGER.info((String) "Patching... {}%", (Object) i);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public void stop() {
|
@Override
|
||||||
}
|
public void resetAtomic() {
|
||||||
|
counter = new AtomicInteger(0);
|
||||||
|
}
|
||||||
|
|
||||||
public void progressStage(Component component) {
|
public void stop() {
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
public void progressStage(Component component) {
|
||||||
|
BCLib.LOGGER.info((String) "Patcher Stage... {}%", component.getString());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
//System.out.println("NO FIXES");
|
progress = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
//UI is asynchronous, so we need to send the callback now
|
Runnable runner = () -> {
|
||||||
if (profile != null && showUI) {
|
if (createBackup) {
|
||||||
onResume.accept(applyFixes);
|
EditWorldScreen.makeBackupAndShowToast(Minecraft.getInstance().getLevelSource(), levelID);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (applyFixes) {
|
||||||
|
runDataFixes(dir, profile, progress);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (showUI) {
|
||||||
|
Thread fixerThread = new Thread(() -> {
|
||||||
|
runner.run();
|
||||||
|
|
||||||
|
Minecraft.getInstance().execute(() -> {
|
||||||
|
if (profile != null && showUI) {
|
||||||
|
onResume.accept(applyFixes);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
fixerThread.start();
|
||||||
|
} else {
|
||||||
|
runner.run();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -195,7 +234,7 @@ public class DataFixerAPI {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
BCLib.LOGGER.warning("Applying Fixes on Level");
|
BCLib.LOGGER.warning("Applying Fixes on Level");
|
||||||
runFixes.accept(true);
|
runFixes.accept(false, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -208,6 +247,8 @@ public class DataFixerAPI {
|
||||||
}
|
}
|
||||||
|
|
||||||
MigrationProfile profile = getMigrationProfile();
|
MigrationProfile profile = getMigrationProfile();
|
||||||
|
//TODO: Remove on Production
|
||||||
|
if (!BCLib.isDevEnvironment())
|
||||||
profile.runPrePatches(levelBaseDir);
|
profile.runPrePatches(levelBaseDir);
|
||||||
|
|
||||||
if (!profile.hasAnyFixes()) {
|
if (!profile.hasAnyFixes()) {
|
||||||
|
@ -226,46 +267,53 @@ public class DataFixerAPI {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Environment(EnvType.CLIENT)
|
@Environment(EnvType.CLIENT)
|
||||||
static void showBackupWarning(String levelID, Consumer<Boolean> whenFinished){
|
static void showBackupWarning(String levelID, BiConsumer<Boolean, Boolean> whenFinished){
|
||||||
Minecraft.getInstance().setScreen(new ConfirmFixScreen((Screen) null, (createBackup, applyFixes) -> {
|
Minecraft.getInstance().setScreen(new ConfirmFixScreen((Screen) null, whenFinished::accept));
|
||||||
if (createBackup) {
|
|
||||||
EditWorldScreen.makeBackupAndShowToast(Minecraft.getInstance().getLevelSource(), levelID);
|
|
||||||
}
|
|
||||||
|
|
||||||
Minecraft.getInstance().setScreen((Screen)null);
|
|
||||||
whenFinished.accept(applyFixes);
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void runDataFixes(File dir, MigrationProfile profile, ProgressListener progress) {
|
private static void runDataFixes(File dir, MigrationProfile profile, AtomicProgressListener progress) {
|
||||||
State state = new State();
|
State state = new State();
|
||||||
|
progress.resetAtomic();
|
||||||
List<File> regions = getAllRegions(dir, null);
|
|
||||||
progress.progressStagePercentage(0);
|
|
||||||
int[] count = {0};
|
|
||||||
regions.parallelStream().forEach((file) -> {
|
|
||||||
fixRegion(profile, state, file);
|
|
||||||
count[0]++;
|
|
||||||
progress.progressStagePercentage((100 * count[0])/regions.size());
|
|
||||||
});
|
|
||||||
progress.stop();
|
|
||||||
|
|
||||||
|
progress.progressStage(new TranslatableComponent("message.bclib.datafixer.progress.reading"));
|
||||||
List<File> players = getAllPlayers(dir);
|
List<File> players = getAllPlayers(dir);
|
||||||
players.parallelStream().forEach((file) -> fixPlayer(profile, state, file));
|
List<File> regions = getAllRegions(dir, null);
|
||||||
|
final int maxProgress = players.size()+regions.size()+4;
|
||||||
|
progress.incAtomic(maxProgress);
|
||||||
|
|
||||||
|
progress.progressStage(new TranslatableComponent("message.bclib.datafixer.progress.players"));
|
||||||
|
players.parallelStream().forEach((file) -> {
|
||||||
|
fixPlayer(profile, state, file);
|
||||||
|
progress.incAtomic(maxProgress);
|
||||||
|
});
|
||||||
|
|
||||||
|
progress.progressStage(new TranslatableComponent("message.bclib.datafixer.progress.level"));
|
||||||
fixLevel(profile, state, dir);
|
fixLevel(profile, state, dir);
|
||||||
|
progress.incAtomic(maxProgress);
|
||||||
|
|
||||||
|
progress.progressStage(new TranslatableComponent("message.bclib.datafixer.progress.worlddata"));
|
||||||
try {
|
try {
|
||||||
profile.patchWorldData();
|
profile.patchWorldData();
|
||||||
} catch (PatchDidiFailException e){
|
} catch (PatchDidiFailException e){
|
||||||
state.didFail = true;
|
state.didFail = true;
|
||||||
BCLib.LOGGER.error(e.getMessage());
|
BCLib.LOGGER.error(e.getMessage());
|
||||||
}
|
}
|
||||||
|
progress.incAtomic(maxProgress);
|
||||||
|
|
||||||
|
progress.progressStage(new TranslatableComponent("message.bclib.datafixer.progress.regions"));
|
||||||
|
regions.parallelStream().forEach((file) -> {
|
||||||
|
fixRegion(profile, state, file);
|
||||||
|
progress.incAtomic(maxProgress);
|
||||||
|
});
|
||||||
|
|
||||||
if (!state.didFail) {
|
if (!state.didFail) {
|
||||||
|
progress.progressStage(new TranslatableComponent("message.bclib.datafixer.progress.saving"));
|
||||||
profile.markApplied();
|
profile.markApplied();
|
||||||
WorldDataAPI.saveFile(BCLib.MOD_ID);
|
WorldDataAPI.saveFile(BCLib.MOD_ID);
|
||||||
}
|
}
|
||||||
|
progress.incAtomic(maxProgress);
|
||||||
|
|
||||||
|
progress.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void fixLevel(MigrationProfile profile, State state, File levelBaseDir) {
|
private static void fixLevel(MigrationProfile profile, State state, File levelBaseDir) {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package ru.bclib.api.datafixer;
|
package ru.bclib.api.datafixer;
|
||||||
|
|
||||||
|
import net.fabricmc.loom.util.ModUtils;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.nbt.ListTag;
|
import net.minecraft.nbt.ListTag;
|
||||||
import net.minecraft.nbt.NbtIo;
|
import net.minecraft.nbt.NbtIo;
|
||||||
|
@ -123,7 +124,7 @@ public class MigrationProfile {
|
||||||
|
|
||||||
final public void markApplied() {
|
final public void markApplied() {
|
||||||
for (String modID : mods) {
|
for (String modID : mods) {
|
||||||
DataFixerAPI.LOGGER.info("Updating Patch-Level for '{}' from {} to {}", modID, currentPatchLevel(modID), Patch.maxPatchLevel(modID));
|
DataFixerAPI.LOGGER.info("Updating Patch-Level for '{}' from {} to {}", modID, ModUtil.convertModVersion(currentPatchLevel(modID)), ModUtil.convertModVersion(Patch.maxPatchLevel(modID)));
|
||||||
config.putString(modID, Patch.maxPatchVersion(modID));
|
config.putString(modID, Patch.maxPatchVersion(modID));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
package ru.bclib.gui.screens;
|
||||||
|
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
|
||||||
|
public interface AtomicProgressListener {
|
||||||
|
public void incAtomic(int maxProgress);
|
||||||
|
public void resetAtomic();
|
||||||
|
public void stop();
|
||||||
|
public void progressStage(Component component);
|
||||||
|
}
|
|
@ -25,6 +25,8 @@ import ru.bclib.gui.gridlayout.GridScreen;
|
||||||
import ru.bclib.gui.gridlayout.GridStringCell;
|
import ru.bclib.gui.gridlayout.GridStringCell;
|
||||||
import ru.bclib.gui.gridlayout.GridTransform;
|
import ru.bclib.gui.gridlayout.GridTransform;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
class ProgressLogoRender extends GridCustomRenderCell {
|
class ProgressLogoRender extends GridCustomRenderCell {
|
||||||
public static final int SIZE = 64;
|
public static final int SIZE = 64;
|
||||||
public static final int LOGO_SIZE = 512;
|
public static final int LOGO_SIZE = 512;
|
||||||
|
@ -95,12 +97,14 @@ class ProgressLogoRender extends GridCustomRenderCell {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ProgressScreen extends GridScreen implements ProgressListener {
|
public class ProgressScreen extends GridScreen implements ProgressListener, AtomicProgressListener {
|
||||||
|
|
||||||
static final ResourceLocation BCLIB_LOGO_PIXELATED_LOCATION = new ResourceLocation(BCLib.MOD_ID, "iconpixelated.png");
|
static final ResourceLocation BCLIB_LOGO_PIXELATED_LOCATION = new ResourceLocation(BCLib.MOD_ID, "iconpixelated.png");
|
||||||
public ProgressScreen(@Nullable Screen parent, Component title, Component description) {
|
public ProgressScreen(@Nullable Screen parent, Component title, Component description) {
|
||||||
super(parent, title, 20, false);
|
super(parent, title, 20, false);
|
||||||
this.description = description;
|
this.description = description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Component description;
|
Component description;
|
||||||
private Component stageComponent;
|
private Component stageComponent;
|
||||||
|
@ -108,6 +112,21 @@ public class ProgressScreen extends GridScreen implements ProgressListener {
|
||||||
private GridStringCell progress;
|
private GridStringCell progress;
|
||||||
private ProgressLogoRender progressImage;
|
private ProgressLogoRender progressImage;
|
||||||
private int currentProgress = 0;
|
private int currentProgress = 0;
|
||||||
|
private AtomicInteger atomicCounter;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void incAtomic(int maxProgress) {
|
||||||
|
if (atomicCounter!=null) {
|
||||||
|
progressStagePercentage((100*atomicCounter.incrementAndGet())/maxProgress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resetAtomic() {
|
||||||
|
progressStagePercentage(0);
|
||||||
|
atomicCounter = new AtomicInteger(0);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean shouldCloseOnEsc() {
|
public boolean shouldCloseOnEsc() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -165,7 +184,6 @@ public class ProgressScreen extends GridScreen implements ProgressListener {
|
||||||
if (i!=currentProgress) {
|
if (i!=currentProgress) {
|
||||||
currentProgress = i;
|
currentProgress = i;
|
||||||
if (progressImage!=null) progressImage.percentage = currentProgress / 100.0f;
|
if (progressImage!=null) progressImage.percentage = currentProgress / 100.0f;
|
||||||
BCLib.LOGGER.info(" -> progress: " + i + "%");
|
|
||||||
if (progress!=null) progress.setText(getProgressComponent());
|
if (progress!=null) progress.setText(getProgressComponent());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -174,13 +192,4 @@ public class ProgressScreen extends GridScreen implements ProgressListener {
|
||||||
public void stop() {
|
public void stop() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double time = 0;
|
|
||||||
@Override
|
|
||||||
public void render(PoseStack poseStack, int i, int j, float f) {
|
|
||||||
//time += 0.05;
|
|
||||||
//progressStagePercentage(((int)time)%100);
|
|
||||||
//progressStagePercentage(1);
|
|
||||||
super.render(poseStack, i, j, f);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,5 +33,14 @@
|
||||||
"title.bclib.syncfiles.modlist": "Mod Information",
|
"title.bclib.syncfiles.modlist": "Mod Information",
|
||||||
"message.bclib.syncfiles.modlist": "The following shows the state of your installed installed Mods.\n\nAll Mods that do not exist locally, or have a different version will on the Server will be synchronized.",
|
"message.bclib.syncfiles.modlist": "The following shows the state of your installed installed Mods.\n\nAll Mods that do not exist locally, or have a different version will on the Server will be synchronized.",
|
||||||
"title.bclib.modmissmatch": "Mod Version Conflict",
|
"title.bclib.modmissmatch": "Mod Version Conflict",
|
||||||
"message.bclib.modmissmatch": "Some Mods on this client do not match the version of Mods on the Server.\n\nMismatching Mods can result in odd game behavior or crashes. Please make sue that you use the same mods as the server."
|
"message.bclib.modmissmatch": "Some Mods on this client do not match the version of Mods on the Server.\n\nMismatching Mods can result in odd game behavior or crashes. Please make sue that you use the same mods as the server.",
|
||||||
|
|
||||||
|
"message.bclib.datafixer.progress.reading": "Reading Data",
|
||||||
|
"message.bclib.datafixer.progress.players": "Fixing Players",
|
||||||
|
"message.bclib.datafixer.progress.level": "Applying Patches to level.dat",
|
||||||
|
"message.bclib.datafixer.progress.worlddata": "Patching Custom World-Data",
|
||||||
|
"message.bclib.datafixer.progress.regions": "Repairing all Regions",
|
||||||
|
"message.bclib.datafixer.progress.saving": "Saving Patch State",
|
||||||
|
"title.bclib.datafixer.progress": "Fixing World",
|
||||||
|
"message.bclib.datafixer.progress": "Applying all Patches to your World."
|
||||||
}
|
}
|
Loading…
Add table
Add a link
Reference in a new issue