package com.mojang.realmsclient.gui.screens; import com.google.common.collect.Lists; import com.mojang.logging.LogUtils; import com.mojang.realmsclient.RealmsMainScreen; import com.mojang.realmsclient.client.RealmsClient; import com.mojang.realmsclient.dto.RealmsServer; import com.mojang.realmsclient.dto.RealmsSlot; import com.mojang.realmsclient.dto.WorldDownload; import com.mojang.realmsclient.exception.RealmsServiceException; import com.mojang.realmsclient.gui.RealmsWorldSlotButton; import com.mojang.realmsclient.util.RealmsTextureManager; import com.mojang.realmsclient.util.RealmsUtil; import com.mojang.realmsclient.util.task.OpenServerTask; import com.mojang.realmsclient.util.task.SwitchSlotTask; import java.util.Collection; import java.util.List; import java.util.Map.Entry; import java.util.stream.Collectors; import java.util.stream.Stream; import net.minecraft.client.gui.GuiGraphicsExtractor; import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.renderer.RenderPipelines; import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.ComponentUtils; import net.minecraft.realms.RealmsScreen; import net.minecraft.resources.Identifier; import net.minecraft.util.ARGB; import net.minecraft.util.Mth; import org.jspecify.annotations.Nullable; import org.slf4j.Logger; public class RealmsBrokenWorldScreen extends RealmsScreen { private static final Identifier SLOT_FRAME_SPRITE = Identifier.withDefaultNamespace("widget/slot_frame"); private static final Logger LOGGER = LogUtils.getLogger(); private static final int DEFAULT_BUTTON_WIDTH = 80; private final Screen lastScreen; @Nullable private RealmsServer serverData; private final long serverId; private final Component[] message = new Component[]{ Component.translatable("mco.brokenworld.message.line1"), Component.translatable("mco.brokenworld.message.line2") }; private int leftX; private final List slotsThatHasBeenDownloaded = Lists.newArrayList(); private int animTick; public RealmsBrokenWorldScreen(final Screen lastScreen, final long serverId, final boolean isMinigame) { super(isMinigame ? Component.translatable("mco.brokenworld.minigame.title") : Component.translatable("mco.brokenworld.title")); this.lastScreen = lastScreen; this.serverId = serverId; } @Override public void init() { this.leftX = this.width / 2 - 150; this.addRenderableWidget(Button.builder(CommonComponents.GUI_BACK, button -> this.onClose()).bounds((this.width - 150) / 2, row(13) - 5, 150, 20).build()); if (this.serverData == null) { this.fetchServerData(this.serverId); } else { this.addButtons(); } } @Override public Component getNarrationMessage() { return ComponentUtils.formatList( (Collection)Stream.concat(Stream.of(this.title), Stream.of(this.message)).collect(Collectors.toList()), CommonComponents.SPACE ); } private void addButtons() { for (Entry entry : this.serverData.slots.entrySet()) { int slot = (Integer)entry.getKey(); boolean canPlay = slot != this.serverData.activeSlot || this.serverData.isMinigameActive(); Button playOrDownloadButton; if (canPlay) { playOrDownloadButton = Button.builder( Component.translatable("mco.brokenworld.play"), var2x -> this.minecraft .gui .setScreen(new RealmsLongRunningMcoTaskScreen(this.lastScreen, new SwitchSlotTask(this.serverData.id, slot, this::doSwitchOrReset))) ) .bounds(this.getFramePositionX(slot), row(8), 80, 20) .build(); playOrDownloadButton.active = !((RealmsSlot)this.serverData.slots.get(slot)).options.empty; } else { playOrDownloadButton = Button.builder( Component.translatable("mco.brokenworld.download"), button -> this.minecraft .gui .setScreen( RealmsPopups.infoPopupScreen(this, Component.translatable("mco.configure.world.restore.download.question.line1"), var2x -> this.downloadWorld(slot)) ) ) .bounds(this.getFramePositionX(slot), row(8), 80, 20) .build(); } if (this.slotsThatHasBeenDownloaded.contains(slot)) { playOrDownloadButton.active = false; playOrDownloadButton.setMessage(Component.translatable("mco.brokenworld.downloaded")); } this.addRenderableWidget(playOrDownloadButton); } } @Override public void tick() { this.animTick++; } @Override public void extractRenderState(final GuiGraphicsExtractor graphics, final int xm, final int ym, final float a) { super.extractRenderState(graphics, xm, ym, a); graphics.centeredText(this.font, this.title, this.width / 2, 17, -1); for (int i = 0; i < this.message.length; i++) { graphics.centeredText(this.font, this.message[i], this.width / 2, row(-1) + 3 + i * 12, -6250336); } if (this.serverData != null) { for (Entry entry : this.serverData.slots.entrySet()) { if (((RealmsSlot)entry.getValue()).options.templateImage != null && ((RealmsSlot)entry.getValue()).options.templateId != -1L) { this.extractSlotFrame( graphics, this.getFramePositionX((Integer)entry.getKey()), row(1) + 5, xm, ym, this.serverData.activeSlot == (Integer)entry.getKey() && !this.isMinigame(), ((RealmsSlot)entry.getValue()).options.getSlotName((Integer)entry.getKey()), (Integer)entry.getKey(), ((RealmsSlot)entry.getValue()).options.templateId, ((RealmsSlot)entry.getValue()).options.templateImage, ((RealmsSlot)entry.getValue()).options.empty ); } else { this.extractSlotFrame( graphics, this.getFramePositionX((Integer)entry.getKey()), row(1) + 5, xm, ym, this.serverData.activeSlot == (Integer)entry.getKey() && !this.isMinigame(), ((RealmsSlot)entry.getValue()).options.getSlotName((Integer)entry.getKey()), (Integer)entry.getKey(), -1L, null, ((RealmsSlot)entry.getValue()).options.empty ); } } } } private int getFramePositionX(final int i) { return this.leftX + (i - 1) * 110; } public Screen createErrorScreen(final RealmsServiceException exception) { return new RealmsGenericErrorScreen(exception, this.lastScreen); } private void fetchServerData(final long realmId) { RealmsUtil.supplyAsync(client -> client.getOwnRealm(realmId), RealmsUtil.openScreenAndLogOnFailure(this::createErrorScreen, "Couldn't get own world")) .thenAcceptAsync(serverData -> { this.serverData = serverData; this.addButtons(); }, this.minecraft); } public void doSwitchOrReset() { new Thread( () -> { RealmsClient client = RealmsClient.getOrCreate(); if (this.serverData.state == RealmsServer.State.CLOSED) { this.minecraft .execute(() -> this.minecraft.gui.setScreen(new RealmsLongRunningMcoTaskScreen(this, new OpenServerTask(this.serverData, this, true, this.minecraft)))); } else { try { RealmsServer ownRealm = client.getOwnRealm(this.serverId); this.minecraft.execute(() -> RealmsMainScreen.play(ownRealm, this)); } catch (RealmsServiceException var3) { LOGGER.error("Couldn't get own world", (Throwable)var3); this.minecraft.execute(() -> this.minecraft.gui.setScreen(this.createErrorScreen(var3))); } } }, "Realms open server" ) .start(); } private void downloadWorld(final int slotId) { RealmsClient client = RealmsClient.getOrCreate(); try { WorldDownload worldDownload = client.requestDownloadInfo(this.serverData.id, slotId); RealmsDownloadLatestWorldScreen downloadScreen = new RealmsDownloadLatestWorldScreen(this, worldDownload, this.serverData.getWorldName(slotId), result -> { if (result) { this.slotsThatHasBeenDownloaded.add(slotId); this.clearWidgets(); this.addButtons(); } else { this.minecraft.gui.setScreen(this); } }); this.minecraft.gui.setScreen(downloadScreen); } catch (RealmsServiceException var5) { LOGGER.error("Couldn't download world data", (Throwable)var5); this.minecraft.gui.setScreen(new RealmsGenericErrorScreen(var5, this)); } } @Override public void onClose() { this.minecraft.gui.setScreen(this.lastScreen); } private boolean isMinigame() { return this.serverData != null && this.serverData.isMinigameActive(); } private void extractSlotFrame( final GuiGraphicsExtractor graphics, final int x, final int y, final int xm, final int ym, final boolean active, final String text, final int i, final long imageId, @Nullable final String image, final boolean empty ) { Identifier texture; if (empty) { texture = RealmsWorldSlotButton.EMPTY_SLOT_LOCATION; } else if (image != null && imageId != -1L) { texture = RealmsTextureManager.worldTemplate(String.valueOf(imageId), image); } else if (i == 1) { texture = RealmsWorldSlotButton.DEFAULT_WORLD_SLOT_1; } else if (i == 2) { texture = RealmsWorldSlotButton.DEFAULT_WORLD_SLOT_2; } else if (i == 3) { texture = RealmsWorldSlotButton.DEFAULT_WORLD_SLOT_3; } else { texture = RealmsTextureManager.worldTemplate(String.valueOf(this.serverData.minigameId), this.serverData.minigameImage); } if (active) { float c = 0.9F + 0.1F * Mth.cos(this.animTick * 0.2F); graphics.blit(RenderPipelines.GUI_TEXTURED, texture, x + 3, y + 3, 0.0F, 0.0F, 74, 74, 74, 74, 74, 74, ARGB.colorFromFloat(1.0F, c, c, c)); graphics.blitSprite(RenderPipelines.GUI_TEXTURED, SLOT_FRAME_SPRITE, x, y, 80, 80); } else { int color = ARGB.colorFromFloat(1.0F, 0.56F, 0.56F, 0.56F); graphics.blit(RenderPipelines.GUI_TEXTURED, texture, x + 3, y + 3, 0.0F, 0.0F, 74, 74, 74, 74, 74, 74, color); graphics.blitSprite(RenderPipelines.GUI_TEXTURED, SLOT_FRAME_SPRITE, x, y, 80, 80, color); } graphics.centeredText(this.font, text, x + 40, y + 66, -1); } }