diff --git a/README.md b/README.md
new file mode 100644
index 0000000..0b6bbf6
--- /dev/null
+++ b/README.md
@@ -0,0 +1,35 @@
+# MinecraftSkinFixer
+
+MinecraftSkinFixer is a simple program which allows old versions of Minecraft to download Skins from the new Skin servers.
+~~The [Minecraft Forum Thread](https://www.minecraftforum.net/forums/mapping-and-modding-java-edition/minecraft-tools/2923190-minecraftskinfixer-skins-in-old-minecraft-versions) contains more information.~~
+*The Minecraft Forum Thread dissappeared around December 2018/January 2019, together with my Minecraft Forum Account.*
+
+**NOTE: Versions 2.2 and 2.3 were removed.**
+This is because the mods for 1.6.2, 1.6.4 and 1.7.2 which shipped with them did not comply with Minecraft's EULA.
+I hope to eventually release a version 2.5 with new, compliant mods.
+*And in case you are wondering: 1.x, 2.0 and 2.1 were never released in the first place.*
+
+---
+
+### Supported Minecraft Versions
+
+All Minecraft versions since the introduction of custom skins up to release 1.5.2 are supported.
+However, if you are using a version between release 1.0 and release 1.2.5, you need to supply the `--flip-bottoms=off` parameter when launching the program to make the skins render correctly.
+
+---
+
+### Usage instructions:
+1. Download the MinecraftSkinFixer .jar file from the releases tab
+2. Start the Minecraft launcher
+3. Start MinecraftSkinFixer
+4. If this is your first time using MinecraftSkinFixer, configure your launcher profile as instructed by the program
+5. Launch Minecraft
+
+---
+
+The main program has two dependencies:
+* [Non-standard JRE HTTP server](https://docs.oracle.com/javase/8/docs/jre/api/net/httpserver/spec/index.html) (included in most JREs)
+* [org.json:json:20150729](https://search.maven.org/artifact/org.json/json/20150729/jar) (included in the release jars)
+
+To be able to use it, you need to have Java 8 or later installed on your computer.
+
diff --git a/main/minecraftskinfixer/HTTPProxyServer.java b/main/minecraftskinfixer/HTTPProxyServer.java
new file mode 100644
index 0000000..5507a56
--- /dev/null
+++ b/main/minecraftskinfixer/HTTPProxyServer.java
@@ -0,0 +1,72 @@
+package minecraftskinfixer;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+import java.net.URL;
+import java.net.URLConnection;
+
+import com.sun.net.httpserver.Headers;
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import com.sun.net.httpserver.HttpServer;
+
+public class HTTPProxyServer implements HttpHandler {
+
+ private static SuperSimpleLogger logger;
+ private static int connectionIdCounter = 0;
+
+ public static void start(int port, SuperSimpleLogger logger) {
+ HTTPProxyServer.logger = logger;
+ HttpServer server = null;
+ try {
+ server = HttpServer.create(new InetSocketAddress("127.0.0.1", port), 0);
+ } catch (IOException e) {
+ logger.log("[HTTP Proxy] Unable to create HTTP Server: " + e.getClass().getName() + ": " + e.getMessage());
+ return;
+ }
+ server.createContext("/", new HTTPProxyServer());
+ server.start();
+ logger.log("[HTTP Proxy] HTTP Server successfully started on port " + port);
+ }
+
+ @Override
+ public void handle(HttpExchange he) throws IOException {
+ String connectionId = "[HTTP #" + connectionIdCounter++ + "] ";
+ Headers requestHeaders = he.getRequestHeaders();
+ String requestedHost = requestHeaders.get("Host").get(0);
+ String requestedUrl = he.getRequestURI().toString();
+ if(requestedUrl.contains(requestedHost)) {
+ requestedUrl = requestedUrl.substring(requestedUrl.indexOf(requestedHost) + requestedHost.length());
+ }
+ logger.log("[HTTP Proxy] " + connectionId + "Received a HTTP " + he.getRequestMethod() + " request for " + requestedHost + requestedUrl);
+ if(he.getRequestMethod().equals("GET") && (
+ requestedHost.equals("www.minecraft.net") && requestedUrl.startsWith("/skin/") ||
+ requestedHost.equals("s3.amazonaws.com") && requestedUrl.startsWith("/MinecraftSkins/") ||
+ requestedHost.equals("s3.amazonaws.com") && requestedUrl.startsWith("/MinecraftCloaks/") ||
+ requestedHost.equals("skins.minecraft.net") && requestedUrl.startsWith("/MinecraftSkins/") ||
+ requestedHost.equals("skins.minecraft.net") && requestedUrl.startsWith("/MinecraftCloaks/"))) {
+ logger.log("[HTTP Proxy] " + connectionId + "Identified request as Minecraft skin request - forwarding to Minecraft skin request handler.");
+ SkinFixer.runSkinFixer(connectionId, he, requestedHost, requestedUrl);
+ } else if(he.getRequestMethod().equals("GET")) {
+ logger.log("[HTTP Proxy] " + connectionId + "Request does not look like a Minecraft skin request - being a really bad but at least possibly kind of working proxy server.");
+ URL url = new URL("http://" + requestedHost + requestedUrl);
+ URLConnection conn = url.openConnection();
+ he.sendResponseHeaders(200, conn.getContentLengthLong());
+ InputStream is = conn.getInputStream();
+ OutputStream os = he.getResponseBody();
+ byte[] buff = new byte[4096];
+ int read;
+ while((read = is.read(buff)) != -1) {
+ os.write(buff, 0, read);
+ }
+ he.close();
+ } else {
+ logger.log("[HTTP Proxy] " + connectionId + "Request is not a GET request and therefore not supported by this program. Responding with 500 Internal Server Error.");
+ he.sendResponseHeaders(500, 0);
+ he.close();
+ }
+ }
+
+}
diff --git a/main/minecraftskinfixer/LogWindow.java b/main/minecraftskinfixer/LogWindow.java
new file mode 100644
index 0000000..b29bed2
--- /dev/null
+++ b/main/minecraftskinfixer/LogWindow.java
@@ -0,0 +1,52 @@
+package minecraftskinfixer;
+
+import java.awt.BorderLayout;
+import java.awt.Font;
+import java.util.Calendar;
+
+import javax.swing.JFrame;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+
+@SuppressWarnings("serial")
+public class LogWindow extends JFrame implements SuperSimpleLogger {
+
+ private JTextArea text;
+ private JScrollPane scroll;
+
+ public LogWindow() {
+ super("Minecraft Skin Fixer " + SkinFixer2Main.VERSION);
+ text = new JTextArea();
+ text.setFont(new Font("Monospaced", 0, 12));
+ text.setEditable(false);
+ scroll = new JScrollPane(text, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
+ setLayout(new BorderLayout());
+ add(scroll, BorderLayout.CENTER);
+ setSize(600, 400);
+ setDefaultCloseOperation(EXIT_ON_CLOSE);
+ setVisible(true);
+ revalidate();
+ repaint();
+ }
+
+ @Override
+ public void log(String s) {
+ Calendar c = Calendar.getInstance();
+ String timestamp = String.format("[%d-%02d-%02d %02d:%02d:%02d.%03d] ",
+ c.get(Calendar.YEAR),
+ c.get(Calendar.MONTH) + 1,
+ c.get(Calendar.DAY_OF_MONTH),
+ c.get(Calendar.HOUR_OF_DAY),
+ c.get(Calendar.MINUTE),
+ c.get(Calendar.SECOND),
+ c.get(Calendar.MILLISECOND));
+ System.out.println(timestamp + s);
+ if(text.getText().length() == 0) {
+ text.setText(timestamp + s);
+ } else {
+ text.setText(text.getText() + '\n' + timestamp + s);
+ }
+ scroll.getVerticalScrollBar().setValue(scroll.getVerticalScrollBar().getMaximum());
+ }
+
+}
diff --git a/main/minecraftskinfixer/SkinConverter.java b/main/minecraftskinfixer/SkinConverter.java
new file mode 100644
index 0000000..ec7ff5c
--- /dev/null
+++ b/main/minecraftskinfixer/SkinConverter.java
@@ -0,0 +1,88 @@
+package minecraftskinfixer;
+
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+
+public class SkinConverter {
+
+ public static BufferedImage convert(BufferedImage original, boolean isSlim, boolean flipBottoms, SuperSimpleLogger logger, String connectionId) {
+ if(original.getHeight() <= 32 && !isSlim && !flipBottoms) {
+ logger.log("[Skin Converter] " + connectionId + "Skin is compatible - not converting.");
+ return original;
+ }
+ BufferedImage converted = new BufferedImage(64, 32, BufferedImage.TYPE_INT_ARGB);
+ Graphics2D g = converted.createGraphics();
+ if(isSlim) {
+ logger.log("[Skin Converter] " + connectionId + "Converting from slim to normal model");
+ //head and second layer of head
+ g.drawImage(original.getSubimage(0, 0, 64, 16), 0, 0, null);
+ //legs, body and
+ //arm: right, front pt. 1 and top pt. 1
+ g.drawImage(original.getSubimage(0, 16, 46, 16), 0, 16, null);
+ //arm: front pt. 2 and top pt. 2
+ g.drawImage(original.getSubimage(45, 16, 2, 16), 46, 16, null);
+ //arm: left, bottom pt. 1 and back pt. 1
+ g.drawImage(original.getSubimage(47, 16, 6, 16), 48, 16, null);
+ //arm: bottom pt. 2
+ g.drawImage(original.getSubimage(48, 16, 2, 4), 50, 16, null);
+ //arm: back pt. 2
+ g.drawImage(original.getSubimage(52, 20, 2, 12), 54, 20, null);
+ } else {
+ g.drawImage(original.getSubimage(0, 0, 64, 32), 0, 0, null);
+ }
+ if(original.getHeight() >= 64) {
+ logger.log("[Skin Converter] " + connectionId + "Merging second layer from 1.8+ skin onto first layer");
+ if(isSlim) {
+ //legs, body and
+ //arm: right, front pt. 1 and top pt. 1
+ g.drawImage(original.getSubimage(0, 32, 46, 16), 0, 16, null);
+ //arm: front pt. 2 and top pt. 2
+ g.drawImage(original.getSubimage(45, 32, 2, 16), 46, 16, null);
+ //arm: left, bottom pt. 1 and back pt. 1
+ g.drawImage(original.getSubimage(47, 32, 6, 16), 48, 16, null);
+ //arm: bottom pt. 2
+ g.drawImage(original.getSubimage(48, 32, 2, 4), 50, 16, null);
+ //arm: back pt. 2
+ g.drawImage(original.getSubimage(52, 36, 2, 12), 54, 20, null);
+ } else {
+ g.drawImage(original.getSubimage(0, 32, 56, 16), 0, 16, null);
+ }
+ }
+ if(flipBottoms) {
+ logger.log("[Skin Converter]" + connectionId + "Flipping bottom pieces");
+ BufferedImage buffer = converted;
+ converted = new BufferedImage(64, 32, BufferedImage.TYPE_INT_ARGB);
+ g = converted.createGraphics();
+ //head top
+ g.drawImage(buffer.getSubimage(8, 0, 8, 8), 8, 0, null);
+ //head2 top
+ g.drawImage(buffer.getSubimage(40, 0, 8, 8), 40, 0, null);
+ //head and head2 right, front, left and back
+ g.drawImage(buffer.getSubimage(0, 8, 64, 8), 0, 8, null);
+ //legs top
+ g.drawImage(buffer.getSubimage(4, 16, 4, 4), 4, 16, null);
+ //body top
+ g.drawImage(buffer.getSubimage(20, 16, 8, 4), 20, 16, null);
+ //arms top
+ g.drawImage(buffer.getSubimage(44, 16, 4, 4), 44, 16, null);
+ //legs, body and arms right, front, left and back
+ g.drawImage(buffer.getSubimage(0, 20, 56, 12), 0, 20, null);
+ for(int i = 0; i < 8; i++) {
+ //head bottom
+ g.drawImage(buffer.getSubimage(16, i, 8, 1), 16, 7 - i, null);
+ //head2 bottom
+ g.drawImage(buffer.getSubimage(48, i, 8, 1), 48, 7 - i, null);
+ }
+ for(int i = 0; i < 4; i++) {
+ //legs bottom
+ g.drawImage(buffer.getSubimage(8, 16 + i, 4, 1), 8, 16 + 3 - i, null);
+ //body bottom
+ g.drawImage(buffer.getSubimage(28, 16 + i, 8, 1), 28, 16 + 3 - i, null);
+ //arms bottom
+ g.drawImage(buffer.getSubimage(48, 16 + i, 4, 1), 48, 16 + 3 - i, null);
+ }
+ }
+ return converted;
+ }
+
+}
diff --git a/main/minecraftskinfixer/SkinFixer.java b/main/minecraftskinfixer/SkinFixer.java
new file mode 100644
index 0000000..0fe74ca
--- /dev/null
+++ b/main/minecraftskinfixer/SkinFixer.java
@@ -0,0 +1,162 @@
+package minecraftskinfixer;
+
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Base64;
+import java.util.HashMap;
+
+import javax.imageio.ImageIO;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import com.sun.net.httpserver.HttpExchange;
+
+public class SkinFixer {
+
+ /**
+ * 0 = automatically decide if bottom sides of skins need to be flipped.
+ * does not work for versions from release 1.0 to release 1.2.5
+ * 1 = don't convert skins
+ * 2 = never flip bottom sides of skin parts
+ * 3 = always flip bottom sides of skin parts
+ */
+ public static byte CONVERT_MODE = 0;
+
+ private static SuperSimpleLogger logger;
+ private static HashMap remoteFileCache = new HashMap();
+
+ public static void gimmeLogger(SuperSimpleLogger logger) {
+ SkinFixer.logger = logger;
+ }
+
+ public static void runSkinFixer(String connectionId, HttpExchange exchange, String hostname, String url) throws IOException {
+ byte[] imageFile = doRunSkinFixer(connectionId, hostname, url);
+ if(imageFile.length != 0) {
+ exchange.getResponseHeaders().add("Content-Type", "image/png");
+ exchange.sendResponseHeaders(200, imageFile.length);
+ exchange.getResponseBody().write(imageFile);
+ exchange.close();
+ } else {
+ exchange.sendResponseHeaders(404, 0);
+ exchange.close();
+ }
+ logger.log("[Skin Fixer] " + connectionId + "Request served successfully. HTTP Connection to game closed.");
+ }
+
+ private static byte[] doRunSkinFixer(String connectionId, String hostname, String url) throws IOException {
+ String username;
+ String textureType;
+ boolean autoWouldFlipBottoms;
+ if(hostname.equals("www.minecraft.net") && url.startsWith("/skin/")) {
+ username = url.substring("/skin/".length(), url.length() - ".png".length());
+ textureType = "SKIN";
+ autoWouldFlipBottoms = true;
+ logger.log("[Skin Fixer] " + connectionId + "Received Generation 1 request for skin of player " + username);
+ } else if(hostname.equals("s3.amazonaws.com") && url.startsWith("/MinecraftSkins/")) {
+ username = url.substring("/MinecraftSkins/".length(), url.length() - ".png".length());
+ textureType = "SKIN";
+ autoWouldFlipBottoms = true;
+ logger.log("[Skin Fixer] " + connectionId + "Received Generation 2 request for skin of player " + username);
+ } else if(hostname.equals("s3.amazonaws.com") && url.startsWith("/MinecraftCloaks/")) {
+ username = url.substring("/MinecraftCloaks/".length(), url.length() - ".png".length());
+ textureType = "CAPE";
+ autoWouldFlipBottoms = true;
+ logger.log("[Skin Fixer] " + connectionId + "Received Generation 2 request for cape of player " + username);
+ } else if(hostname.equals("skins.minecraft.net") && url.startsWith("/MinecraftSkins/")) {
+ username = url.substring("/MinecraftSkins/".length(), url.length() - ".png".length());
+ textureType = "SKIN";
+ autoWouldFlipBottoms = false;
+ logger.log("[Skin Fixer] " + connectionId + "Received Generation 3 request for skin of player " + username);
+ } else if(hostname.equals("skins.minecraft.net") && url.startsWith("/MinecraftCloaks/")) {
+ username = url.substring("/MinecraftCloaks/".length(), url.length() - ".png".length());
+ textureType = "CAPE";
+ autoWouldFlipBottoms = false;
+ logger.log("[Skin Fixer] " + connectionId + "Received Generation 3 request for cape of player " + username);
+ } else {
+ throw new RuntimeException();
+ }
+ String uuid = new JSONObject(new String(getRemoteFile("https://api.mojang.com/users/profiles/minecraft/" + username, connectionId))).getString("id");
+ logger.log("[Skin Fixer] " + connectionId + "UUID of player " + username + " is " + uuid);
+ JSONObject profileData = new JSONObject(new String(getRemoteFile("https://sessionserver.mojang.com/session/minecraft/profile/" + uuid, connectionId)));
+ JSONArray profileProperties = profileData.getJSONArray("properties");
+ JSONObject textureProperties = null;
+ for(Object o : profileProperties) {
+ if(o instanceof JSONObject) {
+ JSONObject obj = (JSONObject)o;
+ if(obj.has("name") && obj.get("name").equals("textures")) {
+ textureProperties = obj;
+ }
+ }
+ }
+ if(textureProperties == null) {
+ logger.log("[Skin Fixer] " + connectionId + "Player does not have texture properties.");
+ return new byte[0];
+ }
+ String texturePropsStr = textureProperties.getString("value");
+ JSONObject texProps = new JSONObject(new String(Base64.getDecoder().decode(texturePropsStr)));
+ if(!(texProps.has("textures") && texProps.get("textures") instanceof JSONObject)) {
+ logger.log("[Skin Fixer] " + connectionId + "Texture properties are missing the textures object.");
+ return new byte[0];
+ }
+ JSONObject textures = texProps.getJSONObject("textures");
+ if(!(textures.has(textureType) && textures.get(textureType) instanceof JSONObject)) {
+ logger.log("[Skin Fixer] " + connectionId + "Player doesn't have a " + textureType.toLowerCase());
+ return new byte[0];
+ }
+ JSONObject texture = textures.getJSONObject(textureType);
+ if(!(texture.has("url") && texture.get("url") instanceof String)) {
+ logger.log("[Skin Fixer] " + connectionId + "Player doesn't have a " + textureType.toLowerCase());
+ return new byte[0];
+ }
+ String textureUrl = texture.getString("url");
+ String textureId = textureUrl.substring("http://textures.minecraft.net/texture/".length());
+ logger.log("[Skin Fixer] " + connectionId + "ID of " + textureType.toLowerCase() + " texture is " + textureId);
+ if(textureType.equals("SKIN") && CONVERT_MODE != 1) {
+ byte[] skinFile = getRemoteFile(textureUrl, connectionId);
+ BufferedImage skinImage = ImageIO.read(new ByteArrayInputStream(skinFile));
+ boolean slim = false;
+ if(texture.has("metadata") && texture.get("metadata") instanceof JSONObject) {
+ JSONObject metadata = texture.getJSONObject("metadata");
+ if(metadata.has("model") && metadata.get("model") instanceof String && metadata.getString("model").equals("slim")) {
+ slim = true;
+ }
+ }
+ boolean flipBottoms = CONVERT_MODE == 0 ? autoWouldFlipBottoms : CONVERT_MODE == 3;
+ BufferedImage convertedSkinImage = SkinConverter.convert(skinImage, slim, flipBottoms, logger, connectionId);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ImageIO.write(convertedSkinImage, "PNG", baos);
+ return baos.toByteArray();
+ } else {
+ return getRemoteFile(textureUrl, connectionId);
+ }
+ }
+
+ private static byte[] getRemoteFile(String url, String connectionId) throws IOException {
+ if(remoteFileCache.containsKey(url)) {
+ logger.log("[Download] " + connectionId + "No need to download " + url + " - file is stored in cache.");
+ return remoteFileCache.get(url);
+ } else {
+ logger.log("[Download] " + connectionId + "Downloading " + url);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
+ URLConnection conn = new URL(url).openConnection();
+ InputStream is = conn.getInputStream();
+ byte[] buff = new byte[4096];
+ int read;
+ while((read = is.read(buff)) != -1) {
+ baos.write(buff, 0, read);
+ }
+ byte[] file = baos.toByteArray();
+ baos.close();
+ logger.log("[Download] " + connectionId + "Successfully downloaded " + url + " (" + file.length + " bytes)");
+ remoteFileCache.put(url, file);
+ return file;
+ }
+ }
+
+}
diff --git a/main/minecraftskinfixer/SkinFixer2Main.java b/main/minecraftskinfixer/SkinFixer2Main.java
new file mode 100644
index 0000000..39aa951
--- /dev/null
+++ b/main/minecraftskinfixer/SkinFixer2Main.java
@@ -0,0 +1,83 @@
+package minecraftskinfixer;
+
+public class SkinFixer2Main {
+
+ public static final String VERSION = "2.4";
+
+ private static SuperSimpleLogger logger;
+
+ public static void main(String[] args) {
+ logger = new LogWindow();
+ SkinFixer.gimmeLogger(logger);
+ logger.log("Welcome to Minecraft Skin Fixer " + VERSION);
+ logger.log("Made by https://github.com/DoubleNegation");
+ logger.log("Source code available at https://github.com/DoubleNegation/MinecraftSkinFixer");
+ logger.log("Running on Java " + System.getProperty("java.version"));
+ logger.log("Close this window to exit.");
+ logger.log("(Build Date: 2019-05-31)");
+ logger.log("----------------------------------------");
+ int overrideHttpPort = -1;
+ boolean printHelp = false;
+ for(String s : args) {
+ if(s.startsWith("--httpport=")) {
+ String portStr = s.substring("--httpport=".length());
+ int portNum = -1;
+ try {
+ portNum = Integer.parseInt(portStr);
+ } catch(NumberFormatException e) {
+ logger.log("WARNING: Invalid value for command line argument httpport: \"" + portStr + "\" is not a number.");
+ }
+ if(!(portNum >= 1 && portNum <= 65535)) {
+ logger.log("WARNING: Invalid port number for httpport - Must be in range 1..65535");
+ portNum = -1;
+ }
+ overrideHttpPort = portNum;
+ } else if(s.equals("--help")) {
+ printHelp = true;
+ } else if(s.equals("--no-convert")) {
+ logger.log("Skin converter was disabled via command-line argument.");
+ SkinFixer.CONVERT_MODE = 1;
+ } else if(s.startsWith("--flip-bottoms=")) {
+ String valueStr = s.substring("--flip-bottoms=".length());
+ if(valueStr.equals("on")) {
+ if(SkinFixer.CONVERT_MODE != 1) SkinFixer.CONVERT_MODE = 3;
+ } else if(valueStr.equals("off")) {
+ if(SkinFixer.CONVERT_MODE != 1) SkinFixer.CONVERT_MODE = 2;
+ } else if(valueStr.equals("auto")) {
+ if(SkinFixer.CONVERT_MODE != 1) SkinFixer.CONVERT_MODE = 0;
+ } else {
+ logger.log("WARNING: Invalid value \"" + valueStr + "\" for option --flip-bottoms. Allowed values are: on, off, auto");
+ }
+ }
+ }
+ int usedHttpPort = overrideHttpPort == -1 ? 8080 : overrideHttpPort;
+ if(overrideHttpPort == -1) {
+ logger.log("Using default port 8080 for HTTP proxy.");
+ } else {
+ logger.log("Using user-specified port " + usedHttpPort + " for HTTP proxy.");
+ }
+ if(SkinFixer.CONVERT_MODE == 2) logger.log("Bottom sides of skins will never be flipped (specified with argument --flip-bottoms=off)");
+ else if(SkinFixer.CONVERT_MODE == 3) logger.log("Bottom sides of skins will always be flipped (specified with argument --flip-bottoms=on)");
+ else if(SkinFixer.CONVERT_MODE == 1) logger.log("Skin converter mode is on automatic mode. This will not work with all versions from Minecraft 1.0 to Minecraft 1.2.5. Specify argument --flip-bottoms=off to use MinecraftSkinFixer with thoes versions.");
+ logger.log("Use command-line option --help to get a list of available command-line arguments.");
+ if(printHelp) {
+ logger.log("----------------------------------------");
+ logger.log("Available Command-Line options:");
+ logger.log("--help Causes this help screen to be displayed.");
+ logger.log("--no-convert Causes the skin converter to be disabled.");
+ logger.log("--flip-bottoms=on|off|auto Changes the behaviour of the skin converter.");
+ logger.log(" This has no effect if --no-convert is specified.");
+ logger.log(" Default: auto");
+ logger.log(" auto does not work with versions 1.0 - 1.2.5. Use off for these versions.");
+ logger.log("--httpport= Causes SkinFixer to use a different port for the HTTP proxy (default is 8080).");
+ }
+ logger.log("----------------------------------------");
+ logger.log("Add the following arguments to the \"JVM Arguments\" option of your minecraft launch configuration / launcher profile to use the skin fixer:");
+ logger.log("-Dhttp.proxyHost=127.0.0.1");
+ logger.log("-Dhttp.proxyPort=" + usedHttpPort);
+ logger.log("----------------------------------------");
+ HTTPProxyServer.start(usedHttpPort, logger);
+ logger.log("----------------------------------------");
+ }
+
+}
diff --git a/main/minecraftskinfixer/SuperSimpleLogger.java b/main/minecraftskinfixer/SuperSimpleLogger.java
new file mode 100644
index 0000000..d4f2ea9
--- /dev/null
+++ b/main/minecraftskinfixer/SuperSimpleLogger.java
@@ -0,0 +1,7 @@
+package minecraftskinfixer;
+
+public interface SuperSimpleLogger {
+
+ public void log(String s);
+
+}