Feat[modloader]: quilt support

This commit is contained in:
artdeell 2023-08-30 16:49:06 +03:00 committed by ArtDev
parent 67213c09b8
commit da3079d30c
9 changed files with 396 additions and 319 deletions

View File

@ -1,282 +1,24 @@
package net.kdt.pojavlaunch.fragments; package net.kdt.pojavlaunch.fragments;
import android.content.Context; import net.kdt.pojavlaunch.modloaders.FabriclikeUtils;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ProgressBar;
import android.widget.Spinner;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import net.kdt.pojavlaunch.PojavApplication;
import net.kdt.pojavlaunch.R;
import net.kdt.pojavlaunch.Tools;
import net.kdt.pojavlaunch.modloaders.FabricDownloadTask;
import net.kdt.pojavlaunch.modloaders.FabricUtils;
import net.kdt.pojavlaunch.modloaders.FabricVersion;
import net.kdt.pojavlaunch.modloaders.ModloaderDownloadListener;
import net.kdt.pojavlaunch.modloaders.ModloaderListenerProxy; import net.kdt.pojavlaunch.modloaders.ModloaderListenerProxy;
import net.kdt.pojavlaunch.modloaders.modpacks.SelfReferencingFuture;
import net.kdt.pojavlaunch.progresskeeper.ProgressKeeper;
import java.io.File; public class FabricInstallFragment extends FabriclikeInstallFragment {
import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.Future;
public class FabricInstallFragment extends Fragment implements ModloaderDownloadListener, CompoundButton.OnCheckedChangeListener { public static final String TAG = "FabricInstallFragment";
public static final String TAG = "FabricInstallTarget";
private static ModloaderListenerProxy sTaskProxy; private static ModloaderListenerProxy sTaskProxy;
private Spinner mGameVersionSpinner;
private FabricVersion[] mGameVersionArray;
private Future<?> mGameVersionFuture;
private String mSelectedGameVersion;
private Spinner mLoaderVersionSpinner;
private FabricVersion[] mLoaderVersionArray;
private Future<?> mLoaderVersionFuture;
private String mSelectedLoaderVersion;
private ProgressBar mProgressBar;
private Button mStartButton;
private View mRetryView;
private CheckBox mOnlyStableCheckbox;
public FabricInstallFragment() { public FabricInstallFragment() {
super(R.layout.fragment_fabric_install); super(FabriclikeUtils.FABRIC_UTILS);
} }
@Override @Override
public void onAttach(@NonNull Context context) { protected ModloaderListenerProxy getListenerProxy() {
super.onAttach(context); return sTaskProxy;
} }
@Override @Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { protected void setListenerProxy(ModloaderListenerProxy listenerProxy) {
super.onViewCreated(view, savedInstanceState); sTaskProxy = listenerProxy;
mStartButton = view.findViewById(R.id.fabric_installer_start_button);
mStartButton.setOnClickListener(this::onClickStart);
mGameVersionSpinner = view.findViewById(R.id.fabric_installer_game_ver_spinner);
mGameVersionSpinner.setOnItemSelectedListener(new GameVersionSelectedListener());
mLoaderVersionSpinner = view.findViewById(R.id.fabric_installer_loader_ver_spinner);
mLoaderVersionSpinner.setOnItemSelectedListener(new LoaderVersionSelectedListener());
mProgressBar = view.findViewById(R.id.fabric_installer_progress_bar);
mRetryView = view.findViewById(R.id.fabric_installer_retry_layout);
mOnlyStableCheckbox = view.findViewById(R.id.fabric_installer_only_stable_checkbox);
mOnlyStableCheckbox.setOnCheckedChangeListener(this);
view.findViewById(R.id.fabric_installer_retry_button).setOnClickListener(this::onClickRetry);
if(sTaskProxy != null) {
mStartButton.setEnabled(false);
sTaskProxy.attachListener(this);
}
updateGameVersions();
}
@Override
public void onDestroyView() {
super.onDestroyView();
cancelFutureChecked(mGameVersionFuture);
cancelFutureChecked(mLoaderVersionFuture);
if(sTaskProxy != null) {
sTaskProxy.detachListener();
}
}
private void onClickStart(View v) {
if(ProgressKeeper.hasOngoingTasks()) {
Toast.makeText(v.getContext(), R.string.tasks_ongoing, Toast.LENGTH_LONG).show();
return;
}
sTaskProxy = new ModloaderListenerProxy();
FabricDownloadTask fabricDownloadTask = new FabricDownloadTask(sTaskProxy, mSelectedGameVersion, mSelectedLoaderVersion, true);
sTaskProxy.attachListener(this);
mStartButton.setEnabled(false);
new Thread(fabricDownloadTask).start();
}
private void onClickRetry(View v) {
mStartButton.setEnabled(false);
mRetryView.setVisibility(View.GONE);
mLoaderVersionSpinner.setAdapter(null);
if(mGameVersionArray == null) {
mGameVersionSpinner.setAdapter(null);
updateGameVersions();
return;
}
updateLoaderVersions();
}
@Override
public void onDownloadFinished(File downloadedFile) {
Tools.runOnUiThread(()->{
sTaskProxy.detachListener();
sTaskProxy = null;
mStartButton.setEnabled(true);
// This works because the due to the fact that we have transitioned here
// without adding a transaction to the back stack, which caused the previous
// transaction to be amended (i guess?? thats how the back stack dump looks like)
// we can get back to the main fragment with just one back stack pop.
// For some reason that amendment causes the transaction to lose its tag
// so we cant use the tag here.
getParentFragmentManager().popBackStackImmediate();
});
}
@Override
public void onDataNotAvailable() {
Tools.runOnUiThread(()->{
Context context = requireContext();
sTaskProxy.detachListener();
sTaskProxy = null;
mStartButton.setEnabled(true);
Tools.dialog(context,
context.getString(R.string.global_error),
context.getString(R.string.fabric_dl_cant_read_meta));
});
}
@Override
public void onDownloadError(Exception e) {
Tools.runOnUiThread(()-> {
Context context = requireContext();
sTaskProxy.detachListener();
sTaskProxy = null;
mStartButton.setEnabled(true);
Tools.showError(context, e);
});
}
private void cancelFutureChecked(Future<?> future) {
if(future != null && !future.isCancelled()) future.cancel(true);
}
private void startLoading() {
mProgressBar.setVisibility(View.VISIBLE);
mStartButton.setEnabled(false);
}
private void stopLoading() {
mProgressBar.setVisibility(View.GONE);
// The "visibility on" is managed by the spinners
}
private ArrayAdapter<FabricVersion> createAdapter(FabricVersion[] fabricVersions, boolean onlyStable) {
ArrayList<FabricVersion> filteredVersions = new ArrayList<>(fabricVersions.length);
for(FabricVersion fabricVersion : fabricVersions) {
if(!onlyStable || fabricVersion.stable) filteredVersions.add(fabricVersion);
}
filteredVersions.trimToSize();
return new ArrayAdapter<>(requireContext(), android.R.layout.simple_spinner_dropdown_item, filteredVersions);
}
private void onException(Future<?> myFuture, Exception e) {
Tools.runOnUiThread(()->{
if(myFuture.isCancelled()) return;
stopLoading();
Tools.showError(requireContext(), e);
mRetryView.setVisibility(View.VISIBLE);
});
}
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
updateGameSpinner();
updateLoaderSpinner();
}
class LoaderVersionSelectedListener implements AdapterView.OnItemSelectedListener {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
mSelectedLoaderVersion = ((FabricVersion) adapterView.getAdapter().getItem(i)).version;
mStartButton.setEnabled(mSelectedGameVersion != null);
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
mSelectedLoaderVersion = null;
mStartButton.setEnabled(false);
}
}
class LoadLoaderVersionsTask implements SelfReferencingFuture.FutureInterface {
@Override
public void run(Future<?> myFuture) {
Log.i("LoadLoaderVersions", "Starting...");
try {
mLoaderVersionArray = FabricUtils.downloadLoaderVersions(mSelectedGameVersion);
onFinished(myFuture);
}catch (IOException e) {
onException(myFuture, e);
}
}
private void onFinished(Future<?> myFuture) {
Tools.runOnUiThread(()->{
if(myFuture.isCancelled()) return;
stopLoading();
updateLoaderSpinner();
});
}
}
private void updateLoaderVersions() {
startLoading();
mLoaderVersionFuture = new SelfReferencingFuture(new LoadLoaderVersionsTask()).startOnExecutor(PojavApplication.sExecutorService);
}
private void updateLoaderSpinner() {
mLoaderVersionSpinner.setAdapter(createAdapter(mLoaderVersionArray, mOnlyStableCheckbox.isChecked()));
}
class GameVersionSelectedListener implements AdapterView.OnItemSelectedListener {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
mSelectedGameVersion = ((FabricVersion) adapterView.getAdapter().getItem(i)).version;
cancelFutureChecked(mLoaderVersionFuture);
updateLoaderVersions();
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
mSelectedGameVersion = null;
if(mLoaderVersionFuture != null) mLoaderVersionFuture.cancel(true);
adapterView.setAdapter(null);
}
}
class LoadGameVersionsTask implements SelfReferencingFuture.FutureInterface {
@Override
public void run(Future<?> myFuture) {
try {
mGameVersionArray = FabricUtils.downloadGameVersions();
onFinished(myFuture);
}catch (IOException e) {
onException(myFuture, e);
}
}
private void onFinished(Future<?> myFuture) {
Tools.runOnUiThread(()->{
if(myFuture.isCancelled()) return;
stopLoading();
updateGameSpinner();
});
}
}
private void updateGameVersions() {
startLoading();
mGameVersionFuture = new SelfReferencingFuture(new LoadGameVersionsTask()).startOnExecutor(PojavApplication.sExecutorService);
}
private void updateGameSpinner() {
mGameVersionSpinner.setAdapter(createAdapter(mGameVersionArray, mOnlyStableCheckbox.isChecked()));
} }
} }

