/* * 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.swing.*; import javax.swing.text.StyleConstants; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.*; import java.math.BigInteger; import java.net.URL; import java.nio.file.*; import java.security.*; // handles setup window public class Kermit implements ActionListener { public enum Pages { AGREEMENT(0), EXPORT_MODE(1), SDK_INSTALL(2), SDK_FAILURE(3), WHAT_OS(4), EXPORT_LOCATION(5), IMPORT_LOCATION(6), DONE(7); public final int value; private Pages(int i) { this.value = i; } } JDialog frame = new JDialog(); JButton button = new JButton("Next"); JButton button2 = new JButton("Quit"); JButton button3 = new JButton("Cancel"); JButton button4 = new JButton("Back"); JTextPane dialogText = new JTextPane(); JRadioButton buttonCompat = new JRadioButton("Compatibility (for consoles)"); JRadioButton buttonFast = new JRadioButton("Fast Mode (for Vita3K emulator)"); ButtonGroup radg1 = new ButtonGroup(); JRadioButton buttonNoWine = new JRadioButton("No, I use Microsoft Windows"); JRadioButton buttonHaveWine = new JRadioButton("Yes, I have a POSIX system with WINE."); ButtonGroup radg2 = new ButtonGroup(); JTextField pathInput = new JTextField(); JButton openconfigfolderbutton = new JButton("Open Firestar Folder"); Pages page = Pages.AGREEMENT; javax.swing.text.StyledDocument document = dialogText.getStyledDocument(); javax.swing.text.SimpleAttributeSet align= new javax.swing.text.SimpleAttributeSet(); public void setup(File fConf) { //File variable is redundant. unused frame.getContentPane().setBackground(Color.WHITE); radg1.add(buttonCompat); radg1.add(buttonFast); radg2.add(buttonNoWine); radg2.add(buttonHaveWine); button.addActionListener(this); button2.addActionListener(this); button3.addActionListener(this); button4.addActionListener(this); buttonCompat.addActionListener(this); buttonFast.addActionListener(this); buttonNoWine.addActionListener(this); buttonHaveWine.addActionListener(this); openconfigfolderbutton.addActionListener(this); changePage(Pages.AGREEMENT); } @Override public void actionPerformed(ActionEvent actionEvent) { if (actionEvent.getSource() == button2){ System.exit(0); } else if (actionEvent.getSource() == button){ //frame.removeAll(); freezes?? switch (page) { case AGREEMENT: button.setVisible(false);frame.remove(button); button2.setVisible(false);frame.remove(button2); dialogText.setVisible(false);frame.remove(dialogText); changePage(Pages.SDK_INSTALL); // EXPORT_MODE break; case EXPORT_MODE: button.setVisible(false);frame.remove(button); button3.setVisible(false);frame.remove(button3); dialogText.setVisible(false);frame.remove(dialogText); buttonCompat.setVisible(false);frame.remove(buttonCompat); buttonFast.setVisible(false);frame.remove(buttonFast); if (Main.repatch) { changePage(Pages.SDK_INSTALL); } else {changePage(Pages.EXPORT_LOCATION);} break; case SDK_INSTALL: break; case SDK_FAILURE: break; case WHAT_OS: button.setVisible(false);frame.remove(button); button3.setVisible(false);frame.remove(button3); dialogText.setVisible(false);frame.remove(dialogText); break; case EXPORT_LOCATION: button.setVisible(false);frame.remove(button); button3.setVisible(false);frame.remove(button3); dialogText.setVisible(false);frame.remove(dialogText); buttonNoWine.setVisible(false);frame.remove(buttonNoWine); buttonHaveWine.setVisible(false);frame.remove(buttonHaveWine); changePage(Pages.IMPORT_LOCATION); break; case IMPORT_LOCATION: Main.outpath = pathInput.getText(); pathInput.setText(""); dialogText.setVisible(false);frame.remove(dialogText); pathInput.setVisible(false);frame.remove(pathInput); changePage(Pages.DONE); break; case DONE: new MissPiggy().Action(); page = Pages.AGREEMENT; //set it here since we're disposing of the entire thing frame.dispose(); break; default: throw new UnsupportedOperationException("ERROR: Undefined behavior in Kermit's event listener. Get a programmer!"); //JOptionPane OhShit = new JOptionPane.showMessageDialog(null, "Fuck"); } } else if (actionEvent.getSource() == button4){ //frame.removeAll(); freezes?? switch (page) { // todo remove elements when going to previous page case EXPORT_MODE: changePage(Pages.AGREEMENT); break; case SDK_INSTALL: changePage(Pages.EXPORT_MODE); break; case SDK_FAILURE: break; case WHAT_OS: changePage(Pages.SDK_INSTALL); break; case EXPORT_LOCATION: if (Main.repatch) {changePage(Pages.WHAT_OS);} else {changePage(Pages.EXPORT_MODE);} break; case IMPORT_LOCATION: changePage(Pages.EXPORT_LOCATION); break; default: throw new UnsupportedOperationException("ERROR: Undefined behavior in Kermit's event listener. Get a programmer!"); //JOptionPane OhShit = new JOptionPane.showMessageDialog(null, "Fuck"); } } else if (actionEvent.getSource() == buttonCompat) { Main.repatch = true; button.setEnabled(true); } else if (actionEvent.getSource() == buttonFast) { Main.repatch = false; button.setEnabled(true); } else if (actionEvent.getSource() == buttonHaveWine) { Main.windows = true; button.setEnabled(true); } else if (actionEvent.getSource() == buttonNoWine) { Main.windows = false; button.setEnabled(true); }else if (actionEvent.getSource() == openconfigfolderbutton) { try { Desktop.getDesktop().open(new File(Main.inpath)); } catch (IOException e) { throw new RuntimeException(e); } } } public void changePage(Pages GoTo){ switch (GoTo) { case AGREEMENT: page = Pages.AGREEMENT; button.setVisible(true); button.setBounds(292, 343, 300, 30); frame.add(button); button2.setVisible(true); button2.setBounds(0, 343, 292, 30); frame.add(button2); dialogText.setVisible(true); dialogText.setHighlighter(null); dialogText.getCaret().setVisible(false); dialogText.setFocusable(false); dialogText.setBounds(0, 0, 592, 343); //dialogText.setAlignmentX(JComponent.CENTER_ALIGNMENT); //dialogText.setAlignmentY(JComponent.CENTER_ALIGNMENT); StyleConstants.setAlignment(align, StyleConstants.ALIGN_CENTER); document.setParagraphAttributes(0, document.getLength(), align, false); //dialogText.setText("Aww Fiddlesticks, what now?"); dialogText.setText("WELCOME TO FIRESTAR\n\n" + "This initial setup guide will help you prepare your Playstation Vita, Playstation TV, or Vita3K emulator to play WipEout mods.\n\n Before continuing, please read the decryption guide at:\nhttps://git.worlio.com/bonkmaykr/firestar/wiki/Decrypting-Original-PSARC-Files\nsince you will need these files in order to use Firestar.\n\n" + "If you encounter any issues while using Firestar you may contact the author at bonkmaykr@screwgravity.net"); frame.add(dialogText); frame.setSize(600, 400); frame.setTitle("Initial Setup"); frame.setAlwaysOnTop(true); frame.setDefaultCloseOperation(0); frame.setResizable(false); frame.setLayout(null); frame.setVisible(true); break; case EXPORT_MODE: page = Pages.EXPORT_MODE; button.setVisible(true); button.setEnabled(false); button.setBounds(292, 343, 300, 30); frame.add(button); button3.setVisible(false); button3.setBounds(0, 343, 292, 30); frame.add(button3); dialogText.setVisible(true); dialogText.setHighlighter(null); dialogText.getCaret().setVisible(false); dialogText.setFocusable(false); dialogText.setBounds(0, 40, 592, 150); StyleConstants.setAlignment(align, StyleConstants.ALIGN_CENTER); document.setParagraphAttributes(0, document.getLength(), align, false); dialogText.setText("Please choose how Firestar will deploy your mods.\n\n" + "Compatibility mode requires software from the PSVita SDK, but works on real hardware.\n" + "Fast mode is easiest, but won't work on FAT32/exFAT drives like what the Vita uses."); frame.add(dialogText); buttonCompat.setBounds(40, 200, 300, 25); buttonFast.setBounds(40, 230, 300, 25); buttonCompat.setBackground(Color.WHITE); buttonFast.setBackground(Color.WHITE); buttonCompat.setVisible(true); buttonFast.setVisible(true); frame.add(buttonCompat); frame.add(buttonFast); frame.setSize(600, 400); frame.setTitle("Initial Setup"); frame.setAlwaysOnTop(true); frame.setDefaultCloseOperation(0); frame.setResizable(false); frame.setLayout(null); frame.setLocationRelativeTo(null); frame.setVisible(true); break; case SDK_INSTALL: page = Pages.SDK_INSTALL; dialogText.setVisible(true); dialogText.setHighlighter(null); dialogText.getCaret().setVisible(false); dialogText.setFocusable(false); dialogText.setBounds(0, 40, 592, 300); StyleConstants.setAlignment(align, StyleConstants.ALIGN_CENTER); document.setParagraphAttributes(0, document.getLength(), align, false); dialogText.setText("Firestar is downloading important dependencies. Please wait."); //some kind of race condition prevents this from displaying? frame.add(dialogText); frame.setSize(600, 400); frame.setTitle("Initial Setup"); frame.setAlwaysOnTop(true); frame.setDefaultCloseOperation(0); frame.setResizable(false); frame.setLayout(null); frame.setVisible(true); //md5 checksum 4ef707b2dba6944a726d46950aaddfd2 try { File downloadLocationDir = new File(System.getProperty("user.home") + "/.firestar/"); File downloadLocation = new File(System.getProperty("user.home") + "/.firestar/psp2psarc.exe"); downloadLocationDir.mkdirs(); if (!downloadLocation.isFile()) { downloadLocation.createNewFile(); } BufferedInputStream in = new BufferedInputStream(new URL("http://bonkmaykr.worlio.com/http/firestar/psp2psarc.exe").openStream()); //FileOutputStream downloadOutput = new FileOutputStream(new File(System.getProperty("user.home") + "/.firestar/psp2psarc.exe")); Files.copy(in, Paths.get(System.getProperty("user.home") + "/.firestar/psp2psarc.exe"), StandardCopyOption.REPLACE_EXISTING); int tests = 0; String checksum =""; while (tests < 60 /*while(true)*/) { byte[] hash = MessageDigest.getInstance("MD5").digest(Files.readAllBytes(Paths.get(System.getProperty("user.home") + "/.firestar/psp2psarc.exe"))); checksum = new BigInteger(1, hash).toString(16); System.out.println("Downloaded psp2psarc.exe successfully."); if(checksum.equals("4ef707b2dba6944a726d46950aaddfd2")) {changePage(Pages.WHAT_OS);break;} Thread.sleep(20); tests++; } if(checksum.equals("4ef707b2dba6944a726d46950aaddfd2")) {changePage(Pages.WHAT_OS);} else { System.out.println("ERROR: Failed to download PSARC tool. Check connection and ensure the file is not corrupt or infected."); dialogText.setText("Firestar tried to download important files needed for operation, but they were either corrupted or did not finish.\n" + "\n\nYou will need to manually install psp2psarc.exe into your Firestar config folder after setup is complete! Or, you can retry the download later."); //frame.setDefaultCloseOperation(DISPOSE_ON_CLOSE); button.setVisible(true); button.setBounds(292, 343, 300, 30); frame.add(button); } } catch (Exception e) { System.out.println("Failed to download PSARC tool due to an internal error:" + e.getMessage()); dialogText.setText("An error has occured.\n" + e.getMessage() + "\n\nYou will need to manually install psp2psarc.exe into your Firestar config folder after setup is complete!!!"); //frame.setDefaultCloseOperation(DISPOSE_ON_CLOSE); button.setVisible(true); button.setBounds(292, 343, 300, 30); frame.add(button); } break; case SDK_FAILURE: page = Pages.SDK_FAILURE; //unused break; case WHAT_OS: page = Pages.WHAT_OS; //do window clear here since the page is never called by the event handler button.setVisible(false);frame.remove(button); button3.setVisible(false);frame.remove(button3); dialogText.setVisible(false);frame.remove(dialogText); //check if this is windows or not if(System.getProperty("os.name").contains("Windows")) {Main.windows = true;System.out.println("Assuming we should NOT use WINE based on known system variables.");changePage(Pages.EXPORT_LOCATION);} else {Main.windows = false;System.out.println("Assuming we should use WINE based on known system variables.");changePage(Pages.EXPORT_LOCATION);} case EXPORT_LOCATION: page = Pages.EXPORT_LOCATION; button.setVisible(true); button.setBounds(292, 343, 300, 30); frame.add(button); button3.setVisible(false); button3.setBounds(0, 343, 292, 30); frame.add(button3); dialogText.setVisible(true); dialogText.setHighlighter(null); dialogText.getCaret().setVisible(false); dialogText.setFocusable(false); dialogText.setBounds(30, 40, 542, 150); StyleConstants.setAlignment(align, StyleConstants.ALIGN_CENTER); document.setParagraphAttributes(0, document.getLength(), align, false); dialogText.setText("Now enter the location of your game's asset folder.\n" + "This can be your install directory on your emulator, your repatch folder on your Vita memory card, or a temporary directory you'd like to copy over yourself.\n\n" + "PLEASE DO NOT POINT THIS DIRECTLY TO WHERE THE GAME IS INSTALLED ON A REAL VITA\n" + "(ux0:/app, ux0:/patch or ux0:/addcont)\n" + "AS THIS WILL CORRUPT YOUR GAME AND YOU WILL NEED TO REINSTALL IT.\nDoing this on an emulator is fine."); frame.add(dialogText); pathInput.setVisible(true); pathInput.setBounds(30,200,542,30); frame.add(pathInput); frame.setSize(600, 400); frame.setTitle("Initial Setup"); frame.setAlwaysOnTop(true); frame.setDefaultCloseOperation(0); frame.setResizable(false); frame.setLayout(null); frame.setVisible(true); break; case IMPORT_LOCATION: // I think for Fast Mode this step may be unnecessary? look into alternatives perhaps page = Pages.IMPORT_LOCATION; pathInput.setVisible(false); //GET OUT OF MY HEAD button.setVisible(true); button.setBounds(292, 343, 300, 30); frame.add(button); button3.setVisible(false); button3.setBounds(0, 343, 292, 30); frame.add(button3); dialogText.setVisible(true); dialogText.setHighlighter(null); dialogText.getCaret().setVisible(false); dialogText.setFocusable(false); dialogText.setBounds(30, 40, 542, 200); StyleConstants.setAlignment(align, StyleConstants.ALIGN_CENTER); document.setParagraphAttributes(0, document.getLength(), align, false); dialogText.setText("You're almost done!\n\n" + "Please move all of your original PSARC files for WipEout (base game, patches, and HD Fury DLC) to the config folder and press Next when you are done.\n" + "Firestar will use these to generate new PSARCs in place of the old ones.\n\n" + "If you do not already have these files, please read:\nhttps://git.worlio.com/bonkmaykr/firestar/wiki/Decrypting-Original-PSARC-Files\nto acquire them."); frame.add(dialogText); //pathInput.setVisible(true); //pathInput.setBounds(30,200,542,30); //frame.add(pathInput); openconfigfolderbutton.setVisible(true); openconfigfolderbutton.setBounds(30,250,542,30); frame.add(openconfigfolderbutton); frame.setSize(600, 400); frame.setTitle("Initial Setup"); frame.setAlwaysOnTop(true); frame.setDefaultCloseOperation(0); frame.setResizable(false); frame.setLayout(null); frame.setVisible(true); break; case DONE: page = Pages.DONE; Main.writeConf(); // save changes //SERIOUS!!!!!!!!!!!!!! cleanup button.setVisible(false);frame.remove(button); button2.setVisible(false);frame.remove(button2); button3.setVisible(false);frame.remove(button3); button4.setVisible(false);frame.remove(button4); openconfigfolderbutton.setVisible(false);frame.remove(openconfigfolderbutton); pathInput.setVisible(false);frame.remove(pathInput); buttonFast.setVisible(false);frame.remove(buttonFast); buttonCompat.setVisible(false);frame.remove(buttonCompat); buttonHaveWine.setVisible(false);frame.remove(buttonHaveWine); buttonNoWine.setVisible(false);frame.remove(buttonNoWine); //congrations, your did it (party time) dialogText.setVisible(true); dialogText.setHighlighter(null); dialogText.getCaret().setVisible(false); dialogText.setFocusable(false); dialogText.setBounds(30, 40, 542, 200); StyleConstants.setAlignment(align, StyleConstants.ALIGN_CENTER); document.setParagraphAttributes(0, document.getLength(), align, false); dialogText.setText("Firestar is ready!\n\n" + "For technical support, see Help > Manual."); frame.add(dialogText); button.setVisible(true); button.setBounds(292, 343, 300, 30); button.setText("OK"); frame.add(button); frame.setSize(600, 400); frame.setTitle("Initial Setup"); frame.setAlwaysOnTop(true); frame.setDefaultCloseOperation(0); frame.setResizable(false); frame.setLayout(null); frame.setVisible(true); break; default: throw new UnsupportedOperationException("ERROR: Undefined behavior in Kermit.changePage(). Get a programmer!"); //JOptionPane OhShit = new JOptionPane.showMessageDialog(null, "Fuck"); } } }