--- a/net/minecraft/world/level/block/entity/SkullBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/SkullBlockEntity.java
@@ -40,7 +_,7 @@
     @Nullable
     private static LoadingCache<String, CompletableFuture<Optional<GameProfile>>> profileCacheByName;
     @Nullable
-    private static LoadingCache<UUID, CompletableFuture<Optional<GameProfile>>> profileCacheById;
+    private static LoadingCache<com.mojang.datafixers.util.Pair<java.util.UUID,  @org.jetbrains.annotations.Nullable GameProfile>, CompletableFuture<Optional<GameProfile>>> profileCacheById; // Paper - player profile events
     public static final Executor CHECKED_MAIN_THREAD_EXECUTOR = runnable -> {
         Executor executor = mainThreadExecutor;
         if (executor != null) {
@@ -48,13 +_,13 @@
         }
     };
     @Nullable
-    private ResolvableProfile owner;
+    public ResolvableProfile owner;
     @Nullable
-    private ResourceLocation noteBlockSound;
+    public ResourceLocation noteBlockSound;
     private int animationTickCount;
     private boolean isAnimating;
     @Nullable
-    private Component customName;
+    public Component customName;
 
     public SkullBlockEntity(BlockPos pos, BlockState blockState) {
         super(BlockEntityType.SKULL, pos, blockState);
@@ -75,9 +_,9 @@
         profileCacheById = CacheBuilder.newBuilder()
             .expireAfterAccess(Duration.ofMinutes(10L))
             .maximumSize(256L)
-            .build(new CacheLoader<UUID, CompletableFuture<Optional<GameProfile>>>() {
+            .build(new CacheLoader<>() { // Paper - player profile events
                 @Override
-                public CompletableFuture<Optional<GameProfile>> load(UUID id) {
+                public CompletableFuture<Optional<GameProfile>> load(com.mojang.datafixers.util.Pair<java.util.UUID, @org.jetbrains.annotations.Nullable GameProfile> id) { // Paper - player profile events
                     return SkullBlockEntity.fetchProfileById(id, services, booleanSupplier);
                 }
             });
@@ -88,23 +_,29 @@
             .getAsync(name)
             .thenCompose(
                 optional -> {
-                    LoadingCache<UUID, CompletableFuture<Optional<GameProfile>>> loadingCache = profileCacheById;
+                    LoadingCache<com.mojang.datafixers.util.Pair<java.util.UUID, @org.jetbrains.annotations.Nullable GameProfile>, CompletableFuture<Optional<GameProfile>>> loadingCache = profileCacheById; // Paper - player profile events
                     return loadingCache != null && !optional.isEmpty()
-                        ? loadingCache.getUnchecked(optional.get().getId()).thenApply(optional1 -> optional1.or(() -> optional))
+                        ? loadingCache.getUnchecked(new com.mojang.datafixers.util.Pair<>(optional.get().getId(), optional.get())).thenApply(optional1 -> optional1.or(() -> optional)) // Paper - player profile events
                         : CompletableFuture.completedFuture(Optional.empty());
                 }
             );
     }
 
-    static CompletableFuture<Optional<GameProfile>> fetchProfileById(UUID id, Services services, BooleanSupplier cacheUninitialized) {
+    static CompletableFuture<Optional<GameProfile>> fetchProfileById(com.mojang.datafixers.util.Pair<java.util.UUID, @org.jetbrains.annotations.Nullable GameProfile> id, Services services, BooleanSupplier cacheUninitialized) { // Paper
         return CompletableFuture.supplyAsync(() -> {
             if (cacheUninitialized.getAsBoolean()) {
                 return Optional.empty();
             } else {
-                ProfileResult profileResult = services.sessionService().fetchProfile(id, true);
+                // Paper start - fill player profile events
+                if (services.sessionService() instanceof com.destroystokyo.paper.profile.PaperMinecraftSessionService paperService) {
+                    final GameProfile profile = id.getSecond() != null ? id.getSecond() : new com.mojang.authlib.GameProfile(id.getFirst(), "");
+                    return Optional.ofNullable(paperService.fetchProfile(profile, true)).map(ProfileResult::profile);
+                }
+                ProfileResult profileResult = services.sessionService().fetchProfile(id.getFirst(), true);
+                // Paper end - fill player profile events
                 return Optional.ofNullable(profileResult).map(ProfileResult::profile);
             }
-        }, Util.backgroundExecutor().forName("fetchProfile"));
+        }, Util.PROFILE_EXECUTOR); // Paper - don't submit BLOCKING PROFILE LOOKUPS to the world gen thread
     }
 
     public static void clear() {
@@ -188,9 +_,11 @@
             : CompletableFuture.completedFuture(Optional.empty());
     }
 
-    public static CompletableFuture<Optional<GameProfile>> fetchGameProfile(UUID profileUuid) {
-        LoadingCache<UUID, CompletableFuture<Optional<GameProfile>>> loadingCache = profileCacheById;
-        return loadingCache != null ? loadingCache.getUnchecked(profileUuid) : CompletableFuture.completedFuture(Optional.empty());
+    // Paper start - player profile events
+    public static CompletableFuture<Optional<GameProfile>> fetchGameProfile(UUID profileUuid, @Nullable String name) {
+        LoadingCache<com.mojang.datafixers.util.Pair<java.util.UUID,  @org.jetbrains.annotations.Nullable GameProfile>, CompletableFuture<Optional<GameProfile>>> loadingCache = profileCacheById;
+        return loadingCache != null ? loadingCache.getUnchecked(new com.mojang.datafixers.util.Pair<>(profileUuid, name != null ? new com.mojang.authlib.GameProfile(profileUuid, name) : null)) : CompletableFuture.completedFuture(Optional.empty());
+        // Paper end - player profile events
     }
 
     @Override
