Store minecraft data in current directory

1.8k views Asked by At

EDIT: used different decompiler now includes the Util$OS.class file

I am trying to modify the mine craft launcher to check for a minecraft folder in the current working directory and if none exists then use the established routines to Crete and download the needed files. This is my first foray into java programing so I am feeling a bit lost. Here is the source of the offending class file: (the block that i think needs modifying starts on line 15)

File Util.class

package net.minecraft;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.lang.reflect.Method;
import java.net.URI;
import java.net.URL;
import java.security.PublicKey;
import java.security.cert.Certificate;
import javax.net.ssl.HttpsURLConnection;

public class Util
{
  private static File workDir = null;

  public static File getWorkingDirectory() {
    if (workDir == null) workDir = getWorkingDirectory("minecraft");
    return workDir;
  }

  public static File getWorkingDirectory(String applicationName) {
    String userHome = System.getProperty("user.home", ".");
    File workingDirectory;
    File workingDirectory;
    File workingDirectory;
    File workingDirectory;
    switch ($SWITCH_TABLE$net$minecraft$Util$OS()[getPlatform().ordinal()]) {
    case 1:
    case 2:
      workingDirectory = new File(userHome, '.' + applicationName + '/');
      break;
    case 3:
      String applicationData = System.getenv("APPDATA");
      File workingDirectory;
      if (applicationData != null) workingDirectory = new File(applicationData, "." + applicationName + '/'); else
        workingDirectory = new File(userHome, '.' + applicationName + '/');
      break;
    case 4:
      workingDirectory = new File(userHome, "Library/Application Support/" + applicationName);
      break;
    default:
      workingDirectory = new File(userHome, applicationName + '/');
    }
    if ((!workingDirectory.exists()) && (!workingDirectory.mkdirs())) throw new RuntimeException("The working directory could not be created: " + workingDirectory);
    return workingDirectory;
  }

  private static OS getPlatform() {
    String osName = System.getProperty("os.name").toLowerCase();
    if (osName.contains("win")) return OS.windows;
    if (osName.contains("mac")) return OS.macos;
    if (osName.contains("solaris")) return OS.solaris;
    if (osName.contains("sunos")) return OS.solaris;
    if (osName.contains("linux")) return OS.linux;
    if (osName.contains("unix")) return OS.linux;
    return OS.unknown;
  }

  public static String excutePost(String targetURL, String urlParameters)
  {
    HttpsURLConnection connection = null;
    try
    {
      URL url = new URL(targetURL);
      connection = (HttpsURLConnection)url.openConnection();
      connection.setRequestMethod("POST");
      connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

      connection.setRequestProperty("Content-Length", Integer.toString(urlParameters.getBytes().length));
      connection.setRequestProperty("Content-Language", "en-US");

      connection.setUseCaches(false);
      connection.setDoInput(true);
      connection.setDoOutput(true);

      connection.connect();
      Certificate[] certs = connection.getServerCertificates();

      byte[] bytes = new byte[294];
      DataInputStream dis = new DataInputStream(Util.class.getResourceAsStream("minecraft.key"));
      dis.readFully(bytes);
      dis.close();

      Certificate c = certs[0];
      PublicKey pk = c.getPublicKey();
      byte[] data = pk.getEncoded();

      for (int i = 0; i < data.length; i++) {
        if (data[i] == bytes[i]) continue; throw new RuntimeException("Public key mismatch");
      }

      DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
      wr.writeBytes(urlParameters);
      wr.flush();
      wr.close();

      InputStream is = connection.getInputStream();
      BufferedReader rd = new BufferedReader(new InputStreamReader(is));

      StringBuffer response = new StringBuffer();
      String line;
      while ((line = rd.readLine()) != null)
      {
        String line;
        response.append(line);
        response.append('\r');
      }
      rd.close();

      String str1 = response.toString();
      return str1;
    }
    catch (Exception e)
    {
      e.printStackTrace();
      return null;
    }
    finally
    {
      if (connection != null)
        connection.disconnect();
    }
    throw localObject;
  }

  public static boolean isEmpty(String str) {
    return (str == null) || (str.length() == 0);
  }

  public static void openLink(URI uri) {
    try {
      Object o = Class.forName("java.awt.Desktop").getMethod("getDesktop", new Class[0]).invoke(null, new Object[0]);
      o.getClass().getMethod("browse", new Class[] { URI.class }).invoke(o, new Object[] { uri });
    } catch (Throwable e) {
      System.out.println("Failed to open link " + uri.toString());
    }
  }

  private static enum OS
  {
    linux, solaris, windows, macos, unknown;
  }
}

I have done some research on getting the current working directory but i am not sure what needs modifing. If someone could at least explain what the various parts of the file mean that would be very helpful.

3

There are 3 answers

1
Leon Blade On BEST ANSWER
public static File getWorkingDirectory(String applicationName) {
    File workingDirectory = new File("." + File.separator + applicationName);
    if ((!workingDirectory.exists()) && (!workingDirectory.mkdirs())) 
        throw new RuntimeException("The working directory could not be created: " + workingDirectory);
    return workingDirectory;
}

Sorry for the confusion, this should work just fine for you. It will create a minecraft folder in the same directory as your launcher.

Note: On OS X this will still create the folder in the folder as the .app, not the .app/Contents/Resources/Java folder that the actual JAR is in, so you wont have any problem on any operating system.

Hope this helps!

1
Bill K On

I'm still not completely sure I understand your goals.

If you want to have it download "Minecraft" for you I'd try to do it in a batch file and shell script and just run the one that was appropriate for your system.

If you want to somehow "download" your worlds, texture packs and mods from somewhere then you could do the same.

If what you want is for every minecraft install you are playing on to use your data (like on a USB stick or something) you might have batch files that either copy over the data before running minecraft or perhaps use "ln" to replace the directories that minecraft thinks it's going to use with your own on your usb stick.

0
kapurai On

You can always modify the field that points to the directory where MC puts its saves and change it to whatever you want. Here's a snippet from my launcher (http://www.github.com/lekro/ModdishLauncher):

ClassLoader cl = new URLClassLoader(urls, ModdishLauncher.class.getClassLoader());
Class<?> mc = null;
try {
    mc = cl.loadClass("net.minecraft.client.Minecraft");
} catch (ClassNotFoundException e2) {
    System.err.println("Couldn't find Minecraft main class!");
    e2.printStackTrace();
}
Field[] fields = mc.getDeclaredFields();
Field mcPathField = null;
for (int i = 0; i < fields.length; i++) {
    Field f = fields[i];
    if (f.getType() != File.class) {
    continue;
    }
    if (f.getModifiers() != (Modifier.PRIVATE + Modifier.STATIC)) {
    continue;
    }
    mcPathField = f;
    break;
}
mcPathField.setAccessible(true);
try {
    mcPathField.set(null, new File(myDir + "/minecrafts/"+minecraftType+"/"));
} catch (IllegalArgumentException e2) {
    e2.printStackTrace();
} catch (IllegalAccessException e2) {
    e2.printStackTrace();
}

This takes the hardcoded path field inside the Minecraft class and modifies it to whatever you want it to be. (e.g. on a USB stick, in a custom folder, etc.)