GuiSkins no longer has a concept of a gateway server.

Servers are now selectable by clicking the "?" button.
This commit is contained in:
Matthew Messinger 2018-08-19 17:55:38 -04:00
parent 95107ddeed
commit 99eed8570d
10 changed files with 119 additions and 74 deletions

View file

@ -6,6 +6,7 @@ import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
@ -37,6 +38,7 @@ import org.apache.commons.io.FileUtils;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
@ -51,16 +53,18 @@ 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.Nonnull;
public final class HDSkinManager implements IResourceManagerReloadListener {
private static final Logger logger = LogManager.getLogger();
public static final ExecutorService skinUploadExecutor = Executors.newSingleThreadExecutor();
public static final ExecutorService skinDownloadExecutor = Executors.newFixedThreadPool(8);
public static final CloseableHttpClient httpClient = HttpClients.createSystem();
@ -89,7 +93,7 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
private SkinResourceManager resources = new SkinResourceManager();
// private ExecutorService executor = Executors.newCachedThreadPool();
private Class<? extends GuiSkins> skinsClass = null;
private Function<List<SkinServer>, GuiSkins> skinsGuiFunc = GuiSkins::new;
private HDSkinManager() {
@ -99,20 +103,13 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
addSkinServerType(BethlehemSkinServer.class);
}
public void setPrefferedSkinsGuiClass(Class<? extends GuiSkins> clazz) {
skinsClass = clazz;
public void setSkinsGui(Function<List<SkinServer>, GuiSkins> skinsGuiFunc) {
Preconditions.checkNotNull(skinsGuiFunc, "skinsGuiFunc");
this.skinsGuiFunc = skinsGuiFunc;
}
public GuiSkins createSkinsGui() {
if (skinsClass != null) {
try {
return skinsClass.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
return new GuiSkins();
return skinsGuiFunc.apply(ImmutableList.copyOf(this.skinServers));
}
public Optional<ResourceLocation> getSkinLocation(GameProfile profile1, final Type type, boolean loadIfAbsent) {
@ -219,7 +216,7 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
break;
}
} catch (IOException e) {
LogManager.getLogger().trace(e);
logger.trace(e);
}
}
@ -254,19 +251,10 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
this.skinServers.add(skinServer);
}
@Deprecated
public SkinServer getGatewayServer() {
return this.skinServers.get(0);
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public static CompletableFuture<PreviewTextureManager> getPreviewTextureManager(GameProfile profile) {
return INSTANCE.getGatewayServer().getPreviewTextures(profile).thenApply(PreviewTextureManager::new);
}
public void addClearListener(ISkinCacheClearListener listener) {
clearListeners.add(listener);
}
@ -296,8 +284,7 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
try {
return callback.onSkinCacheCleared();
} catch (Exception e) {
LiteLoaderLogger.warning("Exception ancountered calling skin listener '{}'. It will be removed.", callback.getClass().getName());
e.printStackTrace();
logger.warn("Exception encountered calling skin listener '{}'. It will be removed.", callback.getClass().getName(), e);
return false;
}
}

View file

@ -1,20 +1,18 @@
package com.voxelmodpack.hdskins;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.texture.DynamicTexture;
import net.minecraft.client.renderer.texture.TextureManager;
import net.minecraft.client.resources.SkinManager.SkinAvailableCallback;
import net.minecraft.util.ResourceLocation;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class LocalTexture {
private final TextureManager textureManager = Minecraft.getMinecraft().getTextureManager();
@ -33,7 +31,7 @@ public class LocalTexture {
this.blank = blank;
this.type = type;
String file = type.name().toLowerCase() + "s/preview_${profile.getName()}.png";
String file = String.format("%s/preview_%s.png", type.name().toLowerCase(), profile.getName());
remoteResource = new ResourceLocation(file);
textureManager.deleteTexture(remoteResource);
@ -113,6 +111,7 @@ public class LocalTexture {
}
public interface IBlankSkinSupplier {
ResourceLocation getBlankSkin(Type type);
}
}

View file

@ -1,14 +1,17 @@
package com.voxelmodpack.hdskins;
import com.google.common.collect.Maps;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload;
import com.voxelmodpack.hdskins.skins.SkinServer;
import net.minecraft.client.renderer.IImageBuffer;
import net.minecraft.client.resources.SkinManager;
import net.minecraft.util.ResourceLocation;
import java.awt.image.BufferedImage;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import javax.annotation.Nullable;
@ -20,7 +23,7 @@ public class PreviewTextureManager {
private final Map<MinecraftProfileTexture.Type, MinecraftProfileTexture> textures;
PreviewTextureManager(MinecraftTexturesPayload payload) {
private PreviewTextureManager(MinecraftTexturesPayload payload) {
this.textures = payload.getTextures();
}
@ -52,4 +55,8 @@ public class PreviewTextureManager {
return skinTexture;
}
public static CompletableFuture<PreviewTextureManager> load(SkinServer server, GameProfile profile) {
return server.getPreviewTextures(profile).thenApply(PreviewTextureManager::new);
}
}

View file

@ -4,7 +4,6 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
import com.voxelmodpack.hdskins.HDSkinManager;
import com.voxelmodpack.hdskins.LocalTexture;
import com.voxelmodpack.hdskins.LocalTexture.IBlankSkinSupplier;
import net.minecraft.client.Minecraft;
@ -35,12 +34,15 @@ public class EntityPlayerModel extends EntityLivingBase implements IBlankSkinSup
protected final LocalTexture skin;
protected final LocalTexture elytra;
public final GameProfile profile;
private final GameProfile profile;
private final GuiSkins skins;
protected boolean previewThinArms = false;
public EntityPlayerModel(GameProfile gameprofile) {
public EntityPlayerModel(GuiSkins skins, GameProfile gameprofile) {
super(new DummyWorld());
this.skins = skins;
profile = gameprofile;
skin = new LocalTexture(profile, Type.SKIN, this);
@ -48,10 +50,10 @@ public class EntityPlayerModel extends EntityLivingBase implements IBlankSkinSup
}
public void reloadRemoteSkin(SkinManager.SkinAvailableCallback listener) {
HDSkinManager.getPreviewTextureManager(profile).thenAccept(ptm -> {
this.skins.loadTextures(profile).thenAcceptAsync(ptm -> {
skin.setRemote(ptm, listener);
elytra.setRemote(ptm, listener);
});
}, Minecraft.getMinecraft()::addScheduledTask); // run on main thread
}
public void setLocalTexture(File skinTextureFile, Type type) {

View file

@ -1,12 +1,9 @@
package com.voxelmodpack.hdskins.gui;
import static com.mojang.authlib.minecraft.MinecraftProfileTexture.Type.ELYTRA;
import static com.mojang.authlib.minecraft.MinecraftProfileTexture.Type.SKIN;
import static net.minecraft.client.renderer.GlStateManager.*;
import com.google.common.base.Splitter;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.minelittlepony.gui.Button;
import com.minelittlepony.gui.GameGui;
import com.minelittlepony.gui.IconicButton;
@ -16,10 +13,11 @@ import com.mojang.authlib.minecraft.MinecraftProfileTexture;
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
import com.mumfrey.liteloader.util.log.LiteLoaderLogger;
import com.voxelmodpack.hdskins.HDSkinManager;
import com.voxelmodpack.hdskins.PreviewTextureManager;
import com.voxelmodpack.hdskins.skins.SkinServer;
import com.voxelmodpack.hdskins.skins.SkinUpload;
import com.voxelmodpack.hdskins.skins.SkinUploadResponse;
import com.voxelmodpack.hdskins.upload.awt.ThreadOpenFilePNG;
import net.minecraft.client.Minecraft;
import net.minecraft.client.audio.PositionedSoundRecord;
import net.minecraft.client.gui.Gui;
@ -34,7 +32,6 @@ import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumHand;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.MathHelper;
import org.apache.commons.io.FilenameUtils;
import org.apache.logging.log4j.LogManager;
import org.lwjgl.BufferUtils;
@ -46,17 +43,27 @@ import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.nio.DoubleBuffer;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.function.Predicate;
import javax.annotation.Nullable;
import javax.imageio.ImageIO;
import javax.swing.UIManager;
import static com.mojang.authlib.minecraft.MinecraftProfileTexture.Type.ELYTRA;
import static com.mojang.authlib.minecraft.MinecraftProfileTexture.Type.SKIN;
import static net.minecraft.client.renderer.GlStateManager.*;
public class GuiSkins extends GameGui {
private static final int MAX_SKIN_DIMENSION = 1024;
private int updateCounter = 0;
private final Iterator<SkinServer> skinServers;
private SkinServer gateway;
private Button btnUpload;
private Button btnClear;
@ -93,11 +100,9 @@ public class GuiSkins extends GameGui {
private File pendingSkinFile;
private File selectedSkin;
private int lastMouseX = 0;
private static GuiSkins instance;
private GuiSkins instance;
protected CubeMap panorama;
@ -112,9 +117,17 @@ public class GuiSkins extends GameGui {
}
}
public GuiSkins() {
public GuiSkins(List<SkinServer> servers) {
instance = this;
// Generate a cycled iterator that will never run out of entries.
this.skinServers = cycle(servers, SkinServer::verifyGateway);
if (this.skinServers.hasNext()) {
this.gateway = this.skinServers.next();
} else {
this.uploadError = "There are no valid skin servers available! Check your config.";
}
Minecraft minecraft = Minecraft.getMinecraft();
GameProfile profile = minecraft.getSession().getProfile();
@ -126,20 +139,25 @@ public class GuiSkins extends GameGui {
rm.options = minecraft.gameSettings;
rm.renderViewEntity = localPlayer;
if (gateway != null) {
reloadRemoteSkin();
fetchingSkin = true;
}
panorama = new CubeMap(this);
initPanorama();
}
private static <T> Iterator<T> cycle(List<T> list, Predicate<T> filter) {
return Iterables.cycle(Iterables.filter(list, filter::test)).iterator();
}
protected void initPanorama() {
panorama.setSource("hdskins:textures/cubemaps/cubemap0_%d.png");
}
protected EntityPlayerModel getModel(GameProfile profile) {
return new EntityPlayerModel(profile);
return new EntityPlayerModel(this, profile);
}
@Override
@ -207,7 +225,7 @@ public class GuiSkins extends GameGui {
@Override
public void initGui() {
GLWindow.current().setDropTargetListener(files -> {
files.stream().findFirst().ifPresent(instance::loadLocalFile);
files.stream().findFirst().ifPresent(this::loadLocalFile);
});
panorama.init();
@ -216,7 +234,7 @@ public class GuiSkins extends GameGui {
addButton(new Label(34, 34, "hdskins.local", 0xffffff));
addButton(new Label(width / 2 + 34, 34, "hdskins.server", 0xffffff));
addButton(new Button(width / 2 - 150, height - 27, 90, 20, "hdskins.options.browse", sender ->{
addButton(new Button(width / 2 - 150, height - 27, 90, 20, "hdskins.options.browse", sender -> {
selectedSkin = null;
localPlayer.releaseTextures();
openFileThread = new ThreadOpenFilePNG(mc, format("hdskins.open.title"), (fileDialog, dialogResult) -> {
@ -262,9 +280,18 @@ public class GuiSkins extends GameGui {
}).setIcon(new ItemStack(Items.ELYTRA))).setEnabled(textureType == SKIN).setTooltip(format("hdskins.mode.skin", toTitleCase(ELYTRA.name())));
addButton(new Button(width - 25, height - 65, 20, 20, "?", sender -> {
addButton(new Button(width - 25, height - 65, 20, 20, "?", this::switchServer))
.setTooltip(Splitter.on("\r\n").splitToList(gateway == null ? "" : gateway.toString()));
}
private void switchServer(Button sender) {
mc.getSoundHandler().playSound(PositionedSoundRecord.getMasterRecord(SoundEvents.ENTITY_VILLAGER_YES, 1));
})).setTooltip(Splitter.on("\r\n").splitToList(HDSkinManager.INSTANCE.getGatewayServer().toString()));
gateway = skinServers.next();
if (gateway != null) {
sender.setTooltip(Splitter.on("\r\n").splitToList(gateway.toString()));
reloadRemoteSkin();
fetchingSkin = true;
}
}
@Override
@ -346,6 +373,7 @@ public class GuiSkins extends GameGui {
@Override
protected void actionPerformed(GuiButton guiButton) {
if (openFileThread == null && !uploadingSkin && clearMessage()) {
super.actionPerformed(guiButton);
}
@ -353,6 +381,10 @@ public class GuiSkins extends GameGui {
@Override
protected void mouseClicked(int mouseX, int mouseY, int button) throws IOException {
if (this.gateway == null) {
// doing things might break everything if there is no gateway
return;
}
if (clearMessage()) {
super.mouseClicked(mouseX, mouseY, button);
@ -436,7 +468,7 @@ public class GuiSkins extends GameGui {
if (!localPlayer.isUsingLocalTexture()) {
Gui.drawRect(40, height / 2 - 12, width / 2 - 40, height / 2 + 12, 0xB0000000);
drawCenteredString(fontRenderer, localMessage, (int)xPos1, height / 2 - 4, 0xffffff);
drawCenteredString(fontRenderer, localMessage, (int) xPos1, height / 2 - 4, 0xffffff);
}
if (fetchingSkin) {
@ -446,10 +478,10 @@ public class GuiSkins extends GameGui {
Gui.drawRect((int) (xPos2 - width / 4 + 40), height / 2 - lineHeight, width - 40, height / 2 + lineHeight, 0xB0000000);
if (throttledByMojang) {
drawCenteredString(fontRenderer, format("hdskins.error.mojang"), (int)xPos2, height / 2 - 10, 0xffffff);
drawCenteredString(fontRenderer, format("hdskins.error.mojang.wait"), (int)xPos2, height / 2 + 2, 0xffffff);
drawCenteredString(fontRenderer, format("hdskins.error.mojang"), (int) xPos2, height / 2 - 10, 0xffffff);
drawCenteredString(fontRenderer, format("hdskins.error.mojang.wait"), (int) xPos2, height / 2 + 2, 0xffffff);
} else {
drawCenteredString(fontRenderer, format("hdskins.fetch"), (int)xPos2, height / 2 - 4, 0xffffff);
drawCenteredString(fontRenderer, format("hdskins.fetch"), (int) xPos2, height / 2 - 4, 0xffffff);
}
}
@ -496,8 +528,8 @@ public class GuiSkins extends GameGui {
rotate(((updateCounter + partialTick) * 2.5F) % 360, 0, 1, 0);
thePlayer.rotationYawHead = (float)Math.atan(mouseX / 20) * 30;
thePlayer.rotationPitch = (float)Math.atan(mouseY / 40) * -20;
thePlayer.rotationYawHead = (float) Math.atan(mouseX / 20) * 30;
thePlayer.rotationPitch = (float) Math.atan(mouseY / 40) * -20;
mc.getRenderManager().renderEntity(thePlayer, 0, 0, 0, 0, 1, false);
@ -543,8 +575,7 @@ public class GuiSkins extends GameGui {
uploadMessage = format(uploadMsg);
btnUpload.enabled = canUpload();
HDSkinManager.INSTANCE.getGatewayServer()
.uploadSkin(mc.getSession(), new SkinUpload(textureType, path, getMetadata()))
gateway.uploadSkin(mc.getSession(), new SkinUpload(textureType, path, getMetadata()))
.thenAccept(this::onUploadComplete)
.exceptionally(this::onUploadFailure);
}
@ -574,4 +605,9 @@ public class GuiSkins extends GameGui {
protected boolean canUpload() {
return selectedSkin != null && !uploadingSkin && !pendingRemoteSkinRefresh;
}
CompletableFuture<PreviewTextureManager> loadTextures(GameProfile profile) {
return PreviewTextureManager.load(this.gateway, profile);
}
}

View file

@ -137,6 +137,11 @@ public class LegacySkinServer implements SkinServer {
return String.format("%s/%s/%s.png", address, path, uuid);
}
@Override
public boolean verifyGateway() {
return !Strings.isNullOrEmpty(this.gateway);
}
@Override
public String toString() {
return new IndentedToStringStyle.Builder(this)

View file

@ -36,6 +36,10 @@ public interface SkinServer extends Exposable {
return CallableFutures.asyncFailableFuture(() -> loadProfileData(profile), HDSkinManager.skinDownloadExecutor);
}
default boolean verifyGateway() {
return true;
}
static void verifyServerConnection(Session session, String serverId) throws AuthenticationException {
MinecraftSessionService service = Minecraft.getMinecraft().getSessionService();
service.joinServer(session.getProfile(), session.getToken(), serverId);

View file

@ -77,7 +77,7 @@ public class MineLittlePony {
// logger.info("Set MineLP skin server URL.");
manager.addClearListener(ponyManager);
manager.setPrefferedSkinsGuiClass(GuiSkinsMineLP.class);
manager.setSkinsGui(GuiSkinsMineLP::new);
RenderManager rm = minecraft.getRenderManager();
renderManager.initialisePlayerRenderers(rm);

View file

@ -3,7 +3,7 @@ package com.minelittlepony.hdskins.gui;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
import com.voxelmodpack.hdskins.gui.EntityPlayerModel;
import com.voxelmodpack.hdskins.gui.GuiSkins;
import net.minecraft.util.ResourceLocation;
/**
@ -16,8 +16,8 @@ public class EntityPonyModel extends EntityPlayerModel {
public boolean wet = false;
public EntityPonyModel(GameProfile profile) {
super(profile);
public EntityPonyModel(GuiSkins skins, GameProfile profile) {
super(skins, profile);
}
@Override

View file

@ -9,13 +9,15 @@ import com.mojang.authlib.minecraft.MinecraftProfileTexture;
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
import com.voxelmodpack.hdskins.gui.EntityPlayerModel;
import com.voxelmodpack.hdskins.gui.GuiSkins;
import com.voxelmodpack.hdskins.skins.SkinServer;
import net.minecraft.client.audio.PositionedSoundRecord;
import net.minecraft.init.Items;
import net.minecraft.init.SoundEvents;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import java.util.List;
/**
* Skin uploading GUI. Usually displayed over the main menu.
*/
@ -28,15 +30,18 @@ public class GuiSkinsMineLP extends GuiSkins {
private boolean isWet = false;
private static final String[] panoramas = new String[] {
"minelp:textures/cubemap/sugarcubecorner_%d.png",
"minelp:textures/cubemap/quillsandsofas_%d.png"
};
public GuiSkinsMineLP(List<SkinServer> servers) {
super(servers);
}
@Override
protected EntityPlayerModel getModel(GameProfile profile) {
return new EntityPonyModel(profile);
return new EntityPonyModel(this, profile);
}
@Override