From 5d72c4f0b49dc1425ba8ac469b7005e5a49b6786 Mon Sep 17 00:00:00 2001 From: Matthew Messinger Date: Tue, 4 Sep 2018 18:51:07 -0400 Subject: [PATCH] Fix parseSkin race condition (final2) --- .../voxelmodpack/hdskins/HDSkinManager.java | 55 ++++++------------- .../hdskins/util/CallableFutures.java | 14 +++++ 2 files changed, 32 insertions(+), 37 deletions(-) diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/HDSkinManager.java b/src/hdskins/java/com/voxelmodpack/hdskins/HDSkinManager.java index 22b7543c..cf3fc6ff 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/HDSkinManager.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/HDSkinManager.java @@ -24,6 +24,7 @@ import com.voxelmodpack.hdskins.skins.LegacySkinServer; import com.voxelmodpack.hdskins.skins.ServerType; import com.voxelmodpack.hdskins.skins.SkinServer; import com.voxelmodpack.hdskins.skins.ValhallaSkinServer; +import com.voxelmodpack.hdskins.util.CallableFutures; import com.voxelmodpack.hdskins.util.PlayerUtil; import com.voxelmodpack.hdskins.util.ProfileTextureUtil; import net.minecraft.client.Minecraft; @@ -310,49 +311,29 @@ public final class HDSkinManager implements IResourceManagerReloadListener { } public void parseSkin(GameProfile profile, Type type, ResourceLocation resource, MinecraftProfileTexture texture) { - TextureManager tm = Minecraft.getMinecraft().getTextureManager(); - try { - // this runs in a separate thread anyway, so just get with a timeout. - getUntilNonnull(() -> tm.getTexture(resource)).get(1, TimeUnit.SECONDS); - } catch (InterruptedException | ExecutionException | TimeoutException e) { - throw new CompletionException(e); - } + CallableFutures.scheduleTask(() -> { - // grab the metadata object via reflection. Object is live. - Map metadata = ProfileTextureUtil.getMetadata(texture); + // grab the metadata object via reflection. Object is live. + Map metadata = ProfileTextureUtil.getMetadata(texture); - boolean wasNull = metadata == null; + boolean wasNull = metadata == null; - if (wasNull) { - metadata = new HashMap<>(); - } - - for (ISkinParser parser : skinParsers) { - try { - parser.parse(profile, type, resource, metadata); - } catch (Throwable t) { - logger.error("Exception thrown while parsing skin: ", t); - } - } - - if (wasNull && !metadata.isEmpty()) { - ProfileTextureUtil.setMetadata(texture, metadata); - } - } - - /** - * Continuously gets a item in a new thread until it returns nonnull. - */ - private static CompletableFuture getUntilNonnull(Supplier getter) { - return CompletableFuture.supplyAsync(() -> { - T res = null; - - while (res == null) { - res = getter.get(); + if (wasNull) { + metadata = new HashMap<>(); } - return res; + for (ISkinParser parser : skinParsers) { + try { + parser.parse(profile, type, resource, metadata); + } catch (Throwable t) { + logger.error("Exception thrown while parsing skin: ", t); + } + } + + if (wasNull && !metadata.isEmpty()) { + ProfileTextureUtil.setMetadata(texture, metadata); + } }); } diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/util/CallableFutures.java b/src/hdskins/java/com/voxelmodpack/hdskins/util/CallableFutures.java index 9afc4be3..4b98f309 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/util/CallableFutures.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/util/CallableFutures.java @@ -1,12 +1,19 @@ package com.voxelmodpack.hdskins.util; +import net.minecraft.client.Minecraft; + import java.util.concurrent.Callable; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import java.util.function.BiFunction; public class CallableFutures { + private static final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); + public static CompletableFuture asyncFailableFuture(Callable call, Executor exec) { CompletableFuture ret = new CompletableFuture<>(); exec.execute(() -> { @@ -31,4 +38,11 @@ public class CallableFutures { return null; }; } + + public static void scheduleTask(Runnable task) { + // schedule a task for next tick. + executor.schedule(() -> { + Minecraft.getMinecraft().addScheduledTask(task); + }, 50, TimeUnit.MILLISECONDS); + } }