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;
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.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.FabriclikeUtils;
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 class FabricInstallFragment extends FabriclikeInstallFragment {
public class FabricInstallFragment extends Fragment implements ModloaderDownloadListener, CompoundButton.OnCheckedChangeListener {
public static final String TAG = "FabricInstallTarget";
public static final String TAG = "FabricInstallFragment";
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() {
super(R.layout.fragment_fabric_install);
super(FabriclikeUtils.FABRIC_UTILS);
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
protected ModloaderListenerProxy getListenerProxy() {
return sTaskProxy;
}
@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);
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()));
protected void setListenerProxy(ModloaderListenerProxy listenerProxy) {
sTaskProxy = listenerProxy;
}
}

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));
view.findViewById(R.id.modded_profile_modpack).setOnClickListener((v)->
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.IOException;
public class FabricDownloadTask implements Runnable, Tools.DownloaderFeedback{
public class FabriclikeDownloadTask implements Runnable, Tools.DownloaderFeedback{
private final ModloaderDownloadListener mModloaderDownloadListener;
private final FabriclikeUtils mUtils;
private final String mGameVersion;
private final String mLoaderVersion;
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.mUtils = utils;
this.mGameVersion = mGameVersion;
this.mLoaderVersion = mLoaderVersion;
this.mCreateProfile = mCreateProfile;
@ -40,7 +42,7 @@ public class FabricDownloadTask implements Runnable, Tools.DownloaderFeedback{
}
private boolean runCatching() throws IOException{
String fabricJson = DownloadUtils.downloadString(FabricUtils.createJsonDownloadUrl(mGameVersion, mLoaderVersion));
String fabricJson = DownloadUtils.downloadString(mUtils.createJsonDownloadUrl(mGameVersion, mLoaderVersion));
String versionId;
try {
JSONObject fabricJsonObject = new JSONObject(fabricJson);
@ -58,7 +60,7 @@ public class FabricDownloadTask implements Runnable, Tools.DownloaderFeedback{
LauncherProfiles.load();
MinecraftProfile fabricProfile = new MinecraftProfile();
fabricProfile.lastVersionId = versionId;
fabricProfile.name = "Minecraft " + mGameVersion + " with Fabric " + mLoaderVersion;
fabricProfile.name = "Minecraft " + mGameVersion + " with " + mUtils.getName()+ " " + mLoaderVersion;
LauncherProfiles.insertMinecraftProfile(fabricProfile);
LauncherProfiles.write();
}
@ -68,6 +70,6 @@ public class FabricDownloadTask implements Runnable, Tools.DownloaderFeedback{
@Override
public void updateProgress(int curr, int max) {
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;
import android.content.Intent;
import com.google.gson.JsonSyntaxException;
import net.kdt.pojavlaunch.Tools;
@ -11,31 +9,44 @@ import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
public class FabricUtils {
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";
public class FabriclikeUtils {
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 {
return DownloadUtils.downloadStringCached(FABRIC_GAME_METADATA_URL, "fabric_game_versions",
FabricUtils::deserializeRawVersions
return DownloadUtils.downloadStringCached(String.format(GAME_METADATA_URL, mApiUrl), mCachePrefix+"_game_versions",
FabriclikeUtils::deserializeRawVersions
);
}catch (DownloadUtils.ParseException ignored) {}
return null;
}
public static FabricVersion[] downloadLoaderVersions(String gameVersion) throws IOException{
public FabricVersion[] downloadLoaderVersions(String gameVersion) throws IOException{
try {
String urlEncodedGameVersion = URLEncoder.encode(gameVersion, "UTF-8");
return DownloadUtils.downloadStringCached(String.format(FABRIC_LOADER_METADATA_URL, urlEncodedGameVersion),
"fabric_loader_versions."+urlEncodedGameVersion,
return DownloadUtils.downloadStringCached(String.format(LOADER_METADATA_URL, mApiUrl, urlEncodedGameVersion),
mCachePrefix+"_loader_versions."+urlEncodedGameVersion,
(input)->{ try {
return deserializeLoaderVersions(input);
}catch (JSONException e) {
@ -48,14 +59,18 @@ public class FabricUtils {
return null;
}
public static String createJsonDownloadUrl(String gameVersion, String loaderVersion) {
public String createJsonDownloadUrl(String gameVersion, String loaderVersion) {
try {
gameVersion = URLEncoder.encode(gameVersion, "UTF-8");
loaderVersion = URLEncoder.encode(loaderVersion, "UTF-8");
} catch (UnsupportedEncodingException 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 {
@ -65,7 +80,12 @@ public class FabricUtils {
JSONObject jsonObject = jsonArray.getJSONObject(i).getJSONObject("loader");
FabricVersion fabricVersion = new FabricVersion();
fabricVersion.version = jsonObject.getString("version");
fabricVersion.stable = jsonObject.getBoolean("stable");
//Quilt has a skill issue and does not say which versions are stable or not
if(jsonObject.has("stable")) {
fabricVersion.stable = jsonObject.getBoolean("stable");
} else {
fabricVersion.stable = !fabricVersion.version.contains("beta");
}
fabricVersions[i] = fabricVersion;
}
return fabricVersions;
@ -79,15 +99,4 @@ public class FabricUtils {
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 net.kdt.pojavlaunch.JavaGUILauncherActivity;
import net.kdt.pojavlaunch.modloaders.FabricDownloadTask;
import net.kdt.pojavlaunch.modloaders.FabricUtils;
import net.kdt.pojavlaunch.modloaders.FabriclikeDownloadTask;
import net.kdt.pojavlaunch.modloaders.FabriclikeUtils;
import net.kdt.pojavlaunch.modloaders.ForgeDownloadTask;
import net.kdt.pojavlaunch.modloaders.ForgeUtils;
import net.kdt.pojavlaunch.modloaders.ModloaderDownloadListener;
@ -37,7 +37,7 @@ public class ModLoader {
case MOD_LOADER_FABRIC:
return "fabric-loader-"+modLoaderVersion+"-"+minecraftVersion;
case MOD_LOADER_QUILT:
throw new RuntimeException("Quilt is not supported");
return "quilt-loader-"+modLoaderVersion+"-"+minecraftVersion;
default:
return null;
}
@ -54,9 +54,9 @@ public class ModLoader {
case MOD_LOADER_FORGE:
return new ForgeDownloadTask(listener, minecraftVersion, modLoaderVersion);
case MOD_LOADER_FABRIC:
return new FabricDownloadTask(listener, minecraftVersion, modLoaderVersion, false);
return createFabriclikeTask(listener, FabriclikeUtils.FABRIC_UTILS);
case MOD_LOADER_QUILT:
throw new RuntimeException("Quilt is not supported");
return createFabriclikeTask(listener, FabriclikeUtils.QUILT_UTILS);
default:
return null;
}
@ -99,4 +99,8 @@ public class ModLoader {
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"?>
<com.kdt.DefocusableScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
<com.kdt.DefocusableScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/background_app"
>
android:background="@color/background_app">
<LinearLayout
android:layout_width="match_parent"
@ -88,9 +85,15 @@
android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/padding_large"
android:layout_marginTop="@dimen/padding_large"
android:text="@string/modloader_dl_install_fabric"
app:layout_constraintTop_toBottomOf="@+id/view_modded"
tools:layout_editor_absoluteX="50dp" />
android:text="@string/modloader_dl_install_fabric" />
<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
android:id="@+id/modded_profile_forge"
@ -98,10 +101,7 @@
android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/padding_large"
android:layout_marginTop="@dimen/padding_large"
android:text="@string/modloader_dl_install_forge"
app:layout_constraintTop_toBottomOf="@+id/modded_profile_fabric" />
android:text="@string/modloader_dl_install_forge" />
<com.kdt.mcgui.MineButton
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="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="fabric_dl_progress">Downloading Fabric installer</string>
<string name="fabric_dl_loader_version">Fabric loader version</string>
<string name="fabric_dl_progress">Downloading %s loader metadata</string>
<string name="fabric_dl_loader_version">%s loader version</string>
<string name="fabric_dl_game_version">Minecraft version</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_quilt">Create Quilt 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_like_versions">Vanilla-like versions</string>