package net.minecraft.world.item.component; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.PropertyMap; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; import io.netty.buffer.ByteBuf; import java.util.Optional; import java.util.UUID; import java.util.concurrent.CompletableFuture; import net.minecraft.Util; import net.minecraft.core.UUIDUtil; import net.minecraft.network.codec.ByteBufCodecs; import net.minecraft.network.codec.StreamCodec; import net.minecraft.util.ExtraCodecs; import net.minecraft.world.level.block.entity.SkullBlockEntity; import org.jetbrains.annotations.Nullable; public record ResolvableProfile(Optional name, Optional id, PropertyMap properties, GameProfile gameProfile) { private static final Codec FULL_CODEC = RecordCodecBuilder.create( instance -> instance.group( ExtraCodecs.PLAYER_NAME.optionalFieldOf("name").forGetter(ResolvableProfile::name), UUIDUtil.CODEC.optionalFieldOf("id").forGetter(ResolvableProfile::id), ExtraCodecs.PROPERTY_MAP.optionalFieldOf("properties", new PropertyMap()).forGetter(ResolvableProfile::properties) ) .apply(instance, ResolvableProfile::new) ); public static final Codec CODEC = Codec.withAlternative( FULL_CODEC, ExtraCodecs.PLAYER_NAME, string -> new ResolvableProfile(Optional.of(string), Optional.empty(), new PropertyMap()) ); public static final StreamCodec STREAM_CODEC = StreamCodec.composite( ByteBufCodecs.stringUtf8(16).apply(ByteBufCodecs::optional), ResolvableProfile::name, UUIDUtil.STREAM_CODEC.apply(ByteBufCodecs::optional), ResolvableProfile::id, ByteBufCodecs.GAME_PROFILE_PROPERTIES, ResolvableProfile::properties, ResolvableProfile::new ); public ResolvableProfile(Optional name, Optional id, PropertyMap properties) { this(name, id, properties, createGameProfile(id, name, properties)); } public ResolvableProfile(GameProfile profile) { this(Optional.of(profile.getName()), Optional.of(profile.getId()), profile.getProperties(), profile); } @Nullable public ResolvableProfile pollResolve() { if (this.isResolved()) { return this; } else { Optional optional; if (this.id.isPresent()) { optional = (Optional)SkullBlockEntity.fetchGameProfile((UUID)this.id.get()).getNow(null); } else { optional = (Optional)SkullBlockEntity.fetchGameProfile((String)this.name.orElseThrow()).getNow(null); } return optional != null ? this.createProfile(optional) : null; } } public CompletableFuture resolve() { if (this.isResolved()) { return CompletableFuture.completedFuture(this); } else { return this.id.isPresent() ? SkullBlockEntity.fetchGameProfile((UUID)this.id.get()).thenApply(this::createProfile) : SkullBlockEntity.fetchGameProfile((String)this.name.orElseThrow()).thenApply(this::createProfile); } } private ResolvableProfile createProfile(Optional profile) { return new ResolvableProfile((GameProfile)profile.orElseGet(() -> createGameProfile(this.id, this.name))); } private static GameProfile createGameProfile(Optional id, Optional name) { return new GameProfile((UUID)id.orElse(Util.NIL_UUID), (String)name.orElse("")); } private static GameProfile createGameProfile(Optional id, Optional name, PropertyMap properties) { GameProfile gameProfile = createGameProfile(id, name); gameProfile.getProperties().putAll(properties); return gameProfile; } public boolean isResolved() { return !this.properties.isEmpty() ? true : this.id.isPresent() == this.name.isPresent(); } }