import com.jfoenix.controls.*; import javafx.beans.value.ChangeListener; import javafx.collections.FXCollections; import javafx.fxml.FXML; import javafx.scene.control.Tooltip; import javafx.stage.FileChooser; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.configuration2.ex.ConfigurationException; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import pojo.App; import util.CreamApiConfig; 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.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; public class Controller { private static final String X86_MD5_HASH = "c6f267a2d10b891ed352ed849a28d69b"; private static final String X64_MD5_HASH = "645c728a6117946294130d07cf6c0cae"; private CreamApiConfig config = CreamApiConfig.getInstance(); private SteamAppsListCache cache = new SteamAppsListCache(); @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(); read(); } private void read() { 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()); language_combobox.setItems(FXCollections.observableArrayList(config.getLanguages())); language_combobox.getSelectionModel().select(config.getLanguage()); 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(""); } }; } public void reset() { config.read(); read(); } public void save() { try { setUpCreamApi(); } catch (IOException e) { e.printStackTrace(); } 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()); try { config.sync(); } catch (ConfigurationException e) { e.printStackTrace(); } } 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() { Map steamStoreDLCs = new HashMap<>(); Map steamDbDLCs = new HashMap<>(); //StringBuilder sb = new StringBuilder(); try { // Steam Store Document steamDoc = Jsoup .connect("https://store.steampowered.com/app/" + appId_textfield.getText() + "/") .get(); Elements steamDLCs = steamDoc.getElementsByClass("game_area_dlc_row"); for (Element dlc : steamDLCs) { String dlc_id = dlc.attr("data-ds-appid"); String dlc_name = dlc .getElementsByClass("game_area_dlc_name") .text().replace("\n", "").trim(); steamStoreDLCs.put(Integer.parseInt(dlc_id), dlc_name); } // SteamDB Document steamDbDoc = Jsoup .connect("https://steamdb.info/app/" + appId_textfield.getText() + "/dlc/") .get(); Element steamDbDlcSection = steamDbDoc.getElementById("dlc"); Elements steamDbDLCElements = steamDbDlcSection.getElementsByClass("app"); for (Element dlc : steamDbDLCElements) { String dlc_id = dlc.attr("data-appid"); String dlc_name = "Unknown DLC " + dlc_id; Elements td = dlc.getElementsByTag("td"); if (!td.isEmpty()) { dlc_name = td.get(1).text().replace("\n", "").trim(); } steamDbDLCs.put(Integer.parseInt(dlc_id), dlc_name); } } catch (IOException e) { e.printStackTrace(); } catch (NullPointerException e) { // ignore } Map allDLCs = new HashMap<>(steamStoreDLCs); steamDbDLCs.forEach(allDLCs::putIfAbsent); StringBuilder sb = new StringBuilder(); LinkedHashMap collect = allDLCs.entrySet().stream() .sorted(Map.Entry.comparingByKey()) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (oldValue, newValue) -> oldValue, LinkedHashMap::new)); collect.forEach((k, v) -> sb.append(k).append("=").append(v).append("\n")); dlc_textarea.setText(sb.toString()); } 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"); path_textfield.setText(file.getParent()); steamApiPathString = file.getAbsolutePath(); } catch (ConfigurationException | IOException e) { e.printStackTrace(); } } /** * check if creamapi version of dll is there, if not, rename original to steam_api(64)_o.dll and copy * creamapi one to the path. * * @throws IOException If file is missing or not accessible/modifiable. */ private void setUpCreamApi() throws IOException { boolean is64Bit = false; if (!steamApiPathString.isEmpty()) { Path path = Paths.get(steamApiPathString); if (path.endsWith("steam_api64.dll")) { is64Bit = true; } InputStream is = Files.newInputStream(path); String md5 = DigestUtils.md5Hex(is); boolean isSameFile = Objects.equals(md5, is64Bit ? X64_MD5_HASH : X86_MD5_HASH); if (!isSameFile) { String pathOrigString = steamApiPathString; pathOrigString = pathOrigString .replaceFirst("(?steam_api(?:64)?.dll)$", is64Bit ? "steam_api64_o.dll" : "steam_api_o.dll"); Path pathOrig = Paths.get(pathOrigString); if (!Files.exists(pathOrig)) { Files.move(path, pathOrig); } Files.deleteIfExists(path); Files.copy(Paths.get(is64Bit ? "steam_api64.dll" : "steam_api.dll"), path); } } } }