mirror of
https://github.com/MineLittlePony/MineLittlePony.git
synced 2025-02-13 16:24:23 +01:00
Fix parseSkin race condition (final2)
This commit is contained in:
parent
953f17828c
commit
5d72c4f0b4
2 changed files with 32 additions and 37 deletions
|
@ -24,6 +24,7 @@ import com.voxelmodpack.hdskins.skins.LegacySkinServer;
|
||||||
import com.voxelmodpack.hdskins.skins.ServerType;
|
import com.voxelmodpack.hdskins.skins.ServerType;
|
||||||
import com.voxelmodpack.hdskins.skins.SkinServer;
|
import com.voxelmodpack.hdskins.skins.SkinServer;
|
||||||
import com.voxelmodpack.hdskins.skins.ValhallaSkinServer;
|
import com.voxelmodpack.hdskins.skins.ValhallaSkinServer;
|
||||||
|
import com.voxelmodpack.hdskins.util.CallableFutures;
|
||||||
import com.voxelmodpack.hdskins.util.PlayerUtil;
|
import com.voxelmodpack.hdskins.util.PlayerUtil;
|
||||||
import com.voxelmodpack.hdskins.util.ProfileTextureUtil;
|
import com.voxelmodpack.hdskins.util.ProfileTextureUtil;
|
||||||
import net.minecraft.client.Minecraft;
|
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) {
|
public void parseSkin(GameProfile profile, Type type, ResourceLocation resource, MinecraftProfileTexture texture) {
|
||||||
TextureManager tm = Minecraft.getMinecraft().getTextureManager();
|
|
||||||
|
|
||||||
try {
|
CallableFutures.scheduleTask(() -> {
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// grab the metadata object via reflection. Object is live.
|
// grab the metadata object via reflection. Object is live.
|
||||||
Map<String, String> metadata = ProfileTextureUtil.getMetadata(texture);
|
Map<String, String> metadata = ProfileTextureUtil.getMetadata(texture);
|
||||||
|
|
||||||
boolean wasNull = metadata == null;
|
boolean wasNull = metadata == null;
|
||||||
|
|
||||||
if (wasNull) {
|
if (wasNull) {
|
||||||
metadata = new HashMap<>();
|
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 <T> CompletableFuture<T> getUntilNonnull(Supplier<T> getter) {
|
|
||||||
return CompletableFuture.supplyAsync(() -> {
|
|
||||||
T res = null;
|
|
||||||
|
|
||||||
while (res == null) {
|
|
||||||
res = getter.get();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,19 @@
|
||||||
package com.voxelmodpack.hdskins.util;
|
package com.voxelmodpack.hdskins.util;
|
||||||
|
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.Executor;
|
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;
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
public class CallableFutures {
|
public class CallableFutures {
|
||||||
|
|
||||||
|
private static final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
|
||||||
|
|
||||||
public static <T> CompletableFuture<T> asyncFailableFuture(Callable<T> call, Executor exec) {
|
public static <T> CompletableFuture<T> asyncFailableFuture(Callable<T> call, Executor exec) {
|
||||||
CompletableFuture<T> ret = new CompletableFuture<>();
|
CompletableFuture<T> ret = new CompletableFuture<>();
|
||||||
exec.execute(() -> {
|
exec.execute(() -> {
|
||||||
|
@ -31,4 +38,11 @@ public class CallableFutures {
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void scheduleTask(Runnable task) {
|
||||||
|
// schedule a task for next tick.
|
||||||
|
executor.schedule(() -> {
|
||||||
|
Minecraft.getMinecraft().addScheduledTask(task);
|
||||||
|
}, 50, TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue