2016-12-25 17:05:30 +08:00
|
|
|
package customskinloader.fake;
|
|
|
|
|
|
|
|
|
|
import java.awt.image.BufferedImage;
|
|
|
|
|
import java.io.File;
|
2022-01-24 13:58:06 +08:00
|
|
|
import java.util.Iterator;
|
2016-12-25 17:05:30 +08:00
|
|
|
import java.util.Map;
|
2022-12-07 19:38:24 +08:00
|
|
|
import java.util.Optional;
|
2022-01-09 21:58:59 +08:00
|
|
|
import java.util.concurrent.ConcurrentHashMap;
|
2016-12-25 17:05:30 +08:00
|
|
|
|
2022-12-07 19:38:24 +08:00
|
|
|
import com.google.common.collect.ImmutableList;
|
2016-12-25 17:05:30 +08:00
|
|
|
import com.google.common.collect.Maps;
|
2022-12-07 19:38:24 +08:00
|
|
|
import com.google.common.collect.Multimap;
|
2016-12-25 17:05:30 +08:00
|
|
|
import com.mojang.authlib.GameProfile;
|
|
|
|
|
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
|
|
|
|
|
import com.mojang.authlib.minecraft.MinecraftSessionService;
|
|
|
|
|
import customskinloader.CustomSkinLoader;
|
|
|
|
|
import customskinloader.utils.HttpTextureUtil;
|
2022-12-07 19:38:24 +08:00
|
|
|
import customskinloader.utils.MinecraftUtil;
|
2016-12-25 17:05:30 +08:00
|
|
|
import net.minecraft.client.renderer.IImageBuffer;
|
|
|
|
|
import net.minecraft.client.renderer.texture.TextureManager;
|
2021-09-24 11:19:06 +08:00
|
|
|
import net.minecraft.client.resources.SkinManager;
|
2022-12-07 19:38:24 +08:00
|
|
|
import net.minecraft.client.resources.SkinManager.SkinAvailableCallback;
|
2016-12-25 17:05:30 +08:00
|
|
|
import net.minecraft.util.ResourceLocation;
|
|
|
|
|
|
2019-04-26 13:56:22 +08:00
|
|
|
public class FakeSkinManager {
|
2018-02-12 12:20:28 +08:00
|
|
|
private final TextureManager textureManager;
|
2016-12-25 17:05:30 +08:00
|
|
|
|
2022-01-09 21:58:59 +08:00
|
|
|
private final Map<ResourceLocation, MinecraftProfileTexture> modelCache = new ConcurrentHashMap<>();
|
2020-05-21 02:37:51 +08:00
|
|
|
|
2018-02-12 12:20:28 +08:00
|
|
|
public FakeSkinManager(TextureManager textureManagerInstance, File skinCacheDirectory, MinecraftSessionService sessionService) {
|
2019-04-26 13:56:22 +08:00
|
|
|
this.textureManager = textureManagerInstance;
|
|
|
|
|
HttpTextureUtil.defaultCacheDir = skinCacheDirectory;
|
2018-02-12 12:20:28 +08:00
|
|
|
}
|
2019-04-26 13:56:22 +08:00
|
|
|
|
2022-12-07 19:38:24 +08:00
|
|
|
/**
|
|
|
|
|
* Invoked from {@link SkinManager#loadSkin(MinecraftProfileTexture, MinecraftProfileTexture.Type, SkinAvailableCallback)}
|
|
|
|
|
*/
|
|
|
|
|
public static ResourceLocation setResourceLocation(ResourceLocation resourceLocation, MinecraftProfileTexture profileTexture) {
|
|
|
|
|
if (profileTexture instanceof FakeMinecraftProfileTexture) {
|
|
|
|
|
((FakeMinecraftProfileTexture) profileTexture).setResourceLocation(resourceLocation);
|
|
|
|
|
}
|
|
|
|
|
return resourceLocation;
|
2018-02-12 12:20:28 +08:00
|
|
|
}
|
2019-04-26 13:56:22 +08:00
|
|
|
|
2022-12-07 19:38:24 +08:00
|
|
|
/**
|
|
|
|
|
* Invoked from {@link SkinManager#loadSkin(MinecraftProfileTexture, MinecraftProfileTexture.Type, SkinAvailableCallback)}
|
|
|
|
|
* <p>
|
|
|
|
|
* {@code skinAvailableCallback.skinAvailable(textureType, resourcelocation, profileTexture);} -> {@code skinAvailableCallback.skinAvailable(textureType, resourcelocation, this.fakeManager.getModelCache(profileTexture, resourcelocation));}
|
|
|
|
|
* <p>
|
|
|
|
|
*/
|
|
|
|
|
public static MinecraftProfileTexture getModelCache(MinecraftProfileTexture profileTexture, FakeSkinManager fakeManager, ResourceLocation location) {
|
|
|
|
|
return fakeManager.modelCache.getOrDefault(location, profileTexture);
|
2020-08-16 19:50:19 +08:00
|
|
|
}
|
2019-04-26 13:56:22 +08:00
|
|
|
|
2022-12-07 19:38:24 +08:00
|
|
|
/**
|
|
|
|
|
* Invoked from {@link SkinManager#loadSkin(MinecraftProfileTexture, MinecraftProfileTexture.Type, SkinAvailableCallback)}
|
|
|
|
|
*/
|
|
|
|
|
public static Object[] createThreadDownloadImageData(ImmutableList<Object> list, FakeSkinManager fakeManager, MinecraftProfileTexture profileTexture, MinecraftProfileTexture.Type textureType, SkinManager.SkinAvailableCallback skinAvailableCallback) {
|
|
|
|
|
Object[] params = list.toArray();
|
|
|
|
|
if (profileTexture instanceof FakeMinecraftProfileTexture && params.length > 1) {
|
|
|
|
|
FakeMinecraftProfileTexture fakeProfileTexture = (FakeMinecraftProfileTexture) profileTexture;
|
|
|
|
|
ResourceLocation resourcelocation = fakeProfileTexture.getResourceLocation();
|
|
|
|
|
if (fakeProfileTexture.getResourceLocation() != null) {
|
2023-03-18 11:07:34 +08:00
|
|
|
params[0] = fakeProfileTexture.getCacheFile();
|
2022-12-07 19:38:24 +08:00
|
|
|
if (params[params.length - 2] instanceof Boolean) {
|
|
|
|
|
params[params.length - 2] = true;
|
|
|
|
|
}
|
2023-03-18 11:07:34 +08:00
|
|
|
params[params.length - 1] = fakeManager.new BaseBuffer(skinAvailableCallback, textureType, resourcelocation, fakeProfileTexture);
|
2022-12-07 19:38:24 +08:00
|
|
|
}
|
2018-02-12 12:20:28 +08:00
|
|
|
}
|
2022-12-07 19:38:24 +08:00
|
|
|
return params;
|
2018-02-12 12:20:28 +08:00
|
|
|
}
|
2019-04-26 13:56:22 +08:00
|
|
|
|
2022-12-07 19:38:24 +08:00
|
|
|
|
|
|
|
|
private final static String KEY = "CustomSkinLoaderInfo";
|
|
|
|
|
/**
|
|
|
|
|
* Invoked from {@link SkinManager#loadProfileTextures(GameProfile, SkinAvailableCallback, boolean)}
|
|
|
|
|
*/
|
|
|
|
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
|
|
|
|
public static void loadProfileTextures(Runnable runnable, GameProfile profile) {
|
2022-07-28 09:24:44 +08:00
|
|
|
CustomSkinLoader.loadProfileTextures(() -> CustomSkinLoader.loadProfileLazily(profile, m -> {
|
2022-12-07 19:38:24 +08:00
|
|
|
// This is a hack.
|
|
|
|
|
((Multimap) profile.getProperties()).put(KEY, m);
|
|
|
|
|
runnable.run();
|
|
|
|
|
}));
|
|
|
|
|
}
|
2016-12-25 17:05:30 +08:00
|
|
|
|
2022-12-07 19:38:24 +08:00
|
|
|
/**
|
|
|
|
|
* Invoked from {@link SkinManager#lambda$loadProfileTextures$1(GameProfile, boolean, SkinAvailableCallback)}
|
|
|
|
|
*/
|
|
|
|
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
|
|
|
|
public static Map<MinecraftProfileTexture.Type, MinecraftProfileTexture> getUserProfile(MinecraftSessionService sessionService, GameProfile profile, boolean requireSecure) {
|
|
|
|
|
// This is a hack.
|
|
|
|
|
return (Map<MinecraftProfileTexture.Type, MinecraftProfileTexture>) ((Optional) profile.getProperties().removeAll(KEY).stream().findFirst()).orElse(Maps.newHashMap());
|
|
|
|
|
}
|
2020-08-16 19:50:19 +08:00
|
|
|
|
2022-12-07 19:38:24 +08:00
|
|
|
/**
|
|
|
|
|
* Invoked from {@link SkinManager#lambda$null$0(Map, SkinAvailableCallback)}
|
|
|
|
|
*/
|
|
|
|
|
public static void loadElytraTexture(SkinManager skinManager, Map<MinecraftProfileTexture.Type, MinecraftProfileTexture> map, SkinManager.SkinAvailableCallback skinAvailableCallback) {
|
|
|
|
|
for (int i = 2; i < MinecraftProfileTexture.Type.values().length; i++) {
|
|
|
|
|
MinecraftProfileTexture.Type type = MinecraftProfileTexture.Type.values()[i];
|
|
|
|
|
if (map.containsKey(type)) {
|
|
|
|
|
skinManager.loadSkin(map.get(type), type, skinAvailableCallback);
|
2018-02-12 12:20:28 +08:00
|
|
|
}
|
2022-12-07 19:38:24 +08:00
|
|
|
}
|
2018-02-12 12:20:28 +08:00
|
|
|
}
|
2019-04-26 13:56:22 +08:00
|
|
|
|
2021-09-24 11:19:06 +08:00
|
|
|
public Map<MinecraftProfileTexture.Type, MinecraftProfileTexture> loadSkinFromCache(GameProfile profile) {
|
2022-01-24 13:58:06 +08:00
|
|
|
Map<MinecraftProfileTexture.Type, MinecraftProfileTexture> map = CustomSkinLoader.loadProfileFromCache(profile);
|
|
|
|
|
for (Iterator<Map.Entry<MinecraftProfileTexture.Type, MinecraftProfileTexture>> it = map.entrySet().iterator(); it.hasNext(); ) {
|
|
|
|
|
Map.Entry<MinecraftProfileTexture.Type, MinecraftProfileTexture> entry = it.next();
|
|
|
|
|
MinecraftProfileTexture texture = entry.getValue();
|
|
|
|
|
if (shouldJudgeType(texture)) {
|
2022-12-07 19:38:24 +08:00
|
|
|
texture = this.modelCache.get(MinecraftUtil.getSkinManager().loadSkin(texture, entry.getKey()));
|
2022-01-24 13:58:06 +08:00
|
|
|
if (texture == null) { // remove texture if was not loaded before
|
|
|
|
|
it.remove();
|
|
|
|
|
} else {
|
|
|
|
|
map.put(entry.getKey(), texture);
|
|
|
|
|
}
|
2022-01-09 21:58:59 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return map;
|
2018-02-12 12:20:28 +08:00
|
|
|
}
|
2019-04-26 13:56:22 +08:00
|
|
|
|
2021-09-24 11:19:06 +08:00
|
|
|
private static void makeCallback(SkinManager.SkinAvailableCallback callback, MinecraftProfileTexture.Type type, ResourceLocation location, MinecraftProfileTexture texture) {
|
2019-04-26 13:56:22 +08:00
|
|
|
if (callback != null)
|
2018-02-12 12:20:28 +08:00
|
|
|
callback.skinAvailable(type, location, texture);
|
|
|
|
|
}
|
2019-04-26 13:56:22 +08:00
|
|
|
|
2022-01-24 13:58:06 +08:00
|
|
|
private static boolean shouldJudgeType(MinecraftProfileTexture texture) {
|
|
|
|
|
return texture != null && "auto".equals(texture.getMetadata("model"));
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-26 13:56:22 +08:00
|
|
|
private class BaseBuffer implements IImageBuffer {
|
2018-02-12 12:20:28 +08:00
|
|
|
private IImageBuffer buffer;
|
2019-04-26 13:56:22 +08:00
|
|
|
|
2021-09-24 11:19:06 +08:00
|
|
|
private SkinManager.SkinAvailableCallback callback;
|
|
|
|
|
private MinecraftProfileTexture.Type type;
|
2018-02-12 12:20:28 +08:00
|
|
|
private ResourceLocation location;
|
2023-03-18 11:07:34 +08:00
|
|
|
private FakeMinecraftProfileTexture texture;
|
2019-04-26 13:56:22 +08:00
|
|
|
|
2023-03-18 11:07:34 +08:00
|
|
|
public BaseBuffer(SkinManager.SkinAvailableCallback callback, MinecraftProfileTexture.Type type, ResourceLocation location, FakeMinecraftProfileTexture texture) {
|
2021-05-07 17:15:45 +08:00
|
|
|
switch (type) {
|
|
|
|
|
case SKIN: this.buffer = new FakeSkinBuffer(); break;
|
|
|
|
|
case CAPE: this.buffer = new FakeCapeBuffer(location); break;
|
|
|
|
|
}
|
2019-04-26 13:56:22 +08:00
|
|
|
|
|
|
|
|
this.callback = callback;
|
|
|
|
|
this.type = type;
|
|
|
|
|
this.location = location;
|
|
|
|
|
this.texture = texture;
|
2018-02-12 12:20:28 +08:00
|
|
|
}
|
2018-07-25 21:06:16 +08:00
|
|
|
|
2019-04-26 13:56:22 +08:00
|
|
|
public net.minecraft.client.renderer.texture.NativeImage func_195786_a(net.minecraft.client.renderer.texture.NativeImage image) {
|
2018-07-25 21:06:16 +08:00
|
|
|
return buffer instanceof FakeSkinBuffer ? ((FakeSkinBuffer) buffer).func_195786_a(image) : image;
|
|
|
|
|
}
|
2019-04-26 13:56:22 +08:00
|
|
|
|
|
|
|
|
public BufferedImage parseUserSkin(BufferedImage image) {
|
2021-05-07 17:15:45 +08:00
|
|
|
return buffer instanceof FakeSkinBuffer ? ((FakeSkinBuffer) buffer).parseUserSkin(image) : image;
|
2018-02-12 12:20:28 +08:00
|
|
|
}
|
2019-04-26 13:56:22 +08:00
|
|
|
|
|
|
|
|
public void skinAvailable() {
|
|
|
|
|
if (buffer != null) {
|
2018-02-12 12:20:28 +08:00
|
|
|
buffer.skinAvailable();
|
2022-01-24 13:58:06 +08:00
|
|
|
if (shouldJudgeType(texture) && buffer instanceof FakeSkinBuffer) {
|
2018-06-24 22:59:46 +08:00
|
|
|
//Auto judge skin type
|
2018-06-25 00:34:32 +08:00
|
|
|
Map<String, String> metadata = Maps.newHashMap();
|
2020-05-21 02:37:51 +08:00
|
|
|
String type = ((FakeSkinBuffer) buffer).judgeType();
|
|
|
|
|
metadata.put("model", type);
|
2023-03-18 11:07:34 +08:00
|
|
|
texture = new FakeMinecraftProfileTexture(texture.getRawUrl(), metadata);
|
2020-05-21 02:37:51 +08:00
|
|
|
FakeSkinManager.this.modelCache.put(location, texture);
|
2018-06-24 22:59:46 +08:00
|
|
|
}
|
2018-05-18 21:06:28 +08:00
|
|
|
}
|
2016-12-25 17:05:30 +08:00
|
|
|
|
2019-04-26 13:56:22 +08:00
|
|
|
FakeSkinManager.makeCallback(callback, type, location, texture);
|
2018-02-12 12:20:28 +08:00
|
|
|
}
|
|
|
|
|
}
|
2016-12-25 17:05:30 +08:00
|
|
|
}
|