package me.km.entities; import java.net.HttpURLConnection; import java.net.URL; import java.util.HashMap; import java.util.HashSet; import java.util.function.Consumer; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.texture.DynamicTexture; import net.minecraft.client.renderer.texture.NativeImage; import net.minecraft.client.renderer.texture.TextureManager; import net.minecraft.util.ResourceLocation; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import org.apache.logging.log4j.LogManager; @OnlyIn(Dist.CLIENT) public class HumanSkinLoader { public final static HumanSkinLoader INSTANCE = new HumanSkinLoader(false); public final static HumanSkinLoader GREY_INSTANCE = new HumanSkinLoader(true); private static final ResourceLocation TEXTURE_STEVE = new ResourceLocation("textures/entity/steve.png"); private final HashMap skins = new HashMap<>(); private final HashSet loading = new HashSet<>(); private final TextureManager manager = Minecraft.getInstance().getRenderManager().textureManager; private final boolean grey; private HumanSkinLoader(boolean grey) { this.grey = grey; } public ResourceLocation getTexture(String name) { ResourceLocation loc = skins.get(name); if(loc != null) { return loc; } if(loading.add(name)) { downloadSkin(name, image -> { ResourceLocation rloc = manager.getDynamicTextureLocation( "skin_grey_" + name.toLowerCase(), new DynamicTexture(image)); skins.put(name, rloc); loading.remove(name); }, grey); } return TEXTURE_STEVE; } private void downloadSkin(String name, Consumer delayed, boolean grey) { new Thread(() -> { HttpURLConnection httpurlconnection = null; try { URL url = new URL("http://skins.hammerle.me/skins/" + name + ".png"); httpurlconnection = (HttpURLConnection) url.openConnection(Minecraft.getInstance().getProxy()); httpurlconnection.setDoInput(true); httpurlconnection.setDoOutput(false); httpurlconnection.connect(); int code = httpurlconnection.getResponseCode(); if(code != 200) { // Failed own server, trying crafatar httpurlconnection.disconnect(); httpurlconnection = (HttpURLConnection) (new URL( "https://crafatar.com/skins/" + name + ".png")) .openConnection(Minecraft.getInstance().getProxy()); httpurlconnection.setDoInput(true); httpurlconnection.setDoOutput(false); httpurlconnection.connect(); code = httpurlconnection.getResponseCode(); if(code != 200) { LogManager.getLogger().warn("Server response code did return " + code + ", skin servers might be down."); return; } } NativeImage image = convert(NativeImage.read(httpurlconnection.getInputStream())); if(grey) { for(int x = 0; x < image.getWidth(); x++) { for(int y = 0; y < image.getHeight(); y++) { int c = image.getPixelRGBA(x, y); int r = (c >> 0) & 0xFF; int g = (c >> 8) & 0xFF; int b = (c >> 16) & 0xFF; int a = (c >> 24) & 0xFF; int mix = (int) (r * 0.3 + g * 0.6 + b * 0.1); c = (mix << 0) | (mix << 8) | (mix << 16) | (a << 24); image.setPixelRGBA(x, y, c); } } } Minecraft.getInstance().enqueue(() -> delayed.accept(image)); } catch(Exception ex) { LogManager.getLogger().warn( "Error occurred when downloading skin, however, skin servers seem to be up: " + ex.getMessage()); } finally { if(httpurlconnection != null) { httpurlconnection.disconnect(); } } }).start(); } @SuppressWarnings("resource") private NativeImage convert(NativeImage old) { boolean flag = old.getHeight() == 32; if(flag) { NativeImage nativeimage = new NativeImage(64, 64, true); nativeimage.copyImageData(old); old.close(); old = nativeimage; nativeimage.fillAreaRGBA(0, 32, 64, 32, 0); nativeimage.copyAreaRGBA(4, 16, 16, 32, 4, 4, true, false); nativeimage.copyAreaRGBA(8, 16, 16, 32, 4, 4, true, false); nativeimage.copyAreaRGBA(0, 20, 24, 32, 4, 12, true, false); nativeimage.copyAreaRGBA(4, 20, 16, 32, 4, 12, true, false); nativeimage.copyAreaRGBA(8, 20, 8, 32, 4, 12, true, false); nativeimage.copyAreaRGBA(12, 20, 16, 32, 4, 12, true, false); nativeimage.copyAreaRGBA(44, 16, -8, 32, 4, 4, true, false); nativeimage.copyAreaRGBA(48, 16, -8, 32, 4, 4, true, false); nativeimage.copyAreaRGBA(40, 20, 0, 32, 4, 12, true, false); nativeimage.copyAreaRGBA(44, 20, -8, 32, 4, 12, true, false); nativeimage.copyAreaRGBA(48, 20, -16, 32, 4, 12, true, false); nativeimage.copyAreaRGBA(52, 20, -8, 32, 4, 12, true, false); } setAreaOpaque(old, 0, 0, 32, 16); if(flag) { setAreaTransparent(old, 32, 0, 64, 32); } setAreaOpaque(old, 0, 16, 64, 32); setAreaOpaque(old, 16, 48, 48, 64); return old; } private static void setAreaTransparent(NativeImage image, int x, int y, int width, int height) { for(int i = x; i < width; ++i) { for(int j = y; j < height; ++j) { int k = image.getPixelRGBA(i, j); if((k >> 24 & 255) < 128) { return; } } } for(int l = x; l < width; ++l) { for(int i1 = y; i1 < height; ++i1) { image.setPixelRGBA(l, i1, image.getPixelRGBA(l, i1) & 16777215); } } } private static void setAreaOpaque(NativeImage image, int x, int y, int width, int height) { for(int i = x; i < width; ++i) { for(int j = y; j < height; ++j) { image.setPixelRGBA(i, j, image.getPixelRGBA(i, j) | -16777216); } } } }