mirror of
https://github.com/AngelAuraMC/Amethyst-Android.git
synced 2026-07-30 10:16:51 -04:00
Merge pull request #320 from AngelAuraMC/fix/modpack-import-perf-issue
Fix/modpack import perf issue
This commit is contained in:
@@ -73,7 +73,7 @@ public class ProgressLayout extends ConstraintLayout implements View.OnClickList
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasProcesses(){
|
||||
public static boolean hasProcesses(){
|
||||
return ProgressKeeper.getTaskCount() > 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,8 +10,10 @@ import android.Manifest;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.database.Cursor;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.provider.OpenableColumns;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.ImageButton;
|
||||
@@ -60,11 +62,14 @@ import net.kdt.pojavlaunch.value.launcherprofiles.LauncherProfiles;
|
||||
import net.kdt.pojavlaunch.value.launcherprofiles.MinecraftProfile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.text.ParseException;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class LauncherActivity extends BaseActivity {
|
||||
public static final String SETTING_FRAGMENT_TAG = "SETTINGS_FRAGMENT";
|
||||
@@ -78,14 +83,42 @@ public class LauncherActivity extends BaseActivity {
|
||||
if(data != null) {
|
||||
PojavApplication.sExecutorService.execute(() -> {
|
||||
try {
|
||||
ModLoader loaderInfo = new CommonApi(getString(R.string.curseforge_api_key)).importModpack(this, data);
|
||||
// Copy ZIP file to cache
|
||||
long fileSize = -1;
|
||||
try (Cursor returnCursor = getContentResolver().query(data, new String[]{OpenableColumns.SIZE}, null, null, null)) {
|
||||
if (returnCursor != null && returnCursor.moveToFirst()) {
|
||||
fileSize = returnCursor.getLong(0);
|
||||
}
|
||||
}
|
||||
File modpackFile = new File(Tools.DIR_CACHE, "import_modpack_placeholdername.cf");
|
||||
try (InputStream inputStream = getContentResolver().openInputStream(data)){
|
||||
FileOutputStream output = new FileOutputStream(modpackFile);
|
||||
byte[] b = new byte[262144];
|
||||
int read;
|
||||
int readTotal = 0;
|
||||
while ((read = inputStream.read(b)) != -1) {
|
||||
output.write(b, 0, read);
|
||||
readTotal += read;
|
||||
String readMB = fileSize > 0 ? String.format(Locale.US, "%.2f", readTotal / (1024.0 * 1024.0)) : "unknown";
|
||||
String totalMB = fileSize > 0 ? String.format(Locale.US, "%.2f", fileSize / (1024.0 * 1024.0)) : "unknown";
|
||||
int progress = fileSize > 0 ? (int) ((readTotal * 100L) / fileSize) : 0;
|
||||
ProgressLayout.setProgress(ProgressLayout.INSTALL_MODPACK, progress, R.string.import_modpack_copy, readMB, totalMB);
|
||||
}
|
||||
output.flush();
|
||||
output.close();
|
||||
}
|
||||
ModLoader loaderInfo = new CommonApi(getString(R.string.curseforge_api_key)).importModpack(modpackFile);
|
||||
modpackFile.delete();
|
||||
if (loaderInfo == null) return;
|
||||
loaderInfo.getDownloadTask(new NotificationDownloadListener(this, loaderInfo)).run();
|
||||
} catch (IOException e) {
|
||||
Tools.showErrorRemote(this, R.string.modpack_install_download_failed, e);
|
||||
ProgressLayout.clearProgress(ProgressLayout.INSTALL_MODPACK);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Tools.showError(this, R.string.not_modpack_file, e);
|
||||
ProgressLayout.clearProgress(ProgressLayout.INSTALL_MODPACK);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
ProgressLayout.clearProgress(ProgressLayout.INSTALL_MODPACK);
|
||||
// Should literally never happen because SHA-1 is required Java spec
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
@@ -138,7 +171,7 @@ public class LauncherActivity extends BaseActivity {
|
||||
};
|
||||
|
||||
private final ExtraListener<Boolean> mLaunchGameListener = (key, value) -> {
|
||||
if(mProgressLayout.hasProcesses()){
|
||||
if(ProgressLayout.hasProcesses()){
|
||||
Toast.makeText(this, R.string.tasks_ongoing, Toast.LENGTH_LONG).show();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import static net.kdt.pojavlaunch.Tools.hasOnlineProfile;
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -13,6 +14,7 @@ import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.kdt.mcgui.MineButton;
|
||||
import com.kdt.mcgui.ProgressLayout;
|
||||
|
||||
import net.kdt.pojavlaunch.BaseActivity;
|
||||
import net.kdt.pojavlaunch.LauncherActivity;
|
||||
@@ -36,6 +38,10 @@ public class ModpackCreateFragment extends Fragment {
|
||||
Activity launcheractivity = requireActivity();
|
||||
if (!(launcheractivity instanceof LauncherActivity))
|
||||
throw new IllegalStateException("Cannot import modpack without LauncherActivity");
|
||||
if(ProgressLayout.hasProcesses()){
|
||||
Toast.makeText(launcheractivity, R.string.tasks_ongoing, Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
((LauncherActivity) launcheractivity).modpackImportLauncher.launch(null);
|
||||
});;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import net.kdt.pojavlaunch.modloaders.modpacks.models.ModDetail;
|
||||
import net.kdt.pojavlaunch.modloaders.modpacks.models.ModItem;
|
||||
import net.kdt.pojavlaunch.modloaders.modpacks.models.SearchFilters;
|
||||
import net.kdt.pojavlaunch.modloaders.modpacks.models.SearchResult;
|
||||
import net.kdt.pojavlaunch.utils.ZipUtils;
|
||||
|
||||
import org.jdom2.IllegalDataException;
|
||||
|
||||
@@ -26,6 +27,7 @@ import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
/**
|
||||
@@ -124,8 +126,8 @@ public class CommonApi implements ModpackApi {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModLoader importModpack(Activity activity, Uri zipUri) throws IOException, NoSuchAlgorithmException {
|
||||
return getModpackApi(activity, zipUri).importModpack(activity, zipUri);
|
||||
public ModLoader importModpack(File modpackFile) throws IOException, NoSuchAlgorithmException {
|
||||
return getModpackApi(modpackFile).importModpack(modpackFile);
|
||||
}
|
||||
|
||||
private @NonNull ModpackApi getModpackApi(int apiSource) {
|
||||
@@ -139,29 +141,37 @@ public class CommonApi implements ModpackApi {
|
||||
}
|
||||
}
|
||||
|
||||
private @NonNull ModpackApi getModpackApi(Activity activity, Uri zipUri){
|
||||
String modrinthPackInfoFileName = "modrinth.index.json";
|
||||
String curseforgePackInfoFileName = "manifest.json";
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
inputStream = activity.getContentResolver().openInputStream(zipUri);
|
||||
ZipInputStream zipInputStream = new ZipInputStream(inputStream);
|
||||
ZipEntry zipEntry;
|
||||
private @NonNull ModpackApi getModpackApi(@NonNull File modpackFile) throws IOException {
|
||||
try (ZipFile zip = new ZipFile(modpackFile)) {
|
||||
boolean isModrinth;
|
||||
boolean isCurseforge;
|
||||
while ((zipEntry = zipInputStream.getNextEntry()) != null) {
|
||||
isModrinth = zipEntry.getName().equals(modrinthPackInfoFileName);
|
||||
isCurseforge = zipEntry.getName().equals(curseforgePackInfoFileName);
|
||||
if(isModrinth) {
|
||||
return mModrinthApi;
|
||||
} else if (isCurseforge) {
|
||||
return mCurseforgeApi;
|
||||
}
|
||||
|
||||
try {
|
||||
ZipUtils.getEntryStream(zip, "modrinth.index.json");
|
||||
isModrinth = true;
|
||||
} catch (IOException ignored) {
|
||||
isModrinth = false;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
|
||||
try {
|
||||
ZipUtils.getEntryStream(zip, "manifest.json");
|
||||
isCurseforge = true;
|
||||
} catch (IOException ignored) {
|
||||
isCurseforge = false;
|
||||
}
|
||||
|
||||
if (isModrinth && isCurseforge) {
|
||||
String name = modpackFile.getName();
|
||||
int dot = name.lastIndexOf('.');
|
||||
String extension = (dot == -1) ? "" : name.substring(dot + 1);
|
||||
if (extension.equalsIgnoreCase("mrpack")) return mModrinthApi;
|
||||
throw new IOException("Ambiguous file contains both modrinth.index.json and manifest.json. Cannot determine modpack format.");
|
||||
}
|
||||
if (isModrinth) return mModrinthApi;
|
||||
if (isCurseforge) return mCurseforgeApi;
|
||||
|
||||
throw new IllegalArgumentException("Zip provided does not contain a manifest file.");
|
||||
}
|
||||
throw new IllegalArgumentException("Zip provided does not contain a manifest file");
|
||||
}
|
||||
|
||||
/** Fuse the arrays in a way that's fair for every endpoint */
|
||||
|
||||
@@ -176,8 +176,8 @@ public class CurseforgeApi implements ModpackApi{
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModLoader importModpack(Activity activity, Uri zipUri) throws IOException, NoSuchAlgorithmException {
|
||||
return ModpackInstaller.importModpack(activity, zipUri, this::installCurseforgeZip);
|
||||
public ModLoader importModpack(File modpackFile) throws IOException, NoSuchAlgorithmException {
|
||||
return ModpackInstaller.importModpack(modpackFile, Constants.SOURCE_CURSEFORGE, this::installCurseforgeZip);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -81,8 +81,7 @@ public interface ModpackApi {
|
||||
* Imports the mod(pack) from a file.
|
||||
* May require the download of additional files.
|
||||
* May requires launching the installation of a modloader
|
||||
* @param activity any activity
|
||||
* @param zipUri URI to DocumentsUI selected zip file
|
||||
* @param modpackFile Zip file to mrpack or cf zip pack
|
||||
*/
|
||||
ModLoader importModpack(Activity activity, Uri zipUri) throws IOException, NoSuchAlgorithmException;
|
||||
ModLoader importModpack(File modpackFile) throws IOException, NoSuchAlgorithmException;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
package net.kdt.pojavlaunch.modloaders.modpacks.api;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.provider.OpenableColumns;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.kdt.mcgui.ProgressLayout;
|
||||
@@ -12,26 +7,23 @@ import com.kdt.mcgui.ProgressLayout;
|
||||
import net.kdt.pojavlaunch.R;
|
||||
import net.kdt.pojavlaunch.Tools;
|
||||
import net.kdt.pojavlaunch.modloaders.modpacks.imagecache.ModIconCache;
|
||||
import net.kdt.pojavlaunch.modloaders.modpacks.models.Constants;
|
||||
import net.kdt.pojavlaunch.modloaders.modpacks.models.ModDetail;
|
||||
import net.kdt.pojavlaunch.progresskeeper.DownloaderProgressWrapper;
|
||||
import net.kdt.pojavlaunch.utils.DownloadUtils;
|
||||
import net.kdt.pojavlaunch.utils.ZipUtils;
|
||||
import net.kdt.pojavlaunch.value.launcherprofiles.LauncherProfiles;
|
||||
import net.kdt.pojavlaunch.value.launcherprofiles.MinecraftProfile;
|
||||
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.security.DigestInputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
public class ModpackInstaller {
|
||||
|
||||
@@ -65,6 +57,7 @@ public class ModpackInstaller {
|
||||
modLoaderInfo = installFunction.installModpack(modpackFile, new File(Tools.DIR_GAME_HOME, "custom_instances/"+modpackName));
|
||||
|
||||
} finally {
|
||||
//noinspection ResultOfMethodCallIgnored It's cache, who cares
|
||||
modpackFile.delete();
|
||||
ProgressLayout.clearProgress(ProgressLayout.INSTALL_MODPACK);
|
||||
}
|
||||
@@ -86,123 +79,92 @@ public class ModpackInstaller {
|
||||
return modLoaderInfo;
|
||||
}
|
||||
|
||||
public static ModLoader importModpack(Activity activity, Uri zipUri, InstallFunction installFunction) throws IOException, NoSuchAlgorithmException {
|
||||
public static ModLoader importModpack(File modpackFile, int apiSource, InstallFunction installFunction) throws IOException, NoSuchAlgorithmException {
|
||||
ProgressLayout.setProgress(ProgressLayout.INSTALL_MODPACK, 1, R.string.import_modpack_start);
|
||||
String modrinthPackInfoFileName = "modrinth.index.json";
|
||||
String curseforgePackInfoFileName = "manifest.json";
|
||||
InputStream inputStream = activity.getContentResolver().openInputStream(zipUri);
|
||||
if (inputStream == null) throw new IOException("Can't open modpack file, try again?");
|
||||
ZipInputStream zipInputStream = new ZipInputStream(inputStream);
|
||||
ZipEntry zipEntry;
|
||||
while ((zipEntry = zipInputStream.getNextEntry()) != null) {
|
||||
boolean isModrinth = zipEntry.getName().equals(modrinthPackInfoFileName);
|
||||
boolean isCurseforge = zipEntry.getName().equals(curseforgePackInfoFileName);
|
||||
if (!(isModrinth || isCurseforge)) continue;
|
||||
// Read Manifest JSON
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(zipInputStream));
|
||||
String str;
|
||||
StringBuilder jsonString = new StringBuilder();
|
||||
while ((str = reader.readLine()) != null) {
|
||||
jsonString.append(str).append("\n");
|
||||
}
|
||||
zipInputStream.close();
|
||||
|
||||
// Hash the ZIP File
|
||||
inputStream = activity.getContentResolver().openInputStream(zipUri);
|
||||
if (inputStream == null) throw new IOException("Can't open modpack file, try again?");
|
||||
MessageDigest algorithm = MessageDigest.getInstance("SHA-1");
|
||||
DigestInputStream hashingStream = new DigestInputStream(inputStream, algorithm);
|
||||
|
||||
long fileSize = -1;
|
||||
long readSize = 0;
|
||||
try (Cursor returnCursor = activity.getContentResolver().query(zipUri, new String[]{OpenableColumns.SIZE}, null, null, null)) {
|
||||
if (returnCursor != null && returnCursor.moveToFirst()) {
|
||||
fileSize = returnCursor.getLong(0);
|
||||
}
|
||||
}
|
||||
|
||||
byte[] buffer = new byte[262144];
|
||||
while (true) {
|
||||
int n = hashingStream.read(buffer);
|
||||
if (n == -1) break;
|
||||
readSize += n;
|
||||
String readMB = fileSize > 0 ? String.format(Locale.US, "%.2f", readSize / (1024.0 * 1024.0)) : "unknown";
|
||||
String totalMB = fileSize > 0 ? String.format(Locale.US, "%.2f",fileSize / (1024.0 * 1024.0)) : "unknown";
|
||||
int progress = fileSize > 0 ? (int) ((readSize * 100L) / fileSize) : 0;
|
||||
ProgressLayout.setProgress(ProgressLayout.INSTALL_MODPACK, progress, R.string.import_modpack_hash, readMB, totalMB);
|
||||
}
|
||||
hashingStream.close();
|
||||
byte[] digest = algorithm.digest();
|
||||
StringBuilder sb = new StringBuilder(digest.length * 2);
|
||||
for (byte b : digest) {
|
||||
sb.append(String.format("%02x", b));
|
||||
}
|
||||
String hash = sb.toString();
|
||||
|
||||
ProgressLayout.setProgress(ProgressLayout.INSTALL_MODPACK, 0, R.string.import_modpack_json);
|
||||
|
||||
// Parse the JSON to prepare for instance creation
|
||||
JsonObject packInfoJson = JsonParser.parseString(jsonString.toString()).getAsJsonObject();
|
||||
String modpackName = "";
|
||||
String modpackVersion = "";
|
||||
String modpackMcVersion = "";
|
||||
if(isModrinth){
|
||||
try {
|
||||
modpackName = packInfoJson.get("name").getAsString();
|
||||
modpackVersion = packInfoJson.get("versionId").getAsString();
|
||||
modpackMcVersion = packInfoJson.get("dependencies").getAsJsonObject().get("minecraft").getAsString();
|
||||
} catch (RuntimeException ignored) {}
|
||||
} else {
|
||||
try {
|
||||
modpackName = packInfoJson.get("name").getAsString();
|
||||
modpackVersion = packInfoJson.get("version").getAsString();
|
||||
modpackMcVersion = packInfoJson.get("minecraft").getAsJsonObject().get("version").getAsString();
|
||||
} catch (RuntimeException ignored) {}
|
||||
}
|
||||
if(modpackName.isBlank() || modpackVersion.isBlank() || modpackMcVersion.isBlank()) throw new IOException("Corrupt Modpack manifest file.");
|
||||
// Added a for because there is an awkward __ that I can't be bothered to fix
|
||||
// FO only deduplication be like:
|
||||
String profileFolderName = String.join(" ", modpackName, modpackVersion, "for", modpackMcVersion, hash);
|
||||
profileFolderName = profileFolderName.trim().replaceAll("[\\\\/:*?\"<>| \\t\\n]", "_");
|
||||
|
||||
// Copy ZIP file to cache
|
||||
File modpackFile = new File(Tools.DIR_CACHE, profileFolderName + ".cf");
|
||||
inputStream = activity.getContentResolver().openInputStream(zipUri);
|
||||
if (inputStream == null) throw new IOException("Can't open modpack file, try again?");
|
||||
FileOutputStream output = new FileOutputStream(modpackFile);
|
||||
byte[] b = new byte[262144];
|
||||
int read;
|
||||
int readTotal = 0;
|
||||
while ((read = inputStream.read(b)) != -1) {
|
||||
output.write(b, 0, read);
|
||||
readTotal += read;
|
||||
String readMB = fileSize > 0 ? String.format(Locale.US, "%.2f", readTotal / (1024.0 * 1024.0)) : "unknown";
|
||||
String totalMB = fileSize > 0 ? String.format(Locale.US, "%.2f", fileSize / (1024.0 * 1024.0)) : "unknown";
|
||||
int progress = fileSize > 0 ? (int) ((readTotal * 100L) / fileSize) : 0;
|
||||
ProgressLayout.setProgress(ProgressLayout.INSTALL_MODPACK, progress, R.string.import_modpack_copy, readMB, totalMB);
|
||||
}
|
||||
output.flush();
|
||||
output.close();
|
||||
|
||||
// Install the actual pack into custom_instances
|
||||
ModLoader modLoaderInfo = installFunction.installModpack(modpackFile, new File(Tools.DIR_GAME_HOME, "custom_instances/"+profileFolderName));
|
||||
// We have to do this because installModpack doesn't clean up after itself
|
||||
ProgressLayout.clearProgress(ProgressLayout.INSTALL_MODPACK);
|
||||
modpackFile.delete();
|
||||
|
||||
// Create the instance (We don't have a picture guys)
|
||||
MinecraftProfile profile = MinecraftProfile.getDefaultProfile();
|
||||
profile.gameDir = "./custom_instances/" + profileFolderName;
|
||||
profile.name = modpackName;
|
||||
if (!modpackMcVersion.isBlank()) profile.lastVersionId = modpackMcVersion;
|
||||
if (modLoaderInfo != null && modLoaderInfo.getVersionId() != null)
|
||||
profile.lastVersionId = modLoaderInfo.getVersionId();
|
||||
LauncherProfiles.mainProfileJson.profiles.put(profileFolderName, profile);
|
||||
LauncherProfiles.write();
|
||||
|
||||
return modLoaderInfo;
|
||||
// modpackFile is deleted in LauncherActivity, no need to delete here.
|
||||
if (modpackFile == null) throw new IOException("Can't open modpack file, try again?");
|
||||
String manifestFileName;
|
||||
switch (apiSource) {
|
||||
case Constants.SOURCE_CURSEFORGE:
|
||||
manifestFileName = "manifest.json";
|
||||
break;
|
||||
case Constants.SOURCE_MODRINTH:
|
||||
manifestFileName = "modrinth.index.json";
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException("Unknown API source: " + apiSource);
|
||||
}
|
||||
throw new IOException("Can't find manifest file in modpack provided");
|
||||
// Read Manifest JSON
|
||||
JsonObject manifestFile = JsonParser.parseString(Tools.read(ZipUtils.getEntryStream(
|
||||
new ZipFile(modpackFile), manifestFileName))).getAsJsonObject();
|
||||
|
||||
// Parse the JSON to prepare for instance creation
|
||||
ProgressLayout.setProgress(ProgressLayout.INSTALL_MODPACK, 1, R.string.import_modpack_json);
|
||||
String modpackName = "";
|
||||
String modpackVersion = "";
|
||||
String modpackMcVersion = "";
|
||||
|
||||
switch (apiSource) {
|
||||
case Constants.SOURCE_CURSEFORGE:
|
||||
try {
|
||||
modpackName = manifestFile.get("name").getAsString();
|
||||
modpackVersion = manifestFile.get("version").getAsString();
|
||||
modpackMcVersion = manifestFile.get("minecraft").getAsJsonObject().get("version").getAsString();
|
||||
} catch (RuntimeException ignored) {}
|
||||
break;
|
||||
case Constants.SOURCE_MODRINTH:
|
||||
try {
|
||||
modpackName = manifestFile.get("name").getAsString();
|
||||
modpackVersion = manifestFile.get("versionId").getAsString();
|
||||
modpackMcVersion = manifestFile.get("dependencies").getAsJsonObject().get("minecraft").getAsString();
|
||||
} catch (RuntimeException ignored) {}
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException("Unknown API source: " + apiSource);
|
||||
}
|
||||
if(modpackName.isBlank() || modpackVersion.isBlank() || modpackMcVersion.isBlank()) throw new IOException("Corrupt Modpack manifest file.");
|
||||
|
||||
// Hash the ZIP File, can't use getSha1 cause progress bar
|
||||
MessageDigest algorithm = MessageDigest.getInstance("SHA-1");
|
||||
//noinspection IOStreamConstructor It will reccomend you use an API26 function like a dumb
|
||||
DigestInputStream hashingStream = new DigestInputStream(new FileInputStream(modpackFile), algorithm);
|
||||
long fileSize = modpackFile.length();
|
||||
long readSize = 0;
|
||||
byte[] buffer = new byte[262144];
|
||||
while (true) {
|
||||
int n = hashingStream.read(buffer);
|
||||
if (n == -1) break;
|
||||
readSize += n;
|
||||
String readMB = fileSize > 0 ? String.format(Locale.US, "%.2f", readSize / (1024.0 * 1024.0)) : "unknown";
|
||||
String totalMB = fileSize > 0 ? String.format(Locale.US, "%.2f",fileSize / (1024.0 * 1024.0)) : "unknown";
|
||||
int progress = fileSize > 0 ? (int) ((readSize * 100L) / fileSize) : 0;
|
||||
ProgressLayout.setProgress(ProgressLayout.INSTALL_MODPACK, progress, R.string.import_modpack_hash, readMB, totalMB);
|
||||
}
|
||||
hashingStream.close();
|
||||
byte[] digest = algorithm.digest();
|
||||
StringBuilder sb = new StringBuilder(digest.length * 2);
|
||||
for (byte b : digest) {
|
||||
sb.append(String.format("%02x", b));
|
||||
}
|
||||
String hash = sb.toString();
|
||||
String profileFolderName = String.join(" ", modpackName, modpackVersion, "for", modpackMcVersion, hash);
|
||||
profileFolderName = profileFolderName.trim().replaceAll("[\\\\/:*?\"<>| \\t\\n]", "_");
|
||||
|
||||
// Install the actual pack into custom_instances
|
||||
ModLoader modLoaderInfo = installFunction.installModpack(modpackFile, new File(Tools.DIR_GAME_HOME, "custom_instances/"+profileFolderName));
|
||||
ProgressLayout.clearProgress(ProgressLayout.INSTALL_MODPACK);
|
||||
|
||||
// Create the instance (We don't have a picture guys)
|
||||
MinecraftProfile profile = MinecraftProfile.getDefaultProfile();
|
||||
profile.gameDir = "./custom_instances/" + profileFolderName;
|
||||
profile.name = modpackName;
|
||||
if (!modpackMcVersion.isBlank()) profile.lastVersionId = modpackMcVersion;
|
||||
if (modLoaderInfo != null && modLoaderInfo.getVersionId() != null)
|
||||
profile.lastVersionId = modLoaderInfo.getVersionId();
|
||||
LauncherProfiles.mainProfileJson.profiles.put(profileFolderName, profile);
|
||||
LauncherProfiles.write();
|
||||
|
||||
return modLoaderInfo;
|
||||
}
|
||||
|
||||
interface InstallFunction {
|
||||
|
||||
@@ -160,8 +160,8 @@ public class ModrinthApi implements ModpackApi{
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModLoader importModpack(Activity activity, Uri zipUri) throws IOException, NoSuchAlgorithmException {
|
||||
return ModpackInstaller.importModpack(activity, zipUri, this::installMrpack);
|
||||
public ModLoader importModpack(File modpackFile) throws IOException, NoSuchAlgorithmException {
|
||||
return ModpackInstaller.importModpack(modpackFile, Constants.SOURCE_MODRINTH, this::installMrpack);
|
||||
}
|
||||
|
||||
private static ModLoader createInfo(ModrinthIndex modrinthIndex) {
|
||||
|
||||
Reference in New Issue
Block a user