View File

@ -0,0 +1,293 @@
package net.kdt.pojavlaunch.fragments;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ProgressBar;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import net.kdt.pojavlaunch.PojavApplication;
import net.kdt.pojavlaunch.R;
import net.kdt.pojavlaunch.Tools;
import net.kdt.pojavlaunch.modloaders.FabriclikeDownloadTask;
import net.kdt.pojavlaunch.modloaders.FabriclikeUtils;
import net.kdt.pojavlaunch.modloaders.FabricVersion;
import net.kdt.pojavlaunch.modloaders.ModloaderDownloadListener;
import net.kdt.pojavlaunch.modloaders.ModloaderListenerProxy;
import net.kdt.pojavlaunch.modloaders.modpacks.SelfReferencingFuture;
import net.kdt.pojavlaunch.progresskeeper.ProgressKeeper;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.Future;
public abstract class FabriclikeInstallFragment extends Fragment implements ModloaderDownloadListener, CompoundButton.OnCheckedChangeListener {
private final FabriclikeUtils mFabriclikeUtils;
private Spinner mGameVersionSpinner;
private FabricVersion[] mGameVersionArray;
private Future<?> mGameVersionFuture;
private String mSelectedGameVersion;
private Spinner mLoaderVersionSpinner;
private FabricVersion[] mLoaderVersionArray;
private Future<?> mLoaderVersionFuture;
private String mSelectedLoaderVersion;
private ProgressBar mProgressBar;
private Button mStartButton;
private View mRetryView;
private CheckBox mOnlyStableCheckbox;
protected FabriclikeInstallFragment(FabriclikeUtils mFabriclikeUtils) {
super(R.layout.fragment_fabric_install);
this.mFabriclikeUtils = mFabriclikeUtils;
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mStartButton = view.findViewById(R.id.fabric_installer_start_button);
mStartButton.setOnClickListener(this::onClickStart);
mGameVersionSpinner = view.findViewById(R.id.fabric_installer_game_ver_spinner);
mGameVersionSpinner.setOnItemSelectedListener(new GameVersionSelectedListener());
mLoaderVersionSpinner = view.findViewById(R.id.fabric_installer_loader_ver_spinner);
mLoaderVersionSpinner.setOnItemSelectedListener(new LoaderVersionSelectedListener());
mProgressBar = view.findViewById(R.id.fabric_installer_progress_bar);
mRetryView = view.findViewById(R.id.fabric_installer_retry_layout);
mOnlyStableCheckbox = view.findViewById(R.id.fabric_installer_only_stable_checkbox);
mOnlyStableCheckbox.setOnCheckedChangeListener(this);
view.findViewById(R.id.fabric_installer_retry_button).setOnClickListener(this::onClickRetry);
((TextView)view.findViewById(R.id.fabric_installer_label_loader_ver)).setText(getString(R.string.fabric_dl_loader_version, mFabriclikeUtils.getName()));
ModloaderListenerProxy proxy = getListenerProxy();
if(proxy != null) {
mStartButton.setEnabled(false);
proxy.attachListener(this);
}
updateGameVersions();
}
@Override
public void onDestroyView() {
super.onDestroyView();
cancelFutureChecked(mGameVersionFuture);
cancelFutureChecked(mLoaderVersionFuture);
ModloaderListenerProxy proxy = getListenerProxy();
if(proxy != null) {
proxy.detachListener();
}
}
private void onClickStart(View v) {
if(ProgressKeeper.hasOngoingTasks()) {
Toast.makeText(v.getContext(), R.string.tasks_ongoing, Toast.LENGTH_LONG).show();
return;
}
ModloaderListenerProxy proxy = new ModloaderListenerProxy();
FabriclikeDownloadTask fabricDownloadTask = new FabriclikeDownloadTask(proxy, mFabriclikeUtils,
mSelectedGameVersion, mSelectedLoaderVersion, true);
proxy.attachListener(this);
setListenerProxy(proxy);
mStartButton.setEnabled(false);
new Thread(fabricDownloadTask).start();
}
private void onClickRetry(View v) {
mStartButton.setEnabled(false);
mRetryView.setVisibility(View.GONE);
mLoaderVersionSpinner.setAdapter(null);
if(mGameVersionArray == null) {
mGameVersionSpinner.setAdapter(null);
updateGameVersions();
return;
}
updateLoaderVersions();
}
@Override
public void onDownloadFinished(File downloadedFile) {
Tools.runOnUiThread(()->{
getListenerProxy().detachListener();
setListenerProxy(null);
mStartButton.setEnabled(true);
// This works because the due to the fact that we have transitioned here
// without adding a transaction to the back stack, which caused the previous
// transaction to be amended (i guess?? thats how the back stack dump looks like)
// we can get back to the main fragment with just one back stack pop.
// For some reason that amendment causes the transaction to lose its tag
// so we cant use the tag here.
getParentFragmentManager().popBackStackImmediate();
});
}
@Override
public void onDataNotAvailable() {
Tools.runOnUiThread(()->{
Context context = requireContext();
getListenerProxy().detachListener();
setListenerProxy(null);
mStartButton.setEnabled(true);
Tools.dialog(context,
context.getString(R.string.global_error),
context.getString(R.string.fabric_dl_cant_read_meta, mFabriclikeUtils.getName()));
});
}
@Override
public void onDownloadError(Exception e) {
Tools.runOnUiThread(()-> {
Context context = requireContext();
getListenerProxy().detachListener();
setListenerProxy(null);
mStartButton.setEnabled(true);
Tools.showError(context, e);
});
}
private void cancelFutureChecked(Future<?> future) {
if(future != null && !future.isCancelled()) future.cancel(true);
}
private void startLoading() {
mProgressBar.setVisibility(View.VISIBLE);
mStartButton.setEnabled(false);
}
private void stopLoading() {
mProgressBar.setVisibility(View.GONE);
// The "visibility on" is managed by the spinners
}
private ArrayAdapter<FabricVersion> createAdapter(FabricVersion[] fabricVersions, boolean onlyStable) {
ArrayList<FabricVersion> filteredVersions = new ArrayList<>(fabricVersions.length);
for(FabricVersion fabricVersion : fabricVersions) {
if(!onlyStable || fabricVersion.stable) filteredVersions.add(fabricVersion);
}
filteredVersions.trimToSize();
return new ArrayAdapter<>(requireContext(), android.R.layout.simple_spinner_dropdown_item, filteredVersions);
}
private void onException(Future<?> myFuture, Exception e) {
Tools.runOnUiThread(()->{
if(myFuture.isCancelled()) return;
stopLoading();
if(e != null) Tools.showError(requireContext(), e);
mRetryView.setVisibility(View.VISIBLE);
});
}
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
updateGameSpinner();
updateLoaderSpinner();
}
class LoaderVersionSelectedListener implements AdapterView.OnItemSelectedListener {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
mSelectedLoaderVersion = ((FabricVersion) adapterView.getAdapter().getItem(i)).version;
mStartButton.setEnabled(mSelectedGameVersion != null);
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
mSelectedLoaderVersion = null;
mStartButton.setEnabled(false);
}
}
class LoadLoaderVersionsTask implements SelfReferencingFuture.FutureInterface {
@Override
public void run(Future<?> myFuture) {
Log.i("LoadLoaderVersions", "Starting...");
try {
mLoaderVersionArray = mFabriclikeUtils.downloadLoaderVersions(mSelectedGameVersion);
if(mLoaderVersionArray != null) onFinished(myFuture);
else onException(myFuture, null);
}catch (IOException e) {
onException(myFuture, e);
}
}
private void onFinished(Future<?> myFuture) {
Tools.runOnUiThread(()->{
if(myFuture.isCancelled()) return;
stopLoading();
updateLoaderSpinner();
});
}
}
private void updateLoaderVersions() {
startLoading();
mLoaderVersionFuture = new SelfReferencingFuture(new LoadLoaderVersionsTask()).startOnExecutor(PojavApplication.sExecutorService);
}
private void updateLoaderSpinner() {
mLoaderVersionSpinner.setAdapter(createAdapter(mLoaderVersionArray, mOnlyStableCheckbox.isChecked()));
}
class GameVersionSelectedListener implements AdapterView.OnItemSelectedListener {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
mSelectedGameVersion = ((FabricVersion) adapterView.getAdapter().getItem(i)).version;
cancelFutureChecked(mLoaderVersionFuture);
updateLoaderVersions();
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
mSelectedGameVersion = null;
if(mLoaderVersionFuture != null) mLoaderVersionFuture.cancel(true);
adapterView.setAdapter(null);
}
}
class LoadGameVersionsTask implements SelfReferencingFuture.FutureInterface {
@Override
public void run(Future<?> myFuture) {
try {
mGameVersionArray = mFabriclikeUtils.downloadGameVersions();
if(mGameVersionArray != null) onFinished(myFuture);
else onException(myFuture, null);
}catch (IOException e) {
onException(myFuture, e);
}
}
private void onFinished(Future<?> myFuture) {
Tools.runOnUiThread(()->{
if(myFuture.isCancelled()) return;
stopLoading();
updateGameSpinner();
});
}
}
private void updateGameVersions() {
startLoading();
mGameVersionFuture = new SelfReferencingFuture(new LoadGameVersionsTask()).startOnExecutor(PojavApplication.sExecutorService);
}
private void updateGameSpinner() {
mGameVersionSpinner.setAdapter(createAdapter(mGameVersionArray, mOnlyStableCheckbox.isChecked()));
}
protected abstract ModloaderListenerProxy getListenerProxy();
protected abstract void setListenerProxy(ModloaderListenerProxy listenerProxy);
}

