RealmsDownloadLatestWorldScreen.java

com.mojang.realmsclient.gui.screens.RealmsDownloadLatestWorldScreen

信息

  • 全限定名:com.mojang.realmsclient.gui.screens.RealmsDownloadLatestWorldScreen
  • 类型:public class
  • 包:com.mojang.realmsclient.gui.screens
  • 源码路径:src/main/java/com/mojang/realmsclient/gui/screens/RealmsDownloadLatestWorldScreen.java
  • 起始行号:L28
  • 继承:RealmsScreen
  • 职责:

    TODO

字段/常量

  • LOGGER

    • 类型: Logger
    • 修饰符: private static final
    • 源码定位: L29
    • 说明:

      TODO

  • DOWNLOAD_LOCK

    • 类型: ReentrantLock
    • 修饰符: private static final
    • 源码定位: L30
    • 说明:

      TODO

  • BAR_WIDTH

    • 类型: int
    • 修饰符: private static final
    • 源码定位: L31
    • 说明:

      TODO

  • BAR_TOP

    • 类型: int
    • 修饰符: private static final
    • 源码定位: L32
    • 说明:

      TODO

  • BAR_BOTTOM

    • 类型: int
    • 修饰符: private static final
    • 源码定位: L33
    • 说明:

      TODO

  • BAR_BORDER

    • 类型: int
    • 修饰符: private static final
    • 源码定位: L34
    • 说明:

      TODO

  • lastScreen

    • 类型: Screen
    • 修饰符: private final
    • 源码定位: L35
    • 说明:

      TODO

  • worldDownload

    • 类型: WorldDownload
    • 修饰符: private final
    • 源码定位: L36
    • 说明:

      TODO

  • downloadTitle

    • 类型: Component
    • 修饰符: private final
    • 源码定位: L37
    • 说明:

      TODO

  • narrationRateLimiter

    • 类型: RateLimiter
    • 修饰符: private final
    • 源码定位: L38
    • 说明:

      TODO

  • cancelButton

    • 类型: Button
    • 修饰符: private
    • 源码定位: L39
    • 说明:

      TODO

  • worldName

    • 类型: String
    • 修饰符: private final
    • 源码定位: L40
    • 说明:

      TODO

  • downloadStatus

    • 类型: RealmsDownloadLatestWorldScreen.DownloadStatus
    • 修饰符: private final
    • 源码定位: L41
    • 说明:

      TODO

  • errorMessage

    • 类型: Component
    • 修饰符: private volatile
    • 源码定位: L42
    • 说明:

      TODO

  • status

    • 类型: Component
    • 修饰符: private volatile
    • 源码定位: L43
    • 说明:

      TODO

  • progress

    • 类型: String
    • 修饰符: private volatile
    • 源码定位: L44
    • 说明:

      TODO

  • cancelled

    • 类型: boolean
    • 修饰符: private volatile
    • 源码定位: L45
    • 说明:

      TODO

  • showDots

    • 类型: boolean
    • 修饰符: private volatile
    • 源码定位: L46
    • 说明:

      TODO

  • finished

    • 类型: boolean
    • 修饰符: private volatile
    • 源码定位: L47
    • 说明:

      TODO

  • extracting

    • 类型: boolean
    • 修饰符: private volatile
    • 源码定位: L48
    • 说明:

      TODO

  • previousWrittenBytes

    • 类型: Long
    • 修饰符: private
    • 源码定位: L49
    • 说明:

      TODO

  • previousTimeSnapshot

    • 类型: Long
    • 修饰符: private
    • 源码定位: L50
    • 说明:

      TODO

  • bytesPersSecond

    • 类型: long
    • 修饰符: private
    • 源码定位: L51
    • 说明:

      TODO

  • animTick

    • 类型: int
    • 修饰符: private
    • 源码定位: L52
    • 说明:

      TODO

  • DOTS

    • 类型: String[]
    • 修饰符: private static final
    • 源码定位: L53
    • 说明:

      TODO

  • dotIndex

    • 类型: int
    • 修饰符: private
    • 源码定位: L54
    • 说明:

      TODO

  • checked

    • 类型: boolean
    • 修饰符: private
    • 源码定位: L55
    • 说明:

      TODO

  • callback

    • 类型: BooleanConsumer
    • 修饰符: private final
    • 源码定位: L56
    • 说明:

      TODO

内部类/嵌套类型

  • com.mojang.realmsclient.gui.screens.RealmsDownloadLatestWorldScreen.DownloadStatus
    • 类型: class
    • 修饰符: public static
    • 源码定位: L272
    • 说明:

      TODO

