diff --git a/firestar/src/main/java/Bert.form b/firestar/src/main/java/Bert.form new file mode 100644 index 0000000..9aaad35 --- /dev/null +++ b/firestar/src/main/java/Bert.form @@ -0,0 +1,131 @@ + +
diff --git a/firestar/src/main/java/Bert.java b/firestar/src/main/java/Bert.java new file mode 100644 index 0000000..c9f78b0 --- /dev/null +++ b/firestar/src/main/java/Bert.java @@ -0,0 +1,243 @@ +/* + * Firestar Mod Manager + * Copyright (C) 2024 bonkmaykr + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ + +import javax.imageio.ImageIO; +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.image.BufferedImage; +import java.io.*; + +public class Bert implements ActionListener { + BufferedImage windowIcon; + public JFrame frame = new JFrame(); + private JPanel frameContainer; + private JButton cancelbtn; + private JButton downloadbtn; + private JRadioButton baseRad; + private JRadioButton patchRad; + private JRadioButton hdRad; + private JRadioButton furyRad; + private ButtonGroup radios = new ButtonGroup(); + + private JFrame invoker; + + public Bert(JFrame parent) { + parent.setEnabled(false); + this.invoker = parent; + + frame.add(frameContainer); // initialize window contents -- will be handled by IntelliJ IDEA + + frame.setSize(600, 300); // 1280 800 + frame.setTitle("Download Assets"); + frame.setResizable(false); + frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + frame.setLayout(new GridLayout()); + frame.setLocationRelativeTo(null); + frame.setAlwaysOnTop(true); + + radios.add(baseRad); + radios.add(patchRad); + radios.add(hdRad); + radios.add(furyRad); + + cancelbtn.addActionListener(this); + downloadbtn.addActionListener(this); + + try { + windowIcon = ImageIO.read(Main.class.getResourceAsStream("/titleIcon.png")); + frame.setIconImage(windowIcon); + } catch (IOException e) { + System.out.println("ERROR: Failed to find /resources/titleIcon.png. Window will not have an icon."); + } + + frame.setVisible(true); + frame.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) + { + parent.setEnabled(true); + e.getWindow().dispose(); + } + }); + + if (!new File(Main.inpath + "pkg2zip.exe").exists() || !new File(Main.inpath + "psvpfsparser.exe").exists()) { + JOptionPane.showMessageDialog(frame, "The decryption tool is missing.\nPlease select \"Get Dependencies\" in the Options menu.", "Error", JOptionPane.ERROR_MESSAGE); + invoker.setEnabled(true); + frame.dispose(); + } + } + + @Override + public void actionPerformed(ActionEvent actionEvent) { + if (actionEvent.getSource() == cancelbtn) { + invoker.setEnabled(true); + frame.dispose(); + } else if (actionEvent.getSource() == downloadbtn) { + int result = JOptionPane.showConfirmDialog(frame, "All existing PSARC dumps will be deleted and replaced by the new ones.\nThis download could take several minutes. Do you want to continue?", "Download Game Assets", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); + if (result == JOptionPane.NO_OPTION) {return;} + System.out.println("User requested download of assets. Deleting existing PSARCs"); + new File(Main.inpath + "data.psarc").delete(); + new File(Main.inpath + "data01.psarc").delete(); + new File(Main.inpath + "data02.psarc").delete(); + new File(Main.inpath + "dlc1.psarc").delete(); + new File(Main.inpath + "dlc2.psarc").delete(); + + Main.ArcTarget type; + Main.ArcKey key; + if (baseRad.isSelected()) { + type = Main.ArcTarget.BASE; + key = Main.ArcKey.BASE; + System.out.println("Begin download of data (Game version 1.0)"); + } else + if (patchRad.isSelected()) { + type = Main.ArcTarget.LATEST; + key = Main.ArcKey.LATEST; + System.out.println("Begin download of data02 (Game version 1.04)"); + } else + if (hdRad.isSelected()) { + type = Main.ArcTarget.ADDON_HD; + key = Main.ArcKey.ADDON_HD; + System.out.println("Begin download of dlc1 (HD DLC)"); + } else + if (furyRad.isSelected()) { + type = Main.ArcTarget.ADDON_HD_FURY; + key = Main.ArcKey.ADDON_HD_FURY; + System.out.println("Begin download of dlc2 (Fury DLC)"); + } else { + return; // fire hydrant + } + + frame.dispose(); + invoker.setVisible(false); + + Thread downloaderPopupThread = new Thread(new Runnable() { // run on separate thread to prevent GUI freezing + @Override + public void run() { + // download file + boolean downloader = new Fozzie().DownloadFile(type.toString(), Main.inpath, "asset.pkg"); + if (!downloader) { + // cleanup + new File(Main.inpath + "asset.pkg").delete(); + + // restore controls + invoker.setEnabled(true); + invoker.setVisible(true); + invoker.toFront(); + invoker.repaint(); + return; + } + + // dump contents + System.out.println("Extracting asset.pkg"); + Process p; + try { + if (!Main.windows) {p = Runtime.getRuntime().exec(new String[]{"bash","-c","cd " + Main.inpath + ";wine pkg2zip.exe -x asset.pkg " + key.toString()});} + else {p = Runtime.getRuntime().exec(new String[]{Main.inpath + "pkg2zip.exe", "-x", "asset.pkg", key.toString()}, null, new File(Main.inpath)); + InputStream debugin = new BufferedInputStream(p.getInputStream()); + FileOutputStream debugout = new FileOutputStream(Main.inpath + "log1.txt"); + int c; + while ((c = debugin.read()) != -1) { + debugout.write(c); + } + debugin.close(); + debugout.close(); + } //inpath cannot change here + p.waitFor(); + } catch (Exception e) { + System.out.println(e.getMessage()); + JOptionPane.showMessageDialog(invoker, "CRITICAL FAILURE: " + e.getMessage(), "Fatal Error", JOptionPane.ERROR_MESSAGE); + new File(Main.inpath + "asset.pkg").delete(); + invoker.setEnabled(true); + invoker.setVisible(true); + invoker.toFront(); + invoker.repaint(); + return; + } + + // decrypt + System.out.println("Decrypting asset.pkg"); + String extracted; + String name; + if (type == Main.ArcTarget.BASE) { + extracted = "app/PCSA00015"; + name = "data.psarc"; + } else if (type == Main.ArcTarget.LATEST) { + extracted = "patch/PCSA00015"; + name = "data02.psarc"; + } else if (type == Main.ArcTarget.ADDON_HD) { + extracted = "addcont/PCSA00015/DLC1W2048PACKAGE"; + name = "dlc1.psarc"; + } else if (type == Main.ArcTarget.ADDON_HD_FURY) { + extracted = "addcont/PCSA00015/DLC2W2048PACKAGE"; + name = "dlc2.psarc"; + } else { + System.out.println("Internal Error: Bert got dementia. Get a programmer!"); + JOptionPane.showMessageDialog(invoker, "Internal Error: Bert got dementia. Get a programmer!", "Fatal Error", JOptionPane.ERROR_MESSAGE); + new File(Main.inpath + "asset.pkg").delete(); + new File(Main.inpath + "app/").delete(); + new File(Main.inpath + "patch/").delete(); + new File(Main.inpath + "addcont/").delete(); + invoker.setEnabled(true); + invoker.setVisible(true); + invoker.toFront(); + invoker.repaint(); + return; + } + try { + if (!Main.windows) {p = Runtime.getRuntime().exec(new String[]{"bash","-c","cd " + Main.inpath + ";wine psvpfsparser.exe -i " + extracted + " -o ./temp/ -z " + key.toString() + " -f cma.henkaku.xyz"});} + else {p = Runtime.getRuntime().exec(new String[]{Main.inpath + "psvpfsparser.exe", "-i", extracted, "-o", "./temp/", "-z", key.toString(), "-f", "cma.henkaku.xyz"}, null, new File(Main.inpath));} + p.waitFor(); + } catch (Exception e) { + System.out.println(e.getMessage()); + JOptionPane.showMessageDialog(invoker, "CRITICAL FAILURE: " + e.getMessage(), "Fatal Error", JOptionPane.ERROR_MESSAGE); + new File(Main.inpath + "asset.pkg").delete(); + new File(Main.inpath + "app/").delete(); + new File(Main.inpath + "patch/").delete(); + new File(Main.inpath + "addcont/").delete(); + invoker.setEnabled(true); + invoker.setVisible(true); + invoker.toFront(); + invoker.repaint(); + return; + } + + // stage & cleanup + System.out.println("Cleaning up"); + new File(Main.inpath + "asset.pkg").delete(); + new File(Main.inpath + "temp/PSP2/" + name).renameTo(new File(Main.inpath + name)); + Main.deleteDir(new File(Main.inpath + "addcont/")); + Main.deleteDir(new File(Main.inpath + "patch/")); + Main.deleteDir(new File(Main.inpath + "app/")); + Main.deleteDir(new File(Main.inpath + "temp/")); + + // restore controls + JOptionPane.showMessageDialog(frame, "Assets downloaded successfully.", "Download Complete", JOptionPane.INFORMATION_MESSAGE); + invoker.setEnabled(true); + invoker.setVisible(true); + invoker.toFront(); + invoker.repaint(); + } + }); + downloaderPopupThread.start(); + } + } +} diff --git a/firestar/src/main/java/Fozzie.java b/firestar/src/main/java/Fozzie.java index 7d996c2..ea1681c 100644 --- a/firestar/src/main/java/Fozzie.java +++ b/firestar/src/main/java/Fozzie.java @@ -16,8 +16,10 @@ * along with this program. If not, see https://www.gnu.org/licenses/. */ +import javax.imageio.ImageIO; import javax.swing.*; import java.awt.*; +import java.awt.image.BufferedImage; import java.io.*; import java.net.MalformedURLException; import java.net.URL; @@ -27,6 +29,7 @@ import java.nio.file.Paths; import java.nio.file.StandardCopyOption; public class Fozzie { + BufferedImage windowIcon; private JFrame frame = new JFrame(); public JProgressBar progressBar; private JPanel frameContainer; @@ -36,21 +39,23 @@ public class Fozzie { private int contentLength; private InputStream inputStream; - //public File output; - public boolean backgroundDone = false; boolean DownloadFile(String url, String odir, String oname) { - //output = o; - frame.add(frameContainer); frame.setSize(300, 100); - frame.setTitle("Firestar Mod Manager"); + frame.setTitle("Download in Progress"); frame.setResizable(false); frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); frame.setLayout(new GridLayout()); frame.setLocationRelativeTo(null); frame.setAlwaysOnTop(true); + try { + windowIcon = ImageIO.read(Main.class.getResourceAsStream("/titleIcon.png")); + frame.setIconImage(windowIcon); + } catch (IOException e) { + System.out.println("ERROR: Failed to find /resources/titleIcon.png. Window will not have an icon."); + } frame.setVisible(true); label.setText("Downloading \"" + oname + "\""); diff --git a/firestar/src/main/java/Main.java b/firestar/src/main/java/Main.java index 8e7dc68..f2e4997 100644 --- a/firestar/src/main/java/Main.java +++ b/firestar/src/main/java/Main.java @@ -31,17 +31,48 @@ public class Main { // Build Information public static final String vstr = "Release 1.3"; public static final String vcode = "Tetsuo"; - public static final int vint = 0; + public static final int vint = 1; // User Settings // TODO: replace with user preference when config i/o is done // also please double check that outpath is actually valid public static String outpath = System.getProperty("user.home") + "/.firestar/out/"; //game assets location - public static String inpath = System.getProperty("user.home") + "/.firestar/"; //game assets location + public final static String inpath = System.getProperty("user.home") + "/.firestar/"; //firestar folder -- do not change this public static boolean repatch; //are we in compat mode? public static boolean windows; //True = windows + public static int confvint = vint; //public static String psarc; //sdk location + public enum ArcTarget { // install target for 2048, type used by downloader + BASE("http://zeus.dl.playstation.net/cdn/UP9000/PCSA00015_00/NYEoaBGfiWymSEVZKxoyrKyBFsZNoFqxdyAIpZayZYuLLbCAArYrYXjPNhKCfXcONmhIZzZEeArycSrjiJOuNMWuWsDONUxMIQtMk.pkg"), + LATEST("http://gs.ww.np.dl.playstation.net/ppkg/np/PCSA00015/PCSA00015_T5/a4b7d9e35ed56e86/UP9000-PCSA00015_00-WIPEOUT2048BASE0-A0104-V0100-059564fcab8ce66d19b5a563e92677e581313205-PE.pkg"), + ADDON_HD("http://zeus.dl.playstation.net/cdn/UP9000/PCSA00015_00/JYMqGNXUKqHEyNLjbOgrWcJdnQJUMzgadRFWekbWFBXAwMeGikOyiHkXKogKIfqGhtNwKgmNWwwcrJORmRUTDzylBPwjGVnVjyDfh.pkg"), + ADDON_HD_FURY("http://zeus.dl.playstation.net/cdn/UP9000/PCSA00015_00/IAoJQaDpySenBmQCKiqecEPMzSdPfPcdXupxZXLTYYTuRgtsdTaHxbeejwGKRQpjJOKBdMMFzSoeEhsHYxNUasQrEzkZPeBxUEqnp.pkg"); + + private final String value; + ArcTarget(final String value) {this.value = value;}; + + @Override + public String toString() { + return value; + } + } + + public enum ArcKey { // install target for 2048, type used by downloader + BASE("KO5ifR1dQ+eHBlgi6TI0Bdkf7hng6h8aYmRgYuHkCLQNn/9ufV+01fmzjNSmwuVHnO4dEBuN8cENACqVFcgA"), + LATEST("KO5ifR1dQ+eHBlgi6TI0Bdkf7hng6h8aYmRgYuHkCLQNn/9ufV+01fmzjNSmwuVHnO4dEBuN8cENACqVFcgA"), + ADDON_HD("KO5ifR1dQ+eHBlgi6TI0Bdnv4uNsGG5kYGIR4Ojs7ejuis9/anXfuudVNvzgdu+9z1z+asJojA9uAACgRhTl"), + ADDON_HD_FURY("KO5ifR1dQ+eHBlgi6TI0Bdnv4uNsFG5kYGIR4Ojs7ejuis9/3fydBRm3eCJX7biz/vVTm/2jMT64AQCCYhVy"); + + private final String value; + ArcKey(final String value) {this.value = value;}; + + @Override + public String toString() { + return value; + } + } + public class Mod { public String path; // file name public int version = 1; @@ -88,15 +119,6 @@ public class Main { fExo2 = new Font("Arial", Font.PLAIN, 12); } - // download dependencies if we know we haven't been here before - // will also need to call this if a needed file is missing before use - // - // mostly for testing. will move to onboarding screen later - if (!new File(System.getProperty("user.home") + "/.firestar/").isDirectory()) { - new File(System.getProperty("user.home") + "/.firestar/").mkdirs(); - downloadDependencies(); - } - // check and load configs File fConf = new File(System.getProperty("user.home") + "/.firestar/firestar.conf"); if (!fConf.isFile()) { @@ -127,7 +149,7 @@ public class Main { try { JSONObject container = new JSONObject(new String(Files.readAllBytes(Paths.get(System.getProperty("user.home") + "/.firestar/firestar.conf")))); System.out.println(container.toString()); // debug - int confvint = (int) container.get("version"); // used for converting configs between program versions later down the line + confvint = (int) container.get("version"); // used for converting configs between program versions later down the line outpath = container.get("2048path").toString(); repatch = (boolean) container.get("safemode"); windows = (boolean) container.get("isWin32"); @@ -142,7 +164,7 @@ public class Main { try { JSONObject container = new JSONObject(new String(Files.readAllBytes(Paths.get(System.getProperty("user.home") + "/.firestar/firestar.conf")))); System.out.println(container.toString()); // debug - int confvint = (int) container.get("version"); // used for converting configs between program versions later down the line + confvint = (int) container.get("version"); // used for converting configs between program versions later down the line outpath = container.get("2048path").toString(); repatch = (boolean) container.get("safemode"); windows = (boolean) container.get("isWin32"); @@ -165,7 +187,15 @@ public class Main { file.delete(); } - public static boolean downloadDependencies () { + public static void downloadDependenciesBeforeSetVisible(JFrame invoker) { + invoker.setVisible(false); + Main.downloadDependencies(); + invoker.setVisible(true); + confvint = vint; + Main.writeConf(); + } + + public static boolean downloadDependencies () { // todo: CHECKSUM!!!! THESE ARE EXECUTABLES!!!!!!!!!!! DON'T ALLOW MALWARE!!!! boolean downloader = new Fozzie().DownloadFile("https://bonkmaykr.worlio.com/http/firestar/firesdk.zip", System.getProperty("user.home") + "/.firestar/", "firesdk.zip"); if (!downloader) {return false;} @@ -181,4 +211,8 @@ public class Main { return true; } + + public static boolean callDownloaderStatically (String url, String folder, String name) { + return new Fozzie().DownloadFile(url, folder, name); + } } \ No newline at end of file diff --git a/firestar/src/main/java/MissPiggy.java b/firestar/src/main/java/MissPiggy.java index fcf2843..c85ba2c 100644 --- a/firestar/src/main/java/MissPiggy.java +++ b/firestar/src/main/java/MissPiggy.java @@ -176,7 +176,24 @@ public class MissPiggy implements ActionListener { frame.setDefaultCloseOperation(EXIT_ON_CLOSE); frame.setLayout(new GridLayout()); frame.setLocationRelativeTo(null); - frame.setVisible(true); + + if (Main.confvint == 0){ // nag + int result = JOptionPane.showConfirmDialog(frame, "Firestar needs to download additional software to function. Setup is automatic and will only take a few minutes.\nIf you select NO, you will have to download additional dependencies later on.\n\nContinue?", "Firestar Setup", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); + if (result == JOptionPane.YES_OPTION) { + Thread downloaderPopupThread = new Thread(new Runnable() { + @Override + public void run() { + Main.downloadDependenciesBeforeSetVisible(frame); + } + }); + downloaderPopupThread.start(); + } else { + Main.writeConf(); // don't warn again + frame.setVisible(true); // no fuck off + } + } else { + frame.setVisible(true); // don't nag + } } public void InitializeModListStructure() { @@ -369,6 +386,22 @@ public class MissPiggy implements ActionListener { frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); frame.setEnabled(false); + if (!new File(Main.inpath + "psp2psarc.exe").exists()) { + JOptionPane.showMessageDialog(frame, "psp2psarc is missing.\nPlease select \"Get Dependencies\" in the Options menu.", "Error", JOptionPane.ERROR_MESSAGE); + wrapUpDeployment(); + return; + } + + if (!new File(Main.inpath + "data.psarc").exists() && + !new File(Main.inpath + "data01.psarc").exists() && + !new File(Main.inpath + "data02.psarc").exists() && + !new File(Main.inpath + "dlc1.psarc").exists() && + !new File(Main.inpath + "dlc2.psarc").exists()) { + JOptionPane.showMessageDialog(frame, "You have no PSARCs.\nPlease dump your copy of WipEout 2048 or download a PSARC from the Options menu.", "Error", JOptionPane.ERROR_MESSAGE); + wrapUpDeployment(); + return; + } + // start new Gonzo().DeployMods(this); } diff --git a/firestar/src/main/java/Rowlf.java b/firestar/src/main/java/Rowlf.java index 60b0b85..5a79b1e 100644 --- a/firestar/src/main/java/Rowlf.java +++ b/firestar/src/main/java/Rowlf.java @@ -52,7 +52,7 @@ public class Rowlf { "\n" + "Special thanks to:\n" + "ThatOneBonk, for Thallium and for modding help\n" + - "Wirlaburla, for web hosting and being awesome\n" + + "Wirlaburla, for web hosting and code assistance\n" + "Psygnosis, for making our favorite game ever\n" + "and to all the PSVita hackers who made this possible"); informationText.setHighlighter(null); diff --git a/firestar/src/main/java/Waldorf.form b/firestar/src/main/java/Waldorf.form index d703b90..28436fc 100644 --- a/firestar/src/main/java/Waldorf.form +++ b/firestar/src/main/java/Waldorf.form @@ -1,7 +1,7 @@ diff --git a/firestar/src/main/java/Waldorf.java b/firestar/src/main/java/Waldorf.java index 6c05098..bb93b5c 100644 --- a/firestar/src/main/java/Waldorf.java +++ b/firestar/src/main/java/Waldorf.java @@ -16,8 +16,6 @@ * along with this program. If not, see https://www.gnu.org/licenses/. */ -import org.json.JSONObject; - import javax.imageio.ImageIO; import javax.swing.*; import java.awt.*; @@ -39,6 +37,8 @@ public class Waldorf implements ActionListener { private JTextField fOutpath; private JButton resetbtn; private JButton bOpenFolder; + private JButton dwnSDKbtn; + private JButton dwnARCbtn; MissPiggy invoker; public void Action(MissPiggy inv) { @@ -65,6 +65,9 @@ public class Waldorf implements ActionListener { resetbtn.addActionListener(this); bOpenFolder.addActionListener(this); + dwnARCbtn.addActionListener(this); + dwnSDKbtn.addActionListener(this); + fOutpath.setText(Main.outpath); frame.setVisible(true); @@ -91,7 +94,7 @@ public class Waldorf implements ActionListener { invoker.frame.setEnabled(true); frame.dispose(); } else - if (actionEvent.getSource() == resetbtn) { + if (actionEvent.getSource() == resetbtn) { // todo: delete firesdk int result = JOptionPane.showConfirmDialog(frame,"Are you sure you want to redo the initial setup?", "Restore Default Settings", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); if (result == JOptionPane.YES_OPTION) { new File(System.getProperty("user.home") + "/.firestar/firestar.conf").delete(); @@ -107,6 +110,21 @@ public class Waldorf implements ActionListener { } catch (IOException e) { throw new RuntimeException(e); } + } else + if (actionEvent.getSource() == dwnARCbtn) { + new Bert(invoker.frame); + frame.dispose(); + } else + if (actionEvent.getSource() == dwnSDKbtn) { + Thread downloaderPopupThread = new Thread(new Runnable() { + @Override + public void run() { + Main.downloadDependenciesBeforeSetVisible(invoker.frame); + invoker.frame.setEnabled(true); + } + }); + downloaderPopupThread.start(); + frame.dispose(); } } }