package net.kdt.pojavlaunch; import java.io.*; import java.util.*; import java.util.concurrent.*; import org.lwjgl.glfw.CallbackBridge; import net.kdt.pojavlaunch.prefs.*; import net.kdt.pojavlaunch.uikit.*; import net.kdt.pojavlaunch.utils.*; import net.kdt.pojavlaunch.value.*; public class PLaunchApp { private static float currProgress, maxProgress; public static JMinecraftVersionList mVersionList; public static volatile JMinecraftVersionList.Version mVersion; public static boolean mIsAssetsProcessing = false; public static void main(String[] args) throws Throwable { // User might remove the minecraft folder, this can cause crashes, safety re-create it try { File mcDir = new File("/var/mobile/Documents/minecraft"); mcDir.mkdirs(); new File(Tools.DIR_ACCOUNT_NEW).mkdirs(); if (!new File(mcDir, "config_ver.txt").exists()) { Tools.write(mcDir.getAbsolutePath() + "/config_ver.txt", "1.16.5"); } } catch (IOException e) { e.printStackTrace(); } if (args[0].startsWith("/Applications/")) { System.out.println("We are on java now! Starting UI..."); UIKit.launchUI(args); } else { // Test on cmdline launchMinecraft(); } LauncherPreferences.loadPreferences(); } // Called from SurfaceViewController public static void launchMinecraft() { System.out.println("Saving GLES context"); JREUtils.saveGLContext(); System.out.println("Launching Minecraft " + mVersion.id); try { Tools.launchMinecraft(AccountJNI.CURRENT_ACCOUNT, mVersion); } catch (Throwable th) { Tools.showError(th); } } public static void installMinecraft() { new Thread(() -> { currProgress = 0; maxProgress = 0; UIKit.updateProgressSafe(0, "Finding a version"); String mcver = "1.16.5"; try { mcver = Tools.read(Tools.DIR_GAME_NEW + "/config_ver.txt"); } catch (IOException e) { UIKit.updateProgressSafe(0, "config_ver.txt not found, defaulting to Minecraft 1.16.5"); } AccountJNI.CURRENT_ACCOUNT.selectedVersion = mcver; try { AccountJNI.CURRENT_ACCOUNT.save(); } catch (IOException e) { e.printStackTrace(); } UIKit.updateProgressSafe(0, "Selected Minecraft version: " + mcver); try { Thread.sleep(1000); } catch (InterruptedException e) {} new File(Tools.DIR_HOME_VERSION + "/" + mcver).mkdirs(); JMinecraftVersionList.Version verInfo = null; try { final String downVName = "/" + mcver + "/" + mcver; String minecraftMainJar = Tools.DIR_HOME_VERSION + downVName + ".jar"; String verJsonDir = Tools.DIR_HOME_VERSION + downVName + ".json"; JAssets assets = null; UIKit.updateProgressSafe(0, "Downloading version list"); try { mVersionList = Tools.GLOBAL_GSON.fromJson(DownloadUtils.downloadString("https://launchermeta.mojang.com/mc/game/version_manifest.json"), JMinecraftVersionList.class); } catch (IOException e) { UIKit.updateProgressSafe(0, "Error: " + e.getMessage()); e.printStackTrace(); } verInfo = findVersion(mcver); if (verInfo.url != null && !new File(verJsonDir).exists() && mVersionList != null) { // mVersionList != null is for checking if user have network connection UIKit.updateProgressSafe(0, "Downloading " + mcver + ".json"); Tools.downloadFile(verInfo.url, verJsonDir); } mVersion = verInfo = Tools.getVersionInfo(mcver); try { UIKit.updateProgressSafe(0, "Downloading " + mcver + ".json assets info"); assets = downloadIndex(verInfo.assets, new File(Tools.ASSETS_PATH, "indexes/" + verInfo.assets + ".json")); } catch (IOException e) { UIKit.updateProgressSafe(0, "Error: " + e.getMessage()); e.printStackTrace(); } maxProgress = verInfo.libraries.length + 1 + (assets == null ? 0 : assets.objects.size()); File outLib; String libPathURL; for (final DependentLibrary libItem : verInfo.libraries) { if ( libItem.name.startsWith("net.java.jinput") || libItem.name.startsWith("org.lwjgl") ) { // Black list currProgress++; UIKit.updateProgressSafe(currProgress / maxProgress, "Ignored " + libItem.name); // Thread.sleep(100); } else { String[] libInfo = libItem.name.split(":"); String libArtifact = Tools.artifactToPath(libInfo[0], libInfo[1], libInfo[2]); outLib = new File(Tools.DIR_HOME_LIBRARY + "/" + libArtifact); outLib.getParentFile().mkdirs(); if (!outLib.exists()) { currProgress++; UIKit.updateProgressSafe(currProgress / maxProgress, "Downloading " + libItem.name); if (libItem.downloads == null || libItem.downloads.artifact == null) { MinecraftLibraryArtifact artifact = new MinecraftLibraryArtifact(); artifact.url = (libItem.url == null ? "https://libraries.minecraft.net/" : libItem.url) + libArtifact; libItem.downloads = new DependentLibrary.LibraryDownloads(artifact); } try { libPathURL = libItem.downloads.artifact.url; Tools.downloadFile(libPathURL, outLib.getAbsolutePath()); } catch (Throwable th) { th.printStackTrace(); UIKit.updateProgressSafe(currProgress / maxProgress, "Download failed"); } } } } currProgress++; UIKit.updateProgressSafe(currProgress / maxProgress, "Downloading " + mcver + ".jar"); File minecraftMainFile = new File(minecraftMainJar); if (!minecraftMainFile.exists() || minecraftMainFile.length() == 0l) { Tools.downloadFile(verInfo.downloads.values().toArray(new MinecraftClientInfo[0])[0].url, minecraftMainJar); } if (assets != null) { mIsAssetsProcessing = true; downloadAssets(assets, verInfo.assets, assets.map_to_resources ? new File(Tools.OBSOLETE_RESOURCES_PATH) : new File(Tools.ASSETS_PATH)); } // TODO download assets } catch (IOException e) { UIKit.updateProgressSafe(currProgress / maxProgress, "Download error, skipping"); e.printStackTrace(); } UIKit.launchMinecraftSurface(mVersion.arguments != null); }).start(); } private static int downloadedSs = 0; public static void downloadAssets(final JAssets assets, String assetsVersion, final File outputDir) throws IOException { ArrayBlockingQueue workQueue = new ArrayBlockingQueue<>(100); RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy(); final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 40, 500, TimeUnit.SECONDS, workQueue, handler); File hasDownloadedFile = new File(outputDir, "downloaded/" + assetsVersion + ".downloaded"); if (!hasDownloadedFile.exists()) { System.out.println("Assets begin time: " + System.currentTimeMillis()); Map assetsObjects = assets.objects; File objectsDir = new File(outputDir, "objects"); for (JAssetInfo asset : assetsObjects.values()) { threadPoolExecutor.execute(() -> { mIsAssetsProcessing = !UIKit.updateProgressSafe(currProgress / maxProgress, "Downloading " + assetsObjects.keySet().toArray(new String[0])[downloadedSs]); if (!mIsAssetsProcessing) { threadPoolExecutor.shutdownNow(); return; } try { if(!assets.map_to_resources) downloadAsset(asset, objectsDir); else downloadAssetMapped(asset,(assetsObjects.keySet().toArray(new String[0])[downloadedSs]),outputDir); } catch (IOException e) { e.printStackTrace(); mIsAssetsProcessing = false; } currProgress++; downloadedSs++; }); } hasDownloadedFile.getParentFile().mkdirs(); hasDownloadedFile.createNewFile(); System.out.println("Assets end time: " + System.currentTimeMillis()); } } public static final String MINECRAFT_RES = "https://resources.download.minecraft.net/"; public static JAssets downloadIndex(String versionName, File output) throws IOException { if (!output.exists()) { output.getParentFile().mkdirs(); DownloadUtils.downloadFile(mVersion.assetIndex != null ? mVersion.assetIndex.url : "https://s3.amazonaws.com/Minecraft.Download/indexes/" + versionName + ".json", output); } return Tools.GLOBAL_GSON.fromJson(Tools.read(output.getAbsolutePath()), JAssets.class); } public static void downloadAsset(JAssetInfo asset, File objectsDir) throws IOException { String assetPath = asset.hash.substring(0, 2) + "/" + asset.hash; File outFile = new File(objectsDir, assetPath); if (!outFile.exists()) { DownloadUtils.downloadFile(MINECRAFT_RES + assetPath, outFile); } } public static void downloadAssetMapped(JAssetInfo asset, String assetName, File resDir) throws IOException { String assetPath = asset.hash.substring(0, 2) + "/" + asset.hash; File outFile = new File(resDir,"/"+assetName); if (!outFile.exists()) { DownloadUtils.downloadFile(MINECRAFT_RES + assetPath, outFile); } } private static JMinecraftVersionList.Version findVersion(String version) { if (mVersionList != null) { for (JMinecraftVersionList.Version valueVer: mVersionList.versions) { if (valueVer.id.equals(version)) { return valueVer; } } } // Custom version, inherits from base. return Tools.getVersionInfo(version); } }