构造器

public RealmsDownloadLatestWorldScreen(Screen lastScreen, WorldDownload worldDownload, String worldName, BooleanConsumer callback) @ L58

  • 构造器名:RealmsDownloadLatestWorldScreen
  • 源码定位:L58
  • 修饰符:public

参数:

  • lastScreen: Screen
  • worldDownload: WorldDownload
  • worldName: String
  • callback: BooleanConsumer

说明:

TODO

方法

下面的方法块按源码顺序生成。

public void init() @ L69

  • 方法名:init
  • 源码定位:L69
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

private void checkDownloadSize() @ L77

  • 方法名:checkDownloadSize
  • 源码定位:L77
  • 返回类型:void
  • 修饰符:private

参数:

说明:

TODO

  • 方法名:getContentLength
  • 源码定位:L92
  • 返回类型:long
  • 修饰符:private

参数:

  • downloadLink: String

说明:

TODO

public void tick() @ L96

  • 方法名:tick
  • 源码定位:L96
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

private Component createProgressNarrationMessage() @ L106

  • 方法名:createProgressNarrationMessage
  • 源码定位:L106
  • 返回类型:Component
  • 修饰符:private

参数:

说明:

TODO

public void onClose() @ L122

  • 方法名:onClose
  • 源码定位:L122
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

public void extractRenderState(GuiGraphicsExtractor graphics, int xm, int ym, float a) @ L132

  • 方法名:extractRenderState
  • 源码定位:L132
  • 返回类型:void
  • 修饰符:public

参数:

  • graphics: GuiGraphicsExtractor
  • xm: int
  • ym: int
  • a: float

说明:

TODO

private void extractDots(GuiGraphicsExtractor graphics) @ L151

  • 方法名:extractDots
  • 源码定位:L151
  • 返回类型:void
  • 修饰符:private

参数:

  • graphics: GuiGraphicsExtractor

说明:

TODO

private void extractProgressBar(GuiGraphicsExtractor graphics) @ L160

  • 方法名:extractProgressBar
  • 源码定位:L160
  • 返回类型:void
  • 修饰符:private

参数:

  • graphics: GuiGraphicsExtractor

说明:

TODO

private void extractDownloadSpeed(GuiGraphicsExtractor graphics) @ L170

  • 方法名:extractDownloadSpeed
  • 源码定位:L170
  • 返回类型:void
  • 修饰符:private

参数:

  • graphics: GuiGraphicsExtractor

说明:

TODO

private void extractDownloadSpeed0(GuiGraphicsExtractor graphics, long bytesPerSecond) @ L189

  • 方法名:extractDownloadSpeed0
  • 源码定位:L189
  • 返回类型:void
  • 修饰符:private

参数:

  • graphics: GuiGraphicsExtractor
  • bytesPerSecond: long

说明:

TODO

private void downloadSave() @ L198

  • 方法名:downloadSave
  • 源码定位:L198
  • 返回类型:void
  • 修饰符:private

参数:

说明:

TODO

private void downloadCancelled() @ L267

  • 方法名:downloadCancelled
  • 源码定位:L267
  • 返回类型:void
  • 修饰符:private

参数:

说明:

TODO

代码

@OnlyIn(Dist.CLIENT)
public class RealmsDownloadLatestWorldScreen extends RealmsScreen {
    private static final Logger LOGGER = LogUtils.getLogger();
    private static final ReentrantLock DOWNLOAD_LOCK = new ReentrantLock();
    private static final int BAR_WIDTH = 200;
    private static final int BAR_TOP = 80;
    private static final int BAR_BOTTOM = 95;
    private static final int BAR_BORDER = 1;
    private final Screen lastScreen;
    private final WorldDownload worldDownload;
    private final Component downloadTitle;
    private final RateLimiter narrationRateLimiter;
    private Button cancelButton;
    private final String worldName;
    private final RealmsDownloadLatestWorldScreen.DownloadStatus downloadStatus;
    private volatile @Nullable Component errorMessage;
    private volatile Component status = Component.translatable("mco.download.preparing");
    private volatile @Nullable String progress;
    private volatile boolean cancelled;
    private volatile boolean showDots = true;
    private volatile boolean finished;
    private volatile boolean extracting;
    private @Nullable Long previousWrittenBytes;
    private @Nullable Long previousTimeSnapshot;
    private long bytesPersSecond;
    private int animTick;
    private static final String[] DOTS = new String[]{"", ".", ". .", ". . ."};
    private int dotIndex;
    private boolean checked;
    private final BooleanConsumer callback;
 
