Skip to content

Commit

Permalink
Version 2.4
Browse files Browse the repository at this point in the history
  • Loading branch information
DoubleNegation committed May 31, 2019
0 parents commit 7de45d7
Show file tree
Hide file tree
Showing 7 changed files with 499 additions and 0 deletions.
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -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.

72 changes: 72 additions & 0 deletions main/minecraftskinfixer/HTTPProxyServer.java
Original file line number Diff line number Diff line change
@@ -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();
}
}

}
52 changes: 52 additions & 0 deletions main/minecraftskinfixer/LogWindow.java
Original file line number Diff line number Diff line change
@@ -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());
}

}
88 changes: 88 additions & 0 deletions main/minecraftskinfixer/SkinConverter.java
Original file line number Diff line number Diff line change
@@ -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;
}

}
Loading

0 comments on commit 7de45d7

Please sign in to comment.