--- a/net/minecraft/world/item/component/ResolvableProfile.java
+++ b/net/minecraft/world/item/component/ResolvableProfile.java
@@ -46,7 +_,7 @@
     private static ResolvableProfile create(Either<GameProfile, ResolvableProfile.Partial> partialProfile, PlayerSkin.Patch skinPatch) {
         return partialProfile.map(
             gameProfile -> new ResolvableProfile.Static(Either.left(gameProfile), skinPatch),
-            partial -> (ResolvableProfile)(partial.properties.isEmpty() && partial.id.isPresent() != partial.name.isPresent()
+            partial -> (ResolvableProfile)(partial.properties.isEmpty() && partial.id.isPresent() != partial.name.isPresent() // Paper - diff on change - heuristic for dynamic vs static resolvable profile - used in CraftPlayerProfile#buildResolvable
                 ? partial.name
                     .<ResolvableProfile>map(string -> new ResolvableProfile.Dynamic(Either.left(string), skinPatch))
                     .orElseGet(() -> new ResolvableProfile.Dynamic(Either.right(partial.id.get()), skinPatch))
@@ -66,7 +_,7 @@
         return new ResolvableProfile.Dynamic(Either.right(id), PlayerSkin.Patch.EMPTY);
     }
 
-    protected abstract Either<GameProfile, ResolvableProfile.Partial> unpack();
+    public abstract Either<GameProfile, ResolvableProfile.Partial> unpack();
 
     protected ResolvableProfile(GameProfile partialProfile, PlayerSkin.Patch skinPatch) {
         this.partialProfile = partialProfile;
@@ -95,7 +_,7 @@
         private static final Component DYNAMIC_TOOLTIP = Component.translatable("component.profile.dynamic").withStyle(ChatFormatting.GRAY);
         private final Either<String, UUID> nameOrId;
 
-        Dynamic(Either<String, UUID> nameOrId, PlayerSkin.Patch patch) {
+        public Dynamic(Either<String, UUID> nameOrId, PlayerSkin.Patch patch) {
             super(ResolvableProfile.createPartialProfile(nameOrId.left(), nameOrId.right(), PropertyMap.EMPTY), patch);
             this.nameOrId = nameOrId;
         }
@@ -118,7 +_,7 @@
         }
 
         @Override
-        protected Either<GameProfile, ResolvableProfile.Partial> unpack() {
+        public Either<GameProfile, ResolvableProfile.Partial> unpack() {
             return Either.right(new ResolvableProfile.Partial(this.nameOrId.left(), this.nameOrId.right(), PropertyMap.EMPTY));
         }
 
@@ -133,15 +_,16 @@
         }
     }
 
-    protected record Partial(Optional<String> name, Optional<UUID> id, PropertyMap properties) {
+    public record Partial(Optional<String> name, Optional<UUID> id, PropertyMap properties) {
         public static final ResolvableProfile.Partial EMPTY = new ResolvableProfile.Partial(Optional.empty(), Optional.empty(), PropertyMap.EMPTY);
-        static final MapCodec<ResolvableProfile.Partial> MAP_CODEC = RecordCodecBuilder.mapCodec(
+        public static final MapCodec<ResolvableProfile.Partial> MAP_CODEC = RecordCodecBuilder.mapCodec(
             instance -> instance.group(
                     ExtraCodecs.PLAYER_NAME.optionalFieldOf("name").forGetter(ResolvableProfile.Partial::name),
                     UUIDUtil.CODEC.optionalFieldOf("id").forGetter(ResolvableProfile.Partial::id),
+                    UUIDUtil.STRING_CODEC.lenientOptionalFieldOf("Id").forGetter($ -> Optional.empty()), // Paper
                     ExtraCodecs.PROPERTY_MAP.optionalFieldOf("properties", PropertyMap.EMPTY).forGetter(ResolvableProfile.Partial::properties)
                 )
-                .apply(instance, ResolvableProfile.Partial::new)
+                .apply(instance, (name, uuid, uuid2, propertyMap) -> new ResolvableProfile.Partial(name, uuid2.or(() -> uuid), propertyMap)) // Paper
         );
         public static final StreamCodec<ByteBuf, ResolvableProfile.Partial> STREAM_CODEC = StreamCodec.composite(
             ByteBufCodecs.PLAYER_NAME.apply(ByteBufCodecs::optional),
@@ -162,7 +_,7 @@
         public static final ResolvableProfile.Static EMPTY = new ResolvableProfile.Static(Either.right(ResolvableProfile.Partial.EMPTY), PlayerSkin.Patch.EMPTY);
         private final Either<GameProfile, ResolvableProfile.Partial> contents;
 
-        Static(Either<GameProfile, ResolvableProfile.Partial> contents, PlayerSkin.Patch patch) {
+        public Static(Either<GameProfile, ResolvableProfile.Partial> contents, PlayerSkin.Patch patch) {
             super(contents.map(gameProfile -> (GameProfile)gameProfile, ResolvableProfile.Partial::createProfile), patch);
             this.contents = contents;
         }
@@ -173,7 +_,7 @@
         }
 
         @Override
-        protected Either<GameProfile, ResolvableProfile.Partial> unpack() {
+        public Either<GameProfile, ResolvableProfile.Partial> unpack() {
             return this.contents;
         }
 
