mirror of
https://github.com/MineLittlePony/MineLittlePony.git
synced 2024-11-26 14:27:59 +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.voxelmodpack.hdskins.gui.GuiSkins;
|
||||
import com.voxelmodpack.hdskins.resource.SkinResourceManager;
|
||||
import com.voxelmodpack.hdskins.skins.AsyncCacheLoader;
|
||||
import com.voxelmodpack.hdskins.skins.BethlehemSkinServer;
|
||||
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 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.IResourceManager;
|
||||
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 org.apache.commons.io.FileUtils;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
|
@ -46,15 +47,17 @@ import java.lang.reflect.Modifier;
|
|||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
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 CloseableHttpClient httpClient = HttpClients.createSystem();
|
||||
|
||||
private static final ResourceLocation LOADING = new ResourceLocation("LOADING");
|
||||
|
||||
public static final HDSkinManager INSTANCE = new HDSkinManager();
|
||||
|
||||
private boolean enabled = true;
|
||||
|
||||
private List<ISkinCacheClearListener> clearListeners = Lists.newArrayList();
|
||||
|
||||
private BiMap<String, Class<? extends SkinServer>> skinServerTypes = HashBiMap.create(2);
|
||||
private List<SkinServer> skinServers = Lists.newArrayList();
|
||||
|
||||
private Map<UUID, Map<Type, ResourceLocation>> skinCache = Maps.newHashMap();
|
||||
|
||||
private LoadingCache<GameProfile, Map<Type, MinecraftProfileTexture>> skins = CacheBuilder.newBuilder()
|
||||
.initialCapacity(20)
|
||||
.maximumSize(100)
|
||||
.expireAfterWrite(4, TimeUnit.HOURS)
|
||||
.build(AsyncCacheLoader.create(CacheLoader.from(this::loadProfileData), Collections.emptyMap(), skinDownloadExecutor));
|
||||
private LoadingCache<GameProfile, CompletableFuture<Map<Type, MinecraftProfileTexture>>> skins = CacheBuilder.newBuilder()
|
||||
.expireAfterAccess(15, TimeUnit.SECONDS)
|
||||
.build(CacheLoader.from(this::loadProfileData));
|
||||
|
||||
private List<ISkinModifier> skinModifiers = Lists.newArrayList();
|
||||
|
||||
|
@ -107,19 +102,30 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
|
|||
return skinsGuiFunc.apply(ImmutableList.copyOf(this.skinServers));
|
||||
}
|
||||
|
||||
public Optional<ResourceLocation> getSkinLocation(GameProfile profile1, final Type type, boolean loadIfAbsent) {
|
||||
if (!enabled) {
|
||||
return Optional.empty();
|
||||
}
|
||||
private CompletableFuture<Map<Type, MinecraftProfileTexture>> loadProfileData(GameProfile profile) {
|
||||
|
||||
ResourceLocation skin = this.resources.getPlayerTexture(profile1, type);
|
||||
if (skin != null) {
|
||||
return Optional.of(skin);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
return textureMap;
|
||||
}, skinDownloadExecutor);
|
||||
}
|
||||
|
||||
public CompletableFuture<Map<Type, MinecraftProfileTexture>> loadProfileTextures(GameProfile profile) {
|
||||
// try to recreate a broken gameprofile
|
||||
// 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) {
|
||||
String json = new String(Base64.getDecoder().decode(textures.getValue()), StandardCharsets.UTF_8);
|
||||
MinecraftTexturesPayload texturePayload = SkinServer.gson.fromJson(json, MinecraftTexturesPayload.class);
|
||||
|
@ -129,86 +135,55 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
|
|||
UUID uuid = texturePayload.getProfileId();
|
||||
// uuid is required
|
||||
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.
|
||||
if (!texturePayload.getTextures().isEmpty() && texturePayload.getProfileId() == null) {
|
||||
return Optional.empty();
|
||||
return CompletableFuture.completedFuture(Collections.emptyMap());
|
||||
}
|
||||
}
|
||||
}
|
||||
final GameProfile profile = profile1;
|
||||
|
||||
// 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);
|
||||
return skins.getUnchecked(profile);
|
||||
}
|
||||
|
||||
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/";
|
||||
|
||||
final MinecraftProfileTexture texture = getProfileData(profile).get(type);
|
||||
final ResourceLocation resource = new ResourceLocation("hdskins", skinDir + texture.getHash());
|
||||
ITextureObject texObj = Minecraft.getMinecraft().getTextureManager().getTexture(resource);
|
||||
|
||||
ISkinAvailableCallback buffs = new ImageBufferDownloadHD(type, () -> {
|
||||
callback.skinAvailable(type, resource, texture);
|
||||
});
|
||||
|
||||
// schedule texture loading on the main thread.
|
||||
TextureLoader.loadTexture(resource, new ThreadDownloadImageETag(
|
||||
new File(LiteLoader.getAssetsDirectory(), "hd/" + skinDir + texture.getHash().substring(0, 2) + "/" + texture.getHash()),
|
||||
texture.getUrl(),
|
||||
DefaultPlayerSkin.getDefaultSkinLegacy(),
|
||||
buffs));
|
||||
}
|
||||
|
||||
private Map<Type, MinecraftProfileTexture> loadProfileData(GameProfile profile) {
|
||||
Map<Type, MinecraftProfileTexture> textures = Maps.newEnumMap(Type.class);
|
||||
for (SkinServer server : skinServers) {
|
||||
try {
|
||||
server.loadProfileData(profile).getTextures().forEach(textures::putIfAbsent);
|
||||
if (textures.size() == Type.values().length) {
|
||||
break;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.trace(e);
|
||||
//noinspection ConstantConditions
|
||||
if (texObj != null) {
|
||||
if (callback != null) {
|
||||
callback.skinAvailable(type, resource, texture);
|
||||
}
|
||||
|
||||
} else {
|
||||
// schedule texture loading on the main thread.
|
||||
TextureLoader.loadTexture(resource, new ThreadDownloadImageETag(
|
||||
new File(LiteLoader.getAssetsDirectory(), "hd/" + skinDir + texture.getHash().substring(0, 2) + "/" + texture.getHash()),
|
||||
texture.getUrl(),
|
||||
DefaultPlayerSkin.getDefaultSkinLegacy(),
|
||||
new ImageBufferDownloadHD(type, () -> {
|
||||
if (callback != null) {
|
||||
callback.skinAvailable(type, resource, texture);
|
||||
}
|
||||
})));
|
||||
}
|
||||
return textures;
|
||||
return resource;
|
||||
}
|
||||
|
||||
public Map<Type, MinecraftProfileTexture> getProfileData(GameProfile profile) {
|
||||
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);
|
||||
public Map<Type, ResourceLocation> getTextures(GameProfile profile) {
|
||||
|
||||
Map<Type, ResourceLocation> map = new HashMap<>();
|
||||
for (Map.Entry<Type, MinecraftProfileTexture> e : loadProfileTextures(profile).getNow(Collections.emptyMap()).entrySet()) {
|
||||
map.put(e.getKey(), loadTexture(e.getKey(), e.getValue(), null));
|
||||
}
|
||||
return textures;
|
||||
return map;
|
||||
|
||||
}
|
||||
|
||||
public void addSkinServerType(Class<? extends SkinServer> type) {
|
||||
private void addSkinServerType(Class<? extends SkinServer> type) {
|
||||
Preconditions.checkArgument(!type.isInterface(), "type cannot be an interface");
|
||||
Preconditions.checkArgument(!Modifier.isAbstract(type.getModifiers()), "type cannot be abstract");
|
||||
ServerType st = type.getAnnotation(ServerType.class);
|
||||
|
@ -222,14 +197,10 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
|
|||
return this.skinServerTypes.get(type);
|
||||
}
|
||||
|
||||
public void addSkinServer(SkinServer skinServer) {
|
||||
void addSkinServer(SkinServer skinServer) {
|
||||
this.skinServers.add(skinServer);
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public void addClearListener(ISkinCacheClearListener listener) {
|
||||
clearListeners.add(listener);
|
||||
}
|
||||
|
@ -237,18 +208,14 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
|
|||
public void clearSkinCache() {
|
||||
LiteLoaderLogger.info("Clearing local player skin cache");
|
||||
|
||||
try {
|
||||
FileUtils.deleteDirectory(new File(LiteLoader.getAssetsDirectory(), "skins"));
|
||||
FileUtils.deleteDirectory(new File(LiteLoader.getAssetsDirectory(), "hd"));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
FileUtils.deleteQuietly(new File(LiteLoader.getAssetsDirectory(), "hd"));
|
||||
|
||||
NetHandlerPlayClient connection = Minecraft.getMinecraft().getConnection();
|
||||
|
||||
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();
|
||||
|
||||
clearListeners = clearListeners.stream()
|
||||
|
@ -256,6 +223,10 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
|
|||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private void clearNetworkSkin(NetworkPlayerInfo player) {
|
||||
((INetworkPlayerInfo) player).deleteTextures();
|
||||
}
|
||||
|
||||
private boolean onSkinCacheCleared(ISkinCacheClearListener callback) {
|
||||
try {
|
||||
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.Type;
|
||||
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.renderer.texture.TextureManager;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
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 java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
@Mixin(NetworkPlayerInfo.class)
|
||||
public abstract class MixinPlayerInfo {
|
||||
public abstract class MixinPlayerInfo implements INetworkPlayerInfo {
|
||||
|
||||
@Shadow
|
||||
public abstract GameProfile getGameProfile();
|
||||
|
||||
@Inject(
|
||||
method = "getLocationSkin",
|
||||
cancellable = true,
|
||||
at = @At("RETURN"))
|
||||
private void getLocationSkin(CallbackInfoReturnable<ResourceLocation> ci) {
|
||||
getTextureLocation(ci, Type.SKIN);
|
||||
private Map<Type, ResourceLocation> customTextures = new HashMap<>();
|
||||
private Map<Type, MinecraftProfileTexture> customProfiles = new HashMap<>();
|
||||
|
||||
@Shadow @Final private GameProfile gameProfile;
|
||||
|
||||
@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(
|
||||
method = "getLocationCape",
|
||||
cancellable = true,
|
||||
at = @At("RETURN"))
|
||||
private void getLocationCape(CallbackInfoReturnable<ResourceLocation> ci) {
|
||||
getTextureLocation(ci, Type.CAPE);
|
||||
// with generics
|
||||
private ResourceLocation getSkin(Map<Type, ResourceLocation> playerTextures, Type type) {
|
||||
return getResourceLocation(type).orElseGet(() -> playerTextures.get(type));
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "getLocationElytra",
|
||||
cancellable = true,
|
||||
at = @At("RETURN"))
|
||||
private void getLocationElytra(CallbackInfoReturnable<ResourceLocation> ci) {
|
||||
getTextureLocation(ci, Type.ELYTRA);
|
||||
@Inject(method = "getSkinType", at = @At("RETURN"), cancellable = true)
|
||||
private void getTextureModel(CallbackInfoReturnable<String> cir) {
|
||||
getProfileTexture(Type.SKIN).ifPresent(profile -> {
|
||||
String model = profile.getMetadata("model");
|
||||
cir.setReturnValue(model != null ? model : "default");
|
||||
});
|
||||
}
|
||||
|
||||
private void getTextureLocation(CallbackInfoReturnable<ResourceLocation> ci, Type type) {
|
||||
Optional<ResourceLocation> texture = HDSkinManager.INSTANCE.getSkinLocation(getGameProfile(), type, true);
|
||||
texture.ifPresent(ci::setReturnValue);
|
||||
@Inject(method = "loadPlayerTextures",
|
||||
at = @At(value = "INVOKE",
|
||||
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(
|
||||
method = "getSkinType",
|
||||
cancellable = true,
|
||||
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);
|
||||
@Override
|
||||
public Optional<ResourceLocation> getResourceLocation(Type type) {
|
||||
return Optional.ofNullable(this.customTextures.get(type));
|
||||
}
|
||||
|
||||
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 javax.annotation.Nullable;
|
||||
import java.util.Optional;
|
||||
|
||||
@Mixin(TileEntitySkullRenderer.class)
|
||||
public abstract class MixinSkullRenderer extends TileEntitySpecialRenderer<TileEntitySkull> {
|
||||
|
@ -24,16 +23,15 @@ public abstract class MixinSkullRenderer extends TileEntitySpecialRenderer<TileE
|
|||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/client/renderer/tileentity/TileEntitySkullRenderer;bindTexture(Lnet/minecraft/util/ResourceLocation;)V",
|
||||
ordinal = 4))
|
||||
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) {
|
||||
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) {
|
||||
if (profile != null) {
|
||||
Optional<ResourceLocation> skin = HDSkinManager.INSTANCE.getSkinLocation(profile, Type.SKIN, true);
|
||||
if (skin.isPresent())
|
||||
// rebind
|
||||
bindTexture(skin.get());
|
||||
else
|
||||
bindTexture(rl);
|
||||
} else
|
||||
bindTexture(rl);
|
||||
ResourceLocation skin = HDSkinManager.INSTANCE.getTextures(profile).get(Type.SKIN);
|
||||
if (skin != null) {
|
||||
rl = skin;
|
||||
}
|
||||
}
|
||||
bindTexture(rl);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,9 +6,7 @@ import com.google.gson.Gson;
|
|||
import com.google.gson.JsonParseException;
|
||||
import com.minelittlepony.pony.data.Pony;
|
||||
import com.minelittlepony.pony.data.PonyLevel;
|
||||
import com.voxelmodpack.hdskins.HDSkinManager;
|
||||
import com.voxelmodpack.hdskins.ISkinCacheClearListener;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.entity.AbstractClientPlayer;
|
||||
import net.minecraft.client.network.NetworkPlayerInfo;
|
||||
|
@ -83,8 +81,6 @@ public class PonyManager implements IResourceManagerReloadListener, ISkinCacheCl
|
|||
}
|
||||
|
||||
public Pony getPony(NetworkPlayerInfo playerInfo) {
|
||||
// force load HDSkins if they're not available
|
||||
HDSkinManager.INSTANCE.getProfileData(playerInfo.getGameProfile());
|
||||
|
||||
ResourceLocation skin = playerInfo.getLocationSkin();
|
||||
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;
|
||||
|
||||
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.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import com.minelittlepony.MineLittlePony;
|
||||
import com.minelittlepony.PonyManager;
|
||||
import com.minelittlepony.ducks.IPlayerInfo;
|
||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
|
||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
|
||||
import com.voxelmodpack.hdskins.HDSkinManager;
|
||||
@Mixin(value = NetworkPlayerInfo.class, priority = 999)
|
||||
public abstract class MixinNetworkPlayerInfo implements INetworkPlayerInfo {
|
||||
|
||||
import net.minecraft.client.network.NetworkPlayerInfo;
|
||||
@Shadow private String skinType;
|
||||
|
||||
@Mixin(NetworkPlayerInfo.class)
|
||||
public abstract class MixinNetworkPlayerInfo implements IPlayerInfo {
|
||||
|
||||
@Shadow
|
||||
private String skinType;
|
||||
@Shadow @Final private GameProfile gameProfile;
|
||||
|
||||
@Inject(method = "getSkinType()Ljava/lang/String;", at = @At("RETURN"), cancellable = true)
|
||||
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
|
||||
public boolean usesSlimArms() {
|
||||
private boolean usesSlimArms() {
|
||||
if (skinType == null) {
|
||||
MinecraftProfileTexture skin = HDSkinManager.INSTANCE.getProfileData(unwrap().getGameProfile()).get(Type.SKIN);
|
||||
|
||||
if (skin != null) {
|
||||
return "slim".equals(skin.getMetadata("model"));
|
||||
}
|
||||
return getProfileTexture(Type.SKIN)
|
||||
.map(profile -> profile.getMetadata("model"))
|
||||
.filter("slim"::equals)
|
||||
.isPresent() || PonyManager.isSlimSkin(this.gameProfile.getId());
|
||||
|
||||
return PonyManager.isSlimSkin(unwrap().getGameProfile().getId());
|
||||
}
|
||||
|
||||
return "slim".equals(skinType);
|
||||
|
|
|
@ -34,7 +34,6 @@ import net.minecraft.util.EnumHandSide;
|
|||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public class RenderPonyPlayer extends RenderPlayer implements IRenderPony<AbstractClientPlayer> {
|
||||
|
||||
|
@ -58,9 +57,9 @@ public class RenderPonyPlayer extends RenderPlayer implements IRenderPony<Abstra
|
|||
if (profile != null) {
|
||||
deadMau5.setVisible("deadmau5".equals(profile.getName()));
|
||||
|
||||
Optional<ResourceLocation> skin = HDSkinManager.INSTANCE.getSkinLocation(profile, Type.SKIN, true);
|
||||
if (skin.isPresent()) {
|
||||
return skin.get();
|
||||
ResourceLocation skin = HDSkinManager.INSTANCE.getTextures(profile).get(Type.SKIN);
|
||||
if (skin != null) {
|
||||
return skin;
|
||||
}
|
||||
|
||||
Minecraft minecraft = Minecraft.getMinecraft();
|
||||
|
|
Loading…
Reference in a new issue