View File

@ -33,5 +33,7 @@ public class ProfileTypeSelectFragment extends Fragment {
Tools.swapFragment(requireActivity(), ForgeInstallFragment.class, ForgeInstallFragment.TAG, false, null)); Tools.swapFragment(requireActivity(), ForgeInstallFragment.class, ForgeInstallFragment.TAG, false, null));
view.findViewById(R.id.modded_profile_modpack).setOnClickListener((v)-> view.findViewById(R.id.modded_profile_modpack).setOnClickListener((v)->
Tools.swapFragment(requireActivity(), SearchModFragment.class, SearchModFragment.TAG, false, null)); Tools.swapFragment(requireActivity(), SearchModFragment.class, SearchModFragment.TAG, false, null));
view.findViewById(R.id.modded_profile_quilt).setOnClickListener((v)->
Tools.swapFragment(requireActivity(), QuiltInstallFragment.class, QuiltInstallFragment.TAG, false, null));
} }
} }

View File

@ -0,0 +1,24 @@
package net.kdt.pojavlaunch.fragments;
import net.kdt.pojavlaunch.modloaders.FabriclikeUtils;
import net.kdt.pojavlaunch.modloaders.ModloaderListenerProxy;
public class QuiltInstallFragment extends FabriclikeInstallFragment {
public static final String TAG = "QuiltInstallFragment";
private static ModloaderListenerProxy sTaskProxy;
public QuiltInstallFragment() {
super(FabriclikeUtils.QUILT_UTILS);
}
@Override
protected ModloaderListenerProxy getListenerProxy() {
return sTaskProxy;
}
@Override
protected void setListenerProxy(ModloaderListenerProxy listenerProxy) {
sTaskProxy = listenerProxy;
}
}

