diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..b365ee4 --- /dev/null +++ b/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,5 @@ +eclipse.preferences.version=1 +encoding//src/test/java=UTF-8 +encoding//src/test/resources=UTF-8 +encoding/=UTF-8 +encoding/src=UTF-8 diff --git a/pom.xml b/pom.xml index c4558c4..5a04546 100644 --- a/pom.xml +++ b/pom.xml @@ -52,7 +52,16 @@ logback-classic 1.2.13 - + + commons-codec + commons-codec + 1.15 + + + com.google.guava + guava + 31.0.1-jre + src diff --git a/src/data/GuiData.java b/src/data/GuiData.java index 26846cf..64fc442 100644 --- a/src/data/GuiData.java +++ b/src/data/GuiData.java @@ -67,7 +67,7 @@ public class GuiData { public void IndexData(ArrayList migrate) throws IOException { DatabaseManager mgr = new DatabaseManager(); - mgr.queryData("levels"); + File filelength = new File("C:\\ExtremeDemonList\\levels"); File[] filelengthindex = filelength.listFiles(); diff --git a/src/gui/AttemptsProgress.java b/src/gui/AttemptsProgress.java new file mode 100644 index 0000000..f61b118 --- /dev/null +++ b/src/gui/AttemptsProgress.java @@ -0,0 +1,68 @@ +package gui; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JProgressBar; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; + +import data.FetchData; +import data.ManageFiles; + +public class AttemptsProgress { + + JProgressBar bar = new JProgressBar(); + JTextArea area = new JTextArea(); + JScrollPane scroll = new JScrollPane(area); + JFrame main = new JFrame("Updater"); + + + public void build() { + + + main.setSize(400, 300); + main.setLayout(null); + main.setResizable(false); + main.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); + + JLabel info = new JLabel("Speicherstand wird gelesen..."); + info.setBounds(120, 1, 500, 30); + + + area.setEditable(false); + area.setLineWrap(true); + area.setWrapStyleWord(true); + + + + scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); + scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); + scroll.setBounds(1, 60, 383, 201); + + FetchData data = new FetchData(); + + bar.setBounds(1, 29, 382, 30); + bar.setMinimum(0); + bar.setMaximum(data.allLevels().size() - 1); + bar.setStringPainted(true); + + main.add(info); + main.add(scroll); + main.add(bar); + main.setVisible(true); + + } + + public void update(String level, int attempts, int selection, int index) { + bar.setValue(index); + area.append(level + " >>> " + attempts + " Attempts\n"); + area.setCaretPosition(area.getDocument().getLength()); + } + + public void close() { + JOptionPane.showMessageDialog(null, "Attempts wurden erfolgreich übertragen.", "Fertig", JOptionPane.INFORMATION_MESSAGE); + main.dispose(); + } + +} diff --git a/src/gui/MainGUI.java b/src/gui/MainGUI.java index 6cf845b..4d5ea3f 100644 --- a/src/gui/MainGUI.java +++ b/src/gui/MainGUI.java @@ -229,7 +229,11 @@ public class MainGUI { @Override public void actionPerformed(ActionEvent e) { - data.modifyData(data.getLevelname().get(index), comp[index], Integer.parseInt(attempts.getText())); + if(!(comp[index] == Boolean.parseBoolean(data.getCompleted().get(index))) || !(attempts.getText().equals(data.getAttempts().get(index) + ""))) { + data.modifyData(data.getLevelname().get(index), comp[index], Integer.parseInt(attempts.getText())); + } + + if(!comp[index]) { contents.setBackground(Color.WHITE); diff --git a/src/gui/SettingsGui.java b/src/gui/SettingsGui.java index 58e6ef4..ff5786b 100644 --- a/src/gui/SettingsGui.java +++ b/src/gui/SettingsGui.java @@ -1,6 +1,17 @@ package gui; +import java.awt.Button; +import java.awt.Font; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.IOException; + import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JOptionPane; + +import readsafefile.SafeFileManager; +import settingsfunctions.ReadAttempts; public class SettingsGui { @@ -12,6 +23,78 @@ public class SettingsGui { settings.setSize(500, 500); settings.setVisible(true); + int val = 120; + int valold = 20; + + StringBuilder str = new StringBuilder(); + + int jbuffer = 0; + + for(int i = 0; i <= 3; i++) { + for(int j = 0; j <= 100; j++) { + str.append("_"); + jbuffer = j; + } + JLabel separator = new JLabel(str.toString()); + separator.setBounds(0, valold, 500, 30); + separator.setVisible(true); + settings.add(separator); + + valold += val; + + str.delete(0, jbuffer); + } + + JLabel datenbank = new JLabel("Spielstand"); + datenbank.setBounds(1, 10, 100, 30); + datenbank.setFont(new Font(null, Font.BOLD, 16)); + datenbank.setVisible(true); + + JLabel data = new JLabel("Datenbank"); + data.setBounds(1, 130, 100, 30); + data.setFont(new Font(null, Font.BOLD, 16)); + + Button refresh = new Button("Speicherstand neu laden"); + refresh.setBounds(250, 86, 150, 30); + refresh.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + SafeFileManager mgr = new SafeFileManager(); + try { + mgr.DecryptSafeFile(); + } catch (IOException e1) { + e1.printStackTrace(); + } + + } + + }); + + Button button = new Button("Attempts Indexieren"); + button.setBounds(60, 86, 150, 30); + button.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + + ReadAttempts atts = new ReadAttempts(); + try { + atts.readAttempts(); + } catch (IOException e1) { + e1.printStackTrace(); + } + + } + + }); + + Button delete = new Button("Datenbank löschen"); + delete.setBounds(150, 206, 150, 30); + + settings.add(button); + settings.add(datenbank); + settings.add(refresh); + settings.add(data); + settings.add(delete); } diff --git a/src/main/Main.java b/src/main/Main.java index 74a55f2..7528468 100644 --- a/src/main/Main.java +++ b/src/main/Main.java @@ -1,6 +1,7 @@ package main; import java.io.IOException; +import java.util.zip.DataFormatException; import data.FetchData; import data.ManageFiles; @@ -8,11 +9,14 @@ import database.DatabaseManager; import filestructure.CreateFileStructure; import gui.LoadMenu; import preload.PreChecks; +import readsafefile.DecryptXOR; +import readsafefile.ReadAttemptsFromXML; +import readsafefile.SafeFileManager; import settingsfunctions.LoadSettings; public class Main { - public static void main(String[] args) throws IOException { + public static void main(String[] args) throws IOException, DataFormatException { LoadMenu load = new LoadMenu(); load.onLoad(); diff --git a/src/module-info.java b/src/module-info.java index d4ce92a..a21e7ba 100644 --- a/src/module-info.java +++ b/src/module-info.java @@ -8,4 +8,6 @@ requires jdash.common; requires jlayer; requires java.sql; + requires java.xml; + requires org.apache.commons.codec; } \ No newline at end of file diff --git a/src/readsafefile/DecryptXOR.java b/src/readsafefile/DecryptXOR.java new file mode 100644 index 0000000..cce2f45 --- /dev/null +++ b/src/readsafefile/DecryptXOR.java @@ -0,0 +1,67 @@ +package readsafefile; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.nio.charset.StandardCharsets; +import java.util.zip.DataFormatException; +import java.util.zip.GZIPInputStream; +import java.util.zip.Inflater; + +import org.apache.commons.codec.binary.Base64; + +public class DecryptXOR { + + private static final String[] SAVES = {"CCGameManager.dat"}; + private static final int XOR_KEY = 11; + + private static byte[] xor(byte[] data, int key) { + byte[] result = new byte[data.length]; + for (int i = 0; i < data.length; i++) { + result[i] = (byte) (data[i] ^ key); + } + return result; + } + + private static byte[] decrypt(String data) throws IOException { + byte[] decodedData = Base64.decodeBase64(data.replace('-', '+').replace('_', '/')); + ByteArrayInputStream bis = new ByteArrayInputStream(decodedData); + GZIPInputStream gzipInputStream = new GZIPInputStream(bis); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + byte[] buffer = new byte[1024]; + int bytesRead; + while ((bytesRead = gzipInputStream.read(buffer)) != -1) { + bos.write(buffer, 0, bytesRead); + } + gzipInputStream.close(); + bis.close(); + bos.close(); + return bos.toByteArray(); + } + + public static void decryptAndWriteFiles() throws IOException { + String appDataPath = System.getenv("LOCALAPPDATA") + "\\GeometryDash\\"; + for (String save : SAVES) { + File inputFile = new File(appDataPath + save); + if (!inputFile.exists()) { + System.err.println("Input file not found: " + inputFile.getAbsolutePath()); + continue; + } + byte[] encryptedData = new byte[(int) inputFile.length()]; + try (FileInputStream fis = new FileInputStream(inputFile)) { + fis.read(encryptedData); + } + + byte[] decryptedData = decrypt(new String(xor(encryptedData, XOR_KEY))); + File outputFile = new File("C:\\ExtremeDemonList\\userdata\\" + save + ".xml"); + try (OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(outputFile), StandardCharsets.UTF_8)) { + osw.write(new String(decryptedData, StandardCharsets.UTF_8)); + } + System.out.println("File decrypted and written: " + outputFile.getAbsolutePath()); + } + } +} diff --git a/src/readsafefile/ReadAttemptsFromXML.java b/src/readsafefile/ReadAttemptsFromXML.java new file mode 100644 index 0000000..d640372 --- /dev/null +++ b/src/readsafefile/ReadAttemptsFromXML.java @@ -0,0 +1,83 @@ +package readsafefile; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +public class ReadAttemptsFromXML { + + public String getAttempts(String level) { + String atts = "0"; + try { + // Pfad zur XML-Datei + String filePath = "C:\\ExtremeDemonList\\userdata\\CCGameManager.dat.xml"; + + + // XML-Datei einlesen und als DOM-Dokument parsen + File xmlFile = new File(filePath); + DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); + Document doc = dBuilder.parse(xmlFile); + doc.getDocumentElement().normalize(); + + // Nach dem Eintrag für "Theory of Everything" suchen + NodeList levelNodes = doc.getElementsByTagName("d"); + int index = 1; + for (int i = 0; i < levelNodes.getLength(); i++) { + + Node levelNode = levelNodes.item(i); + if (levelNode.getNodeType() == Node.ELEMENT_NODE) { + Element levelElement = (Element) levelNode; + NodeList nameNodes = levelElement.getElementsByTagName("s"); + for (int j = 0; j < nameNodes.getLength(); j++) { + Node nameNode = nameNodes.item(j); + if (nameNode.getNodeType() == Node.ELEMENT_NODE) { + Element nameElement = (Element) nameNode; + String name = nameElement.getTextContent(); + if (name.equalsIgnoreCase(level)) { + // Wenn der Name übereinstimmt, die Anzahl der Versuche extrahieren + NodeList keyNodes = levelElement.getElementsByTagName("k"); + for (int k = 0; k < keyNodes.getLength(); k++) { + Node keyNode = keyNodes.item(k); + if (keyNode.getNodeType() == Node.ELEMENT_NODE) { + Element keyElement = (Element) keyNode; + String key = keyElement.getTextContent(); + if (key.equals("k18") && index == 2) { + // Wert des Schlüssels "k18" (Versuche) ausgeben + NodeList valueNodes = levelElement.getElementsByTagName("i"); + Node valueNode = valueNodes.item(k); + atts = valueNode.getTextContent(); // Sobald die Anzahl der Versuche gefunden wurde, die Schleife beenden + } + + if(key.equals("GS_7")) { + NodeList valueNodes = levelElement.getElementsByTagName("i"); + Node valueNode = valueNodes.item(k); + System.out.println(valueNode.getTextContent() + " = practice percent"); + } + + } + } + index++; + } + } + } + } + } + + } catch (Exception e) { + e.printStackTrace(); + } + return atts; + } + + + +} diff --git a/src/readsafefile/SafeFileManager.java b/src/readsafefile/SafeFileManager.java new file mode 100644 index 0000000..36670ed --- /dev/null +++ b/src/readsafefile/SafeFileManager.java @@ -0,0 +1,56 @@ +package readsafefile; + +import java.io.IOException; + +import data.FetchData; +import database.Sqlite; +import gui.AttemptsProgress; + +public class SafeFileManager { + + public void DecryptSafeFile() throws IOException { + DecryptXOR dec = new DecryptXOR(); + dec.decryptAndWriteFiles(); + } + + public void ReadIndexAttempts() throws IOException { + + AttemptsProgress prog = new AttemptsProgress(); + prog.build(); + + Thread thread = new Thread(new Runnable() { + + @Override + public void run() { + // TODO Auto-generated method stub + + + + Sqlite database = new Sqlite("levels"); + database.queryData("levels"); + FetchData fetch = new FetchData(); + try { + fetch.getGithubString(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + + ReadAttemptsFromXML read = new ReadAttemptsFromXML(); + + String attempts; + + for(int i = 0; i < fetch.allLevels().size(); i++) { + + attempts = read.getAttempts(database.getLevelname().get(i)); + + prog.update(database.getLevelname().get(i), Integer.parseInt(attempts), 1, i); + database.modifyData(database.getLevelname().get(i), Boolean.parseBoolean(database.getCompleted().get(i)), Integer.parseInt(attempts)); + } + } + + }); + thread.start(); + } +} diff --git a/src/settingsfunctions/ReadAttempts.java b/src/settingsfunctions/ReadAttempts.java new file mode 100644 index 0000000..b95be6b --- /dev/null +++ b/src/settingsfunctions/ReadAttempts.java @@ -0,0 +1,28 @@ +package settingsfunctions; + +import java.io.File; +import java.io.IOException; + +import javax.swing.JOptionPane; + +import readsafefile.SafeFileManager; + +public class ReadAttempts { + + public void readAttempts() throws IOException { + int response = JOptionPane.showConfirmDialog(null, "Es werden nun von allen Extreme Demons die Attempts in die Datenbank geschrieben. Dies kann eine Weile dauern. Trotzdem fortfahren?", "Attempts Einlesen", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); + if (response == JOptionPane.YES_OPTION) { + SafeFileManager mgr = new SafeFileManager(); + + File file = new File("C:\\ExtremeDemonList\\userdata\\CCGameManager.dat.xml"); + + if(!file.exists()) { + mgr.DecryptSafeFile(); + } + + mgr.ReadIndexAttempts(); + + } + } + +}