diff --git a/src/main/java/ru/bclib/api/datafixer/DataFixerAPI.java b/src/main/java/ru/bclib/api/datafixer/DataFixerAPI.java index 4e03d1e1..c2e1895b 100644 --- a/src/main/java/ru/bclib/api/datafixer/DataFixerAPI.java +++ b/src/main/java/ru/bclib/api/datafixer/DataFixerAPI.java @@ -13,7 +13,7 @@ import net.minecraft.nbt.NbtIo; import net.minecraft.nbt.StringTag; import net.minecraft.nbt.Tag; 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.chunk.storage.RegionFile; import net.minecraft.world.level.storage.LevelResource; @@ -23,7 +23,9 @@ import org.jetbrains.annotations.NotNull; import ru.bclib.BCLib; import ru.bclib.api.WorldDataAPI; import ru.bclib.config.Configs; +import ru.bclib.gui.screens.AtomicProgressListener; import ru.bclib.gui.screens.ConfirmFixScreen; +import ru.bclib.gui.screens.ProgressScreen; import ru.bclib.util.Logger; import java.io.DataInputStream; @@ -32,6 +34,8 @@ import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; @@ -149,41 +153,76 @@ public class DataFixerAPI { 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 onResume) { MigrationProfile profile = loadProfileIfNeeded(dir); - - Consumer runFixes = (applyFixes) -> { + + BiConsumer runFixes = (createBackup, applyFixes) -> { + final AtomicProgressListener progress; if (applyFixes) { - runDataFixes(dir, profile, new ProgressListener() { - private long timeStamp = Util.getMillis(); + if (showUI) { + progress = showProgressScreen(); + } else { + progress = new AtomicProgressListener() { + private long timeStamp = Util.getMillis(); + private AtomicInteger counter = new AtomicInteger(0); - public void progressStartNoAbort(Component component) { - } - - public void progressStart(Component component) { - } - - public void progressStagePercentage(int i) { - if (Util.getMillis() - this.timeStamp >= 1000L) { - this.timeStamp = Util.getMillis(); - BCLib.LOGGER.info((String) "Patching... {}%", (Object) i); + @Override + public void incAtomic(int maxProgress) { + int percentage = (100 * counter.incrementAndGet()) / maxProgress; + if (Util.getMillis() - this.timeStamp >= 1000L) { + this.timeStamp = Util.getMillis(); + BCLib.LOGGER.info((String) "Patching... {}%", percentage); + } } - } - 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 { - //System.out.println("NO FIXES"); + progress = null; } - - //UI is asynchronous, so we need to send the callback now - if (profile != null && showUI) { - onResume.accept(applyFixes); + + Runnable runner = () -> { + if (createBackup) { + 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; } else { BCLib.LOGGER.warning("Applying Fixes on Level"); - runFixes.accept(true); + runFixes.accept(false, true); } } return false; @@ -208,6 +247,8 @@ public class DataFixerAPI { } MigrationProfile profile = getMigrationProfile(); + //TODO: Remove on Production + if (!BCLib.isDevEnvironment()) profile.runPrePatches(levelBaseDir); if (!profile.hasAnyFixes()) { @@ -226,46 +267,53 @@ public class DataFixerAPI { } @Environment(EnvType.CLIENT) - static void showBackupWarning(String levelID, Consumer whenFinished){ - Minecraft.getInstance().setScreen(new ConfirmFixScreen((Screen) null, (createBackup, applyFixes) -> { - if (createBackup) { - EditWorldScreen.makeBackupAndShowToast(Minecraft.getInstance().getLevelSource(), levelID); - } - - Minecraft.getInstance().setScreen((Screen)null); - whenFinished.accept(applyFixes); - })); + static void showBackupWarning(String levelID, BiConsumer whenFinished){ + Minecraft.getInstance().setScreen(new ConfirmFixScreen((Screen) null, whenFinished::accept)); } - private static void runDataFixes(File dir, MigrationProfile profile, ProgressListener progress) { + private static void runDataFixes(File dir, MigrationProfile profile, AtomicProgressListener progress) { State state = new State(); - - List 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.resetAtomic(); + progress.progressStage(new TranslatableComponent("message.bclib.datafixer.progress.reading")); List players = getAllPlayers(dir); - players.parallelStream().forEach((file) -> fixPlayer(profile, state, file)); + List 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); + progress.incAtomic(maxProgress); + progress.progressStage(new TranslatableComponent("message.bclib.datafixer.progress.worlddata")); try { profile.patchWorldData(); } catch (PatchDidiFailException e){ state.didFail = true; 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) { + progress.progressStage(new TranslatableComponent("message.bclib.datafixer.progress.saving")); profile.markApplied(); WorldDataAPI.saveFile(BCLib.MOD_ID); } + progress.incAtomic(maxProgress); + + progress.stop(); } private static void fixLevel(MigrationProfile profile, State state, File levelBaseDir) { diff --git a/src/main/java/ru/bclib/api/datafixer/MigrationProfile.java b/src/main/java/ru/bclib/api/datafixer/MigrationProfile.java index d5e1b6e0..24e5e8ad 100644 --- a/src/main/java/ru/bclib/api/datafixer/MigrationProfile.java +++ b/src/main/java/ru/bclib/api/datafixer/MigrationProfile.java @@ -1,5 +1,6 @@ package ru.bclib.api.datafixer; +import net.fabricmc.loom.util.ModUtils; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtIo; @@ -123,7 +124,7 @@ public class MigrationProfile { final public void markApplied() { 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)); } } diff --git a/src/main/java/ru/bclib/gui/screens/AtomicProgressListener.java b/src/main/java/ru/bclib/gui/screens/AtomicProgressListener.java new file mode 100644 index 00000000..c1b1c7e1 --- /dev/null +++ b/src/main/java/ru/bclib/gui/screens/AtomicProgressListener.java @@ -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); +} diff --git a/src/main/java/ru/bclib/gui/screens/ProgressScreen.java b/src/main/java/ru/bclib/gui/screens/ProgressScreen.java index 54680390..84ee76c8 100644 --- a/src/main/java/ru/bclib/gui/screens/ProgressScreen.java +++ b/src/main/java/ru/bclib/gui/screens/ProgressScreen.java @@ -25,6 +25,8 @@ import ru.bclib.gui.gridlayout.GridScreen; import ru.bclib.gui.gridlayout.GridStringCell; import ru.bclib.gui.gridlayout.GridTransform; +import java.util.concurrent.atomic.AtomicInteger; + class ProgressLogoRender extends GridCustomRenderCell { public static final int SIZE = 64; 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"); public ProgressScreen(@Nullable Screen parent, Component title, Component description) { super(parent, title, 20, false); this.description = description; } + Component description; private Component stageComponent; @@ -108,6 +112,21 @@ public class ProgressScreen extends GridScreen implements ProgressListener { private GridStringCell progress; private ProgressLogoRender progressImage; 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() { return false; } @@ -165,7 +184,6 @@ public class ProgressScreen extends GridScreen implements ProgressListener { if (i!=currentProgress) { currentProgress = i; if (progressImage!=null) progressImage.percentage = currentProgress / 100.0f; - BCLib.LOGGER.info(" -> progress: " + i + "%"); if (progress!=null) progress.setText(getProgressComponent()); } } @@ -174,13 +192,4 @@ public class ProgressScreen extends GridScreen implements ProgressListener { 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); - } } diff --git a/src/main/resources/assets/bclib/lang/en_us.json b/src/main/resources/assets/bclib/lang/en_us.json index 4255702c..70b7d2be 100644 --- a/src/main/resources/assets/bclib/lang/en_us.json +++ b/src/main/resources/assets/bclib/lang/en_us.json @@ -33,5 +33,14 @@ "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.", "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." } \ No newline at end of file