Compare commits

...

29 Commits

Author SHA1 Message Date
Jeddunk
3bf33b0d4c Update 'README.md' 2020-12-30 11:03:47 +00:00
da947e1f51 Code refactoring, improved logging, Drone CI improvements 2020-12-03 00:02:59 +01:00
21a7ec98dd Code changes 2020-10-24 00:45:10 +02:00
992f2fb20c Fixed and enabled SteamDB DLC functionality 2020-10-21 15:47:58 +02:00
26872ec8fb Update CreamAPI to 4.5.0.0 2020-10-21 13:24:58 +02:00
452e78b1ed Disable SteamDB checkbox 2020-10-21 13:14:03 +02:00
cce8bbe513 Fixed an issue where games with an age check could not be parsed 2020-10-21 13:10:42 +02:00
5043ffefff add build status to README.md 2020-10-14 14:37:49 +02:00
032a85600f maven config 2020-10-14 14:32:19 +02:00
4a8ecd32ac updated resources location 2020-10-14 14:02:46 +02:00
6afa33db75 README.md update 2020-10-14 13:46:43 +02:00
7c5329fd54 better logging 2020-10-14 13:43:29 +02:00
b7ec6a62a3 Added toggle for SteamDB DLC
Added custom fonts
2020-10-07 14:42:11 +02:00
bd70c814b9 fixed dumb error 2020-10-07 12:49:54 +02:00
272b1d0833 eh whatevs sry future me 2020-10-07 10:36:37 +02:00
1fdf90da8a code structure changes
drone ci
2020-09-27 17:48:13 +02:00
79bda2b1fd Minor fix 2020-08-30 18:08:28 +02:00
7d9514abae You can now press enter in the "Game..." text field to start a search. 2020-08-30 16:15:46 +02:00
8c23ae27e8 Improved language combobox 2020-08-28 18:32:39 +02:00
308f20cb81 List of languages is now hardcoded! 2020-08-28 15:39:28 +02:00
d71d8ed789 Fixed main window resizing. 2020-08-28 15:25:58 +02:00
dd99292c65 Minor fix to main window 2020-08-28 15:12:44 +02:00
36a05fcd8e Merge branch 'visual-indicators' into 1.1
# Conflicts:
#	src/main/java/Controller.java
#	src/main/resources/mainWindow.fxml
2020-08-28 15:06:31 +02:00
fe71a8acc2 Merge branch 'search-improvements' into 1.1 2020-08-28 14:50:22 +02:00
6f7d1b5695 Improved search function (if name matches exactly, no need to open the window)
Improved search result window design
2020-08-26 16:52:49 +02:00
5b912a0991 Minor fix 2020-08-25 14:30:56 +02:00
30551bccda Updated README.md 2020-08-25 13:34:13 +02:00
c2254856da Search function now brings up a window with a list of search results. 2020-08-24 15:27:34 +02:00
4eda79211e Initial implementation of fuzzy search (fuzzywuzzy library) 2020-08-23 14:59:21 +02:00
48 changed files with 1534 additions and 573 deletions

40
.drone.yml Normal file
View File