    public RealmsDownloadLatestWorldScreen(Screen lastScreen, WorldDownload worldDownload, String worldName, BooleanConsumer callback) {
        super(GameNarrator.NO_TITLE);
        this.callback = callback;
        this.lastScreen = lastScreen;
        this.worldName = worldName;
        this.worldDownload = worldDownload;
        this.downloadStatus = new RealmsDownloadLatestWorldScreen.DownloadStatus();
        this.downloadTitle = Component.translatable("mco.download.title");
        this.narrationRateLimiter = RateLimiter.create(0.1F);
    }
 
    @Override
    public void init() {
        this.cancelButton = this.addRenderableWidget(
            Button.builder(CommonComponents.GUI_CANCEL, button -> this.onClose()).bounds((this.width - 200) / 2, this.height - 42, 200, 20).build()
        );
        this.checkDownloadSize();
    }
 
    private void checkDownloadSize() {
        if (!this.finished && !this.checked) {
            this.checked = true;
            if (this.getContentLength(this.worldDownload.downloadLink()) >= 5368709120L) {
                Component popupMessage = Component.translatable("mco.download.confirmation.oversized", Unit.humanReadable(5368709120L));
                this.minecraft.setScreen(RealmsPopups.warningAcknowledgePopupScreen(this, popupMessage, popupScreen -> {
                    this.minecraft.setScreen(this);
                    this.downloadSave();
                }));
            } else {
                this.downloadSave();
            }
        }
    }
 
    private long getContentLength(String downloadLink) {
        return FileDownload.contentLength(downloadLink).orElse(0L);
    }
 
    @Override
    public void tick() {
        super.tick();
        this.animTick++;
        if (this.status != null && this.narrationRateLimiter.tryAcquire(1)) {
            Component message = this.createProgressNarrationMessage();
            this.minecraft.getNarrator().saySystemNow(message);
        }
    }
 
    private Component createProgressNarrationMessage() {
        List<Component> elements = Lists.newArrayList();
        elements.add(this.downloadTitle);
        elements.add(this.status);
        if (this.progress != null) {
            elements.add(Component.translatable("mco.download.percent", this.progress));
            elements.add(Component.translatable("mco.download.speed.narration", Unit.humanReadable(this.bytesPersSecond)));
        }
 
        if (this.errorMessage != null) {
            elements.add(this.errorMessage);
        }
 
        return CommonComponents.joinLines(elements);
    }
 
    @Override
    public void onClose() {
        this.cancelled = true;
        if (this.finished && this.callback != null && this.errorMessage == null) {
            this.callback.accept(true);
        }
 
        this.minecraft.setScreen(this.lastScreen);
    }
 
    @Override
    public void extractRenderState(GuiGraphicsExtractor graphics, int xm, int ym, float a) {
        super.extractRenderState(graphics, xm, ym, a);
        graphics.centeredText(this.font, this.downloadTitle, this.width / 2, 20, -1);
        graphics.centeredText(this.font, this.status, this.width / 2, 50, -1);
        if (this.showDots) {
            this.extractDots(graphics);
        }
 
        if (this.downloadStatus.bytesWritten != 0L && !this.cancelled) {
            this.extractProgressBar(graphics);
            this.extractDownloadSpeed(graphics);
        }
 
        if (this.errorMessage != null) {
            graphics.centeredText(this.font, this.errorMessage, this.width / 2, 110, -65536);
        }
    }
 
    private void extractDots(GuiGraphicsExtractor graphics) {
        int statusWidth = this.font.width(this.status);
        if (this.animTick != 0 && this.animTick % 10 == 0) {
            this.dotIndex++;
        }
 
        graphics.text(this.font, DOTS[this.dotIndex % DOTS.length], this.width / 2 + statusWidth / 2 + 5, 50, -1);
    }
 
    private void extractProgressBar(GuiGraphicsExtractor graphics) {
        double percentage = Math.min((double)this.downloadStatus.bytesWritten / this.downloadStatus.totalBytes, 1.0);
        this.progress = String.format(Locale.ROOT, "%.1f", percentage * 100.0);
        int left = (this.width - 200) / 2;
        int right = left + (int)Math.round(200.0 * percentage);
        graphics.fill(left - 1, 79, right + 1, 96, -1);
        graphics.fill(left, 80, right, 95, -8355712);
        graphics.centeredText(this.font, Component.translatable("mco.download.percent", this.progress), this.width / 2, 84, -1);
    }
 
