462 lines
20 KiB
Java
462 lines
20 KiB
Java
package com.mojang.realmsclient.gui.screens;
|
|
|
|
import org.apache.logging.log4j.LogManager;
|
|
import java.io.InputStream;
|
|
import org.apache.commons.compress.utils.IOUtils;
|
|
import java.io.FileInputStream;
|
|
import org.apache.commons.compress.archivers.ArchiveEntry;
|
|
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
|
|
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
|
|
import java.io.OutputStream;
|
|
import java.util.zip.GZIPOutputStream;
|
|
import java.io.FileOutputStream;
|
|
import com.mojang.realmsclient.dto.UploadInfo;
|
|
import com.mojang.realmsclient.exception.RealmsServiceException;
|
|
import java.io.IOException;
|
|
import com.mojang.realmsclient.client.FileUpload;
|
|
import java.io.File;
|
|
import com.mojang.realmsclient.exception.RetryCallException;
|
|
import com.mojang.realmsclient.util.UploadTokenCache;
|
|
import java.util.concurrent.TimeUnit;
|
|
import com.mojang.realmsclient.client.RealmsClient;
|
|
import java.util.List;
|
|
import com.google.common.collect.Lists;
|
|
import net.minecraft.realms.RealmsDefaultVertexFormat;
|
|
import net.minecraft.realms.Tezzelator;
|
|
import com.mojang.blaze3d.systems.RenderSystem;
|
|
import java.util.Locale;
|
|
import net.minecraft.realms.Realms;
|
|
import net.minecraft.realms.AbstractRealmsButton;
|
|
import java.util.concurrent.locks.ReentrantLock;
|
|
import net.minecraft.realms.RealmsButton;
|
|
import com.google.common.util.concurrent.RateLimiter;
|
|
import com.mojang.realmsclient.client.UploadStatus;
|
|
import net.minecraft.realms.RealmsLevelSummary;
|
|
import org.apache.logging.log4j.Logger;
|
|
import net.minecraft.realms.RealmsScreen;
|
|
|
|
public class RealmsUploadScreen extends RealmsScreen {
|
|
private static final Logger LOGGER;
|
|
private final RealmsResetWorldScreen lastScreen;
|
|
private final RealmsLevelSummary selectedLevel;
|
|
private final long worldId;
|
|
private final int slotId;
|
|
private final UploadStatus uploadStatus;
|
|
private final RateLimiter narrationRateLimiter;
|
|
private volatile String errorMessage;
|
|
private volatile String status;
|
|
private volatile String progress;
|
|
private volatile boolean cancelled;
|
|
private volatile boolean uploadFinished;
|
|
private volatile boolean showDots;
|
|
private volatile boolean uploadStarted;
|
|
private RealmsButton backButton;
|
|
private RealmsButton cancelButton;
|
|
private int animTick;
|
|
private static final String[] DOTS;
|
|
private int dotIndex;
|
|
private Long previousWrittenBytes;
|
|
private Long previousTimeSnapshot;
|
|
private long bytesPersSecond;
|
|
private static final ReentrantLock uploadLock;
|
|
|
|
public RealmsUploadScreen(final long long1, final int integer, final RealmsResetWorldScreen daf, final RealmsLevelSummary realmsLevelSummary) {
|
|
this.showDots = true;
|
|
this.worldId = long1;
|
|
this.slotId = integer;
|
|
this.lastScreen = daf;
|
|
this.selectedLevel = realmsLevelSummary;
|
|
this.uploadStatus = new UploadStatus();
|
|
this.narrationRateLimiter = RateLimiter.create(0.10000000149011612);
|
|
}
|
|
|
|
@Override
|
|
public void init() {
|
|
this.setKeyboardHandlerSendRepeatsToGui(true);
|
|
this.backButton = new RealmsButton(1, this.width() / 2 - 100, this.height() - 42, 200, 20, RealmsScreen.getLocalizedString("gui.back")) {
|
|
@Override
|
|
public void onPress() {
|
|
RealmsUploadScreen.this.onBack();
|
|
}
|
|
};
|
|
this.buttonsAdd(this.cancelButton = new RealmsButton(0, this.width() / 2 - 100, this.height() - 42, 200, 20, RealmsScreen.getLocalizedString("gui.cancel")) {
|
|
@Override
|
|
public void onPress() {
|
|
RealmsUploadScreen.this.onCancel();
|
|
}
|
|
});
|
|
if (!this.uploadStarted) {
|
|
if (this.lastScreen.slot == -1) {
|
|
this.upload();
|
|
}
|
|
else {
|
|
this.lastScreen.switchSlot(this);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void confirmResult(final boolean boolean1, final int integer) {
|
|
if (boolean1 && !this.uploadStarted) {
|
|
this.uploadStarted = true;
|
|
Realms.setScreen(this);
|
|
this.upload();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void removed() {
|
|
this.setKeyboardHandlerSendRepeatsToGui(false);
|
|
}
|
|
|
|
private void onBack() {
|
|
this.lastScreen.confirmResult(true, 0);
|
|
}
|
|
|
|
private void onCancel() {
|
|
this.cancelled = true;
|
|
Realms.setScreen(this.lastScreen);
|
|
}
|
|
|
|
@Override
|
|
public boolean keyPressed(final int integer1, final int integer2, final int integer3) {
|
|
if (integer1 == 256) {
|
|
if (this.showDots) {
|
|
this.onCancel();
|
|
}
|
|
else {
|
|
this.onBack();
|
|
}
|
|
return true;
|
|
}
|
|
return super.keyPressed(integer1, integer2, integer3);
|
|
}
|
|
|
|
@Override
|
|
public void render(final int integer1, final int integer2, final float float3) {
|
|
this.renderBackground();
|
|
if (!this.uploadFinished && this.uploadStatus.bytesWritten != 0L && this.uploadStatus.bytesWritten == (long)this.uploadStatus.totalBytes) {
|
|
this.status = RealmsScreen.getLocalizedString("mco.upload.verifying");
|
|
this.cancelButton.active(false);
|
|
}
|
|
this.drawCenteredString(this.status, this.width() / 2, 50, 16777215);
|
|
if (this.showDots) {
|
|
this.drawDots();
|
|
}
|
|
if (this.uploadStatus.bytesWritten != 0L && !this.cancelled) {
|
|
this.drawProgressBar();
|
|
this.drawUploadSpeed();
|
|
}
|
|
if (this.errorMessage != null) {
|
|
final String[] arr5 = this.errorMessage.split("\\\\n");
|
|
for (int integer3 = 0; integer3 < arr5.length; ++integer3) {
|
|
this.drawCenteredString(arr5[integer3], this.width() / 2, 110 + 12 * integer3, 16711680);
|
|
}
|
|
}
|
|
super.render(integer1, integer2, float3);
|
|
}
|
|
|
|
private void drawDots() {
|
|
final int integer2 = this.fontWidth(this.status);
|
|
if (this.animTick % 10 == 0) {
|
|
++this.dotIndex;
|
|
}
|
|
this.drawString(RealmsUploadScreen.DOTS[this.dotIndex % RealmsUploadScreen.DOTS.length], this.width() / 2 + integer2 / 2 + 5, 50, 16777215);
|
|
}
|
|
|
|
private void drawProgressBar() {
|
|
double double2 = this.uploadStatus.bytesWritten / (double)this.uploadStatus.totalBytes * 100.0;
|
|
if (double2 > 100.0) {
|
|
double2 = 100.0;
|
|
}
|
|
this.progress = String.format(Locale.ROOT, "%.1f", double2);
|
|
RenderSystem.color4f(1.0f, 1.0f, 1.0f, 1.0f);
|
|
RenderSystem.disableTexture();
|
|
final double double3 = this.width() / 2 - 100;
|
|
final double double4 = 0.5;
|
|
final Tezzelator tezzelator8 = Tezzelator.instance;
|
|
tezzelator8.begin(7, RealmsDefaultVertexFormat.POSITION_COLOR);
|
|
tezzelator8.vertex(double3 - 0.5, 95.5, 0.0).color(217, 210, 210, 255).endVertex();
|
|
tezzelator8.vertex(double3 + 200.0 * double2 / 100.0 + 0.5, 95.5, 0.0).color(217, 210, 210, 255).endVertex();
|
|
tezzelator8.vertex(double3 + 200.0 * double2 / 100.0 + 0.5, 79.5, 0.0).color(217, 210, 210, 255).endVertex();
|
|
tezzelator8.vertex(double3 - 0.5, 79.5, 0.0).color(217, 210, 210, 255).endVertex();
|
|
tezzelator8.vertex(double3, 95.0, 0.0).color(128, 128, 128, 255).endVertex();
|
|
tezzelator8.vertex(double3 + 200.0 * double2 / 100.0, 95.0, 0.0).color(128, 128, 128, 255).endVertex();
|
|
tezzelator8.vertex(double3 + 200.0 * double2 / 100.0, 80.0, 0.0).color(128, 128, 128, 255).endVertex();
|
|
tezzelator8.vertex(double3, 80.0, 0.0).color(128, 128, 128, 255).endVertex();
|
|
tezzelator8.end();
|
|
RenderSystem.enableTexture();
|
|
this.drawCenteredString(this.progress + " %", this.width() / 2, 84, 16777215);
|
|
}
|
|
|
|
private void drawUploadSpeed() {
|
|
if (this.animTick % 20 == 0) {
|
|
if (this.previousWrittenBytes != null) {
|
|
long long2 = System.currentTimeMillis() - this.previousTimeSnapshot;
|
|
if (long2 == 0L) {
|
|
long2 = 1L;
|
|
}
|
|
this.drawUploadSpeed0(this.bytesPersSecond = 1000L * (this.uploadStatus.bytesWritten - this.previousWrittenBytes) / long2);
|
|
}
|
|
this.previousWrittenBytes = this.uploadStatus.bytesWritten;
|
|
this.previousTimeSnapshot = System.currentTimeMillis();
|
|
}
|
|
else {
|
|
this.drawUploadSpeed0(this.bytesPersSecond);
|
|
}
|
|
}
|
|
|
|
private void drawUploadSpeed0(final long long1) {
|
|
if (long1 > 0L) {
|
|
final int integer4 = this.fontWidth(this.progress);
|
|
final String string5 = "(" + humanReadableByteCount(long1) + ")";
|
|
this.drawString(string5, this.width() / 2 + integer4 / 2 + 15, 84, 16777215);
|
|
}
|
|
}
|
|
|
|
public static String humanReadableByteCount(final long long1) {
|
|
final int integer3 = 1024;
|
|
if (long1 < 1024L) {
|
|
return long1 + " B";
|
|
}
|
|
final int integer4 = (int)(Math.log((double)long1) / Math.log(1024.0));
|
|
final String string5 = "KMGTPE".charAt(integer4 - 1) + "";
|
|
return String.format(Locale.ROOT, "%.1f %sB/s", long1 / Math.pow(1024.0, integer4), string5);
|
|
}
|
|
|
|
@Override
|
|
public void tick() {
|
|
super.tick();
|
|
++this.animTick;
|
|
if (this.status != null && this.narrationRateLimiter.tryAcquire(1)) {
|
|
final List<String> list2 = Lists.newArrayList();
|
|
list2.add(this.status);
|
|
if (this.progress != null) {
|
|
list2.add(this.progress + "%");
|
|
}
|
|
if (this.errorMessage != null) {
|
|
list2.add(this.errorMessage);
|
|
}
|
|
Realms.narrateNow(String.join(System.lineSeparator(), list2));
|
|
}
|
|
}
|
|
|
|
public static Unit getLargestUnit(final long long1) {
|
|
if (long1 < 1024L) {
|
|
return Unit.B;
|
|
}
|
|
final int integer3 = (int)(Math.log((double)long1) / Math.log(1024.0));
|
|
final String string4 = "KMGTPE".charAt(integer3 - 1) + "";
|
|
try {
|
|
return Unit.valueOf(string4 + "B");
|
|
}
|
|
catch (Exception exception5) {
|
|
return Unit.GB;
|
|
}
|
|
}
|
|
|
|
public static double convertToUnit(final long long1, final Unit a) {
|
|
if (a.equals(Unit.B)) {
|
|
return (double)long1;
|
|
}
|
|
return long1 / Math.pow(1024.0, a.ordinal());
|
|
}
|
|
|
|
public static String humanReadableSize(final long long1, final Unit a) {
|
|
return String.format("%." + (a.equals(Unit.GB) ? "1" : "0") + "f %s", convertToUnit(long1, a), a.name());
|
|
}
|
|
|
|
private void upload() {
|
|
this.uploadStarted = true;
|
|
File file2;
|
|
final RealmsClient cyy3;
|
|
final long long4;
|
|
UploadInfo uploadInfo6;
|
|
int integer7;
|
|
File file3;
|
|
long long5;
|
|
Unit a10;
|
|
Unit a11;
|
|
Unit a12;
|
|
FileUpload cyw8;
|
|
final long long6;
|
|
new Thread(() -> {
|
|
file2 = null;
|
|
cyy3 = RealmsClient.createRealmsClient();
|
|
long4 = this.worldId;
|
|
try {
|
|
if (!(!RealmsUploadScreen.uploadLock.tryLock(1L, TimeUnit.SECONDS))) {
|
|
this.status = RealmsScreen.getLocalizedString("mco.upload.preparing");
|
|
uploadInfo6 = null;
|
|
integer7 = 0;
|
|
while (integer7 < 20) {
|
|
try {
|
|
if (this.cancelled) {
|
|
this.uploadCancelled();
|
|
return;
|
|
}
|
|
else {
|
|
uploadInfo6 = cyy3.upload(long4, UploadTokenCache.get(long4));
|
|
}
|
|
}
|
|
catch (RetryCallException czh8) {
|
|
Thread.sleep(czh8.delaySeconds * 1000);
|
|
++integer7;
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
if (uploadInfo6 == null) {
|
|
this.status = RealmsScreen.getLocalizedString("mco.upload.close.failure");
|
|
}
|
|
else {
|
|
UploadTokenCache.put(long4, uploadInfo6.getToken());
|
|
if (!uploadInfo6.isWorldClosed()) {
|
|
this.status = RealmsScreen.getLocalizedString("mco.upload.close.failure");
|
|
}
|
|
else if (this.cancelled) {
|
|
this.uploadCancelled();
|
|
}
|
|
else {
|
|
file3 = new File(Realms.getGameDirectoryPath(), "saves");
|
|
file2 = this.tarGzipArchive(new File(file3, this.selectedLevel.getLevelId()));
|
|
if (this.cancelled) {
|
|
this.uploadCancelled();
|
|
}
|
|
else if (!this.verify(file2)) {
|
|
long5 = file2.length();
|
|
a10 = getLargestUnit(long5);
|
|
a11 = getLargestUnit(5368709120L);
|
|
if (humanReadableSize(long5, a10).equals(humanReadableSize(5368709120L, a11)) && a10 != Unit.B) {
|
|
a12 = Unit.values()[a10.ordinal() - 1];
|
|
this.errorMessage = RealmsScreen.getLocalizedString("mco.upload.size.failure.line1", this.selectedLevel.getLevelName()) + "\\n" + RealmsScreen.getLocalizedString("mco.upload.size.failure.line2", humanReadableSize(long5, a12), humanReadableSize(5368709120L, a12));
|
|
}
|
|
else {
|
|
this.errorMessage = RealmsScreen.getLocalizedString("mco.upload.size.failure.line1", this.selectedLevel.getLevelName()) + "\\n" + RealmsScreen.getLocalizedString("mco.upload.size.failure.line2", humanReadableSize(long5, a10), humanReadableSize(5368709120L, a11));
|
|
}
|
|
}
|
|
else {
|
|
this.status = RealmsScreen.getLocalizedString("mco.upload.uploading", this.selectedLevel.getLevelName());
|
|
cyw8 = new FileUpload(file2, this.worldId, this.slotId, uploadInfo6, Realms.getSessionId(), Realms.getName(), Realms.getMinecraftVersionString(), this.uploadStatus);
|
|
cyw8.upload(dap -> {
|
|
if (dap.statusCode >= 200 && dap.statusCode < 300) {
|
|
this.uploadFinished = true;
|
|
this.status = RealmsScreen.getLocalizedString("mco.upload.done");
|
|
this.backButton.setMessage(RealmsScreen.getLocalizedString("gui.done"));
|
|
UploadTokenCache.invalidate(long6);
|
|
}
|
|
else if (dap.statusCode == 400 && dap.errorMessage != null) {
|
|
this.errorMessage = RealmsScreen.getLocalizedString("mco.upload.failed", dap.errorMessage);
|
|
}
|
|
else {
|
|
this.errorMessage = RealmsScreen.getLocalizedString("mco.upload.failed", dap.statusCode);
|
|
}
|
|
return;
|
|
});
|
|
while (!cyw8.isFinished()) {
|
|
if (this.cancelled) {
|
|
cyw8.cancel();
|
|
this.uploadCancelled();
|
|
}
|
|
else {
|
|
try {
|
|
Thread.sleep(500L);
|
|
}
|
|
catch (InterruptedException interruptedException9) {
|
|
RealmsUploadScreen.LOGGER.error("Failed to check Realms file upload status");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (IOException iOException6) {
|
|
this.errorMessage = RealmsScreen.getLocalizedString("mco.upload.failed", iOException6.getMessage());
|
|
}
|
|
catch (RealmsServiceException czg6) {
|
|
this.errorMessage = RealmsScreen.getLocalizedString("mco.upload.failed", czg6.toString());
|
|
}
|
|
catch (InterruptedException interruptedException10) {
|
|
RealmsUploadScreen.LOGGER.error("Could not acquire upload lock");
|
|
}
|
|
finally {
|
|
this.uploadFinished = true;
|
|
if (RealmsUploadScreen.uploadLock.isHeldByCurrentThread()) {
|
|
RealmsUploadScreen.uploadLock.unlock();
|
|
this.showDots = false;
|
|
this.childrenClear();
|
|
this.buttonsAdd(this.backButton);
|
|
if (file2 != null) {
|
|
RealmsUploadScreen.LOGGER.debug("Deleting file " + file2.getAbsolutePath());
|
|
file2.delete();
|
|
}
|
|
}
|
|
}
|
|
}).start();
|
|
}
|
|
|
|
private void uploadCancelled() {
|
|
this.status = RealmsScreen.getLocalizedString("mco.upload.cancelled");
|
|
RealmsUploadScreen.LOGGER.debug("Upload was cancelled");
|
|
}
|
|
|
|
private boolean verify(final File file) {
|
|
return file.length() < 5368709120L;
|
|
}
|
|
|
|
private File tarGzipArchive(final File file) throws IOException {
|
|
TarArchiveOutputStream tarArchiveOutputStream3 = null;
|
|
try {
|
|
final File file2 = File.createTempFile("realms-upload-file", ".tar.gz");
|
|
tarArchiveOutputStream3 = new TarArchiveOutputStream((OutputStream)new GZIPOutputStream(new FileOutputStream(file2)));
|
|
tarArchiveOutputStream3.setLongFileMode(3);
|
|
this.addFileToTarGz(tarArchiveOutputStream3, file.getAbsolutePath(), "world", true);
|
|
tarArchiveOutputStream3.finish();
|
|
return file2;
|
|
}
|
|
finally {
|
|
if (tarArchiveOutputStream3 != null) {
|
|
tarArchiveOutputStream3.close();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void addFileToTarGz(final TarArchiveOutputStream tarArchiveOutputStream, final String string2, final String string3, final boolean boolean4) throws IOException {
|
|
if (this.cancelled) {
|
|
return;
|
|
}
|
|
final File file6 = new File(string2);
|
|
final String string4 = boolean4 ? string3 : (string3 + file6.getName());
|
|
final TarArchiveEntry tarArchiveEntry8 = new TarArchiveEntry(file6, string4);
|
|
tarArchiveOutputStream.putArchiveEntry((ArchiveEntry)tarArchiveEntry8);
|
|
if (file6.isFile()) {
|
|
IOUtils.copy((InputStream)new FileInputStream(file6), (OutputStream)tarArchiveOutputStream);
|
|
tarArchiveOutputStream.closeArchiveEntry();
|
|
}
|
|
else {
|
|
tarArchiveOutputStream.closeArchiveEntry();
|
|
final File[] arr9 = file6.listFiles();
|
|
if (arr9 != null) {
|
|
for (final File file7 : arr9) {
|
|
this.addFileToTarGz(tarArchiveOutputStream, file7.getAbsolutePath(), string4 + "/", false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static {
|
|
LOGGER = LogManager.getLogger();
|
|
DOTS = new String[] { "", ".", ". .", ". . ." };
|
|
uploadLock = new ReentrantLock();
|
|
}
|
|
|
|
enum Unit {
|
|
B,
|
|
KB,
|
|
MB,
|
|
GB;
|
|
}
|
|
}
|