@ -0,0 +1,40 @@
kind: pipeline
type: docker
name: default
steps:
- name: build
image: maven:3-amazoncorretto-8
commands:
- mvn install
- name: gitea_release
image: plugins/gitea-release
settings:
api_key:
from_secret: gitea_token
base_url: https://git.jeddunk.xyz
files:
- auto-cream-api-*.zip
checksum:
- md5
- sha1
- sha256
- sha512
- adler32
- crc32
when:
event:
- tag
- name: discord_webhook
image: appleboy/drone-discord
settings:
webhook_id:
from_secret: discord_webhook_id
webhook_token:
from_secret: discord_webhook_token
message: >
{{#success build.status}}
build {{build.number}} succeeded.
{{else}}
build {{build.number}} failed.
{{/success}}

5
.gitignore vendored
View File

@ -159,5 +159,6 @@ $RECYCLE.BIN/
/steamapps.json
/test.json
/steam_api.md5
/src/main/java/util/env/Default.java
/src/main/java/GetListOfDlc.java
/src/main/java/xyz/jeddunk/autocreamapi/util/env/Default.java
/src/main/java/xyz/jeddunk/autocreamapi/GetListOfDlc.java
dist/

View File

@ -0,0 +1,6 @@
This folder contains libraries copied from the "auto-cream-api" project.
It is managed by the CheckStyle-IDEA IDE plugin.
Do not modify this folder while the IDE is running.
When the IDE is stopped, you may delete this folder at any time. It will be recreated as needed.
In order to prevent the CheckStyle-IDEA IDE plugin from creating this folder,
uncheck the "Copy libraries from project directory" option in the CheckStyle-IDEA settings dialog.

View File

@ -13,7 +13,7 @@
<component name="ProjectKey">
<option name="state" value="project://e79810c8-c5c8-43b1-b19c-90c1f4095425" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8 (amazon)" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

View File

@ -1,9 +1,17 @@
# Auto-CreamAPI
## Development is continuing [here](https://git.jeddunk.xyz/jeddunk/auto-creamapi-2)! However you're still welcome to use this version.
[![ko-fi](https://www.ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/H2H4330U3)
[![Build Status](https://ci.jeddunk.xyz/api/badges/jeddunk/auto-cream-api/status.svg)](https://ci.jeddunk.xyz/jeddunk/auto-cream-api)
Set your game automatically up for use with CreamAPI.
![](https://jeddunk.xyz/javaw_nLB130vOCY.png)
[![](https://jeddunk.xyz/jetbrains-small.png)](https://www.jetbrains.com/?from=Auto-CreamAPI)
[Made with software provided by JetBrains s.r.o.](https://www.jetbrains.com/?from=Auto-CreamAPI)
## Features
* Setup CreamAPIs DLLs and configuration file automatically.
* Find the AppID by providing the games name without having to look it up manually.
@ -35,7 +43,7 @@ Download the latest release and extract it into any folder (e.g. `%USERPROFILE%\
* Select a language and tick the options if needed.
* Click on *"Save"*.
### Java 11
### Java 11/Java 14
*WIP*
@ -51,7 +59,15 @@ The following dependencies are licensed under the Apache License 2.0:
* gson
* Apache Commons BeanUtils
* Apache Commons Configuration
* The Roboto font family
The following dependencies are licensed under the MIT License:
* jsoup
* Unirest-Java
* slf4j
* Copy Rename Maven Plugin
The following dependencies are licensed under the GPL2 License:
* fuzzywuzzy
Logback is dual-licensed under the EPL v1.0 and the LGPL 2.1.

View File

@ -12,6 +12,7 @@
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/dist" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
@ -34,5 +35,68 @@
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpmime:4.5.9" level="project" />
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpasyncclient:4.1.4" level="project" />
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpcore-nio:4.4.10" level="project" />
<orderEntry type="library" name="Maven: me.xdrop:fuzzywuzzy:1.3.1" level="project" />
<orderEntry type="library" name="Maven: com.coderplus.maven.plugins:copy-rename-maven-plugin:1.0.1" level="project" />
<orderEntry type="library" name="Maven: org.apache.maven:maven-model:2.0.9" level="project" />
<orderEntry type="library" name="Maven: org.apache.maven:maven-project:2.0.9" level="project" />
<orderEntry type="library" name="Maven: org.apache.maven:maven-settings:2.0.9" level="project" />
<orderEntry type="library" name="Maven: org.apache.maven:maven-profile:2.0.9" level="project" />
<orderEntry type="library" name="Maven: org.apache.maven:maven-artifact-manager:2.0.9" level="project" />
<orderEntry type="library" name="Maven: org.apache.maven:maven-plugin-registry:2.0.9" level="project" />
<orderEntry type="library" name="Maven: org.codehaus.plexus:plexus-container-default:1.0-alpha-9-stable-1" level="project" />
<orderEntry type="library" name="Maven: junit:junit:3.8.1" level="project" />
<orderEntry type="library" name="Maven: org.apache.maven:maven-core:2.0.9" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: org.apache.maven.wagon:wagon-file:1.0-beta-2" level="project" />
<orderEntry type="library" name="Maven: org.apache.maven:maven-plugin-parameter-documenter:2.0.9" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: org.apache.maven.wagon:wagon-webdav:1.0-beta-2" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: slide:slide-webdavlib:2.1" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: commons-httpclient:commons-httpclient:2.0.2" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: jdom:jdom:1.0" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: de.zeigermann.xml:xml-im-exporter:1.1" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: org.apache.maven.wagon:wagon-http-lightweight:1.0-beta-2" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: org.apache.maven.wagon:wagon-http-shared:1.0-beta-2" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: jtidy:jtidy:4aug2000r7-dev" level="project" />
<orderEntry type="library" name="Maven: xml-apis:xml-apis:1.0.b2" level="project" />
<orderEntry type="library" name="Maven: org.apache.maven.reporting:maven-reporting-api:2.0.9" level="project" />
<orderEntry type="library" name="Maven: org.apache.maven.doxia:doxia-sink-api:1.0-alpha-10" level="project" />
<orderEntry type="library" name="Maven: org.apache.maven.wagon:wagon-provider-api:1.0-beta-2" level="project" />
<orderEntry type="library" name="Maven: org.apache.maven:maven-repository-metadata:2.0.9" level="project" />
<orderEntry type="library" name="Maven: org.apache.maven:maven-error-diagnostics:2.0.9" level="project" />
<orderEntry type="library" name="Maven: commons-cli:commons-cli:1.0" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: org.apache.maven.wagon:wagon-ssh-external:1.0-beta-2" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: org.apache.maven.wagon:wagon-ssh-common:1.0-beta-2" level="project" />
<orderEntry type="library" name="Maven: org.apache.maven:maven-plugin-descriptor:2.0.9" level="project" />
<orderEntry type="library" name="Maven: org.codehaus.plexus:plexus-interactivity-api:1.0-alpha-4" level="project" />
<orderEntry type="library" name="Maven: org.apache.maven:maven-monitor:2.0.9" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: org.apache.maven.wagon:wagon-ssh:1.0-beta-2" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: com.jcraft:jsch:0.1.27" level="project" />
<orderEntry type="library" name="Maven: classworlds:classworlds:1.1" level="project" />
<orderEntry type="library" name="Maven: org.apache.maven:maven-plugin-api:2.0.9" level="project" />
<orderEntry type="library" name="Maven: org.apache.maven:maven-artifact:2.0.9" level="project" />
<orderEntry type="library" name="Maven: org.codehaus.plexus:plexus-utils:1.5.8" level="project" />
<orderEntry type="library" name="Maven: org.sonatype.plexus:plexus-build-api:0.0.7" level="project" />
<orderEntry type="library" name="Maven: ch.qos.logback:logback-classic:1.2.3" level="project" />
<orderEntry type="library" name="Maven: ch.qos.logback:logback-core:1.2.3" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.25" level="project" />
<orderEntry type="library" name="Maven: org.fusesource.jansi:jansi:1.18" level="project" />
<orderEntry type="library" name="Maven: net.sourceforge.htmlunit:htmlunit:2.44.0" level="project" />
<orderEntry type="library" name="Maven: xalan:xalan:2.7.2" level="project" />
<orderEntry type="library" name="Maven: xalan:serializer:2.7.2" level="project" />
<orderEntry type="library" name="Maven: net.sourceforge.htmlunit:htmlunit-core-js:2.44.0" level="project" />
<orderEntry type="library" name="Maven: net.sourceforge.htmlunit:neko-htmlunit:2.44.0" level="project" />
<orderEntry type="library" name="Maven: xerces:xercesImpl:2.12.0" level="project" />
<orderEntry type="library" name="Maven: net.sourceforge.htmlunit:htmlunit-cssparser:1.6.0" level="project" />
<orderEntry type="library" name="Maven: commons-io:commons-io:2.8.0" level="project" />
<orderEntry type="library" name="Maven: commons-net:commons-net:3.7.1" level="project" />
<orderEntry type="library" name="Maven: org.brotli:dec:0.1.2" level="project" />
<orderEntry type="library" name="Maven: com.shapesecurity:salvation2:3.0.0" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-client:9.4.32.v20200930" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-client:9.4.32.v20200930" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-http:9.4.32.v20200930" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-xml:9.4.32.v20200930" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-util:9.4.32.v20200930" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-io:9.4.32.v20200930" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-common:9.4.32.v20200930" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-api:9.4.32.v20200930" level="project" />
</component>
</module>

View File

@ -1,16 +0,0 @@
# List of languages
# https://partner.steamgames.com/doc/store/localization#supported_languages
english
latam
brazilian
german
french
italian
portuguese
spanish
russian
schinese
tchinese
japanese
koreana

113
pom.xml
View File

@ -21,16 +21,28 @@
<groupId>xyz.jeddunk</groupId>
<artifactId>auto-cream-api</artifactId>
<version>1.0-SNAPSHOT</version>
<version>1.2.2</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<dist>${project.basedir}/dist</dist>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>2.5</version>
<configuration>
<filesets>
<fileset>
<directory>dist</directory>
</fileset>
</filesets>
</configuration>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
@ -42,11 +54,11 @@
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-5</version>
<version>2.2.2</version>
<configuration>
<archive>
<manifest>
<mainClass>Main</mainClass>
<mainClass>xyz.jeddunk.autocreamapi.Main</mainClass>
</manifest>
</archive>
<descriptorRefs>
@ -63,6 +75,72 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<version>2.4</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<groupId>com.coderplus.maven.plugins</groupId>
<artifactId>copy-rename-maven-plugin</artifactId>
<version>1.0.1</version>
<executions>
<execution>
<id>install-copy</id>
<phase>install</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<overWrite>true</overWrite>
<fileSets>
<fileSet>
<sourceFile>${project.build.directory}/${project.artifactId}-${project.version}-jar-with-dependencies.jar</sourceFile>
<destinationFile>${dist}/${project.artifactId}.jar</destinationFile>
</fileSet>
<fileSet>
<sourceFile>${project.basedir}/README.md</sourceFile>
<destinationFile>${dist}/README.md</destinationFile>
</fileSet>
<fileSet>
<sourceFile>${project.basedir}/steam_api.dll</sourceFile>
<destinationFile>${dist}/steam_api.dll</destinationFile>
</fileSet>
<fileSet>
<sourceFile>${project.basedir}/steam_api64.dll</sourceFile>
<destinationFile>${dist}/steam_api64.dll</destinationFile>
</fileSet>
<fileSet>
<sourceFile>${project.basedir}/version.txt</sourceFile>
<destinationFile>${dist}/version.txt</destinationFile>
</fileSet>
</fileSets>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<id>install-zip</id>
<phase>install</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<zip destfile="${project.basedir}/${project.artifactId}-${project.version}.zip" basedir="${dist}"/>
</target>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
@ -72,7 +150,7 @@
<enabled>false</enabled>
</snapshots>
<id>bintray-jerady-maven</id>
<name>bintray</name>
<name>bintray-jerady</name>
<url>https://dl.bintray.com/jerady/maven</url>
</repository>
</repositories>
@ -82,7 +160,7 @@
<enabled>false</enabled>
</snapshots>
<id>bintray-jerady-maven</id>
<name>bintray-plugins</name>
<name>bintray-jerady-plugins</name>
<url>https://dl.bintray.com/jerady/maven</url>
</pluginRepository>
</pluginRepositories>
@ -131,5 +209,30 @@
<artifactId>unirest-java</artifactId>
<version>3.1.02</version>
</dependency>
<dependency>
<groupId>me.xdrop</groupId>
<artifactId>fuzzywuzzy</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>com.coderplus.maven.plugins</groupId>
<artifactId>copy-rename-maven-plugin</artifactId>
<version>1.0.1</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.fusesource.jansi</groupId>
<artifactId>jansi</artifactId>
<version>1.18</version>
</dependency>
<dependency>
<groupId>net.sourceforge.htmlunit</groupId>
<artifactId>htmlunit</artifactId>
<version>2.44.0</version>
</dependency>
</dependencies>
</project>

View File

@ -1,193 +0,0 @@
/*
* 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
* <https://www.gnu.org/licenses/>.
*/
package util;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken;
import kong.unirest.HttpResponse;
import kong.unirest.Unirest;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import pojo.App;
import pojo.SteamAppsList;
import util.env.MainEnv;
import java.io.*;
import java.lang.reflect.Type;
import java.time.Duration;
import java.time.Instant;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class SteamAppsListCache {
private SteamAppsList list = new SteamAppsList();
private final File cacheFile = new File("steamapps.json");
private MainEnv env;
//private String key;
public SteamAppsListCache() {
try {
Class<?> envDefault = Class.forName("util.env.Default");
env = (MainEnv) envDefault.newInstance();
// System.out.println(env.getKey());
} catch (ClassNotFoundException e) {
env = new MainEnv();
} catch (IllegalAccessException | InstantiationException e) {
// Only thrown by newInstance()
e.printStackTrace();
}
//boolean fileFound = true;
try {
getListFromFile();
} catch (FileNotFoundException e) {
System.err.println("File does not exist, trying to create steamapps.json for the first time...");
//fileFound = false;
sync();
} catch (JsonSyntaxException e) {
System.err.println("File seems to be corrupt, trying to recreate steamapps.json...");
//fileFound = false;
sync();
}
if (Instant.now().isAfter(list.getTimestamp().plus(Duration.ofDays(3)))) {
System.err.println("List in file is not recent!");
sync();
}
}
private void sync() {
getListFromApi();
try {
saveListToFile();
} catch (IOException ex) {
ex.printStackTrace();
}
}
public App getGame(int appId) {
return list.getSteamAppsList().stream().filter(app -> app.getAppId() == appId).findFirst().orElse(null);
}
@SuppressWarnings("unused")
public App getGame(String name) {
return list.getSteamAppsList().stream()
.filter(app -> app.getName().equalsIgnoreCase(name)).findFirst().orElse(null);
}
public App findGame(String name) {
for (App app : list.getSteamAppsList()) {
if (app.getName().toLowerCase().replaceAll("[^a-zA-Z0-9\\s+]", "")
.startsWith(name.toLowerCase().replaceAll("[^a-zA-Z0-9\\s+]", ""))) {
return app;
}
}
for (App app : list.getSteamAppsList()) {
if (app.getName().toLowerCase().replaceAll("[^a-zA-Z0-9\\s+]", "")
.contains(name.toLowerCase().replaceAll("[^a-zA-Z0-9\\s+]", ""))) {
return app;
}
}
return null;
}
private void getListFromApi() {
System.out.println("Trying to get SteamAppList from API...");
List<App> apps = getApps();
list.setTimestamp(Instant.now());
list.setSteamAppsList(apps);
}
private List<App> getApps() {
HttpResponse<String> httpResponse =
Unirest.get("https://api.steampowered.com/IStoreService/GetAppList/v1/" +
"?key=" + env.getKey() + "&include_games=1&max_results=50000").asString();
return new Gson()
.fromJson(httpResponse.getBody(), App.Rezponze.Download.class)
.getResponse().getApps();
}
private void saveListToFile() throws IOException {
System.out.println("Trying to save SteamAppList to file (" + cacheFile.getAbsolutePath() + ")...");
Gson gson = new Gson();
String jsonString = gson.toJson(list);
BufferedWriter fOut = new BufferedWriter(new FileWriter(cacheFile));
fOut.write(jsonString);
fOut.close();
System.out.println("Successfully saved SteamAppList to file (" + cacheFile.getAbsolutePath() + ")...");
}
private void getListFromFile() throws FileNotFoundException, JsonSyntaxException {
System.out.println("Trying to get SteamAppList from file (" + cacheFile.getAbsolutePath() + ")...");
BufferedReader fIn = new BufferedReader(new FileReader(cacheFile));
String json = fIn.lines().collect(Collectors.joining());
final Type type = new TypeToken<SteamAppsList>() {
}.getType();
Gson gson = new Gson();
list = gson.fromJson(json, type);
System.out.println("Successfully got SteamAppList from file (" + cacheFile.getAbsolutePath() + ")...");
}
public LinkedHashMap<Number, String> getDlcMap(String appId) throws IOException{
Map<Integer, String> steamStoreDLCs = new HashMap<>();
Map<Integer, String> steamDbDLCs = new HashMap<>();
//StringBuilder sb = new StringBuilder();
try {
// Steam Store
Document steamDoc = Jsoup
.connect("https://store.steampowered.com/app/" + appId + "/")
.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 + "/dlc/")
.userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:76.0) Gecko/20100101 Firefox/76.0")
.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 (NullPointerException e) {
// ignore
}
Map<Integer, String> allDLCs = new HashMap<>(steamStoreDLCs);
steamDbDLCs.forEach(allDLCs::putIfAbsent);
return allDLCs.entrySet().stream()
.sorted(Map.Entry.comparingByKey())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
(oldValue, newValue) -> oldValue, LinkedHashMap::new));
}
}

View File

@ -13,108 +13,156 @@
* <https://www.gnu.org/licenses/>.
*/
import com.jfoenix.controls.*;
package xyz.jeddunk.autocreamapi;
import de.jensd.fx.glyphs.fontawesome.FontAwesomeIconView;
import javafx.beans.value.ChangeListener;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.event.Event;
import javafx.fxml.FXML;
import javafx.scene.control.Alert;
import javafx.scene.control.Label;
import javafx.scene.control.Tooltip;
import javafx.fxml.Initializable;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.paint.Color;
import javafx.stage.FileChooser;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.stage.*;
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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import xyz.jeddunk.autocreamapi.pojo.App;
import xyz.jeddunk.autocreamapi.util.CreamApiConfig;
import xyz.jeddunk.autocreamapi.util.CreamApiDllHandler;
import xyz.jeddunk.autocreamapi.util.SteamAppsListCache;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
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;
import java.util.*;
import java.util.stream.Stream;
public class Controller {
public class Controller implements Initializable {
final Logger logger = LoggerFactory.getLogger(Controller.class);
private static final String GLYPH_FAILURE = "TIMES";
private static final String GLYPH_SUCCESS = "CHECK";
private static final Color COLOR_FAILURE = Color.web("#E53935");
private static final Color COLOR_SUCCESS = Color.web("#43A047");
private static final String REGEX = "(?<steamApiDll>steam_api(?:64)?.dll)$";
public Label creamApiDllApplied;
public Label creamApiConfigExists;
public FontAwesomeIconView creamApiDllAppliedIcon;
public FontAwesomeIconView creamApiConfigExistsIcon;
private CreamApiDllHandler handler = null;
private final CreamApiConfig config = CreamApiConfig.getInstance();
private final SteamAppsListCache cache = new SteamAppsListCache();
private boolean is64Bit;
private boolean isSameFile;
@FXML
public Label creamApiDllApplied;
@FXML
public Label creamApiConfigExists;
@FXML
public FontAwesomeIconView creamApiDllAppliedIcon;
@FXML
public FontAwesomeIconView creamApiConfigExistsIcon;
@FXML
public Label state_label;
@FXML
public TextField path_textfield;
@FXML
public TextField appId_textfield;
@FXML
public TextField game_name_textfield;
@FXML
public ComboBox<String> language_combobox;
@FXML
public TextArea dlc_textarea;
@FXML
public CheckBox extra_protection_checkbox;
@FXML
public CheckBox offline_checkbox;
@FXML
public CheckBox unlock_all_checkbox;
@FXML
public CheckBox steamdb_dlc_checkbox;
@FXML
public Button reset_button;
@FXML
public Button save_button;
@FXML
public Button getAppId_button;
@FXML
public Button path_button;
@FXML
public Button getDlcList_button;
private String steamApiPathString;
{
try {
handler = CreamApiDllHandler.getInstance();
} catch (IOException e) {
} catch (FileNotFoundException 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);
System.exit(2);
} catch (IOException e) {
e.printStackTrace();
}
}
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<String> 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() {
@Override
public void initialize(URL location, ResourceBundle resources) {
steamdb_dlc_checkbox.setSelected(true);
appId_textfield.textProperty().addListener(appIdChangesGameName());
//retrieveDlcList_button.setDisable(true); // WIP
game_name_textfield.setOnKeyReleased(event -> {
KeyCode code = event.getCode();
if (code.equals(KeyCode.ENTER)) {
getAppId();
}
});
language_combobox.setItems(FXCollections.observableArrayList(config.getLanguages()));
language_combobox.setTooltip(new Tooltip());
language_combobox.setEditable(false);
new ComboBoxAutoComplete<>(language_combobox);
dlc_textarea.setPromptText("List of DLC...\r0000 = DLC Name");
generate_tooltips();
fix_dlc_textarea_prompt_text();
reset(true);
state_label.setText("Ready.");
}
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);
Tooltip steamdb_dlc_tooltip = new Tooltip("Additionally get DLC data from SteamDB.\n" +
"Especially useful for DLC that is not listed on the Steam Store.\n" +
"This sometimes doesn't work because SteamDB may block access for scrapers.");
steamdb_dlc_checkbox.setTooltip(steamdb_dlc_tooltip);
Tooltip.install(steamdb_dlc_checkbox, steamdb_dlc_tooltip);
}
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());
@ -126,8 +174,8 @@ public class Controller {
}
private void emptyFields() {
creamApiDllAppliedIcon.setGlyphName("TIMES");
creamApiConfigExistsIcon.setGlyphName("TIMES");
/*setIndicator(creamApiDllApplied, creamApiDllAppliedIcon, COLOR_FAILURE, GLYPH_FAILURE);
setIndicator(creamApiConfigExists, creamApiConfigExistsIcon, COLOR_FAILURE, GLYPH_FAILURE);*/
appId_textfield.setText("");
dlc_textarea.setText("");
game_name_textfield.setText("");
@ -137,16 +185,6 @@ public class Controller {
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<String> appIdChangesGameName() {
return (observable, oldValue, newValue) -> {
int appId;
@ -177,10 +215,10 @@ public class Controller {
state_label.setText("Successfully reset all fields!");
}
} catch (NoSuchElementException e) {
System.err.println("Error reading cream_api.ini! " +
logger.warn("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!");
logger.warn("Can't fill out fields, no configuration file set!");
if (!silent) {
state_label.setText("Could not reset fields, no configuration file set!");
}
@ -189,8 +227,6 @@ public class Controller {
}
private void updateIndicators() {
Color colorSuccess = Color.web("#43A047");
Color colorFailure = Color.web("#E53935");
try {
is64Bit = false;
if (!steamApiPathString.isEmpty()) {
@ -202,37 +238,169 @@ public class Controller {
String md5 = DigestUtils.md5Hex(is);
isSameFile = Objects.equals(md5, handler.getDllMd5(is64Bit));
if (isSameFile) {
creamApiDllApplied.setTextFill(colorSuccess);
creamApiDllAppliedIcon.setFill(colorSuccess);
creamApiDllAppliedIcon.setGlyphName("CHECK");
setIndicator(creamApiDllApplied, creamApiDllAppliedIcon, COLOR_SUCCESS, GLYPH_SUCCESS);
} else {
creamApiDllApplied.setTextFill(colorFailure);
creamApiDllAppliedIcon.setFill(colorFailure);
creamApiDllAppliedIcon.setGlyphName("TIMES");
setIndicator(creamApiDllApplied, creamApiDllAppliedIcon, COLOR_FAILURE, GLYPH_FAILURE);
}
Path configPath = Paths.get(config.getPath());
if (Files.exists(configPath) && Files.size(configPath) > 0L) {
creamApiConfigExists.setTextFill(colorSuccess);
creamApiConfigExistsIcon.setFill(colorSuccess);
creamApiConfigExistsIcon.setGlyphName("CHECK");
setIndicator(creamApiConfigExists, creamApiConfigExistsIcon, COLOR_SUCCESS, GLYPH_SUCCESS);
} else {
creamApiConfigExists.setTextFill(colorFailure);
creamApiConfigExistsIcon.setFill(colorFailure);
creamApiConfigExistsIcon.setGlyphName("TIMES");
setIndicator(creamApiConfigExists, creamApiConfigExistsIcon, COLOR_FAILURE, GLYPH_FAILURE);
}
}
} 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");
logger.warn("Resetting visual indicators!");
setIndicator(creamApiDllApplied, creamApiDllAppliedIcon, COLOR_FAILURE, GLYPH_FAILURE);
setIndicator(creamApiConfigExists, creamApiConfigExistsIcon, COLOR_FAILURE, GLYPH_FAILURE);
}
}
private void setIndicator(Label label, FontAwesomeIconView icon, Color color, String glyphName) {
label.setTextFill(color);
icon.setFill(color);
icon.setGlyphName(glyphName);
}
public void save() {
saveService().start();
}
public void getAppId() {
final List<App> games = cache.findListOfGames(game_name_textfield.getText());
if (games.isEmpty()) {
logger.info("No game name was given, setting AppID to \"-1\"!");
appId_textfield.setText("-1");
} else if (games.size() == 1) {
App game = games.get(0);
game_name_textfield.setText(game.getName());
appId_textfield.setText(String.valueOf(game.getAppId()));
} else {
logger.info("Multiple results found, opening search result window!");
try {
URL resource = ClassLoader.getSystemResource("xyz/jeddunk/autocreamapi/searchResultWindow.fxml");
FXMLLoader fxmlLoader = new FXMLLoader(resource);
Parent root1 = fxmlLoader.load();
SearchResultWindowController c = fxmlLoader.getController();
c.initMe(games);
c.setParentController(this);
Stage stage = new Stage();
stage.initModality(Modality.APPLICATION_MODAL);
stage.setResizable(false);
stage.setTitle("Choose game...");
stage.setScene(new Scene(root1));
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void unlockAll_disableDlcTextArea() {
dlc_textarea.setDisable(unlock_all_checkbox.isSelected());
getDlcList_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() {
getDlcListService().start();
}
public void openFileChooser() {
FileChooser chooser = new FileChooser();
chooser.setTitle("Choose steam_api(64).dll...");
FileChooser.ExtensionFilter filter =
new FileChooser.ExtensionFilter("Steam API DLL",
"steam_api.dll", "steam_api64.dll");
chooser.getExtensionFilters().add(filter);
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();
} catch (NullPointerException e) {
logger.warn("Could not set config file location! Did you cancel the file chooser?");
}
emptyFields();
reset(true);
logger.info("File chosen: " + steamApiPathString);
logger.info("Ready.");
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 {
logger.info("Setting up DLL...");
Path path = Paths.get(steamApiPathString);
copyDllFile(path, isSameFile);
findAdditionalDll(path);
logger.info("Set up DLL successfully!");
}
private void findAdditionalDll(Path path) throws IOException {
String aDllString = is64Bit ? "\\steam_api.dll" : "\\steam_api64.dll";
Path dir = path.getParent();
Path aDll = Paths.get(dir.toString() + aDllString);
if (Files.exists(aDll)) {
logger.info("Additional DLL found: (" + aDll.toString() + ")!");
InputStream is = Files.newInputStream(aDll);
String md5 = DigestUtils.md5Hex(is);
boolean aIsSameFile = Objects.equals(md5, handler.getDllMd5(!is64Bit));
copyDllFile(aDll, aIsSameFile);
}
}
private void copyDllFile(Path path, boolean isSameFile) throws IOException {
if (!isSameFile) {
String pathOrigString = steamApiPathString;
String replacement = is64Bit ? "steam_api64_o.dll" : "steam_api_o.dll";
pathOrigString =
pathOrigString
.replaceFirst(REGEX, replacement);
Path pathOrig = Paths.get(pathOrigString);
if (!Files.exists(pathOrig)) {
logger.info("Renaming " + path.toString() + " to " + replacement + "...");
Files.move(path, pathOrig);
} else {
logger.info(pathOrigString + " already exists!");
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);
}
logger.info("Copying CreamAPI DLL to " + path.toString() + " ...");
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);
getDlcList_button.setDisable(b);
}
public void resetFromButton() {
reset(false);
}
private Service<Void> saveService() {
Service<Void> s = new Service<Void>() {
@Override
protected Task<Void> createTask() {
@ -252,7 +420,7 @@ public class Controller {
e.printStackTrace();
cancel();
} catch (NullPointerException e) {
System.err.println("No configuration file set!");
logger.warn("No configuration file set!");
cancel();
}
updateIndicators();
@ -273,51 +441,21 @@ public class Controller {
setDisableAllButtons(false);
state_label.setText("Could not save configuration file!");
});
s.start();
return s;
}
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() {
private Service<Void> getDlcListService() {
Service<Void> s = new Service<Void>() {
@Override
protected Task<Void> createTask() {
return new Task<Void>() {
@Override
protected Void call() {
try {
Map<Number, String> 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();
}
Map<Integer, String> collect =
cache.getDlcMap(appId_textfield.getText(), steamdb_dlc_checkbox.isSelected());
StringBuilder sb = new StringBuilder();
collect.forEach((k, v) -> sb.append(k).append("=").append(v).append("\n"));
dlc_textarea.setText(sb.toString());
return null;
}
};
@ -335,88 +473,64 @@ public class Controller {
setDisableAllButtons(false);
state_label.setText("Could not get list of DLCs!");
});
s.start();
return s;
}
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?");
static class ComboBoxAutoComplete<T> {
private ComboBox<T> cmb;
String filter = "";
private ObservableList<T> originalItems;
public ComboBoxAutoComplete(ComboBox<T> cmb) {
this.cmb = cmb;
originalItems = FXCollections.observableArrayList(cmb.getItems());
cmb.setTooltip(new Tooltip());
cmb.setOnKeyPressed(this::handleOnKeyPressed);
cmb.setOnHidden(this::handleOnHiding);
}
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);
}
public void handleOnKeyPressed(KeyEvent e) {
SingleSelectionModel<T> sm = this.cmb.getSelectionModel();
ObservableList<T> filteredList = FXCollections.observableArrayList();
KeyCode code = e.getCode();
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);
if (code.isLetterKey()) {
filter += e.getText();
}
//Files.deleteIfExists(path);
Files.copy(handler.getDllPath(is64Bit), path);
if (code == KeyCode.BACK_SPACE && filter.length() > 0) {
filter = filter.substring(0, filter.length() - 1);
cmb.getItems().setAll(originalItems);
}
if (code == KeyCode.ESCAPE) {
filter = "";
}
if (filter.length() == 0) {
filteredList = originalItems;
cmb.getTooltip().hide();
} else {
Stream<T> items = cmb.getItems().stream();
String txtUsr = filter.toLowerCase();
items.filter(el -> el.toString().toLowerCase().contains(txtUsr)).forEach(filteredList::add);
cmb.getTooltip().setText(txtUsr);
Window stage = cmb.getScene().getWindow();
double posX = stage.getX() + cmb.getBoundsInParent().getMinX();
double posY = stage.getY() + cmb.getBoundsInParent().getMinY();
cmb.getTooltip().show(stage, posX, posY);
cmb.show();
}
cmb.getItems().setAll(filteredList);
sm.selectFirst();
}
public void handleOnHiding(Event e) {
filter = "";
cmb.getTooltip().hide();
T s = cmb.getSelectionModel().getSelectedItem();
cmb.getItems().setAll(originalItems);
cmb.getSelectionModel().select(s);
}
}
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);
}
}

View File

@ -13,6 +13,8 @@
* <https://www.gnu.org/licenses/>.
*/
package xyz.jeddunk.autocreamapi;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
@ -21,13 +23,18 @@ import javafx.stage.Stage;
public class Main extends Application {
private static final int MIN_WIDTH = 905;
private static final int MIN_HEIGHT = 450;
private static final int PREF_WIDTH = 1200;
private static final int PREF_HEIGHT = 600;
@Override
public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(ClassLoader.getSystemResource("mainWindow.fxml"));
Parent root = FXMLLoader.load(ClassLoader.getSystemResource("xyz/jeddunk/autocreamapi/mainWindow.fxml"));
primaryStage.setTitle("Auto CreamAPI");
primaryStage.setMinWidth(655 + 25);
primaryStage.setMinHeight(400 + 50);
primaryStage.setScene(new Scene(root, 1200, 600));
primaryStage.setMinWidth(MIN_WIDTH + 25);
primaryStage.setMinHeight(MIN_HEIGHT + 50);
primaryStage.setScene(new Scene(root, PREF_WIDTH, PREF_HEIGHT));
primaryStage.show();
}

View File

@ -0,0 +1,109 @@
/*
* 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
* <https://www.gnu.org/licenses/>.
*/
package xyz.jeddunk.autocreamapi;import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import javafx.scene.control.cell.TreeItemPropertyValueFactory;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.stage.Stage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import xyz.jeddunk.autocreamapi.pojo.App;
import java.net.URL;
import java.util.List;
import java.util.ResourceBundle;
import static java.text.MessageFormat.format;
public class SearchResultWindowController implements Initializable {
final Logger logger = LoggerFactory.getLogger(SearchResultWindowController.class);
@FXML
public Button okButton;
@FXML
public Button cancelButton;
@FXML
public TreeTableView<App> gameTable;
@FXML
public TreeTableColumn<App, Integer> appIdCol;
@FXML
public TreeTableColumn<App, String> nameCol;
public Controller parent;
private long lastTime;
private boolean isDblClicked;
public SearchResultWindowController() {
}
@FXML
@Override
public void initialize(URL location, ResourceBundle resources) {
}
public void initMe(List<App> games) {
TreeItem<App> root = new TreeItem<>();
appIdCol.setCellValueFactory(new TreeItemPropertyValueFactory<>("appId"));
nameCol.setCellValueFactory(new TreeItemPropertyValueFactory<>("name"));
games.forEach(game -> root.getChildren().add(new TreeItem<>(game)));
gameTable.setRoot(root);
}
public void confirm() {
App app = gameTable.getSelectionModel().getSelectedItem().getValue();
logger.info(format("Game selected: {0} ({1})!", app.getName(), app.getAppId()));
parent.game_name_textfield.setText(app.getName());
parent.appId_textfield.setText(String.valueOf(app.getAppId()));
Stage current = (Stage) okButton.getScene().getWindow();
current.close();
}
public void cancel() {
logger.info("Closing window without setting game!");
/*parent.game_name_textfield.setText("");
parent.appId_textfield.setText("-1");*/
Stage current = (Stage) cancelButton.getScene().getWindow();
current.close();
}
public void setParentController(Controller controller) {
parent = controller;
}
public void doubleclickConfirm(MouseEvent mouseEvent) {
if (mouseEvent.getButton() == MouseButton.PRIMARY) {
long diff;
long currentTime = System.currentTimeMillis();
if (lastTime != 0 && currentTime != 0) {
diff = currentTime - lastTime;
isDblClicked = (diff <= 215);
}
lastTime = currentTime;
if (isDblClicked) {
/*App app = gameTable.getSelectionModel().getSelectedItem().getValue();
parent.game_name_textfield.setText(app.getName());
parent.appId_textfield.setText(String.valueOf(app.getAppId()));
Stage current = (Stage) gameTable.getScene().getWindow();
current.close();*/
confirm();
}
}
}
}

View File

@ -13,7 +13,7 @@
* <https://www.gnu.org/licenses/>.
*/
package pojo;
package xyz.jeddunk.autocreamapi.pojo;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;

View File

@ -13,7 +13,7 @@
* <https://www.gnu.org/licenses/>.
*/
package pojo;
package xyz.jeddunk.autocreamapi.pojo;
import java.time.Instant;
import java.util.List;

View File

@ -13,18 +13,24 @@
* <https://www.gnu.org/licenses/>.
*/
package util;
package xyz.jeddunk.autocreamapi.util;
import org.apache.commons.configuration2.*;
import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder;
import org.apache.commons.configuration2.builder.fluent.Configurations;
import org.apache.commons.configuration2.ex.ConfigurationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.text.MessageFormat;
import java.util.*;
import static java.text.MessageFormat.format;
public class CreamApiConfig {
final Logger logger = LoggerFactory.getLogger(CreamApiConfig.class);
private static CreamApiConfig configInstance;
private static final Configurations CONFIGS = new Configurations();
@ -48,25 +54,50 @@ public class CreamApiConfig {
config = CONFIGS.ini(path);
config.setCommentLeadingCharsUsedInInput(";");
} catch (ConfigurationException e) {
System.err.println("No config file found in default location!");
logger.warn("No config file found!");
//e.printStackTrace();
}
File langFile = new File("languages.txt");
try {
BufferedReader fIn = new BufferedReader(new FileReader(langFile));
fIn.lines().filter(line -> !line.isEmpty() && !line.startsWith("#")).forEach(languages::add);
} catch (IOException e) {
e.printStackTrace();
}
// https://partner.steamgames.com/doc/store/localization#supported_languages
languages.addAll(Arrays.asList(
"english",
"latam",
"brazilian",
"german",
"french",
"italian",
"portuguese",
"spanish",
"russian",
"schinese",
"tchinese",
"japanese",
"koreana",
"arabic",
"bulgarian",
"czech",
"danish",
"dutch",
"finnish",
"greek",
"hungarian",
"norwegian",
"polish",
"romanian",
"swedish",
"thai",
"turkish",
"ukrainian",
"vietnamese"
));
try {
read();
} catch (NoSuchElementException e) {
System.err.println("Error reading cream_api.ini! " +
logger.warn("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!");
logger.warn("Can't fill out fields, no configuration file set!");
}
}
@ -78,6 +109,7 @@ public class CreamApiConfig {
}
public void read() throws NullPointerException, NoSuchElementException {
logger.info("Reading config file...");
appId = config.getInt("steam.appid");
language = config.getString("steam.language");
if (language == null) {
@ -88,9 +120,11 @@ public class CreamApiConfig {
forceOffline = config.getBoolean("steam.forceoffline");
final SubnodeConfiguration dlc_section = config.getSection("dlc");
dlc_section.getKeys().forEachRemaining(k -> dlc.put(Integer.parseInt(k), dlc_section.getString(k)));
logger.info("Successfully read config file!");
}
public void sync() throws ConfigurationException {
logger.info("Saving config file...");
FileBasedConfigurationBuilder<INIConfiguration> builder = CONFIGS.iniBuilder(path);
config = builder.getConfiguration();
config.setCommentLeadingCharsUsedInInput(";");
@ -111,6 +145,7 @@ public class CreamApiConfig {
config.setProperty("steam_misc.disableuserinterface", false);
builder.save();
logger.info("Saved successfully!");
}
// DLC list parsing
@ -126,7 +161,7 @@ public class CreamApiConfig {
Arrays.stream(str.split("\\R+")).forEach(line -> {
final String[] split = line.split("\\s*=\\s*", 2);
if (split.length == 2) dlc.put(Integer.parseInt(split[0]), split[1]);
else System.err.println(MessageFormat.format("Error while splitting line: \"{0}\"", line));
else logger.error(format("Error while splitting line: \"{0}\"", line));
});
}
@ -179,9 +214,9 @@ public class CreamApiConfig {
public void setConfig(String path) throws ConfigurationException, IOException {
File file = new File(path);
if (file.createNewFile()) {
System.out.println("New config file created!");
logger.info("New config file created!");
} else {
System.out.println("Using existing config file!");
logger.info("Using existing config file!");
}
this.config = CONFIGS.ini(path);
this.config.setCommentLeadingCharsUsedInInput(";");

View File

@ -13,7 +13,7 @@
* <https://www.gnu.org/licenses/>.
*/
package util;
package xyz.jeddunk.autocreamapi.util;
import org.apache.commons.codec.digest.DigestUtils;
@ -31,10 +31,8 @@ public class CreamApiDllHandler {
private final String steamApi64DllMd5;
private CreamApiDllHandler() throws IOException {
String steamApiDllMd5 = DigestUtils.md5Hex(Files.newInputStream(steamApiDllPath));
String steamApi64DllMd5 = DigestUtils.md5Hex(Files.newInputStream(steamApi64DllPath));
this.steamApiDllMd5 = steamApiDllMd5;
this.steamApi64DllMd5 = steamApi64DllMd5;
this.steamApiDllMd5 = DigestUtils.md5Hex(Files.newInputStream(steamApiDllPath));
this.steamApi64DllMd5 = DigestUtils.md5Hex(Files.newInputStream(steamApi64DllPath));
}
public static synchronized CreamApiDllHandler getInstance() throws IOException {

View File

@ -0,0 +1,279 @@
/*
* 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
* <https://www.gnu.org/licenses/>.
*/
package xyz.jeddunk.autocreamapi.util;
import com.gargoylesoftware.htmlunit.BrowserVersion;
import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.gargoylesoftware.htmlunit.util.Cookie;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken;
import kong.unirest.HttpResponse;
import kong.unirest.Unirest;
import me.xdrop.fuzzywuzzy.FuzzySearch;
import me.xdrop.fuzzywuzzy.model.BoundExtractedResult;
import org.jsoup.HttpStatusException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import xyz.jeddunk.autocreamapi.pojo.App;
import xyz.jeddunk.autocreamapi.pojo.SteamAppsList;
import xyz.jeddunk.autocreamapi.util.env.MainEnv;
import java.io.*;
import java.lang.reflect.Type;
import java.net.URL;
import java.time.Duration;
import java.time.Instant;
import java.util.*;
import java.util.stream.Collectors;
public class SteamAppsListCache {
final Logger logger = LoggerFactory.getLogger(SteamAppsListCache.class);
private SteamAppsList list = new SteamAppsList();
private final File cacheFile = new File("steamapps.json");
private MainEnv env;
private String cfduid = "";
public SteamAppsListCache() {
try {
Class<?> envDefault = Class.forName("xyz.jeddunk.autocreamapi.util.env.Default");
env = (MainEnv) envDefault.newInstance();
// System.out.println(env.getKey());
} catch (ClassNotFoundException e) {
logger.debug("Default environment missing, using main environemnt...");
env = new MainEnv();
} catch (IllegalAccessException | InstantiationException e) {
// Only thrown by newInstance()
e.printStackTrace();
}
//boolean fileFound = true;
try {
getListFromFile();
} catch (FileNotFoundException e) {
logger.info("File does not exist, trying to create steamapps.json for the first time...");
//fileFound = false;
sync();
} catch (JsonSyntaxException e) {
logger.warn("File seems to be corrupt, trying to recreate steamapps.json...");
//fileFound = false;
sync();
}
if (Instant.now().isAfter(list.getTimestamp().plus(Duration.ofDays(3)))) {
logger.info("List in file is not recent!");
sync();
}
}
private void sync() {
getListFromApi();
try {
saveListToFile();
} catch (IOException ex) {
ex.printStackTrace();
}
}
public App getGame(int appId) {
return list.getSteamAppsList().stream().filter(app -> app.getAppId() == appId).findFirst().orElse(null);
}
@SuppressWarnings("unused")
public App getGame(String name) {
return list.getSteamAppsList().stream()
.filter(app -> app.getName().equalsIgnoreCase(name)).findFirst().orElse(null);
}
public List<App> findListOfGames(String name) {
List<BoundExtractedResult<App>> match = FuzzySearch.extractSorted(name, list.getSteamAppsList(), app ->
app.getName().toLowerCase().replaceAll("[^a-zA-Z0-9\\s+]", ""), 80);
List<App> collect = match.stream().map(BoundExtractedResult::getReferent).collect(Collectors.toList());
for (App app : collect) {
if (app.getName().replaceAll("[^a-zA-Z0-9\\s+]", "")
.equalsIgnoreCase(name.replaceAll("[^a-zA-Z0-9\\s+]", ""))) {
collect = new ArrayList<>();
collect.add(app);
break;
}
}
return collect;
}
private void getListFromApi() {
logger.info("Trying to get SteamAppList from API...");
List<App> apps = getApps();
list.setTimestamp(Instant.now());
list.setSteamAppsList(apps);
}
private List<App> getApps() {
HttpResponse<String> httpResponse =
Unirest.get("https://api.steampowered.com/IStoreService/GetAppList/v1/" +
"?key=" + env.getKey() + "&include_games=1&max_results=50000").asString();
return new Gson()
.fromJson(httpResponse.getBody(), App.Rezponze.Download.class)
.getResponse().getApps();
}
private void saveListToFile() throws IOException {
logger.info("Trying to save SteamAppList to file \"" + cacheFile.getAbsolutePath() + "\"...");
Gson gson = new Gson();
String jsonString = gson.toJson(list);
BufferedWriter fOut = new BufferedWriter(new FileWriter(cacheFile));
fOut.write(jsonString);
fOut.close();
logger.info("Successfully saved SteamAppList to file \"" + cacheFile.getAbsolutePath() + "\"...");
}
private void getListFromFile() throws FileNotFoundException, JsonSyntaxException {
logger.info("Trying to get SteamAppList from file \"" + cacheFile.getAbsolutePath() + "\"...");
BufferedReader fIn = new BufferedReader(new FileReader(cacheFile));
String json = fIn.lines().collect(Collectors.joining());
final Type type = new TypeToken<SteamAppsList>() {
}.getType();
Gson gson = new Gson();
list = gson.fromJson(json, type);
logger.info("Successfully got SteamAppList from file \"" + cacheFile.getAbsolutePath() + "\"...");
}
public Map<Integer, String> getDlcMap(String appId, boolean use_steamdb) {
logger.info("Getting list of DLC for AppID: " + appId + "...");
Map<Integer, String> steamStoreDLCs = new HashMap<>();
Map<Integer, String> steamDbDLCs = new HashMap<>();
// Steam Store
try {
logger.info("Trying to get DLC from Steam store page...");
Document steamDoc = Jsoup
.connect("https://store.steampowered.com/app/" + appId + "/")
.cookie("birthtime", "470703601")
.cookie("wants_mature_content", "1")
.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);
}
logger.info("Got DLC from Steam store page successfully.");
} catch (HttpStatusException e) {
logger.error(e.getUrl());
if (e.getStatusCode() == 404) {
logger.error("App ID empty or not found! (HTTP Status Code: 404)");
} else {
logger.error("Error occurred while trying to get list of DLCs " +
"(HTTP Status Code: " + e.getStatusCode() + ")");
}
} catch (NullPointerException | IOException e) {
// ignore
}
// SteamDB
if (use_steamdb) {
logger.info("Trying to get DLC from SteamDB...");
if (cfduid.equals("")) {
logger.info("Missing CF cookie, trying to get it...");
WebClient client = new WebClient(BrowserVersion.CHROME);
client.getOptions().setCssEnabled(false);
client.getOptions().setJavaScriptEnabled(false);
client.getOptions().setThrowExceptionOnFailingStatusCode(false);
client.getOptions().setRedirectEnabled(true);
client.getCache().setMaxSize(0);
/*client.waitForBackgroundJavaScript(10000);
client.setJavaScriptTimeout(10000);
client.waitForBackgroundJavaScriptStartingBefore(10000);*/
try {
String urlString = "https://steamdb.info/";
HtmlPage page = client.getPage(urlString);
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (page) {
page.wait(8000);
}
//Print cookies for test purposes. Comment out in production.
URL url = new URL(urlString);
for (Cookie c : client.getCookies(url)) {
//System.out.println(c.getName() +"="+c.getValue());
if (c.getName().equals("__cfduid")) {
cfduid = c.getValue();
logger.info("Got CF cookie successfully.");
}
}
//This prints the content after bypassing Cloudflare.
// System.out.println(client.getPage(url).getWebResponse().getContentAsString());
} catch (FailingHttpStatusCodeException | IOException | InterruptedException e) {
// e.printStackTrace();
logger.error("Could not get CF cookie, skipping SteamDB DLC list...");
}
}
if ((!(cfduid.equals(""))) && (!(cfduid.equals("N/A")))) {
try {
Document steamDbDoc = Jsoup
.connect("https://steamdb.info/app/" + appId + "/dlc/")
.cookie("__cfduid", cfduid)
.userAgent(BrowserVersion.CHROME.getUserAgent())
.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);
}
logger.info("Got DLC from SteamDB successfully.");
} catch (HttpStatusException e) {
logger.error(e.getUrl());
if (e.getStatusCode() == 404) {
logger.error("App ID empty or not found! (HTTP Status Code: 404)");
} else {
logger.error("Error occurred while trying to get list of DLCs " +
"(HTTP Status Code: " + e.getStatusCode() + ")");
}
} catch (NullPointerException | IOException e) {
// ignore
}
}
}
logger.info("Merging both DLC lists...");
Map<Integer, String> allDLCs = new HashMap<>(steamStoreDLCs);
steamDbDLCs.forEach(allDLCs::putIfAbsent);
logger.info("DLC list is done!");
return allDLCs.entrySet().stream()
.sorted(Map.Entry.comparingByKey())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
(oldValue, newValue) -> oldValue, LinkedHashMap::new));
}
}

View File

@ -13,7 +13,7 @@
* <https://www.gnu.org/licenses/>.
*/
package util.env;
package xyz.jeddunk.autocreamapi.util.env;
public class MainEnv {
String key = "";

View File

@ -1 +1 @@
Main-Class: Main
Main-Class: xyz.jeddunk.autocreamapi.Main

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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
~ <https://www.gnu.org/licenses/>.
-->
<configuration>
<property name="PATTERN" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{0} - %msg%n"/>
<!-- Insert the current time formatted as "yyyyMMdd'T'HHmmss" under
the key "bySecond" into the logger context. This value will be
available to all subsequent configuration elements. -->
<timestamp key="bySecond" datePattern="yyyy'_'MM'_'dd'-'HH'_'mm'_'ss"/>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!--withJansi>true</withJansi-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${PATTERN}</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<!-- use the previously created timestamp to create a uniquely
named log file -->
<file>autocreamapi_${bySecond}.log</file>
<encoder>
<pattern>${PATTERN}</pattern>
</encoder>
</appender>
<logger name="com.base22" level="TRACE"/>
<root level="debug">
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE" />
</root>
</configuration>

View File

@ -1,122 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.JFXCheckBox?>
<?import com.jfoenix.controls.JFXComboBox?>
<?import com.jfoenix.controls.JFXTextArea?>
<?import com.jfoenix.controls.JFXTextField?>
<?import de.jensd.fx.glyphs.fontawesome.FontAwesomeIconView?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.text.Font?>
<!--
~ 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
~ <https://www.gnu.org/licenses/>.
-->
<BorderPane prefHeight="361.0" prefWidth="693.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Controller">
<center>
<GridPane hgap="10.0" minHeight="360.0" minWidth="655.0" vgap="10.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308" minWidth="-Infinity" prefWidth="375.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity" minWidth="-Infinity" prefWidth="120.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity" minWidth="-Infinity" prefWidth="120.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="-Infinity" prefHeight="60.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<JFXTextField fx:id="path_textfield" promptText="Path to game's steam_api(64).dll..." GridPane.columnSpan="2" />
<JFXButton fx:id="path_button" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" onAction="#openFileChooser" ripplerFill="BLACK" style="-fx-background-color: #ddd;" GridPane.columnIndex="2">
<graphic>
<FontAwesomeIconView glyphName="FOLDER_OPEN" glyphSize="24" />
</graphic>
</JFXButton>
<JFXTextField fx:id="game_name_textfield" promptText="Game..." GridPane.rowIndex="1" />
<JFXButton fx:id="getAppId_button" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" onAction="#getAppId" ripplerFill="BLACK" style="-fx-background-color: #ddd;" GridPane.columnIndex="1" GridPane.rowIndex="1">
<graphic>
<FontAwesomeIconView glyphName="SEARCH" glyphSize="24" />
</graphic>
</JFXButton>
<JFXTextField fx:id="appId_textfield" prefWidth="299.0" promptText="Steam AppID..." GridPane.columnIndex="2" GridPane.rowIndex="1" />
<JFXComboBox fx:id="language_combobox" editable="true" promptText="Language" GridPane.columnSpan="2147483647" GridPane.rowIndex="2" />
<JFXCheckBox fx:id="offline_checkbox" text="Force offline mode" GridPane.columnSpan="2147483647" GridPane.rowIndex="3" />
<JFXCheckBox fx:id="extra_protection_checkbox" text="Try to bypass game-specific protection" GridPane.columnSpan="2147483647" GridPane.rowIndex="4" />
<JFXCheckBox fx:id="unlock_all_checkbox" onAction="#unlockAll_disableDlcTextArea" text="Unlock all DLC (if possible)" GridPane.columnSpan="2147483647" GridPane.rowIndex="5" />
<JFXTextArea fx:id="dlc_textarea" promptText="List of DLC..." GridPane.columnSpan="2147483647" GridPane.rowIndex="6" />
<JFXButton fx:id="retrieveDlcList_button" maxHeight="1.7976931348623157E308" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" onAction="#getDlcList" ripplerFill="BLACK" style="-fx-background-color: #ddd;" text="Get DLCs for AppID" GridPane.rowIndex="7" />
<JFXButton fx:id="save_button" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" onAction="#save" ripplerFill="BLACK" style="-fx-background-color: #ddd;" text="Save" GridPane.columnIndex="1" GridPane.rowIndex="7" />
<JFXButton fx:id="reset_button" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" onAction="#resetFromButton" ripplerFill="BLACK" style="-fx-background-color: #ddd;" text="Reset" GridPane.columnIndex="2" GridPane.rowIndex="7" />
<BorderPane.margin>
<Insets />
</BorderPane.margin>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</GridPane>
</center>
<bottom>
<Label fx:id="state_label" maxWidth="1.7976931348623157E308" minHeight="25.0" minWidth="-Infinity" style="-fx-background-color: #ddd; -fx-border-color: #aaa;" text="Ready." textFill="#555555" BorderPane.alignment="CENTER">
<BorderPane.margin>
<Insets />
</BorderPane.margin>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding></Label>
</bottom>
<right>
<GridPane maxHeight="-Infinity" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="250.0"
BorderPane.alignment="CENTER">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES"/>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES"/>
</rowConstraints>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
</padding>
<Label maxHeight="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity"
text="CreamAPI DLL applied" fx:id="creamApiDllApplied">
<font>
<Font size="14.0"/>
</font>
<graphic>
<FontAwesomeIconView fx:id="creamApiDllAppliedIcon" glyphName="TIMES" size="20"/>
</graphic>
</Label>
<Label layoutX="20.0" layoutY="20.0" maxHeight="1.7976931348623157E308" minHeight="-Infinity"
minWidth="-Infinity" text="CreamAPI configuration file exists" GridPane.rowIndex="1"
fx:id="creamApiConfigExists">
<font>
<Font size="14.0"/>
</font>
<graphic>
<FontAwesomeIconView fx:id="creamApiConfigExistsIcon" glyphName="TIMES" size="20"/>
</graphic>
</Label>
</GridPane>
</right>
</BorderPane>

View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -0,0 +1,144 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.JFXCheckBox?>
<?import com.jfoenix.controls.JFXComboBox?>
<?import com.jfoenix.controls.JFXTextArea?>
<?import com.jfoenix.controls.JFXTextField?>
<?import de.jensd.fx.glyphs.fontawesome.FontAwesomeIconView?>
<?import java.net.URL?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TitledPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.text.Font?>
<!--
~ 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
~ <https://www.gnu.org/licenses/>.
-->
<BorderPane prefHeight="450.0" prefWidth="705.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="xyz.jeddunk.autocreamapi.Controller">
<center>
<GridPane hgap="10.0" minHeight="410.0" minWidth="655.0" vgap="10.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308" minWidth="-Infinity" prefWidth="375.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity" minWidth="-Infinity" prefWidth="120.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity" minWidth="-Infinity" prefWidth="120.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="-Infinity" prefHeight="60.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
<TitledPane animated="false" collapsible="false" maxHeight="1.7976931348623157E308" styleClass="dlcSettings"
text="DLC Settings" GridPane.columnSpan="2147483647" GridPane.rowIndex="5">
<GridPane hgap="10.0" maxHeight="1.7976931348623157E308" vgap="10.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
</columnConstraints>
<rowConstraints>
<RowConstraints/>
<RowConstraints/>
<RowConstraints maxHeight="1.7976931348623157E308"/>
</rowConstraints>
<JFXCheckBox fx:id="unlock_all_checkbox" onAction="#unlockAll_disableDlcTextArea"
text="Unlock all DLC (if possible)" GridPane.columnSpan="2147483647"/>
<JFXTextArea fx:id="dlc_textarea" maxHeight="1.7976931348623157E308" prefHeight="999999.0"
promptText="List of DLC..." GridPane.columnSpan="2147483647" GridPane.rowIndex="2"
GridPane.rowSpan="2147483647"/>
<JFXCheckBox fx:id="steamdb_dlc_checkbox" text="Additionally use SteamDB for DLCs"
GridPane.rowIndex="1"/>
</GridPane>
</TitledPane>
<JFXTextField fx:id="path_textfield" promptText="Path to game's steam_api(64).dll..." GridPane.columnSpan="2" />
<JFXButton fx:id="path_button" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" onAction="#openFileChooser" ripplerFill="BLACK" GridPane.columnIndex="2">
<graphic>
<FontAwesomeIconView glyphName="FOLDER_OPEN" glyphSize="24" />
</graphic>
</JFXButton>
<JFXTextField fx:id="game_name_textfield" promptText="Game..." GridPane.rowIndex="1" />
<JFXButton fx:id="getAppId_button" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" onAction="#getAppId" ripplerFill="BLACK" GridPane.columnIndex="1" GridPane.rowIndex="1">
<graphic>
<FontAwesomeIconView glyphName="SEARCH" glyphSize="24" />
</graphic>
</JFXButton>
<JFXTextField fx:id="appId_textfield" prefWidth="299.0" promptText="Steam AppID..." GridPane.columnIndex="2" GridPane.rowIndex="1" />
<JFXComboBox fx:id="language_combobox" editable="true" promptText="Language" GridPane.columnSpan="2147483647" GridPane.rowIndex="2" />
<JFXCheckBox fx:id="offline_checkbox" text="Force offline mode" GridPane.columnSpan="2147483647" GridPane.rowIndex="3" />
<JFXCheckBox fx:id="extra_protection_checkbox" text="Try to bypass game-specific protection" GridPane.columnSpan="2147483647" GridPane.rowIndex="4" />
<JFXButton fx:id="getDlcList_button" maxHeight="1.7976931348623157E308" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" onAction="#getDlcList" ripplerFill="BLACK" text="Get DLCs for AppID" GridPane.rowIndex="6" />
<JFXButton fx:id="save_button" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" onAction="#save" ripplerFill="BLACK" text="Save" GridPane.columnIndex="1" GridPane.rowIndex="6" />
<JFXButton fx:id="reset_button" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" onAction="#resetFromButton" ripplerFill="BLACK" text="Reset" GridPane.columnIndex="2" GridPane.rowIndex="6" />
<BorderPane.margin>
<Insets />
</BorderPane.margin>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</GridPane>
</center>
<bottom>
<Label fx:id="state_label" maxWidth="1.7976931348623157E308" minHeight="25.0" minWidth="-Infinity" prefWidth="905.0" text="Ready." textFill="#555555" BorderPane.alignment="CENTER">
<BorderPane.margin>
<Insets />
</BorderPane.margin>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</Label>
</bottom>
<right>
<GridPane maxHeight="-Infinity" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="250.0" BorderPane.alignment="CENTER">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
<Label fx:id="creamApiDllApplied" maxHeight="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" text="CreamAPI DLL applied">
<font>
<Font size="14.0" />
</font>
<graphic>
<FontAwesomeIconView fx:id="creamApiDllAppliedIcon" glyphName="TIMES" size="20" />
</graphic>
</Label>
<Label fx:id="creamApiConfigExists" layoutX="20.0" layoutY="20.0" maxHeight="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" text="CreamAPI configuration file exists" GridPane.rowIndex="1">
<font>
<Font size="14.0" />
</font>
<graphic>
<FontAwesomeIconView fx:id="creamApiConfigExistsIcon" glyphName="TIMES" size="20" />
</graphic>
</Label>
</GridPane>
</right>
<stylesheets>
<URL value="@stylesheet.css" />
</stylesheets>
</BorderPane>

View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.JFXTreeTableView?>
<?import java.net.URL?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.ButtonBar?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TreeTableColumn?>
<?import javafx.scene.layout.VBox?>
<!--
~ 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
~ <https://www.gnu.org/licenses/>.
-->
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="655.0" prefWidth="420.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="xyz.jeddunk.autocreamapi.SearchResultWindowController">
<opaqueInsets>
<Insets />
</opaqueInsets>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
<Label maxWidth="1.7976931348623157E308" text="Choose a game from the list below:" />
<JFXTreeTableView fx:id="gameTable" fixedCellSize="28.0" maxHeight="1.7976931348623157E308" onMouseClicked="#doubleclickConfirm" prefHeight="570.0" prefWidth="400.0" showRoot="false">
<columns>
<TreeTableColumn fx:id="appIdCol" editable="false" maxWidth="100.0" minWidth="100.0" prefWidth="100.0" resizable="false" text="AppID" />
<TreeTableColumn fx:id="nameCol" editable="false" maxWidth="285.0" minWidth="285.0" prefWidth="285.0" resizable="false" text="Name" />
</columns>
<VBox.margin>
<Insets bottom="10.0" top="10.0" />
</VBox.margin>
</JFXTreeTableView>
<ButtonBar prefHeight="40.0" prefWidth="200.0">
<buttons>
<JFXButton fx:id="okButton" mnemonicParsing="false" onAction="#confirm" text="OK" ripplerFill="BLACK" />
<JFXButton fx:id="cancelButton" mnemonicParsing="false" onAction="#cancel" text="Cancel" ripplerFill="BLACK" />
</buttons>
</ButtonBar>
<stylesheets>
<URL value="@stylesheet.css" />
</stylesheets>
</VBox>

View File

@ -0,0 +1,71 @@
/*
* 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
* <https://www.gnu.org/licenses/>.
*/
@font-face {
font-family: 'Roboto Condensed', sans-serif;
src: url("fonts/roboto-condensed/RobotoCondensed-Regular.ttf");
}
@font-face {
font-family: 'Roboto Condensed', sans-serif;
font-weight: bold;
src: url("fonts/roboto-condensed/RobotoCondensed-Bold.ttf");
}
@font-face {
font-family: 'Roboto Condensed', sans-serif;
font-weight: italic;
src: url("fonts/roboto-condensed/RobotoCondensed-Italic.ttf");
}
@font-face {
font-family: 'Roboto Mono', monospace;
src: url("fonts/roboto-mono/RobotoMono-Regular.ttf");
}
@font-face {
font-family: 'Roboto Mono', monospace;
font-weight: bold;
src: url("fonts/roboto-mono/RobotoMono-Bold.ttf");
}
@font-face {
font-family: 'Roboto Mono', monospace;
font-weight: italic;
src: url("fonts/roboto-mono/RobotoMono-Italic.ttf");
}
* {
-fx-font-size: 14;
-fx-font-family: 'Roboto Condensed', sans-serif;
}
JFXButton {
-fx-background-color: #ddd;
}
#state_label {
-fx-background-color: #ddd;
-fx-border-color: #aaa;
}
#dlc_textarea {
-fx-font-family: 'Roboto Mono', sans-serif;
}
.dlcSettings > .title {
-fx-background-color: #ddd;
}

Binary file not shown.

Binary file not shown.

View File

@ -1 +1 @@
4.4.0.0
4.5.0.0