-
Bug
-
Resolution: Duplicate
-
None
-
1.16.5, 21w07a
-
None
-
Unconfirmed
-
(Unassigned)
The game freezes for up to two seconds (twice in sequence) every time I place a custom player head with a missing id parameter
To reproduce give yourself a custom head using these NBT tags:
{ "SkullOwner": {"Name": "Notarealplayersnameplsfixthismojang", "Properties": { "textures": [{ "Value": "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZmQzNGIzZTI3YTNmZTUzODI3YjM3YWQ1OTU2YWNjYTA4ZjI4NjNjNjkyNmNjOTcxMTZkZGEzMzQ4Njk3YTVhOSJ9fX0" }]}}}
Edit: One slight amendment: The "Properties" attribute here may not be required to reproduce the error, as in addition to injecting a random UUID I remember finding that the game would strip all the properties as well.
From my own investigations, this seems to be multiple things going wrong at once:
- Notice that the NBT specifies a game profile with no "ID". By my own debugging I've found that the game profile that ends up being used to render the block has been given a random UUID, probably inserted by something else though I couldn't figure out where.
- Because the profile has a junk UUID, the game ends up trying to "fix" the profile as per the following code in SkullBlockEntity (edited for clarity):
@Nullable public static GameProfile loadProperties(@Nullable GameProfile gameProfile) { if (gameProfile != null && !ChatUtil.isEmpty(gameProfile.getName())) { if (gameProfile.isComplete() && gameProfile.getProperties().containsKey("textures")) { return gameProfile; } else if (userCache != null && sessionService != null) { GameProfile gameProfile2 = userCache.findByName(gameProfile.getName()); if (gameProfile2 != null) { Property property = Iterables.getFirst(gameProfile2.getProperties().get("textures"), null); if (property == null) { gameProfile2 = sessionService.fillProfileProperties(gameProfile2, true); } } return gameProfile2; } } return gameProfile; }
- This goes into UserCache#findByName which calls UserCache#findProfileByName which itself calls GameProfileRepository#findProfilesByNames located in YggdrasilGameProfileRepository.
- Finally, YggdrasilGameProfileRepository does a number of this:
- It calls
authenticationService.makeRequest(...);
Which takes a few seconds, then
- It calls
-
- It calls
Thread.sleep(DELAY_BETWEEN_PAGES);
Which stalls the thread for 100ms
- It calls
-
- If/When it fails, it then calls
Thread.sleep(DELAY_BETWEEN_FAILURES);
Which stalls the thread for an additional 750ms
-
- Finally, it repeats the above up to 3 times if it fails
Based on the above analysis, I can conclude that when placing a head it does the first page request and then unconditionally waits the 100ms, resulting in the pattern of two freezes (one long, one short) in quick succession as observed in the beginning.
My suggestion, since it takes a result callback and looks like it was intended to be called in a worker thread, is that you should really punt this over to a worker thread.
That can be easily done using a LoadingCache:
private static UserCache userCache; @Nullable private static MinecraftSessionService sessionService; private static final LoadingCache<GameProfile, CompletableFuture<GameProfile>> profileResolution = CacheBuilder.newBuilder() .expireAfterAccess(15, TimeUnit.SECONDS) .build(CacheLoader.from(profile -> { return CompletableFuture.supplyAsync(() -> { GameProfile p = userCache.findByName(profile.getName()); if (p != null) { Property property = Iterables.getFirst(p.getProperties().get("textures"), null); if (property == null) { p = sessionService.fillProfileProperties(p, true); } return p; } return profile; }, Util.getMainWorkerExecutor()); })); public GameProfile findFixedProfile(GameProfile profile) { return profileResolution.getUnchecked(profile).getNow(profile); }
But also I would look into why it's giving ids to game profiles that don't exist and were not specified to have one.
Edit 2: After fixing my environment I was able to look a little closer and it looks like the second culprit is the call to
sessionService.fillProfileProperties(gameProfile2, true)
...So I've made the necessary adjustments to my recommendation.
Code analysis + investigation was done in a decompiled development environment based on 21w05b and the Yarn mappings. The issue was also reproduced and confirmed present in a vanilla/official build of 21w07a using the regular launcher with default settings.
- duplicates
-
MC-65587 Lag spike while loading player head textures/player skins
- Resolved