View File

@ -15,13 +15,15 @@ import org.json.JSONObject;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
public class FabricDownloadTask implements Runnable, Tools.DownloaderFeedback{ public class FabriclikeDownloadTask implements Runnable, Tools.DownloaderFeedback{
private final ModloaderDownloadListener mModloaderDownloadListener; private final ModloaderDownloadListener mModloaderDownloadListener;
private final FabriclikeUtils mUtils;
private final String mGameVersion; private final String mGameVersion;
private final String mLoaderVersion; private final String mLoaderVersion;
private final boolean mCreateProfile; private final boolean mCreateProfile;
public FabricDownloadTask(ModloaderDownloadListener modloaderDownloadListener, String mGameVersion, String mLoaderVersion, boolean mCreateProfile) { public FabriclikeDownloadTask(ModloaderDownloadListener modloaderDownloadListener, FabriclikeUtils utils, String mGameVersion, String mLoaderVersion, boolean mCreateProfile) {
this.mModloaderDownloadListener = modloaderDownloadListener; this.mModloaderDownloadListener = modloaderDownloadListener;
this.mUtils = utils;
this.mGameVersion = mGameVersion; this.mGameVersion = mGameVersion;
this.mLoaderVersion = mLoaderVersion; this.mLoaderVersion = mLoaderVersion;
this.mCreateProfile = mCreateProfile; this.mCreateProfile = mCreateProfile;
@ -40,7 +42,7 @@ public class FabricDownloadTask implements Runnable, Tools.DownloaderFeedback{
} }
private boolean runCatching() throws IOException{ private boolean runCatching() throws IOException{
String fabricJson = DownloadUtils.downloadString(FabricUtils.createJsonDownloadUrl(mGameVersion, mLoaderVersion)); String fabricJson = DownloadUtils.downloadString(mUtils.createJsonDownloadUrl(mGameVersion, mLoaderVersion));
String versionId; String versionId;
try { try {
JSONObject fabricJsonObject = new JSONObject(fabricJson); JSONObject fabricJsonObject = new JSONObject(fabricJson);
@ -58,7 +60,7 @@ public class FabricDownloadTask implements Runnable, Tools.DownloaderFeedback{
LauncherProfiles.load(); LauncherProfiles.load();
MinecraftProfile fabricProfile = new MinecraftProfile(); MinecraftProfile fabricProfile = new MinecraftProfile();
fabricProfile.lastVersionId = versionId; fabricProfile.lastVersionId = versionId;
fabricProfile.name = "Minecraft " + mGameVersion + " with Fabric " + mLoaderVersion; fabricProfile.name = "Minecraft " + mGameVersion + " with " + mUtils.getName()+ " " + mLoaderVersion;
LauncherProfiles.insertMinecraftProfile(fabricProfile); LauncherProfiles.insertMinecraftProfile(fabricProfile);
LauncherProfiles.write(); LauncherProfiles.write();
} }
@ -68,6 +70,6 @@ public class FabricDownloadTask implements Runnable, Tools.DownloaderFeedback{
@Override @Override
public void updateProgress(int curr, int max) { public void updateProgress(int curr, int max) {
int progress100 = (int)(((float)curr / (float)max)*100f); int progress100 = (int)(((float)curr / (float)max)*100f);
ProgressKeeper.submitProgress(ProgressLayout.INSTALL_MODPACK, progress100, R.string.fabric_dl_progress); ProgressKeeper.submitProgress(ProgressLayout.INSTALL_MODPACK, progress100, R.string.fabric_dl_progress, mUtils.getName());
} }
} }

View File

@ -1,7 +1,5 @@
package net.kdt.pojavlaunch.modloaders; package net.kdt.pojavlaunch.modloaders;
import android.content.Intent;
import com.google.gson.JsonSyntaxException; import com.google.gson.JsonSyntaxException;
import net.kdt.pojavlaunch.Tools; import net.kdt.pojavlaunch.Tools;
@ -11,31 +9,44 @@ import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.URLEncoder; import java.net.URLEncoder;
public class FabricUtils { public class FabriclikeUtils {
private static final String FABRIC_LOADER_METADATA_URL = "https://meta.fabricmc.net/v2/versions/loader/%s";
private static final String FABRIC_GAME_METADATA_URL = "https://meta.fabricmc.net/v2/versions/game";
private static final String FABRIC_JSON_DOWNLOAD_URL = "https://meta.fabricmc.net/v2/versions/loader/%s/%s/profile/json"; public static final FabriclikeUtils FABRIC_UTILS = new FabriclikeUtils("https://meta.fabricmc.net/v2", "fabric", "Fabric");
public static final FabriclikeUtils QUILT_UTILS = new FabriclikeUtils("https://meta.quiltmc.org/v3", "quilt", "Quilt");
public static FabricVersion[] downloadGameVersions() throws IOException{ private static final String LOADER_METADATA_URL = "%s/versions/loader/%s";
private static final String GAME_METADATA_URL = "%s/versions/game";
private static final String JSON_DOWNLOAD_URL = "%s/versions/loader/%s/%s/profile/json";
private final String mApiUrl;
private final String mCachePrefix;
private final String mName;
private FabriclikeUtils(String mApiUrl, String cachePrefix, String mName) {
this.mApiUrl = mApiUrl;
this.mCachePrefix = cachePrefix;
this.mName = mName;
}
public FabricVersion[] downloadGameVersions() throws IOException{
try { try {
return DownloadUtils.downloadStringCached(FABRIC_GAME_METADATA_URL, "fabric_game_versions", return DownloadUtils.downloadStringCached(String.format(GAME_METADATA_URL, mApiUrl), mCachePrefix+"_game_versions",
FabricUtils::deserializeRawVersions FabriclikeUtils::deserializeRawVersions
); );
}catch (DownloadUtils.ParseException ignored) {} }catch (DownloadUtils.ParseException ignored) {}
return null; return null;
} }
public static FabricVersion[] downloadLoaderVersions(String gameVersion) throws IOException{ public FabricVersion[] downloadLoaderVersions(String gameVersion) throws IOException{
try { try {
String urlEncodedGameVersion = URLEncoder.encode(gameVersion, "UTF-8"); String urlEncodedGameVersion = URLEncoder.encode(gameVersion, "UTF-8");
return DownloadUtils.downloadStringCached(String.format(FABRIC_LOADER_METADATA_URL, urlEncodedGameVersion), return DownloadUtils.downloadStringCached(String.format(LOADER_METADATA_URL, mApiUrl, urlEncodedGameVersion),
"fabric_loader_versions."+urlEncodedGameVersion, mCachePrefix+"_loader_versions."+urlEncodedGameVersion,
(input)->{ try { (input)->{ try {
return deserializeLoaderVersions(input); return deserializeLoaderVersions(input);
}catch (JSONException e) { }catch (JSONException e) {
@ -48,14 +59,18 @@ public class FabricUtils {
return null; return null;
} }
public static String createJsonDownloadUrl(String gameVersion, String loaderVersion) { public String createJsonDownloadUrl(String gameVersion, String loaderVersion) {
try { try {
gameVersion = URLEncoder.encode(gameVersion, "UTF-8"); gameVersion = URLEncoder.encode(gameVersion, "UTF-8");
loaderVersion = URLEncoder.encode(loaderVersion, "UTF-8"); loaderVersion = URLEncoder.encode(loaderVersion, "UTF-8");
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
return String.format(FABRIC_JSON_DOWNLOAD_URL, gameVersion, loaderVersion); return String.format(JSON_DOWNLOAD_URL, mApiUrl, gameVersion, loaderVersion);
}
public String getName() {
return mName;
} }
private static FabricVersion[] deserializeLoaderVersions(String input) throws JSONException { private static FabricVersion[] deserializeLoaderVersions(String input) throws JSONException {
@ -65,7 +80,12 @@ public class FabricUtils {
JSONObject jsonObject = jsonArray.getJSONObject(i).getJSONObject("loader"); JSONObject jsonObject = jsonArray.getJSONObject(i).getJSONObject("loader");
FabricVersion fabricVersion = new FabricVersion(); FabricVersion fabricVersion = new FabricVersion();
fabricVersion.version = jsonObject.getString("version"); fabricVersion.version = jsonObject.getString("version");
//Quilt has a skill issue and does not say which versions are stable or not
if(jsonObject.has("stable")) {
fabricVersion.stable = jsonObject.getBoolean("stable"); fabricVersion.stable = jsonObject.getBoolean("stable");
} else {
fabricVersion.stable = !fabricVersion.version.contains("beta");
}
fabricVersions[i] = fabricVersion; fabricVersions[i] = fabricVersion;
} }
return fabricVersions; return fabricVersions;
@ -79,15 +99,4 @@ public class FabricUtils {
throw new DownloadUtils.ParseException(null); throw new DownloadUtils.ParseException(null);
} }
} }
public static void addAutoInstallArgs(Intent intent, File modInstalllerJar,
String gameVersion, String loaderVersion,
boolean isSnapshot, boolean createProfile) {
intent.putExtra("javaArgs", "-jar " + modInstalllerJar.getAbsolutePath() + " client -dir "+ Tools.DIR_GAME_NEW
+ " -mcversion "+gameVersion +" -loader "+loaderVersion +
(isSnapshot ? " -snapshot" : "") +
(createProfile ? "" : " -noprofile"));
intent.putExtra("openLogOutput", true);
}
} }

View File

@ -4,8 +4,8 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import net.kdt.pojavlaunch.JavaGUILauncherActivity; import net.kdt.pojavlaunch.JavaGUILauncherActivity;
import net.kdt.pojavlaunch.modloaders.FabricDownloadTask; import net.kdt.pojavlaunch.modloaders.FabriclikeDownloadTask;
import net.kdt.pojavlaunch.modloaders.FabricUtils; import net.kdt.pojavlaunch.modloaders.FabriclikeUtils;
import net.kdt.pojavlaunch.modloaders.ForgeDownloadTask; import net.kdt.pojavlaunch.modloaders.ForgeDownloadTask;
import net.kdt.pojavlaunch.modloaders.ForgeUtils; import net.kdt.pojavlaunch.modloaders.ForgeUtils;
import net.kdt.pojavlaunch.modloaders.ModloaderDownloadListener; import net.kdt.pojavlaunch.modloaders.ModloaderDownloadListener;
@ -37,7 +37,7 @@ public class ModLoader {
case MOD_LOADER_FABRIC: case MOD_LOADER_FABRIC:
return "fabric-loader-"+modLoaderVersion+"-"+minecraftVersion; return "fabric-loader-"+modLoaderVersion+"-"+minecraftVersion;
case MOD_LOADER_QUILT: case MOD_LOADER_QUILT:
throw new RuntimeException("Quilt is not supported"); return "quilt-loader-"+modLoaderVersion+"-"+minecraftVersion;
default: default:
return null; return null;
} }
@ -54,9 +54,9 @@ public class ModLoader {
case MOD_LOADER_FORGE: case MOD_LOADER_FORGE:
return new ForgeDownloadTask(listener, minecraftVersion, modLoaderVersion); return new ForgeDownloadTask(listener, minecraftVersion, modLoaderVersion);
case MOD_LOADER_FABRIC: case MOD_LOADER_FABRIC:
return new FabricDownloadTask(listener, minecraftVersion, modLoaderVersion, false); return createFabriclikeTask(listener, FabriclikeUtils.FABRIC_UTILS);
case MOD_LOADER_QUILT: case MOD_LOADER_QUILT:
throw new RuntimeException("Quilt is not supported"); return createFabriclikeTask(listener, FabriclikeUtils.QUILT_UTILS);
default: default:
return null; return null;
} }
@ -99,4 +99,8 @@ public class ModLoader {
return false; return false;
} }
} }
private FabriclikeDownloadTask createFabriclikeTask(ModloaderDownloadListener modloaderDownloadListener, FabriclikeUtils utils) {
return new FabriclikeDownloadTask(modloaderDownloadListener, utils, minecraftVersion, modLoaderVersion, false);
}
} }

View File

@ -1,12 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<com.kdt.DefocusableScrollView <com.kdt.DefocusableScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="@color/background_app" android:background="@color/background_app">
>
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
@ -88,9 +85,15 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/padding_large" android:layout_marginHorizontal="@dimen/padding_large"
android:layout_marginTop="@dimen/padding_large" android:layout_marginTop="@dimen/padding_large"
android:text="@string/modloader_dl_install_fabric" android:text="@string/modloader_dl_install_fabric" />
app:layout_constraintTop_toBottomOf="@+id/view_modded"
tools:layout_editor_absoluteX="50dp" /> <com.kdt.mcgui.MineButton
android:id="@+id/modded_profile_quilt"
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/modloader_dl_install_quilt" />
<com.kdt.mcgui.MineButton <com.kdt.mcgui.MineButton
android:id="@+id/modded_profile_forge" android:id="@+id/modded_profile_forge"
@ -98,10 +101,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/padding_large" android:layout_marginHorizontal="@dimen/padding_large"
android:layout_marginTop="@dimen/padding_large" android:layout_marginTop="@dimen/padding_large"
android:text="@string/modloader_dl_install_forge" />
android:text="@string/modloader_dl_install_forge"
app:layout_constraintTop_toBottomOf="@+id/modded_profile_fabric" />
<com.kdt.mcgui.MineButton <com.kdt.mcgui.MineButton
android:id="@+id/modded_profile_modpack" android:id="@+id/modded_profile_modpack"

View File

@ -388,12 +388,13 @@
<string name="modloader_dl_failed_to_load_list">Failed to load the version list!</string> <string name="modloader_dl_failed_to_load_list">Failed to load the version list!</string>
<string name="forge_dl_no_installer">Sorry, but this version of Forge does not have an installer, which is not yet supported.</string> <string name="forge_dl_no_installer">Sorry, but this version of Forge does not have an installer, which is not yet supported.</string>
<string name="forge_dl_select_version">Select Forge version</string> <string name="forge_dl_select_version">Select Forge version</string>
<string name="fabric_dl_progress">Downloading Fabric installer</string> <string name="fabric_dl_progress">Downloading %s loader metadata</string>
<string name="fabric_dl_loader_version">Fabric loader version</string> <string name="fabric_dl_loader_version">%s loader version</string>
<string name="fabric_dl_game_version">Minecraft version</string> <string name="fabric_dl_game_version">Minecraft version</string>
<string name="fabric_dl_install">Install</string> <string name="fabric_dl_install">Install</string>
<string name="fabric_dl_cant_read_meta">Failed to read Fabric metadata. Please try again later.</string> <string name="fabric_dl_cant_read_meta">Failed to read %s loader metadata. Please try again later.</string>
<string name="modloader_dl_install_fabric">Create Fabric profile</string> <string name="modloader_dl_install_fabric">Create Fabric profile</string>
<string name="modloader_dl_install_quilt">Create Quilt profile</string>
<string name="modloader_dl_install_forge">Create Forge profile</string> <string name="modloader_dl_install_forge">Create Forge profile</string>
<string name="create_profile_vanilla">Create vanilla profile</string> <string name="create_profile_vanilla">Create vanilla profile</string>
<string name="create_profile_vanilla_like_versions">Vanilla-like versions</string> <string name="create_profile_vanilla_like_versions">Vanilla-like versions</string>