init repo
This commit is contained in:
commit
73fbf00bee
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
*.iml
|
||||||
|
.idea/
|
||||||
|
out/
|
||||||
|
META-INF/
|
||||||
|
target/
|
1
linux/.sync/modset.json
Normal file
1
linux/.sync/modset.json
Normal file
File diff suppressed because one or more lines are too long
26
linux/.sync/server.json
Normal file
26
linux/.sync/server.json
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"name": "[The-Town] ACE Taktik",
|
||||||
|
"password": "0815",
|
||||||
|
"ipaddress": "148.251.216.100",
|
||||||
|
"port": "2302",
|
||||||
|
"preset": "Taktik"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"modsets": [
|
||||||
|
{
|
||||||
|
"name": "Taktik",
|
||||||
|
"mods": [
|
||||||
|
"@ace",
|
||||||
|
"@CBA_A3"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ACE",
|
||||||
|
"mods": [
|
||||||
|
"@ace"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
122
linux/generateRepo.sh
Normal file
122
linux/generateRepo.sh
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
###################################################################
|
||||||
|
#Script Name :generateRepo.sh
|
||||||
|
#Description :Generate meta data for ArmA 3 Launcher
|
||||||
|
#Date :24.03.2020
|
||||||
|
#Author :Niklas Schütrumpf
|
||||||
|
#Email :niklas@mc8051.de
|
||||||
|
###################################################################
|
||||||
|
|
||||||
|
if ! [ -x "$(command -v zsyncmake)" ]; then
|
||||||
|
echo 'Error: zsync is not installed.' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! [ -x "$(command -v jq)" ]; then
|
||||||
|
echo 'Error: jq is not installed.' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! [ -x "$(command -v strings)" ]; then
|
||||||
|
echo 'Error: binutils is not installed.' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "===== ===== ===== GENERATE .ZSYNC ===== ===== ====="
|
||||||
|
FILELIST=$(find . -type f ! -path "*/.sync*" ! -path "*.zsync")
|
||||||
|
while IFS= read -r line; do
|
||||||
|
mustgenerate=false
|
||||||
|
zsyncfile="${line}.zsync"
|
||||||
|
|
||||||
|
filebyte=$(wc -c < ${line})
|
||||||
|
filedate=$(stat -c %Y ${line})
|
||||||
|
|
||||||
|
zsyncfiledate=$(strings ${zsyncfile} 2>/dev/null | grep -m 1 MTime | cut -d" " -f2-)
|
||||||
|
|
||||||
|
if [ ! -f "$zsyncfile" ]; then
|
||||||
|
echo "$zsyncfile does not exist"
|
||||||
|
mustgenerate=true
|
||||||
|
elif [[ ! $(strings ${zsyncfile} | grep -m 1 Length | cut -d" " -f2) == $filebyte ]]; then # Check file length
|
||||||
|
echo "$zsyncfile does not have corret length"
|
||||||
|
mustgenerate=true
|
||||||
|
elif [[ ! $filedate == $(date -d "${zsyncfiledate}" +"%s") ]]; then # Check date
|
||||||
|
echo "$zsyncfile does not have corret date"
|
||||||
|
mustgenerate=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$mustgenerate" = true ]; then
|
||||||
|
echo "Generate $zsyncfile"
|
||||||
|
rm ${zsyncfile} 2> /dev/null
|
||||||
|
dirfile=$(dirname ${line})
|
||||||
|
filename=$(basename ${line})
|
||||||
|
filenamezsync=$(basename ${zsyncfile})
|
||||||
|
$(cd ${dirfile} && zsyncmake -o ${filenamezsync} ${filename})
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo "Success: Generated ${zsyncfile}"
|
||||||
|
else
|
||||||
|
echo "Failure: Couldn't generate ${zsyncfile}" >&2
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Nothing changed for $line"
|
||||||
|
fi
|
||||||
|
|
||||||
|
done <<< "$FILELIST"
|
||||||
|
echo -e "===== ===== ===== ===== ===== =====\n"
|
||||||
|
|
||||||
|
|
||||||
|
echo "===== ===== ===== DELETE SINGLE ZFILE WITHOUT FILE ===== ===== ====="
|
||||||
|
ZSYNCLIST=$(find . -name "*.zsync")
|
||||||
|
while IFS= read -r zfile; do
|
||||||
|
ORIG=$(echo ${zfile} | rev | cut -c7- | rev)
|
||||||
|
if [ ! -f "$ORIG" ]; then
|
||||||
|
echo "$ORIG does not exist"
|
||||||
|
rm ${zfile}
|
||||||
|
fi
|
||||||
|
done <<< "$ZSYNCLIST"
|
||||||
|
echo -e "===== ===== ===== ===== ===== =====\n"
|
||||||
|
|
||||||
|
echo "===== ===== ===== GENERATE METADATA ===== ===== ====="
|
||||||
|
FILELIST=$(find . -maxdepth 1 ! -path "*/.sync*" ! -path "*.zsync" ! -path "." | sed 's|^./||')
|
||||||
|
declare -a JSONDATA
|
||||||
|
while IFS= read -r folder; do
|
||||||
|
echo "${folder}"
|
||||||
|
|
||||||
|
if [ -d "$folder" ]; then
|
||||||
|
echo "is dir"
|
||||||
|
x=""
|
||||||
|
foldersize=0
|
||||||
|
FILEFOLDER=$(find ${folder} -type f ! -path "*.zsync" | sed 's|^./||')
|
||||||
|
while IFS= read -r folderfile; do
|
||||||
|
filebyte=$(wc -c < ${folderfile})
|
||||||
|
foldersize=$(expr $foldersize + $filebyte)
|
||||||
|
name=$(echo ${folderfile} | cut -d"/" -f2-)
|
||||||
|
x="\"${name}\":${filebyte},${x}"
|
||||||
|
done <<< "$FILEFOLDER"
|
||||||
|
x=$(echo ${x} | rev | cut -c2- | rev)
|
||||||
|
JSONDATA+=( "\"${folder}\": {\"size\":${foldersize},\"content\":{${x}}}" )
|
||||||
|
else
|
||||||
|
echo "is file"
|
||||||
|
filebyte=$(wc -c < ${folder})
|
||||||
|
JSONDATA+=( "\"${folder}\": {\"size\":${filebyte}}" )
|
||||||
|
fi
|
||||||
|
done <<< "$FILELIST"
|
||||||
|
|
||||||
|
s=""
|
||||||
|
for i in "${JSONDATA[@]}"
|
||||||
|
do
|
||||||
|
s="${s},${i}"
|
||||||
|
done
|
||||||
|
|
||||||
|
s=$(echo ${s} | cut -c2-)
|
||||||
|
s="{${s}}"
|
||||||
|
|
||||||
|
echo $s | jq . > /dev/null
|
||||||
|
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo $s > ./.sync/modset.json
|
||||||
|
echo "Success: Generated metafile"
|
||||||
|
else
|
||||||
|
echo "Failure: invalid json generated" >&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "===== ===== ===== ===== ===== =====\n"
|
101
pom.xml
Normal file
101
pom.xml
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>de.mc8051</groupId>
|
||||||
|
<artifactId>arma3launcher</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>jitpack.io</id>
|
||||||
|
<url>https://jitpack.io</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.json</groupId>
|
||||||
|
<artifactId>json</artifactId>
|
||||||
|
<version>20190722</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.typesafe</groupId>
|
||||||
|
<artifactId>config</artifactId>
|
||||||
|
<version>1.4.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-io</groupId>
|
||||||
|
<artifactId>commons-io</artifactId>
|
||||||
|
<version>2.6</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.formdev</groupId>
|
||||||
|
<artifactId>flatlaf</artifactId>
|
||||||
|
<version>0.28</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.RalleYTN</groupId>
|
||||||
|
<artifactId>SimpleRegistry</artifactId>
|
||||||
|
<version>java8-7949ac7f06-1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.ini4j</groupId>
|
||||||
|
<artifactId>ini4j</artifactId>
|
||||||
|
<version>0.5.4</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.takari.zsync</groupId>
|
||||||
|
<artifactId>zsync-parent</artifactId>
|
||||||
|
<version>0.1.0</version>
|
||||||
|
<type>pom</type>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.bitshifted</groupId>
|
||||||
|
<artifactId>zsyncer</artifactId>
|
||||||
|
<version>-f69d844481-1</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.5.1</version>
|
||||||
|
<configuration>
|
||||||
|
<source>1.8</source>
|
||||||
|
<target>1.8</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
|
<version>2.6</version>
|
||||||
|
<configuration>
|
||||||
|
<appendAssemblyId>false</appendAssemblyId>
|
||||||
|
<finalName>${project.artifactId}</finalName>
|
||||||
|
<descriptorRefs>
|
||||||
|
<descriptorRef>
|
||||||
|
jar-with-dependencies
|
||||||
|
</descriptorRef>
|
||||||
|
</descriptorRefs>
|
||||||
|
<archive>
|
||||||
|
<manifest>
|
||||||
|
<mainClass>${project.groupId}.${project.artifactId}.ArmA3Launcher</mainClass>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>assamble</id>
|
||||||
|
<goals>
|
||||||
|
<goal>single</goal>
|
||||||
|
</goals>
|
||||||
|
<phase>package</phase>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
119
src/main/java/de/mc8051/arma3launcher/ArmA3Launcher.java
Normal file
119
src/main/java/de/mc8051/arma3launcher/ArmA3Launcher.java
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
package de.mc8051.arma3launcher;
|
||||||
|
|
||||||
|
import com.formdev.flatlaf.FlatDarkLaf;
|
||||||
|
import com.typesafe.config.Config;
|
||||||
|
import com.typesafe.config.ConfigFactory;
|
||||||
|
import de.mc8051.arma3launcher.repo.RepositoryManger;
|
||||||
|
import de.mc8051.arma3launcher.steam.SteamTimer;
|
||||||
|
import org.ini4j.Ini;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.WindowAdapter;
|
||||||
|
import java.awt.event.WindowEvent;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by gurkengewuerz.de on 23.03.2020.
|
||||||
|
*/
|
||||||
|
public class ArmA3Launcher {
|
||||||
|
|
||||||
|
public static final String[] SUPPORTED_LANGUAGES = {"en_US", "de_DE"};
|
||||||
|
|
||||||
|
public static String VERSION;
|
||||||
|
public static String CLIENT_NAME;
|
||||||
|
public static String APPLICATION_PATH;
|
||||||
|
|
||||||
|
public static Config config;
|
||||||
|
public static Ini user_config;
|
||||||
|
|
||||||
|
public static void main(String... args) throws Exception {
|
||||||
|
config = ConfigFactory.load("arma3launcher");
|
||||||
|
|
||||||
|
CLIENT_NAME = config.getString("name");
|
||||||
|
VERSION = config.getString("version");
|
||||||
|
|
||||||
|
APPLICATION_PATH = getAppData() + CLIENT_NAME;
|
||||||
|
|
||||||
|
if (new File(APPLICATION_PATH).mkdirs()) {
|
||||||
|
Logger.getLogger(ArmA3Launcher.class.getName()).log(Level.SEVERE, "Can not create " + APPLICATION_PATH);
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
File userConfigFile = new File(APPLICATION_PATH + File.separator + "config.ini");
|
||||||
|
if(!userConfigFile.exists()) {
|
||||||
|
if(!userConfigFile.createNewFile()) {
|
||||||
|
Logger.getLogger(ArmA3Launcher.class.getName()).log(Level.SEVERE, "Can not create " + userConfigFile.getAbsolutePath());
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
user_config = new Ini(userConfigFile);
|
||||||
|
|
||||||
|
Timer steamTimer = new Timer();
|
||||||
|
|
||||||
|
setLanguage();
|
||||||
|
|
||||||
|
UIManager.setLookAndFeel(new FlatDarkLaf());
|
||||||
|
|
||||||
|
JFrame frame = new JFrame(CLIENT_NAME);
|
||||||
|
LauncherGUI gui = new LauncherGUI();
|
||||||
|
frame.setContentPane(gui.mainPanel);
|
||||||
|
|
||||||
|
frame.addWindowListener(new WindowAdapter() {
|
||||||
|
@Override
|
||||||
|
public void windowClosing(WindowEvent e) {
|
||||||
|
steamTimer.cancel();
|
||||||
|
steamTimer.purge();
|
||||||
|
frame.dispose();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
frame.setMinimumSize(new Dimension(1000, 500));
|
||||||
|
|
||||||
|
frame.pack();
|
||||||
|
frame.setLocationRelativeTo(null);
|
||||||
|
|
||||||
|
steamTimer.scheduleAtFixedRate(
|
||||||
|
new SteamTimer(gui),
|
||||||
|
500, // run first occurrence immediately
|
||||||
|
10000); // run every thirty seconds
|
||||||
|
|
||||||
|
frame.setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getAppData() {
|
||||||
|
String path = "";
|
||||||
|
String OS = System.getProperty("os.name").toUpperCase();
|
||||||
|
if (OS.contains("WIN"))
|
||||||
|
path = System.getenv("APPDATA");
|
||||||
|
else if (OS.contains("MAC"))
|
||||||
|
path = System.getProperty("user.home") + "/Library/";
|
||||||
|
else if (OS.contains("NUX"))
|
||||||
|
path = System.getProperty("user.home");
|
||||||
|
else path = System.getProperty("user.dir");
|
||||||
|
|
||||||
|
path = path + File.separator;
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void setLanguage() {
|
||||||
|
String lang = Locale.getDefault().getLanguage() + "_" + Locale.getDefault().getCountry();
|
||||||
|
|
||||||
|
String clientSetting = ArmA3Launcher.user_config.get("client", "language");
|
||||||
|
if(clientSetting != null && !clientSetting.equals("system") && Arrays.asList(SUPPORTED_LANGUAGES).contains(clientSetting)) {
|
||||||
|
Locale.setDefault(new Locale(clientSetting.split("_")[0], clientSetting.split("_")[1]));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!Arrays.asList(SUPPORTED_LANGUAGES).contains(lang))
|
||||||
|
Locale.setDefault(new Locale("en", "US"));
|
||||||
|
}
|
||||||
|
}
|
1639
src/main/java/de/mc8051/arma3launcher/LauncherGUI.form
Normal file
1639
src/main/java/de/mc8051/arma3launcher/LauncherGUI.form
Normal file
File diff suppressed because it is too large
Load Diff
449
src/main/java/de/mc8051/arma3launcher/LauncherGUI.java
Normal file
449
src/main/java/de/mc8051/arma3launcher/LauncherGUI.java
Normal file
@ -0,0 +1,449 @@
|
|||||||
|
package de.mc8051.arma3launcher;
|
||||||
|
|
||||||
|
import de.mc8051.arma3launcher.interfaces.Observer;
|
||||||
|
import de.mc8051.arma3launcher.model.ModListRenderer;
|
||||||
|
import de.mc8051.arma3launcher.model.PresetListRenderer;
|
||||||
|
import de.mc8051.arma3launcher.model.PresetTableModel;
|
||||||
|
import de.mc8051.arma3launcher.model.ServerTableModel;
|
||||||
|
import de.mc8051.arma3launcher.objects.Modset;
|
||||||
|
import de.mc8051.arma3launcher.objects.Server;
|
||||||
|
import de.mc8051.arma3launcher.repo.RepositoryManger;
|
||||||
|
import de.mc8051.arma3launcher.utils.Callback;
|
||||||
|
import de.mc8051.arma3launcher.utils.LangUtils;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import javax.swing.event.ListSelectionEvent;
|
||||||
|
import javax.swing.event.ListSelectionListener;
|
||||||
|
import javax.swing.plaf.basic.BasicTabbedPaneUI;
|
||||||
|
import javax.swing.text.DefaultFormatter;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
import java.awt.event.ItemEvent;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.lang.management.ManagementFactory;
|
||||||
|
import java.net.URLDecoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by gurkengewuerz.de on 23.03.2020.
|
||||||
|
*/
|
||||||
|
public class LauncherGUI implements Observer {
|
||||||
|
public JPanel mainPanel;
|
||||||
|
private JButton settingsPanelButton;
|
||||||
|
private JButton updatePanelButton;
|
||||||
|
private JButton playPanelButton;
|
||||||
|
private JLabel subtitle;
|
||||||
|
private JLabel title;
|
||||||
|
private JTabbedPane tabbedPane1;
|
||||||
|
private JLabel steamStatus;
|
||||||
|
private JLabel armaStatus;
|
||||||
|
private JButton presetPanelButton;
|
||||||
|
private JPanel logo;
|
||||||
|
private JPanel presetsTab;
|
||||||
|
private JButton playPresetButton;
|
||||||
|
private JButton clonePresetButton;
|
||||||
|
private JButton newPresetButtom;
|
||||||
|
private JButton removePresetButtom;
|
||||||
|
private JButton renamePresetButton;
|
||||||
|
private JList presetList;
|
||||||
|
private JList modList;
|
||||||
|
private JPanel playTab;
|
||||||
|
private JTable serverTable;
|
||||||
|
private JButton playButton;
|
||||||
|
private JPanel updateTab;
|
||||||
|
private JPanel settingsTab;
|
||||||
|
private JTextField settingsArmaPathText;
|
||||||
|
private JButton settingsArmaPathBtn;
|
||||||
|
private JComboBox settingsBehaviorStartCombo;
|
||||||
|
private JComboBox settingsProfileCombo;
|
||||||
|
private JComboBox settingsMallocCombo;
|
||||||
|
private JSpinner settingsMaxMemSpinner;
|
||||||
|
private JTextField parameterText;
|
||||||
|
private JButton settingsModsPathBtn;
|
||||||
|
private JTextField settingsModsPathText;
|
||||||
|
private JCheckBox settingsShowParameterBox;
|
||||||
|
private JCheckBox settingsCheckModsBox;
|
||||||
|
private JComboBox settingsLanguageCombo;
|
||||||
|
private JTextField settingsBackendText;
|
||||||
|
private JComboBox settingsExThreadsCombo;
|
||||||
|
private JTextField settingsWorldText;
|
||||||
|
private JTextField settingsInitText;
|
||||||
|
private JTextField settingsBetaText;
|
||||||
|
private JCheckBox settingsUseSixtyFourBitBox;
|
||||||
|
private JCheckBox settingsNoSplashBox;
|
||||||
|
private JCheckBox settingsSkipIntroBox;
|
||||||
|
private JCheckBox settingsNoCBBox;
|
||||||
|
private JCheckBox settingsNoLogsBox;
|
||||||
|
private JCheckBox settingsEnableHTBox;
|
||||||
|
private JCheckBox settingsHugeoagesBox;
|
||||||
|
private JCheckBox settingsNoPauseBox;
|
||||||
|
private JCheckBox settingsShowScriptErrorsBox;
|
||||||
|
private JCheckBox settingsFilePatchingBox;
|
||||||
|
private JCheckBox settingsCrashDiagBox;
|
||||||
|
private JCheckBox settingsWindowBox;
|
||||||
|
private JSpinner settingsMaxVRamSpinner;
|
||||||
|
private JSpinner settingsCpuCountSpinner;
|
||||||
|
private JSpinner settingsPosXSpinner;
|
||||||
|
private JSpinner settingsPosYSpinner;
|
||||||
|
private JButton settingsResetDefault;
|
||||||
|
private JScrollPane settingScrollPane;
|
||||||
|
private JCheckBox settingsUseWorkshopBox;
|
||||||
|
private JTree tree1;
|
||||||
|
private JButton allesAuswählenButton;
|
||||||
|
private JButton allesAusklappenButton;
|
||||||
|
private JProgressBar progressBar1;
|
||||||
|
private JButton abbrechenButton;
|
||||||
|
private JButton überprüfenButton;
|
||||||
|
private JProgressBar progressBar2;
|
||||||
|
private JProgressBar progressBar3;
|
||||||
|
private JButton downloadButton;
|
||||||
|
private JButton abbrechenButton1;
|
||||||
|
private JButton pauseButton;
|
||||||
|
|
||||||
|
// TODO: Updater
|
||||||
|
/*
|
||||||
|
Prüfung
|
||||||
|
In eine Liste hinzufügen wenn Datei in modset.json (Neu runterladen), nicht in modset.json (zum Löschen) oder die Größe unterschiedlich ist (Geändert)
|
||||||
|
*/
|
||||||
|
|
||||||
|
public LauncherGUI() {
|
||||||
|
RepositoryManger.getInstance().addObserver(this);
|
||||||
|
|
||||||
|
tabbedPane1.setUI(new BasicTabbedPaneUI() {
|
||||||
|
private final Insets borderInsets = new Insets(0, 0, 0, 0);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void paintContentBorder(Graphics g, int tabPlacement, int selectedIndex) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Insets getContentBorderInsets(int tabPlacement) {
|
||||||
|
return borderInsets;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int calculateTabAreaHeight(int tab_placement, int run_count, int max_tab_height) {
|
||||||
|
return -5;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Insets x = new Insets(5, 5, 5, 5);
|
||||||
|
settingsPanelButton.setMargin(x);
|
||||||
|
updatePanelButton.setMargin(x);
|
||||||
|
playPanelButton.setMargin(x);
|
||||||
|
presetPanelButton.setMargin(x);
|
||||||
|
|
||||||
|
playPresetButton.setMargin(new Insets(10, 10, 10, 10));
|
||||||
|
|
||||||
|
playPanelButton.addActionListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
tabbedPane1.setSelectedIndex(0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
updatePanelButton.addActionListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
tabbedPane1.setSelectedIndex(1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
presetPanelButton.addActionListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
tabbedPane1.setSelectedIndex(2);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
settingsPanelButton.addActionListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
tabbedPane1.setSelectedIndex(3);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
serverTable.setModel(new ServerTableModel());
|
||||||
|
|
||||||
|
presetList.setModel(new PresetTableModel());
|
||||||
|
presetList.setCellRenderer(new PresetListRenderer());
|
||||||
|
presetList.addListSelectionListener(new ListSelectionListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void valueChanged(ListSelectionEvent e) {
|
||||||
|
if (!e.getValueIsAdjusting()) {
|
||||||
|
PresetTableModel m = (PresetTableModel) presetList.getModel();
|
||||||
|
Modset modset = (Modset) m.getElementAt(presetList.getSelectedIndex());
|
||||||
|
System.out.println(modset.getName());
|
||||||
|
|
||||||
|
if(modset.getType() == Modset.Type.SERVER) {
|
||||||
|
renamePresetButton.setEnabled(false);
|
||||||
|
removePresetButtom.setEnabled(false);
|
||||||
|
} else {
|
||||||
|
renamePresetButton.setEnabled(true);
|
||||||
|
removePresetButtom.setEnabled(true);
|
||||||
|
}
|
||||||
|
clonePresetButton.setEnabled(true);
|
||||||
|
|
||||||
|
updateModList(modset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
modList.setCellRenderer(new ModListRenderer());
|
||||||
|
|
||||||
|
subtitle.setText(
|
||||||
|
ArmA3Launcher.config.getString("subtitle")
|
||||||
|
.replace("${name}", ArmA3Launcher.CLIENT_NAME)
|
||||||
|
.replace("${version}", ArmA3Launcher.VERSION));
|
||||||
|
|
||||||
|
title.setText(
|
||||||
|
ArmA3Launcher.config.getString("title")
|
||||||
|
.replace("${name}", ArmA3Launcher.CLIENT_NAME)
|
||||||
|
.replace("${version}", ArmA3Launcher.VERSION));
|
||||||
|
|
||||||
|
initSettings();
|
||||||
|
|
||||||
|
settingsResetDefault.addActionListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
try {
|
||||||
|
ArmA3Launcher.user_config.remove("arma");
|
||||||
|
ArmA3Launcher.user_config.store();
|
||||||
|
initSettings();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
settingScrollPane.getVerticalScrollBar().setUnitIncrement(16);
|
||||||
|
|
||||||
|
RepositoryManger.getInstance().refreshMeta();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void infoBox(String infoMessage, String titleBar) {
|
||||||
|
JOptionPane.showMessageDialog(null, infoMessage, "INFO: " + titleBar, JOptionPane.INFORMATION_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void warnBox(String infoMessage, String titleBar) {
|
||||||
|
JOptionPane.showMessageDialog(null, infoMessage, titleBar, JOptionPane.WARNING_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void errorBox(String errorMessage, String titleBar) {
|
||||||
|
JOptionPane.showMessageDialog(null, errorMessage, "ERROR: " + titleBar, JOptionPane.ERROR_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateLabels(boolean steamRunning, boolean armaRunning) {
|
||||||
|
if (steamRunning) {
|
||||||
|
steamStatus.setText(LangUtils.getInstance().getString("signed_in"));
|
||||||
|
steamStatus.setForeground(new Color(82, 137, 74));
|
||||||
|
} else {
|
||||||
|
steamStatus.setText(LangUtils.getInstance().getString("closed"));
|
||||||
|
steamStatus.setForeground(Color.RED);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (armaRunning) {
|
||||||
|
armaStatus.setText(LangUtils.getInstance().getString("running"));
|
||||||
|
armaStatus.setForeground(new Color(82, 137, 74));
|
||||||
|
} else {
|
||||||
|
armaStatus.setText(LangUtils.getInstance().getString("closed"));
|
||||||
|
armaStatus.setForeground(Color.red);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void techCheck() {
|
||||||
|
// Arma Path set
|
||||||
|
// Steam running
|
||||||
|
// Arma not running
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean checkArmaPath(String path) {
|
||||||
|
if (settingsArmaPathText.getText().isEmpty()) return false;
|
||||||
|
File dir = new File(settingsArmaPathText.getText());
|
||||||
|
|
||||||
|
ArrayList<String> search = new ArrayList<String>(Arrays.asList("arma3.exe", "steam.dll"));
|
||||||
|
File[] listOfFiles = dir.listFiles();
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (File file : listOfFiles) {
|
||||||
|
if (search.isEmpty()) return true;
|
||||||
|
if (file.isFile()) {
|
||||||
|
search.remove(file.getName().toLowerCase());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (NullPointerException ex) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initSettings() {
|
||||||
|
|
||||||
|
settingsBackendText.setText(ArmA3Launcher.config.getString("sync.url"));
|
||||||
|
|
||||||
|
|
||||||
|
// -------------------------------- PROFILE --------------------------------
|
||||||
|
|
||||||
|
File file = new File((new JFileChooser().getFileSystemView().getDefaultDirectory().toString()) + File.separator + "Arma 3 - Other Profiles");
|
||||||
|
String[] directories = file.list((current, name) -> new File(current, name).isDirectory());
|
||||||
|
|
||||||
|
directories = Stream.concat(Arrays.stream(new String[]{""}), Arrays.stream(directories == null ? new String[]{} : directories)).toArray(String[]::new);
|
||||||
|
|
||||||
|
String[] readableDirectories = new String[directories.length];
|
||||||
|
for (int i = 0; i < directories.length; i++) {
|
||||||
|
try {
|
||||||
|
readableDirectories[i] = URLDecoder.decode(directories[i], StandardCharsets.UTF_8.name());
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
readableDirectories[i] = directories[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
((JComboBox<String>) settingsProfileCombo).setModel(new DefaultComboBoxModel<>(readableDirectories));
|
||||||
|
|
||||||
|
|
||||||
|
initFolderChooser(settingsArmaPathText, settingsArmaPathBtn, "armaPath", Parameter.ParameterType.CLIENT, new Callback.JFileSelectCallback() {
|
||||||
|
@Override
|
||||||
|
public boolean allowSelection(File path) {
|
||||||
|
String sPath = path.getAbsolutePath();
|
||||||
|
if (!checkArmaPath(sPath)) {
|
||||||
|
SwingUtilities.invokeLater(() -> warnBox(LangUtils.getInstance().getString("not_arma_dir_msg"), LangUtils.getInstance().getString("not_arma_dir")));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
settingsArmaPathText.setText(sPath);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
initFolderChooser(settingsModsPathText, settingsModsPathBtn, "modPath", Parameter.ParameterType.CLIENT, new Callback.JFileSelectCallback() {
|
||||||
|
@Override
|
||||||
|
public boolean allowSelection(File path) {
|
||||||
|
settingsModsPathText.setText(path.getAbsolutePath());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// -------------------------------- COMBO BOXES --------------------------------
|
||||||
|
|
||||||
|
initComboBox(settingsLanguageCombo, "language", Parameter.ParameterType.CLIENT, new String[]{"system", "en_US", "de_DE"});
|
||||||
|
initComboBox(settingsBehaviorStartCombo, "behaviourAfterStart", Parameter.ParameterType.CLIENT, new String[]{"nothing", "minimize", "exit"});
|
||||||
|
|
||||||
|
initComboBox(settingsProfileCombo, "Profile", Parameter.ParameterType.ARMA, directories);
|
||||||
|
initComboBox(settingsExThreadsCombo, "ExThreads", Parameter.ParameterType.ARMA, new String[]{"", "3", "7"});
|
||||||
|
initComboBox(settingsMallocCombo, "Malloc", Parameter.ParameterType.ARMA, new String[]{"", "tbb4malloc_bi", "jemalloc_bi", "system"});
|
||||||
|
|
||||||
|
|
||||||
|
// -------------------------------- CHECK BOXES --------------------------------
|
||||||
|
|
||||||
|
initCheckBox(settingsShowParameterBox, "ShowStartParameter", Parameter.ParameterType.CLIENT);
|
||||||
|
settingsShowParameterBox.addItemListener(e -> parameterText.setVisible(e.getStateChange() == ItemEvent.SELECTED));
|
||||||
|
initCheckBox(settingsCheckModsBox, "CheckModset", Parameter.ParameterType.CLIENT);
|
||||||
|
|
||||||
|
initCheckBox(settingsUseWorkshopBox, "UseWorkshop", Parameter.ParameterType.CLIENT);
|
||||||
|
settingsUseWorkshopBox.addItemListener(e -> {
|
||||||
|
if (e.getStateChange() == ItemEvent.SELECTED) {
|
||||||
|
SwingUtilities.invokeLater(() -> warnBox(LangUtils.getInstance().getString("warning_workshop"), LangUtils.getInstance().getString("warning")));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
initCheckBox(settingsUseSixtyFourBitBox, "Use64BitClient", Parameter.ParameterType.ARMA);
|
||||||
|
initCheckBox(settingsNoSplashBox, "NoSplash", Parameter.ParameterType.ARMA);
|
||||||
|
initCheckBox(settingsSkipIntroBox, "SkipIntro", Parameter.ParameterType.ARMA);
|
||||||
|
initCheckBox(settingsNoCBBox, "NoCB", Parameter.ParameterType.ARMA);
|
||||||
|
initCheckBox(settingsNoLogsBox, "NoLogs", Parameter.ParameterType.ARMA);
|
||||||
|
initCheckBox(settingsEnableHTBox, "EnableHT", Parameter.ParameterType.ARMA);
|
||||||
|
initCheckBox(settingsHugeoagesBox, "Hugepages", Parameter.ParameterType.ARMA);
|
||||||
|
initCheckBox(settingsNoPauseBox, "NoPause", Parameter.ParameterType.ARMA);
|
||||||
|
initCheckBox(settingsShowScriptErrorsBox, "ShowScriptErrors", Parameter.ParameterType.ARMA);
|
||||||
|
initCheckBox(settingsFilePatchingBox, "FilePatching", Parameter.ParameterType.ARMA);
|
||||||
|
initCheckBox(settingsCrashDiagBox, "CrashDiag", Parameter.ParameterType.ARMA);
|
||||||
|
initCheckBox(settingsWindowBox, "Window", Parameter.ParameterType.ARMA);
|
||||||
|
|
||||||
|
|
||||||
|
// -------------------------------- SPINNER --------------------------------
|
||||||
|
|
||||||
|
com.sun.management.OperatingSystemMXBean mxbean = (com.sun.management.OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
|
||||||
|
int memorySize = (int) (mxbean.getTotalPhysicalMemorySize() / 1024);
|
||||||
|
|
||||||
|
initSpinner(settingsMaxMemSpinner, "MaxMem", Parameter.ParameterType.ARMA, -1, memorySize);
|
||||||
|
initSpinner(settingsMaxVRamSpinner, "MaxVRAM", Parameter.ParameterType.ARMA, -1, 99999);
|
||||||
|
initSpinner(settingsCpuCountSpinner, "CpuCount", Parameter.ParameterType.ARMA, 0, Runtime.getRuntime().availableProcessors());
|
||||||
|
initSpinner(settingsPosXSpinner, "PosX", Parameter.ParameterType.ARMA, -1, 99999);
|
||||||
|
initSpinner(settingsPosYSpinner, "PosY", Parameter.ParameterType.ARMA, -1, 99999);
|
||||||
|
|
||||||
|
// -------------------------------- -------------------------------- --------------------------------
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initCheckBox(JCheckBox cb, String parameter, Parameter.ParameterType pType) {
|
||||||
|
Parameter<Boolean> paraObj = new Parameter<>(parameter, pType, Boolean.class);
|
||||||
|
cb.setSelected(paraObj.getValue());
|
||||||
|
cb.addItemListener(new SettingsHandler.CheckBoxListener(paraObj));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initComboBox(JComboBox<String> cb, String parameter, Parameter.ParameterType pType, String[] values) {
|
||||||
|
Parameter<String> paraObj = new Parameter<>(parameter, pType, String.class, values);
|
||||||
|
cb.setSelectedIndex(paraObj.getIndex());
|
||||||
|
if (cb.getItemListeners().length == 0) cb.addItemListener(new SettingsHandler.ComboBoxListener(paraObj));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initFolderChooser(JTextField showText, JButton actionButton, String parameter, Parameter.ParameterType pType, Callback.JFileSelectCallback check) {
|
||||||
|
Parameter<String> paraObj = new Parameter<>(parameter, pType, String.class);
|
||||||
|
showText.setText(paraObj.getValue());
|
||||||
|
if (actionButton.getActionListeners().length == 0)
|
||||||
|
actionButton.addActionListener(new SettingsHandler.Fileistener(mainPanel, paraObj, check));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initSpinner(JSpinner spinner, String parameter, Parameter.ParameterType pType, int min, int max) {
|
||||||
|
Parameter<String> paraObj = new Parameter<>(parameter, pType, String.class);
|
||||||
|
|
||||||
|
SpinnerNumberModel RAMModel = new SpinnerNumberModel(Integer.parseInt(paraObj.getValue()), min, max, 1);
|
||||||
|
spinner.setModel(RAMModel);
|
||||||
|
JComponent comp = spinner.getEditor();
|
||||||
|
JFormattedTextField field = (JFormattedTextField) comp.getComponent(0);
|
||||||
|
DefaultFormatter formatter = (DefaultFormatter) field.getFormatter();
|
||||||
|
formatter.setCommitsOnValidEdit(false);
|
||||||
|
spinner.addChangeListener(new SettingsHandler.SpinnerListener(paraObj));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateModList(Modset modset) {
|
||||||
|
ListModel<String> model = (ListModel)modList.getModel();
|
||||||
|
// TODO: RepositoryManger.downloadModlist
|
||||||
|
// TODO: Show All Mods (keyname)
|
||||||
|
// TODO: Show not installed Mods with red font
|
||||||
|
// TODO: Select Mod if in modset.Mods
|
||||||
|
// TODO: Custom Checkbox Render
|
||||||
|
// TODO: Wenn modset.type == Server alle Checkboxen deaktivieren!
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(Object o) {
|
||||||
|
String s = String.valueOf(o);
|
||||||
|
|
||||||
|
if (s.equals("refreshMeta")) {
|
||||||
|
SwingUtilities.invokeLater(() -> {
|
||||||
|
ServerTableModel model = (ServerTableModel) serverTable.getModel();
|
||||||
|
|
||||||
|
Server.SERVER_LIST.forEach((name, server) -> model.add(server));
|
||||||
|
});
|
||||||
|
|
||||||
|
SwingUtilities.invokeLater(() -> {
|
||||||
|
PresetTableModel model = (PresetTableModel) presetList.getModel();
|
||||||
|
model.clear();
|
||||||
|
|
||||||
|
model.add(new Modset("--Server", Modset.Type.CLIENT, null, false));
|
||||||
|
|
||||||
|
Modset.MODSET_LIST.forEach((name, set) -> {
|
||||||
|
model.add(set);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
144
src/main/java/de/mc8051/arma3launcher/Parameter.java
Normal file
144
src/main/java/de/mc8051/arma3launcher/Parameter.java
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
package de.mc8051.arma3launcher;
|
||||||
|
|
||||||
|
import org.ini4j.Ini;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by gurkengewuerz.de on 24.03.2020.
|
||||||
|
*/
|
||||||
|
public class Parameter<T> {
|
||||||
|
|
||||||
|
private static Map<String, String> PARAMETERS = new HashMap<String, String>() {{
|
||||||
|
put("profile", "name");
|
||||||
|
put("nosplash", "noSplash");
|
||||||
|
put("skipintro", "skipIntro");
|
||||||
|
put("world", "world");
|
||||||
|
put("maxmem", "maxMem");
|
||||||
|
put("maxvram", "maxVRAM");
|
||||||
|
put("nocb", "noCB");
|
||||||
|
put("cpucount", "cpuCount");
|
||||||
|
put("exthreads", "exThreads");
|
||||||
|
put("malloc", "malloc");
|
||||||
|
put("nologs", "noLogs");
|
||||||
|
put("enableht", "enableHT");
|
||||||
|
put("hugepages", "hugepages");
|
||||||
|
put("nopause", "noPause");
|
||||||
|
put("showscripterrors", "showScriptErrors");
|
||||||
|
put("filepatching", "filePatching");
|
||||||
|
put("init", "init");
|
||||||
|
put("beta", "beta");
|
||||||
|
put("crashdiag", "crashDiag");
|
||||||
|
put("window", "window");
|
||||||
|
put("posx", "posX");
|
||||||
|
put("posy", "posY");
|
||||||
|
|
||||||
|
// use64bitclient -> arma3_x64.exe
|
||||||
|
}};
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private ParameterType pType;
|
||||||
|
private Class<T> persistentClass;
|
||||||
|
private String[] values = null;
|
||||||
|
|
||||||
|
public Parameter(String name, ParameterType pType, Class<T> persistentClass) {
|
||||||
|
this(name, pType, persistentClass, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Parameter(String name, ParameterType pType, Class<T> persistentClass, String[] values) {
|
||||||
|
this.name = name;
|
||||||
|
this.pType = pType;
|
||||||
|
this.persistentClass = persistentClass;
|
||||||
|
this.values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserConfigSectionName() {
|
||||||
|
if (pType == ParameterType.CLIENT) return "client";
|
||||||
|
if (pType == ParameterType.ARMA) return "arma";
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save(T data) {
|
||||||
|
T def = getDefault();
|
||||||
|
|
||||||
|
if (data == def || (persistentClass.getTypeName().equals("java.lang.String") && String.valueOf(data).equals(String.valueOf(def)))) {
|
||||||
|
// remove entry from user config
|
||||||
|
ArmA3Launcher.user_config.remove(getUserConfigSectionName(), name);
|
||||||
|
} else {
|
||||||
|
// save to user config
|
||||||
|
Ini.Section section = ArmA3Launcher.user_config.get(getUserConfigSectionName());
|
||||||
|
if (section == null) {
|
||||||
|
section = ArmA3Launcher.user_config.add(getUserConfigSectionName());
|
||||||
|
}
|
||||||
|
if (section != null) {
|
||||||
|
if (section.containsKey(name)) {
|
||||||
|
ArmA3Launcher.user_config.remove(getUserConfigSectionName(), name);
|
||||||
|
}
|
||||||
|
section.add(name, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
ArmA3Launcher.user_config.store();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save(int index) {
|
||||||
|
if(values == null) throw new IllegalAccessError("call of save(int index) is only allowed for ComboBoxes");
|
||||||
|
if(index > values.length - 1) throw new IndexOutOfBoundsException("index " + index + " is out of bound. Max: " + (values.length -1));
|
||||||
|
save((T) values[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getParameter() {
|
||||||
|
if(!PARAMETERS.containsKey(name.toLowerCase())) return null;
|
||||||
|
return PARAMETERS.get(name.toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getValue() {
|
||||||
|
// Get User Value else Default else null
|
||||||
|
Ini.Section section = ArmA3Launcher.user_config.get(getUserConfigSectionName());
|
||||||
|
if (section != null) {
|
||||||
|
if(section.containsKey(name)) {
|
||||||
|
String val = section.get(name);
|
||||||
|
|
||||||
|
if (persistentClass.getTypeName().equals("java.lang.Boolean")) {
|
||||||
|
return (T) (Boolean) Boolean.valueOf(val.toLowerCase());
|
||||||
|
} else return (T) val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return getDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
if(values == null) throw new IllegalAccessError("call of save(int index) is only allowed for ComboBoxes");
|
||||||
|
String value =String.valueOf(getValue());
|
||||||
|
for(int i = 0; i < values.length; i++) {
|
||||||
|
if(value.equalsIgnoreCase(values[i])) return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getDefault() {
|
||||||
|
if (persistentClass.getTypeName().equals("java.lang.Boolean")) {
|
||||||
|
return (T) (Boolean) ArmA3Launcher.config.getBoolean( getUserConfigSectionName() + "." + name);
|
||||||
|
} else if (persistentClass.getTypeName().equals("java.lang.String"))
|
||||||
|
return (T) ArmA3Launcher.config.getString(getUserConfigSectionName()+ "." + name);
|
||||||
|
else return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ParameterType {
|
||||||
|
ARMA,
|
||||||
|
CLIENT
|
||||||
|
}
|
||||||
|
}
|
103
src/main/java/de/mc8051/arma3launcher/SettingsHandler.java
Normal file
103
src/main/java/de/mc8051/arma3launcher/SettingsHandler.java
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
package de.mc8051.arma3launcher;
|
||||||
|
|
||||||
|
import de.mc8051.arma3launcher.utils.Callback;
|
||||||
|
import de.mc8051.arma3launcher.utils.LangUtils;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import javax.swing.event.ChangeEvent;
|
||||||
|
import javax.swing.event.ChangeListener;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
import java.awt.event.ItemEvent;
|
||||||
|
import java.awt.event.ItemListener;
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by gurkengewuerz.de on 24.03.2020.
|
||||||
|
*/
|
||||||
|
public class SettingsHandler {
|
||||||
|
|
||||||
|
public static class CheckBoxListener implements ItemListener {
|
||||||
|
private Parameter<Boolean> parameter;
|
||||||
|
|
||||||
|
public CheckBoxListener(Parameter<Boolean> parameter) {
|
||||||
|
this.parameter = parameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void itemStateChanged(ItemEvent e) {
|
||||||
|
parameter.save(e.getStateChange() == ItemEvent.SELECTED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ComboBoxListener implements ItemListener {
|
||||||
|
|
||||||
|
private Parameter<String> parameter;
|
||||||
|
|
||||||
|
public ComboBoxListener(Parameter<String> parameter) {
|
||||||
|
this.parameter = parameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void itemStateChanged(ItemEvent e) {
|
||||||
|
if (e.getStateChange() == ItemEvent.SELECTED) {
|
||||||
|
parameter.save(((JComboBox) e.getItemSelectable()).getSelectedIndex());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class Fileistener implements ActionListener {
|
||||||
|
|
||||||
|
private JPanel parent;
|
||||||
|
private Parameter<String> parameter;
|
||||||
|
private Callback.JFileSelectCallback check;
|
||||||
|
|
||||||
|
public Fileistener(JPanel parent, Parameter<String> parameter, Callback.JFileSelectCallback check) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.parameter = parameter;
|
||||||
|
this.check = check;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
SwingUtilities.invokeLater(() -> {
|
||||||
|
JFileChooser chooser = new JFileChooser();
|
||||||
|
|
||||||
|
chooser.setCurrentDirectory(new File("."));
|
||||||
|
chooser.setDialogTitle(LangUtils.getInstance().getString("select_folder"));
|
||||||
|
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
|
||||||
|
chooser.setAcceptAllFileFilterUsed(false);
|
||||||
|
|
||||||
|
if (chooser.showOpenDialog(parent) == JFileChooser.APPROVE_OPTION) {
|
||||||
|
File path = chooser.getSelectedFile();
|
||||||
|
if(check.allowSelection(path)) {
|
||||||
|
parameter.save(path.getAbsolutePath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SpinnerListener implements ChangeListener {
|
||||||
|
|
||||||
|
private static long lastChange = -1;
|
||||||
|
private Parameter<String> parameter;
|
||||||
|
|
||||||
|
public SpinnerListener(Parameter<String> parameter) {
|
||||||
|
this.parameter = parameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stateChanged(ChangeEvent e) {
|
||||||
|
long time = System.currentTimeMillis();
|
||||||
|
if(lastChange == -1 || time - lastChange > 500) {
|
||||||
|
lastChange = time;
|
||||||
|
parameter.save(String.valueOf(((JSpinner) e.getSource()).getValue()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
29
src/main/java/de/mc8051/arma3launcher/SteamUtils.java
Normal file
29
src/main/java/de/mc8051/arma3launcher/SteamUtils.java
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package de.mc8051.arma3launcher;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by gurkengewuerz.de on 23.03.2020.
|
||||||
|
*/
|
||||||
|
public class SteamUtils {
|
||||||
|
|
||||||
|
public static boolean findProcess(String findProcess) throws IOException {
|
||||||
|
String filenameFilter = "/nh /fi \"Imagename eq "+findProcess+"\"";
|
||||||
|
String tasksCmd = System.getenv("windir") +"/system32/tasklist.exe "+filenameFilter;
|
||||||
|
|
||||||
|
Process p = Runtime.getRuntime().exec(tasksCmd);
|
||||||
|
BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
|
||||||
|
|
||||||
|
ArrayList<String> procs = new ArrayList<String>();
|
||||||
|
String line = null;
|
||||||
|
while ((line = input.readLine()) != null)
|
||||||
|
procs.add(line);
|
||||||
|
|
||||||
|
input.close();
|
||||||
|
|
||||||
|
return procs.stream().anyMatch(row -> row.contains(findProcess));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
package de.mc8051.arma3launcher.interfaces;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by gurkengewuerz.de on 25.03.2020.
|
||||||
|
*/
|
||||||
|
public interface Observable {
|
||||||
|
|
||||||
|
public void addObserver(Observer observer);
|
||||||
|
public void removeObserver(Observer observer);
|
||||||
|
public void notifyObservers(Object obj);
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
package de.mc8051.arma3launcher.interfaces;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by gurkengewuerz.de on 25.03.2020.
|
||||||
|
*/
|
||||||
|
public interface Observer {
|
||||||
|
|
||||||
|
public void update(Object o);
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package de.mc8051.arma3launcher.model;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by gurkengewuerz.de on 25.03.2020.
|
||||||
|
*/
|
||||||
|
public class ModListRenderer extends JCheckBox implements ListCellRenderer {
|
||||||
|
|
||||||
|
public Component getListCellRendererComponent(JList list, Object value, int index,
|
||||||
|
boolean isSelected, boolean cellHasFocus) {
|
||||||
|
|
||||||
|
setComponentOrientation(list.getComponentOrientation());
|
||||||
|
setFont(list.getFont());
|
||||||
|
setBackground(list.getBackground());
|
||||||
|
setForeground(list.getForeground());
|
||||||
|
setSelected(isSelected);
|
||||||
|
setEnabled(list.isEnabled());
|
||||||
|
|
||||||
|
setText(value == null ? "" : value.toString());
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
package de.mc8051.arma3launcher.model;
|
||||||
|
|
||||||
|
import de.mc8051.arma3launcher.objects.Modset;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import javax.swing.border.EmptyBorder;
|
||||||
|
import javax.swing.border.MatteBorder;
|
||||||
|
import javax.swing.border.TitledBorder;
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by gurkengewuerz.de on 25.03.2020.
|
||||||
|
*/
|
||||||
|
public class PresetListRenderer extends JLabel implements ListCellRenderer {
|
||||||
|
JPanel separator;
|
||||||
|
|
||||||
|
public PresetListRenderer() {
|
||||||
|
setOpaque(true);
|
||||||
|
setBorder(new EmptyBorder(0, 0, 0, 0));
|
||||||
|
|
||||||
|
MatteBorder mb = new MatteBorder(1, 0, 0, 0, Color.BLACK);
|
||||||
|
TitledBorder tb = new TitledBorder(mb, "", TitledBorder.CENTER, TitledBorder.DEFAULT_POSITION);
|
||||||
|
separator = new JPanel();
|
||||||
|
separator.setBorder(tb);
|
||||||
|
separator.setPreferredSize(new Dimension(-1, 20));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Component getListCellRendererComponent(JList list, Object value,
|
||||||
|
int index, boolean isSelected, boolean cellHasFocus) {
|
||||||
|
Modset m = value == null ? new Modset("", Modset.Type.CLIENT,null, false) : (Modset) value;
|
||||||
|
if (m.getName().startsWith("--")) {
|
||||||
|
((TitledBorder)separator.getBorder()).setTitle(m.getName().substring(2));
|
||||||
|
return separator;
|
||||||
|
}
|
||||||
|
if (isSelected) {
|
||||||
|
setBackground(list.getSelectionBackground());
|
||||||
|
} else {
|
||||||
|
setBackground(list.getBackground());
|
||||||
|
}
|
||||||
|
setFont(list.getFont());
|
||||||
|
setText(m.getName());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
package de.mc8051.arma3launcher.model;
|
||||||
|
|
||||||
|
import de.mc8051.arma3launcher.objects.Modset;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by gurkengewuerz.de on 25.03.2020.
|
||||||
|
*/
|
||||||
|
public class PresetTableModel extends AbstractListModel {
|
||||||
|
|
||||||
|
private ArrayList<Modset> data = new ArrayList<>();
|
||||||
|
|
||||||
|
public void add(Modset m){
|
||||||
|
data.add(m);
|
||||||
|
fireContentsChanged(this, 0, data.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
data.clear();
|
||||||
|
fireContentsChanged(this, 0, data.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSize() {
|
||||||
|
return data.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getElementAt(int index) {
|
||||||
|
return data.get(index);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
package de.mc8051.arma3launcher.model;
|
||||||
|
|
||||||
|
import de.mc8051.arma3launcher.objects.Server;
|
||||||
|
import de.mc8051.arma3launcher.utils.LangUtils;
|
||||||
|
|
||||||
|
import javax.swing.table.AbstractTableModel;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by gurkengewuerz.de on 24.03.2020.
|
||||||
|
*/
|
||||||
|
public class ServerTableModel extends AbstractTableModel {
|
||||||
|
|
||||||
|
private String[] columnNames = {
|
||||||
|
LangUtils.getInstance().getString("description"),
|
||||||
|
LangUtils.getInstance().getString("ip_address"),
|
||||||
|
LangUtils.getInstance().getString("port"),
|
||||||
|
LangUtils.getInstance().getString("preset")
|
||||||
|
};
|
||||||
|
private List<Server> data = new ArrayList<>();
|
||||||
|
|
||||||
|
public String getColumnName(int col) {
|
||||||
|
return columnNames[col];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(Server s) {
|
||||||
|
data.add(s);
|
||||||
|
fireTableDataChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getRowCount() {
|
||||||
|
return data.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getColumnCount() {
|
||||||
|
return columnNames.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getValueAt(int rowIndex, int columnIndex) {
|
||||||
|
if (columnIndex == 0) return data.get(rowIndex).getName();
|
||||||
|
else if (columnIndex == 1) return data.get(rowIndex).getIp();
|
||||||
|
else if (columnIndex == 2) return data.get(rowIndex).getPort();
|
||||||
|
else if (columnIndex == 3) return data.get(rowIndex).getPreset().getName();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
17
src/main/java/de/mc8051/arma3launcher/objects/Mod.java
Normal file
17
src/main/java/de/mc8051/arma3launcher/objects/Mod.java
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package de.mc8051.arma3launcher.objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by gurkengewuerz.de on 25.03.2020.
|
||||||
|
*/
|
||||||
|
public class Mod {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public Mod(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
63
src/main/java/de/mc8051/arma3launcher/objects/Modset.java
Normal file
63
src/main/java/de/mc8051/arma3launcher/objects/Modset.java
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
package de.mc8051.arma3launcher.objects;
|
||||||
|
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by gurkengewuerz.de on 25.03.2020.
|
||||||
|
*/
|
||||||
|
public class Modset {
|
||||||
|
|
||||||
|
public static HashMap<String, Modset> MODSET_LIST = new HashMap<>();
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private Type type;
|
||||||
|
private List<Mod> mods = new ArrayList<>();
|
||||||
|
|
||||||
|
public Modset(String name, Type type, List<Mod> mods) {
|
||||||
|
this(name, type, mods, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Modset(String name, Type type, List<Mod> mods, boolean add) {
|
||||||
|
this.name = name;
|
||||||
|
this.type = type;
|
||||||
|
this.mods = mods;
|
||||||
|
|
||||||
|
if(add) MODSET_LIST.put(name, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Modset(JSONObject o, Type type) {
|
||||||
|
if(!o.has("name") || !o.has("mods")) return;
|
||||||
|
name = o.getString("name");
|
||||||
|
|
||||||
|
JSONArray modlist = o.getJSONArray("mods");
|
||||||
|
for(int j = 0; j < modlist.length(); j++){
|
||||||
|
mods.add(new Mod(modlist.getString(j)));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.type = type;
|
||||||
|
|
||||||
|
MODSET_LIST.put(name, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Mod> getMods() {
|
||||||
|
return mods;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static enum Type {
|
||||||
|
SERVER,
|
||||||
|
CLIENT
|
||||||
|
}
|
||||||
|
}
|
62
src/main/java/de/mc8051/arma3launcher/objects/Server.java
Normal file
62
src/main/java/de/mc8051/arma3launcher/objects/Server.java
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
package de.mc8051.arma3launcher.objects;
|
||||||
|
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by gurkengewuerz.de on 25.03.2020.
|
||||||
|
*/
|
||||||
|
public class Server {
|
||||||
|
|
||||||
|
public static HashMap<String, Server> SERVER_LIST = new HashMap<>();
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private String password;
|
||||||
|
private String ip;
|
||||||
|
private int port;
|
||||||
|
private Modset preset;
|
||||||
|
|
||||||
|
public Server(String name, String password, String ip, int port, Modset preset) {
|
||||||
|
this.name = name;
|
||||||
|
this.password = password;
|
||||||
|
this.ip = ip;
|
||||||
|
this.port = port;
|
||||||
|
this.preset = preset;
|
||||||
|
|
||||||
|
SERVER_LIST.put(name, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Server(JSONObject o) {
|
||||||
|
if(!o.has("name") || !o.has("password") || !o.has("ipaddress") || !o.has("port") || !o.has("preset")) return;
|
||||||
|
name = o.getString("name");
|
||||||
|
password = o.getString("password");
|
||||||
|
ip = o.getString("ipaddress");
|
||||||
|
port = o.getInt("port");
|
||||||
|
|
||||||
|
if(!Modset.MODSET_LIST.containsKey(o.getString("preset"))) return;
|
||||||
|
preset = Modset.MODSET_LIST.get(o.getString("preset"));
|
||||||
|
|
||||||
|
SERVER_LIST.put(name, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getIp() {
|
||||||
|
return ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPort() {
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Modset getPreset() {
|
||||||
|
return preset;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
package de.mc8051.arma3launcher.repo;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by gurkengewuerz.de on 24.03.2020.
|
||||||
|
*/
|
||||||
|
public class DownloadThread implements Runnable {
|
||||||
|
|
||||||
|
private ProcessBuilder processBuilder;
|
||||||
|
private Process process;
|
||||||
|
private Thread thread;
|
||||||
|
|
||||||
|
private Status status = Status.PENDING;
|
||||||
|
|
||||||
|
public DownloadThread(ProcessBuilder processBuilder) {
|
||||||
|
this.processBuilder = processBuilder;
|
||||||
|
this.processBuilder.redirectErrorStream(true);
|
||||||
|
|
||||||
|
thread = new Thread(this);
|
||||||
|
thread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
process.destroy();
|
||||||
|
thread.interrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Status getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
process = processBuilder.start();
|
||||||
|
status = Status.RUNNING;
|
||||||
|
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||||
|
String line;
|
||||||
|
while ( (line = reader.readLine()) != null && !thread.isInterrupted()) {
|
||||||
|
System.out.println(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
int exitVal = process.waitFor();
|
||||||
|
if(exitVal == 0) status = Status.FINNISHED;
|
||||||
|
else status = Status.ERROR;
|
||||||
|
|
||||||
|
System.out.println(exitVal);
|
||||||
|
} catch (IOException | InterruptedException ex) {
|
||||||
|
Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, ex);
|
||||||
|
status = Status.ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum Status {
|
||||||
|
PENDING(0),
|
||||||
|
RUNNING(1),
|
||||||
|
FINNISHED(2),
|
||||||
|
ERROR(3);
|
||||||
|
|
||||||
|
Status(int i) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
109
src/main/java/de/mc8051/arma3launcher/repo/RepositoryManger.java
Normal file
109
src/main/java/de/mc8051/arma3launcher/repo/RepositoryManger.java
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
package de.mc8051.arma3launcher.repo;
|
||||||
|
|
||||||
|
import de.mc8051.arma3launcher.ArmA3Launcher;
|
||||||
|
import de.mc8051.arma3launcher.interfaces.Observable;
|
||||||
|
import de.mc8051.arma3launcher.interfaces.Observer;
|
||||||
|
import de.mc8051.arma3launcher.objects.Modset;
|
||||||
|
import de.mc8051.arma3launcher.objects.Server;
|
||||||
|
import de.mc8051.arma3launcher.utils.Callback;
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.Response;
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by gurkengewuerz.de on 24.03.2020.
|
||||||
|
*/
|
||||||
|
public class RepositoryManger implements Observable {
|
||||||
|
|
||||||
|
private static RepositoryManger instance;
|
||||||
|
private List<Observer> observerList = new ArrayList<>();
|
||||||
|
private OkHttpClient client = new OkHttpClient();
|
||||||
|
|
||||||
|
private RepositoryManger() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void refreshMeta() {
|
||||||
|
downloadMeta(new Callback.HttpCallback() {
|
||||||
|
@Override
|
||||||
|
public void response(Response r) {
|
||||||
|
if (!r.isSuccessful()) {
|
||||||
|
Logger.getLogger(getClass().getName()).log(Level.SEVERE, "Cant open " + r.request().url().toString() + " code " + r.code());
|
||||||
|
RepositoryManger.getInstance().notifyObservers("refreshMetaFailed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
JSONObject jsonObject = new JSONObject(r.body().string());
|
||||||
|
|
||||||
|
if (jsonObject.has("modsets")) {
|
||||||
|
JSONArray modsets = jsonObject.getJSONArray("modsets");
|
||||||
|
if (modsets.length() > 0) {
|
||||||
|
for (int i = 0; i < modsets.length(); i++) {
|
||||||
|
JSONObject modset = modsets.getJSONObject(i);
|
||||||
|
new Modset(modset, Modset.Type.SERVER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init servers after modsets because server search preset string in modsets
|
||||||
|
if (jsonObject.has("servers")) {
|
||||||
|
JSONArray servers = jsonObject.getJSONArray("servers");
|
||||||
|
if (servers.length() > 0) {
|
||||||
|
for (int i = 0; i < servers.length(); i++) {
|
||||||
|
JSONObject server = servers.getJSONObject(i);
|
||||||
|
new Server(server);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RepositoryManger.getInstance().notifyObservers("refreshMeta");
|
||||||
|
} catch (IOException | NullPointerException e) {
|
||||||
|
Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void downloadMeta(Callback.HttpCallback callback) {
|
||||||
|
new Thread(() -> {
|
||||||
|
try {
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.url(ArmA3Launcher.config.getString("sync.url") + "/.sync/server.json")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
callback.response(client.newCall(request).execute());
|
||||||
|
} catch (IOException e) {
|
||||||
|
Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, e);
|
||||||
|
callback.response(null);
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RepositoryManger getInstance() {
|
||||||
|
if (instance == null) instance = new RepositoryManger();
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addObserver(Observer observer) {
|
||||||
|
observerList.add(observer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeObserver(Observer observer) {
|
||||||
|
observerList.remove(observer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void notifyObservers(Object obj) {
|
||||||
|
for (Observer obs : observerList) obs.update(obj);
|
||||||
|
}
|
||||||
|
}
|
60
src/main/java/de/mc8051/arma3launcher/steam/SteamTimer.java
Normal file
60
src/main/java/de/mc8051/arma3launcher/steam/SteamTimer.java
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package de.mc8051.arma3launcher.steam;
|
||||||
|
|
||||||
|
import de.mc8051.arma3launcher.LauncherGUI;
|
||||||
|
import de.mc8051.arma3launcher.SteamUtils;
|
||||||
|
import de.ralleytn.simple.registry.Key;
|
||||||
|
import de.ralleytn.simple.registry.Registry;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by gurkengewuerz.de on 23.03.2020.
|
||||||
|
*/
|
||||||
|
public class SteamTimer extends TimerTask {
|
||||||
|
|
||||||
|
public static boolean steam_running = false;
|
||||||
|
public static boolean arma_running = false;
|
||||||
|
|
||||||
|
private LauncherGUI gui;
|
||||||
|
|
||||||
|
public SteamTimer(LauncherGUI gui) {
|
||||||
|
this.gui = gui;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
String OS = System.getProperty("os.name").toUpperCase();
|
||||||
|
if (!OS.contains("WIN")) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if(!SteamUtils.findProcess("steam.exe")) {
|
||||||
|
steam_running = false;
|
||||||
|
gui.updateLabels(steam_running, arma_running);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Key activeSteamUserKey = Registry.getKey(Registry.HKEY_CURRENT_USER + "\\Software\\Valve\\Steam\\ActiveProcess");
|
||||||
|
|
||||||
|
String activeSteamUser = activeSteamUserKey.getValueByName("ActiveUser").getRawValue();
|
||||||
|
|
||||||
|
if(activeSteamUser.equals("0x0")) {
|
||||||
|
steam_running = false;
|
||||||
|
gui.updateLabels(steam_running, arma_running);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
steam_running = true;
|
||||||
|
|
||||||
|
arma_running = SteamUtils.findProcess("arma3.exe") || SteamUtils.findProcess("arma3_x64.exe") || SteamUtils.findProcess("arma3launcher.exe");
|
||||||
|
} catch (IOException e) {
|
||||||
|
steam_running = false;
|
||||||
|
arma_running = false;
|
||||||
|
Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
gui.updateLabels(steam_running, arma_running);
|
||||||
|
}
|
||||||
|
}
|
19
src/main/java/de/mc8051/arma3launcher/utils/Callback.java
Normal file
19
src/main/java/de/mc8051/arma3launcher/utils/Callback.java
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package de.mc8051.arma3launcher.utils;
|
||||||
|
|
||||||
|
import okhttp3.Response;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by gurkengewuerz.de on 24.03.2020.
|
||||||
|
*/
|
||||||
|
public class Callback {
|
||||||
|
|
||||||
|
public static interface JFileSelectCallback { //declare an interface with the callback methods, so you can use on more than one class and just refer to the interface
|
||||||
|
boolean allowSelection(File path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static interface HttpCallback {
|
||||||
|
void response(Response r);
|
||||||
|
}
|
||||||
|
}
|
26
src/main/java/de/mc8051/arma3launcher/utils/LangUtils.java
Normal file
26
src/main/java/de/mc8051/arma3launcher/utils/LangUtils.java
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package de.mc8051.arma3launcher.utils;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.ResourceBundle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by gurkengewuerz.de on 24.03.2020.
|
||||||
|
*/
|
||||||
|
public class LangUtils {
|
||||||
|
|
||||||
|
private static LangUtils i;
|
||||||
|
|
||||||
|
private ResourceBundle r = ResourceBundle.getBundle("lang", Locale.getDefault());
|
||||||
|
|
||||||
|
private LangUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getString(String key) {
|
||||||
|
return r.getString(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LangUtils getInstance() {
|
||||||
|
if(i == null) i = new LangUtils();
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
43
src/main/resources/arma3launcher.json
Normal file
43
src/main/resources/arma3launcher.json
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
"version": "0.1.1",
|
||||||
|
"name": "TheTown Client",
|
||||||
|
"title": "Welcome! :P",
|
||||||
|
"subtitle": "${name} v${version}",
|
||||||
|
"sync": {
|
||||||
|
"url": "http://46.4.195.36"
|
||||||
|
},
|
||||||
|
"client": {
|
||||||
|
"armaPath": "",
|
||||||
|
"modPath": "",
|
||||||
|
"ShowStartParameter": true,
|
||||||
|
"CheckModset": false,
|
||||||
|
"UseWorkshop": false,
|
||||||
|
"behaviourAfterStart": "nothing",
|
||||||
|
"language": "system"
|
||||||
|
},
|
||||||
|
"arma": {
|
||||||
|
"Profile": "",
|
||||||
|
"Use64BitClient": true,
|
||||||
|
"NoSplash": true,
|
||||||
|
"SkipIntro": true,
|
||||||
|
"World": "",
|
||||||
|
"MaxMem": -1,
|
||||||
|
"MaxVRAM": -1,
|
||||||
|
"NoCB": false,
|
||||||
|
"CpuCount": 0,
|
||||||
|
"ExThreads": "",
|
||||||
|
"Malloc": "",
|
||||||
|
"NoLogs": false,
|
||||||
|
"EnableHT": false,
|
||||||
|
"Hugepages": false,
|
||||||
|
"NoPause": false,
|
||||||
|
"ShowScriptErrors": true,
|
||||||
|
"FilePatching": false,
|
||||||
|
"Init": "",
|
||||||
|
"Beta": "",
|
||||||
|
"CrashDiag": false,
|
||||||
|
"Window": false,
|
||||||
|
"PosX": -1,
|
||||||
|
"PosY": -1
|
||||||
|
}
|
||||||
|
}
|
82
src/main/resources/lang_de_DE.properties
Normal file
82
src/main/resources/lang_de_DE.properties
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
abort=Abbrechen
|
||||||
|
arm33_parameter=ArmA 3 Startparameter
|
||||||
|
arma3_installpath=ArmA 3 Installationspfad
|
||||||
|
backend_url=Backend-URL
|
||||||
|
behaviour_aafter_start=Verhalten nach dem Start
|
||||||
|
beta_desc=Es können Daten aus Unterverzeichnissen mitgestartet werden.
|
||||||
|
check=Überprüfen
|
||||||
|
check_modset=Modset automatisch überprüfen
|
||||||
|
client_settings=Client Einstellungen
|
||||||
|
clone=Klonen
|
||||||
|
closed=geschlossen
|
||||||
|
common=Allgemein
|
||||||
|
cpucount_desc=Gibt an, wie viele Kerne der CPU von Arma 3 genutzt werden sollen.
|
||||||
|
crashdiag_desc=Zusätzlich zur RPT wird beim Arma-Absturz ein Log vom Crash in einer binarisierten Datei abgelegt.
|
||||||
|
description=Bezeichnung
|
||||||
|
developer_settings=Entwicklereinstellungen
|
||||||
|
display_settings=Anzeigeeinstellungen
|
||||||
|
download=Download
|
||||||
|
downloaded=Heruntergeladen
|
||||||
|
enableht_desc=Sollte eure CPU das sog. „Hyper-Threading“ unterstützen, kann dies für Arma 3 mit dieser Option aktiviert werden (wird von CpuCount überschrieben).
|
||||||
|
expand_all=Alles ausklappen
|
||||||
|
exthreads_desc=Je nach eingegebenen Wert werden ein oder mehrere bestimmte Kerne der CPU für Arma 3 genutzt (3 für Dualcore, 7 für Quadcore).
|
||||||
|
filepatching_desc=Ist die Option aktiv, können ungepackte Daten geladen werden (bpsw. Daten außerhalb von PBO’s).
|
||||||
|
hugepages_desc=Die von der CPU markierten Bereiche des für Arma 3 genutzten RAM werden vergrößert. Kann unter Umständen die Fehleranfälligkeit verringern.
|
||||||
|
init_desc=Führt einen Script-Befehl nach Spielstart im Hauptmenü aus.
|
||||||
|
ip_address=IP-Adresse
|
||||||
|
language=Sprache
|
||||||
|
malloc_desc=Soll ein sog. „Memory Allucator“ zur Performance-Optimierung eingesetzt werden, wird dieser hier eingetragen.
|
||||||
|
maxmem_desc=Hier kann die Limitierung des für Arma 3 zugewiesenen RAM verändert werden (je nach Betriebssystem und verwendeter .exe wird der Wert gekappt).
|
||||||
|
maxvram_desc=Diese Option definiert die Zuweisung des Speichers der Grafikkarte für Arma 3, wird aber unter normalen Bedingungen ignoriert.
|
||||||
|
modset_folder=Modset Installationspfad
|
||||||
|
new=Neu
|
||||||
|
nocb_desc=Ist diese Option aktiv, nutzt Arma 3 nur einen Kern der CPU.
|
||||||
|
nologs_desc=Fehlermeldungen werden bei aktivierter Option nicht mehr in der sog. „RPT“ gespeichert, was die Fehlerbehebung bei Problemen mit Arma 3 erheblich erschwert.
|
||||||
|
nopause_desc=Das Spiel läuft im Singleplayer-Modus auch dann im Hintergrund weiter, wenn es minimiert wird. Vergleichbar mit dem Multiplayer, da dort trotz minimiertem Spiel selbiges weitergeht.
|
||||||
|
nosplash_desc=Ist diese Option aktiviert wird die Seite mit den Logos während des Spielstarts nicht mehr gezeigt.
|
||||||
|
not_arma_dir=Das sieht irgendwie nicht nach deinem Arma-Verzeichnis aus...
|
||||||
|
not_arma_dir_msg=Überprüfe ob sich in diesem Ordner auch eine arma3.exe befindet.\
|
||||||
|
Der Ordner wurde jedoch trotzdem übernommen!
|
||||||
|
pause=Pause
|
||||||
|
performance=Performance
|
||||||
|
play=Spielen
|
||||||
|
play_now=Spiele Jetzt!
|
||||||
|
port=Port
|
||||||
|
posx_desc=Position (nicht Größe) des Fensters im Fenstermodus (X-Achse, horizontal).
|
||||||
|
posy_desc=Das Pendant zu PosX, nur für die Y-Achse (die Vertikale oder „Rauf auf den Baum“).
|
||||||
|
preset=Vorlage
|
||||||
|
preset_settings=Vorlagen Einstellungen
|
||||||
|
presets=Vorlagen
|
||||||
|
profile_desc=Profil, welches beim Arma-Start geladen werden soll.
|
||||||
|
progress=Fortschritt
|
||||||
|
remaining_time=Verbleibende Zeit
|
||||||
|
remove=Entfernen
|
||||||
|
rename=Umbennen
|
||||||
|
repository_content=Repository Inhalt
|
||||||
|
reset_default=Auf Standard zurücksetzten
|
||||||
|
running=gestartet
|
||||||
|
select_all=Alles auswählen
|
||||||
|
select_folder=Ordner auswählen
|
||||||
|
select_mods=Mods auswählen
|
||||||
|
select_server=Server-Auswahl
|
||||||
|
settings=Einstellungen
|
||||||
|
show_startparameter=Startparameter anzeigen
|
||||||
|
showscripterrors_desc=Fehler in Scripten werden in einem Hinweistext signalisiert.
|
||||||
|
signed_in=eingeloggt
|
||||||
|
speed=Geschwindigkeit
|
||||||
|
speed_up_game=Spielstart beschleunigen
|
||||||
|
spikintro_desc=Die Intro-Sequenz wird übersprungen.
|
||||||
|
total_file_size=Gesamtgröße
|
||||||
|
update=Update
|
||||||
|
use64bitclient_desc=Startet Arma3 mit der für 64-Bit Betriebssysteme optimierten .exe-Datei (kann die Performance von Arma 3 verbessern und Probleme beheben (bspw. 3-FPS-Bug).
|
||||||
|
use_workshop=Versuche Workshop Inhalte zu nutzen
|
||||||
|
use_workshop_desc=Bei großen Modspacks versucht der Client bereits heruntergeladene Workshop Inhalte, die gleich sind, zu kopieren um so den Download schneller zu gestalten
|
||||||
|
warning=Warnung
|
||||||
|
warning_workshop=Der Client versucht sein bestes die gleichen Dateien zu finden,\
|
||||||
|
jedoch kann es vorkommen das es nicht die identischen Dateien sind.\
|
||||||
|
Im Falle eines Fehlgeschlagenem Syncen mit dieser Option, solltest\
|
||||||
|
du sie deaktivieren und ohne diese Option erneut syncen.\
|
||||||
|
\
|
||||||
|
Ebenfalls könnte es zu kurzen Performance einbußen kommen.
|
||||||
|
window_desc=Ist diese Option aktiv, wird Arma 3 im Fenstermodus gestartet.
|
||||||
|
world_desc=Hier kann eine Karte eingetragen werden, die geladen und in den Menüs als Hintergrund angezeigt werden soll (z.B. „altis“ oder „stratis“ – ohne Anführungszeichen!). Ist das Feld leer, wird keine Karte während des Startens geladen und der Start von Arma 3 ist entsprechend schneller.
|
81
src/main/resources/lang_en_US.properties
Normal file
81
src/main/resources/lang_en_US.properties
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
abort=Abort
|
||||||
|
arm33_parameter=ArmA 3 Start parameters
|
||||||
|
arma3_installpath=ArmA 3 Installation path
|
||||||
|
backend_url=Backend URL
|
||||||
|
behaviour_aafter_start=Behaviour after start
|
||||||
|
beta_desc=Data from subdirectories can be started as well.
|
||||||
|
check=Check
|
||||||
|
check_modset=Check Modset automatically
|
||||||
|
client_settings=Client Settings
|
||||||
|
clone=Clone
|
||||||
|
closed=closed
|
||||||
|
common=Common
|
||||||
|
cpucount_desc=Specifies how many cores of the CPU should be used by Arma 3.
|
||||||
|
crashdiag_desc=In addition to the RPT, a log of the crash is stored in a binarized file.
|
||||||
|
description=Description
|
||||||
|
developer_settings=Developer settings
|
||||||
|
display_settings=Display settings
|
||||||
|
download=Download
|
||||||
|
downloaded=Downloaded
|
||||||
|
enableht_desc=If your CPU supports the so-called "Hyper-Threading", this can be activated for Arma 3 with this option (will be overwritten by CpuCount)
|
||||||
|
expand_all=Expand All
|
||||||
|
exthreads_desc=Depending on the value entered, one or more specific cores of the CPU are used for Arma 3 (3 for dualcore, 7 for quadcore).
|
||||||
|
filepatching_desc=If the option is active, unpacked data can be loaded (e.g. data outside PBOs).
|
||||||
|
hugepages_desc=The areas of RAM used for Arma 3 marked by the CPU are increased. This may reduce error susceptibility under certain circumstances.
|
||||||
|
init_desc=Executes a script command after game start in the main menu.
|
||||||
|
ip_address=IP-Address
|
||||||
|
language=Language
|
||||||
|
malloc_desc=If a so-called "Memory Allucator" is to be used for performance optimization, it is entered here.
|
||||||
|
maxmem_desc=Here you can change the limit of the RAM allocated for Arma 3 (depending on the operating system and the .exe used, the value is capped)
|
||||||
|
maxvram_desc=This option defines the allocation of the graphics card memory for Arma 3, but is ignored under normal conditions.
|
||||||
|
modset_folder=Modset Installation path
|
||||||
|
new=New
|
||||||
|
nocb_desc=If this option is enabled, Arma 3 uses only one core of the CPU.
|
||||||
|
nologs_desc=Error messages are no longer stored in the so-called "RPT" when this option is activated, which makes troubleshooting problems with Arma 3 much more difficult.
|
||||||
|
nopause_desc=The game continues to run in the background in single player mode even when minimized. Comparable to the multiplayer mode, as the game continues in the background even when minimized.
|
||||||
|
nosplash_desc=If this option is activated, the page with the logos is no longer shown during the game start.
|
||||||
|
not_arma_dir=This doesn't look like your ArmA directory...
|
||||||
|
not_arma_dir_msg=The selected folder does not look like an ArmA directory. Check if there is also an arma3.exe in this folder.\
|
||||||
|
But the folder was still saved!
|
||||||
|
pause=Pause
|
||||||
|
performance=Performance
|
||||||
|
play=Play
|
||||||
|
play_now=Play now on the server!
|
||||||
|
port=Port
|
||||||
|
posx_desc=Position (not size) of the window in window mode (X axis, horizontal).
|
||||||
|
posy_desc=The counterpart to PosX, only for the Y-axis (the vertical or "Up the tree").
|
||||||
|
preset=Preset
|
||||||
|
preset_settings=Presets settings
|
||||||
|
presets=Presets
|
||||||
|
profile_desc=Profile to be loaded at Arma startup.
|
||||||
|
progress=Progress
|
||||||
|
remaining_time=Remaining time
|
||||||
|
remove=Remove
|
||||||
|
rename=Rename
|
||||||
|
reset_default=Reset to default
|
||||||
|
running=running
|
||||||
|
select_all=Select All
|
||||||
|
select_folder=Choose folder
|
||||||
|
select_mods=Select mods
|
||||||
|
select_server=Select Server
|
||||||
|
settings=Settings
|
||||||
|
show_startparameter=Show start parameters
|
||||||
|
showscripterrors_desc=Errors in scripts are signaled in a message text.
|
||||||
|
signed_in=signed in
|
||||||
|
speed=Speed
|
||||||
|
speed_up_game=Speed up game start
|
||||||
|
spikintro_desc=The intro sequence is skipped.
|
||||||
|
total_file_size=Total file size
|
||||||
|
update=Update
|
||||||
|
use64bitclient_desc=Starts Arma3 with the .exe file optimized for 64-bit operating systems (can improve the performance of Arma 3 and fix problems (e.g. 3-FPS bug)
|
||||||
|
use_workshop=Try to use workshop content
|
||||||
|
use_workshop_desc=For large modspacks, the client tries to copy already downloaded workshop content that is the same to make the download faster
|
||||||
|
warning=Warning
|
||||||
|
warning_workshop=The client tries its best to find the same files,\
|
||||||
|
but it can happen that they are not the same files.\
|
||||||
|
In case of a failed sync with this option, you should\
|
||||||
|
you deactivate it and sync again without this option.\
|
||||||
|
\
|
||||||
|
This could also lead to short performance losses.
|
||||||
|
window_desc=If this option is active, Arma 3 is started in windowed mode.
|
||||||
|
world_desc=Here you can enter a card to be loaded and displayed as background in the menus (e.g. "altis" or "stratis" - without quotation marks!). If the field is empty, no map will be loaded during startup and the start of Arma 3 will be faster.
|
Loading…
Reference in New Issue
Block a user