Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import net.kdt.pojavlaunch.R;
import net.kdt.pojavlaunch.Tools;
import net.kdt.pojavlaunch.extra.ExtraCore;
import net.kdt.pojavlaunch.mirrors.DownloadMirror;
import net.kdt.pojavlaunch.modloaders.ModloaderDownloadListener;
import net.kdt.pojavlaunch.modloaders.ModloaderListenerProxy;
import net.kdt.pojavlaunch.progresskeeper.ProgressKeeper;
Expand Down Expand Up @@ -106,7 +105,7 @@ public boolean onChildClick(ExpandableListView expandableListView, View view, in
Object forgeVersion = expandableListView.getExpandableListAdapter().getChild(i, i1);
ModloaderListenerProxy taskProxy = new ModloaderListenerProxy();
Runnable downloadTask = createDownloadTask(forgeVersion, taskProxy);
setTaskProxy(taskProxy);
setTaskProxyValue(taskProxy);
taskProxy.attachListener(this);
mExpandableListView.setEnabled(false);
new Thread(downloadTask).start();
Expand All @@ -118,7 +117,7 @@ public void onDownloadFinished(File downloadedFile) {
Tools.runOnUiThread(()->{
Context context = requireContext();
getTaskProxy().detachListener();
setTaskProxy(null);
deleteTaskProxy();
mExpandableListView.setEnabled(true);
// Read the comment in FabricInstallFragment.onDownloadFinished() to see how this works
getParentFragmentManager().popBackStackImmediate();
Expand All @@ -131,7 +130,7 @@ public void onDataNotAvailable() {
Tools.runOnUiThread(()->{
Context context = requireContext();
getTaskProxy().detachListener();
setTaskProxy(null);
deleteTaskProxy();
mExpandableListView.setEnabled(true);
Tools.dialog(context,
context.getString(R.string.global_error),
Expand All @@ -144,15 +143,18 @@ public void onDownloadError(Exception e) {
Tools.runOnUiThread(()->{
Context context = requireContext();
getTaskProxy().detachListener();
setTaskProxy(null);
deleteTaskProxy();
mExpandableListView.setEnabled(true);
Tools.showError(context, e);
});
}

private void setTaskProxy(ModloaderListenerProxy proxy) {
private void setTaskProxyValue(ModloaderListenerProxy proxy) {
ExtraCore.setValue(mExtraTag, proxy);
}
private void deleteTaskProxy(){
ExtraCore.removeValue(mExtraTag);
}

private ModloaderListenerProxy getTaskProxy() {
return (ModloaderListenerProxy) ExtraCore.getValue(mExtraTag);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package net.kdt.pojavlaunch.fragments;

import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.widget.ExpandableListAdapter;

import androidx.annotation.NonNull;

import net.kdt.pojavlaunch.JavaGUILauncherActivity;
import net.kdt.pojavlaunch.R;
import net.kdt.pojavlaunch.Tools;
import net.kdt.pojavlaunch.modloaders.ForgeDownloadTask;
import net.kdt.pojavlaunch.modloaders.ForgeUtils;
import net.kdt.pojavlaunch.modloaders.ModloaderListenerProxy;
import net.kdt.pojavlaunch.modloaders.NeoForgeDownloadTask;
import net.kdt.pojavlaunch.modloaders.NeoForgeVersionListAdapter;
import net.kdt.pojavlaunch.utils.DownloadUtils;

import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.List;

public class NeoForgeInstallFragment extends ModVersionListFragment<List<String>> {
public static final String TAG = "NeoForgeInstallFragment";
public NeoForgeInstallFragment() {
super(TAG);
}

private static final String NEOFORGE_METADATA_URL = "https://meta.prismlauncher.org/v1/net.neoforged/index.json";


@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
}

@Override
public int getTitleText() {
return R.string.neoforge_dl_select_version;
}

@Override
public int getNoDataMsg() {
return R.string.neoforge_dl_no_installer;
}

@Override
public List<String> loadVersionList() {
String test = null;
try {
test = DownloadUtils.downloadStringCached(NEOFORGE_METADATA_URL, "neoforge_versions", input -> input);
} catch (Exception e) {
Tools.showErrorRemote(e);
}
return Collections.singletonList(test);
// Moved the parsing logic to the adapter because there is no way to get this info easily, we use prism's index
// since neoforge doesn't actually give this information easily anywhere.
// To clarify, neoforge does not provide maven APIs to get supported Minecraft versions for each loader version

}

@Override
public ExpandableListAdapter createAdapter(List<String> versionList, LayoutInflater layoutInflater) {
return new NeoForgeVersionListAdapter(versionList, layoutInflater);
}

@Override
public Runnable createDownloadTask(Object selectedVersion, ModloaderListenerProxy listenerProxy) {
return new NeoForgeDownloadTask(listenerProxy, (String) selectedVersion);
}

@Override
public void onDownloadFinished(Context context, File downloadedFile) {
Intent modInstallerStartIntent = new Intent(context, JavaGUILauncherActivity.class);
modInstallerStartIntent.putExtra("javaArgs", "-jar "+downloadedFile.getAbsolutePath()+" --install-client");
context.startActivity(modInstallerStartIntent);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
tryInstall(FabricInstallFragment.class, FabricInstallFragment.TAG));
view.findViewById(R.id.modded_profile_forge).setOnClickListener((v)->
tryInstall(ForgeInstallFragment.class, ForgeInstallFragment.TAG));
view.findViewById(R.id.modded_profile_neoforge).setOnClickListener((v)->
tryInstall(NeoForgeInstallFragment.class, NeoForgeInstallFragment.TAG));
view.findViewById(R.id.modded_profile_modpack).setOnClickListener((v)->
tryInstall(SearchModFragment.class, SearchModFragment.TAG));
view.findViewById(R.id.modded_profile_quilt).setOnClickListener((v)->
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package net.kdt.pojavlaunch.modloaders;

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 java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;

public class NeoForgeDownloadTask implements Runnable, Tools.DownloaderFeedback {
private String mDownloadUrl;
private String mFullVersion;
private String mLoaderVersion;
private String mGameVersion;
private final ModloaderDownloadListener mListener;
public NeoForgeDownloadTask(ModloaderDownloadListener listener, String forgeVersion) {
this.mListener = listener;
this.mDownloadUrl = "https://maven.neoforged.net/releases/net/neoforged/neoforge/"+ forgeVersion +"/neoforge-"+forgeVersion+"-installer.jar";
this.mFullVersion = forgeVersion;
}

public NeoForgeDownloadTask(ModloaderDownloadListener listener, String gameVersion, String loaderVersion) {
this.mListener = listener;
this.mLoaderVersion = loaderVersion;
this.mGameVersion = gameVersion;
}
@Override
public void run() {
if(determineDownloadUrl()) {
downloadForge();
}
ProgressLayout.clearProgress(ProgressLayout.INSTALL_MODPACK);
}

@Override
public void updateProgress(int curr, int max) {
int progress100 = (int)(((float)curr / (float)max)*100f);
ProgressKeeper.submitProgress(ProgressLayout.INSTALL_MODPACK, progress100, R.string.forge_dl_progress, mFullVersion);
}

private void downloadForge() {
ProgressKeeper.submitProgress(ProgressLayout.INSTALL_MODPACK, 0, R.string.forge_dl_progress, mFullVersion);
try {
File destinationFile = new File(Tools.DIR_CACHE, "neoforge-installer.jar");
byte[] buffer = new byte[8192];
DownloadUtils.downloadFileMonitored(mDownloadUrl, destinationFile, buffer, this);
mListener.onDownloadFinished(destinationFile);
}catch (FileNotFoundException e) {
mListener.onDataNotAvailable();
} catch (IOException e) {
mListener.onDownloadError(e);
}
}

public boolean determineDownloadUrl() {
if(mDownloadUrl != null && mFullVersion != null) return true;
ProgressKeeper.submitProgress(ProgressLayout.INSTALL_MODPACK, 0, R.string.forge_dl_searching);
try {
if(!findVersion()) {
mListener.onDataNotAvailable();
return false;
}
}catch (IOException e) {
mListener.onDownloadError(e);
return false;
}
return true;
}

public boolean findVersion() throws IOException {
List<String> forgeVersions = ForgeUtils.downloadForgeVersions();
if(forgeVersions == null) return false;
String versionStart = mGameVersion+"-"+mLoaderVersion;
for(String versionName : forgeVersions) {
if(!versionName.startsWith(versionStart)) continue;
mFullVersion = versionName;
mDownloadUrl = ForgeUtils.getInstallerUrl(mFullVersion);
return true;
}
return false;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package net.kdt.pojavlaunch.modloaders;

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 com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;

public class NeoForgeVersionListAdapter extends BaseExpandableListAdapter implements ExpandableListAdapter {
private final LayoutInflater mLayoutInflater;
private final LinkedHashMap<String, LinkedHashSet<String>> minecraftToLoaderVersionsHashmap;
private LinkedHashSet<String> generatedHashSet = null;


public NeoForgeVersionListAdapter(List<String> forgeVersions, LayoutInflater layoutInflater) {
this.mLayoutInflater = layoutInflater;
minecraftToLoaderVersionsHashmap = new LinkedHashMap<>();
JsonArray versionsJsonArray = JsonParser.parseString(forgeVersions.get(0)).getAsJsonObject().getAsJsonArray("versions");

ArrayList<JsonElement> sortedVersionsList = new ArrayList<>();
for (JsonElement elem : versionsJsonArray) {
sortedVersionsList.add(elem);
}
Collections.sort(sortedVersionsList, (o1, o2) -> {
String versionString1 = ((JsonObject) o1).get("requires").getAsJsonArray().get(0).getAsJsonObject().get("equals").getAsString();
String versionString2 = ((JsonObject) o2).get("requires").getAsJsonArray().get(0).getAsJsonObject().get("equals").getAsString();
return versionString2.compareTo(versionString1); // Sorts by Minecraft version
});

for (JsonElement sortedVersionPick : sortedVersionsList) {
String loaderVersion = ((JsonObject) sortedVersionPick).get("version").getAsString();
String minecraftVersion = ((JsonObject) sortedVersionPick).get("requires").getAsJsonArray().get(0).getAsJsonObject().get("equals").getAsString();
if (minecraftToLoaderVersionsHashmap.containsKey(minecraftVersion)) {
minecraftToLoaderVersionsHashmap.get(minecraftVersion).add(loaderVersion);
} else {
generatedHashSet = new LinkedHashSet<>();
generatedHashSet.add(loaderVersion);
minecraftToLoaderVersionsHashmap.put(minecraftVersion, generatedHashSet);
}
}
}
@Override
public int getGroupCount() {
return minecraftToLoaderVersionsHashmap.size();
}

@Override
public int getChildrenCount(int i) {
return new ArrayList<>(minecraftToLoaderVersionsHashmap.values()).get(i).size();
}

@Override
public Object getGroup(int i) {
return getGameVersion(i);
}

@Override
public Object getChild(int i, int i1) {
return getForgeVersion(i, 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(getGameVersion(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(getForgeVersion(i, i1));
return convertView;
}

private String getGameVersion(int i) {
return minecraftToLoaderVersionsHashmap.keySet().toArray()[i].toString();
}

private String getForgeVersion(int i, int i1){
return new ArrayList<>(minecraftToLoaderVersionsHashmap.values()).get(i).toArray()[i1].toString();
}

@Override
public boolean isChildSelectable(int i, int i1) {
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,14 @@
android:layout_marginTop="@dimen/padding_large"
android:text="@string/modloader_dl_install_forge" />

<com.kdt.mcgui.MineButton
android:id="@+id/modded_profile_neoforge"
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_neoforge" />

<com.kdt.mcgui.MineButton
android:id="@+id/modded_profile_modpack"
android:layout_width="match_parent"
Expand Down
3 changes: 3 additions & 0 deletions app_pojavlauncher/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -450,4 +450,7 @@
<string name="change_account">Please change accounts to use this function</string>
<string name="no_minecraft_account_found">No Minecraft Account Found</string>
<string name="feature_requires_java_account">This feature requires a Microsoft account that owns Minecraft Java Edition.</string>
<string name="modloader_dl_install_neoforge">Create Neoforge profile</string>
<string name="neoforge_dl_select_version">Select NeoForge version</string>
<string name="neoforge_dl_no_installer">Sorry, but this version of NeoForge does not have an installer, which is not yet supported.</string>
</resources>