mirror of
https://github.com/AngelAuraMC/Amethyst-Android.git
synced 2025-09-12 14:16:58 -04:00
Feat[launcher]: add support for the "Better than Adventure!" mod
This commit is contained in:
parent
3d256a29e4
commit
ee3435d52a
@ -327,7 +327,7 @@ public final class Tools {
|
||||
}
|
||||
javaArgList.addAll(Arrays.asList(getMinecraftJVMArgs(versionId, gamedir)));
|
||||
javaArgList.add("-cp");
|
||||
javaArgList.add(getLWJGL3ClassPath() + ":" + launchClassPath);
|
||||
javaArgList.add(launchClassPath + ":" + getLWJGL3ClassPath());
|
||||
|
||||
javaArgList.add(versionInfo.mainClass);
|
||||
javaArgList.addAll(Arrays.asList(launchArgs));
|
||||
|
@ -0,0 +1,57 @@
|
||||
package net.kdt.pojavlaunch.fragments;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.widget.ExpandableListAdapter;
|
||||
|
||||
import net.kdt.pojavlaunch.R;
|
||||
import net.kdt.pojavlaunch.modloaders.BTADownloadTask;
|
||||
import net.kdt.pojavlaunch.modloaders.BTAUtils;
|
||||
import net.kdt.pojavlaunch.modloaders.BTAVersionListAdapter;
|
||||
import net.kdt.pojavlaunch.modloaders.ModloaderListenerProxy;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class BTAInstallFragment extends ModVersionListFragment<BTAUtils.BTAVersionList> {
|
||||
private static ModloaderListenerProxy sTaskProxy;
|
||||
@Override
|
||||
public int getTitleText() {
|
||||
return R.string.select_bta_version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNoDataMsg() {
|
||||
return R.string.modloader_dl_failed_to_load_list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModloaderListenerProxy getTaskProxy() {
|
||||
return sTaskProxy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BTAUtils.BTAVersionList loadVersionList() throws IOException {
|
||||
return BTAUtils.downloadVersionList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTaskProxy(ModloaderListenerProxy proxy) {
|
||||
sTaskProxy = proxy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpandableListAdapter createAdapter(BTAUtils.BTAVersionList versionList, LayoutInflater layoutInflater) {
|
||||
return new BTAVersionListAdapter(versionList, layoutInflater);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Runnable createDownloadTask(Object selectedVersion, ModloaderListenerProxy listenerProxy) {
|
||||
return new BTADownloadTask(listenerProxy, (BTAUtils.BTAVersion) selectedVersion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDownloadFinished(Context context, File downloadedFile) {
|
||||
// We don't have to do anything after the BTADownloadTask ends, so this is a stub
|
||||
}
|
||||
}
|
@ -35,5 +35,7 @@ public class ProfileTypeSelectFragment extends Fragment {
|
||||
Tools.swapFragment(requireActivity(), SearchModFragment.class, SearchModFragment.TAG, null));
|
||||
view.findViewById(R.id.modded_profile_quilt).setOnClickListener((v)->
|
||||
Tools.swapFragment(requireActivity(), QuiltInstallFragment.class, QuiltInstallFragment.TAG, null));
|
||||
view.findViewById(R.id.modded_profile_bta).setOnClickListener((v)->
|
||||
Tools.swapFragment(requireActivity(), BTAInstallFragment.class, BTAInstallFragment.TAG, null));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,97 @@
|
||||
package net.kdt.pojavlaunch.modloaders;
|
||||
|
||||
import android.util.Base64;
|
||||
import android.util.Base64OutputStream;
|
||||
import android.util.Log;
|
||||
|
||||
import com.kdt.mcgui.ProgressLayout;
|
||||
|
||||
import net.kdt.pojavlaunch.R;
|
||||
import net.kdt.pojavlaunch.Tools;
|
||||
import net.kdt.pojavlaunch.progresskeeper.ProgressKeeper;
|
||||
import net.kdt.pojavlaunch.utils.DownloadUtils;
|
||||
import net.kdt.pojavlaunch.utils.FileUtils;
|
||||
import net.kdt.pojavlaunch.value.launcherprofiles.LauncherProfiles;
|
||||
import net.kdt.pojavlaunch.value.launcherprofiles.MinecraftProfile;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class BTADownloadTask implements Runnable {
|
||||
private static final String BASE_JSON = "{\"inheritsFrom\":\"b1.7.3\",\"mainClass\":\"net.minecraft.client.Minecraft\",\"libraries\":[{\"name\":\"bta-client:bta-client:%1$s\",\"downloads\":{\"artifact\":{\"path\":\"bta-client/bta-client-%1$s.jar\",\"url\":\"%2$s\"}}}],\"id\":\"%3$s\"}";
|
||||
private final ModloaderDownloadListener mListener;
|
||||
private final BTAUtils.BTAVersion mBtaVersion;
|
||||
|
||||
public BTADownloadTask(ModloaderDownloadListener mListener, BTAUtils.BTAVersion mBtaVersion) {
|
||||
this.mListener = mListener;
|
||||
this.mBtaVersion = mBtaVersion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
ProgressKeeper.submitProgress(ProgressLayout.INSTALL_MODPACK, 0, R.string.fabric_dl_progress, "BTA");
|
||||
try {
|
||||
runCatching() ;
|
||||
mListener.onDownloadFinished(null);
|
||||
}catch (IOException e) {
|
||||
mListener.onDownloadError(e);
|
||||
}
|
||||
ProgressLayout.clearProgress(ProgressLayout.INSTALL_MODPACK);
|
||||
}
|
||||
|
||||
private String tryDownloadIcon() {
|
||||
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(mBtaVersion.iconUrl, base64OutputStream);
|
||||
return new String(byteArrayOutputStream.toByteArray(), StandardCharsets.US_ASCII);
|
||||
}catch (IOException e) {
|
||||
Log.w("BTADownloadTask", "Failed to download base64 icon", e);
|
||||
}finally {
|
||||
try {
|
||||
byteArrayOutputStream.close();
|
||||
} catch (IOException e) {
|
||||
Log.wtf("BTADownloadTask", "Failed to close a byte array stream??", e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void createJson(String btaVersionId) throws IOException {
|
||||
String btaJson = String.format(BASE_JSON, mBtaVersion.versionName, mBtaVersion.downloadUrl, btaVersionId);
|
||||
File jsonDir = new File(Tools.DIR_HOME_VERSION, btaVersionId);
|
||||
File jsonFile = new File(jsonDir, btaVersionId+".json");
|
||||
FileUtils.ensureDirectory(jsonDir);
|
||||
Tools.write(jsonFile.getAbsolutePath(), btaJson);
|
||||
}
|
||||
|
||||
// BTA doesn't have SHA1 checksums in its repositories, so the user may try to reinstall it
|
||||
// if it didn't work due to a broken download. So, for reinstalls like that to work,
|
||||
// we need to delete the old client jar to force the download of a new one.
|
||||
private void removeOldClient() throws IOException{
|
||||
File btaClientPath = new File(Tools.DIR_HOME_LIBRARY, String.format("bta-client/bta-client-%1$s.jar", mBtaVersion.versionName));
|
||||
if(btaClientPath.exists() && !btaClientPath.delete())
|
||||
throw new IOException("Failed to delete old client jar");
|
||||
}
|
||||
|
||||
private void createProfile(String btaVersionId) throws IOException {
|
||||
LauncherProfiles.load();
|
||||
MinecraftProfile btaProfile = new MinecraftProfile();
|
||||
btaProfile.lastVersionId = btaVersionId;
|
||||
btaProfile.name = "Better than Adventure!";
|
||||
btaProfile.icon = tryDownloadIcon();
|
||||
LauncherProfiles.insertMinecraftProfile(btaProfile);
|
||||
LauncherProfiles.write();
|
||||
}
|
||||
|
||||
public void runCatching() throws IOException {
|
||||
removeOldClient();
|
||||
String btaVersionId = "bta-"+mBtaVersion.versionName;
|
||||
createJson(btaVersionId);
|
||||
createProfile(btaVersionId);
|
||||
}
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
package net.kdt.pojavlaunch.modloaders;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Keep;
|
||||
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import net.kdt.pojavlaunch.Tools;
|
||||
import net.kdt.pojavlaunch.utils.DownloadUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
public class BTAUtils {
|
||||
private static final String BTA_CLIENT_URL = "https://downloads.betterthanadventure.net/bta-client/release/%s/client.jar";
|
||||
private static final String BTA_ICON_URL = "https://downloads.betterthanadventure.net/bta-client/release/%s/auto/%s.png";
|
||||
private static final List<String> BTA_TESTED_VERSIONS = new ArrayList<>();
|
||||
static {
|
||||
BTA_TESTED_VERSIONS.add("v7.3");
|
||||
BTA_TESTED_VERSIONS.add("v7.2_01");
|
||||
BTA_TESTED_VERSIONS.add("v7.2");
|
||||
BTA_TESTED_VERSIONS.add("v7.1_01");
|
||||
BTA_TESTED_VERSIONS.add("v7.1");
|
||||
}
|
||||
|
||||
private static String getIconUrl(String version) {
|
||||
String versionUnderscore = version.replace('.','_');
|
||||
return String.format(BTA_ICON_URL, version, versionUnderscore);
|
||||
}
|
||||
|
||||
private static List<BTAVersion> createVersionList(List<String> versionStrings) {
|
||||
ListIterator<String> iterator = versionStrings.listIterator(versionStrings.size());
|
||||
ArrayList<BTAVersion> btaVersions = new ArrayList<>(versionStrings.size());
|
||||
while(iterator.hasPrevious()) {
|
||||
String version = iterator.previous();
|
||||
btaVersions.add(new BTAVersion(
|
||||
version,
|
||||
String.format(BTA_CLIENT_URL, version),
|
||||
getIconUrl(version)
|
||||
));
|
||||
}
|
||||
btaVersions.trimToSize();
|
||||
return btaVersions;
|
||||
}
|
||||
|
||||
private static BTAVersionList processReleasesJson(String releasesInfo) throws JsonParseException {
|
||||
BTAVersionsManifest manifest = Tools.GLOBAL_GSON.fromJson(releasesInfo, BTAVersionsManifest.class);
|
||||
List<String> stringVersions = manifest.versions;
|
||||
List<String> testedVersions = new ArrayList<>();
|
||||
List<String> untestedVersions = new ArrayList<>();
|
||||
for(String version : stringVersions) {
|
||||
if(version == null) break;
|
||||
if(BTA_TESTED_VERSIONS.contains(version)) {
|
||||
testedVersions.add(version);
|
||||
}else {
|
||||
untestedVersions.add(version);
|
||||
}
|
||||
}
|
||||
|
||||
return new BTAVersionList(
|
||||
createVersionList(testedVersions),
|
||||
createVersionList(untestedVersions)
|
||||
);
|
||||
}
|
||||
|
||||
public static BTAVersionList downloadVersionList() throws IOException {
|
||||
try {
|
||||
return DownloadUtils.downloadStringCached(
|
||||
"https://downloads.betterthanadventure.net/bta-client/release/versions.json",
|
||||
"bta_releases", BTAUtils::processReleasesJson);
|
||||
}catch (DownloadUtils.ParseException e) {
|
||||
Log.e("BTAUtils", "Failed to process json", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class BTAVersionsManifest {
|
||||
@Keep
|
||||
public List<String> versions;
|
||||
@Keep
|
||||
@SerializedName("default")
|
||||
public String defaultVersion;
|
||||
}
|
||||
|
||||
public static class BTAVersion {
|
||||
public final String versionName;
|
||||
public final String downloadUrl;
|
||||
public final String iconUrl;
|
||||
|
||||
public BTAVersion(String versionName, String downloadUrl, String iconUrl) {
|
||||
this.versionName = versionName;
|
||||
this.downloadUrl = downloadUrl;
|
||||
this.iconUrl = iconUrl;
|
||||
}
|
||||
}
|
||||
public static class BTAVersionList {
|
||||
public final List<BTAVersion> testedVersions;
|
||||
public final List<BTAVersion> untestedVersions;
|
||||
|
||||
public BTAVersionList(List<BTAVersion> mTestedVersions, List<BTAVersion> mUntestedVersions) {
|
||||
this.testedVersions = mTestedVersions;
|
||||
this.untestedVersions = mUntestedVersions;
|
||||
}
|
||||
}
|
||||
}
|
@ -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 BTAVersionListAdapter extends BaseExpandableListAdapter implements ExpandableListAdapter{
|
||||
private final LayoutInflater mLayoutInflater;
|
||||
private final ArrayList<String> mGroupNames;
|
||||
private final ArrayList<List<BTAUtils.BTAVersion>> mGroups;
|
||||
|
||||
public BTAVersionListAdapter(BTAUtils.BTAVersionList versionList, LayoutInflater mLayoutInflater) {
|
||||
this.mLayoutInflater = mLayoutInflater;
|
||||
Context context = mLayoutInflater.getContext();
|
||||
mGroupNames = new ArrayList<>(2);
|
||||
mGroups = new ArrayList<>(2);
|
||||
if(!versionList.testedVersions.isEmpty()) {
|
||||
mGroupNames.add(context.getString(R.string.bta_installer_available_versions));
|
||||
mGroups.add(versionList.testedVersions);
|
||||
}
|
||||
if(!versionList.untestedVersions.isEmpty()) {
|
||||
mGroupNames.add(context.getString(R.string.bta_installer_untested_versions));
|
||||
mGroups.add(versionList.untestedVersions);
|
||||
}
|
||||
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 Object 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(((BTAUtils.BTAVersion)getChild(i,i1)).versionName);
|
||||
return convertView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChildSelectable(int i, int i1) {
|
||||
return true;
|
||||
}
|
||||
}
|
@ -111,6 +111,14 @@
|
||||
android:layout_marginTop="@dimen/padding_large"
|
||||
android:text="@string/modpack_install_button" />
|
||||
|
||||
<com.kdt.mcgui.MineButton
|
||||
android:id="@+id/modded_profile_bta"
|
||||
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_bta_profile" />
|
||||
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
android:id="@+id/guideline"
|
||||
android:layout_width="wrap_content"
|
||||
|
@ -424,4 +424,8 @@
|
||||
<string name="local_login_bad_username_title">Unsuitable username</string>
|
||||
<string name="local_login_bad_username_text">The username must be between 3–16 characters long, and must only contain latin letters, numbers 0–9 and underscores.</string>
|
||||
<string name="quick_setting_title">Quick settings</string>
|
||||
<string name="create_bta_profile">Create \"Better than Adventure!\" profile</string>
|
||||
<string name="select_bta_version">Select \"Better than Adventure!\" version</string>
|
||||
<string name="bta_installer_available_versions">Supported BTA versions</string>
|
||||
<string name="bta_installer_untested_versions">Untested BTA versions</string>
|
||||
</resources>
|
||||
|
@ -1045,6 +1045,12 @@ public class GLFW
|
||||
nglfwSetShowingWindow(window);
|
||||
}
|
||||
|
||||
public static void glfwHideWindow(long window) {
|
||||
GLFWWindowProperties win = internalGetWindow(window);
|
||||
win.windowAttribs.put(GLFW_HOVERED, 0);
|
||||
win.windowAttribs.put(GLFW_VISIBLE, 0);
|
||||
}
|
||||
|
||||
public static void glfwWindowHint(int hint, int value) {
|
||||
if (hint == GLFW_VISIBLE) {
|
||||
mGLFWWindowVisibleOnCreation = value == GLFW_TRUE;
|
||||
|
Loading…
x
Reference in New Issue
Block a user