package com.mojang.realmsclient.util; import com.mojang.logging.LogUtils; import com.mojang.realmsclient.client.RealmsClient; import com.mojang.realmsclient.exception.RealmsServiceException; import java.time.Instant; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; import java.util.function.Function; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphicsExtractor; import net.minecraft.client.gui.components.PlayerFaceExtractor; import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.renderer.PlayerSkinRenderCache; import net.minecraft.network.chat.Component; import net.minecraft.util.Util; import net.minecraft.world.item.component.ResolvableProfile; import org.jspecify.annotations.Nullable; import org.slf4j.Logger; @Environment(EnvType.CLIENT) public class RealmsUtil { private static final Logger LOGGER = LogUtils.getLogger(); private static final Component RIGHT_NOW = Component.translatable("mco.util.time.now"); private static final int MINUTES = 60; private static final int HOURS = 3600; private static final int DAYS = 86400; public static Component convertToAgePresentation(final long timeDiff) { if (timeDiff < 0L) { return RIGHT_NOW; } else { long timeDiffInSeconds = timeDiff / 1000L; if (timeDiffInSeconds < 60L) { return Component.translatable("mco.time.secondsAgo", timeDiffInSeconds); } else if (timeDiffInSeconds < 3600L) { long minutes = timeDiffInSeconds / 60L; return Component.translatable("mco.time.minutesAgo", minutes); } else if (timeDiffInSeconds < 86400L) { long hours = timeDiffInSeconds / 3600L; return Component.translatable("mco.time.hoursAgo", hours); } else { long days = timeDiffInSeconds / 86400L; return Component.translatable("mco.time.daysAgo", days); } } } public static Component convertToAgePresentationFromInstant(final Instant date) { return convertToAgePresentation(System.currentTimeMillis() - date.toEpochMilli()); } public static void extractPlayerFace(final GuiGraphicsExtractor graphics, final int x, final int y, final int size, final UUID playerId) { PlayerSkinRenderCache.RenderInfo renderInfo = Minecraft.getInstance().playerSkinRenderCache().getOrDefault(ResolvableProfile.createUnresolved(playerId)); PlayerFaceExtractor.extractRenderState(graphics, renderInfo.playerSkin(), x, y, size); } public static CompletableFuture supplyAsync(final RealmsUtil.RealmsIoFunction function, @Nullable final Consumer onFailure) { return CompletableFuture.supplyAsync(() -> { RealmsClient client = RealmsClient.getOrCreate(); try { return function.apply(client); } catch (Throwable var5) { if (var5 instanceof RealmsServiceException e) { if (onFailure != null) { onFailure.accept(e); } } else { LOGGER.error("Unhandled exception", var5); } throw new RuntimeException(var5); } }, Util.nonCriticalIoPool()); } public static CompletableFuture runAsync(final RealmsUtil.RealmsIoConsumer function, @Nullable final Consumer onFailure) { return supplyAsync(function, onFailure); } public static Consumer openScreenOnFailure(final Function errorScreen) { Minecraft minecraft = Minecraft.getInstance(); return e -> minecraft.execute(() -> minecraft.gui.setScreen((Screen)errorScreen.apply(e))); } public static Consumer openScreenAndLogOnFailure(final Function errorScreen, final String errorMessage) { return openScreenOnFailure(errorScreen).andThen(e -> LOGGER.error(errorMessage, (Throwable)e)); } @FunctionalInterface @Environment(EnvType.CLIENT) public interface RealmsIoConsumer extends RealmsUtil.RealmsIoFunction { void accept(final RealmsClient client) throws RealmsServiceException; default Void apply(final RealmsClient client) throws RealmsServiceException { this.accept(client); return null; } } @FunctionalInterface @Environment(EnvType.CLIENT) public interface RealmsIoFunction { T apply(final RealmsClient client) throws RealmsServiceException; } }