mirror of
https://github.com/MineLittlePony/MineLittlePony.git
synced 2024-11-29 23:48:00 +01:00
Slightly rewrite texture loading so it is better adaptable.
Also exposes metadata more
This commit is contained in:
parent
72324feaf3
commit
981cd002b3
8 changed files with 183 additions and 193 deletions
|
@ -19,18 +19,19 @@ import com.mumfrey.liteloader.core.LiteLoader;
|
||||||
import com.mumfrey.liteloader.util.log.LiteLoaderLogger;
|
import com.mumfrey.liteloader.util.log.LiteLoaderLogger;
|
||||||
import com.voxelmodpack.hdskins.gui.GuiSkins;
|
import com.voxelmodpack.hdskins.gui.GuiSkins;
|
||||||
import com.voxelmodpack.hdskins.resource.SkinResourceManager;
|
import com.voxelmodpack.hdskins.resource.SkinResourceManager;
|
||||||
import com.voxelmodpack.hdskins.skins.AsyncCacheLoader;
|
|
||||||
import com.voxelmodpack.hdskins.skins.BethlehemSkinServer;
|
import com.voxelmodpack.hdskins.skins.BethlehemSkinServer;
|
||||||
import com.voxelmodpack.hdskins.skins.LegacySkinServer;
|
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 net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.renderer.texture.TextureManager;
|
import net.minecraft.client.network.NetHandlerPlayClient;
|
||||||
|
import net.minecraft.client.network.NetworkPlayerInfo;
|
||||||
|
import net.minecraft.client.renderer.texture.ITextureObject;
|
||||||
import net.minecraft.client.resources.DefaultPlayerSkin;
|
import net.minecraft.client.resources.DefaultPlayerSkin;
|
||||||
import net.minecraft.client.resources.IResourceManager;
|
import net.minecraft.client.resources.IResourceManager;
|
||||||
import net.minecraft.client.resources.IResourceManagerReloadListener;
|
import net.minecraft.client.resources.IResourceManagerReloadListener;
|
||||||
import net.minecraft.client.resources.SkinManager.SkinAvailableCallback;
|
import net.minecraft.client.resources.SkinManager;
|
||||||
import net.minecraft.util.ResourceLocation;
|
import net.minecraft.util.ResourceLocation;
|
||||||
import org.apache.commons.io.FileUtils;
|
import org.apache.commons.io.FileUtils;
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
|
@ -46,15 +47,17 @@ import java.lang.reflect.Modifier;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public final class HDSkinManager implements IResourceManagerReloadListener {
|
public final class HDSkinManager implements IResourceManagerReloadListener {
|
||||||
|
|
||||||
|
@ -64,24 +67,16 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
|
||||||
public static final ExecutorService skinDownloadExecutor = Executors.newFixedThreadPool(8);
|
public static final ExecutorService skinDownloadExecutor = Executors.newFixedThreadPool(8);
|
||||||
public static final CloseableHttpClient httpClient = HttpClients.createSystem();
|
public static final CloseableHttpClient httpClient = HttpClients.createSystem();
|
||||||
|
|
||||||
private static final ResourceLocation LOADING = new ResourceLocation("LOADING");
|
|
||||||
|
|
||||||
public static final HDSkinManager INSTANCE = new HDSkinManager();
|
public static final HDSkinManager INSTANCE = new HDSkinManager();
|
||||||
|
|
||||||
private boolean enabled = true;
|
|
||||||
|
|
||||||
private List<ISkinCacheClearListener> clearListeners = Lists.newArrayList();
|
private List<ISkinCacheClearListener> clearListeners = Lists.newArrayList();
|
||||||
|
|
||||||
private BiMap<String, Class<? extends SkinServer>> skinServerTypes = HashBiMap.create(2);
|
private BiMap<String, Class<? extends SkinServer>> skinServerTypes = HashBiMap.create(2);
|
||||||
private List<SkinServer> skinServers = Lists.newArrayList();
|
private List<SkinServer> skinServers = Lists.newArrayList();
|
||||||
|
|
||||||
private Map<UUID, Map<Type, ResourceLocation>> skinCache = Maps.newHashMap();
|
private LoadingCache<GameProfile, CompletableFuture<Map<Type, MinecraftProfileTexture>>> skins = CacheBuilder.newBuilder()
|
||||||
|
.expireAfterAccess(15, TimeUnit.SECONDS)
|
||||||
private LoadingCache<GameProfile, Map<Type, MinecraftProfileTexture>> skins = CacheBuilder.newBuilder()
|
.build(CacheLoader.from(this::loadProfileData));
|
||||||
.initialCapacity(20)
|
|
||||||
.maximumSize(100)
|
|
||||||
.expireAfterWrite(4, TimeUnit.HOURS)
|
|
||||||
.build(AsyncCacheLoader.create(CacheLoader.from(this::loadProfileData), Collections.emptyMap(), skinDownloadExecutor));
|
|
||||||
|
|
||||||
private List<ISkinModifier> skinModifiers = Lists.newArrayList();
|
private List<ISkinModifier> skinModifiers = Lists.newArrayList();
|
||||||
|
|
||||||
|
@ -107,19 +102,30 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
|
||||||
return skinsGuiFunc.apply(ImmutableList.copyOf(this.skinServers));
|
return skinsGuiFunc.apply(ImmutableList.copyOf(this.skinServers));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<ResourceLocation> getSkinLocation(GameProfile profile1, final Type type, boolean loadIfAbsent) {
|
private CompletableFuture<Map<Type, MinecraftProfileTexture>> loadProfileData(GameProfile profile) {
|
||||||
if (!enabled) {
|
|
||||||
return Optional.empty();
|
return CompletableFuture.supplyAsync(() -> {
|
||||||
|
Map<Type, MinecraftProfileTexture> textureMap = Maps.newEnumMap(Type.class);
|
||||||
|
|
||||||
|
for (SkinServer server : skinServers) {
|
||||||
|
try {
|
||||||
|
server.loadProfileData(profile).getTextures().forEach(textureMap::putIfAbsent);
|
||||||
|
if (textureMap.size() == Type.values().length) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.trace(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResourceLocation skin = this.resources.getPlayerTexture(profile1, type);
|
}
|
||||||
if (skin != null) {
|
return textureMap;
|
||||||
return Optional.of(skin);
|
}, skinDownloadExecutor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<Map<Type, MinecraftProfileTexture>> loadProfileTextures(GameProfile profile) {
|
||||||
// try to recreate a broken gameprofile
|
// try to recreate a broken gameprofile
|
||||||
// happens when server sends a random profile with skin and displayname
|
// happens when server sends a random profile with skin and displayname
|
||||||
Property textures = Iterables.getFirst(profile1.getProperties().get("textures"), null);
|
Property textures = Iterables.getFirst(profile.getProperties().get("textures"), null);
|
||||||
if (textures != null) {
|
if (textures != null) {
|
||||||
String json = new String(Base64.getDecoder().decode(textures.getValue()), StandardCharsets.UTF_8);
|
String json = new String(Base64.getDecoder().decode(textures.getValue()), StandardCharsets.UTF_8);
|
||||||
MinecraftTexturesPayload texturePayload = SkinServer.gson.fromJson(json, MinecraftTexturesPayload.class);
|
MinecraftTexturesPayload texturePayload = SkinServer.gson.fromJson(json, MinecraftTexturesPayload.class);
|
||||||
|
@ -129,86 +135,55 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
|
||||||
UUID uuid = texturePayload.getProfileId();
|
UUID uuid = texturePayload.getProfileId();
|
||||||
// uuid is required
|
// uuid is required
|
||||||
if (uuid != null) {
|
if (uuid != null) {
|
||||||
profile1 = new GameProfile(uuid, name);
|
profile = new GameProfile(uuid, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// probably uses this texture for a reason. Don't mess with it.
|
// probably uses this texture for a reason. Don't mess with it.
|
||||||
if (!texturePayload.getTextures().isEmpty() && texturePayload.getProfileId() == null) {
|
if (!texturePayload.getTextures().isEmpty() && texturePayload.getProfileId() == null) {
|
||||||
return Optional.empty();
|
return CompletableFuture.completedFuture(Collections.emptyMap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final GameProfile profile = profile1;
|
return skins.getUnchecked(profile);
|
||||||
|
|
||||||
// cannot get texture without id!
|
|
||||||
if (profile.getId() == null) {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.skinCache.containsKey(profile.getId())) {
|
|
||||||
this.skinCache.put(profile.getId(), Maps.newHashMap());
|
|
||||||
}
|
|
||||||
|
|
||||||
skin = this.skinCache.get(profile.getId()).get(type);
|
|
||||||
if (skin == null) {
|
|
||||||
if (loadIfAbsent && getProfileData(profile).containsKey(type)) {
|
|
||||||
skinCache.get(profile.getId()).put(type, LOADING);
|
|
||||||
loadTexture(profile, type, (t, loc, tex) -> skinCache.get(profile.getId()).put(t, loc));
|
|
||||||
}
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
return skin == LOADING ? Optional.empty() : Optional.of(skin);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadTexture(GameProfile profile, final Type type, final SkinAvailableCallback callback) {
|
|
||||||
if (profile.getId() == null) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ResourceLocation loadTexture(Type type, MinecraftProfileTexture texture, @Nullable SkinManager.SkinAvailableCallback callback) {
|
||||||
String skinDir = type.toString().toLowerCase() + "s/";
|
String skinDir = type.toString().toLowerCase() + "s/";
|
||||||
|
|
||||||
final MinecraftProfileTexture texture = getProfileData(profile).get(type);
|
|
||||||
final ResourceLocation resource = new ResourceLocation("hdskins", skinDir + texture.getHash());
|
final ResourceLocation resource = new ResourceLocation("hdskins", skinDir + texture.getHash());
|
||||||
|
ITextureObject texObj = Minecraft.getMinecraft().getTextureManager().getTexture(resource);
|
||||||
|
|
||||||
ISkinAvailableCallback buffs = new ImageBufferDownloadHD(type, () -> {
|
//noinspection ConstantConditions
|
||||||
|
if (texObj != null) {
|
||||||
|
if (callback != null) {
|
||||||
callback.skinAvailable(type, resource, texture);
|
callback.skinAvailable(type, resource, texture);
|
||||||
});
|
}
|
||||||
|
} else {
|
||||||
// schedule texture loading on the main thread.
|
// schedule texture loading on the main thread.
|
||||||
TextureLoader.loadTexture(resource, new ThreadDownloadImageETag(
|
TextureLoader.loadTexture(resource, new ThreadDownloadImageETag(
|
||||||
new File(LiteLoader.getAssetsDirectory(), "hd/" + skinDir + texture.getHash().substring(0, 2) + "/" + texture.getHash()),
|
new File(LiteLoader.getAssetsDirectory(), "hd/" + skinDir + texture.getHash().substring(0, 2) + "/" + texture.getHash()),
|
||||||
texture.getUrl(),
|
texture.getUrl(),
|
||||||
DefaultPlayerSkin.getDefaultSkinLegacy(),
|
DefaultPlayerSkin.getDefaultSkinLegacy(),
|
||||||
buffs));
|
new ImageBufferDownloadHD(type, () -> {
|
||||||
|
if (callback != null) {
|
||||||
|
callback.skinAvailable(type, resource, texture);
|
||||||
|
}
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
return resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<Type, MinecraftProfileTexture> loadProfileData(GameProfile profile) {
|
public Map<Type, ResourceLocation> getTextures(GameProfile profile) {
|
||||||
Map<Type, MinecraftProfileTexture> textures = Maps.newEnumMap(Type.class);
|
|
||||||
for (SkinServer server : skinServers) {
|
Map<Type, ResourceLocation> map = new HashMap<>();
|
||||||
try {
|
for (Map.Entry<Type, MinecraftProfileTexture> e : loadProfileTextures(profile).getNow(Collections.emptyMap()).entrySet()) {
|
||||||
server.loadProfileData(profile).getTextures().forEach(textures::putIfAbsent);
|
map.put(e.getKey(), loadTexture(e.getKey(), e.getValue(), null));
|
||||||
if (textures.size() == Type.values().length) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.trace(e);
|
|
||||||
}
|
}
|
||||||
|
return map;
|
||||||
|
|
||||||
}
|
}
|
||||||
return textures;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<Type, MinecraftProfileTexture> getProfileData(GameProfile profile) {
|
private void addSkinServerType(Class<? extends SkinServer> type) {
|
||||||
boolean was = !skins.asMap().containsKey(profile);
|
|
||||||
Map<Type, MinecraftProfileTexture> textures = skins.getUnchecked(profile);
|
|
||||||
// This is the initial value. Refreshing will load it asynchronously.
|
|
||||||
if (was) {
|
|
||||||
skins.refresh(profile);
|
|
||||||
}
|
|
||||||
return textures;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addSkinServerType(Class<? extends SkinServer> type) {
|
|
||||||
Preconditions.checkArgument(!type.isInterface(), "type cannot be an interface");
|
Preconditions.checkArgument(!type.isInterface(), "type cannot be an interface");
|
||||||
Preconditions.checkArgument(!Modifier.isAbstract(type.getModifiers()), "type cannot be abstract");
|
Preconditions.checkArgument(!Modifier.isAbstract(type.getModifiers()), "type cannot be abstract");
|
||||||
ServerType st = type.getAnnotation(ServerType.class);
|
ServerType st = type.getAnnotation(ServerType.class);
|
||||||
|
@ -222,14 +197,10 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
|
||||||
return this.skinServerTypes.get(type);
|
return this.skinServerTypes.get(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addSkinServer(SkinServer skinServer) {
|
void addSkinServer(SkinServer skinServer) {
|
||||||
this.skinServers.add(skinServer);
|
this.skinServers.add(skinServer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setEnabled(boolean enabled) {
|
|
||||||
this.enabled = enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addClearListener(ISkinCacheClearListener listener) {
|
public void addClearListener(ISkinCacheClearListener listener) {
|
||||||
clearListeners.add(listener);
|
clearListeners.add(listener);
|
||||||
}
|
}
|
||||||
|
@ -237,18 +208,14 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
|
||||||
public void clearSkinCache() {
|
public void clearSkinCache() {
|
||||||
LiteLoaderLogger.info("Clearing local player skin cache");
|
LiteLoaderLogger.info("Clearing local player skin cache");
|
||||||
|
|
||||||
try {
|
FileUtils.deleteQuietly(new File(LiteLoader.getAssetsDirectory(), "hd"));
|
||||||
FileUtils.deleteDirectory(new File(LiteLoader.getAssetsDirectory(), "skins"));
|
|
||||||
FileUtils.deleteDirectory(new File(LiteLoader.getAssetsDirectory(), "hd"));
|
NetHandlerPlayClient connection = Minecraft.getMinecraft().getConnection();
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
if (connection != null) {
|
||||||
|
connection.getPlayerInfoMap().forEach(this::clearNetworkSkin);
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureManager textures = Minecraft.getMinecraft().getTextureManager();
|
|
||||||
skinCache.values().stream()
|
|
||||||
.flatMap(m -> m.values().stream())
|
|
||||||
.forEach(textures::deleteTexture);
|
|
||||||
skinCache.clear();
|
|
||||||
skins.invalidateAll();
|
skins.invalidateAll();
|
||||||
|
|
||||||
clearListeners = clearListeners.stream()
|
clearListeners = clearListeners.stream()
|
||||||
|
@ -256,6 +223,10 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void clearNetworkSkin(NetworkPlayerInfo player) {
|
||||||
|
((INetworkPlayerInfo) player).deleteTextures();
|
||||||
|
}
|
||||||
|
|
||||||
private boolean onSkinCacheCleared(ISkinCacheClearListener callback) {
|
private boolean onSkinCacheCleared(ISkinCacheClearListener callback) {
|
||||||
try {
|
try {
|
||||||
return callback.onSkinCacheCleared();
|
return callback.onSkinCacheCleared();
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
package com.voxelmodpack.hdskins;
|
||||||
|
|
||||||
|
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
|
||||||
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public interface INetworkPlayerInfo {
|
||||||
|
|
||||||
|
Optional<ResourceLocation> getResourceLocation(MinecraftProfileTexture.Type type);
|
||||||
|
|
||||||
|
Optional<MinecraftProfileTexture> getProfileTexture(MinecraftProfileTexture.Type type);
|
||||||
|
|
||||||
|
void deleteTextures();
|
||||||
|
}
|
|
@ -4,65 +4,92 @@ import com.mojang.authlib.GameProfile;
|
||||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
|
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
|
||||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
|
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
|
||||||
import com.voxelmodpack.hdskins.HDSkinManager;
|
import com.voxelmodpack.hdskins.HDSkinManager;
|
||||||
|
import com.voxelmodpack.hdskins.INetworkPlayerInfo;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.network.NetworkPlayerInfo;
|
import net.minecraft.client.network.NetworkPlayerInfo;
|
||||||
|
import net.minecraft.client.renderer.texture.TextureManager;
|
||||||
import net.minecraft.util.ResourceLocation;
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
@Mixin(NetworkPlayerInfo.class)
|
@Mixin(NetworkPlayerInfo.class)
|
||||||
public abstract class MixinPlayerInfo {
|
public abstract class MixinPlayerInfo implements INetworkPlayerInfo {
|
||||||
|
|
||||||
@Shadow
|
|
||||||
public abstract GameProfile getGameProfile();
|
|
||||||
|
|
||||||
@Inject(
|
private Map<Type, ResourceLocation> customTextures = new HashMap<>();
|
||||||
method = "getLocationSkin",
|
private Map<Type, MinecraftProfileTexture> customProfiles = new HashMap<>();
|
||||||
cancellable = true,
|
|
||||||
at = @At("RETURN"))
|
@Shadow @Final private GameProfile gameProfile;
|
||||||
private void getLocationSkin(CallbackInfoReturnable<ResourceLocation> ci) {
|
|
||||||
getTextureLocation(ci, Type.SKIN);
|
@Shadow public abstract String getSkinType();
|
||||||
|
|
||||||
|
@SuppressWarnings("InvalidMemberReference") // mc-dev bug?
|
||||||
|
@Redirect(
|
||||||
|
method = {
|
||||||
|
"getLocationSkin",
|
||||||
|
"getLocationCape",
|
||||||
|
"getLocationElytra"
|
||||||
|
}, at = @At(value = "INVOKE", target = "Ljava/util/Map;get(Ljava/lang/Object;)Ljava/lang/Object;"))
|
||||||
|
// synthetic
|
||||||
|
private Object getSkin(Map<Type, ResourceLocation> playerTextures, Object key) {
|
||||||
|
return getSkin(playerTextures, (Type) key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Inject(
|
// with generics
|
||||||
method = "getLocationCape",
|
private ResourceLocation getSkin(Map<Type, ResourceLocation> playerTextures, Type type) {
|
||||||
cancellable = true,
|
return getResourceLocation(type).orElseGet(() -> playerTextures.get(type));
|
||||||
at = @At("RETURN"))
|
|
||||||
private void getLocationCape(CallbackInfoReturnable<ResourceLocation> ci) {
|
|
||||||
getTextureLocation(ci, Type.CAPE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Inject(
|
@Inject(method = "getSkinType", at = @At("RETURN"), cancellable = true)
|
||||||
method = "getLocationElytra",
|
private void getTextureModel(CallbackInfoReturnable<String> cir) {
|
||||||
cancellable = true,
|
getProfileTexture(Type.SKIN).ifPresent(profile -> {
|
||||||
at = @At("RETURN"))
|
String model = profile.getMetadata("model");
|
||||||
private void getLocationElytra(CallbackInfoReturnable<ResourceLocation> ci) {
|
cir.setReturnValue(model != null ? model : "default");
|
||||||
getTextureLocation(ci, Type.ELYTRA);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void getTextureLocation(CallbackInfoReturnable<ResourceLocation> ci, Type type) {
|
@Inject(method = "loadPlayerTextures",
|
||||||
Optional<ResourceLocation> texture = HDSkinManager.INSTANCE.getSkinLocation(getGameProfile(), type, true);
|
at = @At(value = "INVOKE",
|
||||||
texture.ifPresent(ci::setReturnValue);
|
target = "Lnet/minecraft/client/resources/SkinManager;loadProfileTextures("
|
||||||
|
+ "Lcom/mojang/authlib/GameProfile;"
|
||||||
|
+ "Lnet/minecraft/client/resources/SkinManager$SkinAvailableCallback;"
|
||||||
|
+ "Z)V",
|
||||||
|
shift = At.Shift.BEFORE))
|
||||||
|
private void onLoadTexture(CallbackInfo ci) {
|
||||||
|
HDSkinManager.INSTANCE.loadProfileTextures(this.gameProfile)
|
||||||
|
.thenAcceptAsync(m -> m.forEach((type, profile) -> {
|
||||||
|
HDSkinManager.INSTANCE.loadTexture(type, profile, (typeIn, location, profileTexture) -> {
|
||||||
|
customTextures.put(type, location);
|
||||||
|
customProfiles.put(type, profileTexture);
|
||||||
|
});
|
||||||
|
}), Minecraft.getMinecraft()::addScheduledTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Inject(
|
@Override
|
||||||
method = "getSkinType",
|
public Optional<ResourceLocation> getResourceLocation(Type type) {
|
||||||
cancellable = true,
|
return Optional.ofNullable(this.customTextures.get(type));
|
||||||
at = @At("RETURN"))
|
|
||||||
private void getSkinType(CallbackInfoReturnable<String> ci) {
|
|
||||||
MinecraftProfileTexture skin = HDSkinManager.INSTANCE.getProfileData(getGameProfile()).get(Type.SKIN);
|
|
||||||
if (skin != null) {
|
|
||||||
String type = skin.getMetadata("model");
|
|
||||||
if (type == null)
|
|
||||||
type = "default";
|
|
||||||
String type1 = type;
|
|
||||||
Optional<ResourceLocation> texture = HDSkinManager.INSTANCE.getSkinLocation(getGameProfile(), Type.SKIN, false);
|
|
||||||
|
|
||||||
texture.ifPresent((res) -> ci.setReturnValue(type1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<MinecraftProfileTexture> getProfileTexture(Type type) {
|
||||||
|
return Optional.ofNullable(this.customProfiles.get(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteTextures() {
|
||||||
|
TextureManager tm = Minecraft.getMinecraft().getTextureManager();
|
||||||
|
this.customTextures.values().forEach(tm::deleteTexture);
|
||||||
|
this.customTextures.clear();
|
||||||
|
this.customProfiles.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,6 @@ import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
@Mixin(TileEntitySkullRenderer.class)
|
@Mixin(TileEntitySkullRenderer.class)
|
||||||
public abstract class MixinSkullRenderer extends TileEntitySpecialRenderer<TileEntitySkull> {
|
public abstract class MixinSkullRenderer extends TileEntitySpecialRenderer<TileEntitySkull> {
|
||||||
|
@ -24,16 +23,15 @@ public abstract class MixinSkullRenderer extends TileEntitySpecialRenderer<TileE
|
||||||
value = "INVOKE",
|
value = "INVOKE",
|
||||||
target = "Lnet/minecraft/client/renderer/tileentity/TileEntitySkullRenderer;bindTexture(Lnet/minecraft/util/ResourceLocation;)V",
|
target = "Lnet/minecraft/client/renderer/tileentity/TileEntitySkullRenderer;bindTexture(Lnet/minecraft/util/ResourceLocation;)V",
|
||||||
ordinal = 4))
|
ordinal = 4))
|
||||||
private void onBindTexture(TileEntitySkullRenderer tesr, ResourceLocation rl, float x, float y, float z, EnumFacing facing, float rotation, int meta,
|
private void onBindTexture(TileEntitySkullRenderer tesr, ResourceLocation rl, float x, float y, float z, EnumFacing facing, float rotation,
|
||||||
|
int meta,
|
||||||
@Nullable GameProfile profile, int p_180543_8_, float ticks) {
|
@Nullable GameProfile profile, int p_180543_8_, float ticks) {
|
||||||
if (profile != null) {
|
if (profile != null) {
|
||||||
Optional<ResourceLocation> skin = HDSkinManager.INSTANCE.getSkinLocation(profile, Type.SKIN, true);
|
ResourceLocation skin = HDSkinManager.INSTANCE.getTextures(profile).get(Type.SKIN);
|
||||||
if (skin.isPresent())
|
if (skin != null) {
|
||||||
// rebind
|
rl = skin;
|
||||||
bindTexture(skin.get());
|
}
|
||||||
else
|
}
|
||||||
bindTexture(rl);
|
|
||||||
} else
|
|
||||||
bindTexture(rl);
|
bindTexture(rl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,7 @@ import com.google.gson.Gson;
|
||||||
import com.google.gson.JsonParseException;
|
import com.google.gson.JsonParseException;
|
||||||
import com.minelittlepony.pony.data.Pony;
|
import com.minelittlepony.pony.data.Pony;
|
||||||
import com.minelittlepony.pony.data.PonyLevel;
|
import com.minelittlepony.pony.data.PonyLevel;
|
||||||
import com.voxelmodpack.hdskins.HDSkinManager;
|
|
||||||
import com.voxelmodpack.hdskins.ISkinCacheClearListener;
|
import com.voxelmodpack.hdskins.ISkinCacheClearListener;
|
||||||
|
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.entity.AbstractClientPlayer;
|
import net.minecraft.client.entity.AbstractClientPlayer;
|
||||||
import net.minecraft.client.network.NetworkPlayerInfo;
|
import net.minecraft.client.network.NetworkPlayerInfo;
|
||||||
|
@ -83,8 +81,6 @@ public class PonyManager implements IResourceManagerReloadListener, ISkinCacheCl
|
||||||
}
|
}
|
||||||
|
|
||||||
public Pony getPony(NetworkPlayerInfo playerInfo) {
|
public Pony getPony(NetworkPlayerInfo playerInfo) {
|
||||||
// force load HDSkins if they're not available
|
|
||||||
HDSkinManager.INSTANCE.getProfileData(playerInfo.getGameProfile());
|
|
||||||
|
|
||||||
ResourceLocation skin = playerInfo.getLocationSkin();
|
ResourceLocation skin = playerInfo.getLocationSkin();
|
||||||
UUID uuid = playerInfo.getGameProfile().getId();
|
UUID uuid = playerInfo.getGameProfile().getId();
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
package com.minelittlepony.ducks;
|
|
||||||
|
|
||||||
import net.minecraft.client.network.NetworkPlayerInfo;
|
|
||||||
|
|
||||||
public interface IPlayerInfo {
|
|
||||||
/**
|
|
||||||
* Returns true if the vanilla skin (the one returned by NetworkPlayerInfo.getSkinLocation) uses the ALEX model type.
|
|
||||||
*/
|
|
||||||
boolean usesSlimArms();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Quick cast back to the original type.
|
|
||||||
*/
|
|
||||||
default NetworkPlayerInfo unwrap() {
|
|
||||||
return (NetworkPlayerInfo)this;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,41 +1,42 @@
|
||||||
package com.minelittlepony.mixin;
|
package com.minelittlepony.mixin;
|
||||||
|
|
||||||
|
import com.minelittlepony.MineLittlePony;
|
||||||
|
import com.minelittlepony.PonyManager;
|
||||||
|
import com.mojang.authlib.GameProfile;
|
||||||
|
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
|
||||||
|
import com.voxelmodpack.hdskins.INetworkPlayerInfo;
|
||||||
|
import net.minecraft.client.network.NetworkPlayerInfo;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
import com.minelittlepony.MineLittlePony;
|
@Mixin(value = NetworkPlayerInfo.class, priority = 999)
|
||||||
import com.minelittlepony.PonyManager;
|
public abstract class MixinNetworkPlayerInfo implements INetworkPlayerInfo {
|
||||||
import com.minelittlepony.ducks.IPlayerInfo;
|
|
||||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
|
|
||||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
|
|
||||||
import com.voxelmodpack.hdskins.HDSkinManager;
|
|
||||||
|
|
||||||
import net.minecraft.client.network.NetworkPlayerInfo;
|
@Shadow private String skinType;
|
||||||
|
|
||||||
@Mixin(NetworkPlayerInfo.class)
|
@Shadow @Final private GameProfile gameProfile;
|
||||||
public abstract class MixinNetworkPlayerInfo implements IPlayerInfo {
|
|
||||||
|
|
||||||
@Shadow
|
|
||||||
private String skinType;
|
|
||||||
|
|
||||||
@Inject(method = "getSkinType()Ljava/lang/String;", at = @At("RETURN"), cancellable = true)
|
@Inject(method = "getSkinType()Ljava/lang/String;", at = @At("RETURN"), cancellable = true)
|
||||||
private void getSkinType(CallbackInfoReturnable<String> info) {
|
private void getSkinType(CallbackInfoReturnable<String> info) {
|
||||||
info.setReturnValue(MineLittlePony.getInstance().getManager().getPony(unwrap()).getRace(false).getModel().getId(usesSlimArms()));
|
info.setReturnValue(MineLittlePony.getInstance().getManager()
|
||||||
|
.getPony((NetworkPlayerInfo) (Object) this)
|
||||||
|
.getRace(false)
|
||||||
|
.getModel()
|
||||||
|
.getId(usesSlimArms()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private boolean usesSlimArms() {
|
||||||
public boolean usesSlimArms() {
|
|
||||||
if (skinType == null) {
|
if (skinType == null) {
|
||||||
MinecraftProfileTexture skin = HDSkinManager.INSTANCE.getProfileData(unwrap().getGameProfile()).get(Type.SKIN);
|
|
||||||
|
|
||||||
if (skin != null) {
|
return getProfileTexture(Type.SKIN)
|
||||||
return "slim".equals(skin.getMetadata("model"));
|
.map(profile -> profile.getMetadata("model"))
|
||||||
}
|
.filter("slim"::equals)
|
||||||
|
.isPresent() || PonyManager.isSlimSkin(this.gameProfile.getId());
|
||||||
|
|
||||||
return PonyManager.isSlimSkin(unwrap().getGameProfile().getId());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return "slim".equals(skinType);
|
return "slim".equals(skinType);
|
||||||
|
|
|
@ -34,7 +34,6 @@ import net.minecraft.util.EnumHandSide;
|
||||||
import net.minecraft.util.ResourceLocation;
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
public class RenderPonyPlayer extends RenderPlayer implements IRenderPony<AbstractClientPlayer> {
|
public class RenderPonyPlayer extends RenderPlayer implements IRenderPony<AbstractClientPlayer> {
|
||||||
|
|
||||||
|
@ -58,9 +57,9 @@ public class RenderPonyPlayer extends RenderPlayer implements IRenderPony<Abstra
|
||||||
if (profile != null) {
|
if (profile != null) {
|
||||||
deadMau5.setVisible("deadmau5".equals(profile.getName()));
|
deadMau5.setVisible("deadmau5".equals(profile.getName()));
|
||||||
|
|
||||||
Optional<ResourceLocation> skin = HDSkinManager.INSTANCE.getSkinLocation(profile, Type.SKIN, true);
|
ResourceLocation skin = HDSkinManager.INSTANCE.getTextures(profile).get(Type.SKIN);
|
||||||
if (skin.isPresent()) {
|
if (skin != null) {
|
||||||
return skin.get();
|
return skin;
|
||||||
}
|
}
|
||||||
|
|
||||||
Minecraft minecraft = Minecraft.getMinecraft();
|
Minecraft minecraft = Minecraft.getMinecraft();
|
||||||
|
|
Loading…
Reference in a new issue