    private void extractDownloadSpeed(GuiGraphicsExtractor graphics) {
        if (this.animTick % 20 == 0) {
            if (this.previousWrittenBytes != null) {
                long timeElapsed = Util.getMillis() - this.previousTimeSnapshot;
                if (timeElapsed == 0L) {
                    timeElapsed = 1L;
                }
 
                this.bytesPersSecond = 1000L * (this.downloadStatus.bytesWritten - this.previousWrittenBytes) / timeElapsed;
                this.extractDownloadSpeed0(graphics, this.bytesPersSecond);
            }
 
            this.previousWrittenBytes = this.downloadStatus.bytesWritten;
            this.previousTimeSnapshot = Util.getMillis();
        } else {
            this.extractDownloadSpeed0(graphics, this.bytesPersSecond);
        }
    }
 
    private void extractDownloadSpeed0(GuiGraphicsExtractor graphics, long bytesPerSecond) {
        if (bytesPerSecond > 0L) {
            int progressLength = this.font.width(this.progress);
            graphics.text(
                this.font, Component.translatable("mco.download.speed", Unit.humanReadable(bytesPerSecond)), this.width / 2 + progressLength / 2 + 15, 84, -1
            );
        }
    }
 
    private void downloadSave() {
        new Thread(() -> {
            try {
                try {
                    if (!DOWNLOAD_LOCK.tryLock(1L, TimeUnit.SECONDS)) {
                        this.status = Component.translatable("mco.download.failed");
                        return;
                    }
 
                    if (this.cancelled) {
                        this.downloadCancelled();
                        return;
                    }
 
                    this.status = Component.translatable("mco.download.downloading", this.worldName);
                    FileDownload fileDownload = new FileDownload();
                    fileDownload.download(this.worldDownload, this.worldName, this.downloadStatus, this.minecraft.getLevelSource());
 
                    while (!fileDownload.isFinished()) {
                        if (fileDownload.isError()) {
                            fileDownload.cancel();
                            this.errorMessage = Component.translatable("mco.download.failed");
                            this.cancelButton.setMessage(CommonComponents.GUI_DONE);
                            return;
                        }
 
                        if (fileDownload.isExtracting()) {
                            if (!this.extracting) {
                                this.status = Component.translatable("mco.download.extracting");
                            }
 
                            this.extracting = true;
                        }
 
                        if (this.cancelled) {
                            fileDownload.cancel();
                            this.downloadCancelled();
                            return;
                        }
 
                        try {
                            Thread.sleep(500L);
                        } catch (InterruptedException var8) {
                            LOGGER.error("Failed to check Realms backup download status");
                        }
                    }
 
                    this.finished = true;
                    this.status = Component.translatable("mco.download.done");
                    this.cancelButton.setMessage(CommonComponents.GUI_DONE);
                    return;
                } catch (InterruptedException var9) {
                    LOGGER.error("Could not acquire upload lock");
                } catch (Exception var10) {
                    this.errorMessage = Component.translatable("mco.download.failed");
                    LOGGER.info("Exception while downloading world", (Throwable)var10);
                }
            } finally {
                if (!DOWNLOAD_LOCK.isHeldByCurrentThread()) {
                    return;
                } else {
                    DOWNLOAD_LOCK.unlock();
                    this.showDots = false;
                    this.finished = true;
                }
            }
        }).start();
    }
 
    private void downloadCancelled() {
        this.status = Component.translatable("mco.download.cancelled");
    }
 
    @OnlyIn(Dist.CLIENT)
    public static class DownloadStatus {
        public volatile long bytesWritten;
        public volatile long totalBytes;
    }
}

引用的其他类

  • Unit

    • 引用位置: 方法调用
    • 关联成员: Unit.humanReadable()
  • FileDownload

    • 引用位置: 方法调用/构造调用
    • 关联成员: FileDownload(), FileDownload.contentLength()
  • WorldDownload

    • 引用位置: 参数/字段
  • RealmsPopups

    • 引用位置: 方法调用
    • 关联成员: RealmsPopups.warningAcknowledgePopupScreen()
  • GuiGraphicsExtractor

    • 引用位置: 参数
  • Button

    • 引用位置: 字段/方法调用
    • 关联成员: Button.builder()
  • Screen

    • 引用位置: 参数/字段
  • CommonComponents

    • 引用位置: 方法调用
    • 关联成员: CommonComponents.joinLines()
  • Component

    • 引用位置: 字段/方法调用/返回值
    • 关联成员: Component.translatable()
  • RealmsScreen

    • 引用位置: 继承
  • Util

    • 引用位置: 方法调用
    • 关联成员: Util.getMillis()