mirror of
https://github.com/AngelAuraMC/Amethyst-Android.git
synced 2026-08-02 11:46:08 -04:00
feat: LWJGL3ify support
Now should run lwjgl3ify ootb (assuming non-debug builds, the forgePatches url is broken there, not our bug)
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
|
||||
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
|
||||
import static net.kdt.pojavlaunch.Tools.getMods;
|
||||
import static net.kdt.pojavlaunch.Tools.hasMods;
|
||||
import static net.kdt.pojavlaunch.Tools.hasNoOnlineProfileDialog;
|
||||
import static net.kdt.pojavlaunch.Tools.isOnline;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.NotificationManager;
|
||||
@@ -36,6 +39,7 @@ import net.kdt.pojavlaunch.fragments.MicrosoftLoginFragment;
|
||||
import net.kdt.pojavlaunch.fragments.SelectAuthFragment;
|
||||
import net.kdt.pojavlaunch.lifecycle.ContextAwareDoneListener;
|
||||
import net.kdt.pojavlaunch.lifecycle.ContextExecutor;
|
||||
import net.kdt.pojavlaunch.modloaders.LWJGL3ifyUtils;
|
||||
import net.kdt.pojavlaunch.modloaders.modpacks.ModloaderInstallTracker;
|
||||
import net.kdt.pojavlaunch.modloaders.modpacks.api.CommonApi;
|
||||
import net.kdt.pojavlaunch.modloaders.modpacks.api.ModLoader;
|
||||
@@ -55,10 +59,12 @@ import net.kdt.pojavlaunch.utils.NotificationUtils;
|
||||
import net.kdt.pojavlaunch.value.launcherprofiles.LauncherProfiles;
|
||||
import net.kdt.pojavlaunch.value.launcherprofiles.MinecraftProfile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.text.ParseException;
|
||||
import java.util.List;
|
||||
|
||||
public class LauncherActivity extends BaseActivity {
|
||||
public static final String SETTING_FRAGMENT_TAG = "SETTINGS_FRAGMENT";
|
||||
@@ -172,6 +178,46 @@ public class LauncherActivity extends BaseActivity {
|
||||
}
|
||||
}
|
||||
|
||||
// Override whatever version is in use and replace it with lwjgl3ify if needed
|
||||
List<File> lwjgl3ifyJars = getMods("lwjgl3ify-3");
|
||||
if (!lwjgl3ifyJars.isEmpty()) {
|
||||
if (lwjgl3ifyJars.size() > 1) {
|
||||
// "Duplicate LWJGL3ify jars found, cannot launch."
|
||||
Tools.dialogOnUiThread(this, R.string.global_error, R.string.mc_download_failed);
|
||||
return false;
|
||||
}
|
||||
|
||||
File lwjgl3ifyJar = lwjgl3ifyJars.get(0);
|
||||
|
||||
// If the version contains lwjgl3ify, its probably someone who knows what they're doing
|
||||
// so lets leave that alone
|
||||
if (!prof.lastVersionId.toLowerCase().contains("lwjgl3ify")) {
|
||||
try {
|
||||
prof.lastVersionId = LWJGL3ifyUtils.installJson(lwjgl3ifyJar).id;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
LauncherProfiles.mainProfileJson.profiles.put(selectedProfile, prof);
|
||||
LauncherProfiles.write();
|
||||
|
||||
|
||||
}
|
||||
// We just installed a json, we need internet + online acc to download so we add super
|
||||
// basic detection whether lwjgl3ify assets were downloaded
|
||||
try {
|
||||
String jsonPath = LWJGL3ifyUtils.getJsonPath(LWJGL3ifyUtils.getProfileID(lwjgl3ifyJar));
|
||||
File lwjgl3ifyClientJar = new File(jsonPath.replace(".json", ".jar"));
|
||||
if (!lwjgl3ifyClientJar.exists()){
|
||||
if (mAccountSpinner.getSelectedAccount().isLocal() || !isOnline(this)){
|
||||
Tools.dialogOnUiThread(this, R.string.global_error, R.string.mc_download_failed);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
new MinecraftDownloader().start(
|
||||
this,
|
||||
mcVersion,
|
||||
|
||||
@@ -280,15 +280,30 @@ public final class Tools {
|
||||
* @return Whether or not the .jar is found
|
||||
*/
|
||||
public static boolean hasMods(String... filenames) {
|
||||
return !getMods(filenames).isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for mod in mods directory of current selected profile
|
||||
* Not case-sensitive
|
||||
* @param filenames Filename(s) of the .jar mod(s)
|
||||
* @return The found mods
|
||||
*/
|
||||
public static List<File> getMods(String... filenames) {
|
||||
File gameDir = getGameDir();
|
||||
File modsDir = new File(gameDir, "mods");
|
||||
File[] modFiles = modsDir.listFiles(file -> file.isFile() && file.getName().endsWith(".jar"));
|
||||
if (modFiles == null) return false;
|
||||
File[] modFiles = modsDir.listFiles(file -> file.isFile() && file.getName().toLowerCase().endsWith(".jar"));
|
||||
if (modFiles == null) return new ArrayList<>();
|
||||
List<File> foundModFiles = new ArrayList<>();
|
||||
for (File file : modFiles) {
|
||||
for (String filename : filenames)
|
||||
if (file.getName().toLowerCase().contains(filename.toLowerCase())) return true;
|
||||
if (file.getName().toLowerCase().contains(filename.toLowerCase()) &&
|
||||
file.getName().toLowerCase().endsWith(".jar")) {
|
||||
foundModFiles.add(file);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return foundModFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
package net.kdt.pojavlaunch.fragments;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.widget.ExpandableListAdapter;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import net.kdt.pojavlaunch.R;
|
||||
import net.kdt.pojavlaunch.modloaders.LWJGL3ifyDownloadTask;
|
||||
import net.kdt.pojavlaunch.modloaders.LWJGL3ifyUtils;
|
||||
import net.kdt.pojavlaunch.modloaders.LWJGL3ifyVersionListAdapter;
|
||||
import net.kdt.pojavlaunch.modloaders.ModloaderListenerProxy;
|
||||
import net.kdt.pojavlaunch.modloaders.modpacks.api.CommonApi;
|
||||
import net.kdt.pojavlaunch.modloaders.modpacks.api.ModpackApi;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class LWJGL3ifyInstallFragment extends ModVersionListFragment<LWJGL3ifyUtils.LWJGL3ifyVersionList>{
|
||||
public static final String TAG = "LWJGL3ifyInstallFragment";
|
||||
private ModpackApi modpackApi;
|
||||
|
||||
@Override
|
||||
public void onAttach(@NonNull Context context) {
|
||||
super.onAttach(context);
|
||||
modpackApi = new CommonApi(context.getString(R.string.curseforge_api_key));
|
||||
}
|
||||
public LWJGL3ifyInstallFragment() {
|
||||
super(TAG);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public int getTitleText() {
|
||||
return R.string.select_lwjgl3ify_version;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public int getNoDataMsg() {
|
||||
return R.string.modloader_dl_failed_to_load_list;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
public LWJGL3ifyUtils.LWJGL3ifyVersionList loadVersionList() throws IOException {
|
||||
return LWJGL3ifyUtils.getLWJGL3ifyVersionList(modpackApi);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param versionList
|
||||
* @param layoutInflater
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public ExpandableListAdapter createAdapter(LWJGL3ifyUtils.LWJGL3ifyVersionList versionList, LayoutInflater layoutInflater) {
|
||||
return new LWJGL3ifyVersionListAdapter(versionList, layoutInflater);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param selectedVersion
|
||||
* @param listenerProxy
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Runnable createDownloadTask(Object selectedVersion, ModloaderListenerProxy listenerProxy) {
|
||||
return new LWJGL3ifyDownloadTask(listenerProxy, (LWJGL3ifyUtils.LWJGL3ifyMod) selectedVersion, requireActivity());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param context
|
||||
* @param downloadedFile
|
||||
*/
|
||||
@Override
|
||||
public void onDownloadFinished(Context context, File downloadedFile) {
|
||||
// Nothing to do.
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.kdt.pojavlaunch.fragments;
|
||||
|
||||
import static net.kdt.pojavlaunch.Tools.dialogOnUiThread;
|
||||
import static net.kdt.pojavlaunch.Tools.hasMods;
|
||||
import static net.kdt.pojavlaunch.Tools.hasNoOnlineProfileDialog;
|
||||
import static net.kdt.pojavlaunch.Tools.hasOnlineProfile;
|
||||
import static net.kdt.pojavlaunch.Tools.openPath;
|
||||
@@ -27,12 +28,14 @@ import net.kdt.pojavlaunch.R;
|
||||
import net.kdt.pojavlaunch.Tools;
|
||||
import net.kdt.pojavlaunch.extra.ExtraConstants;
|
||||
import net.kdt.pojavlaunch.extra.ExtraCore;
|
||||
import net.kdt.pojavlaunch.modloaders.LWJGL3ifyUtils;
|
||||
import net.kdt.pojavlaunch.prefs.LauncherPreferences;
|
||||
import net.kdt.pojavlaunch.progresskeeper.ProgressKeeper;
|
||||
import net.kdt.pojavlaunch.value.launcherprofiles.LauncherProfiles;
|
||||
import net.kdt.pojavlaunch.value.launcherprofiles.MinecraftProfile;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
public class MainMenuFragment extends Fragment {
|
||||
public static final String TAG = "MainMenuFragment";
|
||||
@@ -80,8 +83,6 @@ public class MainMenuFragment extends Fragment {
|
||||
.create();
|
||||
sodiumWarningDialog.show();
|
||||
} else ExtraCore.setValue(ExtraConstants.LAUNCH_GAME, true);
|
||||
|
||||
|
||||
});
|
||||
|
||||
mShareLogsButton.setOnClickListener((v) -> shareLog(requireContext()));
|
||||
|
||||
@@ -43,6 +43,8 @@ public class ProfileTypeSelectFragment extends Fragment {
|
||||
tryInstall(NeoForgeInstallFragment.class, NeoForgeInstallFragment.TAG));
|
||||
view.findViewById(R.id.modded_profile_modpack).setOnClickListener((v)->
|
||||
tryInstall(ModpackCreateFragment.class, ModpackCreateFragment.TAG));
|
||||
view.findViewById(R.id.modded_profile_lwjgl3ify).setOnClickListener((v)->
|
||||
tryInstall(LWJGL3ifyInstallFragment.class, LWJGL3ifyInstallFragment.TAG));
|
||||
view.findViewById(R.id.modded_profile_quilt).setOnClickListener((v)->
|
||||
tryInstall(QuiltInstallFragment.class, QuiltInstallFragment.TAG));
|
||||
view.findViewById(R.id.modded_profile_bta).setOnClickListener((v)->
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
package net.kdt.pojavlaunch.modloaders;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import com.kdt.mcgui.ProgressLayout;
|
||||
|
||||
import net.kdt.pojavlaunch.R;
|
||||
import net.kdt.pojavlaunch.Tools;
|
||||
import net.kdt.pojavlaunch.modloaders.modpacks.api.CommonApi;
|
||||
import net.kdt.pojavlaunch.progresskeeper.ProgressKeeper;
|
||||
import net.kdt.pojavlaunch.tasks.AsyncMinecraftDownloader;
|
||||
import net.kdt.pojavlaunch.tasks.MinecraftDownloader;
|
||||
import net.kdt.pojavlaunch.utils.DownloadUtils;
|
||||
import net.kdt.pojavlaunch.value.launcherprofiles.LauncherProfiles;
|
||||
import net.kdt.pojavlaunch.value.launcherprofiles.MinecraftProfile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.security.DigestInputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class LWJGL3ifyDownloadTask implements Runnable, Tools.DownloaderFeedback, AsyncMinecraftDownloader.DoneListener {
|
||||
protected static final String TAG = "LWJGL3ifyDownloadTask";
|
||||
private final ModloaderDownloadListener mListener;
|
||||
private final LWJGL3ifyUtils.LWJGL3ifyMod mLWJGL3ifyMod;
|
||||
private final Activity mActivity;
|
||||
|
||||
public LWJGL3ifyDownloadTask(ModloaderDownloadListener mListener, LWJGL3ifyUtils.LWJGL3ifyMod mLWJGL3ifyMod, Activity activity) {
|
||||
this.mListener = mListener;
|
||||
this.mLWJGL3ifyMod = mLWJGL3ifyMod;
|
||||
this.mActivity = activity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
ProgressKeeper.submitProgress(ProgressLayout.INSTALL_MODPACK, 0, R.string.fabric_dl_progress, "BTA");
|
||||
try {
|
||||
runCatching();
|
||||
mListener.onDownloadFinished(null);
|
||||
}catch (Exception e) {
|
||||
mListener.onDownloadError(e);
|
||||
}finally {
|
||||
ProgressLayout.clearProgress(ProgressLayout.INSTALL_MODPACK);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private File tryDownloadModJar() throws IOException {
|
||||
try {
|
||||
File jarFile = new File(Tools.DIR_CACHE, "lwjgl3ify-jars/lwjgl3ify-"+ mLWJGL3ifyMod.versionName+".jar");
|
||||
if (!(jarFile.exists() && Objects.equals(getSha1(jarFile), mLWJGL3ifyMod.hash)))
|
||||
DownloadUtils.downloadFileMonitored(
|
||||
mLWJGL3ifyMod.downloadUrl,
|
||||
jarFile,
|
||||
new byte[8192],
|
||||
this
|
||||
);
|
||||
return jarFile;
|
||||
} catch (IOException | NoSuchAlgorithmException e) {
|
||||
throw new IOException("Unable to download LWJGL3ify from " + mLWJGL3ifyMod.downloadUrl, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void tryDownloadDeps(File modsDir) throws IOException {
|
||||
List<LWJGL3ifyUtils.LWJGL3ifyMod> deps = LWJGL3ifyUtils.collectDependencies(mLWJGL3ifyMod, new CommonApi(mActivity.getString(R.string.curseforge_api_key)));
|
||||
for (int i=0; i < deps.size(); ++i) {
|
||||
URI uri = null;
|
||||
try {
|
||||
uri = new URI(deps.get(i).downloadUrl);
|
||||
} catch (URISyntaxException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
String path = uri.getPath();
|
||||
String fileName = new File(path).getName();
|
||||
try {
|
||||
DownloadUtils.downloadFileMonitored(
|
||||
deps.get(i).downloadUrl,
|
||||
new File(modsDir, fileName),
|
||||
new byte[8192],
|
||||
this
|
||||
);
|
||||
} catch (IOException e) {
|
||||
throw new IOException("Unable to download"+deps.get(i).versionName+" from " + deps.get(i).downloadUrl, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getSha1(File file) throws IOException, NoSuchAlgorithmException {
|
||||
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(file), algorithm);
|
||||
byte[] buffer = new byte[8192];
|
||||
while (hashingStream.read(buffer) != -1) {} // just read to update the digest
|
||||
hashingStream.close();
|
||||
byte[] digest = algorithm.digest();
|
||||
StringBuilder sb = new StringBuilder(digest.length * 2);
|
||||
for (byte b : digest) {
|
||||
sb.append(String.format("%02x", b));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public void runCatching() throws IOException {
|
||||
File modJar = tryDownloadModJar();
|
||||
// This cannot be allowed to match the mod.jar ID otherwise conflicts occur and GLFW input breaks
|
||||
String LWJGL3ifyProfileID = LWJGL3ifyUtils.getProfileID(modJar);
|
||||
if (!modJar.exists()) throw new IOException("Failed to download LWJGL3ify "+ mLWJGL3ifyMod.versionName);
|
||||
MinecraftProfile profile = LWJGL3ifyUtils.createProfile(LWJGL3ifyProfileID, mLWJGL3ifyMod.versionName, mLWJGL3ifyMod.iconUrl);
|
||||
new MinecraftDownloader().start(mActivity, LWJGL3ifyUtils.installJson(modJar), LWJGL3ifyProfileID, this);
|
||||
LWJGL3ifyUtils.createInstance(profile, modJar, mLWJGL3ifyMod.versionName);
|
||||
tryDownloadDeps(new File(Tools.DIR_GAME_HOME, profile.gameDir+"/mods"));
|
||||
|
||||
LauncherProfiles.load();
|
||||
LauncherProfiles.insertMinecraftProfile(profile);
|
||||
LauncherProfiles.write();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateProgress(int curr, int max) {
|
||||
int progress100 = (int)(((float)curr / (float)max)*100f);
|
||||
ProgressKeeper.submitProgress(ProgressLayout.INSTALL_MODPACK, progress100, R.string.of_dl_progress, mLWJGL3ifyMod.versionName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDownloadDone() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDownloadFailed(Throwable throwable) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,274 @@
|
||||
package net.kdt.pojavlaunch.modloaders;
|
||||
|
||||
import android.util.Base64;
|
||||
import android.util.Base64OutputStream;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import net.kdt.pojavlaunch.JMinecraftVersionList;
|
||||
import net.kdt.pojavlaunch.Tools;
|
||||
import net.kdt.pojavlaunch.modloaders.modpacks.api.ModpackApi;
|
||||
import net.kdt.pojavlaunch.modloaders.modpacks.models.Constants;
|
||||
import net.kdt.pojavlaunch.modloaders.modpacks.models.ModDetail;
|
||||
import net.kdt.pojavlaunch.modloaders.modpacks.models.ModItem;
|
||||
import net.kdt.pojavlaunch.utils.DownloadUtils;
|
||||
import net.kdt.pojavlaunch.utils.FileUtils;
|
||||
import net.kdt.pojavlaunch.utils.ZipUtils;
|
||||
import net.kdt.pojavlaunch.value.launcherprofiles.MinecraftProfile;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
public class LWJGL3ifyUtils {
|
||||
public static LWJGL3ifyVersionList getLWJGL3ifyVersionList(ModpackApi modpackApi) throws IOException {
|
||||
ModDetail lwjgl3ifyModDetail = getLWJGL3ifyModDetail(modpackApi);
|
||||
List<LWJGL3ifyMod> supportedVersions = new ArrayList<>(), brokenVersions = new ArrayList<>();
|
||||
for (int i = 0; i < lwjgl3ifyModDetail.versionNames.length; i++) {
|
||||
String normalizedVersion = normalizeVersionName(lwjgl3ifyModDetail.versionNames[i], lwjgl3ifyModDetail.apiSource);
|
||||
// boolean isSupportedVersion = Integer.parseInt(normalizedVersion.split("\\.")[0]) < 3;
|
||||
|
||||
LWJGL3ifyMod version = new LWJGL3ifyMod(
|
||||
normalizedVersion,
|
||||
lwjgl3ifyModDetail.versionUrls[i],
|
||||
lwjgl3ifyModDetail.imageUrl,
|
||||
lwjgl3ifyModDetail.id,
|
||||
lwjgl3ifyModDetail.versionHashes[i],
|
||||
lwjgl3ifyModDetail.dependencies[i]
|
||||
);
|
||||
// It's fixed, probably.
|
||||
// // LWJGL3ify 3.x uses SDL which needs to be fixed first
|
||||
// (isSupportedVersion ? supportedVersions : brokenVersions).add(version);
|
||||
supportedVersions.add(version);
|
||||
|
||||
}
|
||||
return new LWJGL3ifyVersionList(supportedVersions, brokenVersions);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param jarName LWJGL3ify jar name, the same as Curseforge {@code versionNames} (ex. {@code 3.0.16}, {@code 2.1.18})
|
||||
* @param source Either {@link Constants#SOURCE_MODRINTH} or {@link Constants#SOURCE_CURSEFORGE}
|
||||
* @return Filled out {@link LWJGL3ifyMod} corresponding to version provided
|
||||
* @throws IllegalArgumentException If LWJGL3ify version was not found in the source provided
|
||||
* @throws IOException If provided source is not what was expected
|
||||
*/
|
||||
public static LWJGL3ifyMod getLWJGL3ifyVersion(String jarName, ModpackApi source) throws IOException {
|
||||
// This is a hack but it should work
|
||||
String providedNormalizedVersion = normalizeVersionName(jarName, Constants.SOURCE_CURSEFORGE);
|
||||
ModDetail lwjgl3ifyModDetail = getLWJGL3ifyModDetail(source);
|
||||
for (int i = 0; i < lwjgl3ifyModDetail.versionNames.length; i++) {
|
||||
String normalizedVersion = normalizeVersionName(lwjgl3ifyModDetail.versionNames[i], lwjgl3ifyModDetail.apiSource);
|
||||
if (providedNormalizedVersion.equals(normalizedVersion))
|
||||
return new LWJGL3ifyMod(
|
||||
providedNormalizedVersion,
|
||||
lwjgl3ifyModDetail.versionUrls[i],
|
||||
lwjgl3ifyModDetail.imageUrl,
|
||||
lwjgl3ifyModDetail.id,
|
||||
lwjgl3ifyModDetail.versionHashes[i],
|
||||
lwjgl3ifyModDetail.dependencies[i]
|
||||
);
|
||||
}
|
||||
String sourceName = (lwjgl3ifyModDetail.apiSource == Constants.SOURCE_MODRINTH) ? "Modrinth" : "Curseforge";
|
||||
throw new IllegalArgumentException("Cannot find LWJGL3ify version "+providedNormalizedVersion+" from "+sourceName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Flat list of all dependencies needed by {@code lwjgl3ifyMod}.
|
||||
*/
|
||||
public static List<LWJGL3ifyMod> collectDependencies(LWJGL3ifyMod lwjgl3ifyMod, ModpackApi modpackApi) {
|
||||
List<LWJGL3ifyMod> allDeps = new ArrayList<>();
|
||||
for (ModDetail.Dependencies dep : lwjgl3ifyMod.dependencies) {
|
||||
ModDetail detail = getModDetail(modpackApi, dep.project_id);
|
||||
if (detail != null) {
|
||||
LWJGL3ifyMod newMod = new LWJGL3ifyMod(
|
||||
detail.versionNames[0],
|
||||
detail.versionUrls[0],
|
||||
detail.imageUrl,
|
||||
detail.id,
|
||||
detail.versionHashes[0],
|
||||
detail.dependencies[0]
|
||||
);
|
||||
|
||||
allDeps.add(newMod);
|
||||
// omg recursion!?!?!
|
||||
allDeps.addAll(collectDependencies(newMod, modpackApi));
|
||||
}
|
||||
}
|
||||
return allDeps;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static String normalizeVersionName(String versionName, int apiSource) {
|
||||
if (apiSource == Constants.SOURCE_MODRINTH) { // Ex. 3.0.16 - 1.7.10
|
||||
versionName = versionName.replaceAll(" - .*", "");
|
||||
}else if (apiSource == Constants.SOURCE_CURSEFORGE) { // Ex. lwjgl3ify-3.0.16.jar - 1.7.10
|
||||
versionName = versionName.split("-")[1].replace(".jar", "");
|
||||
}else throw new IllegalArgumentException("LWJGL3ify is only available on Modrinth or Curseforge!");
|
||||
return versionName;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static ModDetail getModDetail(ModpackApi modpackApi, String id){
|
||||
ModDetail modDetail = null;
|
||||
try {
|
||||
// Modrinth is more complete in this context. Curseforge is missing some releases.
|
||||
if (id != null && !id.isEmpty()) {
|
||||
modDetail = fetch(modpackApi, Constants.SOURCE_MODRINTH, id);
|
||||
}
|
||||
if (modDetail == null && id != null && !id.isEmpty()) {
|
||||
Integer.parseInt(id); // Triggers exception, skipping call to CF if provided id isn't int
|
||||
modDetail = fetch(modpackApi, Constants.SOURCE_CURSEFORGE, id);
|
||||
}
|
||||
} catch (NumberFormatException ignored) {}
|
||||
return modDetail;
|
||||
}
|
||||
|
||||
private static ModDetail fetch(ModpackApi modpackApi, int source, String id) {
|
||||
ModItem item = new ModItem(source, false, id, null, null, null);
|
||||
return modpackApi.getModDetails(item);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static ModDetail getLWJGL3ifyModDetail(ModpackApi modpackApi) throws IOException {
|
||||
ModDetail lwjgl3ifyModDetail = getModDetail(modpackApi, "lwjgl3ify");
|
||||
if (lwjgl3ifyModDetail == null) // Hardcoded ID is a bad idea, but it'll work well enough
|
||||
lwjgl3ifyModDetail = getModDetail(modpackApi, "998880");
|
||||
if (lwjgl3ifyModDetail == null) throw new IOException("Unable to fetch LWJGL3ify version list from Curseforge and Modrinth. " +
|
||||
"Please check your internet connection and whether Modrinth and Curseforge are accessible.");
|
||||
return lwjgl3ifyModDetail;
|
||||
}
|
||||
|
||||
public static JMinecraftVersionList.Version installJson(File modJar) throws IOException {
|
||||
String profileID = getProfileID(modJar);
|
||||
String jsonPath = getJsonPath(profileID);
|
||||
try {
|
||||
JMinecraftVersionList.Version version = Tools.GLOBAL_GSON.fromJson(
|
||||
Tools.read(
|
||||
ZipUtils.getEntryStream(
|
||||
new ZipFile(modJar),
|
||||
"me/eigenraven/lwjgl3ify/relauncher/version.json"
|
||||
)
|
||||
),
|
||||
JMinecraftVersionList.Version.class);
|
||||
version.id = profileID;
|
||||
if (!org.apache.commons.io.FileUtils.getFile(jsonPath).exists())
|
||||
Tools.write(jsonPath, Tools.GLOBAL_GSON.toJson(version));
|
||||
return version;
|
||||
} catch (IOException e) {
|
||||
throw new IOException("Failed to install "+profileID+" json file.");
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static String getJsonPath(String profileID) {
|
||||
return Tools.DIR_HOME_VERSION + "/" + profileID + "/" + profileID + ".json";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static String getProfileID(File modJar) throws IOException {
|
||||
return "1.7.10-LWJGL3ify-"+getVersionFromJar(modJar);
|
||||
}
|
||||
|
||||
public static String getVersionFromJar(File modJar) throws IOException {
|
||||
try (ZipFile zipFile = new ZipFile(modJar)) {
|
||||
JsonObject root = Tools.GLOBAL_GSON.fromJson(
|
||||
Tools.read(ZipUtils.getEntryStream(zipFile, "mcmod.info")),
|
||||
JsonObject.class);
|
||||
return root.getAsJsonArray("modList")
|
||||
.get(0).getAsJsonObject()
|
||||
.get("version").getAsString();
|
||||
}
|
||||
}
|
||||
|
||||
public static void createInstance(MinecraftProfile profile, File modJar, String versionName) throws IOException {
|
||||
File modsDir = new File(Tools.DIR_GAME_HOME, profile.gameDir+"/mods");
|
||||
if (modsDir.isFile()) {
|
||||
if (!modsDir.delete()) {
|
||||
throw new IOException("Failed to delete file where directory should be: " + modsDir.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
try {
|
||||
FileUtils.ensureDirectory(modsDir);
|
||||
} catch (IOException e) {
|
||||
throw new IOException("Failed to create folder " + modsDir.getAbsolutePath());
|
||||
}
|
||||
// Copy downloaded cached mod jar
|
||||
try (FileInputStream fis = new FileInputStream(modJar);
|
||||
FileOutputStream fos = new FileOutputStream(new File(modsDir, "lwjgl3ify-"+ versionName+".jar"))) {
|
||||
byte[] buffer = new byte[8192];
|
||||
int length;
|
||||
while ((length = fis.read(buffer)) > 0) {
|
||||
fos.write(buffer, 0, length);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static MinecraftProfile createProfile(String profileID, String versionName, String iconUrl) {
|
||||
MinecraftProfile LWJGL3ifyProfile = new MinecraftProfile();
|
||||
LWJGL3ifyProfile.lastVersionId = profileID;
|
||||
LWJGL3ifyProfile.name = "LWJGL3ify - "+ versionName;
|
||||
LWJGL3ifyProfile.gameDir = String.format("./custom_instances/LWJGL3ify_%s", versionName);
|
||||
LWJGL3ifyProfile.icon = tryDownloadIcon(iconUrl);
|
||||
return LWJGL3ifyProfile;
|
||||
}
|
||||
|
||||
public static String tryDownloadIcon(String iconUrl) {
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
try (Base64OutputStream base64OutputStream = new Base64OutputStream(byteArrayOutputStream, Base64.DEFAULT)){
|
||||
// Instead of appending and wasting memory with a StringBuilder, just write the prefix
|
||||
// to the stream before the base64 icon data.
|
||||
byteArrayOutputStream.write("data:image/png;base64,".getBytes(StandardCharsets.US_ASCII));
|
||||
DownloadUtils.download(iconUrl, base64OutputStream);
|
||||
return new String(byteArrayOutputStream.toByteArray(), StandardCharsets.US_ASCII);
|
||||
}catch (IOException e) {
|
||||
Log.w(LWJGL3ifyDownloadTask.TAG, "Failed to download base64 icon", e);
|
||||
}finally {
|
||||
try {
|
||||
byteArrayOutputStream.close();
|
||||
} catch (IOException e) {
|
||||
Log.wtf(LWJGL3ifyDownloadTask.TAG, "Failed to close a byte array stream??", e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO: Turn this into a generic ModItem class for general mods and refactor that crusty modpack naming scheme
|
||||
public static class LWJGL3ifyMod {
|
||||
public final String versionName;
|
||||
public final String downloadUrl;
|
||||
public final String iconUrl;
|
||||
public final String id;
|
||||
public final String hash;
|
||||
public final ModDetail.Dependencies[] dependencies;
|
||||
|
||||
public LWJGL3ifyMod(String versionName, String downloadUrl, String iconUrl, String id, String hash, ModDetail.Dependencies[] dependencies) {
|
||||
this.versionName = versionName;
|
||||
this.downloadUrl = downloadUrl;
|
||||
this.iconUrl = iconUrl;
|
||||
this.id = id;
|
||||
this.hash = hash;
|
||||
this.dependencies = dependencies;
|
||||
}
|
||||
}
|
||||
public static class LWJGL3ifyVersionList {
|
||||
public final List<LWJGL3ifyMod> supportedVersions;
|
||||
public final List<LWJGL3ifyMod> brokenVersions; // SDL versions for now
|
||||
|
||||
public LWJGL3ifyVersionList(List<LWJGL3ifyMod> mSupportedVersions, List<LWJGL3ifyMod> mBrokenVersions) {
|
||||
this.supportedVersions = mSupportedVersions;
|
||||
this.brokenVersions = mBrokenVersions;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package net.kdt.pojavlaunch.modloaders;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseExpandableListAdapter;
|
||||
import android.widget.ExpandableListAdapter;
|
||||
import android.widget.TextView;
|
||||
|
||||
import net.kdt.pojavlaunch.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class LWJGL3ifyVersionListAdapter extends BaseExpandableListAdapter implements ExpandableListAdapter {
|
||||
private final LayoutInflater mLayoutInflater;
|
||||
private final ArrayList<String> mGroupNames;
|
||||
private final ArrayList<List<LWJGL3ifyUtils.LWJGL3ifyMod>> mGroups;
|
||||
|
||||
public LWJGL3ifyVersionListAdapter(LWJGL3ifyUtils.LWJGL3ifyVersionList versionList, LayoutInflater mLayoutInflater) {
|
||||
this.mLayoutInflater = mLayoutInflater;
|
||||
Context context = mLayoutInflater.getContext();
|
||||
mGroupNames = new ArrayList<>(2);
|
||||
mGroups = new ArrayList<>(2);
|
||||
if(!versionList.supportedVersions.isEmpty()) {
|
||||
mGroupNames.add(context.getString(R.string.lwjgl3ify_installer_available_versions));
|
||||
mGroups.add(versionList.supportedVersions);
|
||||
}
|
||||
if(!versionList.brokenVersions.isEmpty()) {
|
||||
mGroupNames.add(context.getString(R.string.lwjgl3ify_installer_broken_versions));
|
||||
mGroups.add(versionList.brokenVersions);
|
||||
}
|
||||
mGroupNames.trimToSize();
|
||||
mGroups.trimToSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getGroupCount() {
|
||||
return mGroups.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChildrenCount(int i) {
|
||||
return mGroups.get(i).size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getGroup(int i) {
|
||||
return mGroupNames.get(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LWJGL3ifyUtils.LWJGL3ifyMod getChild(int i, int i1) {
|
||||
return mGroups.get(i).get(i1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getGroupId(int i) {
|
||||
return i;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getChildId(int i, int i1) {
|
||||
return i1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasStableIds() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getGroupView(int i, boolean b, View convertView, ViewGroup viewGroup) {
|
||||
if(convertView == null)
|
||||
convertView = mLayoutInflater.inflate(android.R.layout.simple_expandable_list_item_1, viewGroup, false);
|
||||
|
||||
((TextView) convertView).setText((String)getGroup(i));
|
||||
|
||||
return convertView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getChildView(int i, int i1, boolean b, View convertView, ViewGroup viewGroup) {
|
||||
if(convertView == null)
|
||||
convertView = mLayoutInflater.inflate(android.R.layout.simple_expandable_list_item_1, viewGroup, false);
|
||||
((TextView) convertView).setText(getChild(i,i1).versionName);
|
||||
return convertView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChildSelectable(int i, int i1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -311,7 +311,8 @@ public class JREUtils {
|
||||
// Has to run after SDL env vars are set
|
||||
try {
|
||||
Os.setenv("SDL_OPENGL_LIBRARY", graphicsLib, true);
|
||||
Os.setenv("SDL_EGL_LIBRARY", NATIVE_LIB_DIR+"/"+Os.getenv("POJAVEXEC_EGL"), true);
|
||||
if (Os.getenv("POJAVEXEC_EGL") != null)
|
||||
Os.setenv("SDL_EGL_LIBRARY", NATIVE_LIB_DIR+"/"+Os.getenv("POJAVEXEC_EGL"), true);
|
||||
} catch (ErrnoException e) {
|
||||
Log.wtf("RENDER_LIBRARY", "Failed to load set SDL env vars");
|
||||
}
|
||||
|
||||
@@ -119,6 +119,14 @@
|
||||
android:layout_marginTop="@dimen/padding_large"
|
||||
android:text="@string/modpack_install_button" />
|
||||
|
||||
<com.kdt.mcgui.MineButton
|
||||
android:id="@+id/modded_profile_lwjgl3ify"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="@dimen/padding_large"
|
||||
android:layout_marginTop="@dimen/padding_large"
|
||||
android:text="@string/create_lwjgl3ify_profile" />
|
||||
|
||||
<com.kdt.mcgui.MineButton
|
||||
android:id="@+id/modded_profile_bta"
|
||||
android:layout_width="match_parent"
|
||||
|
||||
@@ -508,5 +508,9 @@
|
||||
<string name="error_key_unsupported">Error! The key assigned to this button is invalid. Did you try updating?</string>
|
||||
<string name="error_invalid_value">Error! Invalid value!</string>
|
||||
<string name="minecraft_no_username_set">Your Minecraft username is not set! You must set it in the Minecraft website before being able to log in!</string>
|
||||
<string name="create_lwjgl3ify_profile">Create LWJGL3ify profile</string>
|
||||
<string name="select_lwjgl3ify_version">Select LWJGL3ify version</string>
|
||||
<string name="lwjgl3ify_installer_available_versions">Supported LWJGL3IFY versions</string>
|
||||
<string name="lwjgl3ify_installer_broken_versions">Broken LWJGL3ify versions (SDL)</string>
|
||||
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user