/* * Auto-CreamAPI * Copyright (C) 2020 Jeddunk * * 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 * . */ import com.jfoenix.controls.*; import de.jensd.fx.glyphs.fontawesome.FontAwesomeIconView; import javafx.beans.value.ChangeListener; import javafx.collections.FXCollections; import javafx.concurrent.Service; import javafx.concurrent.Task; import javafx.fxml.FXML; import javafx.scene.control.Alert; import javafx.scene.control.Label; import javafx.scene.control.Tooltip; import javafx.scene.paint.Color; import javafx.stage.FileChooser; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.configuration2.ex.ConfigurationException; import org.jsoup.HttpStatusException; import pojo.App; import util.CreamApiConfig; import util.CreamApiDllHandler; import util.SteamAppsListCache; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.util.Map; import java.util.NoSuchElementException; import java.util.Objects; public class Controller { private static final String REGEX = "(?steam_api(?:64)?.dll)$"; public Label creamApiDllApplied; public Label creamApiConfigExists; public FontAwesomeIconView creamApiDllAppliedIcon; public FontAwesomeIconView creamApiConfigExistsIcon; private CreamApiDllHandler handler = null; private boolean is64Bit; private boolean isSameFile; { try { handler = CreamApiDllHandler.getInstance(); } catch (IOException e) { Alert alert = new Alert(Alert.AlertType.ERROR); alert.setTitle("CreamAPI DLLs missing!"); alert.setHeaderText("CreamAPI DLL files can't be found!"); alert.setContentText("Please download CreamAPI and extract the non-log " + "version in the same folder as Auto-CreamAPI!\nThe program will now close."); alert.showAndWait(); System.exit(10); } } private final CreamApiConfig config = CreamApiConfig.getInstance(); private final SteamAppsListCache cache = new SteamAppsListCache(); @FXML public Label state_label; @FXML public JFXTextField path_textfield; @FXML public JFXTextField appId_textfield; @FXML public JFXTextField game_name_textfield; @FXML public JFXComboBox language_combobox; @FXML public JFXTextArea dlc_textarea; @FXML public JFXCheckBox extra_protection_checkbox; @FXML public JFXCheckBox offline_checkbox; @FXML public JFXCheckBox unlock_all_checkbox; @FXML public JFXButton reset_button; @FXML public JFXButton save_button; @FXML public JFXButton getAppId_button; @FXML public JFXButton path_button; @FXML public JFXButton retrieveDlcList_button; private String steamApiPathString; public Controller() { } @FXML public void initialize() { appId_textfield.textProperty().addListener(appIdChangesGameName()); //retrieveDlcList_button.setDisable(true); // WIP generate_tooltips(); fix_dlc_textarea_prompt_text(); reset(true); } private void read() { language_combobox.setItems(FXCollections.observableArrayList(config.getLanguages())); language_combobox.getSelectionModel().select(config.getLanguage()); appId_textfield.setText(config.getAppId().toString()); dlc_textarea.setText(config.getDlcListAsString()); game_name_textfield.setText(cache.getGame(config.getAppId()).getName()); extra_protection_checkbox.setSelected(config.getExtraProtection()); offline_checkbox.setSelected(config.getForceOffline()); unlock_all_checkbox.setSelected(config.getUnlockAll()); unlockAll_disableDlcTextArea(); } private void emptyFields() { creamApiDllAppliedIcon.setGlyphName("TIMES"); creamApiConfigExistsIcon.setGlyphName("TIMES"); appId_textfield.setText(""); dlc_textarea.setText(""); game_name_textfield.setText(""); extra_protection_checkbox.setSelected(false); offline_checkbox.setSelected(false); unlock_all_checkbox.setSelected(false); unlockAll_disableDlcTextArea(); } private void fix_dlc_textarea_prompt_text() { dlc_textarea.setPromptText("List of DLC...\r0000 = DLC Name"); } private void generate_tooltips() { Tooltip extra_protection_tooltip = new Tooltip("\"extra protection\""); extra_protection_checkbox.setTooltip(extra_protection_tooltip); Tooltip.install(extra_protection_checkbox, extra_protection_tooltip); } private ChangeListener appIdChangesGameName() { return (observable, oldValue, newValue) -> { int appId; try { appId = Integer.parseInt(newValue); final App game = cache.getGame(appId); if (game != null) { game_name_textfield.setText(game.getName()); } else { game_name_textfield.setText(""); } } catch (NumberFormatException e) { game_name_textfield.setText(""); } }; } private void reset(boolean silent) { if (silent) { state_label.setText(""); } else { state_label.setText("Resetting fields..."); } try { config.read(); read(); if (!silent) { state_label.setText("Successfully reset all fields!"); } } catch (NoSuchElementException e) { System.err.println("Error reading cream_api.ini! " + "This can be ignored if setting up CreamAPI for the first time."); } catch (NullPointerException e) { System.err.println("Can't fill out fields, no configuration file set!"); if (!silent) { state_label.setText("Could not reset fields, no configuration file set!"); } } updateIndicators(); } private void updateIndicators() { Color colorSuccess = Color.web("#43A047"); Color colorFailure = Color.web("#E53935"); try { is64Bit = false; if (!steamApiPathString.isEmpty()) { Path dllPath = Paths.get(steamApiPathString); if (dllPath.endsWith("steam_api64.dll")) { is64Bit = true; } InputStream is = Files.newInputStream(dllPath); String md5 = DigestUtils.md5Hex(is); isSameFile = Objects.equals(md5, handler.getDllMd5(is64Bit)); if (isSameFile) { creamApiDllApplied.setTextFill(colorSuccess); creamApiDllAppliedIcon.setFill(colorSuccess); creamApiDllAppliedIcon.setGlyphName("CHECK"); } else { creamApiDllApplied.setTextFill(colorFailure); creamApiDllAppliedIcon.setFill(colorFailure); creamApiDllAppliedIcon.setGlyphName("TIMES"); } Path configPath = Paths.get(config.getPath()); if (Files.exists(configPath) && Files.size(configPath) > 0L) { creamApiConfigExists.setTextFill(colorSuccess); creamApiConfigExistsIcon.setFill(colorSuccess); creamApiConfigExistsIcon.setGlyphName("CHECK"); } else { creamApiConfigExists.setTextFill(colorFailure); creamApiConfigExistsIcon.setFill(colorFailure); creamApiConfigExistsIcon.setGlyphName("TIMES"); } } } catch (Exception e) { System.err.println("Error! Resetting visual indicators!"); creamApiDllApplied.setTextFill(colorFailure); creamApiDllAppliedIcon.setFill(colorFailure); creamApiDllAppliedIcon.setGlyphName("TIMES"); creamApiConfigExists.setTextFill(colorFailure); creamApiConfigExistsIcon.setFill(colorFailure); creamApiConfigExistsIcon.setGlyphName("TIMES"); } } public void save() { Service s = new Service() { @Override protected Task createTask() { return new Task() { @Override protected Void call() { try { setUpCreamApi(); config.setDlcListFromString(dlc_textarea.getText()); config.setAppId(Integer.parseInt(appId_textfield.getText())); config.setExtraProtection(extra_protection_checkbox.isSelected()); config.setForceOffline(offline_checkbox.isSelected()); config.setUnlockAll(unlock_all_checkbox.isSelected()); config.setLanguage(language_combobox.getValue()); config.sync(); } catch (IOException | ConfigurationException e) { e.printStackTrace(); cancel(); } catch (NullPointerException e) { System.err.println("No configuration file set!"); cancel(); } updateIndicators(); return null; } }; } }; s.setOnRunning(event -> { setDisableAllButtons(true); state_label.setText("Saving..."); }); s.setOnSucceeded(event -> { setDisableAllButtons(false); state_label.setText("Saved successfully!"); }); s.setOnCancelled(event -> { setDisableAllButtons(false); state_label.setText("Could not save configuration file!"); }); s.start(); } public void getAppId() { final App game = cache.findGame(game_name_textfield.getText()); if (game == null) { appId_textfield.setText("-1"); } else { appId_textfield.setText(String.valueOf(game.getAppId())); } } public void unlockAll_disableDlcTextArea() { dlc_textarea.setDisable(unlock_all_checkbox.isSelected()); retrieveDlcList_button.setDisable(unlock_all_checkbox.isSelected()); } /** * Gets DLC from both the Steam Store and SteamDB, since the latter has a (weird) limit of 64(?) DLCs. SteamDB * also lists DLC not available for purchase. */ public void getDlcList() { Service s = new Service() { @Override protected Task createTask() { return new Task() { @Override protected Void call() { try { Map collect = cache.getDlcMap(appId_textfield.getText()); StringBuilder sb = new StringBuilder(); collect.forEach((k, v) -> sb.append(k).append("=").append(v).append("\n")); dlc_textarea.setText(sb.toString()); } catch (HttpStatusException e) { if (e.getStatusCode() == 404) { System.err.println("App ID empty or not found! (HTTP Status Code: 404)"); } else { // e.printStackTrace(); System.err.println("STATUS CODE: " + e.getStatusCode()); } cancel(); } catch (IOException e) { e.printStackTrace(); cancel(); } return null; } }; } }; s.setOnRunning(event -> { setDisableAllButtons(true); state_label.setText("Getting list of DLCs..."); }); s.setOnSucceeded(event -> { setDisableAllButtons(false); state_label.setText("Got list of DLCs successfully!"); }); s.setOnCancelled(event -> { setDisableAllButtons(false); state_label.setText("Could not get list of DLCs!"); }); s.start(); } public void openFileChooser() { FileChooser chooser = new FileChooser(); chooser.setTitle("Choose steam_api(64).dll..."); FileChooser.ExtensionFilter filter = new FileChooser.ExtensionFilter("steam_api(64).dll", "steam_api.dll", "steam_api64.dll"); chooser.getExtensionFilters().add(filter); final File file = chooser.showOpenDialog(path_button.getScene().getWindow()); try { config.setConfig(file.getParent() + "\\cream_api.ini"); } catch (ConfigurationException | IOException e) { e.printStackTrace(); } catch (NullPointerException e) { System.err.println("Could not set config file location! Did you cancel the file chooser?"); } path_textfield.setText(file.getParent()); steamApiPathString = file.getAbsolutePath(); emptyFields(); reset(true); state_label.setText("Ready."); } /** * check if creamapi version of dll is there, if not, rename original to steam_api(64)_o.dll and copy * creamapi dll to the path. also looks for alternative steam dll (which means it patches both 64 and 32 bit * dlls at once if found) * * @throws IOException If file is missing or not accessible/modifiable. */ private void setUpCreamApi() throws IOException { Path path = Paths.get(steamApiPathString); copyDllFile(path, isSameFile); findAdditionalDll(path); } private void findAdditionalDll(Path path) throws IOException { String secondDllString = is64Bit ? "\\steam_api.dll" : "\\steam_api64.dll"; Path dir = path.getParent(); Path secondDll = Paths.get(dir.toString() + secondDllString); if (Files.exists(secondDll)) { System.out.println("Alternative DLL found!"); InputStream is = Files.newInputStream(secondDll); String md5 = DigestUtils.md5Hex(is); boolean isSameFile1 = Objects.equals(md5, handler.getDllMd5(!is64Bit)); copyDllFile(secondDll, isSameFile1); } } private void copyDllFile(Path path, boolean isSameFile) throws IOException { if (!isSameFile) { String pathOrigString = steamApiPathString; pathOrigString = pathOrigString .replaceFirst(REGEX, is64Bit ? "steam_api64_o.dll" : "steam_api_o.dll"); Path pathOrig = Paths.get(pathOrigString); if (!Files.exists(pathOrig)) { Files.move(path, pathOrig); } else { String pathBakString = steamApiPathString; pathBakString = pathBakString .replaceFirst(REGEX, is64Bit ? "steam_api64.dll.backup" : "steam_api.dll.backup"); Path pathBak = Paths.get(pathBakString); Files.move(path, pathBak, StandardCopyOption.REPLACE_EXISTING); } //Files.deleteIfExists(path); Files.copy(handler.getDllPath(is64Bit), path); } } private void setDisableAllButtons(boolean b) { reset_button.setDisable(b); save_button.setDisable(b); getAppId_button.setDisable(b); path_button.setDisable(b); retrieveDlcList_button.setDisable(b); } public void resetFromButton() { reset(false); } }