package com.mojang.realmsclient.gui.screens; import com.mojang.logging.LogUtils; import com.mojang.realmsclient.client.RealmsClient; import com.mojang.realmsclient.dto.Backup; import com.mojang.realmsclient.dto.RealmsServer; import com.mojang.realmsclient.dto.RealmsWorldOptions; import com.mojang.realmsclient.exception.RealmsServiceException; import com.mojang.realmsclient.util.RealmsUtil; import com.mojang.realmsclient.util.task.DownloadTask; import com.mojang.realmsclient.util.task.RestoreTask; import java.text.DateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Objects; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.Minecraft; 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.ContainerObjectSelectionList; import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.gui.layouts.HeaderAndFooterLayout; import net.minecraft.client.gui.layouts.LinearLayout; import net.minecraft.client.gui.narration.NarratableEntry; import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Component; import net.minecraft.realms.RealmsScreen; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; @Environment(EnvType.CLIENT) public class RealmsBackupScreen extends RealmsScreen { static final Logger LOGGER = LogUtils.getLogger(); private static final Component TITLE = Component.translatable("mco.configure.world.backup"); static final Component RESTORE_TOOLTIP = Component.translatable("mco.backup.button.restore"); static final Component HAS_CHANGES_TOOLTIP = Component.translatable("mco.backup.changes.tooltip"); private static final Component NO_BACKUPS_LABEL = Component.translatable("mco.backup.nobackups"); private static final Component DOWNLOAD_LATEST = Component.translatable("mco.backup.button.download"); private static final String UPLOADED_KEY = "uploaded"; private static final int PADDING = 8; final RealmsConfigureWorldScreen lastScreen; List backups = Collections.emptyList(); @Nullable RealmsBackupScreen.BackupObjectSelectionList backupList; final HeaderAndFooterLayout layout = new HeaderAndFooterLayout(this); private final int slotId; @Nullable Button downloadButton; final RealmsServer serverData; boolean noBackups = false; public RealmsBackupScreen(RealmsConfigureWorldScreen lastScreen, RealmsServer serverData, int slotId) { super(TITLE); this.lastScreen = lastScreen; this.serverData = serverData; this.slotId = slotId; } @Override public void init() { this.layout.addTitleHeader(TITLE, this.font); this.backupList = this.layout.addToContents(new RealmsBackupScreen.BackupObjectSelectionList()); LinearLayout linearLayout = this.layout.addToFooter(LinearLayout.horizontal().spacing(8)); this.downloadButton = linearLayout.addChild(Button.builder(DOWNLOAD_LATEST, button -> this.downloadClicked()).build()); this.downloadButton.active = false; linearLayout.addChild(Button.builder(CommonComponents.GUI_BACK, button -> this.onClose()).build()); this.layout.visitWidgets(guiEventListener -> { AbstractWidget var10000 = this.addRenderableWidget(guiEventListener); }); this.repositionElements(); this.fetchRealmsBackups(); } @Override public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { super.render(guiGraphics, mouseX, mouseY, partialTick); if (this.noBackups && this.backupList != null) { guiGraphics.drawString( this.font, NO_BACKUPS_LABEL, this.width / 2 - this.font.width(NO_BACKUPS_LABEL) / 2, this.backupList.getY() + this.backupList.getHeight() / 2 - 9 / 2, -1 ); } } @Override protected void repositionElements() { this.layout.arrangeElements(); if (this.backupList != null) { this.backupList.updateSize(this.width, this.layout); } } private void fetchRealmsBackups() { (new Thread("Realms-fetch-backups") { public void run() { RealmsClient realmsClient = RealmsClient.getOrCreate(); try { List list = realmsClient.backupsFor(RealmsBackupScreen.this.serverData.id).backups; RealmsBackupScreen.this.minecraft .execute( () -> { RealmsBackupScreen.this.backups = list; RealmsBackupScreen.this.noBackups = RealmsBackupScreen.this.backups.isEmpty(); if (!RealmsBackupScreen.this.noBackups && RealmsBackupScreen.this.downloadButton != null) { RealmsBackupScreen.this.downloadButton.active = true; } if (RealmsBackupScreen.this.backupList != null) { RealmsBackupScreen.this.backupList .replaceEntries(RealmsBackupScreen.this.backups.stream().map(backup -> RealmsBackupScreen.this.new Entry(backup)).toList()); } } ); } catch (RealmsServiceException var3) { RealmsBackupScreen.LOGGER.error("Couldn't request backups", (Throwable)var3); } } }) .start(); } @Override public void onClose() { this.minecraft.setScreen(this.lastScreen); } private void downloadClicked() { this.minecraft .setScreen( RealmsPopups.infoPopupScreen( this, Component.translatable("mco.configure.world.restore.download.question.line1"), popupScreen -> this.minecraft .setScreen( new RealmsLongRunningMcoTaskScreen( this.lastScreen.getNewScreen(), new DownloadTask( this.serverData.id, this.slotId, (String)Objects.requireNonNullElse(this.serverData.name, "") + " (" + ((RealmsWorldOptions)this.serverData.slots.get(this.serverData.activeSlot)).getSlotName(this.serverData.activeSlot) + ")", this ) ) ) ) ); } @Environment(EnvType.CLIENT) class BackupObjectSelectionList extends ContainerObjectSelectionList { private static final int ITEM_HEIGHT = 36; public BackupObjectSelectionList() { super( Minecraft.getInstance(), RealmsBackupScreen.this.width, RealmsBackupScreen.this.layout.getContentHeight(), RealmsBackupScreen.this.layout.getHeaderHeight(), 36 ); } @Override public int getRowWidth() { return 300; } } @Environment(EnvType.CLIENT) class Entry extends ContainerObjectSelectionList.Entry { private static final int Y_PADDING = 2; private final Backup backup; @Nullable private Button restoreButton; @Nullable private Button changesButton; private final List children = new ArrayList(); public Entry(final Backup backup) { this.backup = backup; this.populateChangeList(backup); if (!backup.changeList.isEmpty()) { this.changesButton = Button.builder( RealmsBackupScreen.HAS_CHANGES_TOOLTIP, button -> RealmsBackupScreen.this.minecraft.setScreen(new RealmsBackupInfoScreen(RealmsBackupScreen.this, this.backup)) ) .width(8 + RealmsBackupScreen.this.font.width(RealmsBackupScreen.HAS_CHANGES_TOOLTIP)) .createNarration( supplier -> CommonComponents.joinForNarration(Component.translatable("mco.backup.narration", this.getShortBackupDate()), (Component)supplier.get()) ) .build(); this.children.add(this.changesButton); } if (!RealmsBackupScreen.this.serverData.expired) { this.restoreButton = Button.builder(RealmsBackupScreen.RESTORE_TOOLTIP, button -> this.restoreClicked()) .width(8 + RealmsBackupScreen.this.font.width(RealmsBackupScreen.HAS_CHANGES_TOOLTIP)) .createNarration( supplier -> CommonComponents.joinForNarration(Component.translatable("mco.backup.narration", this.getShortBackupDate()), (Component)supplier.get()) ) .build(); this.children.add(this.restoreButton); } } private void populateChangeList(Backup backup) { int i = RealmsBackupScreen.this.backups.indexOf(backup); if (i != RealmsBackupScreen.this.backups.size() - 1) { Backup backup2 = (Backup)RealmsBackupScreen.this.backups.get(i + 1); for (String string : backup.metadata.keySet()) { if (!string.contains("uploaded") && backup2.metadata.containsKey(string)) { if (!((String)backup.metadata.get(string)).equals(backup2.metadata.get(string))) { this.addToChangeList(string); } } else { this.addToChangeList(string); } } } } private void addToChangeList(String change) { if (change.contains("uploaded")) { String string = DateFormat.getDateTimeInstance(3, 3).format(this.backup.lastModifiedDate); this.backup.changeList.put(change, string); this.backup.setUploadedVersion(true); } else { this.backup.changeList.put(change, (String)this.backup.metadata.get(change)); } } private String getShortBackupDate() { return DateFormat.getDateTimeInstance(3, 3).format(this.backup.lastModifiedDate); } private void restoreClicked() { Component component = RealmsUtil.convertToAgePresentationFromInstant(this.backup.lastModifiedDate); Component component2 = Component.translatable("mco.configure.world.restore.question.line1", this.getShortBackupDate(), component); RealmsBackupScreen.this.minecraft .setScreen( RealmsPopups.warningPopupScreen( RealmsBackupScreen.this, component2, popupScreen -> RealmsBackupScreen.this.minecraft .setScreen( new RealmsLongRunningMcoTaskScreen( RealmsBackupScreen.this.lastScreen.getNewScreen(), new RestoreTask(this.backup, RealmsBackupScreen.this.serverData.id, RealmsBackupScreen.this.lastScreen) ) ) ) ); } @Override public List children() { return this.children; } @Override public List narratables() { return this.children; } @Override public void render(GuiGraphics guiGraphics, int index, int top, int left, int width, int height, int mouseX, int mouseY, boolean hovering, float partialTick) { int i = top + height / 2; int j = i - 9 - 2; int k = i + 2; int l = this.backup.isUploadedVersion() ? -8388737 : -1; guiGraphics.drawString( RealmsBackupScreen.this.font, Component.translatable("mco.backup.entry", RealmsUtil.convertToAgePresentationFromInstant(this.backup.lastModifiedDate)), left, j, l ); guiGraphics.drawString(RealmsBackupScreen.this.font, this.getMediumDatePresentation(this.backup.lastModifiedDate), left, k, 5000268); int m = 0; int n = top + height / 2 - 10; if (this.restoreButton != null) { m += this.restoreButton.getWidth() + 8; this.restoreButton.setX(left + width - m); this.restoreButton.setY(n); this.restoreButton.render(guiGraphics, mouseX, mouseY, partialTick); } if (this.changesButton != null) { m += this.changesButton.getWidth() + 8; this.changesButton.setX(left + width - m); this.changesButton.setY(n); this.changesButton.render(guiGraphics, mouseX, mouseY, partialTick); } } private String getMediumDatePresentation(Date date) { return DateFormat.getDateTimeInstance(3, 3).format(date); } } }