Initial Commit

This commit is contained in:
richard committed 2026-11-13 22:25:04 +01:00
1 parent 377b32db6e
commit 2d9a5eecba
14134 files changed
+1160982

No files matched your search

@@ -0,0 +1,48 @@
package com.mojang.realmsclient;
import java.util.Arrays;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class KeyCombo {
private final char[] chars;
private int matchIndex;
private final Runnable onCompletion;
public KeyCombo(char[] pChars, Runnable pOnCompletion) {
this.onCompletion = pOnCompletion;
if (pChars.length < 1) {
throw new IllegalArgumentException("Must have at least one char");
} else {
this.chars = pChars;
}
}
public KeyCombo(char[] pChars) {
this(pChars, () -> {
});
}
public boolean keyPressed(char pKey) {
if (pKey == this.chars[this.matchIndex++]) {
if (this.matchIndex == this.chars.length) {
this.reset();
this.onCompletion.run();
return true;
}
} else {
this.reset();
}
return false;
}
public void reset() {
this.matchIndex = 0;
}
public String toString() {
return "KeyCombo{chars=" + Arrays.toString(this.chars) + ", matchIndex=" + this.matchIndex + "}";
}
}
@@ -0,0 +1,48 @@
package com.mojang.realmsclient;
import java.util.Locale;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public enum Unit {
B,
KB,
MB,
GB;
private static final int BASE_UNIT = 1024;
public static Unit getLargest(long pBytes) {
if (pBytes < 1024L) {
return B;
} else {
try {
int i = (int)(Math.log((double)pBytes) / Math.log(1024.0D));
String s = String.valueOf("KMGTPE".charAt(i - 1));
return valueOf(s + "B");
} catch (Exception exception) {
return GB;
}
}
}
public static double convertTo(long pBytes, Unit pUnit) {
return pUnit == B ? (double)pBytes : (double)pBytes / Math.pow(1024.0D, (double)pUnit.ordinal());
}
public static String humanReadable(long pBytes) {
int i = 1024;
if (pBytes < 1024L) {
return pBytes + " B";
} else {
int j = (int)(Math.log((double)pBytes) / Math.log(1024.0D));
String s = "" + "KMGTPE".charAt(j - 1);
return String.format(Locale.ROOT, "%.1f %sB", (double)pBytes / Math.pow(1024.0D, (double)j), s);
}
}
public static String humanReadable(long pBytes, Unit pUnit) {
return String.format(Locale.ROOT, "%." + (pUnit == GB ? "1" : "0") + "f %s", convertTo(pBytes, pUnit), pUnit.name());
}
}
@@ -0,0 +1,413 @@
package com.mojang.realmsclient.client;
import com.google.common.hash.Hashing;
import com.google.common.io.Files;
import com.mojang.logging.LogUtils;
import com.mojang.realmsclient.dto.WorldDownload;
import com.mojang.realmsclient.exception.RealmsDefaultUncaughtExceptionHandler;
import com.mojang.realmsclient.gui.screens.RealmsDownloadLatestWorldScreen;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Path;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Nullable;
import net.minecraft.SharedConstants;
import net.minecraft.client.Minecraft;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtIo;
import net.minecraft.world.level.storage.LevelResource;
import net.minecraft.world.level.storage.LevelStorageSource;
import net.minecraft.world.level.validation.ContentValidationException;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.CountingOutputStream;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class FileDownload {
static final Logger LOGGER = LogUtils.getLogger();
volatile boolean cancelled;
volatile boolean finished;
volatile boolean error;
volatile boolean extracting;
@Nullable
private volatile File tempFile;
volatile File resourcePackPath;
@Nullable
private volatile HttpGet request;
@Nullable
private Thread currentThread;
private final RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(120000).setConnectTimeout(120000).build();
private static final String[] INVALID_FILE_NAMES = new String[]{"CON", "COM", "PRN", "AUX", "CLOCK$", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"};
public long contentLength(String pUri) {
CloseableHttpClient closeablehttpclient = null;
HttpGet httpget = null;
long i;
try {
httpget = new HttpGet(pUri);
closeablehttpclient = HttpClientBuilder.create().setDefaultRequestConfig(this.requestConfig).build();
CloseableHttpResponse closeablehttpresponse = closeablehttpclient.execute(httpget);
return Long.parseLong(closeablehttpresponse.getFirstHeader("Content-Length").getValue());
} catch (Throwable throwable) {
LOGGER.error("Unable to get content length for download");
i = 0L;
} finally {
if (httpget != null) {
httpget.releaseConnection();
}
if (closeablehttpclient != null) {
try {
closeablehttpclient.close();
} catch (IOException ioexception) {
LOGGER.error("Could not close http client", (Throwable)ioexception);
}
}
}
return i;
}
public void download(WorldDownload pDownload, String pWorldName, RealmsDownloadLatestWorldScreen.DownloadStatus pStatus, LevelStorageSource pSource) {
if (this.currentThread == null) {
this.currentThread = new Thread(() -> {
CloseableHttpClient closeablehttpclient = null;
try {
this.tempFile = File.createTempFile("backup", ".tar.gz");
this.request = new HttpGet(pDownload.downloadLink);
closeablehttpclient = HttpClientBuilder.create().setDefaultRequestConfig(this.requestConfig).build();
HttpResponse httpresponse = closeablehttpclient.execute(this.request);
pStatus.totalBytes = Long.parseLong(httpresponse.getFirstHeader("Content-Length").getValue());
if (httpresponse.getStatusLine().getStatusCode() == 200) {
OutputStream outputstream = new FileOutputStream(this.tempFile);
FileDownload.ProgressListener filedownload$progresslistener = new FileDownload.ProgressListener(pWorldName.trim(), this.tempFile, pSource, pStatus);
FileDownload.DownloadCountingOutputStream filedownload$downloadcountingoutputstream = new FileDownload.DownloadCountingOutputStream(outputstream);
filedownload$downloadcountingoutputstream.setListener(filedownload$progresslistener);
IOUtils.copy(httpresponse.getEntity().getContent(), filedownload$downloadcountingoutputstream);
return;
}
this.error = true;
this.request.abort();
} catch (Exception exception1) {
LOGGER.error("Caught exception while downloading: {}", (Object)exception1.getMessage());
this.error = true;
return;
} finally {
this.request.releaseConnection();
if (this.tempFile != null) {
this.tempFile.delete();
}
if (!this.error) {
if (!pDownload.resourcePackUrl.isEmpty() && !pDownload.resourcePackHash.isEmpty()) {
try {
this.tempFile = File.createTempFile("resources", ".tar.gz");
this.request = new HttpGet(pDownload.resourcePackUrl);
HttpResponse httpresponse1 = closeablehttpclient.execute(this.request);
pStatus.totalBytes = Long.parseLong(httpresponse1.getFirstHeader("Content-Length").getValue());
if (httpresponse1.getStatusLine().getStatusCode() != 200) {
this.error = true;
this.request.abort();
return;
}
OutputStream outputstream1 = new FileOutputStream(this.tempFile);
FileDownload.ResourcePackProgressListener filedownload$resourcepackprogresslistener = new FileDownload.ResourcePackProgressListener(this.tempFile, pStatus, pDownload);
FileDownload.DownloadCountingOutputStream filedownload$downloadcountingoutputstream1 = new FileDownload.DownloadCountingOutputStream(outputstream1);
filedownload$downloadcountingoutputstream1.setListener(filedownload$resourcepackprogresslistener);
IOUtils.copy(httpresponse1.getEntity().getContent(), filedownload$downloadcountingoutputstream1);
} catch (Exception exception) {
LOGGER.error("Caught exception while downloading: {}", (Object)exception.getMessage());
this.error = true;
} finally {
this.request.releaseConnection();
if (this.tempFile != null) {
this.tempFile.delete();
}
}
} else {
this.finished = true;
}
}
if (closeablehttpclient != null) {
try {
closeablehttpclient.close();
} catch (IOException ioexception) {
LOGGER.error("Failed to close Realms download client");
}
}
}
});
this.currentThread.setUncaughtExceptionHandler(new RealmsDefaultUncaughtExceptionHandler(LOGGER));
this.currentThread.start();
}
}
public void cancel() {
if (this.request != null) {
this.request.abort();
}
if (this.tempFile != null) {
this.tempFile.delete();
}
this.cancelled = true;
}
public boolean isFinished() {
return this.finished;
}
public boolean isError() {
return this.error;
}
public boolean isExtracting() {
return this.extracting;
}
/**
* Modifies a folder name to make sure it is valid to store on disk.
* @return the modified folder name
* @param pFolderName The folder name to modify
*/
public static String findAvailableFolderName(String pFolderName) {
pFolderName = pFolderName.replaceAll("[\\./\"]", "_");
for(String s : INVALID_FILE_NAMES) {
if (pFolderName.equalsIgnoreCase(s)) {
pFolderName = "_" + pFolderName + "_";
}
}
return pFolderName;
}
void untarGzipArchive(String p_86992_, @Nullable File p_86993_, LevelStorageSource p_86994_) throws IOException {
Pattern pattern = Pattern.compile(".*-([0-9]+)$");
int i = 1;
for(char c0 : SharedConstants.ILLEGAL_FILE_CHARACTERS) {
p_86992_ = p_86992_.replace(c0, '_');
}
if (StringUtils.isEmpty(p_86992_)) {
p_86992_ = "Realm";
}
p_86992_ = findAvailableFolderName(p_86992_);
try {
for(LevelStorageSource.LevelDirectory levelstoragesource$leveldirectory : p_86994_.findLevelCandidates()) {
String s1 = levelstoragesource$leveldirectory.directoryName();
if (s1.toLowerCase(Locale.ROOT).startsWith(p_86992_.toLowerCase(Locale.ROOT))) {
Matcher matcher = pattern.matcher(s1);
if (matcher.matches()) {
int j = Integer.parseInt(matcher.group(1));
if (j > i) {
i = j;
}
} else {
++i;
}
}
}
} catch (Exception exception1) {
LOGGER.error("Error getting level list", (Throwable)exception1);
this.error = true;
return;
}
String s;
if (p_86994_.isNewLevelIdAcceptable(p_86992_) && i <= 1) {
s = p_86992_;
} else {
s = p_86992_ + (i == 1 ? "" : "-" + i);
if (!p_86994_.isNewLevelIdAcceptable(s)) {
boolean flag = false;
while(!flag) {
++i;
s = p_86992_ + (i == 1 ? "" : "-" + i);
if (p_86994_.isNewLevelIdAcceptable(s)) {
flag = true;
}
}
}
}
TarArchiveInputStream tararchiveinputstream = null;
File file1 = new File(Minecraft.getInstance().gameDirectory.getAbsolutePath(), "saves");
try {
file1.mkdir();
tararchiveinputstream = new TarArchiveInputStream(new GzipCompressorInputStream(new BufferedInputStream(new FileInputStream(p_86993_))));
for(TarArchiveEntry tararchiveentry = tararchiveinputstream.getNextTarEntry(); tararchiveentry != null; tararchiveentry = tararchiveinputstream.getNextTarEntry()) {
File file2 = new File(file1, tararchiveentry.getName().replace("world", s));
if (tararchiveentry.isDirectory()) {
file2.mkdirs();
} else {
file2.createNewFile();
try (FileOutputStream fileoutputstream = new FileOutputStream(file2)) {
IOUtils.copy(tararchiveinputstream, fileoutputstream);
}
}
}
} catch (Exception exception) {
LOGGER.error("Error extracting world", (Throwable)exception);
this.error = true;
} finally {
if (tararchiveinputstream != null) {
tararchiveinputstream.close();
}
if (p_86993_ != null) {
p_86993_.delete();
}
try (LevelStorageSource.LevelStorageAccess levelstoragesource$levelstorageaccess = p_86994_.validateAndCreateAccess(s)) {
levelstoragesource$levelstorageaccess.renameLevel(s.trim());
Path path = levelstoragesource$levelstorageaccess.getLevelPath(LevelResource.LEVEL_DATA_FILE);
deletePlayerTag(path.toFile());
} catch (IOException ioexception) {
LOGGER.error("Failed to rename unpacked realms level {}", s, ioexception);
} catch (ContentValidationException contentvalidationexception) {
LOGGER.warn("{}", (Object)contentvalidationexception.getMessage());
}
this.resourcePackPath = new File(file1, s + File.separator + "resources.zip");
}
}
private static void deletePlayerTag(File p_86988_) {
if (p_86988_.exists()) {
try {
CompoundTag compoundtag = NbtIo.readCompressed(p_86988_);
CompoundTag compoundtag1 = compoundtag.getCompound("Data");
compoundtag1.remove("Player");
NbtIo.writeCompressed(compoundtag, p_86988_);
} catch (Exception exception) {
exception.printStackTrace();
}
}
}
@OnlyIn(Dist.CLIENT)
static class DownloadCountingOutputStream extends CountingOutputStream {
@Nullable
private ActionListener listener;
public DownloadCountingOutputStream(OutputStream pOut) {
super(pOut);
}
public void setListener(ActionListener pListener) {
this.listener = pListener;
}
protected void afterWrite(int pBytesWritten) throws IOException {
super.afterWrite(pBytesWritten);
if (this.listener != null) {
this.listener.actionPerformed(new ActionEvent(this, 0, (String)null));
}
}
}
@OnlyIn(Dist.CLIENT)
class ProgressListener implements ActionListener {
private final String worldName;
private final File tempFile;
private final LevelStorageSource levelStorageSource;
private final RealmsDownloadLatestWorldScreen.DownloadStatus downloadStatus;
ProgressListener(String pWorldName, File pTempFile, LevelStorageSource pLevelStorageSource, RealmsDownloadLatestWorldScreen.DownloadStatus pDownloadStatus) {
this.worldName = pWorldName;
this.tempFile = pTempFile;
this.levelStorageSource = pLevelStorageSource;
this.downloadStatus = pDownloadStatus;
}
public void actionPerformed(ActionEvent pAction) {
this.downloadStatus.bytesWritten = ((FileDownload.DownloadCountingOutputStream)pAction.getSource()).getByteCount();
if (this.downloadStatus.bytesWritten >= this.downloadStatus.totalBytes && !FileDownload.this.cancelled && !FileDownload.this.error) {
try {
FileDownload.this.extracting = true;
FileDownload.this.untarGzipArchive(this.worldName, this.tempFile, this.levelStorageSource);
} catch (IOException ioexception) {
FileDownload.LOGGER.error("Error extracting archive", (Throwable)ioexception);
FileDownload.this.error = true;
}
}
}
}
@OnlyIn(Dist.CLIENT)
class ResourcePackProgressListener implements ActionListener {
private final File tempFile;
private final RealmsDownloadLatestWorldScreen.DownloadStatus downloadStatus;
private final WorldDownload worldDownload;
ResourcePackProgressListener(File pTempFile, RealmsDownloadLatestWorldScreen.DownloadStatus pDownloadStatus, WorldDownload pWorldDownload) {
this.tempFile = pTempFile;
this.downloadStatus = pDownloadStatus;
this.worldDownload = pWorldDownload;
}
public void actionPerformed(ActionEvent pAction) {
this.downloadStatus.bytesWritten = ((FileDownload.DownloadCountingOutputStream)pAction.getSource()).getByteCount();
if (this.downloadStatus.bytesWritten >= this.downloadStatus.totalBytes && !FileDownload.this.cancelled) {
try {
String s = Hashing.sha1().hashBytes(Files.toByteArray(this.tempFile)).toString();
if (s.equals(this.worldDownload.resourcePackHash)) {
FileUtils.copyFile(this.tempFile, FileDownload.this.resourcePackPath);
FileDownload.this.finished = true;
} else {
FileDownload.LOGGER.error("Resourcepack had wrong hash (expected {}, found {}). Deleting it.", this.worldDownload.resourcePackHash, s);
FileUtils.deleteQuietly(this.tempFile);
FileDownload.this.error = true;
}
} catch (IOException ioexception) {
FileDownload.LOGGER.error("Error copying resourcepack file: {}", (Object)ioexception.getMessage());
FileDownload.this.error = true;
}
}
}
}
}
@@ -0,0 +1,224 @@
package com.mojang.realmsclient.client;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.mojang.logging.LogUtils;
import com.mojang.realmsclient.dto.UploadInfo;
import com.mojang.realmsclient.gui.screens.UploadResult;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.time.Duration;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import javax.annotation.Nullable;
import net.minecraft.client.User;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.Args;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class FileUpload {
private static final Logger LOGGER = LogUtils.getLogger();
private static final int MAX_RETRIES = 5;
private static final String UPLOAD_PATH = "/upload";
private final File file;
private final long worldId;
private final int slotId;
private final UploadInfo uploadInfo;
private final String sessionId;
private final String username;
private final String clientVersion;
private final UploadStatus uploadStatus;
private final AtomicBoolean cancelled = new AtomicBoolean(false);
@Nullable
private CompletableFuture<UploadResult> uploadTask;
private final RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout((int)TimeUnit.MINUTES.toMillis(10L)).setConnectTimeout((int)TimeUnit.SECONDS.toMillis(15L)).build();
public FileUpload(File pFile, long pWorldId, int pSlotId, UploadInfo pUploadInfo, User pUser, String pClientVersion, UploadStatus pUploadStatus) {
this.file = pFile;
this.worldId = pWorldId;
this.slotId = pSlotId;
this.uploadInfo = pUploadInfo;
this.sessionId = pUser.getSessionId();
this.username = pUser.getName();
this.clientVersion = pClientVersion;
this.uploadStatus = pUploadStatus;
}
public void upload(Consumer<UploadResult> p_87085_) {
if (this.uploadTask == null) {
this.uploadTask = CompletableFuture.supplyAsync(() -> {
return this.requestUpload(0);
});
this.uploadTask.thenAccept(p_87085_);
}
}
public void cancel() {
this.cancelled.set(true);
if (this.uploadTask != null) {
this.uploadTask.cancel(false);
this.uploadTask = null;
}
}
/**
*
* @param pRetries The number of times this upload has already been attempted
*/
private UploadResult requestUpload(int pRetries) {
UploadResult.Builder uploadresult$builder = new UploadResult.Builder();
if (this.cancelled.get()) {
return uploadresult$builder.build();
} else {
this.uploadStatus.totalBytes = this.file.length();
HttpPost httppost = new HttpPost(this.uploadInfo.getUploadEndpoint().resolve("/upload/" + this.worldId + "/" + this.slotId));
CloseableHttpClient closeablehttpclient = HttpClientBuilder.create().setDefaultRequestConfig(this.requestConfig).build();
UploadResult uploadresult;
try {
this.setupRequest(httppost);
HttpResponse httpresponse = closeablehttpclient.execute(httppost);
long i = this.getRetryDelaySeconds(httpresponse);
if (!this.shouldRetry(i, pRetries)) {
this.handleResponse(httpresponse, uploadresult$builder);
return uploadresult$builder.build();
}
uploadresult = this.retryUploadAfter(i, pRetries);
} catch (Exception exception) {
if (!this.cancelled.get()) {
LOGGER.error("Caught exception while uploading: ", (Throwable)exception);
}
return uploadresult$builder.build();
} finally {
this.cleanup(httppost, closeablehttpclient);
}
return uploadresult;
}
}
private void cleanup(HttpPost p_87094_, @Nullable CloseableHttpClient p_87095_) {
p_87094_.releaseConnection();
if (p_87095_ != null) {
try {
p_87095_.close();
} catch (IOException ioexception) {
LOGGER.error("Failed to close Realms upload client");
}
}
}
private void setupRequest(HttpPost p_87092_) throws FileNotFoundException {
p_87092_.setHeader("Cookie", "sid=" + this.sessionId + ";token=" + this.uploadInfo.getToken() + ";user=" + this.username + ";version=" + this.clientVersion);
FileUpload.CustomInputStreamEntity fileupload$custominputstreamentity = new FileUpload.CustomInputStreamEntity(new FileInputStream(this.file), this.file.length(), this.uploadStatus);
fileupload$custominputstreamentity.setContentType("application/octet-stream");
p_87092_.setEntity(fileupload$custominputstreamentity);
}
private void handleResponse(HttpResponse pResponse, UploadResult.Builder pUploadResult) throws IOException {
int i = pResponse.getStatusLine().getStatusCode();
if (i == 401) {
LOGGER.debug("Realms server returned 401: {}", (Object)pResponse.getFirstHeader("WWW-Authenticate"));
}
pUploadResult.withStatusCode(i);
if (pResponse.getEntity() != null) {
String s = EntityUtils.toString(pResponse.getEntity(), "UTF-8");
if (s != null) {
try {
JsonParser jsonparser = new JsonParser();
JsonElement jsonelement = jsonparser.parse(s).getAsJsonObject().get("errorMsg");
Optional<String> optional = Optional.ofNullable(jsonelement).map(JsonElement::getAsString);
pUploadResult.withErrorMessage(optional.orElse((String)null));
} catch (Exception exception) {
}
}
}
}
private boolean shouldRetry(long p_87082_, int pRetries) {
return p_87082_ > 0L && pRetries + 1 < 5;
}
private UploadResult retryUploadAfter(long pSeconds, int pRetries) throws InterruptedException {
Thread.sleep(Duration.ofSeconds(pSeconds).toMillis());
return this.requestUpload(pRetries + 1);
}
private long getRetryDelaySeconds(HttpResponse pHttpResponse) {
return Optional.ofNullable(pHttpResponse.getFirstHeader("Retry-After")).map(NameValuePair::getValue).map(Long::valueOf).orElse(0L);
}
public boolean isFinished() {
return this.uploadTask.isDone() || this.uploadTask.isCancelled();
}
@OnlyIn(Dist.CLIENT)
static class CustomInputStreamEntity extends InputStreamEntity {
private final long length;
private final InputStream content;
private final UploadStatus uploadStatus;
public CustomInputStreamEntity(InputStream pContent, long pLength, UploadStatus pUploadStatus) {
super(pContent);
this.content = pContent;
this.length = pLength;
this.uploadStatus = pUploadStatus;
}
public void writeTo(OutputStream p_87109_) throws IOException {
Args.notNull(p_87109_, "Output stream");
InputStream inputstream = this.content;
try {
byte[] abyte = new byte[4096];
int j;
if (this.length < 0L) {
while((j = inputstream.read(abyte)) != -1) {
p_87109_.write(abyte, 0, j);
this.uploadStatus.bytesWritten += (long)j;
}
} else {
long i = this.length;
while(i > 0L) {
j = inputstream.read(abyte, 0, (int)Math.min(4096L, i));
if (j == -1) {
break;
}
p_87109_.write(abyte, 0, j);
this.uploadStatus.bytesWritten += (long)j;
i -= (long)j;
p_87109_.flush();
}
}
} finally {
inputstream.close();
}
}
}
}
@@ -0,0 +1,81 @@
package com.mojang.realmsclient.client;
import com.google.common.collect.Lists;
import com.mojang.realmsclient.dto.RegionPingResult;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.util.Comparator;
import java.util.List;
import net.minecraft.Util;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.apache.commons.io.IOUtils;
@OnlyIn(Dist.CLIENT)
public class Ping {
public static List<RegionPingResult> ping(Ping.Region... pRegions) {
for(Ping.Region ping$region : pRegions) {
ping(ping$region.endpoint);
}
List<RegionPingResult> list = Lists.newArrayList();
for(Ping.Region ping$region1 : pRegions) {
list.add(new RegionPingResult(ping$region1.name, ping(ping$region1.endpoint)));
}
list.sort(Comparator.comparingInt(RegionPingResult::ping));
return list;
}
private static int ping(String pHostname) {
int i = 700;
long j = 0L;
Socket socket = null;
for(int k = 0; k < 5; ++k) {
try {
SocketAddress socketaddress = new InetSocketAddress(pHostname, 80);
socket = new Socket();
long l = now();
socket.connect(socketaddress, 700);
j += now() - l;
} catch (Exception exception) {
j += 700L;
} finally {
IOUtils.closeQuietly(socket);
}
}
return (int)((double)j / 5.0D);
}
private static long now() {
return Util.getMillis();
}
public static List<RegionPingResult> pingAllRegions() {
return ping(Ping.Region.values());
}
@OnlyIn(Dist.CLIENT)
static enum Region {
US_EAST_1("us-east-1", "ec2.us-east-1.amazonaws.com"),
US_WEST_2("us-west-2", "ec2.us-west-2.amazonaws.com"),
US_WEST_1("us-west-1", "ec2.us-west-1.amazonaws.com"),
EU_WEST_1("eu-west-1", "ec2.eu-west-1.amazonaws.com"),
AP_SOUTHEAST_1("ap-southeast-1", "ec2.ap-southeast-1.amazonaws.com"),
AP_SOUTHEAST_2("ap-southeast-2", "ec2.ap-southeast-2.amazonaws.com"),
AP_NORTHEAST_1("ap-northeast-1", "ec2.ap-northeast-1.amazonaws.com"),
SA_EAST_1("sa-east-1", "ec2.sa-east-1.amazonaws.com");
final String name;
final String endpoint;
private Region(String pName, String pEndpoint) {
this.name = pName;
this.endpoint = pEndpoint;
}
}
}
@@ -0,0 +1,497 @@
package com.mojang.realmsclient.client;
import com.google.gson.JsonArray;
import com.mojang.logging.LogUtils;
import com.mojang.realmsclient.dto.BackupList;
import com.mojang.realmsclient.dto.GuardedSerializer;
import com.mojang.realmsclient.dto.Ops;
import com.mojang.realmsclient.dto.PendingInvite;
import com.mojang.realmsclient.dto.PendingInvitesList;
import com.mojang.realmsclient.dto.PingResult;
import com.mojang.realmsclient.dto.PlayerInfo;
import com.mojang.realmsclient.dto.RealmsDescriptionDto;
import com.mojang.realmsclient.dto.RealmsNews;
import com.mojang.realmsclient.dto.RealmsNotification;
import com.mojang.realmsclient.dto.RealmsServer;
import com.mojang.realmsclient.dto.RealmsServerAddress;
import com.mojang.realmsclient.dto.RealmsServerList;
import com.mojang.realmsclient.dto.RealmsServerPlayerLists;
import com.mojang.realmsclient.dto.RealmsWorldOptions;
import com.mojang.realmsclient.dto.RealmsWorldResetDto;
import com.mojang.realmsclient.dto.ServerActivityList;
import com.mojang.realmsclient.dto.Subscription;
import com.mojang.realmsclient.dto.UploadInfo;
import com.mojang.realmsclient.dto.WorldDownload;
import com.mojang.realmsclient.dto.WorldTemplatePaginatedList;
import com.mojang.realmsclient.exception.RealmsHttpException;
import com.mojang.realmsclient.exception.RealmsServiceException;
import com.mojang.realmsclient.exception.RetryCallException;
import com.mojang.realmsclient.util.WorldGenerationInfo;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.UUID;
import javax.annotation.Nullable;
import net.minecraft.SharedConstants;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.language.I18n;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class RealmsClient {
public static RealmsClient.Environment currentEnvironment = RealmsClient.Environment.PRODUCTION;
private static boolean initialized;
private static final Logger LOGGER = LogUtils.getLogger();
private final String sessionId;
private final String username;
private final Minecraft minecraft;
private static final String WORLDS_RESOURCE_PATH = "worlds";
private static final String INVITES_RESOURCE_PATH = "invites";
private static final String MCO_RESOURCE_PATH = "mco";
private static final String SUBSCRIPTION_RESOURCE = "subscriptions";
private static final String ACTIVITIES_RESOURCE = "activities";
private static final String OPS_RESOURCE = "ops";
private static final String REGIONS_RESOURCE = "regions/ping/stat";
private static final String TRIALS_RESOURCE = "trial";
private static final String NOTIFICATIONS_RESOURCE = "notifications";
private static final String PATH_INITIALIZE = "/$WORLD_ID/initialize";
private static final String PATH_GET_ACTIVTIES = "/$WORLD_ID";
private static final String PATH_GET_LIVESTATS = "/liveplayerlist";
private static final String PATH_GET_SUBSCRIPTION = "/$WORLD_ID";
private static final String PATH_OP = "/$WORLD_ID/$PROFILE_UUID";
private static final String PATH_PUT_INTO_MINIGAMES_MODE = "/minigames/$MINIGAME_ID/$WORLD_ID";
private static final String PATH_AVAILABLE = "/available";
private static final String PATH_TEMPLATES = "/templates/$WORLD_TYPE";
private static final String PATH_WORLD_JOIN = "/v1/$ID/join/pc";
private static final String PATH_WORLD_GET = "/$ID";
private static final String PATH_WORLD_INVITES = "/$WORLD_ID";
private static final String PATH_WORLD_UNINVITE = "/$WORLD_ID/invite/$UUID";
private static final String PATH_PENDING_INVITES_COUNT = "/count/pending";
private static final String PATH_PENDING_INVITES = "/pending";
private static final String PATH_ACCEPT_INVITE = "/accept/$INVITATION_ID";
private static final String PATH_REJECT_INVITE = "/reject/$INVITATION_ID";
private static final String PATH_UNINVITE_MYSELF = "/$WORLD_ID";
private static final String PATH_WORLD_UPDATE = "/$WORLD_ID";
private static final String PATH_SLOT = "/$WORLD_ID/slot/$SLOT_ID";
private static final String PATH_WORLD_OPEN = "/$WORLD_ID/open";
private static final String PATH_WORLD_CLOSE = "/$WORLD_ID/close";
private static final String PATH_WORLD_RESET = "/$WORLD_ID/reset";
private static final String PATH_DELETE_WORLD = "/$WORLD_ID";
private static final String PATH_WORLD_BACKUPS = "/$WORLD_ID/backups";
private static final String PATH_WORLD_DOWNLOAD = "/$WORLD_ID/slot/$SLOT_ID/download";
private static final String PATH_WORLD_UPLOAD = "/$WORLD_ID/backups/upload";
private static final String PATH_CLIENT_COMPATIBLE = "/client/compatible";
private static final String PATH_TOS_AGREED = "/tos/agreed";
private static final String PATH_NEWS = "/v1/news";
private static final String PATH_MARK_NOTIFICATIONS_SEEN = "/seen";
private static final String PATH_DISMISS_NOTIFICATIONS = "/dismiss";
private static final String PATH_STAGE_AVAILABLE = "/stageAvailable";
private static final GuardedSerializer GSON = new GuardedSerializer();
public static RealmsClient create() {
Minecraft minecraft = Minecraft.getInstance();
return create(minecraft);
}
public static RealmsClient create(Minecraft pMinecraft) {
String s = pMinecraft.getUser().getName();
String s1 = pMinecraft.getUser().getSessionId();
if (!initialized) {
initialized = true;
Optional<String> optional = Optional.ofNullable(System.getenv("realms.environment")).or(() -> {
return Optional.ofNullable(System.getProperty("realms.environment"));
});
optional.flatMap(RealmsClient.Environment::byName).ifPresent((p_289648_) -> {
currentEnvironment = p_289648_;
});
}
return new RealmsClient(s1, s, pMinecraft);
}
public static void switchToStage() {
currentEnvironment = RealmsClient.Environment.STAGE;
}
public static void switchToProd() {
currentEnvironment = RealmsClient.Environment.PRODUCTION;
}
public static void switchToLocal() {
currentEnvironment = RealmsClient.Environment.LOCAL;
}
public RealmsClient(String pSessionId, String pUsername, Minecraft pMinecraft) {
this.sessionId = pSessionId;
this.username = pUsername;
this.minecraft = pMinecraft;
RealmsClientConfig.setProxy(pMinecraft.getProxy());
}
public RealmsServerList listWorlds() throws RealmsServiceException {
String s = this.url("worlds");
String s1 = this.execute(Request.get(s));
return RealmsServerList.parse(s1);
}
public List<RealmsNotification> getNotifications() throws RealmsServiceException {
String s = this.url("notifications");
String s1 = this.execute(Request.get(s));
List<RealmsNotification> list = RealmsNotification.parseList(s1);
return list.size() > 1 ? List.of(list.get(0)) : list;
}
private static JsonArray uuidListToJsonArray(List<UUID> pUuidList) {
JsonArray jsonarray = new JsonArray();
for(UUID uuid : pUuidList) {
if (uuid != null) {
jsonarray.add(uuid.toString());
}
}
return jsonarray;
}
public void notificationsSeen(List<UUID> pUuidList) throws RealmsServiceException {
String s = this.url("notifications/seen");
this.execute(Request.post(s, GSON.toJson(uuidListToJsonArray(pUuidList))));
}
public void notificationsDismiss(List<UUID> pUuidList) throws RealmsServiceException {
String s = this.url("notifications/dismiss");
this.execute(Request.post(s, GSON.toJson(uuidListToJsonArray(pUuidList))));
}
public RealmsServer getOwnWorld(long pServerId) throws RealmsServiceException {
String s = this.url("worlds" + "/$ID".replace("$ID", String.valueOf(pServerId)));
String s1 = this.execute(Request.get(s));
return RealmsServer.parse(s1);
}
public ServerActivityList getActivity(long pWorldId) throws RealmsServiceException {
String s = this.url("activities" + "/$WORLD_ID".replace("$WORLD_ID", String.valueOf(pWorldId)));
String s1 = this.execute(Request.get(s));
return ServerActivityList.parse(s1);
}
public RealmsServerPlayerLists getLiveStats() throws RealmsServiceException {
String s = this.url("activities/liveplayerlist");
String s1 = this.execute(Request.get(s));
return RealmsServerPlayerLists.parse(s1);
}
public RealmsServerAddress join(long pServerId) throws RealmsServiceException {
String s = this.url("worlds" + "/v1/$ID/join/pc".replace("$ID", "" + pServerId));
String s1 = this.execute(Request.get(s, 5000, 30000));
return RealmsServerAddress.parse(s1);
}
public void initializeWorld(long pWorldId, String pName, String pDescription) throws RealmsServiceException {
RealmsDescriptionDto realmsdescriptiondto = new RealmsDescriptionDto(pName, pDescription);
String s = this.url("worlds" + "/$WORLD_ID/initialize".replace("$WORLD_ID", String.valueOf(pWorldId)));
String s1 = GSON.toJson(realmsdescriptiondto);
this.execute(Request.post(s, s1, 5000, 10000));
}
public Boolean mcoEnabled() throws RealmsServiceException {
String s = this.url("mco/available");
String s1 = this.execute(Request.get(s));
return Boolean.valueOf(s1);
}
public Boolean stageAvailable() throws RealmsServiceException {
String s = this.url("mco/stageAvailable");
String s1 = this.execute(Request.get(s));
return Boolean.valueOf(s1);
}
public RealmsClient.CompatibleVersionResponse clientCompatible() throws RealmsServiceException {
String s = this.url("mco/client/compatible");
String s1 = this.execute(Request.get(s));
try {
return RealmsClient.CompatibleVersionResponse.valueOf(s1);
} catch (IllegalArgumentException illegalargumentexception) {
throw new RealmsServiceException(500, "Could not check compatible version, got response: " + s1);
}
}
public void uninvite(long pWorldId, String pUuid) throws RealmsServiceException {
String s = this.url("invites" + "/$WORLD_ID/invite/$UUID".replace("$WORLD_ID", String.valueOf(pWorldId)).replace("$UUID", pUuid));
this.execute(Request.delete(s));
}
public void uninviteMyselfFrom(long pWorldId) throws RealmsServiceException {
String s = this.url("invites" + "/$WORLD_ID".replace("$WORLD_ID", String.valueOf(pWorldId)));
this.execute(Request.delete(s));
}
public RealmsServer invite(long pWorldId, String pPlayerName) throws RealmsServiceException {
PlayerInfo playerinfo = new PlayerInfo();
playerinfo.setName(pPlayerName);
String s = this.url("invites" + "/$WORLD_ID".replace("$WORLD_ID", String.valueOf(pWorldId)));
String s1 = this.execute(Request.post(s, GSON.toJson(playerinfo)));
return RealmsServer.parse(s1);
}
public BackupList backupsFor(long pWorldId) throws RealmsServiceException {
String s = this.url("worlds" + "/$WORLD_ID/backups".replace("$WORLD_ID", String.valueOf(pWorldId)));
String s1 = this.execute(Request.get(s));
return BackupList.parse(s1);
}
public void update(long pWorldId, String pName, String pDescription) throws RealmsServiceException {
RealmsDescriptionDto realmsdescriptiondto = new RealmsDescriptionDto(pName, pDescription);
String s = this.url("worlds" + "/$WORLD_ID".replace("$WORLD_ID", String.valueOf(pWorldId)));
this.execute(Request.post(s, GSON.toJson(realmsdescriptiondto)));
}
public void updateSlot(long pWorldId, int pSlotId, RealmsWorldOptions pWorldOptions) throws RealmsServiceException {
String s = this.url("worlds" + "/$WORLD_ID/slot/$SLOT_ID".replace("$WORLD_ID", String.valueOf(pWorldId)).replace("$SLOT_ID", String.valueOf(pSlotId)));
String s1 = pWorldOptions.toJson();
this.execute(Request.post(s, s1));
}
public boolean switchSlot(long pWorldId, int pSlotId) throws RealmsServiceException {
String s = this.url("worlds" + "/$WORLD_ID/slot/$SLOT_ID".replace("$WORLD_ID", String.valueOf(pWorldId)).replace("$SLOT_ID", String.valueOf(pSlotId)));
String s1 = this.execute(Request.put(s, ""));
return Boolean.valueOf(s1);
}
public void restoreWorld(long pWorldId, String pBackupId) throws RealmsServiceException {
String s = this.url("worlds" + "/$WORLD_ID/backups".replace("$WORLD_ID", String.valueOf(pWorldId)), "backupId=" + pBackupId);
this.execute(Request.put(s, "", 40000, 600000));
}
public WorldTemplatePaginatedList fetchWorldTemplates(int pPage, int pPageSize, RealmsServer.WorldType pWorldType) throws RealmsServiceException {
String s = this.url("worlds" + "/templates/$WORLD_TYPE".replace("$WORLD_TYPE", pWorldType.toString()), String.format(Locale.ROOT, "page=%d&pageSize=%d", pPage, pPageSize));
String s1 = this.execute(Request.get(s));
return WorldTemplatePaginatedList.parse(s1);
}
public Boolean putIntoMinigameMode(long pWorldId, String pMinigameId) throws RealmsServiceException {
String s = "/minigames/$MINIGAME_ID/$WORLD_ID".replace("$MINIGAME_ID", pMinigameId).replace("$WORLD_ID", String.valueOf(pWorldId));
String s1 = this.url("worlds" + s);
return Boolean.valueOf(this.execute(Request.put(s1, "")));
}
public Ops op(long pWorldId, String pProfileUuid) throws RealmsServiceException {
String s = "/$WORLD_ID/$PROFILE_UUID".replace("$WORLD_ID", String.valueOf(pWorldId)).replace("$PROFILE_UUID", pProfileUuid);
String s1 = this.url("ops" + s);
return Ops.parse(this.execute(Request.post(s1, "")));
}
public Ops deop(long pWorldId, String pProfileUuid) throws RealmsServiceException {
String s = "/$WORLD_ID/$PROFILE_UUID".replace("$WORLD_ID", String.valueOf(pWorldId)).replace("$PROFILE_UUID", pProfileUuid);
String s1 = this.url("ops" + s);
return Ops.parse(this.execute(Request.delete(s1)));
}
public Boolean open(long pWorldId) throws RealmsServiceException {
String s = this.url("worlds" + "/$WORLD_ID/open".replace("$WORLD_ID", String.valueOf(pWorldId)));
String s1 = this.execute(Request.put(s, ""));
return Boolean.valueOf(s1);
}
public Boolean close(long pWorldId) throws RealmsServiceException {
String s = this.url("worlds" + "/$WORLD_ID/close".replace("$WORLD_ID", String.valueOf(pWorldId)));
String s1 = this.execute(Request.put(s, ""));
return Boolean.valueOf(s1);
}
public Boolean resetWorldWithSeed(long pWorldId, WorldGenerationInfo pGenerationInfo) throws RealmsServiceException {
RealmsWorldResetDto realmsworldresetdto = new RealmsWorldResetDto(pGenerationInfo.getSeed(), -1L, pGenerationInfo.getLevelType().getDtoIndex(), pGenerationInfo.shouldGenerateStructures());
String s = this.url("worlds" + "/$WORLD_ID/reset".replace("$WORLD_ID", String.valueOf(pWorldId)));
String s1 = this.execute(Request.post(s, GSON.toJson(realmsworldresetdto), 30000, 80000));
return Boolean.valueOf(s1);
}
public Boolean resetWorldWithTemplate(long pWorldId, String pWorldTemplateId) throws RealmsServiceException {
RealmsWorldResetDto realmsworldresetdto = new RealmsWorldResetDto((String)null, Long.valueOf(pWorldTemplateId), -1, false);
String s = this.url("worlds" + "/$WORLD_ID/reset".replace("$WORLD_ID", String.valueOf(pWorldId)));
String s1 = this.execute(Request.post(s, GSON.toJson(realmsworldresetdto), 30000, 80000));
return Boolean.valueOf(s1);
}
public Subscription subscriptionFor(long pWorldId) throws RealmsServiceException {
String s = this.url("subscriptions" + "/$WORLD_ID".replace("$WORLD_ID", String.valueOf(pWorldId)));
String s1 = this.execute(Request.get(s));
return Subscription.parse(s1);
}
public int pendingInvitesCount() throws RealmsServiceException {
return this.pendingInvites().pendingInvites.size();
}
public PendingInvitesList pendingInvites() throws RealmsServiceException {
String s = this.url("invites/pending");
String s1 = this.execute(Request.get(s));
PendingInvitesList pendinginviteslist = PendingInvitesList.parse(s1);
pendinginviteslist.pendingInvites.removeIf(this::isBlocked);
return pendinginviteslist;
}
private boolean isBlocked(PendingInvite p_87198_) {
try {
UUID uuid = UUID.fromString(p_87198_.worldOwnerUuid);
return this.minecraft.getPlayerSocialManager().isBlocked(uuid);
} catch (IllegalArgumentException illegalargumentexception) {
return false;
}
}
public void acceptInvitation(String pInviteId) throws RealmsServiceException {
String s = this.url("invites" + "/accept/$INVITATION_ID".replace("$INVITATION_ID", pInviteId));
this.execute(Request.put(s, ""));
}
public WorldDownload requestDownloadInfo(long pWorldId, int pSlotId) throws RealmsServiceException {
String s = this.url("worlds" + "/$WORLD_ID/slot/$SLOT_ID/download".replace("$WORLD_ID", String.valueOf(pWorldId)).replace("$SLOT_ID", String.valueOf(pSlotId)));
String s1 = this.execute(Request.get(s));
return WorldDownload.parse(s1);
}
@Nullable
public UploadInfo requestUploadInfo(long pWorldId, @Nullable String pToken) throws RealmsServiceException {
String s = this.url("worlds" + "/$WORLD_ID/backups/upload".replace("$WORLD_ID", String.valueOf(pWorldId)));
return UploadInfo.parse(this.execute(Request.put(s, UploadInfo.createRequest(pToken))));
}
public void rejectInvitation(String pInviteId) throws RealmsServiceException {
String s = this.url("invites" + "/reject/$INVITATION_ID".replace("$INVITATION_ID", pInviteId));
this.execute(Request.put(s, ""));
}
public void agreeToTos() throws RealmsServiceException {
String s = this.url("mco/tos/agreed");
this.execute(Request.post(s, ""));
}
public RealmsNews getNews() throws RealmsServiceException {
String s = this.url("mco/v1/news");
String s1 = this.execute(Request.get(s, 5000, 10000));
return RealmsNews.parse(s1);
}
public void sendPingResults(PingResult pPingResult) throws RealmsServiceException {
String s = this.url("regions/ping/stat");
this.execute(Request.post(s, GSON.toJson(pPingResult)));
}
public Boolean trialAvailable() throws RealmsServiceException {
String s = this.url("trial");
String s1 = this.execute(Request.get(s));
return Boolean.valueOf(s1);
}
public void deleteWorld(long pWorldId) throws RealmsServiceException {
String s = this.url("worlds" + "/$WORLD_ID".replace("$WORLD_ID", String.valueOf(pWorldId)));
this.execute(Request.delete(s));
}
private String url(String pPath) {
return this.url(pPath, (String)null);
}
private String url(String pPath, @Nullable String pQuery) {
try {
return (new URI(currentEnvironment.protocol, currentEnvironment.baseUrl, "/" + pPath, pQuery, (String)null)).toASCIIString();
} catch (URISyntaxException urisyntaxexception) {
throw new IllegalArgumentException(pPath, urisyntaxexception);
}
}
private String execute(Request<?> pRequest) throws RealmsServiceException {
pRequest.cookie("sid", this.sessionId);
pRequest.cookie("user", this.username);
pRequest.cookie("version", SharedConstants.getCurrentVersion().getName());
try {
int i = pRequest.responseCode();
if (i != 503 && i != 277) {
String s1 = pRequest.text();
if (i >= 200 && i < 300) {
return s1;
} else if (i == 401) {
String s2 = pRequest.getHeader("WWW-Authenticate");
LOGGER.info("Could not authorize you against Realms server: {}", (Object)s2);
throw new RealmsServiceException(i, s2);
} else {
RealmsError realmserror = RealmsError.parse(s1);
if (realmserror != null) {
LOGGER.error("Realms http code: {} - error code: {} - message: {} - raw body: {}", i, realmserror.getErrorCode(), realmserror.getErrorMessage(), s1);
throw new RealmsServiceException(i, s1, realmserror);
} else {
LOGGER.error("Realms http code: {} - raw body (message failed to parse): {}", i, s1);
String s = getHttpCodeDescription(i);
throw new RealmsServiceException(i, s);
}
}
} else {
int j = pRequest.getRetryAfterHeader();
throw new RetryCallException(j, i);
}
} catch (RealmsHttpException realmshttpexception) {
throw new RealmsServiceException(500, "Could not connect to Realms: " + realmshttpexception.getMessage());
}
}
private static String getHttpCodeDescription(int pHttpCode) {
String s;
switch (pHttpCode) {
case 429:
s = I18n.get("mco.errorMessage.serviceBusy");
break;
default:
s = "Unknown error";
}
return s;
}
@OnlyIn(Dist.CLIENT)
public static enum CompatibleVersionResponse {
COMPATIBLE,
OUTDATED,
OTHER;
}
@OnlyIn(Dist.CLIENT)
public static enum Environment {
PRODUCTION("pc.realms.minecraft.net", "https"),
STAGE("pc-stage.realms.minecraft.net", "https"),
LOCAL("localhost:8080", "http");
public String baseUrl;
public String protocol;
private Environment(String pBaseUrl, String pProtocol) {
this.baseUrl = pBaseUrl;
this.protocol = pProtocol;
}
public static Optional<RealmsClient.Environment> byName(String pName) {
Optional optional;
switch (pName.toLowerCase(Locale.ROOT)) {
case "production":
optional = Optional.of(PRODUCTION);
break;
case "local":
optional = Optional.of(LOCAL);
break;
case "stage":
optional = Optional.of(STAGE);
break;
default:
optional = Optional.empty();
}
return optional;
}
}
}
@@ -0,0 +1,24 @@
package com.mojang.realmsclient.client;
import java.net.Proxy;
import javax.annotation.Nullable;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class RealmsClientConfig {
@Nullable
private static Proxy proxy;
@Nullable
public static Proxy getProxy() {
return proxy;
}
public static void setProxy(Proxy pProxy) {
if (proxy == null) {
proxy = pProxy;
}
}
}
@@ -0,0 +1,49 @@
package com.mojang.realmsclient.client;
import com.google.common.base.Strings;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.mojang.logging.LogUtils;
import com.mojang.realmsclient.util.JsonUtils;
import javax.annotation.Nullable;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class RealmsError {
private static final Logger LOGGER = LogUtils.getLogger();
private final String errorMessage;
private final int errorCode;
private RealmsError(String pErrorMessage, int pErrorCode) {
this.errorMessage = pErrorMessage;
this.errorCode = pErrorCode;
}
@Nullable
public static RealmsError parse(String pError) {
if (Strings.isNullOrEmpty(pError)) {
return null;
} else {
try {
JsonObject jsonobject = JsonParser.parseString(pError).getAsJsonObject();
String s = JsonUtils.getStringOr("errorMsg", jsonobject, "");
int i = JsonUtils.getIntOr("errorCode", jsonobject, -1);
return new RealmsError(s, i);
} catch (Exception exception) {
LOGGER.error("Could not parse RealmsError: {}", (Object)exception.getMessage());
LOGGER.error("The error was: {}", (Object)pError);
return null;
}
}
}
public String getErrorMessage() {
return this.errorMessage;
}
public int getErrorCode() {
return this.errorCode;
}
}
@@ -0,0 +1,301 @@
package com.mojang.realmsclient.client;
import com.mojang.realmsclient.exception.RealmsHttpException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.Proxy;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import javax.annotation.Nullable;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public abstract class Request<T extends Request<T>> {
protected HttpURLConnection connection;
private boolean connected;
protected String url;
private static final int DEFAULT_READ_TIMEOUT = 60000;
private static final int DEFAULT_CONNECT_TIMEOUT = 5000;
public Request(String pUrl, int pConnectTimeout, int pReadTimeout) {
try {
this.url = pUrl;
Proxy proxy = RealmsClientConfig.getProxy();
if (proxy != null) {
this.connection = (HttpURLConnection)(new URL(pUrl)).openConnection(proxy);
} else {
this.connection = (HttpURLConnection)(new URL(pUrl)).openConnection();
}
this.connection.setConnectTimeout(pConnectTimeout);
this.connection.setReadTimeout(pReadTimeout);
} catch (MalformedURLException malformedurlexception) {
throw new RealmsHttpException(malformedurlexception.getMessage(), malformedurlexception);
} catch (IOException ioexception) {
throw new RealmsHttpException(ioexception.getMessage(), ioexception);
}
}
public void cookie(String pKey, String pValue) {
cookie(this.connection, pKey, pValue);
}
public static void cookie(HttpURLConnection pConnection, String pKey, String pValue) {
String s = pConnection.getRequestProperty("Cookie");
if (s == null) {
pConnection.setRequestProperty("Cookie", pKey + "=" + pValue);
} else {
pConnection.setRequestProperty("Cookie", s + ";" + pKey + "=" + pValue);
}
}
public T header(String pException, String p_167287_) {
this.connection.addRequestProperty(pException, p_167287_);
return (T)this;
}
public int getRetryAfterHeader() {
return getRetryAfterHeader(this.connection);
}
public static int getRetryAfterHeader(HttpURLConnection pConnection) {
String s = pConnection.getHeaderField("Retry-After");
try {
return Integer.valueOf(s);
} catch (Exception exception) {
return 5;
}
}
public int responseCode() {
try {
this.connect();
return this.connection.getResponseCode();
} catch (Exception exception) {
throw new RealmsHttpException(exception.getMessage(), exception);
}
}
public String text() {
try {
this.connect();
String s;
if (this.responseCode() >= 400) {
s = this.read(this.connection.getErrorStream());
} else {
s = this.read(this.connection.getInputStream());
}
this.dispose();
return s;
} catch (IOException ioexception) {
throw new RealmsHttpException(ioexception.getMessage(), ioexception);
}
}
private String read(@Nullable InputStream p_87315_) throws IOException {
if (p_87315_ == null) {
return "";
} else {
InputStreamReader inputstreamreader = new InputStreamReader(p_87315_, StandardCharsets.UTF_8);
StringBuilder stringbuilder = new StringBuilder();
for(int i = inputstreamreader.read(); i != -1; i = inputstreamreader.read()) {
stringbuilder.append((char)i);
}
return stringbuilder.toString();
}
}
private void dispose() {
byte[] abyte = new byte[1024];
try {
InputStream inputstream = this.connection.getInputStream();
while(inputstream.read(abyte) > 0) {
}
inputstream.close();
return;
} catch (Exception exception) {
try {
InputStream inputstream1 = this.connection.getErrorStream();
if (inputstream1 != null) {
while(inputstream1.read(abyte) > 0) {
}
inputstream1.close();
return;
}
} catch (IOException ioexception) {
return;
}
} finally {
if (this.connection != null) {
this.connection.disconnect();
}
}
}
protected T connect() {
if (this.connected) {
return (T)this;
} else {
T t = this.doConnect();
this.connected = true;
return t;
}
}
protected abstract T doConnect();
public static Request<?> get(String pUrl) {
return new Request.Get(pUrl, 5000, 60000);
}
public static Request<?> get(String pUrl, int pConnectTimeout, int pReadTimeout) {
return new Request.Get(pUrl, pConnectTimeout, pReadTimeout);
}
public static Request<?> post(String pUrl, String pContent) {
return new Request.Post(pUrl, pContent, 5000, 60000);
}
public static Request<?> post(String pUrl, String pContent, int pConnectTimeout, int pReadTimeout) {
return new Request.Post(pUrl, pContent, pConnectTimeout, pReadTimeout);
}
public static Request<?> delete(String pUrl) {
return new Request.Delete(pUrl, 5000, 60000);
}
public static Request<?> put(String pUrl, String pContent) {
return new Request.Put(pUrl, pContent, 5000, 60000);
}
public static Request<?> put(String pUrl, String pContent, int pConnectTimeout, int pReadTimeout) {
return new Request.Put(pUrl, pContent, pConnectTimeout, pReadTimeout);
}
public String getHeader(String pName) {
return getHeader(this.connection, pName);
}
public static String getHeader(HttpURLConnection pConnection, String pName) {
try {
return pConnection.getHeaderField(pName);
} catch (Exception exception) {
return "";
}
}
@OnlyIn(Dist.CLIENT)
public static class Delete extends Request<Request.Delete> {
public Delete(String p_87359_, int p_87360_, int p_87361_) {
super(p_87359_, p_87360_, p_87361_);
}
public Request.Delete doConnect() {
try {
this.connection.setDoOutput(true);
this.connection.setRequestMethod("DELETE");
this.connection.connect();
return this;
} catch (Exception exception) {
throw new RealmsHttpException(exception.getMessage(), exception);
}
}
}
@OnlyIn(Dist.CLIENT)
public static class Get extends Request<Request.Get> {
public Get(String p_87365_, int p_87366_, int p_87367_) {
super(p_87365_, p_87366_, p_87367_);
}
public Request.Get doConnect() {
try {
this.connection.setDoInput(true);
this.connection.setDoOutput(true);
this.connection.setUseCaches(false);
this.connection.setRequestMethod("GET");
return this;
} catch (Exception exception) {
throw new RealmsHttpException(exception.getMessage(), exception);
}
}
}
@OnlyIn(Dist.CLIENT)
public static class Post extends Request<Request.Post> {
private final String content;
public Post(String pUrl, String pContent, int pConnectTimeout, int pReadTimeout) {
super(pUrl, pConnectTimeout, pReadTimeout);
this.content = pContent;
}
public Request.Post doConnect() {
try {
if (this.content != null) {
this.connection.setRequestProperty("Content-Type", "application/json; charset=utf-8");
}
this.connection.setDoInput(true);
this.connection.setDoOutput(true);
this.connection.setUseCaches(false);
this.connection.setRequestMethod("POST");
OutputStream outputstream = this.connection.getOutputStream();
OutputStreamWriter outputstreamwriter = new OutputStreamWriter(outputstream, "UTF-8");
outputstreamwriter.write(this.content);
outputstreamwriter.close();
outputstream.flush();
return this;
} catch (Exception exception) {
throw new RealmsHttpException(exception.getMessage(), exception);
}
}
}
@OnlyIn(Dist.CLIENT)
public static class Put extends Request<Request.Put> {
private final String content;
public Put(String pUrl, String pContent, int pConnectTimeout, int pReadTimeout) {
super(pUrl, pConnectTimeout, pReadTimeout);
this.content = pContent;
}
public Request.Put doConnect() {
try {
if (this.content != null) {
this.connection.setRequestProperty("Content-Type", "application/json; charset=utf-8");
}
this.connection.setDoOutput(true);
this.connection.setDoInput(true);
this.connection.setRequestMethod("PUT");
OutputStream outputstream = this.connection.getOutputStream();
OutputStreamWriter outputstreamwriter = new OutputStreamWriter(outputstream, "UTF-8");
outputstreamwriter.write(this.content);
outputstreamwriter.close();
outputstream.flush();
return this;
} catch (Exception exception) {
throw new RealmsHttpException(exception.getMessage(), exception);
}
}
}
}
@@ -0,0 +1,10 @@
package com.mojang.realmsclient.client;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class UploadStatus {
public volatile long bytesWritten;
public volatile long totalBytes;
}
@@ -0,0 +1,11 @@
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
@FieldsAreNonnullByDefault
@OnlyIn(Dist.CLIENT)
package com.mojang.realmsclient.client;
import javax.annotation.ParametersAreNonnullByDefault;
import net.minecraft.FieldsAreNonnullByDefault;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@@ -0,0 +1,55 @@
package com.mojang.realmsclient.dto;
import com.google.common.collect.Maps;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.mojang.logging.LogUtils;
import com.mojang.realmsclient.util.JsonUtils;
import java.util.Date;
import java.util.Map;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class Backup extends ValueObject {
private static final Logger LOGGER = LogUtils.getLogger();
public String backupId;
public Date lastModifiedDate;
public long size;
private boolean uploadedVersion;
public Map<String, String> metadata = Maps.newHashMap();
public Map<String, String> changeList = Maps.newHashMap();
public static Backup parse(JsonElement pJson) {
JsonObject jsonobject = pJson.getAsJsonObject();
Backup backup = new Backup();
try {
backup.backupId = JsonUtils.getStringOr("backupId", jsonobject, "");
backup.lastModifiedDate = JsonUtils.getDateOr("lastModifiedDate", jsonobject);
backup.size = JsonUtils.getLongOr("size", jsonobject, 0L);
if (jsonobject.has("metadata")) {
JsonObject jsonobject1 = jsonobject.getAsJsonObject("metadata");
for(Map.Entry<String, JsonElement> entry : jsonobject1.entrySet()) {
if (!entry.getValue().isJsonNull()) {
backup.metadata.put(entry.getKey(), entry.getValue().getAsString());
}
}
}
} catch (Exception exception) {
LOGGER.error("Could not parse Backup: {}", (Object)exception.getMessage());
}
return backup;
}
public boolean isUploadedVersion() {
return this.uploadedVersion;
}
public void setUploadedVersion(boolean pUploadedVersion) {
this.uploadedVersion = pUploadedVersion;
}
}
@@ -0,0 +1,38 @@
package com.mojang.realmsclient.dto;
import com.google.common.collect.Lists;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.mojang.logging.LogUtils;
import java.util.Iterator;
import java.util.List;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class BackupList extends ValueObject {
private static final Logger LOGGER = LogUtils.getLogger();
public List<Backup> backups;
public static BackupList parse(String pJson) {
JsonParser jsonparser = new JsonParser();
BackupList backuplist = new BackupList();
backuplist.backups = Lists.newArrayList();
try {
JsonElement jsonelement = jsonparser.parse(pJson).getAsJsonObject().get("backups");
if (jsonelement.isJsonArray()) {
Iterator<JsonElement> iterator = jsonelement.getAsJsonArray().iterator();
while(iterator.hasNext()) {
backuplist.backups.add(Backup.parse(iterator.next()));
}
}
} catch (Exception exception) {
LOGGER.error("Could not parse BackupList: {}", (Object)exception.getMessage());
}
return backuplist;
}
}
@@ -0,0 +1,25 @@
package com.mojang.realmsclient.dto;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import javax.annotation.Nullable;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class GuardedSerializer {
private final Gson gson = new Gson();
public String toJson(ReflectionBasedSerialization pReflectionBasedSerialization) {
return this.gson.toJson(pReflectionBasedSerialization);
}
public String toJson(JsonElement pJson) {
return this.gson.toJson(pJson);
}
@Nullable
public <T extends ReflectionBasedSerialization> T fromJson(String pJson, Class<T> pClassOfT) {
return this.gson.fromJson(pJson, pClassOfT);
}
}
@@ -0,0 +1,33 @@
package com.mojang.realmsclient.dto;
import com.google.common.collect.Sets;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.util.Set;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class Ops extends ValueObject {
public Set<String> ops = Sets.newHashSet();
public static Ops parse(String pJson) {
Ops ops = new Ops();
JsonParser jsonparser = new JsonParser();
try {
JsonElement jsonelement = jsonparser.parse(pJson);
JsonObject jsonobject = jsonelement.getAsJsonObject();
JsonElement jsonelement1 = jsonobject.get("ops");
if (jsonelement1.isJsonArray()) {
for(JsonElement jsonelement2 : jsonelement1.getAsJsonArray()) {
ops.ops.add(jsonelement2.getAsString());
}
}
} catch (Exception exception) {
}
return ops;
}
}
@@ -0,0 +1,35 @@
package com.mojang.realmsclient.dto;
import com.google.gson.JsonObject;
import com.mojang.logging.LogUtils;
import com.mojang.realmsclient.util.JsonUtils;
import java.util.Date;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class PendingInvite extends ValueObject {
private static final Logger LOGGER = LogUtils.getLogger();
public String invitationId;
public String worldName;
public String worldOwnerName;
public String worldOwnerUuid;
public Date date;
public static PendingInvite parse(JsonObject pJson) {
PendingInvite pendinginvite = new PendingInvite();
try {
pendinginvite.invitationId = JsonUtils.getStringOr("invitationId", pJson, "");
pendinginvite.worldName = JsonUtils.getStringOr("worldName", pJson, "");
pendinginvite.worldOwnerName = JsonUtils.getStringOr("worldOwnerName", pJson, "");
pendinginvite.worldOwnerUuid = JsonUtils.getStringOr("worldOwnerUuid", pJson, "");
pendinginvite.date = JsonUtils.getDateOr("date", pJson);
} catch (Exception exception) {
LOGGER.error("Could not parse PendingInvite: {}", (Object)exception.getMessage());
}
return pendinginvite;
}
}
@@ -0,0 +1,38 @@
package com.mojang.realmsclient.dto;
import com.google.common.collect.Lists;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.mojang.logging.LogUtils;
import java.util.Iterator;
import java.util.List;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class PendingInvitesList extends ValueObject {
private static final Logger LOGGER = LogUtils.getLogger();
public List<PendingInvite> pendingInvites = Lists.newArrayList();
public static PendingInvitesList parse(String pJson) {
PendingInvitesList pendinginviteslist = new PendingInvitesList();
try {
JsonParser jsonparser = new JsonParser();
JsonObject jsonobject = jsonparser.parse(pJson).getAsJsonObject();
if (jsonobject.get("invites").isJsonArray()) {
Iterator<JsonElement> iterator = jsonobject.get("invites").getAsJsonArray().iterator();
while(iterator.hasNext()) {
pendinginviteslist.pendingInvites.add(PendingInvite.parse(iterator.next().getAsJsonObject()));
}
}
} catch (Exception exception) {
LOGGER.error("Could not parse PendingInvitesList: {}", (Object)exception.getMessage());
}
return pendinginviteslist;
}
}
@@ -0,0 +1,15 @@
package com.mojang.realmsclient.dto;
import com.google.common.collect.Lists;
import com.google.gson.annotations.SerializedName;
import java.util.List;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class PingResult extends ValueObject implements ReflectionBasedSerialization {
@SerializedName("pingResults")
public List<RegionPingResult> pingResults = Lists.newArrayList();
@SerializedName("worldIds")
public List<Long> worldIds = Lists.newArrayList();
}
@@ -0,0 +1,59 @@
package com.mojang.realmsclient.dto;
import com.google.gson.annotations.SerializedName;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class PlayerInfo extends ValueObject implements ReflectionBasedSerialization {
@SerializedName("name")
private String name;
@SerializedName("uuid")
private String uuid;
@SerializedName("operator")
private boolean operator;
@SerializedName("accepted")
private boolean accepted;
@SerializedName("online")
private boolean online;
public String getName() {
return this.name;
}
public void setName(String pName) {
this.name = pName;
}
public String getUuid() {
return this.uuid;
}
public void setUuid(String pUuid) {
this.uuid = pUuid;
}
public boolean isOperator() {
return this.operator;
}
public void setOperator(boolean pOperator) {
this.operator = pOperator;
}
public boolean getAccepted() {
return this.accepted;
}
public void setAccepted(boolean pAccepted) {
this.accepted = pAccepted;
}
public boolean getOnline() {
return this.online;
}
public void setOnline(boolean pOnline) {
this.online = pOnline;
}
}
@@ -0,0 +1,18 @@
package com.mojang.realmsclient.dto;
import com.google.gson.annotations.SerializedName;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class RealmsDescriptionDto extends ValueObject implements ReflectionBasedSerialization {
@SerializedName("name")
public String name;
@SerializedName("description")
public String description;
public RealmsDescriptionDto(String pName, String pDescription) {
this.name = pName;
this.description = pDescription;
}
}
@@ -0,0 +1,29 @@
package com.mojang.realmsclient.dto;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.mojang.logging.LogUtils;
import com.mojang.realmsclient.util.JsonUtils;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class RealmsNews extends ValueObject {
private static final Logger LOGGER = LogUtils.getLogger();
public String newsLink;
public static RealmsNews parse(String pJson) {
RealmsNews realmsnews = new RealmsNews();
try {
JsonParser jsonparser = new JsonParser();
JsonObject jsonobject = jsonparser.parse(pJson).getAsJsonObject();
realmsnews.newsLink = JsonUtils.getStringOr("newsLink", jsonobject, (String)null);
} catch (Exception exception) {
LOGGER.error("Could not parse RealmsNews: {}", (Object)exception.getMessage());
}
return realmsnews;
}
}
@@ -0,0 +1,110 @@
package com.mojang.realmsclient.dto;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.mojang.logging.LogUtils;
import com.mojang.realmsclient.util.JsonUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.screens.ConfirmLinkScreen;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class RealmsNotification {
private static final Logger LOGGER = LogUtils.getLogger();
private static final String NOTIFICATION_UUID = "notificationUuid";
private static final String DISMISSABLE = "dismissable";
private static final String SEEN = "seen";
private static final String TYPE = "type";
private static final String VISIT_URL = "visitUrl";
final UUID uuid;
final boolean dismissable;
final boolean seen;
final String type;
RealmsNotification(UUID pUuid, boolean pDismissable, boolean pSeen, String pType) {
this.uuid = pUuid;
this.dismissable = pDismissable;
this.seen = pSeen;
this.type = pType;
}
public boolean seen() {
return this.seen;
}
public boolean dismissable() {
return this.dismissable;
}
public UUID uuid() {
return this.uuid;
}
public static List<RealmsNotification> parseList(String pJson) {
List<RealmsNotification> list = new ArrayList<>();
try {
for(JsonElement jsonelement : JsonParser.parseString(pJson).getAsJsonObject().get("notifications").getAsJsonArray()) {
list.add(parse(jsonelement.getAsJsonObject()));
}
} catch (Exception exception) {
LOGGER.error("Could not parse list of RealmsNotifications", (Throwable)exception);
}
return list;
}
private static RealmsNotification parse(JsonObject pJson) {
UUID uuid = JsonUtils.getUuidOr("notificationUuid", pJson, (UUID)null);
if (uuid == null) {
throw new IllegalStateException("Missing required property notificationUuid");
} else {
boolean flag = JsonUtils.getBooleanOr("dismissable", pJson, true);
boolean flag1 = JsonUtils.getBooleanOr("seen", pJson, false);
String s = JsonUtils.getRequiredString("type", pJson);
RealmsNotification realmsnotification = new RealmsNotification(uuid, flag, flag1, s);
return (RealmsNotification)("visitUrl".equals(s) ? RealmsNotification.VisitUrl.parse(realmsnotification, pJson) : realmsnotification);
}
}
@OnlyIn(Dist.CLIENT)
public static class VisitUrl extends RealmsNotification {
private static final String URL = "url";
private static final String BUTTON_TEXT = "buttonText";
private static final String MESSAGE = "message";
private final String url;
private final RealmsText buttonText;
private final RealmsText message;
private VisitUrl(RealmsNotification pNotification, String pUrl, RealmsText pButtonText, RealmsText pMessage) {
super(pNotification.uuid, pNotification.dismissable, pNotification.seen, pNotification.type);
this.url = pUrl;
this.buttonText = pButtonText;
this.message = pMessage;
}
public static RealmsNotification.VisitUrl parse(RealmsNotification pNotification, JsonObject pJson) {
String s = JsonUtils.getRequiredString("url", pJson);
RealmsText realmstext = JsonUtils.getRequired("buttonText", pJson, RealmsText::parse);
RealmsText realmstext1 = JsonUtils.getRequired("message", pJson, RealmsText::parse);
return new RealmsNotification.VisitUrl(pNotification, s, realmstext, realmstext1);
}
public Component getMessage() {
return this.message.createComponent(Component.translatable("mco.notification.visitUrl.message.default"));
}
public Button buildOpenLinkButton(Screen pLastScreen) {
Component component = this.buttonText.createComponent(Component.translatable("mco.notification.visitUrl.buttonText.default"));
return Button.builder(component, ConfirmLinkScreen.confirmLink(this.url, pLastScreen, true)).build();
}
}
}
@@ -0,0 +1,308 @@
package com.mojang.realmsclient.dto;
import com.google.common.base.Joiner;
import com.google.common.collect.ComparisonChain;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.mojang.logging.LogUtils;
import com.mojang.realmsclient.util.JsonUtils;
import com.mojang.realmsclient.util.RealmsUtil;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ServerData;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class RealmsServer extends ValueObject {
private static final Logger LOGGER = LogUtils.getLogger();
public long id;
public String remoteSubscriptionId;
public String name;
public String motd;
public RealmsServer.State state;
public String owner;
public String ownerUUID;
public List<PlayerInfo> players;
public Map<Integer, RealmsWorldOptions> slots;
public boolean expired;
public boolean expiredTrial;
public int daysLeft;
public RealmsServer.WorldType worldType;
public int activeSlot;
public String minigameName;
public int minigameId;
public String minigameImage;
public RealmsServerPing serverPing = new RealmsServerPing();
public String getDescription() {
return this.motd;
}
public String getName() {
return this.name;
}
public String getMinigameName() {
return this.minigameName;
}
public void setName(String pName) {
this.name = pName;
}
public void setDescription(String pMotd) {
this.motd = pMotd;
}
public void updateServerPing(RealmsServerPlayerList pRealmsServerPlayerList) {
List<String> list = Lists.newArrayList();
int i = 0;
for(String s : pRealmsServerPlayerList.players) {
if (!s.equals(Minecraft.getInstance().getUser().getUuid())) {
String s1 = "";
try {
s1 = RealmsUtil.uuidToName(s);
} catch (Exception exception) {
LOGGER.error("Could not get name for {}", s, exception);
continue;
}
list.add(s1);
++i;
}
}
this.serverPing.nrOfPlayers = String.valueOf(i);
this.serverPing.playerList = Joiner.on('\n').join(list);
}
public static RealmsServer parse(JsonObject pJson) {
RealmsServer realmsserver = new RealmsServer();
try {
realmsserver.id = JsonUtils.getLongOr("id", pJson, -1L);
realmsserver.remoteSubscriptionId = JsonUtils.getStringOr("remoteSubscriptionId", pJson, (String)null);
realmsserver.name = JsonUtils.getStringOr("name", pJson, (String)null);
realmsserver.motd = JsonUtils.getStringOr("motd", pJson, (String)null);
realmsserver.state = getState(JsonUtils.getStringOr("state", pJson, RealmsServer.State.CLOSED.name()));
realmsserver.owner = JsonUtils.getStringOr("owner", pJson, (String)null);
if (pJson.get("players") != null && pJson.get("players").isJsonArray()) {
realmsserver.players = parseInvited(pJson.get("players").getAsJsonArray());
sortInvited(realmsserver);
} else {
realmsserver.players = Lists.newArrayList();
}
realmsserver.daysLeft = JsonUtils.getIntOr("daysLeft", pJson, 0);
realmsserver.expired = JsonUtils.getBooleanOr("expired", pJson, false);
realmsserver.expiredTrial = JsonUtils.getBooleanOr("expiredTrial", pJson, false);
realmsserver.worldType = getWorldType(JsonUtils.getStringOr("worldType", pJson, RealmsServer.WorldType.NORMAL.name()));
realmsserver.ownerUUID = JsonUtils.getStringOr("ownerUUID", pJson, "");
if (pJson.get("slots") != null && pJson.get("slots").isJsonArray()) {
realmsserver.slots = parseSlots(pJson.get("slots").getAsJsonArray());
} else {
realmsserver.slots = createEmptySlots();
}
realmsserver.minigameName = JsonUtils.getStringOr("minigameName", pJson, (String)null);
realmsserver.activeSlot = JsonUtils.getIntOr("activeSlot", pJson, -1);
realmsserver.minigameId = JsonUtils.getIntOr("minigameId", pJson, -1);
realmsserver.minigameImage = JsonUtils.getStringOr("minigameImage", pJson, (String)null);
} catch (Exception exception) {
LOGGER.error("Could not parse McoServer: {}", (Object)exception.getMessage());
}
return realmsserver;
}
private static void sortInvited(RealmsServer pRealmsServer) {
pRealmsServer.players.sort((p_87502_, p_87503_) -> {
return ComparisonChain.start().compareFalseFirst(p_87503_.getAccepted(), p_87502_.getAccepted()).compare(p_87502_.getName().toLowerCase(Locale.ROOT), p_87503_.getName().toLowerCase(Locale.ROOT)).result();
});
}
private static List<PlayerInfo> parseInvited(JsonArray pJsonArray) {
List<PlayerInfo> list = Lists.newArrayList();
for(JsonElement jsonelement : pJsonArray) {
try {
JsonObject jsonobject = jsonelement.getAsJsonObject();
PlayerInfo playerinfo = new PlayerInfo();
playerinfo.setName(JsonUtils.getStringOr("name", jsonobject, (String)null));
playerinfo.setUuid(JsonUtils.getStringOr("uuid", jsonobject, (String)null));
playerinfo.setOperator(JsonUtils.getBooleanOr("operator", jsonobject, false));
playerinfo.setAccepted(JsonUtils.getBooleanOr("accepted", jsonobject, false));
playerinfo.setOnline(JsonUtils.getBooleanOr("online", jsonobject, false));
list.add(playerinfo);
} catch (Exception exception) {
}
}
return list;
}
private static Map<Integer, RealmsWorldOptions> parseSlots(JsonArray pJsonArray) {
Map<Integer, RealmsWorldOptions> map = Maps.newHashMap();
for(JsonElement jsonelement : pJsonArray) {
try {
JsonObject jsonobject = jsonelement.getAsJsonObject();
JsonParser jsonparser = new JsonParser();
JsonElement jsonelement1 = jsonparser.parse(jsonobject.get("options").getAsString());
RealmsWorldOptions realmsworldoptions;
if (jsonelement1 == null) {
realmsworldoptions = RealmsWorldOptions.createDefaults();
} else {
realmsworldoptions = RealmsWorldOptions.parse(jsonelement1.getAsJsonObject());
}
int i = JsonUtils.getIntOr("slotId", jsonobject, -1);
map.put(i, realmsworldoptions);
} catch (Exception exception) {
}
}
for(int j = 1; j <= 3; ++j) {
if (!map.containsKey(j)) {
map.put(j, RealmsWorldOptions.createEmptyDefaults());
}
}
return map;
}
private static Map<Integer, RealmsWorldOptions> createEmptySlots() {
Map<Integer, RealmsWorldOptions> map = Maps.newHashMap();
map.put(1, RealmsWorldOptions.createEmptyDefaults());
map.put(2, RealmsWorldOptions.createEmptyDefaults());
map.put(3, RealmsWorldOptions.createEmptyDefaults());
return map;
}
public static RealmsServer parse(String pJson) {
try {
return parse((new JsonParser()).parse(pJson).getAsJsonObject());
} catch (Exception exception) {
LOGGER.error("Could not parse McoServer: {}", (Object)exception.getMessage());
return new RealmsServer();
}
}
private static RealmsServer.State getState(String pName) {
try {
return RealmsServer.State.valueOf(pName);
} catch (Exception exception) {
return RealmsServer.State.CLOSED;
}
}
private static RealmsServer.WorldType getWorldType(String pName) {
try {
return RealmsServer.WorldType.valueOf(pName);
} catch (Exception exception) {
return RealmsServer.WorldType.NORMAL;
}
}
public int hashCode() {
return Objects.hash(this.id, this.name, this.motd, this.state, this.owner, this.expired);
}
public boolean equals(Object pOther) {
if (pOther == null) {
return false;
} else if (pOther == this) {
return true;
} else if (pOther.getClass() != this.getClass()) {
return false;
} else {
RealmsServer realmsserver = (RealmsServer)pOther;
return (new EqualsBuilder()).append(this.id, realmsserver.id).append((Object)this.name, (Object)realmsserver.name).append((Object)this.motd, (Object)realmsserver.motd).append((Object)this.state, (Object)realmsserver.state).append((Object)this.owner, (Object)realmsserver.owner).append(this.expired, realmsserver.expired).append((Object)this.worldType, (Object)this.worldType).isEquals();
}
}
public RealmsServer clone() {
RealmsServer realmsserver = new RealmsServer();
realmsserver.id = this.id;
realmsserver.remoteSubscriptionId = this.remoteSubscriptionId;
realmsserver.name = this.name;
realmsserver.motd = this.motd;
realmsserver.state = this.state;
realmsserver.owner = this.owner;
realmsserver.players = this.players;
realmsserver.slots = this.cloneSlots(this.slots);
realmsserver.expired = this.expired;
realmsserver.expiredTrial = this.expiredTrial;
realmsserver.daysLeft = this.daysLeft;
realmsserver.serverPing = new RealmsServerPing();
realmsserver.serverPing.nrOfPlayers = this.serverPing.nrOfPlayers;
realmsserver.serverPing.playerList = this.serverPing.playerList;
realmsserver.worldType = this.worldType;
realmsserver.ownerUUID = this.ownerUUID;
realmsserver.minigameName = this.minigameName;
realmsserver.activeSlot = this.activeSlot;
realmsserver.minigameId = this.minigameId;
realmsserver.minigameImage = this.minigameImage;
return realmsserver;
}
public Map<Integer, RealmsWorldOptions> cloneSlots(Map<Integer, RealmsWorldOptions> pSlots) {
Map<Integer, RealmsWorldOptions> map = Maps.newHashMap();
for(Map.Entry<Integer, RealmsWorldOptions> entry : pSlots.entrySet()) {
map.put(entry.getKey(), entry.getValue().clone());
}
return map;
}
public String getWorldName(int pSlot) {
return this.name + " (" + this.slots.get(pSlot).getSlotName(pSlot) + ")";
}
public ServerData toServerData(String pIp) {
return new ServerData(this.name, pIp, false);
}
@OnlyIn(Dist.CLIENT)
public static class McoServerComparator implements Comparator<RealmsServer> {
private final String refOwner;
public McoServerComparator(String pRefOwner) {
this.refOwner = pRefOwner;
}
public int compare(RealmsServer p_87536_, RealmsServer p_87537_) {
return ComparisonChain.start().compareTrueFirst(p_87536_.state == RealmsServer.State.UNINITIALIZED, p_87537_.state == RealmsServer.State.UNINITIALIZED).compareTrueFirst(p_87536_.expiredTrial, p_87537_.expiredTrial).compareTrueFirst(p_87536_.owner.equals(this.refOwner), p_87537_.owner.equals(this.refOwner)).compareFalseFirst(p_87536_.expired, p_87537_.expired).compareTrueFirst(p_87536_.state == RealmsServer.State.OPEN, p_87537_.state == RealmsServer.State.OPEN).compare(p_87536_.id, p_87537_.id).result();
}
}
@OnlyIn(Dist.CLIENT)
public static enum State {
CLOSED,
OPEN,
UNINITIALIZED;
}
@OnlyIn(Dist.CLIENT)
public static enum WorldType {
NORMAL,
MINIGAME,
ADVENTUREMAP,
EXPERIENCE,
INSPIRATION;
}
}
@@ -0,0 +1,33 @@
package com.mojang.realmsclient.dto;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.mojang.logging.LogUtils;
import com.mojang.realmsclient.util.JsonUtils;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class RealmsServerAddress extends ValueObject {
private static final Logger LOGGER = LogUtils.getLogger();
public String address;
public String resourcePackUrl;
public String resourcePackHash;
public static RealmsServerAddress parse(String pJson) {
JsonParser jsonparser = new JsonParser();
RealmsServerAddress realmsserveraddress = new RealmsServerAddress();
try {
JsonObject jsonobject = jsonparser.parse(pJson).getAsJsonObject();
realmsserveraddress.address = JsonUtils.getStringOr("address", jsonobject, (String)null);
realmsserveraddress.resourcePackUrl = JsonUtils.getStringOr("resourcePackUrl", jsonobject, (String)null);
realmsserveraddress.resourcePackHash = JsonUtils.getStringOr("resourcePackHash", jsonobject, (String)null);
} catch (Exception exception) {
LOGGER.error("Could not parse RealmsServerAddress: {}", (Object)exception.getMessage());
}
return realmsserveraddress;
}
}
@@ -0,0 +1,41 @@
package com.mojang.realmsclient.dto;
import com.google.common.collect.Lists;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.mojang.logging.LogUtils;
import java.util.Iterator;
import java.util.List;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class RealmsServerList extends ValueObject {
private static final Logger LOGGER = LogUtils.getLogger();
public List<RealmsServer> servers;
public static RealmsServerList parse(String pJson) {
RealmsServerList realmsserverlist = new RealmsServerList();
realmsserverlist.servers = Lists.newArrayList();
try {
JsonParser jsonparser = new JsonParser();
JsonObject jsonobject = jsonparser.parse(pJson).getAsJsonObject();
if (jsonobject.get("servers").isJsonArray()) {
JsonArray jsonarray = jsonobject.get("servers").getAsJsonArray();
Iterator<JsonElement> iterator = jsonarray.iterator();
while(iterator.hasNext()) {
realmsserverlist.servers.add(RealmsServer.parse(iterator.next().getAsJsonObject()));
}
}
} catch (Exception exception) {
LOGGER.error("Could not parse McoServerList: {}", (Object)exception.getMessage());
}
return realmsserverlist;
}
}
@@ -0,0 +1,10 @@
package com.mojang.realmsclient.dto;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class RealmsServerPing extends ValueObject {
public volatile String nrOfPlayers = "0";
public volatile String playerList = "";
}
@@ -0,0 +1,57 @@
package com.mojang.realmsclient.dto;
import com.google.common.collect.Lists;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.mojang.logging.LogUtils;
import com.mojang.realmsclient.util.JsonUtils;
import java.util.List;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class RealmsServerPlayerList extends ValueObject {
private static final Logger LOGGER = LogUtils.getLogger();
private static final JsonParser JSON_PARSER = new JsonParser();
public long serverId;
public List<String> players;
public static RealmsServerPlayerList parse(JsonObject pJson) {
RealmsServerPlayerList realmsserverplayerlist = new RealmsServerPlayerList();
try {
realmsserverplayerlist.serverId = JsonUtils.getLongOr("serverId", pJson, -1L);
String s = JsonUtils.getStringOr("playerList", pJson, (String)null);
if (s != null) {
JsonElement jsonelement = JSON_PARSER.parse(s);
if (jsonelement.isJsonArray()) {
realmsserverplayerlist.players = parsePlayers(jsonelement.getAsJsonArray());
} else {
realmsserverplayerlist.players = Lists.newArrayList();
}
} else {
realmsserverplayerlist.players = Lists.newArrayList();
}
} catch (Exception exception) {
LOGGER.error("Could not parse RealmsServerPlayerList: {}", (Object)exception.getMessage());
}
return realmsserverplayerlist;
}
private static List<String> parsePlayers(JsonArray pJsonArray) {
List<String> list = Lists.newArrayList();
for(JsonElement jsonelement : pJsonArray) {
try {
list.add(jsonelement.getAsString());
} catch (Exception exception) {
}
}
return list;
}
}
@@ -0,0 +1,41 @@
package com.mojang.realmsclient.dto;
import com.google.common.collect.Lists;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.mojang.logging.LogUtils;
import java.util.Iterator;
import java.util.List;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class RealmsServerPlayerLists extends ValueObject {
private static final Logger LOGGER = LogUtils.getLogger();
public List<RealmsServerPlayerList> servers;
public static RealmsServerPlayerLists parse(String pJson) {
RealmsServerPlayerLists realmsserverplayerlists = new RealmsServerPlayerLists();
realmsserverplayerlists.servers = Lists.newArrayList();
try {
JsonParser jsonparser = new JsonParser();
JsonObject jsonobject = jsonparser.parse(pJson).getAsJsonObject();
if (jsonobject.get("lists").isJsonArray()) {
JsonArray jsonarray = jsonobject.get("lists").getAsJsonArray();
Iterator<JsonElement> iterator = jsonarray.iterator();
while(iterator.hasNext()) {
realmsserverplayerlists.servers.add(RealmsServerPlayerList.parse(iterator.next().getAsJsonObject()));
}
}
} catch (Exception exception) {
LOGGER.error("Could not parse RealmsServerPlayerLists: {}", (Object)exception.getMessage());
}
return realmsserverplayerlists;
}
}
@@ -0,0 +1,51 @@
package com.mojang.realmsclient.dto;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.mojang.realmsclient.util.JsonUtils;
import javax.annotation.Nullable;
import net.minecraft.client.resources.language.I18n;
import net.minecraft.network.chat.Component;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class RealmsText {
private static final String TRANSLATION_KEY = "translationKey";
private static final String ARGS = "args";
private final String translationKey;
@Nullable
private final Object[] args;
private RealmsText(String pTranslationKey, @Nullable Object[] pArgs) {
this.translationKey = pTranslationKey;
this.args = pArgs;
}
public Component createComponent(Component pDefaultValue) {
if (!I18n.exists(this.translationKey)) {
return pDefaultValue;
} else {
return this.args == null ? Component.translatable(this.translationKey) : Component.translatable(this.translationKey, this.args);
}
}
public static RealmsText parse(JsonObject pJson) {
String s = JsonUtils.getRequiredString("translationKey", pJson);
JsonElement jsonelement = pJson.get("args");
String[] astring;
if (jsonelement != null && !jsonelement.isJsonNull()) {
JsonArray jsonarray = jsonelement.getAsJsonArray();
astring = new String[jsonarray.size()];
for(int i = 0; i < jsonarray.size(); ++i) {
astring[i] = jsonarray.get(i).getAsString();
}
} else {
astring = null;
}
return new RealmsText(s, astring);
}
}
@@ -0,0 +1,135 @@
package com.mojang.realmsclient.dto;
import com.google.gson.JsonObject;
import com.mojang.realmsclient.util.JsonUtils;
import java.util.Objects;
import javax.annotation.Nullable;
import net.minecraft.client.resources.language.I18n;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class RealmsWorldOptions extends ValueObject {
public final boolean pvp;
public final boolean spawnAnimals;
public final boolean spawnMonsters;
public final boolean spawnNPCs;
public final int spawnProtection;
public final boolean commandBlocks;
public final boolean forceGameMode;
public final int difficulty;
public final int gameMode;
@Nullable
private final String slotName;
public long templateId;
@Nullable
public String templateImage;
public boolean empty;
private static final boolean DEFAULT_FORCE_GAME_MODE = false;
private static final boolean DEFAULT_PVP = true;
private static final boolean DEFAULT_SPAWN_ANIMALS = true;
private static final boolean DEFAULT_SPAWN_MONSTERS = true;
private static final boolean DEFAULT_SPAWN_NPCS = true;
private static final int DEFAULT_SPAWN_PROTECTION = 0;
private static final boolean DEFAULT_COMMAND_BLOCKS = false;
private static final int DEFAULT_DIFFICULTY = 2;
private static final int DEFAULT_GAME_MODE = 0;
private static final String DEFAULT_SLOT_NAME = "";
private static final long DEFAULT_TEMPLATE_ID = -1L;
private static final String DEFAULT_TEMPLATE_IMAGE = null;
public RealmsWorldOptions(boolean pPvp, boolean pSpawnAnimals, boolean pSpawnMonsters, boolean pSpawnNPCs, int pSpawnProtection, boolean pCommandBlocks, int pDifficulty, int pGameMode, boolean pForceGameMode, @Nullable String pSlotName) {
this.pvp = pPvp;
this.spawnAnimals = pSpawnAnimals;
this.spawnMonsters = pSpawnMonsters;
this.spawnNPCs = pSpawnNPCs;
this.spawnProtection = pSpawnProtection;
this.commandBlocks = pCommandBlocks;
this.difficulty = pDifficulty;
this.gameMode = pGameMode;
this.forceGameMode = pForceGameMode;
this.slotName = pSlotName;
}
public static RealmsWorldOptions createDefaults() {
return new RealmsWorldOptions(true, true, true, true, 0, false, 2, 0, false, "");
}
public static RealmsWorldOptions createEmptyDefaults() {
RealmsWorldOptions realmsworldoptions = createDefaults();
realmsworldoptions.setEmpty(true);
return realmsworldoptions;
}
public void setEmpty(boolean pEmpty) {
this.empty = pEmpty;
}
public static RealmsWorldOptions parse(JsonObject pJson) {
RealmsWorldOptions realmsworldoptions = new RealmsWorldOptions(JsonUtils.getBooleanOr("pvp", pJson, true), JsonUtils.getBooleanOr("spawnAnimals", pJson, true), JsonUtils.getBooleanOr("spawnMonsters", pJson, true), JsonUtils.getBooleanOr("spawnNPCs", pJson, true), JsonUtils.getIntOr("spawnProtection", pJson, 0), JsonUtils.getBooleanOr("commandBlocks", pJson, false), JsonUtils.getIntOr("difficulty", pJson, 2), JsonUtils.getIntOr("gameMode", pJson, 0), JsonUtils.getBooleanOr("forceGameMode", pJson, false), JsonUtils.getStringOr("slotName", pJson, ""));
realmsworldoptions.templateId = JsonUtils.getLongOr("worldTemplateId", pJson, -1L);
realmsworldoptions.templateImage = JsonUtils.getStringOr("worldTemplateImage", pJson, DEFAULT_TEMPLATE_IMAGE);
return realmsworldoptions;
}
public String getSlotName(int pSlotIndex) {
if (this.slotName != null && !this.slotName.isEmpty()) {
return this.slotName;
} else {
return this.empty ? I18n.get("mco.configure.world.slot.empty") : this.getDefaultSlotName(pSlotIndex);
}
}
public String getDefaultSlotName(int pSlotIndex) {
return I18n.get("mco.configure.world.slot", pSlotIndex);
}
public String toJson() {
JsonObject jsonobject = new JsonObject();
if (!this.pvp) {
jsonobject.addProperty("pvp", this.pvp);
}
if (!this.spawnAnimals) {
jsonobject.addProperty("spawnAnimals", this.spawnAnimals);
}
if (!this.spawnMonsters) {
jsonobject.addProperty("spawnMonsters", this.spawnMonsters);
}
if (!this.spawnNPCs) {
jsonobject.addProperty("spawnNPCs", this.spawnNPCs);
}
if (this.spawnProtection != 0) {
jsonobject.addProperty("spawnProtection", this.spawnProtection);
}
if (this.commandBlocks) {
jsonobject.addProperty("commandBlocks", this.commandBlocks);
}
if (this.difficulty != 2) {
jsonobject.addProperty("difficulty", this.difficulty);
}
if (this.gameMode != 0) {
jsonobject.addProperty("gameMode", this.gameMode);
}
if (this.forceGameMode) {
jsonobject.addProperty("forceGameMode", this.forceGameMode);
}
if (!Objects.equals(this.slotName, "")) {
jsonobject.addProperty("slotName", this.slotName);
}
return jsonobject.toString();
}
public RealmsWorldOptions clone() {
return new RealmsWorldOptions(this.pvp, this.spawnAnimals, this.spawnMonsters, this.spawnNPCs, this.spawnProtection, this.commandBlocks, this.difficulty, this.gameMode, this.forceGameMode, this.slotName);
}
}
@@ -0,0 +1,24 @@
package com.mojang.realmsclient.dto;
import com.google.gson.annotations.SerializedName;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class RealmsWorldResetDto extends ValueObject implements ReflectionBasedSerialization {
@SerializedName("seed")
private final String seed;
@SerializedName("worldTemplateId")
private final long worldTemplateId;
@SerializedName("levelType")
private final int levelType;
@SerializedName("generateStructures")
private final boolean generateStructures;
public RealmsWorldResetDto(String pSeed, long pWorldTemplateId, int pLevelType, boolean pGenerateStructures) {
this.seed = pSeed;
this.worldTemplateId = pWorldTemplateId;
this.levelType = pLevelType;
this.generateStructures = pGenerateStructures;
}
}
@@ -0,0 +1,8 @@
package com.mojang.realmsclient.dto;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public interface ReflectionBasedSerialization {
}
@@ -0,0 +1,27 @@
package com.mojang.realmsclient.dto;
import com.google.gson.annotations.SerializedName;
import java.util.Locale;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class RegionPingResult extends ValueObject implements ReflectionBasedSerialization {
@SerializedName("regionName")
private final String regionName;
@SerializedName("ping")
private final int ping;
public RegionPingResult(String pRegionName, int pPing) {
this.regionName = pRegionName;
this.ping = pPing;
}
public int ping() {
return this.ping;
}
public String toString() {
return String.format(Locale.ROOT, "%s --> %.2f ms", this.regionName, (float)this.ping);
}
}
@@ -0,0 +1,26 @@
package com.mojang.realmsclient.dto;
import com.google.gson.JsonObject;
import com.mojang.realmsclient.util.JsonUtils;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class ServerActivity extends ValueObject {
public String profileUuid;
public long joinTime;
public long leaveTime;
public static ServerActivity parse(JsonObject pJson) {
ServerActivity serveractivity = new ServerActivity();
try {
serveractivity.profileUuid = JsonUtils.getStringOr("profileUuid", pJson, (String)null);
serveractivity.joinTime = JsonUtils.getLongOr("joinTime", pJson, Long.MIN_VALUE);
serveractivity.leaveTime = JsonUtils.getLongOr("leaveTime", pJson, Long.MIN_VALUE);
} catch (Exception exception) {
}
return serveractivity;
}
}
@@ -0,0 +1,37 @@
package com.mojang.realmsclient.dto;
import com.google.common.collect.Lists;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.mojang.realmsclient.util.JsonUtils;
import java.util.List;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class ServerActivityList extends ValueObject {
public long periodInMillis;
public List<ServerActivity> serverActivities = Lists.newArrayList();
public static ServerActivityList parse(String pJson) {
ServerActivityList serveractivitylist = new ServerActivityList();
JsonParser jsonparser = new JsonParser();
try {
JsonElement jsonelement = jsonparser.parse(pJson);
JsonObject jsonobject = jsonelement.getAsJsonObject();
serveractivitylist.periodInMillis = JsonUtils.getLongOr("periodInMillis", jsonobject, -1L);
JsonElement jsonelement1 = jsonobject.get("playerActivityDto");
if (jsonelement1 != null && jsonelement1.isJsonArray()) {
for(JsonElement jsonelement2 : jsonelement1.getAsJsonArray()) {
ServerActivity serveractivity = ServerActivity.parse(jsonelement2.getAsJsonObject());
serveractivitylist.serverActivities.add(serveractivity);
}
}
} catch (Exception exception) {
}
return serveractivitylist;
}
}
@@ -0,0 +1,47 @@
package com.mojang.realmsclient.dto;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.mojang.logging.LogUtils;
import com.mojang.realmsclient.util.JsonUtils;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class Subscription extends ValueObject {
private static final Logger LOGGER = LogUtils.getLogger();
public long startDate;
public int daysLeft;
public Subscription.SubscriptionType type = Subscription.SubscriptionType.NORMAL;
public static Subscription parse(String pJson) {
Subscription subscription = new Subscription();
try {
JsonParser jsonparser = new JsonParser();
JsonObject jsonobject = jsonparser.parse(pJson).getAsJsonObject();
subscription.startDate = JsonUtils.getLongOr("startDate", jsonobject, 0L);
subscription.daysLeft = JsonUtils.getIntOr("daysLeft", jsonobject, 0);
subscription.type = typeFrom(JsonUtils.getStringOr("subscriptionType", jsonobject, Subscription.SubscriptionType.NORMAL.name()));
} catch (Exception exception) {
LOGGER.error("Could not parse Subscription: {}", (Object)exception.getMessage());
}
return subscription;
}
private static Subscription.SubscriptionType typeFrom(String pName) {
try {
return Subscription.SubscriptionType.valueOf(pName);
} catch (Exception exception) {
return Subscription.SubscriptionType.NORMAL;
}
}
@OnlyIn(Dist.CLIENT)
public static enum SubscriptionType {
NORMAL,
RECURRING;
}
}
@@ -0,0 +1,105 @@
package com.mojang.realmsclient.dto;
import com.google.common.annotations.VisibleForTesting;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.mojang.logging.LogUtils;
import com.mojang.realmsclient.util.JsonUtils;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Nullable;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class UploadInfo extends ValueObject {
private static final Logger LOGGER = LogUtils.getLogger();
private static final String DEFAULT_SCHEMA = "http://";
private static final int DEFAULT_PORT = 8080;
private static final Pattern URI_SCHEMA_PATTERN = Pattern.compile("^[a-zA-Z][-a-zA-Z0-9+.]+:");
private final boolean worldClosed;
@Nullable
private final String token;
private final URI uploadEndpoint;
private UploadInfo(boolean pWorldClosed, @Nullable String pToken, URI pUploadEndpoint) {
this.worldClosed = pWorldClosed;
this.token = pToken;
this.uploadEndpoint = pUploadEndpoint;
}
@Nullable
public static UploadInfo parse(String pJson) {
try {
JsonParser jsonparser = new JsonParser();
JsonObject jsonobject = jsonparser.parse(pJson).getAsJsonObject();
String s = JsonUtils.getStringOr("uploadEndpoint", jsonobject, (String)null);
if (s != null) {
int i = JsonUtils.getIntOr("port", jsonobject, -1);
URI uri = assembleUri(s, i);
if (uri != null) {
boolean flag = JsonUtils.getBooleanOr("worldClosed", jsonobject, false);
String s1 = JsonUtils.getStringOr("token", jsonobject, (String)null);
return new UploadInfo(flag, s1, uri);
}
}
} catch (Exception exception) {
LOGGER.error("Could not parse UploadInfo: {}", (Object)exception.getMessage());
}
return null;
}
@Nullable
@VisibleForTesting
public static URI assembleUri(String pUri, int pPort) {
Matcher matcher = URI_SCHEMA_PATTERN.matcher(pUri);
String s = ensureEndpointSchema(pUri, matcher);
try {
URI uri = new URI(s);
int i = selectPortOrDefault(pPort, uri.getPort());
return i != uri.getPort() ? new URI(uri.getScheme(), uri.getUserInfo(), uri.getHost(), i, uri.getPath(), uri.getQuery(), uri.getFragment()) : uri;
} catch (URISyntaxException urisyntaxexception) {
LOGGER.warn("Failed to parse URI {}", s, urisyntaxexception);
return null;
}
}
private static int selectPortOrDefault(int pPort, int pDefaultPort) {
if (pPort != -1) {
return pPort;
} else {
return pDefaultPort != -1 ? pDefaultPort : 8080;
}
}
private static String ensureEndpointSchema(String pUri, Matcher pMatcher) {
return pMatcher.find() ? pUri : "http://" + pUri;
}
public static String createRequest(@Nullable String pToken) {
JsonObject jsonobject = new JsonObject();
if (pToken != null) {
jsonobject.addProperty("token", pToken);
}
return jsonobject.toString();
}
@Nullable
public String getToken() {
return this.token;
}
public URI getUploadEndpoint() {
return this.uploadEndpoint;
}
public boolean isWorldClosed() {
return this.worldClosed;
}
}
@@ -0,0 +1,36 @@
package com.mojang.realmsclient.dto;
import com.google.gson.annotations.SerializedName;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public abstract class ValueObject {
public String toString() {
StringBuilder stringbuilder = new StringBuilder("{");
for(Field field : this.getClass().getFields()) {
if (!isStatic(field)) {
try {
stringbuilder.append(getName(field)).append("=").append(field.get(this)).append(" ");
} catch (IllegalAccessException illegalaccessexception) {
}
}
}
stringbuilder.deleteCharAt(stringbuilder.length() - 1);
stringbuilder.append('}');
return stringbuilder.toString();
}
private static String getName(Field pField) {
SerializedName serializedname = pField.getAnnotation(SerializedName.class);
return serializedname != null ? serializedname.value() : pField.getName();
}
private static boolean isStatic(Field pField) {
return Modifier.isStatic(pField.getModifiers());
}
}
@@ -0,0 +1,33 @@
package com.mojang.realmsclient.dto;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.mojang.logging.LogUtils;
import com.mojang.realmsclient.util.JsonUtils;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class WorldDownload extends ValueObject {
private static final Logger LOGGER = LogUtils.getLogger();
public String downloadLink;
public String resourcePackUrl;
public String resourcePackHash;
public static WorldDownload parse(String pJson) {
JsonParser jsonparser = new JsonParser();
JsonObject jsonobject = jsonparser.parse(pJson).getAsJsonObject();
WorldDownload worlddownload = new WorldDownload();
try {
worlddownload.downloadLink = JsonUtils.getStringOr("downloadLink", jsonobject, "");
worlddownload.resourcePackUrl = JsonUtils.getStringOr("resourcePackUrl", jsonobject, "");
worlddownload.resourcePackHash = JsonUtils.getStringOr("resourcePackHash", jsonobject, "");
} catch (Exception exception) {
LOGGER.error("Could not parse WorldDownload: {}", (Object)exception.getMessage());
}
return worlddownload;
}
}
@@ -0,0 +1,53 @@
package com.mojang.realmsclient.dto;
import com.google.gson.JsonObject;
import com.mojang.logging.LogUtils;
import com.mojang.realmsclient.util.JsonUtils;
import javax.annotation.Nullable;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class WorldTemplate extends ValueObject {
private static final Logger LOGGER = LogUtils.getLogger();
public String id = "";
public String name = "";
public String version = "";
public String author = "";
public String link = "";
@Nullable
public String image;
public String trailer = "";
public String recommendedPlayers = "";
public WorldTemplate.WorldTemplateType type = WorldTemplate.WorldTemplateType.WORLD_TEMPLATE;
public static WorldTemplate parse(JsonObject pJson) {
WorldTemplate worldtemplate = new WorldTemplate();
try {
worldtemplate.id = JsonUtils.getStringOr("id", pJson, "");
worldtemplate.name = JsonUtils.getStringOr("name", pJson, "");
worldtemplate.version = JsonUtils.getStringOr("version", pJson, "");
worldtemplate.author = JsonUtils.getStringOr("author", pJson, "");
worldtemplate.link = JsonUtils.getStringOr("link", pJson, "");
worldtemplate.image = JsonUtils.getStringOr("image", pJson, (String)null);
worldtemplate.trailer = JsonUtils.getStringOr("trailer", pJson, "");
worldtemplate.recommendedPlayers = JsonUtils.getStringOr("recommendedPlayers", pJson, "");
worldtemplate.type = WorldTemplate.WorldTemplateType.valueOf(JsonUtils.getStringOr("type", pJson, WorldTemplate.WorldTemplateType.WORLD_TEMPLATE.name()));
} catch (Exception exception) {
LOGGER.error("Could not parse WorldTemplate: {}", (Object)exception.getMessage());
}
return worldtemplate;
}
@OnlyIn(Dist.CLIENT)
public static enum WorldTemplateType {
WORLD_TEMPLATE,
MINIGAME,
ADVENTUREMAP,
EXPERIENCE,
INSPIRATION;
}
}
@@ -0,0 +1,62 @@
package com.mojang.realmsclient.dto;
import com.google.common.collect.Lists;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.mojang.logging.LogUtils;
import com.mojang.realmsclient.util.JsonUtils;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class WorldTemplatePaginatedList extends ValueObject {
private static final Logger LOGGER = LogUtils.getLogger();
public List<WorldTemplate> templates;
public int page;
public int size;
public int total;
public WorldTemplatePaginatedList() {
}
public WorldTemplatePaginatedList(int pSize) {
this.templates = Collections.emptyList();
this.page = 0;
this.size = pSize;
this.total = -1;
}
public boolean isLastPage() {
return this.page * this.size >= this.total && this.page > 0 && this.total > 0 && this.size > 0;
}
public static WorldTemplatePaginatedList parse(String pJson) {
WorldTemplatePaginatedList worldtemplatepaginatedlist = new WorldTemplatePaginatedList();
worldtemplatepaginatedlist.templates = Lists.newArrayList();
try {
JsonParser jsonparser = new JsonParser();
JsonObject jsonobject = jsonparser.parse(pJson).getAsJsonObject();
if (jsonobject.get("templates").isJsonArray()) {
Iterator<JsonElement> iterator = jsonobject.get("templates").getAsJsonArray().iterator();
while(iterator.hasNext()) {
worldtemplatepaginatedlist.templates.add(WorldTemplate.parse(iterator.next().getAsJsonObject()));
}
}
worldtemplatepaginatedlist.page = JsonUtils.getIntOr("page", jsonobject, 0);
worldtemplatepaginatedlist.size = JsonUtils.getIntOr("size", jsonobject, 0);
worldtemplatepaginatedlist.total = JsonUtils.getIntOr("total", jsonobject, 0);
} catch (Exception exception) {
LOGGER.error("Could not parse WorldTemplatePaginatedList: {}", (Object)exception.getMessage());
}
return worldtemplatepaginatedlist;
}
}
@@ -0,0 +1,9 @@
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
@OnlyIn(Dist.CLIENT)
package com.mojang.realmsclient.dto;
import javax.annotation.ParametersAreNonnullByDefault;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@@ -0,0 +1,18 @@
package com.mojang.realmsclient.exception;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class RealmsDefaultUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
private final Logger logger;
public RealmsDefaultUncaughtExceptionHandler(Logger pLogger) {
this.logger = pLogger;
}
public void uncaughtException(Thread pThread, Throwable pThrowable) {
this.logger.error("Caught previously unhandled exception", pThrowable);
}
}
@@ -0,0 +1,11 @@
package com.mojang.realmsclient.exception;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class RealmsHttpException extends RuntimeException {
public RealmsHttpException(String pMessage, Exception pCause) {
super(pMessage, pCause);
}
}
@@ -0,0 +1,44 @@
package com.mojang.realmsclient.exception;
import com.mojang.realmsclient.client.RealmsError;
import java.util.Locale;
import javax.annotation.Nullable;
import net.minecraft.client.resources.language.I18n;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class RealmsServiceException extends Exception {
public final int httpResultCode;
public final String rawResponse;
@Nullable
public final RealmsError realmsError;
public RealmsServiceException(int pHttpResultCode, String pHttpResponseContent, RealmsError pRealmsError) {
super(pHttpResponseContent);
this.httpResultCode = pHttpResultCode;
this.rawResponse = pHttpResponseContent;
this.realmsError = pRealmsError;
}
public RealmsServiceException(int pHttpResultCode, String pRawResponse) {
super(pRawResponse);
this.httpResultCode = pHttpResultCode;
this.rawResponse = pRawResponse;
this.realmsError = null;
}
public String getMessage() {
if (this.realmsError != null) {
String s = "mco.errorMessage." + this.realmsError.getErrorCode();
String s1 = I18n.exists(s) ? I18n.get(s) : this.realmsError.getErrorMessage();
return String.format(Locale.ROOT, "Realms service error (%d/%d) %s", this.httpResultCode, this.realmsError.getErrorCode(), s1);
} else {
return String.format(Locale.ROOT, "Realms service error (%d) %s", this.httpResultCode, this.rawResponse);
}
}
public int realmsErrorCodeOrDefault(int pDefaultErrorCode) {
return this.realmsError != null ? this.realmsError.getErrorCode() : pDefaultErrorCode;
}
}
@@ -0,0 +1,20 @@
package com.mojang.realmsclient.exception;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class RetryCallException extends RealmsServiceException {
public static final int DEFAULT_DELAY = 5;
public final int delaySeconds;
public RetryCallException(int pRetryAfter, int pHttpResultCode) {
super(pHttpResultCode, "Retry operation");
if (pRetryAfter >= 0 && pRetryAfter <= 120) {
this.delaySeconds = pRetryAfter;
} else {
this.delaySeconds = 5;
}
}
}
@@ -0,0 +1,11 @@
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
@FieldsAreNonnullByDefault
@OnlyIn(Dist.CLIENT)
package com.mojang.realmsclient.exception;
import javax.annotation.ParametersAreNonnullByDefault;
import net.minecraft.FieldsAreNonnullByDefault;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@@ -0,0 +1,14 @@
package com.mojang.realmsclient.gui;
import net.minecraft.network.chat.Component;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public interface ErrorCallback {
void error(Component pError);
default void error(String pError) {
this.error(Component.literal(pError));
}
}
@@ -0,0 +1,39 @@
package com.mojang.realmsclient.gui;
import com.mojang.realmsclient.client.RealmsClient;
import com.mojang.realmsclient.dto.RealmsNews;
import com.mojang.realmsclient.dto.RealmsNotification;
import com.mojang.realmsclient.dto.RealmsServer;
import com.mojang.realmsclient.dto.RealmsServerPlayerLists;
import com.mojang.realmsclient.gui.task.DataFetcher;
import com.mojang.realmsclient.gui.task.RepeatedDelayStrategy;
import com.mojang.realmsclient.util.RealmsPersistence;
import java.time.Duration;
import java.util.List;
import java.util.concurrent.TimeUnit;
import net.minecraft.Util;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class RealmsDataFetcher {
public final DataFetcher dataFetcher = new DataFetcher(Util.ioPool(), TimeUnit.MILLISECONDS, Util.timeSource);
public final DataFetcher.Task<List<RealmsNotification>> notificationsTask;
public final DataFetcher.Task<List<RealmsServer>> serverListUpdateTask;
public final DataFetcher.Task<RealmsServerPlayerLists> liveStatsTask;
public final DataFetcher.Task<Integer> pendingInvitesTask;
public final DataFetcher.Task<Boolean> trialAvailabilityTask;
public final DataFetcher.Task<RealmsNews> newsTask;
public final RealmsNewsManager newsManager = new RealmsNewsManager(new RealmsPersistence());
public RealmsDataFetcher(RealmsClient pRealmsClient) {
this.serverListUpdateTask = this.dataFetcher.createTask("server list", () -> {
return pRealmsClient.listWorlds().servers;
}, Duration.ofSeconds(60L), RepeatedDelayStrategy.CONSTANT);
this.liveStatsTask = this.dataFetcher.createTask("live stats", pRealmsClient::getLiveStats, Duration.ofSeconds(10L), RepeatedDelayStrategy.CONSTANT);
this.pendingInvitesTask = this.dataFetcher.createTask("pending invite count", pRealmsClient::pendingInvitesCount, Duration.ofSeconds(10L), RepeatedDelayStrategy.exponentialBackoff(360));
this.trialAvailabilityTask = this.dataFetcher.createTask("trial availablity", pRealmsClient::trialAvailable, Duration.ofSeconds(60L), RepeatedDelayStrategy.exponentialBackoff(60));
this.newsTask = this.dataFetcher.createTask("unread news", pRealmsClient::getNews, Duration.ofMinutes(5L), RepeatedDelayStrategy.CONSTANT);
this.notificationsTask = this.dataFetcher.createTask("notifications", pRealmsClient::getNotifications, Duration.ofMinutes(5L), RepeatedDelayStrategy.CONSTANT);
}
}
@@ -0,0 +1,48 @@
package com.mojang.realmsclient.gui;
import com.mojang.realmsclient.dto.RealmsNews;
import com.mojang.realmsclient.util.RealmsPersistence;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class RealmsNewsManager {
private final RealmsPersistence newsLocalStorage;
private boolean hasUnreadNews;
private String newsLink;
public RealmsNewsManager(RealmsPersistence pNewsLocalStorage) {
this.newsLocalStorage = pNewsLocalStorage;
RealmsPersistence.RealmsPersistenceData realmspersistence$realmspersistencedata = pNewsLocalStorage.read();
this.hasUnreadNews = realmspersistence$realmspersistencedata.hasUnreadNews;
this.newsLink = realmspersistence$realmspersistencedata.newsLink;
}
public boolean hasUnreadNews() {
return this.hasUnreadNews;
}
public String newsLink() {
return this.newsLink;
}
public void updateUnreadNews(RealmsNews pRealmsNews) {
RealmsPersistence.RealmsPersistenceData realmspersistence$realmspersistencedata = this.updateNewsStorage(pRealmsNews);
this.hasUnreadNews = realmspersistence$realmspersistencedata.hasUnreadNews;
this.newsLink = realmspersistence$realmspersistencedata.newsLink;
}
private RealmsPersistence.RealmsPersistenceData updateNewsStorage(RealmsNews pRealmsNews) {
RealmsPersistence.RealmsPersistenceData realmspersistence$realmspersistencedata = new RealmsPersistence.RealmsPersistenceData();
realmspersistence$realmspersistencedata.newsLink = pRealmsNews.newsLink;
RealmsPersistence.RealmsPersistenceData realmspersistence$realmspersistencedata1 = this.newsLocalStorage.read();
boolean flag = realmspersistence$realmspersistencedata.newsLink == null || realmspersistence$realmspersistencedata.newsLink.equals(realmspersistence$realmspersistencedata1.newsLink);
if (flag) {
return realmspersistence$realmspersistencedata1;
} else {
realmspersistence$realmspersistencedata.hasUnreadNews = true;
this.newsLocalStorage.save(realmspersistence$realmspersistencedata);
return realmspersistence$realmspersistencedata;
}
}
}
@@ -0,0 +1,40 @@
package com.mojang.realmsclient.gui;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.mojang.realmsclient.dto.RealmsServer;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import net.minecraft.client.Minecraft;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class RealmsServerList {
private final Minecraft minecraft;
private final Set<RealmsServer> removedServers = Sets.newHashSet();
private List<RealmsServer> servers = Lists.newArrayList();
public RealmsServerList(Minecraft pMinecraft) {
this.minecraft = pMinecraft;
}
public List<RealmsServer> updateServersList(List<RealmsServer> pServers) {
List<RealmsServer> list = new ArrayList<>(pServers);
list.sort(new RealmsServer.McoServerComparator(this.minecraft.getUser().getName()));
boolean flag = list.removeAll(this.removedServers);
if (!flag) {
this.removedServers.clear();
}
this.servers = list;
return List.copyOf(this.servers);
}
public synchronized List<RealmsServer> removeItem(RealmsServer pServer) {
this.servers.remove(pServer);
this.removedServers.add(pServer);
return List.copyOf(this.servers);
}
}
@@ -0,0 +1,216 @@
package com.mojang.realmsclient.gui;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.datafixers.util.Pair;
import com.mojang.realmsclient.dto.RealmsServer;
import com.mojang.realmsclient.dto.RealmsWorldOptions;
import com.mojang.realmsclient.util.RealmsTextureManager;
import java.util.function.Consumer;
import java.util.function.Supplier;
import javax.annotation.Nullable;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.Button;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class RealmsWorldSlotButton extends Button {
public static final ResourceLocation SLOT_FRAME_LOCATION = new ResourceLocation("realms", "textures/gui/realms/slot_frame.png");
public static final ResourceLocation EMPTY_SLOT_LOCATION = new ResourceLocation("realms", "textures/gui/realms/empty_frame.png");
public static final ResourceLocation CHECK_MARK_LOCATION = new ResourceLocation("minecraft", "textures/gui/checkmark.png");
public static final ResourceLocation DEFAULT_WORLD_SLOT_1 = new ResourceLocation("minecraft", "textures/gui/title/background/panorama_0.png");
public static final ResourceLocation DEFAULT_WORLD_SLOT_2 = new ResourceLocation("minecraft", "textures/gui/title/background/panorama_2.png");
public static final ResourceLocation DEFAULT_WORLD_SLOT_3 = new ResourceLocation("minecraft", "textures/gui/title/background/panorama_3.png");
private static final Component SLOT_ACTIVE_TOOLTIP = Component.translatable("mco.configure.world.slot.tooltip.active");
private static final Component SWITCH_TO_MINIGAME_SLOT_TOOLTIP = Component.translatable("mco.configure.world.slot.tooltip.minigame");
private static final Component SWITCH_TO_WORLD_SLOT_TOOLTIP = Component.translatable("mco.configure.world.slot.tooltip");
private static final Component MINIGAME = Component.translatable("mco.worldSlot.minigame");
private final Supplier<RealmsServer> serverDataProvider;
private final Consumer<Component> toolTipSetter;
private final int slotIndex;
@Nullable
private RealmsWorldSlotButton.State state;
public RealmsWorldSlotButton(int pX, int pY, int pWidth, int pHeight, Supplier<RealmsServer> pServerDataProvider, Consumer<Component> pToolTipSetter, int pSlotIndex, Button.OnPress pOnPress) {
super(pX, pY, pWidth, pHeight, CommonComponents.EMPTY, pOnPress, DEFAULT_NARRATION);
this.serverDataProvider = pServerDataProvider;
this.slotIndex = pSlotIndex;
this.toolTipSetter = pToolTipSetter;
}
@Nullable
public RealmsWorldSlotButton.State getState() {
return this.state;
}
public void tick() {
RealmsServer realmsserver = this.serverDataProvider.get();
if (realmsserver != null) {
RealmsWorldOptions realmsworldoptions = realmsserver.slots.get(this.slotIndex);
boolean flag2 = this.slotIndex == 4;
boolean flag;
String s;
long i;
String s1;
boolean flag1;
if (flag2) {
flag = realmsserver.worldType == RealmsServer.WorldType.MINIGAME;
s = MINIGAME.getString();
i = (long)realmsserver.minigameId;
s1 = realmsserver.minigameImage;
flag1 = realmsserver.minigameId == -1;
} else {
flag = realmsserver.activeSlot == this.slotIndex && realmsserver.worldType != RealmsServer.WorldType.MINIGAME;
s = realmsworldoptions.getSlotName(this.slotIndex);
i = realmsworldoptions.templateId;
s1 = realmsworldoptions.templateImage;
flag1 = realmsworldoptions.empty;
}
RealmsWorldSlotButton.Action realmsworldslotbutton$action = getAction(realmsserver, flag, flag2);
Pair<Component, Component> pair = this.getTooltipAndNarration(realmsserver, s, flag1, flag2, realmsworldslotbutton$action);
this.state = new RealmsWorldSlotButton.State(flag, s, i, s1, flag1, flag2, realmsworldslotbutton$action, pair.getFirst());
this.setMessage(pair.getSecond());
}
}
private static RealmsWorldSlotButton.Action getAction(RealmsServer pRealmsServer, boolean p_87961_, boolean p_87962_) {
if (p_87961_) {
if (!pRealmsServer.expired && pRealmsServer.state != RealmsServer.State.UNINITIALIZED) {
return RealmsWorldSlotButton.Action.JOIN;
}
} else {
if (!p_87962_) {
return RealmsWorldSlotButton.Action.SWITCH_SLOT;
}
if (!pRealmsServer.expired) {
return RealmsWorldSlotButton.Action.SWITCH_SLOT;
}
}
return RealmsWorldSlotButton.Action.NOTHING;
}
private Pair<Component, Component> getTooltipAndNarration(RealmsServer pRealmsServer, String p_87955_, boolean p_87956_, boolean p_87957_, RealmsWorldSlotButton.Action p_87958_) {
if (p_87958_ == RealmsWorldSlotButton.Action.NOTHING) {
return Pair.of((Component)null, Component.literal(p_87955_));
} else {
Component component;
if (p_87957_) {
if (p_87956_) {
component = CommonComponents.EMPTY;
} else {
component = CommonComponents.space().append(p_87955_).append(CommonComponents.SPACE).append(pRealmsServer.minigameName);
}
} else {
component = CommonComponents.space().append(p_87955_);
}
Component component1;
if (p_87958_ == RealmsWorldSlotButton.Action.JOIN) {
component1 = SLOT_ACTIVE_TOOLTIP;
} else {
component1 = p_87957_ ? SWITCH_TO_MINIGAME_SLOT_TOOLTIP : SWITCH_TO_WORLD_SLOT_TOOLTIP;
}
Component component2 = component1.copy().append(component);
return Pair.of(component1, component2);
}
}
public void renderWidget(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) {
if (this.state != null) {
this.drawSlotFrame(pGuiGraphics, this.getX(), this.getY(), pMouseX, pMouseY, this.state.isCurrentlyActiveSlot, this.state.slotName, this.slotIndex, this.state.imageId, this.state.image, this.state.empty, this.state.minigame, this.state.action, this.state.actionPrompt);
}
}
private void drawSlotFrame(GuiGraphics pGuiGraphics, int pX, int pY, int pMouseX, int pMouseY, boolean pIsSelected, String pText, int p_283521_, long p_281546_, @Nullable String p_283361_, boolean p_283516_, boolean p_281611_, RealmsWorldSlotButton.Action p_281804_, @Nullable Component pTooltip) {
boolean flag = this.isHoveredOrFocused();
if (this.isMouseOver((double)pMouseX, (double)pMouseY) && pTooltip != null) {
this.toolTipSetter.accept(pTooltip);
}
Minecraft minecraft = Minecraft.getInstance();
ResourceLocation resourcelocation;
if (p_281611_) {
resourcelocation = RealmsTextureManager.worldTemplate(String.valueOf(p_281546_), p_283361_);
} else if (p_283516_) {
resourcelocation = EMPTY_SLOT_LOCATION;
} else if (p_283361_ != null && p_281546_ != -1L) {
resourcelocation = RealmsTextureManager.worldTemplate(String.valueOf(p_281546_), p_283361_);
} else if (p_283521_ == 1) {
resourcelocation = DEFAULT_WORLD_SLOT_1;
} else if (p_283521_ == 2) {
resourcelocation = DEFAULT_WORLD_SLOT_2;
} else if (p_283521_ == 3) {
resourcelocation = DEFAULT_WORLD_SLOT_3;
} else {
resourcelocation = EMPTY_SLOT_LOCATION;
}
if (pIsSelected) {
pGuiGraphics.setColor(0.56F, 0.56F, 0.56F, 1.0F);
}
pGuiGraphics.blit(resourcelocation, pX + 3, pY + 3, 0.0F, 0.0F, 74, 74, 74, 74);
boolean flag1 = flag && p_281804_ != RealmsWorldSlotButton.Action.NOTHING;
if (flag1) {
pGuiGraphics.setColor(1.0F, 1.0F, 1.0F, 1.0F);
} else if (pIsSelected) {
pGuiGraphics.setColor(0.8F, 0.8F, 0.8F, 1.0F);
} else {
pGuiGraphics.setColor(0.56F, 0.56F, 0.56F, 1.0F);
}
pGuiGraphics.blit(SLOT_FRAME_LOCATION, pX, pY, 0.0F, 0.0F, 80, 80, 80, 80);
pGuiGraphics.setColor(1.0F, 1.0F, 1.0F, 1.0F);
if (pIsSelected) {
this.renderCheckMark(pGuiGraphics, pX, pY);
}
pGuiGraphics.drawCenteredString(minecraft.font, pText, pX + 40, pY + 66, 16777215);
}
private void renderCheckMark(GuiGraphics pGuiGraphics, int pX, int pY) {
RenderSystem.enableBlend();
pGuiGraphics.blit(CHECK_MARK_LOCATION, pX + 67, pY + 4, 0.0F, 0.0F, 9, 8, 9, 8);
RenderSystem.disableBlend();
}
@OnlyIn(Dist.CLIENT)
public static enum Action {
NOTHING,
SWITCH_SLOT,
JOIN;
}
@OnlyIn(Dist.CLIENT)
public static class State {
final boolean isCurrentlyActiveSlot;
final String slotName;
final long imageId;
@Nullable
final String image;
public final boolean empty;
public final boolean minigame;
public final RealmsWorldSlotButton.Action action;
@Nullable
final Component actionPrompt;
State(boolean pIsCurrentlyActiveSlot, String pSlotName, long pImageId, @Nullable String pImage, boolean pEmpty, boolean pMinigame, RealmsWorldSlotButton.Action pAction, @Nullable Component pActionPrompt) {
this.isCurrentlyActiveSlot = pIsCurrentlyActiveSlot;
this.slotName = pSlotName;
this.imageId = pImageId;
this.image = pImage;
this.empty = pEmpty;
this.minigame = pMinigame;
this.action = pAction;
this.actionPrompt = pActionPrompt;
}
}
}
@@ -0,0 +1,71 @@
package com.mojang.realmsclient.gui;
import java.util.List;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.ObjectSelectionList;
import net.minecraft.realms.RealmsObjectSelectionList;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public abstract class RowButton {
public final int width;
public final int height;
public final int xOffset;
public final int yOffset;
public RowButton(int pWidth, int pHeight, int pXOffset, int pYOffset) {
this.width = pWidth;
this.height = pHeight;
this.xOffset = pXOffset;
this.yOffset = pYOffset;
}
public void drawForRowAt(GuiGraphics pGuiGraphics, int pX, int pY, int pMouseX, int pMouseY) {
int i = pX + this.xOffset;
int j = pY + this.yOffset;
boolean flag = pMouseX >= i && pMouseX <= i + this.width && pMouseY >= j && pMouseY <= j + this.height;
this.draw(pGuiGraphics, i, j, flag);
}
protected abstract void draw(GuiGraphics pGuiGraphics, int pX, int pY, boolean pShowTooltip);
public int getRight() {
return this.xOffset + this.width;
}
public int getBottom() {
return this.yOffset + this.height;
}
public abstract void onClick(int p_88017_);
public static void drawButtonsInRow(GuiGraphics pGuiGraphics, List<RowButton> pButtons, RealmsObjectSelectionList<?> pPendingInvitations, int pX, int pY, int pMouseX, int pMouseY) {
for(RowButton rowbutton : pButtons) {
if (pPendingInvitations.getRowWidth() > rowbutton.getRight()) {
rowbutton.drawForRowAt(pGuiGraphics, pX, pY, pMouseX, pMouseY);
}
}
}
public static void rowButtonMouseClicked(RealmsObjectSelectionList<?> p_88037_, ObjectSelectionList.Entry<?> p_88038_, List<RowButton> p_88039_, int p_88040_, double p_88041_, double p_88042_) {
if (p_88040_ == 0) {
int i = p_88037_.children().indexOf(p_88038_);
if (i > -1) {
p_88037_.selectItem(i);
int j = p_88037_.getRowLeft();
int k = p_88037_.getRowTop(i);
int l = (int)(p_88041_ - (double)j);
int i1 = (int)(p_88042_ - (double)k);
for(RowButton rowbutton : p_88039_) {
if (l >= rowbutton.xOffset && l <= rowbutton.getRight() && i1 >= rowbutton.yOffset && i1 <= rowbutton.getBottom()) {
rowbutton.onClick(i);
}
}
}
}
}
}
@@ -0,0 +1,11 @@
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
@FieldsAreNonnullByDefault
@OnlyIn(Dist.CLIENT)
package com.mojang.realmsclient.gui;
import javax.annotation.ParametersAreNonnullByDefault;
import net.minecraft.FieldsAreNonnullByDefault;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@@ -0,0 +1,166 @@
package com.mojang.realmsclient.gui.screens;
import com.mojang.realmsclient.dto.Backup;
import java.util.Locale;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.ObjectSelectionList;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.realms.RealmsScreen;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class RealmsBackupInfoScreen extends RealmsScreen {
private static final Component UNKNOWN = Component.translatable("mco.backup.unknown");
private final Screen lastScreen;
final Backup backup;
private RealmsBackupInfoScreen.BackupInfoList backupInfoList;
public RealmsBackupInfoScreen(Screen pLastScreen, Backup pBackup) {
super(Component.translatable("mco.backup.info.title"));
this.lastScreen = pLastScreen;
this.backup = pBackup;
}
public void tick() {
}
public void init() {
this.addRenderableWidget(Button.builder(CommonComponents.GUI_BACK, (p_280689_) -> {
this.minecraft.setScreen(this.lastScreen);
}).bounds(this.width / 2 - 100, this.height / 4 + 120 + 24, 200, 20).build());
this.backupInfoList = new RealmsBackupInfoScreen.BackupInfoList(this.minecraft);
this.addWidget(this.backupInfoList);
this.magicalSpecialHackyFocus(this.backupInfoList);
}
public boolean keyPressed(int pKeyCode, int pScanCode, int pModifiers) {
if (pKeyCode == 256) {
this.minecraft.setScreen(this.lastScreen);
return true;
} else {
return super.keyPressed(pKeyCode, pScanCode, pModifiers);
}
}
public void render(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) {
this.renderBackground(pGuiGraphics);
this.backupInfoList.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
pGuiGraphics.drawCenteredString(this.font, this.title, this.width / 2, 10, 16777215);
super.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
}
Component checkForSpecificMetadata(String pKey, String pValue) {
String s = pKey.toLowerCase(Locale.ROOT);
if (s.contains("game") && s.contains("mode")) {
return this.gameModeMetadata(pValue);
} else {
return (Component)(s.contains("game") && s.contains("difficulty") ? this.gameDifficultyMetadata(pValue) : Component.literal(pValue));
}
}
private Component gameDifficultyMetadata(String pValue) {
try {
return RealmsSlotOptionsScreen.DIFFICULTIES.get(Integer.parseInt(pValue)).getDisplayName();
} catch (Exception exception) {
return UNKNOWN;
}
}
private Component gameModeMetadata(String pValue) {
try {
return RealmsSlotOptionsScreen.GAME_MODES.get(Integer.parseInt(pValue)).getShortDisplayName();
} catch (Exception exception) {
return UNKNOWN;
}
}
@OnlyIn(Dist.CLIENT)
class BackupInfoList extends ObjectSelectionList<RealmsBackupInfoScreen.BackupInfoListEntry> {
public BackupInfoList(Minecraft pMinecraft) {
super(pMinecraft, RealmsBackupInfoScreen.this.width, RealmsBackupInfoScreen.this.height, 32, RealmsBackupInfoScreen.this.height - 64, 36);
this.setRenderSelection(false);
if (RealmsBackupInfoScreen.this.backup.changeList != null) {
RealmsBackupInfoScreen.this.backup.changeList.forEach((p_88084_, p_88085_) -> {
this.addEntry(RealmsBackupInfoScreen.this.new BackupInfoListEntry(p_88084_, p_88085_));
});
}
}
}
@OnlyIn(Dist.CLIENT)
class BackupInfoListEntry extends ObjectSelectionList.Entry<RealmsBackupInfoScreen.BackupInfoListEntry> {
private static final Component TEMPLATE_NAME = Component.translatable("mco.backup.entry.templateName");
private static final Component GAME_DIFFICULTY = Component.translatable("mco.backup.entry.gameDifficulty");
private static final Component NAME = Component.translatable("mco.backup.entry.name");
private static final Component GAME_SERVER_VERSION = Component.translatable("mco.backup.entry.gameServerVersion");
private static final Component UPLOADED = Component.translatable("mco.backup.entry.uploaded");
private static final Component ENABLED_PACK = Component.translatable("mco.backup.entry.enabledPack");
private static final Component DESCRIPTION = Component.translatable("mco.backup.entry.description");
private static final Component GAME_MODE = Component.translatable("mco.backup.entry.gameMode");
private static final Component SEED = Component.translatable("mco.backup.entry.seed");
private static final Component WORLD_TYPE = Component.translatable("mco.backup.entry.worldType");
private static final Component UNDEFINED = Component.translatable("mco.backup.entry.undefined");
private final String key;
private final String value;
public BackupInfoListEntry(String pKey, String pValue) {
this.key = pKey;
this.value = pValue;
}
public void render(GuiGraphics pGuiGraphics, int pIndex, int pTop, int pLeft, int pWidth, int pHeight, int pMouseX, int pMouseY, boolean p_281916_, float pPartialTick) {
pGuiGraphics.drawString(RealmsBackupInfoScreen.this.font, this.translateKey(this.key), pLeft, pTop, 10526880);
pGuiGraphics.drawString(RealmsBackupInfoScreen.this.font, RealmsBackupInfoScreen.this.checkForSpecificMetadata(this.key, this.value), pLeft, pTop + 12, 16777215);
}
private Component translateKey(String pKey) {
Component component;
switch (pKey) {
case "template_name":
component = TEMPLATE_NAME;
break;
case "game_difficulty":
component = GAME_DIFFICULTY;
break;
case "name":
component = NAME;
break;
case "game_server_version":
component = GAME_SERVER_VERSION;
break;
case "uploaded":
component = UPLOADED;
break;
case "enabled_pack":
component = ENABLED_PACK;
break;
case "description":
component = DESCRIPTION;
break;
case "game_mode":
component = GAME_MODE;
break;
case "seed":
component = SEED;
break;
case "world_type":
component = WORLD_TYPE;
break;
default:
component = UNDEFINED;
}
return component;
}
public Component getNarration() {
return Component.translatable("narrator.select", this.key + " " + this.value);
}
}
}
@@ -0,0 +1,339 @@
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.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 javax.annotation.Nullable;
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.ImageButton;
import net.minecraft.client.gui.components.ObjectSelectionList;
import net.minecraft.client.gui.components.Tooltip;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.realms.RealmsObjectSelectionList;
import net.minecraft.realms.RealmsScreen;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class RealmsBackupScreen extends RealmsScreen {
static final Logger LOGGER = LogUtils.getLogger();
static final ResourceLocation PLUS_ICON_LOCATION = new ResourceLocation("realms", "textures/gui/realms/plus_icon.png");
static final ResourceLocation RESTORE_ICON_LOCATION = new ResourceLocation("realms", "textures/gui/realms/restore_icon.png");
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 TITLE = Component.translatable("mco.configure.world.backup");
private static final Component NO_BACKUPS_LABEL = Component.translatable("mco.backup.nobackups");
private final RealmsConfigureWorldScreen lastScreen;
List<Backup> backups = Collections.emptyList();
RealmsBackupScreen.BackupObjectSelectionList backupObjectSelectionList;
int selectedBackup = -1;
private final int slotId;
private Button downloadButton;
private Button restoreButton;
private Button changesButton;
Boolean noBackups = false;
final RealmsServer serverData;
private static final String UPLOADED_KEY = "uploaded";
public RealmsBackupScreen(RealmsConfigureWorldScreen pLastScreen, RealmsServer pServerData, int pSlotId) {
super(Component.translatable("mco.configure.world.backup"));
this.lastScreen = pLastScreen;
this.serverData = pServerData;
this.slotId = pSlotId;
}
public void init() {
this.backupObjectSelectionList = new RealmsBackupScreen.BackupObjectSelectionList();
(new Thread("Realms-fetch-backups") {
public void run() {
RealmsClient realmsclient = RealmsClient.create();
try {
List<Backup> list = realmsclient.backupsFor(RealmsBackupScreen.this.serverData.id).backups;
RealmsBackupScreen.this.minecraft.execute(() -> {
RealmsBackupScreen.this.backups = list;
RealmsBackupScreen.this.noBackups = RealmsBackupScreen.this.backups.isEmpty();
RealmsBackupScreen.this.backupObjectSelectionList.clear();
for(Backup backup : RealmsBackupScreen.this.backups) {
RealmsBackupScreen.this.backupObjectSelectionList.addEntry(backup);
}
});
} catch (RealmsServiceException realmsserviceexception) {
RealmsBackupScreen.LOGGER.error("Couldn't request backups", (Throwable)realmsserviceexception);
}
}
}).start();
this.downloadButton = this.addRenderableWidget(Button.builder(Component.translatable("mco.backup.button.download"), (p_88185_) -> {
this.downloadClicked();
}).bounds(this.width - 135, row(1), 120, 20).build());
this.restoreButton = this.addRenderableWidget(Button.builder(Component.translatable("mco.backup.button.restore"), (p_88179_) -> {
this.restoreClicked(this.selectedBackup);
}).bounds(this.width - 135, row(3), 120, 20).build());
this.changesButton = this.addRenderableWidget(Button.builder(Component.translatable("mco.backup.changes.tooltip"), (p_280692_) -> {
this.minecraft.setScreen(new RealmsBackupInfoScreen(this, this.backups.get(this.selectedBackup)));
this.selectedBackup = -1;
}).bounds(this.width - 135, row(5), 120, 20).build());
this.addRenderableWidget(Button.builder(CommonComponents.GUI_BACK, (p_280691_) -> {
this.minecraft.setScreen(this.lastScreen);
}).bounds(this.width - 100, this.height - 35, 85, 20).build());
this.addWidget(this.backupObjectSelectionList);
this.magicalSpecialHackyFocus(this.backupObjectSelectionList);
this.updateButtonStates();
}
void updateButtonStates() {
this.restoreButton.visible = this.shouldRestoreButtonBeVisible();
this.changesButton.visible = this.shouldChangesButtonBeVisible();
}
private boolean shouldChangesButtonBeVisible() {
if (this.selectedBackup == -1) {
return false;
} else {
return !(this.backups.get(this.selectedBackup)).changeList.isEmpty();
}
}
private boolean shouldRestoreButtonBeVisible() {
if (this.selectedBackup == -1) {
return false;
} else {
return !this.serverData.expired;
}
}
public boolean keyPressed(int pKeyCode, int pScanCode, int pModifiers) {
if (pKeyCode == 256) {
this.minecraft.setScreen(this.lastScreen);
return true;
} else {
return super.keyPressed(pKeyCode, pScanCode, pModifiers);
}
}
void restoreClicked(int p_88167_) {
if (p_88167_ >= 0 && p_88167_ < this.backups.size() && !this.serverData.expired) {
this.selectedBackup = p_88167_;
Date date = (this.backups.get(p_88167_)).lastModifiedDate;
String s = DateFormat.getDateTimeInstance(3, 3).format(date);
Component component = RealmsUtil.convertToAgePresentationFromInstant(date);
Component component1 = Component.translatable("mco.configure.world.restore.question.line1", s, component);
Component component2 = Component.translatable("mco.configure.world.restore.question.line2");
this.minecraft.setScreen(new RealmsLongConfirmationScreen((p_280693_) -> {
if (p_280693_) {
this.restore();
} else {
this.selectedBackup = -1;
this.minecraft.setScreen(this);
}
}, RealmsLongConfirmationScreen.Type.WARNING, component1, component2, true));
}
}
private void downloadClicked() {
Component component = Component.translatable("mco.configure.world.restore.download.question.line1");
Component component1 = Component.translatable("mco.configure.world.restore.download.question.line2");
this.minecraft.setScreen(new RealmsLongConfirmationScreen((p_280690_) -> {
if (p_280690_) {
this.downloadWorldData();
} else {
this.minecraft.setScreen(this);
}
}, RealmsLongConfirmationScreen.Type.INFO, component, component1, true));
}
private void downloadWorldData() {
this.minecraft.setScreen(new RealmsLongRunningMcoTaskScreen(this.lastScreen.getNewScreen(), new DownloadTask(this.serverData.id, this.slotId, this.serverData.name + " (" + this.serverData.slots.get(this.serverData.activeSlot).getSlotName(this.serverData.activeSlot) + ")", this)));
}
private void restore() {
Backup backup = this.backups.get(this.selectedBackup);
this.selectedBackup = -1;
this.minecraft.setScreen(new RealmsLongRunningMcoTaskScreen(this.lastScreen.getNewScreen(), new RestoreTask(backup, this.serverData.id, this.lastScreen)));
}
public void render(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) {
this.renderBackground(pGuiGraphics);
this.backupObjectSelectionList.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
pGuiGraphics.drawCenteredString(this.font, this.title, this.width / 2, 12, 16777215);
pGuiGraphics.drawString(this.font, TITLE, (this.width - 150) / 2 - 90, 20, 10526880, false);
if (this.noBackups) {
pGuiGraphics.drawString(this.font, NO_BACKUPS_LABEL, 20, this.height / 2 - 10, 16777215, false);
}
this.downloadButton.active = !this.noBackups;
super.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
}
@OnlyIn(Dist.CLIENT)
class BackupObjectSelectionList extends RealmsObjectSelectionList<RealmsBackupScreen.Entry> {
public BackupObjectSelectionList() {
super(RealmsBackupScreen.this.width - 150, RealmsBackupScreen.this.height, 32, RealmsBackupScreen.this.height - 15, 36);
}
public void addEntry(Backup pBackup) {
this.addEntry(RealmsBackupScreen.this.new Entry(pBackup));
}
public int getRowWidth() {
return (int)((double)this.width * 0.93D);
}
public int getMaxPosition() {
return this.getItemCount() * 36;
}
public void renderBackground(GuiGraphics pGuiGraphics) {
RealmsBackupScreen.this.renderBackground(pGuiGraphics);
}
public int getScrollbarPosition() {
return this.width - 5;
}
public void selectItem(int pIndex) {
super.selectItem(pIndex);
this.selectInviteListItem(pIndex);
}
public void selectInviteListItem(int pIndex) {
RealmsBackupScreen.this.selectedBackup = pIndex;
RealmsBackupScreen.this.updateButtonStates();
}
public void setSelected(@Nullable RealmsBackupScreen.Entry pSelected) {
super.setSelected(pSelected);
RealmsBackupScreen.this.selectedBackup = this.children().indexOf(pSelected);
RealmsBackupScreen.this.updateButtonStates();
}
}
@OnlyIn(Dist.CLIENT)
class Entry extends ObjectSelectionList.Entry<RealmsBackupScreen.Entry> {
private static final int Y_PADDING = 2;
private static final int X_PADDING = 7;
private final Backup backup;
private final List<AbstractWidget> children = new ArrayList<>();
@Nullable
private ImageButton restoreButton;
@Nullable
private ImageButton changesButton;
public Entry(Backup pBackup) {
this.backup = pBackup;
this.populateChangeList(pBackup);
if (!pBackup.changeList.isEmpty()) {
this.addChangesButton();
}
if (!RealmsBackupScreen.this.serverData.expired) {
this.addRestoreButton();
}
}
private void populateChangeList(Backup p_279365_) {
int i = RealmsBackupScreen.this.backups.indexOf(p_279365_);
if (i != RealmsBackupScreen.this.backups.size() - 1) {
Backup backup = RealmsBackupScreen.this.backups.get(i + 1);
for(String s : p_279365_.metadata.keySet()) {
if (!s.contains("uploaded") && backup.metadata.containsKey(s)) {
if (!p_279365_.metadata.get(s).equals(backup.metadata.get(s))) {
this.addToChangeList(s);
}
} else {
this.addToChangeList(s);
}
}
}
}
private void addToChangeList(String p_279195_) {
if (p_279195_.contains("uploaded")) {
String s = DateFormat.getDateTimeInstance(3, 3).format(this.backup.lastModifiedDate);
this.backup.changeList.put(p_279195_, s);
this.backup.setUploadedVersion(true);
} else {
this.backup.changeList.put(p_279195_, this.backup.metadata.get(p_279195_));
}
}
private void addChangesButton() {
int i = 9;
int j = 9;
int k = RealmsBackupScreen.this.backupObjectSelectionList.getRowRight() - 9 - 28;
int l = RealmsBackupScreen.this.backupObjectSelectionList.getRowTop(RealmsBackupScreen.this.backups.indexOf(this.backup)) + 2;
this.changesButton = new ImageButton(k, l, 9, 9, 0, 0, 9, RealmsBackupScreen.PLUS_ICON_LOCATION, 9, 18, (p_279278_) -> {
RealmsBackupScreen.this.minecraft.setScreen(new RealmsBackupInfoScreen(RealmsBackupScreen.this, this.backup));
});
this.changesButton.setTooltip(Tooltip.create(RealmsBackupScreen.HAS_CHANGES_TOOLTIP));
this.children.add(this.changesButton);
}
private void addRestoreButton() {
int i = 17;
int j = 10;
int k = RealmsBackupScreen.this.backupObjectSelectionList.getRowRight() - 17 - 7;
int l = RealmsBackupScreen.this.backupObjectSelectionList.getRowTop(RealmsBackupScreen.this.backups.indexOf(this.backup)) + 2;
this.restoreButton = new ImageButton(k, l, 17, 10, 0, 0, 10, RealmsBackupScreen.RESTORE_ICON_LOCATION, 17, 20, (p_279191_) -> {
RealmsBackupScreen.this.restoreClicked(RealmsBackupScreen.this.backups.indexOf(this.backup));
});
this.restoreButton.setTooltip(Tooltip.create(RealmsBackupScreen.RESTORE_TOOLTIP));
this.children.add(this.restoreButton);
}
public boolean mouseClicked(double pMouseX, double pMouseY, int pButton) {
if (this.restoreButton != null) {
this.restoreButton.mouseClicked(pMouseX, pMouseY, pButton);
}
if (this.changesButton != null) {
this.changesButton.mouseClicked(pMouseX, pMouseY, pButton);
}
return true;
}
public void render(GuiGraphics pGuiGraphics, int pIndex, int pTop, int pLeft, int pWidth, int pHeight, int pMouseX, int pMouseY, boolean p_283105_, float pPartialTick) {
int i = this.backup.isUploadedVersion() ? -8388737 : 16777215;
pGuiGraphics.drawString(RealmsBackupScreen.this.font, Component.translatable("mco.backup.entry", RealmsUtil.convertToAgePresentationFromInstant(this.backup.lastModifiedDate)), pLeft, pTop + 1, i, false);
pGuiGraphics.drawString(RealmsBackupScreen.this.font, this.getMediumDatePresentation(this.backup.lastModifiedDate), pLeft, pTop + 12, 5000268, false);
this.children.forEach((p_280700_) -> {
p_280700_.setY(pTop + 2);
p_280700_.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
});
}
private String getMediumDatePresentation(Date pDate) {
return DateFormat.getDateTimeInstance(3, 3).format(pDate);
}
public Component getNarration() {
return Component.translatable("narrator.select", this.backup.lastModifiedDate.toString());
}
}
}
@@ -0,0 +1,271 @@
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.RealmsWorldOptions;
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.task.OpenServerTask;
import com.mojang.realmsclient.util.task.SwitchSlotTask;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.screens.Screen;
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.ResourceLocation;
import net.minecraft.util.Mth;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class RealmsBrokenWorldScreen extends RealmsScreen {
private static final Logger LOGGER = LogUtils.getLogger();
private static final int DEFAULT_BUTTON_WIDTH = 80;
private final Screen lastScreen;
private final RealmsMainScreen mainScreen;
@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 int rightX;
private final List<Integer> slotsThatHasBeenDownloaded = Lists.newArrayList();
private int animTick;
public RealmsBrokenWorldScreen(Screen pLastScreen, RealmsMainScreen pMainScreen, long pServerId, boolean pIsMinigame) {
super(pIsMinigame ? Component.translatable("mco.brokenworld.minigame.title") : Component.translatable("mco.brokenworld.title"));
this.lastScreen = pLastScreen;
this.mainScreen = pMainScreen;
this.serverId = pServerId;
}
public void init() {
this.leftX = this.width / 2 - 150;
this.rightX = this.width / 2 + 190;
this.addRenderableWidget(Button.builder(CommonComponents.GUI_BACK, (p_88333_) -> {
this.backButtonClicked();
}).bounds(this.rightX - 80 + 8, row(13) - 5, 70, 20).build());
if (this.serverData == null) {
this.fetchServerData(this.serverId);
} else {
this.addButtons();
}
}
public Component getNarrationMessage() {
return ComponentUtils.formatList(Stream.concat(Stream.of(this.title), Stream.of(this.message)).collect(Collectors.toList()), CommonComponents.SPACE);
}
private void addButtons() {
for(Map.Entry<Integer, RealmsWorldOptions> entry : this.serverData.slots.entrySet()) {
int i = entry.getKey();
boolean flag = i != this.serverData.activeSlot || this.serverData.worldType == RealmsServer.WorldType.MINIGAME;
Button button;
if (flag) {
button = Button.builder(Component.translatable("mco.brokenworld.play"), (p_88347_) -> {
if ((this.serverData.slots.get(i)).empty) {
RealmsResetWorldScreen realmsresetworldscreen = new RealmsResetWorldScreen(this, this.serverData, Component.translatable("mco.configure.world.switch.slot"), Component.translatable("mco.configure.world.switch.slot.subtitle"), 10526880, CommonComponents.GUI_CANCEL, this::doSwitchOrReset, () -> {
this.minecraft.setScreen(this);
this.doSwitchOrReset();
});
realmsresetworldscreen.setSlot(i);
realmsresetworldscreen.setResetTitle(Component.translatable("mco.create.world.reset.title"));
this.minecraft.setScreen(realmsresetworldscreen);
} else {
this.minecraft.setScreen(new RealmsLongRunningMcoTaskScreen(this.lastScreen, new SwitchSlotTask(this.serverData.id, i, this::doSwitchOrReset)));
}
}).bounds(this.getFramePositionX(i), row(8), 80, 20).build();
} else {
button = Button.builder(Component.translatable("mco.brokenworld.download"), (p_287302_) -> {
Component component = Component.translatable("mco.configure.world.restore.download.question.line1");
Component component1 = Component.translatable("mco.configure.world.restore.download.question.line2");
this.minecraft.setScreen(new RealmsLongConfirmationScreen((p_280705_) -> {
if (p_280705_) {
this.downloadWorld(i);
} else {
this.minecraft.setScreen(this);
}
}, RealmsLongConfirmationScreen.Type.INFO, component, component1, true));
}).bounds(this.getFramePositionX(i), row(8), 80, 20).build();
}
if (this.slotsThatHasBeenDownloaded.contains(i)) {
button.active = false;
button.setMessage(Component.translatable("mco.brokenworld.downloaded"));
}
this.addRenderableWidget(button);
this.addRenderableWidget(Button.builder(Component.translatable("mco.brokenworld.reset"), (p_280707_) -> {
RealmsResetWorldScreen realmsresetworldscreen = new RealmsResetWorldScreen(this, this.serverData, this::doSwitchOrReset, () -> {
this.minecraft.setScreen(this);
this.doSwitchOrReset();
});
if (i != this.serverData.activeSlot || this.serverData.worldType == RealmsServer.WorldType.MINIGAME) {
realmsresetworldscreen.setSlot(i);
}
this.minecraft.setScreen(realmsresetworldscreen);
}).bounds(this.getFramePositionX(i), row(10), 80, 20).build());
}
}
public void tick() {
++this.animTick;
}
public void render(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) {
this.renderBackground(pGuiGraphics);
super.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
pGuiGraphics.drawCenteredString(this.font, this.title, this.width / 2, 17, 16777215);
for(int i = 0; i < this.message.length; ++i) {
pGuiGraphics.drawCenteredString(this.font, this.message[i], this.width / 2, row(-1) + 3 + i * 12, 10526880);
}
if (this.serverData != null) {
for(Map.Entry<Integer, RealmsWorldOptions> entry : this.serverData.slots.entrySet()) {
if ((entry.getValue()).templateImage != null && (entry.getValue()).templateId != -1L) {
this.drawSlotFrame(pGuiGraphics, this.getFramePositionX(entry.getKey()), row(1) + 5, pMouseX, pMouseY, this.serverData.activeSlot == entry.getKey() && !this.isMinigame(), entry.getValue().getSlotName(entry.getKey()), entry.getKey(), (entry.getValue()).templateId, (entry.getValue()).templateImage, (entry.getValue()).empty);
} else {
this.drawSlotFrame(pGuiGraphics, this.getFramePositionX(entry.getKey()), row(1) + 5, pMouseX, pMouseY, this.serverData.activeSlot == entry.getKey() && !this.isMinigame(), entry.getValue().getSlotName(entry.getKey()), entry.getKey(), -1L, (String)null, (entry.getValue()).empty);
}
}
}
}
private int getFramePositionX(int p_88302_) {
return this.leftX + (p_88302_ - 1) * 110;
}
public boolean keyPressed(int pKeyCode, int pScanCode, int pModifiers) {
if (pKeyCode == 256) {
this.backButtonClicked();
return true;
} else {
return super.keyPressed(pKeyCode, pScanCode, pModifiers);
}
}
private void backButtonClicked() {
this.minecraft.setScreen(this.lastScreen);
}
private void fetchServerData(long pServerId) {
(new Thread(() -> {
RealmsClient realmsclient = RealmsClient.create();
try {
this.serverData = realmsclient.getOwnWorld(pServerId);
this.addButtons();
} catch (RealmsServiceException realmsserviceexception) {
LOGGER.error("Couldn't get own world");
this.minecraft.setScreen(new RealmsGenericErrorScreen(Component.nullToEmpty(realmsserviceexception.getMessage()), this.lastScreen));
}
})).start();
}
public void doSwitchOrReset() {
(new Thread(() -> {
RealmsClient realmsclient = RealmsClient.create();
if (this.serverData.state == RealmsServer.State.CLOSED) {
this.minecraft.execute(() -> {
this.minecraft.setScreen(new RealmsLongRunningMcoTaskScreen(this, new OpenServerTask(this.serverData, this, this.mainScreen, true, this.minecraft)));
});
} else {
try {
RealmsServer realmsserver = realmsclient.getOwnWorld(this.serverId);
this.minecraft.execute(() -> {
this.mainScreen.newScreen().play(realmsserver, this);
});
} catch (RealmsServiceException realmsserviceexception) {
LOGGER.error("Couldn't get own world");
this.minecraft.execute(() -> {
this.minecraft.setScreen(this.lastScreen);
});
}
}
})).start();
}
private void downloadWorld(int pSlotIndex) {
RealmsClient realmsclient = RealmsClient.create();
try {
WorldDownload worlddownload = realmsclient.requestDownloadInfo(this.serverData.id, pSlotIndex);
RealmsDownloadLatestWorldScreen realmsdownloadlatestworldscreen = new RealmsDownloadLatestWorldScreen(this, worlddownload, this.serverData.getWorldName(pSlotIndex), (p_280702_) -> {
if (p_280702_) {
this.slotsThatHasBeenDownloaded.add(pSlotIndex);
this.clearWidgets();
this.addButtons();
} else {
this.minecraft.setScreen(this);
}
});
this.minecraft.setScreen(realmsdownloadlatestworldscreen);
} catch (RealmsServiceException realmsserviceexception) {
LOGGER.error("Couldn't download world data");
this.minecraft.setScreen(new RealmsGenericErrorScreen(realmsserviceexception, this));
}
}
private boolean isMinigame() {
return this.serverData != null && this.serverData.worldType == RealmsServer.WorldType.MINIGAME;
}
private void drawSlotFrame(GuiGraphics pGuiGraphics, int pX, int pY, int pMouseX, int pMouseY, boolean pIsActiveNonMinigame, String pText, int pSlotIndex, long p_283588_, @Nullable String p_282484_, boolean pHasTemplateImage) {
ResourceLocation resourcelocation;
if (pHasTemplateImage) {
resourcelocation = RealmsWorldSlotButton.EMPTY_SLOT_LOCATION;
} else if (p_282484_ != null && p_283588_ != -1L) {
resourcelocation = RealmsTextureManager.worldTemplate(String.valueOf(p_283588_), p_282484_);
} else if (pSlotIndex == 1) {
resourcelocation = RealmsWorldSlotButton.DEFAULT_WORLD_SLOT_1;
} else if (pSlotIndex == 2) {
resourcelocation = RealmsWorldSlotButton.DEFAULT_WORLD_SLOT_2;
} else if (pSlotIndex == 3) {
resourcelocation = RealmsWorldSlotButton.DEFAULT_WORLD_SLOT_3;
} else {
resourcelocation = RealmsTextureManager.worldTemplate(String.valueOf(this.serverData.minigameId), this.serverData.minigameImage);
}
if (!pIsActiveNonMinigame) {
pGuiGraphics.setColor(0.56F, 0.56F, 0.56F, 1.0F);
} else if (pIsActiveNonMinigame) {
float f = 0.9F + 0.1F * Mth.cos((float)this.animTick * 0.2F);
pGuiGraphics.setColor(f, f, f, 1.0F);
}
pGuiGraphics.blit(resourcelocation, pX + 3, pY + 3, 0.0F, 0.0F, 74, 74, 74, 74);
if (pIsActiveNonMinigame) {
pGuiGraphics.setColor(1.0F, 1.0F, 1.0F, 1.0F);
} else {
pGuiGraphics.setColor(0.56F, 0.56F, 0.56F, 1.0F);
}
pGuiGraphics.blit(RealmsWorldSlotButton.SLOT_FRAME_LOCATION, pX, pY, 0.0F, 0.0F, 80, 80, 80, 80);
pGuiGraphics.drawCenteredString(this.font, pText, pX + 40, pY + 66, 16777215);
pGuiGraphics.setColor(1.0F, 1.0F, 1.0F, 1.0F);
}
}
@@ -0,0 +1,55 @@
package com.mojang.realmsclient.gui.screens;
import net.minecraft.SharedConstants;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.realms.RealmsScreen;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class RealmsClientOutdatedScreen extends RealmsScreen {
private static final Component INCOMPATIBLE_TITLE = Component.translatable("mco.client.incompatible.title");
private static final Component[] INCOMPATIBLE_MESSAGES_SNAPSHOT = new Component[]{Component.translatable("mco.client.incompatible.msg.line1"), Component.translatable("mco.client.incompatible.msg.line2"), Component.translatable("mco.client.incompatible.msg.line3")};
private static final Component[] INCOMPATIBLE_MESSAGES = new Component[]{Component.translatable("mco.client.incompatible.msg.line1"), Component.translatable("mco.client.incompatible.msg.line2")};
private final Screen lastScreen;
public RealmsClientOutdatedScreen(Screen pLastScreen) {
super(INCOMPATIBLE_TITLE);
this.lastScreen = pLastScreen;
}
public void init() {
this.addRenderableWidget(Button.builder(CommonComponents.GUI_BACK, (p_280710_) -> {
this.minecraft.setScreen(this.lastScreen);
}).bounds(this.width / 2 - 100, row(12), 200, 20).build());
}
public void render(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) {
this.renderBackground(pGuiGraphics);
pGuiGraphics.drawCenteredString(this.font, this.title, this.width / 2, row(3), 16711680);
Component[] acomponent = this.getMessages();
for(int i = 0; i < acomponent.length; ++i) {
pGuiGraphics.drawCenteredString(this.font, acomponent[i], this.width / 2, row(5) + i * 12, 16777215);
}
super.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
}
private Component[] getMessages() {
return SharedConstants.getCurrentVersion().isStable() ? INCOMPATIBLE_MESSAGES : INCOMPATIBLE_MESSAGES_SNAPSHOT;
}
public boolean keyPressed(int pKeyCode, int pScanCode, int pModifiers) {
if (pKeyCode != 257 && pKeyCode != 335 && pKeyCode != 256) {
return super.keyPressed(pKeyCode, pScanCode, pModifiers);
} else {
this.minecraft.setScreen(this.lastScreen);
return true;
}
}
}
@@ -0,0 +1,477 @@
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.RealmsWorldOptions;
import com.mojang.realmsclient.dto.WorldTemplate;
import com.mojang.realmsclient.exception.RealmsServiceException;
import com.mojang.realmsclient.gui.RealmsWorldSlotButton;
import com.mojang.realmsclient.util.task.CloseServerTask;
import com.mojang.realmsclient.util.task.OpenServerTask;
import com.mojang.realmsclient.util.task.SwitchMinigameTask;
import com.mojang.realmsclient.util.task.SwitchSlotTask;
import java.util.List;
import javax.annotation.Nullable;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.realms.RealmsScreen;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class RealmsConfigureWorldScreen extends RealmsScreen {
private static final Logger LOGGER = LogUtils.getLogger();
private static final ResourceLocation ON_ICON_LOCATION = new ResourceLocation("realms", "textures/gui/realms/on_icon.png");
private static final ResourceLocation OFF_ICON_LOCATION = new ResourceLocation("realms", "textures/gui/realms/off_icon.png");
private static final ResourceLocation EXPIRED_ICON_LOCATION = new ResourceLocation("realms", "textures/gui/realms/expired_icon.png");
private static final ResourceLocation EXPIRES_SOON_ICON_LOCATION = new ResourceLocation("realms", "textures/gui/realms/expires_soon_icon.png");
private static final Component WORLD_LIST_TITLE = Component.translatable("mco.configure.worlds.title");
private static final Component TITLE = Component.translatable("mco.configure.world.title");
private static final Component SERVER_EXPIRED_TOOLTIP = Component.translatable("mco.selectServer.expired");
private static final Component SERVER_EXPIRING_SOON_TOOLTIP = Component.translatable("mco.selectServer.expires.soon");
private static final Component SERVER_EXPIRING_IN_DAY_TOOLTIP = Component.translatable("mco.selectServer.expires.day");
private static final Component SERVER_OPEN_TOOLTIP = Component.translatable("mco.selectServer.open");
private static final Component SERVER_CLOSED_TOOLTIP = Component.translatable("mco.selectServer.closed");
private static final int DEFAULT_BUTTON_WIDTH = 80;
private static final int DEFAULT_BUTTON_OFFSET = 5;
@Nullable
private Component toolTip;
private final RealmsMainScreen lastScreen;
@Nullable
private RealmsServer serverData;
private final long serverId;
private int leftX;
private int rightX;
private Button playersButton;
private Button settingsButton;
private Button subscriptionButton;
private Button optionsButton;
private Button backupButton;
private Button resetWorldButton;
private Button switchMinigameButton;
private boolean stateChanged;
private int animTick;
private int clicks;
private final List<RealmsWorldSlotButton> slotButtonList = Lists.newArrayList();
public RealmsConfigureWorldScreen(RealmsMainScreen pLastScreen, long pServerId) {
super(TITLE);
this.lastScreen = pLastScreen;
this.serverId = pServerId;
}
public void init() {
if (this.serverData == null) {
this.fetchServerData(this.serverId);
}
this.leftX = this.width / 2 - 187;
this.rightX = this.width / 2 + 190;
this.playersButton = this.addRenderableWidget(Button.builder(Component.translatable("mco.configure.world.buttons.players"), (p_280722_) -> {
this.minecraft.setScreen(new RealmsPlayerScreen(this, this.serverData));
}).bounds(this.centerButton(0, 3), row(0), 100, 20).build());
this.settingsButton = this.addRenderableWidget(Button.builder(Component.translatable("mco.configure.world.buttons.settings"), (p_280716_) -> {
this.minecraft.setScreen(new RealmsSettingsScreen(this, this.serverData.clone()));
}).bounds(this.centerButton(1, 3), row(0), 100, 20).build());
this.subscriptionButton = this.addRenderableWidget(Button.builder(Component.translatable("mco.configure.world.buttons.subscription"), (p_280725_) -> {
this.minecraft.setScreen(new RealmsSubscriptionInfoScreen(this, this.serverData.clone(), this.lastScreen));
}).bounds(this.centerButton(2, 3), row(0), 100, 20).build());
this.slotButtonList.clear();
for(int i = 1; i < 5; ++i) {
this.slotButtonList.add(this.addSlotButton(i));
}
this.switchMinigameButton = this.addRenderableWidget(Button.builder(Component.translatable("mco.configure.world.buttons.switchminigame"), (p_280711_) -> {
this.minecraft.setScreen(new RealmsSelectWorldTemplateScreen(Component.translatable("mco.template.title.minigame"), this::templateSelectionCallback, RealmsServer.WorldType.MINIGAME));
}).bounds(this.leftButton(0), row(13) - 5, 100, 20).build());
this.optionsButton = this.addRenderableWidget(Button.builder(Component.translatable("mco.configure.world.buttons.options"), (p_280720_) -> {
this.minecraft.setScreen(new RealmsSlotOptionsScreen(this, this.serverData.slots.get(this.serverData.activeSlot).clone(), this.serverData.worldType, this.serverData.activeSlot));
}).bounds(this.leftButton(0), row(13) - 5, 90, 20).build());
this.backupButton = this.addRenderableWidget(Button.builder(Component.translatable("mco.configure.world.backup"), (p_280715_) -> {
this.minecraft.setScreen(new RealmsBackupScreen(this, this.serverData.clone(), this.serverData.activeSlot));
}).bounds(this.leftButton(1), row(13) - 5, 90, 20).build());
this.resetWorldButton = this.addRenderableWidget(Button.builder(Component.translatable("mco.configure.world.buttons.resetworld"), (p_280724_) -> {
this.minecraft.setScreen(new RealmsResetWorldScreen(this, this.serverData.clone(), () -> {
this.minecraft.execute(() -> {
this.minecraft.setScreen(this.getNewScreen());
});
}, () -> {
this.minecraft.setScreen(this.getNewScreen());
}));
}).bounds(this.leftButton(2), row(13) - 5, 90, 20).build());
this.addRenderableWidget(Button.builder(CommonComponents.GUI_BACK, (p_167407_) -> {
this.backButtonClicked();
}).bounds(this.rightX - 80 + 8, row(13) - 5, 70, 20).build());
this.backupButton.active = true;
if (this.serverData == null) {
this.hideMinigameButtons();
this.hideRegularButtons();
this.playersButton.active = false;
this.settingsButton.active = false;
this.subscriptionButton.active = false;
} else {
this.disableButtons();
if (this.isMinigame()) {
this.hideRegularButtons();
} else {
this.hideMinigameButtons();
}
}
}
private RealmsWorldSlotButton addSlotButton(int p_167386_) {
int i = this.frame(p_167386_);
int j = row(5) + 5;
RealmsWorldSlotButton realmsworldslotbutton = new RealmsWorldSlotButton(i, j, 80, 80, () -> {
return this.serverData;
}, (p_167399_) -> {
this.toolTip = p_167399_;
}, p_167386_, (p_167389_) -> {
RealmsWorldSlotButton.State realmsworldslotbutton$state = ((RealmsWorldSlotButton)p_167389_).getState();
if (realmsworldslotbutton$state != null) {
switch (realmsworldslotbutton$state.action) {
case NOTHING:
break;
case JOIN:
this.joinRealm(this.serverData);
break;
case SWITCH_SLOT:
if (realmsworldslotbutton$state.minigame) {
this.switchToMinigame();
} else if (realmsworldslotbutton$state.empty) {
this.switchToEmptySlot(p_167386_, this.serverData);
} else {
this.switchToFullSlot(p_167386_, this.serverData);
}
break;
default:
throw new IllegalStateException("Unknown action " + realmsworldslotbutton$state.action);
}
}
});
return this.addRenderableWidget(realmsworldslotbutton);
}
private int leftButton(int p_88464_) {
return this.leftX + p_88464_ * 95;
}
private int centerButton(int p_88466_, int p_88467_) {
return this.width / 2 - (p_88467_ * 105 - 5) / 2 + p_88466_ * 105;
}
public void tick() {
super.tick();
++this.animTick;
--this.clicks;
if (this.clicks < 0) {
this.clicks = 0;
}
this.slotButtonList.forEach(RealmsWorldSlotButton::tick);
}
public void render(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) {
this.toolTip = null;
this.renderBackground(pGuiGraphics);
pGuiGraphics.drawCenteredString(this.font, WORLD_LIST_TITLE, this.width / 2, row(4), 16777215);
super.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
if (this.serverData == null) {
pGuiGraphics.drawCenteredString(this.font, this.title, this.width / 2, 17, 16777215);
} else {
String s = this.serverData.getName();
int i = this.font.width(s);
int j = this.serverData.state == RealmsServer.State.CLOSED ? 10526880 : 8388479;
int k = this.font.width(this.title);
pGuiGraphics.drawCenteredString(this.font, this.title, this.width / 2, 12, 16777215);
pGuiGraphics.drawCenteredString(this.font, s, this.width / 2, 24, j);
int l = Math.min(this.centerButton(2, 3) + 80 - 11, this.width / 2 + i / 2 + k / 2 + 10);
this.drawServerStatus(pGuiGraphics, l, 7, pMouseX, pMouseY);
if (this.isMinigame()) {
pGuiGraphics.drawString(this.font, Component.translatable("mco.configure.world.minigame", this.serverData.getMinigameName()), this.leftX + 80 + 20 + 10, row(13), 16777215, false);
}
if (this.toolTip != null) {
this.renderMousehoverTooltip(pGuiGraphics, this.toolTip, pMouseX, pMouseY);
}
}
}
private int frame(int p_88488_) {
return this.leftX + (p_88488_ - 1) * 98;
}
public boolean keyPressed(int pKeyCode, int pScanCode, int pModifiers) {
if (pKeyCode == 256) {
this.backButtonClicked();
return true;
} else {
return super.keyPressed(pKeyCode, pScanCode, pModifiers);
}
}
private void backButtonClicked() {
if (this.stateChanged) {
this.lastScreen.resetScreen();
}
this.minecraft.setScreen(this.lastScreen);
}
private void fetchServerData(long pServerId) {
(new Thread(() -> {
RealmsClient realmsclient = RealmsClient.create();
try {
RealmsServer realmsserver = realmsclient.getOwnWorld(pServerId);
this.minecraft.execute(() -> {
this.serverData = realmsserver;
this.disableButtons();
if (this.isMinigame()) {
this.show(this.switchMinigameButton);
} else {
this.show(this.optionsButton);
this.show(this.backupButton);
this.show(this.resetWorldButton);
}
});
} catch (RealmsServiceException realmsserviceexception) {
LOGGER.error("Couldn't get own world");
this.minecraft.execute(() -> {
this.minecraft.setScreen(new RealmsGenericErrorScreen(Component.nullToEmpty(realmsserviceexception.getMessage()), this.lastScreen));
});
}
})).start();
}
private void disableButtons() {
this.playersButton.active = !this.serverData.expired;
this.settingsButton.active = !this.serverData.expired;
this.subscriptionButton.active = true;
this.switchMinigameButton.active = !this.serverData.expired;
this.optionsButton.active = !this.serverData.expired;
this.resetWorldButton.active = !this.serverData.expired;
}
private void joinRealm(RealmsServer pServer) {
if (this.serverData.state == RealmsServer.State.OPEN) {
this.lastScreen.play(pServer, new RealmsConfigureWorldScreen(this.lastScreen.newScreen(), this.serverId));
} else {
this.openTheWorld(true, new RealmsConfigureWorldScreen(this.lastScreen.newScreen(), this.serverId));
}
}
private void switchToMinigame() {
RealmsSelectWorldTemplateScreen realmsselectworldtemplatescreen = new RealmsSelectWorldTemplateScreen(Component.translatable("mco.template.title.minigame"), this::templateSelectionCallback, RealmsServer.WorldType.MINIGAME);
realmsselectworldtemplatescreen.setWarning(Component.translatable("mco.minigame.world.info.line1"), Component.translatable("mco.minigame.world.info.line2"));
this.minecraft.setScreen(realmsselectworldtemplatescreen);
}
private void switchToFullSlot(int pSlot, RealmsServer pServer) {
Component component = Component.translatable("mco.configure.world.slot.switch.question.line1");
Component component1 = Component.translatable("mco.configure.world.slot.switch.question.line2");
this.minecraft.setScreen(new RealmsLongConfirmationScreen((p_280714_) -> {
if (p_280714_) {
this.minecraft.setScreen(new RealmsLongRunningMcoTaskScreen(this.lastScreen, new SwitchSlotTask(pServer.id, pSlot, () -> {
this.minecraft.execute(() -> {
this.minecraft.setScreen(this.getNewScreen());
});
})));
} else {
this.minecraft.setScreen(this);
}
}, RealmsLongConfirmationScreen.Type.INFO, component, component1, true));
}
private void switchToEmptySlot(int pSlot, RealmsServer pServer) {
Component component = Component.translatable("mco.configure.world.slot.switch.question.line1");
Component component1 = Component.translatable("mco.configure.world.slot.switch.question.line2");
this.minecraft.setScreen(new RealmsLongConfirmationScreen((p_280719_) -> {
if (p_280719_) {
RealmsResetWorldScreen realmsresetworldscreen = new RealmsResetWorldScreen(this, pServer, Component.translatable("mco.configure.world.switch.slot"), Component.translatable("mco.configure.world.switch.slot.subtitle"), 10526880, CommonComponents.GUI_CANCEL, () -> {
this.minecraft.execute(() -> {
this.minecraft.setScreen(this.getNewScreen());
});
}, () -> {
this.minecraft.setScreen(this.getNewScreen());
});
realmsresetworldscreen.setSlot(pSlot);
realmsresetworldscreen.setResetTitle(Component.translatable("mco.create.world.reset.title"));
this.minecraft.setScreen(realmsresetworldscreen);
} else {
this.minecraft.setScreen(this);
}
}, RealmsLongConfirmationScreen.Type.INFO, component, component1, true));
}
protected void renderMousehoverTooltip(GuiGraphics pGuiGraphics, @Nullable Component pTooltip, int pMouseX, int pMouseY) {
int i = pMouseX + 12;
int j = pMouseY - 12;
int k = this.font.width(pTooltip);
if (i + k + 3 > this.rightX) {
i = i - k - 20;
}
pGuiGraphics.fillGradient(i - 3, j - 3, i + k + 3, j + 8 + 3, -1073741824, -1073741824);
pGuiGraphics.drawString(this.font, pTooltip, i, j, 16777215);
}
private void drawServerStatus(GuiGraphics pGuiGraphics, int pX, int pY, int pMouseX, int pMouseY) {
if (this.serverData.expired) {
this.drawExpired(pGuiGraphics, pX, pY, pMouseX, pMouseY);
} else if (this.serverData.state == RealmsServer.State.CLOSED) {
this.drawClose(pGuiGraphics, pX, pY, pMouseX, pMouseY);
} else if (this.serverData.state == RealmsServer.State.OPEN) {
if (this.serverData.daysLeft < 7) {
this.drawExpiring(pGuiGraphics, pX, pY, pMouseX, pMouseY, this.serverData.daysLeft);
} else {
this.drawOpen(pGuiGraphics, pX, pY, pMouseX, pMouseY);
}
}
}
private void drawExpired(GuiGraphics pGuiGraphics, int pX, int pY, int pMouseX, int pMouseY) {
pGuiGraphics.blit(EXPIRED_ICON_LOCATION, pX, pY, 0.0F, 0.0F, 10, 28, 10, 28);
if (pMouseX >= pX && pMouseX <= pX + 9 && pMouseY >= pY && pMouseY <= pY + 27) {
this.toolTip = SERVER_EXPIRED_TOOLTIP;
}
}
private void drawExpiring(GuiGraphics pGuiGraphics, int pX, int pY, int pMouseX, int pMouseY, int pDaysLeft) {
if (this.animTick % 20 < 10) {
pGuiGraphics.blit(EXPIRES_SOON_ICON_LOCATION, pX, pY, 0.0F, 0.0F, 10, 28, 20, 28);
} else {
pGuiGraphics.blit(EXPIRES_SOON_ICON_LOCATION, pX, pY, 10.0F, 0.0F, 10, 28, 20, 28);
}
if (pMouseX >= pX && pMouseX <= pX + 9 && pMouseY >= pY && pMouseY <= pY + 27) {
if (pDaysLeft <= 0) {
this.toolTip = SERVER_EXPIRING_SOON_TOOLTIP;
} else if (pDaysLeft == 1) {
this.toolTip = SERVER_EXPIRING_IN_DAY_TOOLTIP;
} else {
this.toolTip = Component.translatable("mco.selectServer.expires.days", pDaysLeft);
}
}
}
private void drawOpen(GuiGraphics pGuiGraphics, int pX, int pY, int pMouseX, int pMouseY) {
pGuiGraphics.blit(ON_ICON_LOCATION, pX, pY, 0.0F, 0.0F, 10, 28, 10, 28);
if (pMouseX >= pX && pMouseX <= pX + 9 && pMouseY >= pY && pMouseY <= pY + 27) {
this.toolTip = SERVER_OPEN_TOOLTIP;
}
}
private void drawClose(GuiGraphics pGuiGraphics, int pX, int pY, int pMouseX, int pMouseY) {
pGuiGraphics.blit(OFF_ICON_LOCATION, pX, pY, 0.0F, 0.0F, 10, 28, 10, 28);
if (pMouseX >= pX && pMouseX <= pX + 9 && pMouseY >= pY && pMouseY <= pY + 27) {
this.toolTip = SERVER_CLOSED_TOOLTIP;
}
}
private boolean isMinigame() {
return this.serverData != null && this.serverData.worldType == RealmsServer.WorldType.MINIGAME;
}
private void hideRegularButtons() {
this.hide(this.optionsButton);
this.hide(this.backupButton);
this.hide(this.resetWorldButton);
}
private void hide(Button pButton) {
pButton.visible = false;
this.removeWidget(pButton);
}
private void show(Button pButton) {
pButton.visible = true;
this.addRenderableWidget(pButton);
}
private void hideMinigameButtons() {
this.hide(this.switchMinigameButton);
}
public void saveSlotSettings(RealmsWorldOptions pWorldOptions) {
RealmsWorldOptions realmsworldoptions = this.serverData.slots.get(this.serverData.activeSlot);
pWorldOptions.templateId = realmsworldoptions.templateId;
pWorldOptions.templateImage = realmsworldoptions.templateImage;
RealmsClient realmsclient = RealmsClient.create();
try {
realmsclient.updateSlot(this.serverData.id, this.serverData.activeSlot, pWorldOptions);
this.serverData.slots.put(this.serverData.activeSlot, pWorldOptions);
} catch (RealmsServiceException realmsserviceexception) {
LOGGER.error("Couldn't save slot settings");
this.minecraft.setScreen(new RealmsGenericErrorScreen(realmsserviceexception, this));
return;
}
this.minecraft.setScreen(this);
}
public void saveSettings(String pKey, String pValue) {
String s = pValue.trim().isEmpty() ? null : pValue;
RealmsClient realmsclient = RealmsClient.create();
try {
realmsclient.update(this.serverData.id, pKey, s);
this.serverData.setName(pKey);
this.serverData.setDescription(s);
} catch (RealmsServiceException realmsserviceexception) {
LOGGER.error("Couldn't save settings");
this.minecraft.setScreen(new RealmsGenericErrorScreen(realmsserviceexception, this));
return;
}
this.minecraft.setScreen(this);
}
public void openTheWorld(boolean pJoin, Screen pLastScreen) {
this.minecraft.setScreen(new RealmsLongRunningMcoTaskScreen(pLastScreen, new OpenServerTask(this.serverData, this, this.lastScreen, pJoin, this.minecraft)));
}
public void closeTheWorld(Screen pLastScreen) {
this.minecraft.setScreen(new RealmsLongRunningMcoTaskScreen(pLastScreen, new CloseServerTask(this.serverData, this)));
}
public void stateChanged() {
this.stateChanged = true;
}
private void templateSelectionCallback(@Nullable WorldTemplate p_167395_) {
if (p_167395_ != null && WorldTemplate.WorldTemplateType.MINIGAME == p_167395_.type) {
this.minecraft.setScreen(new RealmsLongRunningMcoTaskScreen(this.lastScreen, new SwitchMinigameTask(this.serverData.id, p_167395_, this.getNewScreen())));
} else {
this.minecraft.setScreen(this);
}
}
public RealmsConfigureWorldScreen getNewScreen() {
return new RealmsConfigureWorldScreen(this.lastScreen, this.serverId);
}
}
@@ -0,0 +1,41 @@
package com.mojang.realmsclient.gui.screens;
import it.unimi.dsi.fastutil.booleans.BooleanConsumer;
import net.minecraft.client.GameNarrator;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.Button;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.realms.RealmsScreen;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class RealmsConfirmScreen extends RealmsScreen {
protected BooleanConsumer callback;
private final Component title1;
private final Component title2;
public RealmsConfirmScreen(BooleanConsumer pCallback, Component pTitle1, Component pTitle2) {
super(GameNarrator.NO_TITLE);
this.callback = pCallback;
this.title1 = pTitle1;
this.title2 = pTitle2;
}
public void init() {
this.addRenderableWidget(Button.builder(CommonComponents.GUI_YES, (p_88562_) -> {
this.callback.accept(true);
}).bounds(this.width / 2 - 105, row(9), 100, 20).build());
this.addRenderableWidget(Button.builder(CommonComponents.GUI_NO, (p_88559_) -> {
this.callback.accept(false);
}).bounds(this.width / 2 + 5, row(9), 100, 20).build());
}
public void render(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) {
this.renderBackground(pGuiGraphics);
pGuiGraphics.drawCenteredString(this.font, this.title1, this.width / 2, row(3), 16777215);
pGuiGraphics.drawCenteredString(this.font, this.title2, this.width / 2, row(5), 16777215);
super.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
}
}
@@ -0,0 +1,108 @@
package com.mojang.realmsclient.gui.screens;
import com.mojang.realmsclient.RealmsMainScreen;
import com.mojang.realmsclient.dto.RealmsServer;
import com.mojang.realmsclient.util.task.WorldCreationTask;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.EditBox;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.realms.RealmsScreen;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class RealmsCreateRealmScreen extends RealmsScreen {
private static final Component NAME_LABEL = Component.translatable("mco.configure.world.name");
private static final Component DESCRIPTION_LABEL = Component.translatable("mco.configure.world.description");
private final RealmsServer server;
private final RealmsMainScreen lastScreen;
private EditBox nameBox;
private EditBox descriptionBox;
private Button createButton;
public RealmsCreateRealmScreen(RealmsServer pServer, RealmsMainScreen pLastScreen) {
super(Component.translatable("mco.selectServer.create"));
this.server = pServer;
this.lastScreen = pLastScreen;
}
public void tick() {
if (this.nameBox != null) {
this.nameBox.tick();
}
if (this.descriptionBox != null) {
this.descriptionBox.tick();
}
}
public void init() {
this.createButton = this.addRenderableWidget(Button.builder(Component.translatable("mco.create.world"), (p_88592_) -> {
this.createWorld();
}).bounds(this.width / 2 - 100, this.height / 4 + 120 + 17, 97, 20).build());
this.addRenderableWidget(Button.builder(CommonComponents.GUI_CANCEL, (p_280726_) -> {
this.minecraft.setScreen(this.lastScreen);
}).bounds(this.width / 2 + 5, this.height / 4 + 120 + 17, 95, 20).build());
this.createButton.active = false;
this.nameBox = new EditBox(this.minecraft.font, this.width / 2 - 100, 65, 200, 20, (EditBox)null, Component.translatable("mco.configure.world.name"));
this.addWidget(this.nameBox);
this.setInitialFocus(this.nameBox);
this.descriptionBox = new EditBox(this.minecraft.font, this.width / 2 - 100, 115, 200, 20, (EditBox)null, Component.translatable("mco.configure.world.description"));
this.addWidget(this.descriptionBox);
}
public boolean charTyped(char pCodePoint, int pModifiers) {
boolean flag = super.charTyped(pCodePoint, pModifiers);
this.createButton.active = this.valid();
return flag;
}
public boolean keyPressed(int pKeyCode, int pScanCode, int pModifiers) {
if (pKeyCode == 256) {
this.minecraft.setScreen(this.lastScreen);
return true;
} else {
boolean flag = super.keyPressed(pKeyCode, pScanCode, pModifiers);
this.createButton.active = this.valid();
return flag;
}
}
private void createWorld() {
if (this.valid()) {
RealmsResetWorldScreen realmsresetworldscreen = new RealmsResetWorldScreen(this.lastScreen, this.server, Component.translatable("mco.selectServer.create"), Component.translatable("mco.create.world.subtitle"), 10526880, Component.translatable("mco.create.world.skip"), () -> {
this.minecraft.execute(() -> {
this.minecraft.setScreen(this.lastScreen.newScreen());
});
}, () -> {
this.minecraft.setScreen(this.lastScreen.newScreen());
});
realmsresetworldscreen.setResetTitle(Component.translatable("mco.create.world.reset.title"));
this.minecraft.setScreen(new RealmsLongRunningMcoTaskScreen(this.lastScreen, new WorldCreationTask(this.server.id, this.nameBox.getValue(), this.descriptionBox.getValue(), realmsresetworldscreen)));
}
}
private boolean valid() {
return !this.nameBox.getValue().trim().isEmpty();
}
public void render(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) {
this.renderBackground(pGuiGraphics);
pGuiGraphics.drawCenteredString(this.font, this.title, this.width / 2, 11, 16777215);
pGuiGraphics.drawString(this.font, NAME_LABEL, this.width / 2 - 100, 52, 10526880, false);
pGuiGraphics.drawString(this.font, DESCRIPTION_LABEL, this.width / 2 - 100, 102, 10526880, false);
if (this.nameBox != null) {
this.nameBox.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
}
if (this.descriptionBox != null) {
this.descriptionBox.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
}
super.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
}
}
@@ -0,0 +1,293 @@
package com.mojang.realmsclient.gui.screens;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.RateLimiter;
import com.mojang.logging.LogUtils;
import com.mojang.realmsclient.Unit;
import com.mojang.realmsclient.client.FileDownload;
import com.mojang.realmsclient.dto.WorldDownload;
import it.unimi.dsi.fastutil.booleans.BooleanConsumer;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import javax.annotation.Nullable;
import net.minecraft.Util;
import net.minecraft.client.GameNarrator;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.realms.RealmsScreen;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.slf4j.Logger;
@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;
@Nullable
private volatile Component errorMessage;
private volatile Component status = Component.translatable("mco.download.preparing");
@Nullable
private volatile String progress;
private volatile boolean cancelled;
private volatile boolean showDots = true;
private volatile boolean finished;
private volatile boolean extracting;
@Nullable
private Long previousWrittenBytes;
@Nullable
private 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 pLastScreen, WorldDownload pWorldDownload, String pWorldName, BooleanConsumer pCallback) {
super(GameNarrator.NO_TITLE);
this.callback = pCallback;
this.lastScreen = pLastScreen;
this.worldName = pWorldName;
this.worldDownload = pWorldDownload;
this.downloadStatus = new RealmsDownloadLatestWorldScreen.DownloadStatus();
this.downloadTitle = Component.translatable("mco.download.title");
this.narrationRateLimiter = RateLimiter.create((double)0.1F);
}
public void init() {
this.cancelButton = this.addRenderableWidget(Button.builder(CommonComponents.GUI_CANCEL, (p_88642_) -> {
this.cancelled = true;
this.backButtonClicked();
}).bounds((this.width - 200) / 2, this.height - 42, 200, 20).build());
this.checkDownloadSize();
}
private void checkDownloadSize() {
if (!this.finished) {
if (!this.checked && this.getContentLength(this.worldDownload.downloadLink) >= 5368709120L) {
Component component = Component.translatable("mco.download.confirmation.line1", Unit.humanReadable(5368709120L));
Component component1 = Component.translatable("mco.download.confirmation.line2");
this.minecraft.setScreen(new RealmsLongConfirmationScreen((p_280727_) -> {
this.checked = true;
this.minecraft.setScreen(this);
this.downloadSave();
}, RealmsLongConfirmationScreen.Type.WARNING, component, component1, false));
} else {
this.downloadSave();
}
}
}
private long getContentLength(String pUri) {
FileDownload filedownload = new FileDownload();
return filedownload.contentLength(pUri);
}
public void tick() {
super.tick();
++this.animTick;
if (this.status != null && this.narrationRateLimiter.tryAcquire(1)) {
Component component = this.createProgressNarrationMessage();
this.minecraft.getNarrator().sayNow(component);
}
}
private Component createProgressNarrationMessage() {
List<Component> list = Lists.newArrayList();
list.add(this.downloadTitle);
list.add(this.status);
if (this.progress != null) {
list.add(Component.literal(this.progress + "%"));
list.add(Component.literal(Unit.humanReadable(this.bytesPersSecond) + "/s"));
}
if (this.errorMessage != null) {
list.add(this.errorMessage);
}
return CommonComponents.joinLines(list);
}
public boolean keyPressed(int pKeyCode, int pScanCode, int pModifiers) {
if (pKeyCode == 256) {
this.cancelled = true;
this.backButtonClicked();
return true;
} else {
return super.keyPressed(pKeyCode, pScanCode, pModifiers);
}
}
private void backButtonClicked() {
if (this.finished && this.callback != null && this.errorMessage == null) {
this.callback.accept(true);
}
this.minecraft.setScreen(this.lastScreen);
}
public void render(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) {
this.renderBackground(pGuiGraphics);
pGuiGraphics.drawCenteredString(this.font, this.downloadTitle, this.width / 2, 20, 16777215);
pGuiGraphics.drawCenteredString(this.font, this.status, this.width / 2, 50, 16777215);
if (this.showDots) {
this.drawDots(pGuiGraphics);
}
if (this.downloadStatus.bytesWritten != 0L && !this.cancelled) {
this.drawProgressBar(pGuiGraphics);
this.drawDownloadSpeed(pGuiGraphics);
}
if (this.errorMessage != null) {
pGuiGraphics.drawCenteredString(this.font, this.errorMessage, this.width / 2, 110, 16711680);
}
super.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
}
private void drawDots(GuiGraphics pGuiGraphics) {
int i = this.font.width(this.status);
if (this.animTick % 10 == 0) {
++this.dotIndex;
}
pGuiGraphics.drawString(this.font, DOTS[this.dotIndex % DOTS.length], this.width / 2 + i / 2 + 5, 50, 16777215, false);
}
private void drawProgressBar(GuiGraphics pGuiGraphics) {
double d0 = Math.min((double)this.downloadStatus.bytesWritten / (double)this.downloadStatus.totalBytes, 1.0D);
this.progress = String.format(Locale.ROOT, "%.1f", d0 * 100.0D);
int i = (this.width - 200) / 2;
int j = i + (int)Math.round(200.0D * d0);
pGuiGraphics.fill(i - 1, 79, j + 1, 96, -2501934);
pGuiGraphics.fill(i, 80, j, 95, -8355712);
pGuiGraphics.drawCenteredString(this.font, Component.translatable("mco.download.percent", this.progress), this.width / 2, 84, 16777215);
}
private void drawDownloadSpeed(GuiGraphics pGuiGraphics) {
if (this.animTick % 20 == 0) {
if (this.previousWrittenBytes != null) {
long i = Util.getMillis() - this.previousTimeSnapshot;
if (i == 0L) {
i = 1L;
}
this.bytesPersSecond = 1000L * (this.downloadStatus.bytesWritten - this.previousWrittenBytes) / i;
this.drawDownloadSpeed0(pGuiGraphics, this.bytesPersSecond);
}
this.previousWrittenBytes = this.downloadStatus.bytesWritten;
this.previousTimeSnapshot = Util.getMillis();
} else {
this.drawDownloadSpeed0(pGuiGraphics, this.bytesPersSecond);
}
}
private void drawDownloadSpeed0(GuiGraphics pGuiGraphics, long pBytesPerSecond) {
if (pBytesPerSecond > 0L) {
int i = this.font.width(this.progress);
pGuiGraphics.drawString(this.font, Component.translatable("mco.download.speed", Unit.humanReadable(pBytesPerSecond)), this.width / 2 + i / 2 + 15, 84, 16777215, false);
}
}
private void downloadSave() {
(new Thread(() -> {
try {
if (DOWNLOAD_LOCK.tryLock(1L, TimeUnit.SECONDS)) {
if (this.cancelled) {
this.downloadCancelled();
return;
}
this.status = Component.translatable("mco.download.downloading", this.worldName);
FileDownload filedownload = new FileDownload();
filedownload.contentLength(this.worldDownload.downloadLink);
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 interruptedexception) {
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;
}
this.status = Component.translatable("mco.download.failed");
} catch (InterruptedException interruptedexception1) {
LOGGER.error("Could not acquire upload lock");
return;
} catch (Exception exception) {
this.errorMessage = Component.translatable("mco.download.failed");
exception.printStackTrace();
return;
} finally {
if (!DOWNLOAD_LOCK.isHeldByCurrentThread()) {
return;
}
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;
}
}
@@ -0,0 +1,90 @@
package com.mojang.realmsclient.gui.screens;
import com.mojang.realmsclient.client.RealmsError;
import com.mojang.realmsclient.exception.RealmsServiceException;
import net.minecraft.client.GameNarrator;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.MultiLineLabel;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.resources.language.I18n;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.realms.RealmsScreen;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class RealmsGenericErrorScreen extends RealmsScreen {
private final Screen nextScreen;
private final RealmsGenericErrorScreen.ErrorMessage lines;
private MultiLineLabel line2Split = MultiLineLabel.EMPTY;
public RealmsGenericErrorScreen(RealmsServiceException pServiceException, Screen pNextScreen) {
super(GameNarrator.NO_TITLE);
this.nextScreen = pNextScreen;
this.lines = errorMessage(pServiceException);
}
public RealmsGenericErrorScreen(Component pMessage, Screen pNextScreen) {
super(GameNarrator.NO_TITLE);
this.nextScreen = pNextScreen;
this.lines = errorMessage(pMessage);
}
public RealmsGenericErrorScreen(Component pTitle, Component pLine2, Screen pMessage) {
super(GameNarrator.NO_TITLE);
this.nextScreen = pMessage;
this.lines = errorMessage(pTitle, pLine2);
}
private static RealmsGenericErrorScreen.ErrorMessage errorMessage(RealmsServiceException pException) {
RealmsError realmserror = pException.realmsError;
if (realmserror == null) {
return errorMessage(Component.translatable("mco.errorMessage.realmsService", pException.httpResultCode), Component.literal(pException.rawResponse));
} else {
int i = realmserror.getErrorCode();
String s = "mco.errorMessage." + i;
return errorMessage(Component.translatable("mco.errorMessage.realmsService.realmsError", i), (Component)(I18n.exists(s) ? Component.translatable(s) : Component.nullToEmpty(realmserror.getErrorMessage())));
}
}
private static RealmsGenericErrorScreen.ErrorMessage errorMessage(Component pMessage) {
return errorMessage(Component.translatable("mco.errorMessage.generic"), pMessage);
}
private static RealmsGenericErrorScreen.ErrorMessage errorMessage(Component pTitle, Component pMessage) {
return new RealmsGenericErrorScreen.ErrorMessage(pTitle, pMessage);
}
public void init() {
this.addRenderableWidget(Button.builder(CommonComponents.GUI_OK, (p_280728_) -> {
this.minecraft.setScreen(this.nextScreen);
}).bounds(this.width / 2 - 100, this.height - 52, 200, 20).build());
this.line2Split = MultiLineLabel.create(this.font, this.lines.detail, this.width * 3 / 4);
}
public Component getNarrationMessage() {
return Component.empty().append(this.lines.title).append(": ").append(this.lines.detail);
}
@Override
public boolean keyPressed(int key, int scanCode, int modifiers) {
if (key == org.lwjgl.glfw.GLFW.GLFW_KEY_ESCAPE) {
minecraft.setScreen(this.nextScreen);
return true;
}
return super.keyPressed(key, scanCode, modifiers);
}
public void render(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) {
this.renderBackground(pGuiGraphics);
pGuiGraphics.drawCenteredString(this.font, this.lines.title, this.width / 2, 80, 16777215);
this.line2Split.renderCentered(pGuiGraphics, this.width / 2, 100, 9, 16711680);
super.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
}
@OnlyIn(Dist.CLIENT)
static record ErrorMessage(Component title, Component detail) {
}
}
@@ -0,0 +1,118 @@
package com.mojang.realmsclient.gui.screens;
import com.mojang.logging.LogUtils;
import com.mojang.realmsclient.client.RealmsClient;
import com.mojang.realmsclient.dto.RealmsServer;
import java.util.concurrent.CompletableFuture;
import javax.annotation.Nullable;
import net.minecraft.Util;
import net.minecraft.client.GameNarrator;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.EditBox;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.realms.RealmsScreen;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class RealmsInviteScreen extends RealmsScreen {
private static final Logger LOGGER = LogUtils.getLogger();
private static final Component NAME_LABEL = Component.translatable("mco.configure.world.invite.profile.name").withStyle((p_289621_) -> {
return p_289621_.withColor(-6250336);
});
private static final Component INVITING_PLAYER_TEXT = Component.translatable("mco.configure.world.players.inviting").withStyle((p_289617_) -> {
return p_289617_.withColor(-6250336);
});
private static final Component NO_SUCH_PLAYER_ERROR_TEXT = Component.translatable("mco.configure.world.players.error").withStyle((p_289622_) -> {
return p_289622_.withColor(-65536);
});
private EditBox profileName;
private Button inviteButton;
private final RealmsServer serverData;
private final RealmsConfigureWorldScreen configureScreen;
private final Screen lastScreen;
@Nullable
private Component message;
public RealmsInviteScreen(RealmsConfigureWorldScreen pConfigureScreen, Screen pLastScreen, RealmsServer pServerData) {
super(GameNarrator.NO_TITLE);
this.configureScreen = pConfigureScreen;
this.lastScreen = pLastScreen;
this.serverData = pServerData;
}
public void tick() {
this.profileName.tick();
}
public void init() {
this.profileName = new EditBox(this.minecraft.font, this.width / 2 - 100, row(2), 200, 20, (EditBox)null, Component.translatable("mco.configure.world.invite.profile.name"));
this.addWidget(this.profileName);
this.setInitialFocus(this.profileName);
this.inviteButton = this.addRenderableWidget(Button.builder(Component.translatable("mco.configure.world.buttons.invite"), (p_88721_) -> {
this.onInvite();
}).bounds(this.width / 2 - 100, row(10), 200, 20).build());
this.addRenderableWidget(Button.builder(CommonComponents.GUI_CANCEL, (p_280729_) -> {
this.minecraft.setScreen(this.lastScreen);
}).bounds(this.width / 2 - 100, row(12), 200, 20).build());
}
private void onInvite() {
if (Util.isBlank(this.profileName.getValue())) {
this.showMessage(NO_SUCH_PLAYER_ERROR_TEXT);
} else {
long i = this.serverData.id;
String s = this.profileName.getValue().trim();
this.inviteButton.active = false;
this.profileName.setEditable(false);
this.showMessage(INVITING_PLAYER_TEXT);
CompletableFuture.supplyAsync(() -> {
try {
return RealmsClient.create().invite(i, s);
} catch (Exception exception) {
LOGGER.error("Couldn't invite user");
return null;
}
}, Util.ioPool()).thenAcceptAsync((p_289618_) -> {
if (p_289618_ != null) {
this.serverData.players = p_289618_.players;
this.minecraft.setScreen(new RealmsPlayerScreen(this.configureScreen, this.serverData));
} else {
this.showMessage(NO_SUCH_PLAYER_ERROR_TEXT);
}
this.profileName.setEditable(true);
this.inviteButton.active = true;
}, this.screenExecutor);
}
}
private void showMessage(Component pMessage) {
this.message = pMessage;
this.minecraft.getNarrator().sayNow(pMessage);
}
public boolean keyPressed(int pKeyCode, int pScanCode, int pModifiers) {
if (pKeyCode == 256) {
this.minecraft.setScreen(this.lastScreen);
return true;
} else {
return super.keyPressed(pKeyCode, pScanCode, pModifiers);
}
}
public void render(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) {
this.renderBackground(pGuiGraphics);
pGuiGraphics.drawString(this.font, NAME_LABEL, this.width / 2 - 100, row(1), -1, false);
if (this.message != null) {
pGuiGraphics.drawCenteredString(this.font, this.message, this.width / 2, row(5), -1);
}
this.profileName.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
super.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
}
}
@@ -0,0 +1,82 @@
package com.mojang.realmsclient.gui.screens;
import it.unimi.dsi.fastutil.booleans.BooleanConsumer;
import net.minecraft.client.GameNarrator;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.Button;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.realms.RealmsScreen;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class RealmsLongConfirmationScreen extends RealmsScreen {
static final Component WARNING = Component.translatable("mco.warning");
static final Component INFO = Component.translatable("mco.info");
private final RealmsLongConfirmationScreen.Type type;
private final Component line2;
private final Component line3;
protected final BooleanConsumer callback;
private final boolean yesNoQuestion;
public RealmsLongConfirmationScreen(BooleanConsumer pConsumer, RealmsLongConfirmationScreen.Type pType, Component pLine2, Component pLine3, boolean pYesNoQuestion) {
super(GameNarrator.NO_TITLE);
this.callback = pConsumer;
this.type = pType;
this.line2 = pLine2;
this.line3 = pLine3;
this.yesNoQuestion = pYesNoQuestion;
}
public void init() {
if (this.yesNoQuestion) {
this.addRenderableWidget(Button.builder(CommonComponents.GUI_YES, (p_88751_) -> {
this.callback.accept(true);
}).bounds(this.width / 2 - 105, row(8), 100, 20).build());
this.addRenderableWidget(Button.builder(CommonComponents.GUI_NO, (p_88749_) -> {
this.callback.accept(false);
}).bounds(this.width / 2 + 5, row(8), 100, 20).build());
} else {
this.addRenderableWidget(Button.builder(CommonComponents.GUI_OK, (p_88746_) -> {
this.callback.accept(true);
}).bounds(this.width / 2 - 50, row(8), 100, 20).build());
}
}
public Component getNarrationMessage() {
return CommonComponents.joinLines(this.type.text, this.line2, this.line3);
}
public boolean keyPressed(int pKeyCode, int pScanCode, int pModifiers) {
if (pKeyCode == 256) {
this.callback.accept(false);
return true;
} else {
return super.keyPressed(pKeyCode, pScanCode, pModifiers);
}
}
public void render(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) {
this.renderBackground(pGuiGraphics);
pGuiGraphics.drawCenteredString(this.font, this.type.text, this.width / 2, row(2), this.type.colorCode);
pGuiGraphics.drawCenteredString(this.font, this.line2, this.width / 2, row(4), 16777215);
pGuiGraphics.drawCenteredString(this.font, this.line3, this.width / 2, row(6), 16777215);
super.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
}
@OnlyIn(Dist.CLIENT)
public static enum Type {
WARNING(RealmsLongConfirmationScreen.WARNING, 16711680),
INFO(RealmsLongConfirmationScreen.INFO, 8226750);
public final int colorCode;
public final Component text;
private Type(Component pText, int pColorCode) {
this.text = pText;
this.colorCode = pColorCode;
}
}
}
@@ -0,0 +1,106 @@
package com.mojang.realmsclient.gui.screens;
import com.mojang.logging.LogUtils;
import com.mojang.realmsclient.exception.RealmsDefaultUncaughtExceptionHandler;
import com.mojang.realmsclient.gui.ErrorCallback;
import com.mojang.realmsclient.util.task.LongRunningTask;
import java.time.Duration;
import javax.annotation.Nullable;
import net.minecraft.client.GameNarrator;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.realms.RealmsScreen;
import net.minecraft.realms.RepeatedNarrator;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class RealmsLongRunningMcoTaskScreen extends RealmsScreen implements ErrorCallback {
private static final RepeatedNarrator REPEATED_NARRATOR = new RepeatedNarrator(Duration.ofSeconds(5L));
private static final Logger LOGGER = LogUtils.getLogger();
private final Screen lastScreen;
private volatile Component title = CommonComponents.EMPTY;
@Nullable
private volatile Component errorMessage;
private volatile boolean aborted;
private int animTicks;
private final LongRunningTask task;
private final int buttonLength = 212;
private Button cancelOrBackButton;
public static final String[] SYMBOLS = new String[]{"\u2583 \u2584 \u2585 \u2586 \u2587 \u2588 \u2587 \u2586 \u2585 \u2584 \u2583", "_ \u2583 \u2584 \u2585 \u2586 \u2587 \u2588 \u2587 \u2586 \u2585 \u2584", "_ _ \u2583 \u2584 \u2585 \u2586 \u2587 \u2588 \u2587 \u2586 \u2585", "_ _ _ \u2583 \u2584 \u2585 \u2586 \u2587 \u2588 \u2587 \u2586", "_ _ _ _ \u2583 \u2584 \u2585 \u2586 \u2587 \u2588 \u2587", "_ _ _ _ _ \u2583 \u2584 \u2585 \u2586 \u2587 \u2588", "_ _ _ _ \u2583 \u2584 \u2585 \u2586 \u2587 \u2588 \u2587", "_ _ _ \u2583 \u2584 \u2585 \u2586 \u2587 \u2588 \u2587 \u2586", "_ _ \u2583 \u2584 \u2585 \u2586 \u2587 \u2588 \u2587 \u2586 \u2585", "_ \u2583 \u2584 \u2585 \u2586 \u2587 \u2588 \u2587 \u2586 \u2585 \u2584", "\u2583 \u2584 \u2585 \u2586 \u2587 \u2588 \u2587 \u2586 \u2585 \u2584 \u2583", "\u2584 \u2585 \u2586 \u2587 \u2588 \u2587 \u2586 \u2585 \u2584 \u2583 _", "\u2585 \u2586 \u2587 \u2588 \u2587 \u2586 \u2585 \u2584 \u2583 _ _", "\u2586 \u2587 \u2588 \u2587 \u2586 \u2585 \u2584 \u2583 _ _ _", "\u2587 \u2588 \u2587 \u2586 \u2585 \u2584 \u2583 _ _ _ _", "\u2588 \u2587 \u2586 \u2585 \u2584 \u2583 _ _ _ _ _", "\u2587 \u2588 \u2587 \u2586 \u2585 \u2584 \u2583 _ _ _ _", "\u2586 \u2587 \u2588 \u2587 \u2586 \u2585 \u2584 \u2583 _ _ _", "\u2585 \u2586 \u2587 \u2588 \u2587 \u2586 \u2585 \u2584 \u2583 _ _", "\u2584 \u2585 \u2586 \u2587 \u2588 \u2587 \u2586 \u2585 \u2584 \u2583 _"};
public RealmsLongRunningMcoTaskScreen(Screen pLastScreen, LongRunningTask pTask) {
super(GameNarrator.NO_TITLE);
this.lastScreen = pLastScreen;
this.task = pTask;
pTask.setScreen(this);
Thread thread = new Thread(pTask, "Realms-long-running-task");
thread.setUncaughtExceptionHandler(new RealmsDefaultUncaughtExceptionHandler(LOGGER));
thread.start();
}
public void tick() {
super.tick();
REPEATED_NARRATOR.narrate(this.minecraft.getNarrator(), this.title);
++this.animTicks;
this.task.tick();
}
public boolean keyPressed(int pKeyCode, int pScanCode, int pModifiers) {
if (pKeyCode == 256) {
this.cancelOrBackButtonClicked();
return true;
} else {
return super.keyPressed(pKeyCode, pScanCode, pModifiers);
}
}
public void init() {
this.task.init();
this.cancelOrBackButton = this.addRenderableWidget(Button.builder(CommonComponents.GUI_CANCEL, (p_88795_) -> {
this.cancelOrBackButtonClicked();
}).bounds(this.width / 2 - 106, row(12), 212, 20).build());
}
private void cancelOrBackButtonClicked() {
this.aborted = true;
this.task.abortTask();
this.minecraft.setScreen(this.lastScreen);
}
public void render(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) {
this.renderBackground(pGuiGraphics);
pGuiGraphics.drawCenteredString(this.font, this.title, this.width / 2, row(3), 16777215);
Component component = this.errorMessage;
if (component == null) {
pGuiGraphics.drawCenteredString(this.font, SYMBOLS[this.animTicks % SYMBOLS.length], this.width / 2, row(8), 8421504);
} else {
pGuiGraphics.drawCenteredString(this.font, component, this.width / 2, row(8), 16711680);
}
super.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
}
public void error(Component pError) {
this.errorMessage = pError;
this.minecraft.getNarrator().sayNow(pError);
this.minecraft.execute(() -> {
this.removeWidget(this.cancelOrBackButton);
this.cancelOrBackButton = this.addRenderableWidget(Button.builder(CommonComponents.GUI_BACK, (p_88790_) -> {
this.cancelOrBackButtonClicked();
}).bounds(this.width / 2 - 106, this.height / 4 + 120 + 12, 200, 20).build());
});
}
public void setTitle(Component pTitle) {
this.title = pTitle;
}
public boolean aborted() {
return this.aborted;
}
}
@@ -0,0 +1,217 @@
package com.mojang.realmsclient.gui.screens;
import com.mojang.realmsclient.client.RealmsClient;
import com.mojang.realmsclient.dto.RealmsNotification;
import com.mojang.realmsclient.exception.RealmsServiceException;
import com.mojang.realmsclient.gui.RealmsDataFetcher;
import com.mojang.realmsclient.gui.task.DataFetcher;
import java.util.Objects;
import javax.annotation.Nullable;
import net.minecraft.Util;
import net.minecraft.client.GameNarrator;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.screens.TitleScreen;
import net.minecraft.realms.RealmsScreen;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class RealmsNotificationsScreen extends RealmsScreen {
private static final ResourceLocation INVITE_ICON_LOCATION = new ResourceLocation("realms", "textures/gui/realms/invite_icon.png");
private static final ResourceLocation TRIAL_ICON_LOCATION = new ResourceLocation("realms", "textures/gui/realms/trial_icon.png");
private static final ResourceLocation NEWS_ICON_LOCATION = new ResourceLocation("realms", "textures/gui/realms/news_notification_mainscreen.png");
private static final ResourceLocation UNSEEN_NOTIFICATION_ICON_LOCATION = new ResourceLocation("minecraft", "textures/gui/unseen_notification.png");
@Nullable
private DataFetcher.Subscription realmsDataSubscription;
@Nullable
private RealmsNotificationsScreen.DataFetcherConfiguration currentConfiguration;
private volatile int numberOfPendingInvites;
static boolean checkedMcoAvailability;
private static boolean trialAvailable;
static boolean validClient;
private static boolean hasUnreadNews;
private static boolean hasUnseenNotifications;
private final RealmsNotificationsScreen.DataFetcherConfiguration showAll = new RealmsNotificationsScreen.DataFetcherConfiguration() {
public DataFetcher.Subscription initDataFetcher(RealmsDataFetcher p_275318_) {
DataFetcher.Subscription datafetcher$subscription = p_275318_.dataFetcher.createSubscription();
RealmsNotificationsScreen.this.addNewsAndInvitesSubscriptions(p_275318_, datafetcher$subscription);
RealmsNotificationsScreen.this.addNotificationsSubscriptions(p_275318_, datafetcher$subscription);
return datafetcher$subscription;
}
public boolean showOldNotifications() {
return true;
}
};
private final RealmsNotificationsScreen.DataFetcherConfiguration onlyNotifications = new RealmsNotificationsScreen.DataFetcherConfiguration() {
public DataFetcher.Subscription initDataFetcher(RealmsDataFetcher p_275318_) {
DataFetcher.Subscription datafetcher$subscription = p_275318_.dataFetcher.createSubscription();
RealmsNotificationsScreen.this.addNotificationsSubscriptions(p_275318_, datafetcher$subscription);
return datafetcher$subscription;
}
public boolean showOldNotifications() {
return false;
}
};
public RealmsNotificationsScreen() {
super(GameNarrator.NO_TITLE);
}
public void init() {
this.checkIfMcoEnabled();
if (this.realmsDataSubscription != null) {
this.realmsDataSubscription.forceUpdate();
}
}
public void added() {
super.added();
this.minecraft.realmsDataFetcher().notificationsTask.reset();
}
@Nullable
private RealmsNotificationsScreen.DataFetcherConfiguration getConfiguration() {
boolean flag = this.inTitleScreen() && validClient;
if (!flag) {
return null;
} else {
return this.getRealmsNotificationsEnabled() ? this.showAll : this.onlyNotifications;
}
}
public void tick() {
RealmsNotificationsScreen.DataFetcherConfiguration realmsnotificationsscreen$datafetcherconfiguration = this.getConfiguration();
if (!Objects.equals(this.currentConfiguration, realmsnotificationsscreen$datafetcherconfiguration)) {
this.currentConfiguration = realmsnotificationsscreen$datafetcherconfiguration;
if (this.currentConfiguration != null) {
this.realmsDataSubscription = this.currentConfiguration.initDataFetcher(this.minecraft.realmsDataFetcher());
} else {
this.realmsDataSubscription = null;
}
}
if (this.realmsDataSubscription != null) {
this.realmsDataSubscription.tick();
}
}
private boolean getRealmsNotificationsEnabled() {
return this.minecraft.options.realmsNotifications().get();
}
private boolean inTitleScreen() {
return this.minecraft.screen instanceof TitleScreen;
}
private void checkIfMcoEnabled() {
if (!checkedMcoAvailability) {
checkedMcoAvailability = true;
(new Thread("Realms Notification Availability checker #1") {
public void run() {
RealmsClient realmsclient = RealmsClient.create();
try {
RealmsClient.CompatibleVersionResponse realmsclient$compatibleversionresponse = realmsclient.clientCompatible();
if (realmsclient$compatibleversionresponse != RealmsClient.CompatibleVersionResponse.COMPATIBLE) {
return;
}
} catch (RealmsServiceException realmsserviceexception) {
if (realmsserviceexception.httpResultCode != 401) {
RealmsNotificationsScreen.checkedMcoAvailability = false;
}
return;
}
RealmsNotificationsScreen.validClient = true;
}
}).start();
}
}
public void render(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) {
if (validClient) {
this.drawIcons(pGuiGraphics);
}
super.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
}
private void drawIcons(GuiGraphics pGuiGraphics) {
int i = this.numberOfPendingInvites;
int j = 24;
int k = this.height / 4 + 48;
int l = this.width / 2 + 80;
int i1 = k + 48 + 2;
int j1 = 0;
if (hasUnseenNotifications) {
pGuiGraphics.blit(UNSEEN_NOTIFICATION_ICON_LOCATION, l - j1 + 5, i1 + 3, 0.0F, 0.0F, 10, 10, 10, 10);
j1 += 14;
}
if (this.currentConfiguration != null && this.currentConfiguration.showOldNotifications()) {
if (hasUnreadNews) {
pGuiGraphics.pose().pushPose();
pGuiGraphics.pose().scale(0.4F, 0.4F, 0.4F);
pGuiGraphics.blit(NEWS_ICON_LOCATION, (int)((double)(l + 2 - j1) * 2.5D), (int)((double)i1 * 2.5D), 0.0F, 0.0F, 40, 40, 40, 40);
pGuiGraphics.pose().popPose();
j1 += 14;
}
if (i != 0) {
pGuiGraphics.blit(INVITE_ICON_LOCATION, l - j1, i1, 0.0F, 0.0F, 18, 15, 18, 30);
j1 += 16;
}
if (trialAvailable) {
int k1 = 0;
if ((Util.getMillis() / 800L & 1L) == 1L) {
k1 = 8;
}
pGuiGraphics.blit(TRIAL_ICON_LOCATION, l + 4 - j1, i1 + 4, 0.0F, (float)k1, 8, 8, 8, 16);
}
}
}
void addNewsAndInvitesSubscriptions(RealmsDataFetcher pDataFetcher, DataFetcher.Subscription pSubscription) {
pSubscription.subscribe(pDataFetcher.pendingInvitesTask, (p_239521_) -> {
this.numberOfPendingInvites = p_239521_;
});
pSubscription.subscribe(pDataFetcher.trialAvailabilityTask, (p_239494_) -> {
trialAvailable = p_239494_;
});
pSubscription.subscribe(pDataFetcher.newsTask, (p_238946_) -> {
pDataFetcher.newsManager.updateUnreadNews(p_238946_);
hasUnreadNews = pDataFetcher.newsManager.hasUnreadNews();
});
}
void addNotificationsSubscriptions(RealmsDataFetcher pDataFetcher, DataFetcher.Subscription pSubscription) {
pSubscription.subscribe(pDataFetcher.notificationsTask, (p_274637_) -> {
hasUnseenNotifications = false;
for(RealmsNotification realmsnotification : p_274637_) {
if (!realmsnotification.seen()) {
hasUnseenNotifications = true;
break;
}
}
});
}
@OnlyIn(Dist.CLIENT)
interface DataFetcherConfiguration {
DataFetcher.Subscription initDataFetcher(RealmsDataFetcher pDataFetcher);
boolean showOldNotifications();
}
}
@@ -0,0 +1,53 @@
package com.mojang.realmsclient.gui.screens;
import net.minecraft.Util;
import net.minecraft.client.GameNarrator;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.MultiLineLabel;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.realms.RealmsScreen;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class RealmsParentalConsentScreen extends RealmsScreen {
private static final Component MESSAGE = Component.translatable("mco.account.privacyinfo");
private final Screen nextScreen;
private MultiLineLabel messageLines = MultiLineLabel.EMPTY;
public RealmsParentalConsentScreen(Screen pNextScreen) {
super(GameNarrator.NO_TITLE);
this.nextScreen = pNextScreen;
}
public void init() {
Component component = Component.translatable("mco.account.update");
Component component1 = CommonComponents.GUI_BACK;
int i = Math.max(this.font.width(component), this.font.width(component1)) + 30;
Component component2 = Component.translatable("mco.account.privacy.info");
int j = (int)((double)this.font.width(component2) * 1.2D);
this.addRenderableWidget(Button.builder(component2, (p_88873_) -> {
Util.getPlatform().openUri("https://aka.ms/MinecraftGDPR");
}).bounds(this.width / 2 - j / 2, row(11), j, 20).build());
this.addRenderableWidget(Button.builder(component, (p_88871_) -> {
Util.getPlatform().openUri("https://aka.ms/UpdateMojangAccount");
}).bounds(this.width / 2 - (i + 5), row(13), i, 20).build());
this.addRenderableWidget(Button.builder(component1, (p_280730_) -> {
this.minecraft.setScreen(this.nextScreen);
}).bounds(this.width / 2 + 5, row(13), i, 20).build());
this.messageLines = MultiLineLabel.create(this.font, MESSAGE, (int)Math.round((double)this.width * 0.9D));
}
public Component getNarrationMessage() {
return MESSAGE;
}
public void render(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) {
this.renderBackground(pGuiGraphics);
this.messageLines.renderCentered(pGuiGraphics, this.width / 2, 15, 15, 16777215);
super.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
}
}
@@ -0,0 +1,288 @@
package com.mojang.realmsclient.gui.screens;
import com.mojang.logging.LogUtils;
import com.mojang.realmsclient.RealmsMainScreen;
import com.mojang.realmsclient.client.RealmsClient;
import com.mojang.realmsclient.dto.PendingInvite;
import com.mojang.realmsclient.exception.RealmsServiceException;
import com.mojang.realmsclient.gui.RowButton;
import com.mojang.realmsclient.util.RealmsUtil;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.ObjectSelectionList;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.realms.RealmsObjectSelectionList;
import net.minecraft.realms.RealmsScreen;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class RealmsPendingInvitesScreen extends RealmsScreen {
static final Logger LOGGER = LogUtils.getLogger();
static final ResourceLocation ACCEPT_ICON_LOCATION = new ResourceLocation("realms", "textures/gui/realms/accept_icon.png");
static final ResourceLocation REJECT_ICON_LOCATION = new ResourceLocation("realms", "textures/gui/realms/reject_icon.png");
private static final Component NO_PENDING_INVITES_TEXT = Component.translatable("mco.invites.nopending");
static final Component ACCEPT_INVITE_TOOLTIP = Component.translatable("mco.invites.button.accept");
static final Component REJECT_INVITE_TOOLTIP = Component.translatable("mco.invites.button.reject");
private final Screen lastScreen;
@Nullable
Component toolTip;
boolean loaded;
RealmsPendingInvitesScreen.PendingInvitationSelectionList pendingInvitationSelectionList;
int selectedInvite = -1;
private Button acceptButton;
private Button rejectButton;
public RealmsPendingInvitesScreen(Screen pLastScreen, Component pTitle) {
super(pTitle);
this.lastScreen = pLastScreen;
}
public void init() {
this.pendingInvitationSelectionList = new RealmsPendingInvitesScreen.PendingInvitationSelectionList();
(new Thread("Realms-pending-invitations-fetcher") {
public void run() {
RealmsClient realmsclient = RealmsClient.create();
try {
List<PendingInvite> list = realmsclient.pendingInvites().pendingInvites;
List<RealmsPendingInvitesScreen.Entry> list1 = list.stream().map((p_88969_) -> {
return RealmsPendingInvitesScreen.this.new Entry(p_88969_);
}).collect(Collectors.toList());
RealmsPendingInvitesScreen.this.minecraft.execute(() -> {
RealmsPendingInvitesScreen.this.pendingInvitationSelectionList.replaceEntries(list1);
});
} catch (RealmsServiceException realmsserviceexception) {
RealmsPendingInvitesScreen.LOGGER.error("Couldn't list invites");
} finally {
RealmsPendingInvitesScreen.this.loaded = true;
}
}
}).start();
this.addWidget(this.pendingInvitationSelectionList);
this.acceptButton = this.addRenderableWidget(Button.builder(Component.translatable("mco.invites.button.accept"), (p_88940_) -> {
this.accept(this.selectedInvite);
this.selectedInvite = -1;
this.updateButtonStates();
}).bounds(this.width / 2 - 174, this.height - 32, 100, 20).build());
this.addRenderableWidget(Button.builder(CommonComponents.GUI_DONE, (p_280731_) -> {
this.minecraft.setScreen(new RealmsMainScreen(this.lastScreen));
}).bounds(this.width / 2 - 50, this.height - 32, 100, 20).build());
this.rejectButton = this.addRenderableWidget(Button.builder(Component.translatable("mco.invites.button.reject"), (p_88920_) -> {
this.reject(this.selectedInvite);
this.selectedInvite = -1;
this.updateButtonStates();
}).bounds(this.width / 2 + 74, this.height - 32, 100, 20).build());
this.updateButtonStates();
}
public boolean keyPressed(int pKeyCode, int pScanCode, int pModifiers) {
if (pKeyCode == 256) {
this.minecraft.setScreen(new RealmsMainScreen(this.lastScreen));
return true;
} else {
return super.keyPressed(pKeyCode, pScanCode, pModifiers);
}
}
void updateList(int pIndex) {
this.pendingInvitationSelectionList.removeAtIndex(pIndex);
}
void reject(final int pIndex) {
if (pIndex < this.pendingInvitationSelectionList.getItemCount()) {
(new Thread("Realms-reject-invitation") {
public void run() {
try {
RealmsClient realmsclient = RealmsClient.create();
realmsclient.rejectInvitation((RealmsPendingInvitesScreen.this.pendingInvitationSelectionList.children().get(pIndex)).pendingInvite.invitationId);
RealmsPendingInvitesScreen.this.minecraft.execute(() -> {
RealmsPendingInvitesScreen.this.updateList(pIndex);
});
} catch (RealmsServiceException realmsserviceexception) {
RealmsPendingInvitesScreen.LOGGER.error("Couldn't reject invite");
}
}
}).start();
}
}
void accept(final int pIndex) {
if (pIndex < this.pendingInvitationSelectionList.getItemCount()) {
(new Thread("Realms-accept-invitation") {
public void run() {
try {
RealmsClient realmsclient = RealmsClient.create();
realmsclient.acceptInvitation((RealmsPendingInvitesScreen.this.pendingInvitationSelectionList.children().get(pIndex)).pendingInvite.invitationId);
RealmsPendingInvitesScreen.this.minecraft.execute(() -> {
RealmsPendingInvitesScreen.this.updateList(pIndex);
});
} catch (RealmsServiceException realmsserviceexception) {
RealmsPendingInvitesScreen.LOGGER.error("Couldn't accept invite");
}
}
}).start();
}
}
public void render(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) {
this.toolTip = null;
this.renderBackground(pGuiGraphics);
this.pendingInvitationSelectionList.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
pGuiGraphics.drawCenteredString(this.font, this.title, this.width / 2, 12, 16777215);
if (this.toolTip != null) {
this.renderMousehoverTooltip(pGuiGraphics, this.toolTip, pMouseX, pMouseY);
}
if (this.pendingInvitationSelectionList.getItemCount() == 0 && this.loaded) {
pGuiGraphics.drawCenteredString(this.font, NO_PENDING_INVITES_TEXT, this.width / 2, this.height / 2 - 20, 16777215);
}
super.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
}
protected void renderMousehoverTooltip(GuiGraphics pGuiGraphics, @Nullable Component pTooltip, int pMouseX, int pMouseY) {
if (pTooltip != null) {
int i = pMouseX + 12;
int j = pMouseY - 12;
int k = this.font.width(pTooltip);
pGuiGraphics.fillGradient(i - 3, j - 3, i + k + 3, j + 8 + 3, -1073741824, -1073741824);
pGuiGraphics.drawString(this.font, pTooltip, i, j, 16777215);
}
}
void updateButtonStates() {
this.acceptButton.visible = this.shouldAcceptAndRejectButtonBeVisible(this.selectedInvite);
this.rejectButton.visible = this.shouldAcceptAndRejectButtonBeVisible(this.selectedInvite);
}
private boolean shouldAcceptAndRejectButtonBeVisible(int p_88963_) {
return p_88963_ != -1;
}
@OnlyIn(Dist.CLIENT)
class Entry extends ObjectSelectionList.Entry<RealmsPendingInvitesScreen.Entry> {
private static final int TEXT_LEFT = 38;
final PendingInvite pendingInvite;
private final List<RowButton> rowButtons;
Entry(PendingInvite pPendingInvite) {
this.pendingInvite = pPendingInvite;
this.rowButtons = Arrays.asList(new RealmsPendingInvitesScreen.Entry.AcceptRowButton(), new RealmsPendingInvitesScreen.Entry.RejectRowButton());
}
public void render(GuiGraphics pGuiGraphics, int pIndex, int pTop, int pLeft, int pWidth, int pHeight, int pMouseX, int pMouseY, boolean p_282274_, float pPartialTick) {
this.renderPendingInvitationItem(pGuiGraphics, this.pendingInvite, pLeft, pTop, pMouseX, pMouseY);
}
public boolean mouseClicked(double pMouseX, double pMouseY, int pButton) {
RowButton.rowButtonMouseClicked(RealmsPendingInvitesScreen.this.pendingInvitationSelectionList, this, this.rowButtons, pButton, pMouseX, pMouseY);
return true;
}
private void renderPendingInvitationItem(GuiGraphics pGuiGraphics, PendingInvite pPendingInvite, int pX, int pY, int pMouseX, int pMouseY) {
pGuiGraphics.drawString(RealmsPendingInvitesScreen.this.font, pPendingInvite.worldName, pX + 38, pY + 1, 16777215, false);
pGuiGraphics.drawString(RealmsPendingInvitesScreen.this.font, pPendingInvite.worldOwnerName, pX + 38, pY + 12, 7105644, false);
pGuiGraphics.drawString(RealmsPendingInvitesScreen.this.font, RealmsUtil.convertToAgePresentationFromInstant(pPendingInvite.date), pX + 38, pY + 24, 7105644, false);
RowButton.drawButtonsInRow(pGuiGraphics, this.rowButtons, RealmsPendingInvitesScreen.this.pendingInvitationSelectionList, pX, pY, pMouseX, pMouseY);
RealmsUtil.renderPlayerFace(pGuiGraphics, pX, pY, 32, pPendingInvite.worldOwnerUuid);
}
public Component getNarration() {
Component component = CommonComponents.joinLines(Component.literal(this.pendingInvite.worldName), Component.literal(this.pendingInvite.worldOwnerName), RealmsUtil.convertToAgePresentationFromInstant(this.pendingInvite.date));
return Component.translatable("narrator.select", component);
}
@OnlyIn(Dist.CLIENT)
class AcceptRowButton extends RowButton {
AcceptRowButton() {
super(15, 15, 215, 5);
}
protected void draw(GuiGraphics p_282151_, int p_283695_, int p_282436_, boolean p_282168_) {
float f = p_282168_ ? 19.0F : 0.0F;
p_282151_.blit(RealmsPendingInvitesScreen.ACCEPT_ICON_LOCATION, p_283695_, p_282436_, f, 0.0F, 18, 18, 37, 18);
if (p_282168_) {
RealmsPendingInvitesScreen.this.toolTip = RealmsPendingInvitesScreen.ACCEPT_INVITE_TOOLTIP;
}
}
public void onClick(int p_89029_) {
RealmsPendingInvitesScreen.this.accept(p_89029_);
}
}
@OnlyIn(Dist.CLIENT)
class RejectRowButton extends RowButton {
RejectRowButton() {
super(15, 15, 235, 5);
}
protected void draw(GuiGraphics p_282457_, int p_281421_, int p_281260_, boolean p_281476_) {
float f = p_281476_ ? 19.0F : 0.0F;
p_282457_.blit(RealmsPendingInvitesScreen.REJECT_ICON_LOCATION, p_281421_, p_281260_, f, 0.0F, 18, 18, 37, 18);
if (p_281476_) {
RealmsPendingInvitesScreen.this.toolTip = RealmsPendingInvitesScreen.REJECT_INVITE_TOOLTIP;
}
}
public void onClick(int p_89039_) {
RealmsPendingInvitesScreen.this.reject(p_89039_);
}
}
}
@OnlyIn(Dist.CLIENT)
class PendingInvitationSelectionList extends RealmsObjectSelectionList<RealmsPendingInvitesScreen.Entry> {
public PendingInvitationSelectionList() {
super(RealmsPendingInvitesScreen.this.width, RealmsPendingInvitesScreen.this.height, 32, RealmsPendingInvitesScreen.this.height - 40, 36);
}
public void removeAtIndex(int pIndex) {
this.remove(pIndex);
}
public int getMaxPosition() {
return this.getItemCount() * 36;
}
public int getRowWidth() {
return 260;
}
public void renderBackground(GuiGraphics pGuiGraphics) {
RealmsPendingInvitesScreen.this.renderBackground(pGuiGraphics);
}
public void selectItem(int pIndex) {
super.selectItem(pIndex);
this.selectInviteListItem(pIndex);
}
public void selectInviteListItem(int pIndex) {
RealmsPendingInvitesScreen.this.selectedInvite = pIndex;
RealmsPendingInvitesScreen.this.updateButtonStates();
}
public void setSelected(@Nullable RealmsPendingInvitesScreen.Entry pSelected) {
super.setSelected(pSelected);
RealmsPendingInvitesScreen.this.selectedInvite = this.children().indexOf(pSelected);
RealmsPendingInvitesScreen.this.updateButtonStates();
}
}
}
@@ -0,0 +1,312 @@
package com.mojang.realmsclient.gui.screens;
import com.mojang.logging.LogUtils;
import com.mojang.realmsclient.client.RealmsClient;
import com.mojang.realmsclient.dto.Ops;
import com.mojang.realmsclient.dto.PlayerInfo;
import com.mojang.realmsclient.dto.RealmsServer;
import com.mojang.realmsclient.exception.RealmsServiceException;
import com.mojang.realmsclient.util.RealmsUtil;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nullable;
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.ImageButton;
import net.minecraft.client.gui.components.ObjectSelectionList;
import net.minecraft.client.gui.components.Tooltip;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.realms.RealmsObjectSelectionList;
import net.minecraft.realms.RealmsScreen;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class RealmsPlayerScreen extends RealmsScreen {
private static final Logger LOGGER = LogUtils.getLogger();
static final ResourceLocation OP_ICON_LOCATION = new ResourceLocation("realms", "textures/gui/realms/op_icon.png");
static final ResourceLocation USER_ICON_LOCATION = new ResourceLocation("realms", "textures/gui/realms/user_icon.png");
static final ResourceLocation CROSS_ICON_LOCATION = new ResourceLocation("realms", "textures/gui/realms/cross_player_icon.png");
private static final ResourceLocation OPTIONS_BACKGROUND = new ResourceLocation("minecraft", "textures/gui/options_background.png");
private static final Component QUESTION_TITLE = Component.translatable("mco.question");
static final Component NORMAL_USER_TOOLTIP = Component.translatable("mco.configure.world.invites.normal.tooltip");
static final Component OP_TOOLTIP = Component.translatable("mco.configure.world.invites.ops.tooltip");
static final Component REMOVE_ENTRY_TOOLTIP = Component.translatable("mco.configure.world.invites.remove.tooltip");
private static final int NO_ENTRY_SELECTED = -1;
private final RealmsConfigureWorldScreen lastScreen;
final RealmsServer serverData;
RealmsPlayerScreen.InvitedObjectSelectionList invitedObjectSelectionList;
int column1X;
int columnWidth;
private Button removeButton;
private Button opdeopButton;
int playerIndex = -1;
private boolean stateChanged;
public RealmsPlayerScreen(RealmsConfigureWorldScreen pLastScreen, RealmsServer pServerData) {
super(Component.translatable("mco.configure.world.players.title"));
this.lastScreen = pLastScreen;
this.serverData = pServerData;
}
public void init() {
this.column1X = this.width / 2 - 160;
this.columnWidth = 150;
int i = this.width / 2 + 12;
this.invitedObjectSelectionList = new RealmsPlayerScreen.InvitedObjectSelectionList();
this.invitedObjectSelectionList.setLeftPos(this.column1X);
this.addWidget(this.invitedObjectSelectionList);
for(PlayerInfo playerinfo : this.serverData.players) {
this.invitedObjectSelectionList.addEntry(playerinfo);
}
this.playerIndex = -1;
this.addRenderableWidget(Button.builder(Component.translatable("mco.configure.world.buttons.invite"), (p_280732_) -> {
this.minecraft.setScreen(new RealmsInviteScreen(this.lastScreen, this, this.serverData));
}).bounds(i, row(1), this.columnWidth + 10, 20).build());
this.removeButton = this.addRenderableWidget(Button.builder(Component.translatable("mco.configure.world.invites.remove.tooltip"), (p_278866_) -> {
this.uninvite(this.playerIndex);
}).bounds(i, row(7), this.columnWidth + 10, 20).build());
this.opdeopButton = this.addRenderableWidget(Button.builder(Component.translatable("mco.configure.world.invites.ops.tooltip"), (p_278869_) -> {
if (this.serverData.players.get(this.playerIndex).isOperator()) {
this.deop(this.playerIndex);
} else {
this.op(this.playerIndex);
}
}).bounds(i, row(9), this.columnWidth + 10, 20).build());
this.addRenderableWidget(Button.builder(CommonComponents.GUI_BACK, (p_89122_) -> {
this.backButtonClicked();
}).bounds(i + this.columnWidth / 2 + 2, row(12), this.columnWidth / 2 + 10 - 2, 20).build());
this.updateButtonStates();
}
void updateButtonStates() {
this.removeButton.visible = this.shouldRemoveAndOpdeopButtonBeVisible(this.playerIndex);
this.opdeopButton.visible = this.shouldRemoveAndOpdeopButtonBeVisible(this.playerIndex);
this.invitedObjectSelectionList.updateButtons();
}
private boolean shouldRemoveAndOpdeopButtonBeVisible(int p_89191_) {
return p_89191_ != -1;
}
public boolean keyPressed(int pKeyCode, int pScanCode, int pModifiers) {
if (pKeyCode == 256) {
this.backButtonClicked();
return true;
} else {
return super.keyPressed(pKeyCode, pScanCode, pModifiers);
}
}
private void backButtonClicked() {
if (this.stateChanged) {
this.minecraft.setScreen(this.lastScreen.getNewScreen());
} else {
this.minecraft.setScreen(this.lastScreen);
}
}
void op(int pIndex) {
RealmsClient realmsclient = RealmsClient.create();
String s = this.serverData.players.get(pIndex).getUuid();
try {
this.updateOps(realmsclient.op(this.serverData.id, s));
} catch (RealmsServiceException realmsserviceexception) {
LOGGER.error("Couldn't op the user");
}
this.updateButtonStates();
}
void deop(int pIndex) {
RealmsClient realmsclient = RealmsClient.create();
String s = this.serverData.players.get(pIndex).getUuid();
try {
this.updateOps(realmsclient.deop(this.serverData.id, s));
} catch (RealmsServiceException realmsserviceexception) {
LOGGER.error("Couldn't deop the user");
}
this.updateButtonStates();
}
private void updateOps(Ops pOps) {
for(PlayerInfo playerinfo : this.serverData.players) {
playerinfo.setOperator(pOps.ops.contains(playerinfo.getName()));
}
}
void uninvite(int pIndex) {
this.updateButtonStates();
if (pIndex >= 0 && pIndex < this.serverData.players.size()) {
PlayerInfo playerinfo = this.serverData.players.get(pIndex);
RealmsConfirmScreen realmsconfirmscreen = new RealmsConfirmScreen((p_278868_) -> {
if (p_278868_) {
RealmsClient realmsclient = RealmsClient.create();
try {
realmsclient.uninvite(this.serverData.id, playerinfo.getUuid());
} catch (RealmsServiceException realmsserviceexception) {
LOGGER.error("Couldn't uninvite user");
}
this.serverData.players.remove(this.playerIndex);
this.playerIndex = -1;
this.updateButtonStates();
}
this.stateChanged = true;
this.minecraft.setScreen(this);
}, QUESTION_TITLE, Component.translatable("mco.configure.world.uninvite.player", playerinfo.getName()));
this.minecraft.setScreen(realmsconfirmscreen);
}
}
public void render(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) {
this.renderBackground(pGuiGraphics);
this.invitedObjectSelectionList.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
pGuiGraphics.drawCenteredString(this.font, this.title, this.width / 2, 17, 16777215);
int i = row(12) + 20;
pGuiGraphics.setColor(0.25F, 0.25F, 0.25F, 1.0F);
pGuiGraphics.blit(OPTIONS_BACKGROUND, 0, i, 0.0F, 0.0F, this.width, this.height - i, 32, 32);
pGuiGraphics.setColor(1.0F, 1.0F, 1.0F, 1.0F);
String s = this.serverData.players != null ? Integer.toString(this.serverData.players.size()) : "0";
pGuiGraphics.drawString(this.font, Component.translatable("mco.configure.world.invited.number", s), this.column1X, row(0), 10526880, false);
super.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
}
@OnlyIn(Dist.CLIENT)
class Entry extends ObjectSelectionList.Entry<RealmsPlayerScreen.Entry> {
private static final int X_OFFSET = 3;
private static final int Y_PADDING = 1;
private static final int BUTTON_WIDTH = 8;
private static final int BUTTON_HEIGHT = 7;
private final PlayerInfo playerInfo;
private final List<AbstractWidget> children = new ArrayList<>();
private final ImageButton removeButton;
private final ImageButton makeOpButton;
private final ImageButton removeOpButton;
public Entry(PlayerInfo pPlayerInfo) {
this.playerInfo = pPlayerInfo;
int i = RealmsPlayerScreen.this.serverData.players.indexOf(this.playerInfo);
int j = RealmsPlayerScreen.this.invitedObjectSelectionList.getRowRight() - 16 - 9;
int k = RealmsPlayerScreen.this.invitedObjectSelectionList.getRowTop(i) + 1;
this.removeButton = new ImageButton(j, k, 8, 7, 0, 0, 7, RealmsPlayerScreen.CROSS_ICON_LOCATION, 8, 14, (p_279099_) -> {
RealmsPlayerScreen.this.uninvite(i);
});
this.removeButton.setTooltip(Tooltip.create(RealmsPlayerScreen.REMOVE_ENTRY_TOOLTIP));
this.children.add(this.removeButton);
j += 11;
this.makeOpButton = new ImageButton(j, k, 8, 7, 0, 0, 7, RealmsPlayerScreen.USER_ICON_LOCATION, 8, 14, (p_279435_) -> {
RealmsPlayerScreen.this.op(i);
});
this.makeOpButton.setTooltip(Tooltip.create(RealmsPlayerScreen.NORMAL_USER_TOOLTIP));
this.children.add(this.makeOpButton);
this.removeOpButton = new ImageButton(j, k, 8, 7, 0, 0, 7, RealmsPlayerScreen.OP_ICON_LOCATION, 8, 14, (p_279383_) -> {
RealmsPlayerScreen.this.deop(i);
});
this.removeOpButton.setTooltip(Tooltip.create(RealmsPlayerScreen.OP_TOOLTIP));
this.children.add(this.removeOpButton);
this.updateButtons();
}
public void updateButtons() {
this.makeOpButton.visible = !this.playerInfo.isOperator();
this.removeOpButton.visible = !this.makeOpButton.visible;
}
public boolean mouseClicked(double pMouseX, double pMouseY, int pButton) {
if (!this.makeOpButton.mouseClicked(pMouseX, pMouseY, pButton)) {
this.removeOpButton.mouseClicked(pMouseX, pMouseY, pButton);
}
this.removeButton.mouseClicked(pMouseX, pMouseY, pButton);
return true;
}
public void render(GuiGraphics pGuiGraphics, int pIndex, int pTop, int pLeft, int pWidth, int pHeight, int pMouseX, int pMouseY, boolean p_283067_, float pPartialTick) {
int i;
if (!this.playerInfo.getAccepted()) {
i = 10526880;
} else if (this.playerInfo.getOnline()) {
i = 8388479;
} else {
i = 16777215;
}
RealmsUtil.renderPlayerFace(pGuiGraphics, RealmsPlayerScreen.this.column1X + 2 + 2, pTop + 1, 8, this.playerInfo.getUuid());
pGuiGraphics.drawString(RealmsPlayerScreen.this.font, this.playerInfo.getName(), RealmsPlayerScreen.this.column1X + 3 + 12, pTop + 1, i, false);
this.children.forEach((p_280738_) -> {
p_280738_.setY(pTop + 1);
p_280738_.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
});
}
public Component getNarration() {
return Component.translatable("narrator.select", this.playerInfo.getName());
}
}
@OnlyIn(Dist.CLIENT)
class InvitedObjectSelectionList extends RealmsObjectSelectionList<RealmsPlayerScreen.Entry> {
public InvitedObjectSelectionList() {
super(RealmsPlayerScreen.this.columnWidth + 10, RealmsPlayerScreen.row(12) + 20, RealmsPlayerScreen.row(1), RealmsPlayerScreen.row(12) + 20, 13);
}
public void updateButtons() {
if (RealmsPlayerScreen.this.playerIndex != -1) {
this.getEntry(RealmsPlayerScreen.this.playerIndex).updateButtons();
}
}
public void addEntry(PlayerInfo pPlayerInfo) {
this.addEntry(RealmsPlayerScreen.this.new Entry(pPlayerInfo));
}
public int getRowWidth() {
return (int)((double)this.width * 1.0D);
}
public void selectItem(int pIndex) {
super.selectItem(pIndex);
this.selectInviteListItem(pIndex);
}
public void selectInviteListItem(int pIndex) {
RealmsPlayerScreen.this.playerIndex = pIndex;
RealmsPlayerScreen.this.updateButtonStates();
}
public void setSelected(@Nullable RealmsPlayerScreen.Entry pSelected) {
super.setSelected(pSelected);
RealmsPlayerScreen.this.playerIndex = this.children().indexOf(pSelected);
RealmsPlayerScreen.this.updateButtonStates();
}
public void renderBackground(GuiGraphics pGuiGraphics) {
RealmsPlayerScreen.this.renderBackground(pGuiGraphics);
}
public int getScrollbarPosition() {
return RealmsPlayerScreen.this.column1X + this.width - 5;
}
public int getMaxPosition() {
return this.getItemCount() * 13;
}
}
}
@@ -0,0 +1,66 @@
package com.mojang.realmsclient.gui.screens;
import com.mojang.realmsclient.util.LevelType;
import com.mojang.realmsclient.util.WorldGenerationInfo;
import java.util.function.Consumer;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.CycleButton;
import net.minecraft.client.gui.components.EditBox;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.realms.RealmsScreen;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class RealmsResetNormalWorldScreen extends RealmsScreen {
private static final Component SEED_LABEL = Component.translatable("mco.reset.world.seed");
private final Consumer<WorldGenerationInfo> callback;
private EditBox seedEdit;
private LevelType levelType = LevelType.DEFAULT;
private boolean generateStructures = true;
private final Component buttonTitle;
public RealmsResetNormalWorldScreen(Consumer<WorldGenerationInfo> pCallback, Component pButtonTitle) {
super(Component.translatable("mco.reset.world.generate"));
this.callback = pCallback;
this.buttonTitle = pButtonTitle;
}
public void tick() {
this.seedEdit.tick();
super.tick();
}
public void init() {
this.seedEdit = new EditBox(this.minecraft.font, this.width / 2 - 100, row(2), 200, 20, (EditBox)null, Component.translatable("mco.reset.world.seed"));
this.seedEdit.setMaxLength(32);
this.addWidget(this.seedEdit);
this.setInitialFocus(this.seedEdit);
this.addRenderableWidget(CycleButton.builder(LevelType::getName).withValues(LevelType.values()).withInitialValue(this.levelType).create(this.width / 2 - 102, row(4), 205, 20, Component.translatable("selectWorld.mapType"), (p_167441_, p_167442_) -> {
this.levelType = p_167442_;
}));
this.addRenderableWidget(CycleButton.onOffBuilder(this.generateStructures).create(this.width / 2 - 102, row(6) - 2, 205, 20, Component.translatable("selectWorld.mapFeatures"), (p_167444_, p_167445_) -> {
this.generateStructures = p_167445_;
}));
this.addRenderableWidget(Button.builder(this.buttonTitle, (p_89291_) -> {
this.callback.accept(new WorldGenerationInfo(this.seedEdit.getValue(), this.levelType, this.generateStructures));
}).bounds(this.width / 2 - 102, row(12), 97, 20).build());
this.addRenderableWidget(Button.builder(CommonComponents.GUI_BACK, (p_89288_) -> {
this.onClose();
}).bounds(this.width / 2 + 8, row(12), 97, 20).build());
}
public void onClose() {
this.callback.accept((WorldGenerationInfo)null);
}
public void render(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) {
this.renderBackground(pGuiGraphics);
pGuiGraphics.drawCenteredString(this.font, this.title, this.width / 2, 17, 16777215);
pGuiGraphics.drawString(this.font, SEED_LABEL, this.width / 2 - 100, row(1), 10526880, false);
this.seedEdit.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
super.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
}
}
@@ -0,0 +1,211 @@
package com.mojang.realmsclient.gui.screens;
import com.mojang.logging.LogUtils;
import com.mojang.realmsclient.client.RealmsClient;
import com.mojang.realmsclient.dto.RealmsServer;
import com.mojang.realmsclient.dto.WorldTemplate;
import com.mojang.realmsclient.dto.WorldTemplatePaginatedList;
import com.mojang.realmsclient.exception.RealmsServiceException;
import com.mojang.realmsclient.util.WorldGenerationInfo;
import com.mojang.realmsclient.util.task.LongRunningTask;
import com.mojang.realmsclient.util.task.ResettingGeneratedWorldTask;
import com.mojang.realmsclient.util.task.ResettingTemplateWorldTask;
import com.mojang.realmsclient.util.task.SwitchSlotTask;
import javax.annotation.Nullable;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.realms.RealmsLabel;
import net.minecraft.realms.RealmsScreen;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class RealmsResetWorldScreen extends RealmsScreen {
static final Logger LOGGER = LogUtils.getLogger();
private final Screen lastScreen;
private final RealmsServer serverData;
private Component subtitle = Component.translatable("mco.reset.world.warning");
private Component buttonTitle = CommonComponents.GUI_CANCEL;
private int subtitleColor = 16711680;
private static final ResourceLocation SLOT_FRAME_LOCATION = new ResourceLocation("realms", "textures/gui/realms/slot_frame.png");
private static final ResourceLocation UPLOAD_LOCATION = new ResourceLocation("realms", "textures/gui/realms/upload.png");
private static final ResourceLocation ADVENTURE_MAP_LOCATION = new ResourceLocation("realms", "textures/gui/realms/adventure.png");
private static final ResourceLocation SURVIVAL_SPAWN_LOCATION = new ResourceLocation("realms", "textures/gui/realms/survival_spawn.png");
private static final ResourceLocation NEW_WORLD_LOCATION = new ResourceLocation("realms", "textures/gui/realms/new_world.png");
private static final ResourceLocation EXPERIENCE_LOCATION = new ResourceLocation("realms", "textures/gui/realms/experience.png");
private static final ResourceLocation INSPIRATION_LOCATION = new ResourceLocation("realms", "textures/gui/realms/inspiration.png");
WorldTemplatePaginatedList templates;
WorldTemplatePaginatedList adventuremaps;
WorldTemplatePaginatedList experiences;
WorldTemplatePaginatedList inspirations;
public int slot = -1;
private Component resetTitle = Component.translatable("mco.reset.world.resetting.screen.title");
private final Runnable resetWorldRunnable;
private final Runnable callback;
public RealmsResetWorldScreen(Screen pLastScreen, RealmsServer pServerData, Component pTitle, Runnable pResetWorldRunnable, Runnable pCallback) {
super(pTitle);
this.lastScreen = pLastScreen;
this.serverData = pServerData;
this.resetWorldRunnable = pResetWorldRunnable;
this.callback = pCallback;
}
public RealmsResetWorldScreen(Screen pLastScreen, RealmsServer pServerData, Runnable pResetWorldRunnable, Runnable pCallback) {
this(pLastScreen, pServerData, Component.translatable("mco.reset.world.title"), pResetWorldRunnable, pCallback);
}
public RealmsResetWorldScreen(Screen pLastScreen, RealmsServer pServerData, Component pTitle, Component pSubtitle, int pSubtitleColor, Component pButtonTitle, Runnable pResetWorldRunnable, Runnable pCallback) {
this(pLastScreen, pServerData, pTitle, pResetWorldRunnable, pCallback);
this.subtitle = pSubtitle;
this.subtitleColor = pSubtitleColor;
this.buttonTitle = pButtonTitle;
}
public void setSlot(int pSlot) {
this.slot = pSlot;
}
public void setResetTitle(Component pResetTitle) {
this.resetTitle = pResetTitle;
}
public void init() {
this.addRenderableWidget(Button.builder(this.buttonTitle, (p_280741_) -> {
this.minecraft.setScreen(this.lastScreen);
}).bounds(this.width / 2 - 40, row(14) - 10, 80, 20).build());
(new Thread("Realms-reset-world-fetcher") {
public void run() {
RealmsClient realmsclient = RealmsClient.create();
try {
WorldTemplatePaginatedList worldtemplatepaginatedlist = realmsclient.fetchWorldTemplates(1, 10, RealmsServer.WorldType.NORMAL);
WorldTemplatePaginatedList worldtemplatepaginatedlist1 = realmsclient.fetchWorldTemplates(1, 10, RealmsServer.WorldType.ADVENTUREMAP);
WorldTemplatePaginatedList worldtemplatepaginatedlist2 = realmsclient.fetchWorldTemplates(1, 10, RealmsServer.WorldType.EXPERIENCE);
WorldTemplatePaginatedList worldtemplatepaginatedlist3 = realmsclient.fetchWorldTemplates(1, 10, RealmsServer.WorldType.INSPIRATION);
RealmsResetWorldScreen.this.minecraft.execute(() -> {
RealmsResetWorldScreen.this.templates = worldtemplatepaginatedlist;
RealmsResetWorldScreen.this.adventuremaps = worldtemplatepaginatedlist1;
RealmsResetWorldScreen.this.experiences = worldtemplatepaginatedlist2;
RealmsResetWorldScreen.this.inspirations = worldtemplatepaginatedlist3;
});
} catch (RealmsServiceException realmsserviceexception) {
RealmsResetWorldScreen.LOGGER.error("Couldn't fetch templates in reset world", (Throwable)realmsserviceexception);
}
}
}).start();
this.addLabel(new RealmsLabel(this.subtitle, this.width / 2, 22, this.subtitleColor));
this.addRenderableWidget(new RealmsResetWorldScreen.FrameButton(this.frame(1), row(0) + 10, Component.translatable("mco.reset.world.generate"), NEW_WORLD_LOCATION, (p_280746_) -> {
this.minecraft.setScreen(new RealmsResetNormalWorldScreen(this::generationSelectionCallback, this.title));
}));
this.addRenderableWidget(new RealmsResetWorldScreen.FrameButton(this.frame(2), row(0) + 10, Component.translatable("mco.reset.world.upload"), UPLOAD_LOCATION, (p_280744_) -> {
this.minecraft.setScreen(new RealmsSelectFileToUploadScreen(this.serverData.id, this.slot != -1 ? this.slot : this.serverData.activeSlot, this, this.callback));
}));
this.addRenderableWidget(new RealmsResetWorldScreen.FrameButton(this.frame(3), row(0) + 10, Component.translatable("mco.reset.world.template"), SURVIVAL_SPAWN_LOCATION, (p_280742_) -> {
this.minecraft.setScreen(new RealmsSelectWorldTemplateScreen(Component.translatable("mco.reset.world.template"), this::templateSelectionCallback, RealmsServer.WorldType.NORMAL, this.templates));
}));
this.addRenderableWidget(new RealmsResetWorldScreen.FrameButton(this.frame(1), row(6) + 20, Component.translatable("mco.reset.world.adventure"), ADVENTURE_MAP_LOCATION, (p_280739_) -> {
this.minecraft.setScreen(new RealmsSelectWorldTemplateScreen(Component.translatable("mco.reset.world.adventure"), this::templateSelectionCallback, RealmsServer.WorldType.ADVENTUREMAP, this.adventuremaps));
}));
this.addRenderableWidget(new RealmsResetWorldScreen.FrameButton(this.frame(2), row(6) + 20, Component.translatable("mco.reset.world.experience"), EXPERIENCE_LOCATION, (p_280745_) -> {
this.minecraft.setScreen(new RealmsSelectWorldTemplateScreen(Component.translatable("mco.reset.world.experience"), this::templateSelectionCallback, RealmsServer.WorldType.EXPERIENCE, this.experiences));
}));
this.addRenderableWidget(new RealmsResetWorldScreen.FrameButton(this.frame(3), row(6) + 20, Component.translatable("mco.reset.world.inspiration"), INSPIRATION_LOCATION, (p_280740_) -> {
this.minecraft.setScreen(new RealmsSelectWorldTemplateScreen(Component.translatable("mco.reset.world.inspiration"), this::templateSelectionCallback, RealmsServer.WorldType.INSPIRATION, this.inspirations));
}));
}
public Component getNarrationMessage() {
return CommonComponents.joinForNarration(this.getTitle(), this.createLabelNarration());
}
public boolean keyPressed(int pKeyCode, int pScanCode, int pModifiers) {
if (pKeyCode == 256) {
this.minecraft.setScreen(this.lastScreen);
return true;
} else {
return super.keyPressed(pKeyCode, pScanCode, pModifiers);
}
}
private int frame(int p_89393_) {
return this.width / 2 - 130 + (p_89393_ - 1) * 100;
}
public void render(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) {
this.renderBackground(pGuiGraphics);
pGuiGraphics.drawCenteredString(this.font, this.title, this.width / 2, 7, 16777215);
super.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
}
void drawFrame(GuiGraphics pGuiGraphics, int pX, int pY, Component pText, ResourceLocation pAtlasLocation, boolean p_282720_, boolean p_282971_) {
if (p_282720_) {
pGuiGraphics.setColor(0.56F, 0.56F, 0.56F, 1.0F);
}
pGuiGraphics.blit(pAtlasLocation, pX + 2, pY + 14, 0.0F, 0.0F, 56, 56, 56, 56);
pGuiGraphics.blit(SLOT_FRAME_LOCATION, pX, pY + 12, 0.0F, 0.0F, 60, 60, 60, 60);
int i = p_282720_ ? 10526880 : 16777215;
pGuiGraphics.drawCenteredString(this.font, pText, pX + 30, pY, i);
pGuiGraphics.setColor(1.0F, 1.0F, 1.0F, 1.0F);
}
private void startTask(LongRunningTask pTask) {
this.minecraft.setScreen(new RealmsLongRunningMcoTaskScreen(this.lastScreen, pTask));
}
public void switchSlot(Runnable p_89383_) {
this.startTask(new SwitchSlotTask(this.serverData.id, this.slot, () -> {
this.minecraft.execute(p_89383_);
}));
}
private void templateSelectionCallback(@Nullable WorldTemplate p_167454_) {
this.minecraft.setScreen(this);
if (p_167454_ != null) {
this.resetWorld(() -> {
this.startTask(new ResettingTemplateWorldTask(p_167454_, this.serverData.id, this.resetTitle, this.resetWorldRunnable));
});
}
}
private void generationSelectionCallback(@Nullable WorldGenerationInfo p_167456_) {
this.minecraft.setScreen(this);
if (p_167456_ != null) {
this.resetWorld(() -> {
this.startTask(new ResettingGeneratedWorldTask(p_167456_, this.serverData.id, this.resetTitle, this.resetWorldRunnable));
});
}
}
private void resetWorld(Runnable p_167465_) {
if (this.slot == -1) {
p_167465_.run();
} else {
this.switchSlot(p_167465_);
}
}
@OnlyIn(Dist.CLIENT)
class FrameButton extends Button {
private final ResourceLocation image;
public FrameButton(int pX, int pY, Component pMessage, ResourceLocation pImage, Button.OnPress pOnPress) {
super(pX, pY, 60, 72, pMessage, pOnPress, DEFAULT_NARRATION);
this.image = pImage;
}
public void renderWidget(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) {
RealmsResetWorldScreen.this.drawFrame(pGuiGraphics, this.getX(), this.getY(), this.getMessage(), this.image, this.isHoveredOrFocused(), this.isMouseOver((double)pMouseX, (double)pMouseY));
}
}
}
@@ -0,0 +1,203 @@
package com.mojang.realmsclient.gui.screens;
import com.google.common.collect.Lists;
import com.mojang.logging.LogUtils;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.ObjectSelectionList;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.realms.RealmsLabel;
import net.minecraft.realms.RealmsObjectSelectionList;
import net.minecraft.realms.RealmsScreen;
import net.minecraft.world.level.storage.LevelStorageSource;
import net.minecraft.world.level.storage.LevelSummary;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class RealmsSelectFileToUploadScreen extends RealmsScreen {
private static final Logger LOGGER = LogUtils.getLogger();
private static final Component UNABLE_TO_LOAD_WORLD = Component.translatable("selectWorld.unable_to_load");
static final Component WORLD_TEXT = Component.translatable("selectWorld.world");
static final Component HARDCORE_TEXT = Component.translatable("mco.upload.hardcore").withStyle((p_264655_) -> {
return p_264655_.withColor(-65536);
});
static final Component CHEATS_TEXT = Component.translatable("selectWorld.cheats");
private static final DateFormat DATE_FORMAT = new SimpleDateFormat();
private final RealmsResetWorldScreen lastScreen;
private final long worldId;
private final int slotId;
Button uploadButton;
List<LevelSummary> levelList = Lists.newArrayList();
int selectedWorld = -1;
RealmsSelectFileToUploadScreen.WorldSelectionList worldSelectionList;
private final Runnable callback;
public RealmsSelectFileToUploadScreen(long pWorldId, int pSlotId, RealmsResetWorldScreen pLastScreen, Runnable pCallback) {
super(Component.translatable("mco.upload.select.world.title"));
this.lastScreen = pLastScreen;
this.worldId = pWorldId;
this.slotId = pSlotId;
this.callback = pCallback;
}
private void loadLevelList() throws Exception {
LevelStorageSource.LevelCandidates levelstoragesource$levelcandidates = this.minecraft.getLevelSource().findLevelCandidates();
this.levelList = this.minecraft.getLevelSource().loadLevelSummaries(levelstoragesource$levelcandidates).join().stream().filter((p_193517_) -> {
return !p_193517_.requiresManualConversion() && !p_193517_.isLocked();
}).collect(Collectors.toList());
for(LevelSummary levelsummary : this.levelList) {
this.worldSelectionList.addEntry(levelsummary);
}
}
public void init() {
this.worldSelectionList = new RealmsSelectFileToUploadScreen.WorldSelectionList();
try {
this.loadLevelList();
} catch (Exception exception) {
LOGGER.error("Couldn't load level list", (Throwable)exception);
this.minecraft.setScreen(new RealmsGenericErrorScreen(UNABLE_TO_LOAD_WORLD, Component.nullToEmpty(exception.getMessage()), this.lastScreen));
return;
}
this.addWidget(this.worldSelectionList);
this.uploadButton = this.addRenderableWidget(Button.builder(Component.translatable("mco.upload.button.name"), (p_231307_) -> {
this.upload();
}).bounds(this.width / 2 - 154, this.height - 32, 153, 20).build());
this.uploadButton.active = this.selectedWorld >= 0 && this.selectedWorld < this.levelList.size();
this.addRenderableWidget(Button.builder(CommonComponents.GUI_BACK, (p_280747_) -> {
this.minecraft.setScreen(this.lastScreen);
}).bounds(this.width / 2 + 6, this.height - 32, 153, 20).build());
this.addLabel(new RealmsLabel(Component.translatable("mco.upload.select.world.subtitle"), this.width / 2, row(-1), 10526880));
if (this.levelList.isEmpty()) {
this.addLabel(new RealmsLabel(Component.translatable("mco.upload.select.world.none"), this.width / 2, this.height / 2 - 20, 16777215));
}
}
public Component getNarrationMessage() {
return CommonComponents.joinForNarration(this.getTitle(), this.createLabelNarration());
}
private void upload() {
if (this.selectedWorld != -1 && !this.levelList.get(this.selectedWorld).isHardcore()) {
LevelSummary levelsummary = this.levelList.get(this.selectedWorld);
this.minecraft.setScreen(new RealmsUploadScreen(this.worldId, this.slotId, this.lastScreen, levelsummary, this.callback));
}
}
public void render(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) {
this.renderBackground(pGuiGraphics);
this.worldSelectionList.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
pGuiGraphics.drawCenteredString(this.font, this.title, this.width / 2, 13, 16777215);
super.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
}
public boolean keyPressed(int pKeyCode, int pScanCode, int pModifiers) {
if (pKeyCode == 256) {
this.minecraft.setScreen(this.lastScreen);
return true;
} else {
return super.keyPressed(pKeyCode, pScanCode, pModifiers);
}
}
static Component gameModeName(LevelSummary pLevelSummary) {
return pLevelSummary.getGameMode().getLongDisplayName();
}
static String formatLastPlayed(LevelSummary pLevelSummary) {
return DATE_FORMAT.format(new Date(pLevelSummary.getLastPlayed()));
}
@OnlyIn(Dist.CLIENT)
class Entry extends ObjectSelectionList.Entry<RealmsSelectFileToUploadScreen.Entry> {
private final LevelSummary levelSummary;
private final String name;
private final Component id;
private final Component info;
public Entry(LevelSummary pLevelSummary) {
this.levelSummary = pLevelSummary;
this.name = pLevelSummary.getLevelName();
this.id = Component.translatable("mco.upload.entry.id", pLevelSummary.getLevelId(), RealmsSelectFileToUploadScreen.formatLastPlayed(pLevelSummary));
Component component;
if (pLevelSummary.isHardcore()) {
component = RealmsSelectFileToUploadScreen.HARDCORE_TEXT;
} else {
component = RealmsSelectFileToUploadScreen.gameModeName(pLevelSummary);
}
if (pLevelSummary.hasCheats()) {
component = Component.translatable("mco.upload.entry.cheats", component.getString(), RealmsSelectFileToUploadScreen.CHEATS_TEXT);
}
this.info = component;
}
public void render(GuiGraphics pGuiGraphics, int pIndex, int pTop, int pLeft, int pWidth, int pHeight, int pMouseX, int pMouseY, boolean p_283120_, float pPartialTick) {
this.renderItem(pGuiGraphics, pIndex, pLeft, pTop);
}
public boolean mouseClicked(double pMouseX, double pMouseY, int pButton) {
RealmsSelectFileToUploadScreen.this.worldSelectionList.selectItem(RealmsSelectFileToUploadScreen.this.levelList.indexOf(this.levelSummary));
return true;
}
protected void renderItem(GuiGraphics pGuiGraphics, int pIndex, int pX, int pY) {
String s;
if (this.name.isEmpty()) {
s = RealmsSelectFileToUploadScreen.WORLD_TEXT + " " + (pIndex + 1);
} else {
s = this.name;
}
pGuiGraphics.drawString(RealmsSelectFileToUploadScreen.this.font, s, pX + 2, pY + 1, 16777215, false);
pGuiGraphics.drawString(RealmsSelectFileToUploadScreen.this.font, this.id, pX + 2, pY + 12, 8421504, false);
pGuiGraphics.drawString(RealmsSelectFileToUploadScreen.this.font, this.info, pX + 2, pY + 12 + 10, 8421504, false);
}
public Component getNarration() {
Component component = CommonComponents.joinLines(Component.literal(this.levelSummary.getLevelName()), Component.literal(RealmsSelectFileToUploadScreen.formatLastPlayed(this.levelSummary)), RealmsSelectFileToUploadScreen.gameModeName(this.levelSummary));
return Component.translatable("narrator.select", component);
}
}
@OnlyIn(Dist.CLIENT)
class WorldSelectionList extends RealmsObjectSelectionList<RealmsSelectFileToUploadScreen.Entry> {
public WorldSelectionList() {
super(RealmsSelectFileToUploadScreen.this.width, RealmsSelectFileToUploadScreen.this.height, RealmsSelectFileToUploadScreen.row(0), RealmsSelectFileToUploadScreen.this.height - 40, 36);
}
public void addEntry(LevelSummary pLevelSummary) {
this.addEntry(RealmsSelectFileToUploadScreen.this.new Entry(pLevelSummary));
}
public int getMaxPosition() {
return RealmsSelectFileToUploadScreen.this.levelList.size() * 36;
}
public void renderBackground(GuiGraphics pGuiGraphics) {
RealmsSelectFileToUploadScreen.this.renderBackground(pGuiGraphics);
}
public void setSelected(@Nullable RealmsSelectFileToUploadScreen.Entry pSelected) {
super.setSelected(pSelected);
RealmsSelectFileToUploadScreen.this.selectedWorld = this.children().indexOf(pSelected);
RealmsSelectFileToUploadScreen.this.uploadButton.active = RealmsSelectFileToUploadScreen.this.selectedWorld >= 0 && RealmsSelectFileToUploadScreen.this.selectedWorld < this.getItemCount() && !RealmsSelectFileToUploadScreen.this.levelList.get(RealmsSelectFileToUploadScreen.this.selectedWorld).isHardcore();
}
}
}
@@ -0,0 +1,474 @@
package com.mojang.realmsclient.gui.screens;
import com.google.common.collect.Lists;
import com.mojang.datafixers.util.Either;
import com.mojang.logging.LogUtils;
import com.mojang.realmsclient.client.RealmsClient;
import com.mojang.realmsclient.dto.RealmsServer;
import com.mojang.realmsclient.dto.WorldTemplate;
import com.mojang.realmsclient.dto.WorldTemplatePaginatedList;
import com.mojang.realmsclient.exception.RealmsServiceException;
import com.mojang.realmsclient.util.RealmsTextureManager;
import com.mojang.realmsclient.util.TextRenderingUtils;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import net.minecraft.ChatFormatting;
import net.minecraft.Util;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.ObjectSelectionList;
import net.minecraft.client.resources.language.I18n;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.realms.RealmsObjectSelectionList;
import net.minecraft.realms.RealmsScreen;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class RealmsSelectWorldTemplateScreen extends RealmsScreen {
static final Logger LOGGER = LogUtils.getLogger();
static final ResourceLocation LINK_ICON = new ResourceLocation("realms", "textures/gui/realms/link_icons.png");
static final ResourceLocation TRAILER_ICON = new ResourceLocation("realms", "textures/gui/realms/trailer_icons.png");
static final ResourceLocation SLOT_FRAME_LOCATION = new ResourceLocation("realms", "textures/gui/realms/slot_frame.png");
static final Component PUBLISHER_LINK_TOOLTIP = Component.translatable("mco.template.info.tooltip");
static final Component TRAILER_LINK_TOOLTIP = Component.translatable("mco.template.trailer.tooltip");
private final Consumer<WorldTemplate> callback;
RealmsSelectWorldTemplateScreen.WorldTemplateObjectSelectionList worldTemplateObjectSelectionList;
int selectedTemplate = -1;
private Button selectButton;
private Button trailerButton;
private Button publisherButton;
@Nullable
Component toolTip;
@Nullable
String currentLink;
private final RealmsServer.WorldType worldType;
int clicks;
@Nullable
private Component[] warning;
private String warningURL;
boolean displayWarning;
private boolean hoverWarning;
@Nullable
List<TextRenderingUtils.Line> noTemplatesMessage;
public RealmsSelectWorldTemplateScreen(Component pTitle, Consumer<WorldTemplate> pCallback, RealmsServer.WorldType pWorldType) {
this(pTitle, pCallback, pWorldType, (WorldTemplatePaginatedList)null);
}
public RealmsSelectWorldTemplateScreen(Component pTitle, Consumer<WorldTemplate> pCallback, RealmsServer.WorldType pWorldType, @Nullable WorldTemplatePaginatedList pWorldTemplatePaginatedList) {
super(pTitle);
this.callback = pCallback;
this.worldType = pWorldType;
if (pWorldTemplatePaginatedList == null) {
this.worldTemplateObjectSelectionList = new RealmsSelectWorldTemplateScreen.WorldTemplateObjectSelectionList();
this.fetchTemplatesAsync(new WorldTemplatePaginatedList(10));
} else {
this.worldTemplateObjectSelectionList = new RealmsSelectWorldTemplateScreen.WorldTemplateObjectSelectionList(Lists.newArrayList(pWorldTemplatePaginatedList.templates));
this.fetchTemplatesAsync(pWorldTemplatePaginatedList);
}
}
public void setWarning(Component... pWarning) {
this.warning = pWarning;
this.displayWarning = true;
}
public boolean mouseClicked(double pMouseX, double pMouseY, int pButton) {
if (this.hoverWarning && this.warningURL != null) {
Util.getPlatform().openUri("https://www.minecraft.net/realms/adventure-maps-in-1-9");
return true;
} else {
return super.mouseClicked(pMouseX, pMouseY, pButton);
}
}
public void init() {
this.worldTemplateObjectSelectionList = new RealmsSelectWorldTemplateScreen.WorldTemplateObjectSelectionList(this.worldTemplateObjectSelectionList.getTemplates());
this.trailerButton = this.addRenderableWidget(Button.builder(Component.translatable("mco.template.button.trailer"), (p_89701_) -> {
this.onTrailer();
}).bounds(this.width / 2 - 206, this.height - 32, 100, 20).build());
this.selectButton = this.addRenderableWidget(Button.builder(Component.translatable("mco.template.button.select"), (p_89696_) -> {
this.selectTemplate();
}).bounds(this.width / 2 - 100, this.height - 32, 100, 20).build());
Component component = this.worldType == RealmsServer.WorldType.MINIGAME ? CommonComponents.GUI_CANCEL : CommonComponents.GUI_BACK;
Button button = Button.builder(component, (p_89691_) -> {
this.onClose();
}).bounds(this.width / 2 + 6, this.height - 32, 100, 20).build();
this.addRenderableWidget(button);
this.publisherButton = this.addRenderableWidget(Button.builder(Component.translatable("mco.template.button.publisher"), (p_89679_) -> {
this.onPublish();
}).bounds(this.width / 2 + 112, this.height - 32, 100, 20).build());
this.selectButton.active = false;
this.trailerButton.visible = false;
this.publisherButton.visible = false;
this.addWidget(this.worldTemplateObjectSelectionList);
this.magicalSpecialHackyFocus(this.worldTemplateObjectSelectionList);
}
public Component getNarrationMessage() {
List<Component> list = Lists.newArrayListWithCapacity(2);
if (this.title != null) {
list.add(this.title);
}
if (this.warning != null) {
list.addAll(Arrays.asList(this.warning));
}
return CommonComponents.joinLines(list);
}
void updateButtonStates() {
this.publisherButton.visible = this.shouldPublisherBeVisible();
this.trailerButton.visible = this.shouldTrailerBeVisible();
this.selectButton.active = this.shouldSelectButtonBeActive();
}
private boolean shouldSelectButtonBeActive() {
return this.selectedTemplate != -1;
}
private boolean shouldPublisherBeVisible() {
return this.selectedTemplate != -1 && !this.getSelectedTemplate().link.isEmpty();
}
private WorldTemplate getSelectedTemplate() {
return this.worldTemplateObjectSelectionList.get(this.selectedTemplate);
}
private boolean shouldTrailerBeVisible() {
return this.selectedTemplate != -1 && !this.getSelectedTemplate().trailer.isEmpty();
}
public void tick() {
super.tick();
--this.clicks;
if (this.clicks < 0) {
this.clicks = 0;
}
}
public void onClose() {
this.callback.accept((WorldTemplate)null);
}
void selectTemplate() {
if (this.hasValidTemplate()) {
this.callback.accept(this.getSelectedTemplate());
}
}
private boolean hasValidTemplate() {
return this.selectedTemplate >= 0 && this.selectedTemplate < this.worldTemplateObjectSelectionList.getItemCount();
}
private void onTrailer() {
if (this.hasValidTemplate()) {
WorldTemplate worldtemplate = this.getSelectedTemplate();
if (!"".equals(worldtemplate.trailer)) {
Util.getPlatform().openUri(worldtemplate.trailer);
}
}
}
private void onPublish() {
if (this.hasValidTemplate()) {
WorldTemplate worldtemplate = this.getSelectedTemplate();
if (!"".equals(worldtemplate.link)) {
Util.getPlatform().openUri(worldtemplate.link);
}
}
}
private void fetchTemplatesAsync(final WorldTemplatePaginatedList p_89654_) {
(new Thread("realms-template-fetcher") {
public void run() {
WorldTemplatePaginatedList worldtemplatepaginatedlist = p_89654_;
RealmsClient realmsclient = RealmsClient.create();
while (worldtemplatepaginatedlist != null) {
Either<WorldTemplatePaginatedList, String> either = RealmsSelectWorldTemplateScreen.this.fetchTemplates(worldtemplatepaginatedlist, realmsclient);
worldtemplatepaginatedlist = RealmsSelectWorldTemplateScreen.this.minecraft.submit(() -> {
if (either.right().isPresent()) {
RealmsSelectWorldTemplateScreen.LOGGER.error("Couldn't fetch templates: {}", either.right().get());
if (RealmsSelectWorldTemplateScreen.this.worldTemplateObjectSelectionList.isEmpty()) {
RealmsSelectWorldTemplateScreen.this.noTemplatesMessage = TextRenderingUtils.decompose(I18n.get("mco.template.select.failure"));
}
return null;
} else {
WorldTemplatePaginatedList worldtemplatepaginatedlist1 = either.left().get();
for(WorldTemplate worldtemplate : worldtemplatepaginatedlist1.templates) {
RealmsSelectWorldTemplateScreen.this.worldTemplateObjectSelectionList.addEntry(worldtemplate);
}
if (worldtemplatepaginatedlist1.templates.isEmpty()) {
if (RealmsSelectWorldTemplateScreen.this.worldTemplateObjectSelectionList.isEmpty()) {
String s = I18n.get("mco.template.select.none", "%link");
TextRenderingUtils.LineSegment textrenderingutils$linesegment = TextRenderingUtils.LineSegment.link(I18n.get("mco.template.select.none.linkTitle"), "https://aka.ms/MinecraftRealmsContentCreator");
RealmsSelectWorldTemplateScreen.this.noTemplatesMessage = TextRenderingUtils.decompose(s, textrenderingutils$linesegment);
}
return null;
} else {
return worldtemplatepaginatedlist1;
}
}
}).join();
}
}
}).start();
}
Either<WorldTemplatePaginatedList, String> fetchTemplates(WorldTemplatePaginatedList p_89656_, RealmsClient p_89657_) {
try {
return Either.left(p_89657_.fetchWorldTemplates(p_89656_.page + 1, p_89656_.size, this.worldType));
} catch (RealmsServiceException realmsserviceexception) {
return Either.right(realmsserviceexception.getMessage());
}
}
public void render(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) {
this.toolTip = null;
this.currentLink = null;
this.hoverWarning = false;
this.renderBackground(pGuiGraphics);
this.worldTemplateObjectSelectionList.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
if (this.noTemplatesMessage != null) {
this.renderMultilineMessage(pGuiGraphics, pMouseX, pMouseY, this.noTemplatesMessage);
}
pGuiGraphics.drawCenteredString(this.font, this.title, this.width / 2, 13, 16777215);
if (this.displayWarning) {
Component[] acomponent = this.warning;
for(int i = 0; i < acomponent.length; ++i) {
int j = this.font.width(acomponent[i]);
int k = this.width / 2 - j / 2;
int l = row(-1 + i);
if (pMouseX >= k && pMouseX <= k + j && pMouseY >= l && pMouseY <= l + 9) {
this.hoverWarning = true;
}
}
for(int i1 = 0; i1 < acomponent.length; ++i1) {
Component component = acomponent[i1];
int j1 = 10526880;
if (this.warningURL != null) {
if (this.hoverWarning) {
j1 = 7107012;
component = component.copy().withStyle(ChatFormatting.STRIKETHROUGH);
} else {
j1 = 3368635;
}
}
pGuiGraphics.drawCenteredString(this.font, component, this.width / 2, row(-1 + i1), j1);
}
}
super.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
this.renderMousehoverTooltip(pGuiGraphics, this.toolTip, pMouseX, pMouseY);
}
private void renderMultilineMessage(GuiGraphics pGuiGraphics, int pX, int pY, List<TextRenderingUtils.Line> pLines) {
for(int i = 0; i < pLines.size(); ++i) {
TextRenderingUtils.Line textrenderingutils$line = pLines.get(i);
int j = row(4 + i);
int k = textrenderingutils$line.segments.stream().mapToInt((p_280748_) -> {
return this.font.width(p_280748_.renderedText());
}).sum();
int l = this.width / 2 - k / 2;
for(TextRenderingUtils.LineSegment textrenderingutils$linesegment : textrenderingutils$line.segments) {
int i1 = textrenderingutils$linesegment.isLink() ? 3368635 : 16777215;
int j1 = pGuiGraphics.drawString(this.font, textrenderingutils$linesegment.renderedText(), l, j, i1);
if (textrenderingutils$linesegment.isLink() && pX > l && pX < j1 && pY > j - 3 && pY < j + 8) {
this.toolTip = Component.literal(textrenderingutils$linesegment.getLinkUrl());
this.currentLink = textrenderingutils$linesegment.getLinkUrl();
}
l = j1;
}
}
}
protected void renderMousehoverTooltip(GuiGraphics pGuiGraphics, @Nullable Component pTooltip, int pMouseX, int pMouseY) {
if (pTooltip != null) {
int i = pMouseX + 12;
int j = pMouseY - 12;
int k = this.font.width(pTooltip);
pGuiGraphics.fillGradient(i - 3, j - 3, i + k + 3, j + 8 + 3, -1073741824, -1073741824);
pGuiGraphics.drawString(this.font, pTooltip, i, j, 16777215);
}
}
@OnlyIn(Dist.CLIENT)
class Entry extends ObjectSelectionList.Entry<RealmsSelectWorldTemplateScreen.Entry> {
final WorldTemplate template;
public Entry(WorldTemplate pTemplate) {
this.template = pTemplate;
}
public void render(GuiGraphics pGuiGraphics, int pIndex, int pTop, int pLeft, int pWidth, int pHeight, int pMouseX, int pMouseY, boolean p_282866_, float pPartialTick) {
this.renderWorldTemplateItem(pGuiGraphics, this.template, pLeft, pTop, pMouseX, pMouseY);
}
private void renderWorldTemplateItem(GuiGraphics pGuiGraphics, WorldTemplate pTemplate, int pX, int pY, int pMouseX, int pMouseY) {
int i = pX + 45 + 20;
pGuiGraphics.drawString(RealmsSelectWorldTemplateScreen.this.font, pTemplate.name, i, pY + 2, 16777215, false);
pGuiGraphics.drawString(RealmsSelectWorldTemplateScreen.this.font, pTemplate.author, i, pY + 15, 7105644, false);
pGuiGraphics.drawString(RealmsSelectWorldTemplateScreen.this.font, pTemplate.version, i + 227 - RealmsSelectWorldTemplateScreen.this.font.width(pTemplate.version), pY + 1, 7105644, false);
if (!"".equals(pTemplate.link) || !"".equals(pTemplate.trailer) || !"".equals(pTemplate.recommendedPlayers)) {
this.drawIcons(pGuiGraphics, i - 1, pY + 25, pMouseX, pMouseY, pTemplate.link, pTemplate.trailer, pTemplate.recommendedPlayers);
}
this.drawImage(pGuiGraphics, pX, pY + 1, pMouseX, pMouseY, pTemplate);
}
private void drawImage(GuiGraphics pGuiGraphics, int pX, int pY, int pMouseX, int pMouseY, WorldTemplate pTemplate) {
pGuiGraphics.blit(RealmsTextureManager.worldTemplate(pTemplate.id, pTemplate.image), pX + 1, pY + 1, 0.0F, 0.0F, 38, 38, 38, 38);
pGuiGraphics.blit(RealmsSelectWorldTemplateScreen.SLOT_FRAME_LOCATION, pX, pY, 0.0F, 0.0F, 40, 40, 40, 40);
}
private void drawIcons(GuiGraphics pGuiGraphics, int pX, int pY, int pMouseX, int pMouseY, String p_281390_, String p_281552_, String p_281807_) {
if (!"".equals(p_281807_)) {
pGuiGraphics.drawString(RealmsSelectWorldTemplateScreen.this.font, p_281807_, pX, pY + 4, 5000268, false);
}
int i = "".equals(p_281807_) ? 0 : RealmsSelectWorldTemplateScreen.this.font.width(p_281807_) + 2;
boolean flag = false;
boolean flag1 = false;
boolean flag2 = "".equals(p_281390_);
if (pMouseX >= pX + i && pMouseX <= pX + i + 32 && pMouseY >= pY && pMouseY <= pY + 15 && pMouseY < RealmsSelectWorldTemplateScreen.this.height - 15 && pMouseY > 32) {
if (pMouseX <= pX + 15 + i && pMouseX > i) {
if (flag2) {
flag1 = true;
} else {
flag = true;
}
} else if (!flag2) {
flag1 = true;
}
}
if (!flag2) {
float f = flag ? 15.0F : 0.0F;
pGuiGraphics.blit(RealmsSelectWorldTemplateScreen.LINK_ICON, pX + i, pY, f, 0.0F, 15, 15, 30, 15);
}
if (!"".equals(p_281552_)) {
int j = pX + i + (flag2 ? 0 : 17);
float f1 = flag1 ? 15.0F : 0.0F;
pGuiGraphics.blit(RealmsSelectWorldTemplateScreen.TRAILER_ICON, j, pY, f1, 0.0F, 15, 15, 30, 15);
}
if (flag) {
RealmsSelectWorldTemplateScreen.this.toolTip = RealmsSelectWorldTemplateScreen.PUBLISHER_LINK_TOOLTIP;
RealmsSelectWorldTemplateScreen.this.currentLink = p_281390_;
} else if (flag1 && !"".equals(p_281552_)) {
RealmsSelectWorldTemplateScreen.this.toolTip = RealmsSelectWorldTemplateScreen.TRAILER_LINK_TOOLTIP;
RealmsSelectWorldTemplateScreen.this.currentLink = p_281552_;
}
}
public Component getNarration() {
Component component = CommonComponents.joinLines(Component.literal(this.template.name), Component.translatable("mco.template.select.narrate.authors", this.template.author), Component.literal(this.template.recommendedPlayers), Component.translatable("mco.template.select.narrate.version", this.template.version));
return Component.translatable("narrator.select", component);
}
}
@OnlyIn(Dist.CLIENT)
class WorldTemplateObjectSelectionList extends RealmsObjectSelectionList<RealmsSelectWorldTemplateScreen.Entry> {
public WorldTemplateObjectSelectionList() {
this(Collections.emptyList());
}
public WorldTemplateObjectSelectionList(Iterable<WorldTemplate> pTemplates) {
super(RealmsSelectWorldTemplateScreen.this.width, RealmsSelectWorldTemplateScreen.this.height, RealmsSelectWorldTemplateScreen.this.displayWarning ? RealmsSelectWorldTemplateScreen.row(1) : 32, RealmsSelectWorldTemplateScreen.this.height - 40, 46);
pTemplates.forEach(this::addEntry);
}
public void addEntry(WorldTemplate p_89805_) {
this.addEntry(RealmsSelectWorldTemplateScreen.this.new Entry(p_89805_));
}
public boolean mouseClicked(double pMouseX, double pMouseY, int pButton) {
if (pButton == 0 && pMouseY >= (double)this.y0 && pMouseY <= (double)this.y1) {
int i = this.width / 2 - 150;
if (RealmsSelectWorldTemplateScreen.this.currentLink != null) {
Util.getPlatform().openUri(RealmsSelectWorldTemplateScreen.this.currentLink);
}
int j = (int)Math.floor(pMouseY - (double)this.y0) - this.headerHeight + (int)this.getScrollAmount() - 4;
int k = j / this.itemHeight;
if (pMouseX >= (double)i && pMouseX < (double)this.getScrollbarPosition() && k >= 0 && j >= 0 && k < this.getItemCount()) {
this.selectItem(k);
this.itemClicked(j, k, pMouseX, pMouseY, this.width, pButton);
if (k >= RealmsSelectWorldTemplateScreen.this.worldTemplateObjectSelectionList.getItemCount()) {
return super.mouseClicked(pMouseX, pMouseY, pButton);
}
RealmsSelectWorldTemplateScreen.this.clicks += 7;
if (RealmsSelectWorldTemplateScreen.this.clicks >= 10) {
RealmsSelectWorldTemplateScreen.this.selectTemplate();
}
return true;
}
}
return super.mouseClicked(pMouseX, pMouseY, pButton);
}
public void setSelected(@Nullable RealmsSelectWorldTemplateScreen.Entry pSelected) {
super.setSelected(pSelected);
RealmsSelectWorldTemplateScreen.this.selectedTemplate = this.children().indexOf(pSelected);
RealmsSelectWorldTemplateScreen.this.updateButtonStates();
}
public int getMaxPosition() {
return this.getItemCount() * 46;
}
public int getRowWidth() {
return 300;
}
public void renderBackground(GuiGraphics pGuiGraphics) {
RealmsSelectWorldTemplateScreen.this.renderBackground(pGuiGraphics);
}
public boolean isEmpty() {
return this.getItemCount() == 0;
}
public WorldTemplate get(int pIndex) {
return (this.children().get(pIndex)).template;
}
public List<WorldTemplate> getTemplates() {
return this.children().stream().map((p_89814_) -> {
return p_89814_.template;
}).collect(Collectors.toList());
}
}
}
@@ -0,0 +1,96 @@
package com.mojang.realmsclient.gui.screens;
import com.mojang.realmsclient.dto.RealmsServer;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.EditBox;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.realms.RealmsScreen;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class RealmsSettingsScreen extends RealmsScreen {
private static final int COMPONENT_WIDTH = 212;
private static final Component NAME_LABEL = Component.translatable("mco.configure.world.name");
private static final Component DESCRIPTION_LABEL = Component.translatable("mco.configure.world.description");
private final RealmsConfigureWorldScreen configureWorldScreen;
private final RealmsServer serverData;
private Button doneButton;
private EditBox descEdit;
private EditBox nameEdit;
public RealmsSettingsScreen(RealmsConfigureWorldScreen pConfigureWorldScreen, RealmsServer pServerData) {
super(Component.translatable("mco.configure.world.settings.title"));
this.configureWorldScreen = pConfigureWorldScreen;
this.serverData = pServerData;
}
public void tick() {
this.nameEdit.tick();
this.descEdit.tick();
this.doneButton.active = !this.nameEdit.getValue().trim().isEmpty();
}
public void init() {
int i = this.width / 2 - 106;
this.doneButton = this.addRenderableWidget(Button.builder(Component.translatable("mco.configure.world.buttons.done"), (p_89847_) -> {
this.save();
}).bounds(i - 2, row(12), 106, 20).build());
this.addRenderableWidget(Button.builder(CommonComponents.GUI_CANCEL, (p_280749_) -> {
this.minecraft.setScreen(this.configureWorldScreen);
}).bounds(this.width / 2 + 2, row(12), 106, 20).build());
String s = this.serverData.state == RealmsServer.State.OPEN ? "mco.configure.world.buttons.close" : "mco.configure.world.buttons.open";
Button button = Button.builder(Component.translatable(s), (p_287303_) -> {
if (this.serverData.state == RealmsServer.State.OPEN) {
Component component = Component.translatable("mco.configure.world.close.question.line1");
Component component1 = Component.translatable("mco.configure.world.close.question.line2");
this.minecraft.setScreen(new RealmsLongConfirmationScreen((p_280750_) -> {
if (p_280750_) {
this.configureWorldScreen.closeTheWorld(this);
} else {
this.minecraft.setScreen(this);
}
}, RealmsLongConfirmationScreen.Type.INFO, component, component1, true));
} else {
this.configureWorldScreen.openTheWorld(false, this);
}
}).bounds(this.width / 2 - 53, row(0), 106, 20).build();
this.addRenderableWidget(button);
this.nameEdit = new EditBox(this.minecraft.font, i, row(4), 212, 20, (EditBox)null, Component.translatable("mco.configure.world.name"));
this.nameEdit.setMaxLength(32);
this.nameEdit.setValue(this.serverData.getName());
this.addWidget(this.nameEdit);
this.magicalSpecialHackyFocus(this.nameEdit);
this.descEdit = new EditBox(this.minecraft.font, i, row(8), 212, 20, (EditBox)null, Component.translatable("mco.configure.world.description"));
this.descEdit.setMaxLength(32);
this.descEdit.setValue(this.serverData.getDescription());
this.addWidget(this.descEdit);
}
public boolean keyPressed(int pKeyCode, int pScanCode, int pModifiers) {
if (pKeyCode == 256) {
this.minecraft.setScreen(this.configureWorldScreen);
return true;
} else {
return super.keyPressed(pKeyCode, pScanCode, pModifiers);
}
}
public void render(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) {
this.renderBackground(pGuiGraphics);
pGuiGraphics.drawCenteredString(this.font, this.title, this.width / 2, 17, 16777215);
pGuiGraphics.drawString(this.font, NAME_LABEL, this.width / 2 - 106, row(3), 10526880, false);
pGuiGraphics.drawString(this.font, DESCRIPTION_LABEL, this.width / 2 - 106, row(7), 10526880, false);
this.nameEdit.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
this.descEdit.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
super.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
}
public void save() {
this.configureWorldScreen.saveSettings(this.nameEdit.getValue(), this.descEdit.getValue());
}
}
@@ -0,0 +1,265 @@
package com.mojang.realmsclient.gui.screens;
import com.google.common.collect.ImmutableList;
import com.mojang.realmsclient.dto.RealmsServer;
import com.mojang.realmsclient.dto.RealmsWorldOptions;
import java.util.List;
import java.util.function.Consumer;
import net.minecraft.ChatFormatting;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.AbstractSliderButton;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.CycleButton;
import net.minecraft.client.gui.components.EditBox;
import net.minecraft.client.gui.screens.ConfirmScreen;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.realms.RealmsLabel;
import net.minecraft.realms.RealmsScreen;
import net.minecraft.util.Mth;
import net.minecraft.world.Difficulty;
import net.minecraft.world.level.GameType;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class RealmsSlotOptionsScreen extends RealmsScreen {
private static final int DEFAULT_DIFFICULTY = 2;
public static final List<Difficulty> DIFFICULTIES = ImmutableList.of(Difficulty.PEACEFUL, Difficulty.EASY, Difficulty.NORMAL, Difficulty.HARD);
private static final int DEFAULT_GAME_MODE = 0;
public static final List<GameType> GAME_MODES = ImmutableList.of(GameType.SURVIVAL, GameType.CREATIVE, GameType.ADVENTURE);
private static final Component NAME_LABEL = Component.translatable("mco.configure.world.edit.slot.name");
static final Component SPAWN_PROTECTION_TEXT = Component.translatable("mco.configure.world.spawnProtection");
private static final Component SPAWN_WARNING_TITLE = Component.translatable("mco.configure.world.spawn_toggle.title").withStyle(ChatFormatting.RED, ChatFormatting.BOLD);
private EditBox nameEdit;
protected final RealmsConfigureWorldScreen parent;
private int column1X;
private int columnWidth;
private final RealmsWorldOptions options;
private final RealmsServer.WorldType worldType;
private Difficulty difficulty;
private GameType gameMode;
private final String defaultSlotName;
private String worldName;
private boolean pvp;
private boolean spawnNPCs;
private boolean spawnAnimals;
private boolean spawnMonsters;
int spawnProtection;
private boolean commandBlocks;
private boolean forceGameMode;
RealmsSlotOptionsScreen.SettingsSlider spawnProtectionButton;
public RealmsSlotOptionsScreen(RealmsConfigureWorldScreen pParent, RealmsWorldOptions pOptions, RealmsServer.WorldType pWorldType, int pActiveSlot) {
super(Component.translatable("mco.configure.world.buttons.options"));
this.parent = pParent;
this.options = pOptions;
this.worldType = pWorldType;
this.difficulty = findByIndex(DIFFICULTIES, pOptions.difficulty, 2);
this.gameMode = findByIndex(GAME_MODES, pOptions.gameMode, 0);
this.defaultSlotName = pOptions.getDefaultSlotName(pActiveSlot);
this.setWorldName(pOptions.getSlotName(pActiveSlot));
if (pWorldType == RealmsServer.WorldType.NORMAL) {
this.pvp = pOptions.pvp;
this.spawnProtection = pOptions.spawnProtection;
this.forceGameMode = pOptions.forceGameMode;
this.spawnAnimals = pOptions.spawnAnimals;
this.spawnMonsters = pOptions.spawnMonsters;
this.spawnNPCs = pOptions.spawnNPCs;
this.commandBlocks = pOptions.commandBlocks;
} else {
this.pvp = true;
this.spawnProtection = 0;
this.forceGameMode = false;
this.spawnAnimals = true;
this.spawnMonsters = true;
this.spawnNPCs = true;
this.commandBlocks = true;
}
}
public void tick() {
this.nameEdit.tick();
}
public boolean keyPressed(int pKeyCode, int pScanCode, int pModifiers) {
if (pKeyCode == 256) {
this.minecraft.setScreen(this.parent);
return true;
} else {
return super.keyPressed(pKeyCode, pScanCode, pModifiers);
}
}
private static <T> T findByIndex(List<T> p_167525_, int p_167526_, int p_167527_) {
try {
return p_167525_.get(p_167526_);
} catch (IndexOutOfBoundsException indexoutofboundsexception) {
return p_167525_.get(p_167527_);
}
}
private static <T> int findIndex(List<T> p_167529_, T p_167530_, int p_167531_) {
int i = p_167529_.indexOf(p_167530_);
return i == -1 ? p_167531_ : i;
}
public void init() {
this.columnWidth = 170;
this.column1X = this.width / 2 - this.columnWidth;
int i = this.width / 2 + 10;
if (this.worldType != RealmsServer.WorldType.NORMAL) {
Component component;
if (this.worldType == RealmsServer.WorldType.ADVENTUREMAP) {
component = Component.translatable("mco.configure.world.edit.subscreen.adventuremap");
} else if (this.worldType == RealmsServer.WorldType.INSPIRATION) {
component = Component.translatable("mco.configure.world.edit.subscreen.inspiration");
} else {
component = Component.translatable("mco.configure.world.edit.subscreen.experience");
}
this.addLabel(new RealmsLabel(component, this.width / 2, 26, 16711680));
}
this.nameEdit = new EditBox(this.minecraft.font, this.column1X + 2, row(1), this.columnWidth - 4, 20, (EditBox)null, Component.translatable("mco.configure.world.edit.slot.name"));
this.nameEdit.setMaxLength(10);
this.nameEdit.setValue(this.worldName);
this.nameEdit.setResponder(this::setWorldName);
this.magicalSpecialHackyFocus(this.nameEdit);
CycleButton<Boolean> cyclebutton5 = this.addRenderableWidget(CycleButton.onOffBuilder(this.pvp).create(i, row(1), this.columnWidth, 20, Component.translatable("mco.configure.world.pvp"), (p_167546_, p_167547_) -> {
this.pvp = p_167547_;
}));
this.addRenderableWidget(CycleButton.builder(GameType::getShortDisplayName).withValues(GAME_MODES).withInitialValue(this.gameMode).create(this.column1X, row(3), this.columnWidth, 20, Component.translatable("selectWorld.gameMode"), (p_167515_, p_167516_) -> {
this.gameMode = p_167516_;
}));
Component component1 = Component.translatable("mco.configure.world.spawn_toggle.message");
CycleButton<Boolean> cyclebutton = this.addRenderableWidget(CycleButton.onOffBuilder(this.spawnAnimals).create(i, row(3), this.columnWidth, 20, Component.translatable("mco.configure.world.spawnAnimals"), this.confirmDangerousOption(component1, (p_231329_) -> {
this.spawnAnimals = p_231329_;
})));
CycleButton<Boolean> cyclebutton1 = CycleButton.onOffBuilder(this.difficulty != Difficulty.PEACEFUL && this.spawnMonsters).create(i, row(5), this.columnWidth, 20, Component.translatable("mco.configure.world.spawnMonsters"), this.confirmDangerousOption(component1, (p_231327_) -> {
this.spawnMonsters = p_231327_;
}));
this.addRenderableWidget(CycleButton.builder(Difficulty::getDisplayName).withValues(DIFFICULTIES).withInitialValue(this.difficulty).create(this.column1X, row(5), this.columnWidth, 20, Component.translatable("options.difficulty"), (p_167519_, p_167520_) -> {
this.difficulty = p_167520_;
if (this.worldType == RealmsServer.WorldType.NORMAL) {
boolean flag = this.difficulty != Difficulty.PEACEFUL;
cyclebutton1.active = flag;
cyclebutton1.setValue(flag && this.spawnMonsters);
}
}));
this.addRenderableWidget(cyclebutton1);
this.spawnProtectionButton = this.addRenderableWidget(new RealmsSlotOptionsScreen.SettingsSlider(this.column1X, row(7), this.columnWidth, this.spawnProtection, 0.0F, 16.0F));
CycleButton<Boolean> cyclebutton2 = this.addRenderableWidget(CycleButton.onOffBuilder(this.spawnNPCs).create(i, row(7), this.columnWidth, 20, Component.translatable("mco.configure.world.spawnNPCs"), this.confirmDangerousOption(Component.translatable("mco.configure.world.spawn_toggle.message.npc"), (p_231312_) -> {
this.spawnNPCs = p_231312_;
})));
CycleButton<Boolean> cyclebutton3 = this.addRenderableWidget(CycleButton.onOffBuilder(this.forceGameMode).create(this.column1X, row(9), this.columnWidth, 20, Component.translatable("mco.configure.world.forceGameMode"), (p_167534_, p_167535_) -> {
this.forceGameMode = p_167535_;
}));
CycleButton<Boolean> cyclebutton4 = this.addRenderableWidget(CycleButton.onOffBuilder(this.commandBlocks).create(i, row(9), this.columnWidth, 20, Component.translatable("mco.configure.world.commandBlocks"), (p_167522_, p_167523_) -> {
this.commandBlocks = p_167523_;
}));
if (this.worldType != RealmsServer.WorldType.NORMAL) {
cyclebutton5.active = false;
cyclebutton.active = false;
cyclebutton2.active = false;
cyclebutton1.active = false;
this.spawnProtectionButton.active = false;
cyclebutton4.active = false;
cyclebutton3.active = false;
}
if (this.difficulty == Difficulty.PEACEFUL) {
cyclebutton1.active = false;
}
this.addRenderableWidget(Button.builder(Component.translatable("mco.configure.world.buttons.done"), (p_89910_) -> {
this.saveSettings();
}).bounds(this.column1X, row(13), this.columnWidth, 20).build());
this.addRenderableWidget(Button.builder(CommonComponents.GUI_CANCEL, (p_280758_) -> {
this.minecraft.setScreen(this.parent);
}).bounds(i, row(13), this.columnWidth, 20).build());
this.addWidget(this.nameEdit);
}
private CycleButton.OnValueChange<Boolean> confirmDangerousOption(Component p_231324_, Consumer<Boolean> p_231325_) {
return (p_280754_, p_280755_) -> {
if (p_280755_) {
p_231325_.accept(true);
} else {
this.minecraft.setScreen(new ConfirmScreen((p_280757_) -> {
if (p_280757_) {
p_231325_.accept(false);
}
this.minecraft.setScreen(this);
}, SPAWN_WARNING_TITLE, p_231324_, CommonComponents.GUI_PROCEED, CommonComponents.GUI_CANCEL));
}
};
}
public Component getNarrationMessage() {
return CommonComponents.joinForNarration(this.getTitle(), this.createLabelNarration());
}
public void render(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) {
this.renderBackground(pGuiGraphics);
pGuiGraphics.drawCenteredString(this.font, this.title, this.width / 2, 17, 16777215);
pGuiGraphics.drawString(this.font, NAME_LABEL, this.column1X + this.columnWidth / 2 - this.font.width(NAME_LABEL) / 2, row(0) - 5, 16777215, false);
this.nameEdit.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
super.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
}
private void setWorldName(String p_231314_) {
if (p_231314_.equals(this.defaultSlotName)) {
this.worldName = "";
} else {
this.worldName = p_231314_;
}
}
private void saveSettings() {
int i = findIndex(DIFFICULTIES, this.difficulty, 2);
int j = findIndex(GAME_MODES, this.gameMode, 0);
if (this.worldType != RealmsServer.WorldType.ADVENTUREMAP && this.worldType != RealmsServer.WorldType.EXPERIENCE && this.worldType != RealmsServer.WorldType.INSPIRATION) {
boolean flag = this.worldType == RealmsServer.WorldType.NORMAL && this.difficulty != Difficulty.PEACEFUL && this.spawnMonsters;
this.parent.saveSlotSettings(new RealmsWorldOptions(this.pvp, this.spawnAnimals, flag, this.spawnNPCs, this.spawnProtection, this.commandBlocks, i, j, this.forceGameMode, this.worldName));
} else {
this.parent.saveSlotSettings(new RealmsWorldOptions(this.options.pvp, this.options.spawnAnimals, this.options.spawnMonsters, this.options.spawnNPCs, this.options.spawnProtection, this.options.commandBlocks, i, j, this.options.forceGameMode, this.worldName));
}
}
@OnlyIn(Dist.CLIENT)
class SettingsSlider extends AbstractSliderButton {
private final double minValue;
private final double maxValue;
public SettingsSlider(int pX, int pY, int pWidth, int pValue, float pMinValue, float pMaxValue) {
super(pX, pY, pWidth, 20, CommonComponents.EMPTY, 0.0D);
this.minValue = (double)pMinValue;
this.maxValue = (double)pMaxValue;
this.value = (double)((Mth.clamp((float)pValue, pMinValue, pMaxValue) - pMinValue) / (pMaxValue - pMinValue));
this.updateMessage();
}
public void applyValue() {
if (RealmsSlotOptionsScreen.this.spawnProtectionButton.active) {
RealmsSlotOptionsScreen.this.spawnProtection = (int)Mth.lerp(Mth.clamp(this.value, 0.0D, 1.0D), this.minValue, this.maxValue);
}
}
protected void updateMessage() {
this.setMessage(CommonComponents.optionNameValue(RealmsSlotOptionsScreen.SPAWN_PROTECTION_TEXT, (Component)(RealmsSlotOptionsScreen.this.spawnProtection == 0 ? CommonComponents.OPTION_OFF : Component.literal(String.valueOf(RealmsSlotOptionsScreen.this.spawnProtection)))));
}
public void onClick(double pMouseX, double pMouseY) {
}
public void onRelease(double pMouseX, double pMouseY) {
}
}
}
@@ -0,0 +1,165 @@
package com.mojang.realmsclient.gui.screens;
import com.mojang.logging.LogUtils;
import com.mojang.realmsclient.client.RealmsClient;
import com.mojang.realmsclient.dto.RealmsServer;
import com.mojang.realmsclient.dto.Subscription;
import com.mojang.realmsclient.exception.RealmsServiceException;
import java.text.DateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;
import javax.annotation.Nullable;
import net.minecraft.Util;
import net.minecraft.client.GameNarrator;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.FittingMultiLineTextWidget;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.realms.RealmsScreen;
import net.minecraft.util.CommonLinks;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class RealmsSubscriptionInfoScreen extends RealmsScreen {
static final Logger LOGGER = LogUtils.getLogger();
private static final Component SUBSCRIPTION_TITLE = Component.translatable("mco.configure.world.subscription.title");
private static final Component SUBSCRIPTION_START_LABEL = Component.translatable("mco.configure.world.subscription.start");
private static final Component TIME_LEFT_LABEL = Component.translatable("mco.configure.world.subscription.timeleft");
private static final Component DAYS_LEFT_LABEL = Component.translatable("mco.configure.world.subscription.recurring.daysleft");
private static final Component SUBSCRIPTION_EXPIRED_TEXT = Component.translatable("mco.configure.world.subscription.expired");
private static final Component SUBSCRIPTION_LESS_THAN_A_DAY_TEXT = Component.translatable("mco.configure.world.subscription.less_than_a_day");
private static final Component UNKNOWN = Component.translatable("mco.configure.world.subscription.unknown");
private static final Component RECURRING_INFO = Component.translatable("mco.configure.world.subscription.recurring.info");
private final Screen lastScreen;
final RealmsServer serverData;
final Screen mainScreen;
private Component daysLeft = UNKNOWN;
private Component startDate = UNKNOWN;
@Nullable
private Subscription.SubscriptionType type;
public RealmsSubscriptionInfoScreen(Screen pLastScreen, RealmsServer pServerData, Screen pMainScreen) {
super(GameNarrator.NO_TITLE);
this.lastScreen = pLastScreen;
this.serverData = pServerData;
this.mainScreen = pMainScreen;
}
public void init() {
this.getSubscription(this.serverData.id);
this.addRenderableWidget(Button.builder(Component.translatable("mco.configure.world.subscription.extend"), (p_280761_) -> {
String s = CommonLinks.extendRealms(this.serverData.remoteSubscriptionId, this.minecraft.getUser().getUuid());
this.minecraft.keyboardHandler.setClipboard(s);
Util.getPlatform().openUri(s);
}).bounds(this.width / 2 - 100, row(6), 200, 20).build());
if (this.serverData.expired) {
this.addRenderableWidget(Button.builder(Component.translatable("mco.configure.world.delete.button"), (p_287304_) -> {
Component component = Component.translatable("mco.configure.world.delete.question.line1");
Component component1 = Component.translatable("mco.configure.world.delete.question.line2");
this.minecraft.setScreen(new RealmsLongConfirmationScreen(this::deleteRealm, RealmsLongConfirmationScreen.Type.WARNING, component, component1, true));
}).bounds(this.width / 2 - 100, row(10), 200, 20).build());
} else {
this.addRenderableWidget((new FittingMultiLineTextWidget(this.width / 2 - 100, row(8), 200, 46, RECURRING_INFO, this.font)).setColor(10526880));
}
this.addRenderableWidget(Button.builder(CommonComponents.GUI_BACK, (p_280760_) -> {
this.minecraft.setScreen(this.lastScreen);
}).bounds(this.width / 2 - 100, row(12), 200, 20).build());
}
public Component getNarrationMessage() {
return CommonComponents.joinLines(SUBSCRIPTION_TITLE, SUBSCRIPTION_START_LABEL, this.startDate, TIME_LEFT_LABEL, this.daysLeft);
}
private void deleteRealm(boolean p_90012_) {
if (p_90012_) {
(new Thread("Realms-delete-realm") {
public void run() {
try {
RealmsClient realmsclient = RealmsClient.create();
realmsclient.deleteWorld(RealmsSubscriptionInfoScreen.this.serverData.id);
} catch (RealmsServiceException realmsserviceexception) {
RealmsSubscriptionInfoScreen.LOGGER.error("Couldn't delete world", (Throwable)realmsserviceexception);
}
RealmsSubscriptionInfoScreen.this.minecraft.execute(() -> {
RealmsSubscriptionInfoScreen.this.minecraft.setScreen(RealmsSubscriptionInfoScreen.this.mainScreen);
});
}
}).start();
}
this.minecraft.setScreen(this);
}
private void getSubscription(long pServerId) {
RealmsClient realmsclient = RealmsClient.create();
try {
Subscription subscription = realmsclient.subscriptionFor(pServerId);
this.daysLeft = this.daysLeftPresentation(subscription.daysLeft);
this.startDate = localPresentation(subscription.startDate);
this.type = subscription.type;
} catch (RealmsServiceException realmsserviceexception) {
LOGGER.error("Couldn't get subscription");
this.minecraft.setScreen(new RealmsGenericErrorScreen(realmsserviceexception, this.lastScreen));
}
}
private static Component localPresentation(long pTime) {
Calendar calendar = new GregorianCalendar(TimeZone.getDefault());
calendar.setTimeInMillis(pTime);
return Component.literal(DateFormat.getDateTimeInstance().format(calendar.getTime()));
}
public boolean keyPressed(int pKeyCode, int pScanCode, int pModifiers) {
if (pKeyCode == 256) {
this.minecraft.setScreen(this.lastScreen);
return true;
} else {
return super.keyPressed(pKeyCode, pScanCode, pModifiers);
}
}
public void render(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) {
this.renderBackground(pGuiGraphics);
int i = this.width / 2 - 100;
pGuiGraphics.drawCenteredString(this.font, SUBSCRIPTION_TITLE, this.width / 2, 17, 16777215);
pGuiGraphics.drawString(this.font, SUBSCRIPTION_START_LABEL, i, row(0), 10526880, false);
pGuiGraphics.drawString(this.font, this.startDate, i, row(1), 16777215, false);
if (this.type == Subscription.SubscriptionType.NORMAL) {
pGuiGraphics.drawString(this.font, TIME_LEFT_LABEL, i, row(3), 10526880, false);
} else if (this.type == Subscription.SubscriptionType.RECURRING) {
pGuiGraphics.drawString(this.font, DAYS_LEFT_LABEL, i, row(3), 10526880, false);
}
pGuiGraphics.drawString(this.font, this.daysLeft, i, row(4), 16777215, false);
super.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
}
private Component daysLeftPresentation(int pDaysLeft) {
if (pDaysLeft < 0 && this.serverData.expired) {
return SUBSCRIPTION_EXPIRED_TEXT;
} else if (pDaysLeft <= 1) {
return SUBSCRIPTION_LESS_THAN_A_DAY_TEXT;
} else {
int i = pDaysLeft / 30;
int j = pDaysLeft % 30;
boolean flag = i > 0;
boolean flag1 = j > 0;
if (flag && flag1) {
return Component.translatable("mco.configure.world.subscription.remaining.months.days", i, j);
} else if (flag) {
return Component.translatable("mco.configure.world.subscription.remaining.months", i);
} else {
return flag1 ? Component.translatable("mco.configure.world.subscription.remaining.days", j) : Component.empty();
}
}
}
}
@@ -0,0 +1,104 @@
package com.mojang.realmsclient.gui.screens;
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.exception.RealmsServiceException;
import com.mojang.realmsclient.util.task.GetServerDetailsTask;
import java.util.concurrent.locks.ReentrantLock;
import net.minecraft.Util;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.Style;
import net.minecraft.realms.RealmsScreen;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class RealmsTermsScreen extends RealmsScreen {
private static final Logger LOGGER = LogUtils.getLogger();
private static final Component TITLE = Component.translatable("mco.terms.title");
private static final Component TERMS_STATIC_TEXT = Component.translatable("mco.terms.sentence.1");
private static final Component TERMS_LINK_TEXT = CommonComponents.space().append(Component.translatable("mco.terms.sentence.2").withStyle(Style.EMPTY.withUnderlined(true)));
private final Screen lastScreen;
private final RealmsMainScreen mainScreen;
/**
* The screen to display when OK is clicked on the disconnect screen.
*
* Seems to be either null (integrated server) or an instance of either {@link MultiplayerScreen} (when connecting to
* a server) or {@link com.mojang.realmsclient.gui.screens.RealmsTermsScreen} (when connecting to MCO server)
*/
private final RealmsServer realmsServer;
private boolean onLink;
public RealmsTermsScreen(Screen pLastScreen, RealmsMainScreen pMainScreen, RealmsServer pRealmsServer) {
super(TITLE);
this.lastScreen = pLastScreen;
this.mainScreen = pMainScreen;
this.realmsServer = pRealmsServer;
}
public void init() {
int i = this.width / 4 - 2;
this.addRenderableWidget(Button.builder(Component.translatable("mco.terms.buttons.agree"), (p_90054_) -> {
this.agreedToTos();
}).bounds(this.width / 4, row(12), i, 20).build());
this.addRenderableWidget(Button.builder(Component.translatable("mco.terms.buttons.disagree"), (p_280762_) -> {
this.minecraft.setScreen(this.lastScreen);
}).bounds(this.width / 2 + 4, row(12), i, 20).build());
}
public boolean keyPressed(int pKeyCode, int pScanCode, int pModifiers) {
if (pKeyCode == 256) {
this.minecraft.setScreen(this.lastScreen);
return true;
} else {
return super.keyPressed(pKeyCode, pScanCode, pModifiers);
}
}
private void agreedToTos() {
RealmsClient realmsclient = RealmsClient.create();
try {
realmsclient.agreeToTos();
this.minecraft.setScreen(new RealmsLongRunningMcoTaskScreen(this.lastScreen, new GetServerDetailsTask(this.mainScreen, this.lastScreen, this.realmsServer, new ReentrantLock())));
} catch (RealmsServiceException realmsserviceexception) {
LOGGER.error("Couldn't agree to TOS");
}
}
public boolean mouseClicked(double pMouseX, double pMouseY, int pButton) {
if (this.onLink) {
this.minecraft.keyboardHandler.setClipboard("https://aka.ms/MinecraftRealmsTerms");
Util.getPlatform().openUri("https://aka.ms/MinecraftRealmsTerms");
return true;
} else {
return super.mouseClicked(pMouseX, pMouseY, pButton);
}
}
public Component getNarrationMessage() {
return CommonComponents.joinForNarration(super.getNarrationMessage(), TERMS_STATIC_TEXT).append(CommonComponents.SPACE).append(TERMS_LINK_TEXT);
}
public void render(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) {
this.renderBackground(pGuiGraphics);
pGuiGraphics.drawCenteredString(this.font, this.title, this.width / 2, 17, 16777215);
pGuiGraphics.drawString(this.font, TERMS_STATIC_TEXT, this.width / 2 - 120, row(5), 16777215, false);
int i = this.font.width(TERMS_STATIC_TEXT);
int j = this.width / 2 - 121 + i;
int k = row(5);
int l = j + this.font.width(TERMS_LINK_TEXT) + 1;
int i1 = k + 1 + 9;
this.onLink = j <= pMouseX && pMouseX <= l && k <= pMouseY && pMouseY <= i1;
pGuiGraphics.drawString(this.font, TERMS_LINK_TEXT, this.width / 2 - 120 + i, row(5), this.onLink ? 7107012 : 3368635, false);
super.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
}
}
@@ -0,0 +1,410 @@
package com.mojang.realmsclient.gui.screens;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.RateLimiter;
import com.mojang.logging.LogUtils;
import com.mojang.realmsclient.Unit;
import com.mojang.realmsclient.client.FileUpload;
import com.mojang.realmsclient.client.RealmsClient;
import com.mojang.realmsclient.client.UploadStatus;
import com.mojang.realmsclient.dto.UploadInfo;
import com.mojang.realmsclient.exception.RealmsServiceException;
import com.mojang.realmsclient.exception.RetryCallException;
import com.mojang.realmsclient.util.UploadTokenCache;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import java.util.zip.GZIPOutputStream;
import javax.annotation.Nullable;
import net.minecraft.SharedConstants;
import net.minecraft.Util;
import net.minecraft.client.GameNarrator;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.Button;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.realms.RealmsScreen;
import net.minecraft.world.level.storage.LevelSummary;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.compress.utils.IOUtils;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class RealmsUploadScreen extends RealmsScreen {
private static final Logger LOGGER = LogUtils.getLogger();
private static final ReentrantLock UPLOAD_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 static final String[] DOTS = new String[]{"", ".", ". .", ". . ."};
private static final Component VERIFYING_TEXT = Component.translatable("mco.upload.verifying");
private final RealmsResetWorldScreen lastScreen;
private final LevelSummary selectedLevel;
private final long worldId;
private final int slotId;
private final UploadStatus uploadStatus;
private final RateLimiter narrationRateLimiter;
@Nullable
private volatile Component[] errorMessage;
private volatile Component status = Component.translatable("mco.upload.preparing");
private volatile String progress;
private volatile boolean cancelled;
private volatile boolean uploadFinished;
private volatile boolean showDots = true;
private volatile boolean uploadStarted;
private Button backButton;
private Button cancelButton;
private int tickCount;
@Nullable
private Long previousWrittenBytes;
@Nullable
private Long previousTimeSnapshot;
private long bytesPersSecond;
private final Runnable callback;
public RealmsUploadScreen(long pWorldId, int pSlotId, RealmsResetWorldScreen pLastScreen, LevelSummary pSelectedLevel, Runnable pCallback) {
super(GameNarrator.NO_TITLE);
this.worldId = pWorldId;
this.slotId = pSlotId;
this.lastScreen = pLastScreen;
this.selectedLevel = pSelectedLevel;
this.uploadStatus = new UploadStatus();
this.narrationRateLimiter = RateLimiter.create((double)0.1F);
this.callback = pCallback;
}
public void init() {
this.backButton = this.addRenderableWidget(Button.builder(CommonComponents.GUI_BACK, (p_90118_) -> {
this.onBack();
}).bounds((this.width - 200) / 2, this.height - 42, 200, 20).build());
this.backButton.visible = false;
this.cancelButton = this.addRenderableWidget(Button.builder(CommonComponents.GUI_CANCEL, (p_90104_) -> {
this.onCancel();
}).bounds((this.width - 200) / 2, this.height - 42, 200, 20).build());
if (!this.uploadStarted) {
if (this.lastScreen.slot == -1) {
this.upload();
} else {
this.lastScreen.switchSlot(() -> {
if (!this.uploadStarted) {
this.uploadStarted = true;
this.minecraft.setScreen(this);
this.upload();
}
});
}
}
}
private void onBack() {
this.callback.run();
}
private void onCancel() {
this.cancelled = true;
this.minecraft.setScreen(this.lastScreen);
}
public boolean keyPressed(int pKeyCode, int pScanCode, int pModifiers) {
if (pKeyCode == 256) {
if (this.showDots) {
this.onCancel();
} else {
this.onBack();
}
return true;
} else {
return super.keyPressed(pKeyCode, pScanCode, pModifiers);
}
}
public void render(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) {
this.renderBackground(pGuiGraphics);
if (!this.uploadFinished && this.uploadStatus.bytesWritten != 0L && this.uploadStatus.bytesWritten == this.uploadStatus.totalBytes) {
this.status = VERIFYING_TEXT;
this.cancelButton.active = false;
}
pGuiGraphics.drawCenteredString(this.font, this.status, this.width / 2, 50, 16777215);
if (this.showDots) {
this.drawDots(pGuiGraphics);
}
if (this.uploadStatus.bytesWritten != 0L && !this.cancelled) {
this.drawProgressBar(pGuiGraphics);
this.drawUploadSpeed(pGuiGraphics);
}
if (this.errorMessage != null) {
for(int i = 0; i < this.errorMessage.length; ++i) {
pGuiGraphics.drawCenteredString(this.font, this.errorMessage[i], this.width / 2, 110 + 12 * i, 16711680);
}
}
super.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
}
private void drawDots(GuiGraphics pGuiGraphics) {
int i = this.font.width(this.status);
pGuiGraphics.drawString(this.font, DOTS[this.tickCount / 10 % DOTS.length], this.width / 2 + i / 2 + 5, 50, 16777215, false);
}
private void drawProgressBar(GuiGraphics pGuiGraphics) {
double d0 = Math.min((double)this.uploadStatus.bytesWritten / (double)this.uploadStatus.totalBytes, 1.0D);
this.progress = String.format(Locale.ROOT, "%.1f", d0 * 100.0D);
int i = (this.width - 200) / 2;
int j = i + (int)Math.round(200.0D * d0);
pGuiGraphics.fill(i - 1, 79, j + 1, 96, -2501934);
pGuiGraphics.fill(i, 80, j, 95, -8355712);
pGuiGraphics.drawCenteredString(this.font, this.progress + " %", this.width / 2, 84, 16777215);
}
private void drawUploadSpeed(GuiGraphics pGuiGraphics) {
if (this.tickCount % 20 == 0) {
if (this.previousWrittenBytes != null) {
long i = Util.getMillis() - this.previousTimeSnapshot;
if (i == 0L) {
i = 1L;
}
this.bytesPersSecond = 1000L * (this.uploadStatus.bytesWritten - this.previousWrittenBytes) / i;
this.drawUploadSpeed0(pGuiGraphics, this.bytesPersSecond);
}
this.previousWrittenBytes = this.uploadStatus.bytesWritten;
this.previousTimeSnapshot = Util.getMillis();
} else {
this.drawUploadSpeed0(pGuiGraphics, this.bytesPersSecond);
}
}
private void drawUploadSpeed0(GuiGraphics pGuiGraphics, long pBytesPerSecond) {
if (pBytesPerSecond > 0L) {
int i = this.font.width(this.progress);
String s = "(" + Unit.humanReadable(pBytesPerSecond) + "/s)";
pGuiGraphics.drawString(this.font, s, this.width / 2 + i / 2 + 15, 84, 16777215, false);
}
}
public void tick() {
super.tick();
++this.tickCount;
if (this.status != null && this.narrationRateLimiter.tryAcquire(1)) {
Component component = this.createProgressNarrationMessage();
this.minecraft.getNarrator().sayNow(component);
}
}
private Component createProgressNarrationMessage() {
List<Component> list = Lists.newArrayList();
list.add(this.status);
if (this.progress != null) {
list.add(Component.literal(this.progress + "%"));
}
if (this.errorMessage != null) {
list.addAll(Arrays.asList(this.errorMessage));
}
return CommonComponents.joinLines(list);
}
private void upload() {
this.uploadStarted = true;
(new Thread(() -> {
File file1 = null;
RealmsClient realmsclient = RealmsClient.create();
long i = this.worldId;
try {
if (UPLOAD_LOCK.tryLock(1L, TimeUnit.SECONDS)) {
UploadInfo uploadinfo = null;
for(int j = 0; j < 20; ++j) {
try {
if (this.cancelled) {
this.uploadCancelled();
return;
}
uploadinfo = realmsclient.requestUploadInfo(i, UploadTokenCache.get(i));
if (uploadinfo != null) {
break;
}
} catch (RetryCallException retrycallexception) {
Thread.sleep((long)(retrycallexception.delaySeconds * 1000));
}
}
if (uploadinfo == null) {
this.status = Component.translatable("mco.upload.close.failure");
return;
}
UploadTokenCache.put(i, uploadinfo.getToken());
if (!uploadinfo.isWorldClosed()) {
this.status = Component.translatable("mco.upload.close.failure");
return;
}
if (this.cancelled) {
this.uploadCancelled();
return;
}
File file2 = new File(this.minecraft.gameDirectory.getAbsolutePath(), "saves");
file1 = this.tarGzipArchive(new File(file2, this.selectedLevel.getLevelId()));
if (this.cancelled) {
this.uploadCancelled();
return;
}
if (this.verify(file1)) {
this.status = Component.translatable("mco.upload.uploading", this.selectedLevel.getLevelName());
FileUpload fileupload = new FileUpload(file1, this.worldId, this.slotId, uploadinfo, this.minecraft.getUser(), SharedConstants.getCurrentVersion().getName(), this.uploadStatus);
fileupload.upload((p_167557_) -> {
if (p_167557_.statusCode >= 200 && p_167557_.statusCode < 300) {
this.uploadFinished = true;
this.status = Component.translatable("mco.upload.done");
this.backButton.setMessage(CommonComponents.GUI_DONE);
UploadTokenCache.invalidate(i);
} else if (p_167557_.statusCode == 400 && p_167557_.errorMessage != null) {
this.setErrorMessage(Component.translatable("mco.upload.failed", p_167557_.errorMessage));
} else {
this.setErrorMessage(Component.translatable("mco.upload.failed", p_167557_.statusCode));
}
});
while(!fileupload.isFinished()) {
if (this.cancelled) {
fileupload.cancel();
this.uploadCancelled();
return;
}
try {
Thread.sleep(500L);
} catch (InterruptedException interruptedexception) {
LOGGER.error("Failed to check Realms file upload status");
}
}
return;
}
long k = file1.length();
Unit unit = Unit.getLargest(k);
Unit unit1 = Unit.getLargest(5368709120L);
if (Unit.humanReadable(k, unit).equals(Unit.humanReadable(5368709120L, unit1)) && unit != Unit.B) {
Unit unit2 = Unit.values()[unit.ordinal() - 1];
this.setErrorMessage(Component.translatable("mco.upload.size.failure.line1", this.selectedLevel.getLevelName()), Component.translatable("mco.upload.size.failure.line2", Unit.humanReadable(k, unit2), Unit.humanReadable(5368709120L, unit2)));
return;
}
this.setErrorMessage(Component.translatable("mco.upload.size.failure.line1", this.selectedLevel.getLevelName()), Component.translatable("mco.upload.size.failure.line2", Unit.humanReadable(k, unit), Unit.humanReadable(5368709120L, unit1)));
return;
}
this.status = Component.translatable("mco.upload.close.failure");
} catch (IOException ioexception) {
this.setErrorMessage(Component.translatable("mco.upload.failed", ioexception.getMessage()));
return;
} catch (RealmsServiceException realmsserviceexception) {
this.setErrorMessage(Component.translatable("mco.upload.failed", realmsserviceexception.toString()));
return;
} catch (InterruptedException interruptedexception1) {
LOGGER.error("Could not acquire upload lock");
return;
} finally {
this.uploadFinished = true;
if (UPLOAD_LOCK.isHeldByCurrentThread()) {
UPLOAD_LOCK.unlock();
this.showDots = false;
this.backButton.visible = true;
this.cancelButton.visible = false;
if (file1 != null) {
LOGGER.debug("Deleting file {}", (Object)file1.getAbsolutePath());
file1.delete();
}
}
return;
}
})).start();
}
private void setErrorMessage(Component... pErrorMessage) {
this.errorMessage = pErrorMessage;
}
private void uploadCancelled() {
this.status = Component.translatable("mco.upload.cancelled");
LOGGER.debug("Upload was cancelled");
}
private boolean verify(File pFile) {
return pFile.length() < 5368709120L;
}
private File tarGzipArchive(File pFile) throws IOException {
TarArchiveOutputStream tararchiveoutputstream = null;
File file2;
try {
File file1 = File.createTempFile("realms-upload-file", ".tar.gz");
tararchiveoutputstream = new TarArchiveOutputStream(new GZIPOutputStream(new FileOutputStream(file1)));
tararchiveoutputstream.setLongFileMode(3);
this.addFileToTarGz(tararchiveoutputstream, pFile.getAbsolutePath(), "world", true);
tararchiveoutputstream.finish();
file2 = file1;
} finally {
if (tararchiveoutputstream != null) {
tararchiveoutputstream.close();
}
}
return file2;
}
private void addFileToTarGz(TarArchiveOutputStream pTarArchiveOutputStream, String pPathname, String p_90110_, boolean p_90111_) throws IOException {
if (!this.cancelled) {
File file1 = new File(pPathname);
String s = p_90111_ ? p_90110_ : p_90110_ + file1.getName();
TarArchiveEntry tararchiveentry = new TarArchiveEntry(file1, s);
pTarArchiveOutputStream.putArchiveEntry(tararchiveentry);
if (file1.isFile()) {
IOUtils.copy(new FileInputStream(file1), pTarArchiveOutputStream);
pTarArchiveOutputStream.closeArchiveEntry();
} else {
pTarArchiveOutputStream.closeArchiveEntry();
File[] afile = file1.listFiles();
if (afile != null) {
for(File file2 : afile) {
this.addFileToTarGz(pTarArchiveOutputStream, file2.getAbsolutePath(), s + "/", false);
}
}
}
}
}
}
@@ -0,0 +1,37 @@
package com.mojang.realmsclient.gui.screens;
import javax.annotation.Nullable;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class UploadResult {
public final int statusCode;
@Nullable
public final String errorMessage;
UploadResult(int pStatusCode, String pErrorMessage) {
this.statusCode = pStatusCode;
this.errorMessage = pErrorMessage;
}
@OnlyIn(Dist.CLIENT)
public static class Builder {
private int statusCode = -1;
private String errorMessage;
public UploadResult.Builder withStatusCode(int pStatusCode) {
this.statusCode = pStatusCode;
return this;
}
public UploadResult.Builder withErrorMessage(@Nullable String pErrorMessage) {
this.errorMessage = pErrorMessage;
return this;
}
public UploadResult build() {
return new UploadResult(this.statusCode, this.errorMessage);
}
}
}
@@ -0,0 +1,11 @@
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
@FieldsAreNonnullByDefault
@OnlyIn(Dist.CLIENT)
package com.mojang.realmsclient.gui.screens;
import javax.annotation.ParametersAreNonnullByDefault;
import net.minecraft.FieldsAreNonnullByDefault;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@@ -0,0 +1,184 @@
package com.mojang.realmsclient.gui.task;
import com.mojang.datafixers.util.Either;
import com.mojang.logging.LogUtils;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import javax.annotation.Nullable;
import net.minecraft.util.TimeSource;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class DataFetcher {
static final Logger LOGGER = LogUtils.getLogger();
final Executor executor;
final TimeUnit resolution;
final TimeSource timeSource;
public DataFetcher(Executor pExecutor, TimeUnit pResolution, TimeSource pTimeSource) {
this.executor = pExecutor;
this.resolution = pResolution;
this.timeSource = pTimeSource;
}
public <T> DataFetcher.Task<T> createTask(String pId, Callable<T> pUpdater, Duration pPeriod, RepeatedDelayStrategy pRepeatStrategy) {
long i = this.resolution.convert(pPeriod);
if (i == 0L) {
throw new IllegalArgumentException("Period of " + pPeriod + " too short for selected resolution of " + this.resolution);
} else {
return new DataFetcher.Task<>(pId, pUpdater, i, pRepeatStrategy);
}
}
public DataFetcher.Subscription createSubscription() {
return new DataFetcher.Subscription();
}
@OnlyIn(Dist.CLIENT)
static record ComputationResult<T>(Either<T, Exception> value, long time) {
}
@OnlyIn(Dist.CLIENT)
class SubscribedTask<T> {
private final DataFetcher.Task<T> task;
private final Consumer<T> output;
private long lastCheckTime = -1L;
SubscribedTask(DataFetcher.Task<T> pTask, Consumer<T> pOutput) {
this.task = pTask;
this.output = pOutput;
}
void update(long p_239226_) {
this.task.updateIfNeeded(p_239226_);
this.runCallbackIfNeeded();
}
void runCallbackIfNeeded() {
DataFetcher.SuccessfulComputationResult<T> successfulcomputationresult = this.task.lastResult;
if (successfulcomputationresult != null && this.lastCheckTime < successfulcomputationresult.time) {
this.output.accept(successfulcomputationresult.value);
this.lastCheckTime = successfulcomputationresult.time;
}
}
void runCallback() {
DataFetcher.SuccessfulComputationResult<T> successfulcomputationresult = this.task.lastResult;
if (successfulcomputationresult != null) {
this.output.accept(successfulcomputationresult.value);
this.lastCheckTime = successfulcomputationresult.time;
}
}
void reset() {
this.task.reset();
this.lastCheckTime = -1L;
}
}
@OnlyIn(Dist.CLIENT)
public class Subscription {
private final List<DataFetcher.SubscribedTask<?>> subscriptions = new ArrayList<>();
public <T> void subscribe(DataFetcher.Task<T> pTask, Consumer<T> pOutput) {
DataFetcher.SubscribedTask<T> subscribedtask = DataFetcher.this.new SubscribedTask<>(pTask, pOutput);
this.subscriptions.add(subscribedtask);
subscribedtask.runCallbackIfNeeded();
}
public void forceUpdate() {
for(DataFetcher.SubscribedTask<?> subscribedtask : this.subscriptions) {
subscribedtask.runCallback();
}
}
public void tick() {
for(DataFetcher.SubscribedTask<?> subscribedtask : this.subscriptions) {
subscribedtask.update(DataFetcher.this.timeSource.get(DataFetcher.this.resolution));
}
}
public void reset() {
for(DataFetcher.SubscribedTask<?> subscribedtask : this.subscriptions) {
subscribedtask.reset();
}
}
}
@OnlyIn(Dist.CLIENT)
static record SuccessfulComputationResult<T>(T value, long time) {
}
@OnlyIn(Dist.CLIENT)
public class Task<T> {
private final String id;
private final Callable<T> updater;
private final long period;
private final RepeatedDelayStrategy repeatStrategy;
@Nullable
private CompletableFuture<DataFetcher.ComputationResult<T>> pendingTask;
@Nullable
DataFetcher.SuccessfulComputationResult<T> lastResult;
private long nextUpdate = -1L;
Task(String pId, Callable<T> pUpdater, long pPeriod, RepeatedDelayStrategy pRepeatStrategy) {
this.id = pId;
this.updater = pUpdater;
this.period = pPeriod;
this.repeatStrategy = pRepeatStrategy;
}
void updateIfNeeded(long p_239710_) {
if (this.pendingTask != null) {
DataFetcher.ComputationResult<T> computationresult = this.pendingTask.getNow((DataFetcher.ComputationResult<T>)null);
if (computationresult == null) {
return;
}
this.pendingTask = null;
long i = computationresult.time;
computationresult.value().ifLeft((p_239691_) -> {
this.lastResult = new DataFetcher.SuccessfulComputationResult<>(p_239691_, i);
this.nextUpdate = i + this.period * this.repeatStrategy.delayCyclesAfterSuccess();
}).ifRight((p_239281_) -> {
long j = this.repeatStrategy.delayCyclesAfterFailure();
DataFetcher.LOGGER.warn("Failed to process task {}, will repeat after {} cycles", this.id, j, p_239281_);
this.nextUpdate = i + this.period * j;
});
}
if (this.nextUpdate <= p_239710_) {
this.pendingTask = CompletableFuture.supplyAsync(() -> {
try {
T t = this.updater.call();
long k = DataFetcher.this.timeSource.get(DataFetcher.this.resolution);
return new DataFetcher.ComputationResult<>(Either.left(t), k);
} catch (Exception exception) {
long j = DataFetcher.this.timeSource.get(DataFetcher.this.resolution);
return new DataFetcher.ComputationResult<>(Either.right(exception), j);
}
}, DataFetcher.this.executor);
}
}
public void reset() {
this.pendingTask = null;
this.lastResult = null;
this.nextUpdate = -1L;
}
}
}
@@ -0,0 +1,42 @@
package com.mojang.realmsclient.gui.task;
import com.mojang.logging.LogUtils;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public interface RepeatedDelayStrategy {
RepeatedDelayStrategy CONSTANT = new RepeatedDelayStrategy() {
public long delayCyclesAfterSuccess() {
return 1L;
}
public long delayCyclesAfterFailure() {
return 1L;
}
};
long delayCyclesAfterSuccess();
long delayCyclesAfterFailure();
static RepeatedDelayStrategy exponentialBackoff(final int pMaxFailureDelay) {
return new RepeatedDelayStrategy() {
private static final Logger LOGGER = LogUtils.getLogger();
private int failureCount;
public long delayCyclesAfterSuccess() {
this.failureCount = 0;
return 1L;
}
public long delayCyclesAfterFailure() {
++this.failureCount;
long i = Math.min(1L << this.failureCount, (long)pMaxFailureDelay);
LOGGER.debug("Skipping for {} extra cycles", (long)i);
return i;
}
};
}
}
@@ -0,0 +1,11 @@
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
@FieldsAreNonnullByDefault
@OnlyIn(Dist.CLIENT)
package com.mojang.realmsclient.gui.task;
import javax.annotation.ParametersAreNonnullByDefault;
import net.minecraft.FieldsAreNonnullByDefault;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@@ -0,0 +1,11 @@
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
@FieldsAreNonnullByDefault
@OnlyIn(Dist.CLIENT)
package com.mojang.realmsclient;
import javax.annotation.ParametersAreNonnullByDefault;
import net.minecraft.FieldsAreNonnullByDefault;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@@ -0,0 +1,83 @@
package com.mojang.realmsclient.util;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.util.Date;
import java.util.UUID;
import java.util.function.Function;
import javax.annotation.Nullable;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class JsonUtils {
public static <T> T getRequired(String pKey, JsonObject pJson, Function<JsonObject, T> pOutput) {
JsonElement jsonelement = pJson.get(pKey);
if (jsonelement != null && !jsonelement.isJsonNull()) {
if (!jsonelement.isJsonObject()) {
throw new IllegalStateException("Required property " + pKey + " was not a JsonObject as espected");
} else {
return pOutput.apply(jsonelement.getAsJsonObject());
}
} else {
throw new IllegalStateException("Missing required property: " + pKey);
}
}
public static String getRequiredString(String pKey, JsonObject pJson) {
String s = getStringOr(pKey, pJson, (String)null);
if (s == null) {
throw new IllegalStateException("Missing required property: " + pKey);
} else {
return s;
}
}
@Nullable
public static String getStringOr(String pKey, JsonObject pJson, @Nullable String pDefaultValue) {
JsonElement jsonelement = pJson.get(pKey);
if (jsonelement != null) {
return jsonelement.isJsonNull() ? pDefaultValue : jsonelement.getAsString();
} else {
return pDefaultValue;
}
}
@Nullable
public static UUID getUuidOr(String pKey, JsonObject pJson, @Nullable UUID pDefaultValue) {
String s = getStringOr(pKey, pJson, (String)null);
return s == null ? pDefaultValue : UUID.fromString(s);
}
public static int getIntOr(String pKey, JsonObject pJson, int pDefaultValue) {
JsonElement jsonelement = pJson.get(pKey);
if (jsonelement != null) {
return jsonelement.isJsonNull() ? pDefaultValue : jsonelement.getAsInt();
} else {
return pDefaultValue;
}
}
public static long getLongOr(String pKey, JsonObject pJson, long pDefaultValue) {
JsonElement jsonelement = pJson.get(pKey);
if (jsonelement != null) {
return jsonelement.isJsonNull() ? pDefaultValue : jsonelement.getAsLong();
} else {
return pDefaultValue;
}
}
public static boolean getBooleanOr(String pKey, JsonObject pJson, boolean pDefaultValue) {
JsonElement jsonelement = pJson.get(pKey);
if (jsonelement != null) {
return jsonelement.isJsonNull() ? pDefaultValue : jsonelement.getAsBoolean();
} else {
return pDefaultValue;
}
}
public static Date getDateOr(String pKey, JsonObject pJson) {
JsonElement jsonelement = pJson.get(pKey);
return jsonelement != null ? new Date(Long.parseLong(jsonelement.getAsString())) : new Date();
}
}
@@ -0,0 +1,32 @@
package com.mojang.realmsclient.util;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.levelgen.presets.WorldPreset;
import net.minecraft.world.level.levelgen.presets.WorldPresets;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public enum LevelType {
DEFAULT(0, WorldPresets.NORMAL),
FLAT(1, WorldPresets.FLAT),
LARGE_BIOMES(2, WorldPresets.LARGE_BIOMES),
AMPLIFIED(3, WorldPresets.AMPLIFIED);
private final int index;
private final Component name;
private LevelType(int pIndex, ResourceKey<WorldPreset> pName) {
this.index = pIndex;
this.name = Component.translatable(pName.location().toLanguageKey("generator"));
}
public Component getName() {
return this.name;
}
public int getDtoIndex() {
return this.index;
}
}
@@ -0,0 +1,68 @@
package com.mojang.realmsclient.util;
import com.google.gson.annotations.SerializedName;
import com.mojang.logging.LogUtils;
import com.mojang.realmsclient.dto.GuardedSerializer;
import com.mojang.realmsclient.dto.ReflectionBasedSerialization;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import net.minecraft.client.Minecraft;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class RealmsPersistence {
private static final String FILE_NAME = "realms_persistence.json";
private static final GuardedSerializer GSON = new GuardedSerializer();
private static final Logger LOGGER = LogUtils.getLogger();
public RealmsPersistence.RealmsPersistenceData read() {
return readFile();
}
public void save(RealmsPersistence.RealmsPersistenceData pPersistenceData) {
writeFile(pPersistenceData);
}
public static RealmsPersistence.RealmsPersistenceData readFile() {
Path path = getPathToData();
try {
String s = Files.readString(path, StandardCharsets.UTF_8);
RealmsPersistence.RealmsPersistenceData realmspersistence$realmspersistencedata = GSON.fromJson(s, RealmsPersistence.RealmsPersistenceData.class);
if (realmspersistence$realmspersistencedata != null) {
return realmspersistence$realmspersistencedata;
}
} catch (NoSuchFileException nosuchfileexception) {
} catch (Exception exception) {
LOGGER.warn("Failed to read Realms storage {}", path, exception);
}
return new RealmsPersistence.RealmsPersistenceData();
}
public static void writeFile(RealmsPersistence.RealmsPersistenceData pPersistenceData) {
Path path = getPathToData();
try {
Files.writeString(path, GSON.toJson(pPersistenceData), StandardCharsets.UTF_8);
} catch (Exception exception) {
}
}
private static Path getPathToData() {
return Minecraft.getInstance().gameDirectory.toPath().resolve("realms_persistence.json");
}
@OnlyIn(Dist.CLIENT)
public static class RealmsPersistenceData implements ReflectionBasedSerialization {
@SerializedName("newsLink")
public String newsLink;
@SerializedName("hasUnreadNews")
public boolean hasUnreadNews;
}
}
@@ -0,0 +1,68 @@
package com.mojang.realmsclient.util;
import com.google.common.collect.Maps;
import com.mojang.blaze3d.platform.NativeImage;
import com.mojang.logging.LogUtils;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Base64;
import java.util.Map;
import javax.annotation.Nullable;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.texture.DynamicTexture;
import net.minecraft.client.renderer.texture.MissingTextureAtlasSprite;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.lwjgl.system.MemoryUtil;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class RealmsTextureManager {
private static final Map<String, RealmsTextureManager.RealmsTexture> TEXTURES = Maps.newHashMap();
private static final Logger LOGGER = LogUtils.getLogger();
private static final ResourceLocation TEMPLATE_ICON_LOCATION = new ResourceLocation("textures/gui/presets/isles.png");
public static ResourceLocation worldTemplate(String p_270945_, @Nullable String p_270612_) {
return p_270612_ == null ? TEMPLATE_ICON_LOCATION : getTexture(p_270945_, p_270612_);
}
private static ResourceLocation getTexture(String p_90197_, String p_90198_) {
RealmsTextureManager.RealmsTexture realmstexturemanager$realmstexture = TEXTURES.get(p_90197_);
if (realmstexturemanager$realmstexture != null && realmstexturemanager$realmstexture.image().equals(p_90198_)) {
return realmstexturemanager$realmstexture.textureId;
} else {
NativeImage nativeimage = loadImage(p_90198_);
if (nativeimage == null) {
ResourceLocation resourcelocation1 = MissingTextureAtlasSprite.getLocation();
TEXTURES.put(p_90197_, new RealmsTextureManager.RealmsTexture(p_90198_, resourcelocation1));
return resourcelocation1;
} else {
ResourceLocation resourcelocation = new ResourceLocation("realms", "dynamic/" + p_90197_);
Minecraft.getInstance().getTextureManager().register(resourcelocation, new DynamicTexture(nativeimage));
TEXTURES.put(p_90197_, new RealmsTextureManager.RealmsTexture(p_90198_, resourcelocation));
return resourcelocation;
}
}
}
@Nullable
private static NativeImage loadImage(String p_270725_) {
byte[] abyte = Base64.getDecoder().decode(p_270725_);
ByteBuffer bytebuffer = MemoryUtil.memAlloc(abyte.length);
try {
return NativeImage.read(bytebuffer.put(abyte).flip());
} catch (IOException ioexception) {
LOGGER.warn("Failed to load world image: {}", p_270725_, ioexception);
} finally {
MemoryUtil.memFree(bytebuffer);
}
return null;
}
@OnlyIn(Dist.CLIENT)
public static record RealmsTexture(String image, ResourceLocation textureId) {
}
}
@@ -0,0 +1,69 @@
package com.mojang.realmsclient.util;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.minecraft.MinecraftSessionService;
import com.mojang.util.UUIDTypeAdapter;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.PlayerFaceRenderer;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class RealmsUtil {
static final MinecraftSessionService SESSION_SERVICE = Minecraft.getInstance().getMinecraftSessionService();
private static final Component RIGHT_NOW = Component.translatable("mco.util.time.now");
private static final LoadingCache<String, GameProfile> GAME_PROFILE_CACHE = CacheBuilder.newBuilder().expireAfterWrite(60L, TimeUnit.MINUTES).build(new CacheLoader<String, GameProfile>() {
public GameProfile load(String p_90229_) {
return RealmsUtil.SESSION_SERVICE.fillProfileProperties(new GameProfile(UUIDTypeAdapter.fromString(p_90229_), (String)null), false);
}
});
private static final int MINUTES = 60;
private static final int HOURS = 3600;
private static final int DAYS = 86400;
public static String uuidToName(String pProfileUuid) {
return GAME_PROFILE_CACHE.getUnchecked(pProfileUuid).getName();
}
public static GameProfile getGameProfile(String pProfileUuid) {
return GAME_PROFILE_CACHE.getUnchecked(pProfileUuid);
}
public static Component convertToAgePresentation(long pMillis) {
if (pMillis < 0L) {
return RIGHT_NOW;
} else {
long i = pMillis / 1000L;
if (i < 60L) {
return Component.translatable("mco.time.secondsAgo", i);
} else if (i < 3600L) {
long l = i / 60L;
return Component.translatable("mco.time.minutesAgo", l);
} else if (i < 86400L) {
long k = i / 3600L;
return Component.translatable("mco.time.hoursAgo", k);
} else {
long j = i / 86400L;
return Component.translatable("mco.time.daysAgo", j);
}
}
}
public static Component convertToAgePresentationFromInstant(Date pDate) {
return convertToAgePresentation(System.currentTimeMillis() - pDate.getTime());
}
public static void renderPlayerFace(GuiGraphics p_281255_, int p_281818_, int p_281791_, int p_282088_, String p_282512_) {
GameProfile gameprofile = getGameProfile(p_282512_);
ResourceLocation resourcelocation = Minecraft.getInstance().getSkinManager().getInsecureSkinLocation(gameprofile);
PlayerFaceRenderer.draw(p_281255_, resourcelocation, p_281818_, p_281791_, p_282088_);
}
}
@@ -0,0 +1,172 @@
package com.mojang.realmsclient.util;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Lists;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import javax.annotation.Nullable;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class TextRenderingUtils {
private TextRenderingUtils() {
}
@VisibleForTesting
protected static List<String> lineBreak(String p_90249_) {
return Arrays.asList(p_90249_.split("\\n"));
}
public static List<TextRenderingUtils.Line> decompose(String p_90257_, TextRenderingUtils.LineSegment... p_90258_) {
return decompose(p_90257_, Arrays.asList(p_90258_));
}
private static List<TextRenderingUtils.Line> decompose(String p_90254_, List<TextRenderingUtils.LineSegment> p_90255_) {
List<String> list = lineBreak(p_90254_);
return insertLinks(list, p_90255_);
}
private static List<TextRenderingUtils.Line> insertLinks(List<String> p_90260_, List<TextRenderingUtils.LineSegment> p_90261_) {
int i = 0;
List<TextRenderingUtils.Line> list = Lists.newArrayList();
for(String s : p_90260_) {
List<TextRenderingUtils.LineSegment> list1 = Lists.newArrayList();
for(String s1 : split(s, "%link")) {
if ("%link".equals(s1)) {
list1.add(p_90261_.get(i++));
} else {
list1.add(TextRenderingUtils.LineSegment.text(s1));
}
}
list.add(new TextRenderingUtils.Line(list1));
}
return list;
}
public static List<String> split(String pToSplit, String pDelimiter) {
if (pDelimiter.isEmpty()) {
throw new IllegalArgumentException("Delimiter cannot be the empty string");
} else {
List<String> list = Lists.newArrayList();
int i;
int j;
for(i = 0; (j = pToSplit.indexOf(pDelimiter, i)) != -1; i = j + pDelimiter.length()) {
if (j > i) {
list.add(pToSplit.substring(i, j));
}
list.add(pDelimiter);
}
if (i < pToSplit.length()) {
list.add(pToSplit.substring(i));
}
return list;
}
}
@OnlyIn(Dist.CLIENT)
public static class Line {
public final List<TextRenderingUtils.LineSegment> segments;
Line(TextRenderingUtils.LineSegment... pSegments) {
this(Arrays.asList(pSegments));
}
Line(List<TextRenderingUtils.LineSegment> pSegments) {
this.segments = pSegments;
}
public String toString() {
return "Line{segments=" + this.segments + "}";
}
public boolean equals(Object pOther) {
if (this == pOther) {
return true;
} else if (pOther != null && this.getClass() == pOther.getClass()) {
TextRenderingUtils.Line textrenderingutils$line = (TextRenderingUtils.Line)pOther;
return Objects.equals(this.segments, textrenderingutils$line.segments);
} else {
return false;
}
}
public int hashCode() {
return Objects.hash(this.segments);
}
}
@OnlyIn(Dist.CLIENT)
public static class LineSegment {
private final String fullText;
@Nullable
private final String linkTitle;
@Nullable
private final String linkUrl;
private LineSegment(String pFullText) {
this.fullText = pFullText;
this.linkTitle = null;
this.linkUrl = null;
}
private LineSegment(String pFullText, @Nullable String pLinkTitle, @Nullable String pLinkUrl) {
this.fullText = pFullText;
this.linkTitle = pLinkTitle;
this.linkUrl = pLinkUrl;
}
public boolean equals(Object pOther) {
if (this == pOther) {
return true;
} else if (pOther != null && this.getClass() == pOther.getClass()) {
TextRenderingUtils.LineSegment textrenderingutils$linesegment = (TextRenderingUtils.LineSegment)pOther;
return Objects.equals(this.fullText, textrenderingutils$linesegment.fullText) && Objects.equals(this.linkTitle, textrenderingutils$linesegment.linkTitle) && Objects.equals(this.linkUrl, textrenderingutils$linesegment.linkUrl);
} else {
return false;
}
}
public int hashCode() {
return Objects.hash(this.fullText, this.linkTitle, this.linkUrl);
}
public String toString() {
return "Segment{fullText='" + this.fullText + "', linkTitle='" + this.linkTitle + "', linkUrl='" + this.linkUrl + "'}";
}
public String renderedText() {
return this.isLink() ? this.linkTitle : this.fullText;
}
public boolean isLink() {
return this.linkTitle != null;
}
public String getLinkUrl() {
if (!this.isLink()) {
throw new IllegalStateException("Not a link: " + this);
} else {
return this.linkUrl;
}
}
public static TextRenderingUtils.LineSegment link(String pLinkTitle, String pLinkUrl) {
return new TextRenderingUtils.LineSegment((String)null, pLinkTitle, pLinkUrl);
}
@VisibleForTesting
protected static TextRenderingUtils.LineSegment text(String pFullText) {
return new TextRenderingUtils.LineSegment(pFullText);
}
}
}
@@ -0,0 +1,23 @@
package com.mojang.realmsclient.util;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class UploadTokenCache {
private static final Long2ObjectMap<String> TOKEN_CACHE = new Long2ObjectOpenHashMap<>();
public static String get(long pWorldId) {
return TOKEN_CACHE.get(pWorldId);
}
public static void invalidate(long pWorldId) {
TOKEN_CACHE.remove(pWorldId);
}
public static void put(long pWorldId, String pToken) {
TOKEN_CACHE.put(pWorldId, pToken);
}
}
@@ -0,0 +1,29 @@
package com.mojang.realmsclient.util;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class WorldGenerationInfo {
private final String seed;
private final LevelType levelType;
private final boolean generateStructures;
public WorldGenerationInfo(String pSeed, LevelType pLevelType, boolean pGenerateStructures) {
this.seed = pSeed;
this.levelType = pLevelType;
this.generateStructures = pGenerateStructures;
}
public String getSeed() {
return this.seed;
}
public LevelType getLevelType() {
return this.levelType;
}
public boolean shouldGenerateStructures() {
return this.generateStructures;
}
}
@@ -0,0 +1,11 @@
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
@FieldsAreNonnullByDefault
@OnlyIn(Dist.CLIENT)
package com.mojang.realmsclient.util;
import javax.annotation.ParametersAreNonnullByDefault;
import net.minecraft.FieldsAreNonnullByDefault;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@@ -0,0 +1,58 @@
package com.mojang.realmsclient.util.task;
import com.mojang.logging.LogUtils;
import com.mojang.realmsclient.client.RealmsClient;
import com.mojang.realmsclient.dto.RealmsServer;
import com.mojang.realmsclient.exception.RetryCallException;
import com.mojang.realmsclient.gui.screens.RealmsConfigureWorldScreen;
import net.minecraft.network.chat.Component;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class CloseServerTask extends LongRunningTask {
private static final Logger LOGGER = LogUtils.getLogger();
private final RealmsServer serverData;
private final RealmsConfigureWorldScreen configureScreen;
public CloseServerTask(RealmsServer pServerData, RealmsConfigureWorldScreen pConfigureScreen) {
this.serverData = pServerData;
this.configureScreen = pConfigureScreen;
}
public void run() {
this.setTitle(Component.translatable("mco.configure.world.closing"));
RealmsClient realmsclient = RealmsClient.create();
for(int i = 0; i < 25; ++i) {
if (this.aborted()) {
return;
}
try {
boolean flag = realmsclient.close(this.serverData.id);
if (flag) {
this.configureScreen.stateChanged();
this.serverData.state = RealmsServer.State.CLOSED;
setScreen(this.configureScreen);
break;
}
} catch (RetryCallException retrycallexception) {
if (this.aborted()) {
return;
}
pause((long)retrycallexception.delaySeconds);
} catch (Exception exception) {
if (this.aborted()) {
return;
}
LOGGER.error("Failed to close server", (Throwable)exception);
this.error("Failed to close the server");
}
}
}
}
@@ -0,0 +1,38 @@
package com.mojang.realmsclient.util.task;
import com.mojang.realmsclient.dto.RealmsServer;
import com.mojang.realmsclient.dto.RealmsServerAddress;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.multiplayer.resolver.ServerAddress;
import net.minecraft.network.chat.Component;
import net.minecraft.realms.RealmsConnect;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class ConnectTask extends LongRunningTask {
private final RealmsConnect realmsConnect;
private final RealmsServer server;
private final RealmsServerAddress address;
public ConnectTask(Screen pOnlineScreen, RealmsServer pServer, RealmsServerAddress pAddress) {
this.server = pServer;
this.address = pAddress;
this.realmsConnect = new RealmsConnect(pOnlineScreen);
}
public void run() {
this.setTitle(Component.translatable("mco.connect.connecting"));
this.realmsConnect.connect(this.server, ServerAddress.parseString(this.address.address));
}
public void abortTask() {
this.realmsConnect.abort();
Minecraft.getInstance().getDownloadedPackSource().clearServerPack();
}
public void tick() {
this.realmsConnect.tick();
}
}
@@ -0,0 +1,78 @@
package com.mojang.realmsclient.util.task;
import com.mojang.logging.LogUtils;
import com.mojang.realmsclient.client.RealmsClient;
import com.mojang.realmsclient.dto.WorldDownload;
import com.mojang.realmsclient.exception.RealmsServiceException;
import com.mojang.realmsclient.exception.RetryCallException;
import com.mojang.realmsclient.gui.screens.RealmsDownloadLatestWorldScreen;
import com.mojang.realmsclient.gui.screens.RealmsGenericErrorScreen;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class DownloadTask extends LongRunningTask {
private static final Logger LOGGER = LogUtils.getLogger();
private final long worldId;
private final int slot;
private final Screen lastScreen;
private final String downloadName;
public DownloadTask(long pWorldId, int pSlot, String pDownloadName, Screen pLastScreen) {
this.worldId = pWorldId;
this.slot = pSlot;
this.lastScreen = pLastScreen;
this.downloadName = pDownloadName;
}
public void run() {
this.setTitle(Component.translatable("mco.download.preparing"));
RealmsClient realmsclient = RealmsClient.create();
int i = 0;
while(i < 25) {
try {
if (this.aborted()) {
return;
}
WorldDownload worlddownload = realmsclient.requestDownloadInfo(this.worldId, this.slot);
pause(1L);
if (this.aborted()) {
return;
}
setScreen(new RealmsDownloadLatestWorldScreen(this.lastScreen, worlddownload, this.downloadName, (p_90325_) -> {
}));
return;
} catch (RetryCallException retrycallexception) {
if (this.aborted()) {
return;
}
pause((long)retrycallexception.delaySeconds);
++i;
} catch (RealmsServiceException realmsserviceexception) {
if (this.aborted()) {
return;
}
LOGGER.error("Couldn't download world data");
setScreen(new RealmsGenericErrorScreen(realmsserviceexception, this.lastScreen));
return;
} catch (Exception exception) {
if (this.aborted()) {
return;
}
LOGGER.error("Couldn't download world data", (Throwable)exception);
this.error(exception.getLocalizedMessage());
return;
}
}
}
}
@@ -0,0 +1,139 @@
package com.mojang.realmsclient.util.task;
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.RealmsServerAddress;
import com.mojang.realmsclient.exception.RealmsServiceException;
import com.mojang.realmsclient.exception.RetryCallException;
import com.mojang.realmsclient.gui.screens.RealmsBrokenWorldScreen;
import com.mojang.realmsclient.gui.screens.RealmsGenericErrorScreen;
import com.mojang.realmsclient.gui.screens.RealmsLongConfirmationScreen;
import com.mojang.realmsclient.gui.screens.RealmsLongRunningMcoTaskScreen;
import com.mojang.realmsclient.gui.screens.RealmsTermsScreen;
import it.unimi.dsi.fastutil.booleans.BooleanConsumer;
import java.net.URL;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Function;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class GetServerDetailsTask extends LongRunningTask {
private static final Logger LOGGER = LogUtils.getLogger();
private final RealmsServer server;
private final Screen lastScreen;
private final RealmsMainScreen mainScreen;
private final ReentrantLock connectLock;
public GetServerDetailsTask(RealmsMainScreen pMainScreen, Screen pLastScreen, RealmsServer pServer, ReentrantLock pConnectLock) {
this.lastScreen = pLastScreen;
this.mainScreen = pMainScreen;
this.server = pServer;
this.connectLock = pConnectLock;
}
public void run() {
this.setTitle(Component.translatable("mco.connect.connecting"));
RealmsServerAddress realmsserveraddress;
try {
realmsserveraddress = this.fetchServerAddress();
} catch (CancellationException cancellationexception) {
LOGGER.info("User aborted connecting to realms");
return;
} catch (RealmsServiceException realmsserviceexception) {
switch (realmsserviceexception.realmsErrorCodeOrDefault(-1)) {
case 6002:
setScreen(new RealmsTermsScreen(this.lastScreen, this.mainScreen, this.server));
return;
case 6006:
boolean flag1 = this.server.ownerUUID.equals(Minecraft.getInstance().getUser().getUuid());
setScreen((Screen)(flag1 ? new RealmsBrokenWorldScreen(this.lastScreen, this.mainScreen, this.server.id, this.server.worldType == RealmsServer.WorldType.MINIGAME) : new RealmsGenericErrorScreen(Component.translatable("mco.brokenworld.nonowner.title"), Component.translatable("mco.brokenworld.nonowner.error"), this.lastScreen)));
return;
default:
this.error(realmsserviceexception.toString());
LOGGER.error("Couldn't connect to world", (Throwable)realmsserviceexception);
return;
}
} catch (TimeoutException timeoutexception) {
this.error(Component.translatable("mco.errorMessage.connectionFailure"));
return;
} catch (Exception exception) {
LOGGER.error("Couldn't connect to world", (Throwable)exception);
this.error(exception.getLocalizedMessage());
return;
}
boolean flag = realmsserveraddress.resourcePackUrl != null && realmsserveraddress.resourcePackHash != null;
Screen screen = (Screen)(flag ? this.resourcePackDownloadConfirmationScreen(realmsserveraddress, this::connectScreen) : this.connectScreen(realmsserveraddress));
setScreen(screen);
}
private RealmsServerAddress fetchServerAddress() throws RealmsServiceException, TimeoutException, CancellationException {
RealmsClient realmsclient = RealmsClient.create();
for(int i = 0; i < 40; ++i) {
if (this.aborted()) {
throw new CancellationException();
}
try {
return realmsclient.join(this.server.id);
} catch (RetryCallException retrycallexception) {
pause((long)retrycallexception.delaySeconds);
}
}
throw new TimeoutException();
}
public RealmsLongRunningMcoTaskScreen connectScreen(RealmsServerAddress p_167638_) {
return new RealmsLongRunningMcoTaskScreen(this.lastScreen, new ConnectTask(this.lastScreen, this.server, p_167638_));
}
private RealmsLongConfirmationScreen resourcePackDownloadConfirmationScreen(RealmsServerAddress pServerAddress, Function<RealmsServerAddress, Screen> p_167641_) {
BooleanConsumer booleanconsumer = (p_167645_) -> {
try {
if (p_167645_) {
this.scheduleResourcePackDownload(pServerAddress).thenRun(() -> {
setScreen(p_167641_.apply(pServerAddress));
}).exceptionally((p_287306_) -> {
Minecraft.getInstance().getDownloadedPackSource().clearServerPack();
LOGGER.error("Failed to download resource pack from {}", pServerAddress, p_287306_);
setScreen(new RealmsGenericErrorScreen(Component.translatable("mco.download.resourcePack.fail"), this.lastScreen));
return null;
});
return;
}
setScreen(this.lastScreen);
} finally {
if (this.connectLock.isHeldByCurrentThread()) {
this.connectLock.unlock();
}
}
};
return new RealmsLongConfirmationScreen(booleanconsumer, RealmsLongConfirmationScreen.Type.INFO, Component.translatable("mco.configure.world.resourcepack.question.line1"), Component.translatable("mco.configure.world.resourcepack.question.line2"), true);
}
private CompletableFuture<?> scheduleResourcePackDownload(RealmsServerAddress pServerAddress) {
try {
return Minecraft.getInstance().getDownloadedPackSource().downloadAndSelectResourcePack(new URL(pServerAddress.resourcePackUrl), pServerAddress.resourcePackHash, false);
} catch (Exception exception) {
CompletableFuture<Void> completablefuture = new CompletableFuture<>();
completablefuture.completeExceptionally(exception);
return completablefuture;
}
}
}
@@ -0,0 +1,60 @@
package com.mojang.realmsclient.util.task;
import com.mojang.logging.LogUtils;
import com.mojang.realmsclient.gui.ErrorCallback;
import com.mojang.realmsclient.gui.screens.RealmsLongRunningMcoTaskScreen;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public abstract class LongRunningTask implements ErrorCallback, Runnable {
protected static final int NUMBER_OF_RETRIES = 25;
private static final Logger LOGGER = LogUtils.getLogger();
protected RealmsLongRunningMcoTaskScreen longRunningMcoTaskScreen;
protected static void pause(long pSeconds) {
try {
Thread.sleep(pSeconds * 1000L);
} catch (InterruptedException interruptedexception) {
Thread.currentThread().interrupt();
LOGGER.error("", (Throwable)interruptedexception);
}
}
public static void setScreen(Screen pScreen) {
Minecraft minecraft = Minecraft.getInstance();
minecraft.execute(() -> {
minecraft.setScreen(pScreen);
});
}
public void setScreen(RealmsLongRunningMcoTaskScreen pLongRunningMcoTaskScreen) {
this.longRunningMcoTaskScreen = pLongRunningMcoTaskScreen;
}
public void error(Component pError) {
this.longRunningMcoTaskScreen.error(pError);
}
public void setTitle(Component pTitle) {
this.longRunningMcoTaskScreen.setTitle(pTitle);
}
public boolean aborted() {
return this.longRunningMcoTaskScreen.aborted();
}
public void tick() {
}
public void init() {
}
public void abortTask() {
}
}
Loaded 100 of 14134 files, more files were not shown because too many files have changed in this diff. Show more