package com.mojang.realmsclient; import com.mojang.logging.LogUtils; import com.mojang.realmsclient.client.RealmsClient; import com.mojang.realmsclient.exception.RealmsServiceException; import com.mojang.realmsclient.gui.screens.RealmsClientOutdatedScreen; import com.mojang.realmsclient.gui.screens.RealmsGenericErrorScreen; import com.mojang.realmsclient.gui.screens.RealmsParentalConsentScreen; import java.util.Objects; import java.util.concurrent.CompletableFuture; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.Util; import net.minecraft.client.Minecraft; import net.minecraft.client.User; import net.minecraft.client.gui.screens.Screen; import net.minecraft.network.chat.Component; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; @Environment(EnvType.CLIENT) public class RealmsAvailability { private static final Logger LOGGER = LogUtils.getLogger(); @Nullable private static CompletableFuture future; public static CompletableFuture get() { if (future == null || shouldRefresh(future)) { future = check(); } return future; } private static boolean shouldRefresh(CompletableFuture future) { RealmsAvailability.Result result = (RealmsAvailability.Result)future.getNow(null); return result != null && result.exception() != null; } private static CompletableFuture check() { User user = Minecraft.getInstance().getUser(); return user.getType() != User.Type.MSA ? CompletableFuture.completedFuture(new RealmsAvailability.Result(RealmsAvailability.Type.AUTHENTICATION_ERROR)) : CompletableFuture.supplyAsync( () -> { RealmsClient realmsClient = RealmsClient.getOrCreate(); try { if (realmsClient.clientCompatible() != RealmsClient.CompatibleVersionResponse.COMPATIBLE) { return new RealmsAvailability.Result(RealmsAvailability.Type.INCOMPATIBLE_CLIENT); } else { return !realmsClient.hasParentalConsent() ? new RealmsAvailability.Result(RealmsAvailability.Type.NEEDS_PARENTAL_CONSENT) : new RealmsAvailability.Result(RealmsAvailability.Type.SUCCESS); } } catch (RealmsServiceException var2) { LOGGER.error("Couldn't connect to realms", (Throwable)var2); return var2.realmsError.errorCode() == 401 ? new RealmsAvailability.Result(RealmsAvailability.Type.AUTHENTICATION_ERROR) : new RealmsAvailability.Result(var2); } }, Util.ioPool() ); } @Environment(EnvType.CLIENT) public record Result(RealmsAvailability.Type type, @Nullable RealmsServiceException exception) { public Result(RealmsAvailability.Type type) { this(type, null); } public Result(RealmsServiceException exception) { this(RealmsAvailability.Type.UNEXPECTED_ERROR, exception); } @Nullable public Screen createErrorScreen(Screen lastScreen) { return (Screen)(switch (this.type) { case SUCCESS -> null; case INCOMPATIBLE_CLIENT -> new RealmsClientOutdatedScreen(lastScreen); case NEEDS_PARENTAL_CONSENT -> new RealmsParentalConsentScreen(lastScreen); case AUTHENTICATION_ERROR -> new RealmsGenericErrorScreen( Component.translatable("mco.error.invalid.session.title"), Component.translatable("mco.error.invalid.session.message"), lastScreen ); case UNEXPECTED_ERROR -> new RealmsGenericErrorScreen((RealmsServiceException)Objects.requireNonNull(this.exception), lastScreen); }); } } @Environment(EnvType.CLIENT) public static enum Type { SUCCESS, INCOMPATIBLE_CLIENT, NEEDS_PARENTAL_CONSENT, AUTHENTICATION_ERROR, UNEXPECTED_ERROR; } }