minecraft-src/net/minecraft/client/gui/screens/worldselection/EditWorldScreen.java
2025-07-04 03:45:38 +03:00

173 lines
7.9 KiB
Java

package net.minecraft.client.gui.screens.worldselection;
import com.mojang.logging.LogUtils;
import it.unimi.dsi.fastutil.booleans.BooleanConsumer;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.ChatFormatting;
import net.minecraft.FileUtil;
import net.minecraft.Util;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.EditBox;
import net.minecraft.client.gui.components.StringWidget;
import net.minecraft.client.gui.components.toasts.SystemToast;
import net.minecraft.client.gui.layouts.FrameLayout;
import net.minecraft.client.gui.layouts.LinearLayout;
import net.minecraft.client.gui.layouts.SpacerElement;
import net.minecraft.client.gui.screens.BackupConfirmScreen;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.nbt.NbtException;
import net.minecraft.nbt.ReportedNbtException;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.util.Mth;
import net.minecraft.util.StringUtil;
import net.minecraft.world.level.storage.LevelResource;
import net.minecraft.world.level.storage.LevelStorageSource;
import net.minecraft.world.level.storage.LevelSummary;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
@Environment(EnvType.CLIENT)
public class EditWorldScreen extends Screen {
private static final Logger LOGGER = LogUtils.getLogger();
private static final Component NAME_LABEL = Component.translatable("selectWorld.enterName").withStyle(ChatFormatting.GRAY);
private static final Component RESET_ICON_BUTTON = Component.translatable("selectWorld.edit.resetIcon");
private static final Component FOLDER_BUTTON = Component.translatable("selectWorld.edit.openFolder");
private static final Component BACKUP_BUTTON = Component.translatable("selectWorld.edit.backup");
private static final Component BACKUP_FOLDER_BUTTON = Component.translatable("selectWorld.edit.backupFolder");
private static final Component OPTIMIZE_BUTTON = Component.translatable("selectWorld.edit.optimize");
private static final Component OPTIMIZE_TITLE = Component.translatable("optimizeWorld.confirm.title");
private static final Component OPTIMIIZE_DESCRIPTION = Component.translatable("optimizeWorld.confirm.description");
private static final Component OPTIMIIZE_CONFIRMATION = Component.translatable("optimizeWorld.confirm.proceed");
private static final Component SAVE_BUTTON = Component.translatable("selectWorld.edit.save");
private static final int DEFAULT_WIDTH = 200;
private static final int VERTICAL_SPACING = 4;
private static final int HALF_WIDTH = 98;
private final LinearLayout layout = LinearLayout.vertical().spacing(5);
private final BooleanConsumer callback;
private final LevelStorageSource.LevelStorageAccess levelAccess;
private final EditBox nameEdit;
public static EditWorldScreen create(Minecraft minecraft, LevelStorageSource.LevelStorageAccess levelAccess, BooleanConsumer callback) throws IOException {
LevelSummary levelSummary = levelAccess.getSummary(levelAccess.getDataTag());
return new EditWorldScreen(minecraft, levelAccess, levelSummary.getLevelName(), callback);
}
private EditWorldScreen(Minecraft minecraft, LevelStorageSource.LevelStorageAccess levelAccess, String levelName, BooleanConsumer callback) {
super(Component.translatable("selectWorld.edit.title"));
this.callback = callback;
this.levelAccess = levelAccess;
Font font = minecraft.font;
this.layout.addChild(new SpacerElement(200, 20));
this.layout.addChild(new StringWidget(NAME_LABEL, font));
this.nameEdit = this.layout.addChild(new EditBox(font, 200, 20, NAME_LABEL));
this.nameEdit.setValue(levelName);
LinearLayout linearLayout = LinearLayout.horizontal().spacing(4);
Button button = linearLayout.addChild(Button.builder(SAVE_BUTTON, buttonx -> this.onRename(this.nameEdit.getValue())).width(98).build());
linearLayout.addChild(Button.builder(CommonComponents.GUI_CANCEL, buttonx -> this.onClose()).width(98).build());
this.nameEdit.setResponder(string -> button.active = !StringUtil.isBlank(string));
this.layout.addChild(Button.builder(RESET_ICON_BUTTON, buttonx -> {
levelAccess.getIconFile().ifPresent(path -> FileUtils.deleteQuietly(path.toFile()));
buttonx.active = false;
}).width(200).build()).active = levelAccess.getIconFile().filter(path -> Files.isRegularFile(path, new LinkOption[0])).isPresent();
this.layout.addChild(Button.builder(FOLDER_BUTTON, buttonx -> Util.getPlatform().openPath(levelAccess.getLevelPath(LevelResource.ROOT))).width(200).build());
this.layout.addChild(Button.builder(BACKUP_BUTTON, buttonx -> {
boolean bl = makeBackupAndShowToast(levelAccess);
this.callback.accept(!bl);
}).width(200).build());
this.layout.addChild(Button.builder(BACKUP_FOLDER_BUTTON, buttonx -> {
LevelStorageSource levelStorageSource = minecraft.getLevelSource();
Path path = levelStorageSource.getBackupPath();
try {
FileUtil.createDirectoriesSafe(path);
} catch (IOException var5x) {
throw new RuntimeException(var5x);
}
Util.getPlatform().openPath(path);
}).width(200).build());
this.layout.addChild(Button.builder(OPTIMIZE_BUTTON, buttonx -> minecraft.setScreen(new BackupConfirmScreen(() -> minecraft.setScreen(this), (bl, bl2) -> {
if (bl) {
makeBackupAndShowToast(levelAccess);
}
minecraft.setScreen(OptimizeWorldScreen.create(minecraft, this.callback, minecraft.getFixerUpper(), levelAccess, bl2));
}, OPTIMIZE_TITLE, OPTIMIIZE_DESCRIPTION, OPTIMIIZE_CONFIRMATION, true))).width(200).build());
this.layout.addChild(new SpacerElement(200, 20));
this.layout.addChild(linearLayout);
this.layout.visitWidgets(guiEventListener -> {
AbstractWidget var10000 = this.addRenderableWidget(guiEventListener);
});
}
@Override
protected void setInitialFocus() {
this.setInitialFocus(this.nameEdit);
}
@Override
protected void init() {
this.repositionElements();
}
@Override
protected void repositionElements() {
this.layout.arrangeElements();
FrameLayout.centerInRectangle(this.layout, this.getRectangle());
}
@Override
public void onClose() {
this.callback.accept(false);
}
private void onRename(String saveName) {
try {
this.levelAccess.renameLevel(saveName);
} catch (NbtException | ReportedNbtException | IOException var3) {
LOGGER.error("Failed to access world '{}'", this.levelAccess.getLevelId(), var3);
SystemToast.onWorldAccessFailure(this.minecraft, this.levelAccess.getLevelId());
}
this.callback.accept(true);
}
public static boolean makeBackupAndShowToast(LevelStorageSource.LevelStorageAccess levelAccess) {
long l = 0L;
IOException iOException = null;
try {
l = levelAccess.makeWorldBackup();
} catch (IOException var6) {
iOException = var6;
}
if (iOException != null) {
Component component = Component.translatable("selectWorld.edit.backupFailed");
Component component2 = Component.literal(iOException.getMessage());
Minecraft.getInstance().getToastManager().addToast(new SystemToast(SystemToast.SystemToastId.WORLD_BACKUP, component, component2));
return false;
} else {
Component component = Component.translatable("selectWorld.edit.backupCreated", levelAccess.getLevelId());
Component component2 = Component.translatable("selectWorld.edit.backupSize", Mth.ceil(l / 1048576.0));
Minecraft.getInstance().getToastManager().addToast(new SystemToast(SystemToast.SystemToastId.WORLD_BACKUP, component, component2));
return true;
}
}
@Override
public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) {
super.render(guiGraphics, mouseX, mouseY, partialTick);
guiGraphics.drawCenteredString(this.font, this.title, this.width / 2, 15, 16777215);
}
}