diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/settings/CSubmenuDownloaders.java b/forge-gui-desktop/src/main/java/forge/screens/home/settings/CSubmenuDownloaders.java index 53a0814f8c3..b3fd57d9a7f 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/home/settings/CSubmenuDownloaders.java +++ b/forge-gui-desktop/src/main/java/forge/screens/home/settings/CSubmenuDownloaders.java @@ -23,6 +23,13 @@ public enum CSubmenuDownloaders implements ICDoc { VSubmenuDownloaders.SINGLETON_INSTANCE.showLicensing(); } }; + private final UiCommand cmdCheckForUpdates = new UiCommand() { + @Override + public void run() { + new AutoUpdater(false).attemptToUpdate(); + } + }; + private final UiCommand cmdPicDownload = new UiCommand() { @Override public void run() { new GuiDownloader(new GuiDownloadPicturesLQ()).show(); @@ -84,6 +91,7 @@ public enum CSubmenuDownloaders implements ICDoc { @Override public void initialize() { final VSubmenuDownloaders view = VSubmenuDownloaders.SINGLETON_INSTANCE; + view.setCheckForUpdatesCommand(cmdCheckForUpdates); view.setDownloadPicsCommand(cmdPicDownload); view.setDownloadPicsHQCommand(cmdPicDownloadHQ); view.setDownloadSetPicsCommand(cmdSetDownload); diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/settings/CSubmenuPreferences.java b/forge-gui-desktop/src/main/java/forge/screens/home/settings/CSubmenuPreferences.java index 96080f2a500..3e26afdf007 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/home/settings/CSubmenuPreferences.java +++ b/forge-gui-desktop/src/main/java/forge/screens/home/settings/CSubmenuPreferences.java @@ -3,6 +3,7 @@ package forge.screens.home.settings; import forge.*; import forge.ai.AiProfileUtil; import forge.control.FControl.CloseAction; +import forge.download.AutoUpdater; import forge.game.GameLogEntryType; import forge.gui.framework.FScreen; import forge.gui.framework.ICDoc; @@ -225,6 +226,7 @@ public enum CSubmenuPreferences implements ICDoc { initializeGameLogVerbosityComboBox(); initializeCloseActionComboBox(); initializeDefaultFontSizeComboBox(); + initializeAutoUpdaterComboBox(); initializeMulliganRuleComboBox(); initializeAiProfilesComboBox(); initializeStackAdditionsComboBox(); @@ -378,6 +380,16 @@ public enum CSubmenuPreferences implements ICDoc { panel.setComboBox(comboBox, selectedItem); } + private void initializeAutoUpdaterComboBox() { + // TODO: Ideally we would filter out update paths based on the type of Forge people have + final String[] updatePaths = AutoUpdater.updateChannels; + final FPref updatePreference = FPref.AUTO_UPDATE; + final FComboBoxPanel panel = this.view.getCbpAutoUpdater(); + final FComboBox comboBox = createComboBox(updatePaths, updatePreference); + final String selectedItem = this.prefs.getPref(updatePreference); + panel.setComboBox(comboBox, selectedItem); + } + private void initializeMulliganRuleComboBox() { final String [] choices = MulliganDefs.getMulliganRuleNames(); final FPref userSetting = FPref.MULLIGAN_RULE; diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/settings/VSubmenuDownloaders.java b/forge-gui-desktop/src/main/java/forge/screens/home/settings/VSubmenuDownloaders.java index 6e1354a6727..2f48c1841ef 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/home/settings/VSubmenuDownloaders.java +++ b/forge-gui-desktop/src/main/java/forge/screens/home/settings/VSubmenuDownloaders.java @@ -55,6 +55,7 @@ public enum VSubmenuDownloaders implements IVSubmenu { private final JPanel pnlContent = new JPanel(new MigLayout("insets 0, gap 0, wrap, ay center")); private final FScrollPane scrContent = new FScrollPane(pnlContent, false); + private final FLabel btnCheckForUpdates = _makeButton(localizer.getMessage("btnCheckForUpdates")); private final FLabel btnDownloadSetPics = _makeButton(localizer.getMessage("btnDownloadSetPics")); private final FLabel btnDownloadPics = _makeButton(localizer.getMessage("btnDownloadPics")); private final FLabel btnDownloadPicsHQ = _makeButton(localizer.getMessage("btnDownloadPicsHQ")); @@ -80,6 +81,9 @@ public enum VSubmenuDownloaders implements IVSubmenu { if (javaRecentEnough()) { + pnlContent.add(btnCheckForUpdates, constraintsBTN); + pnlContent.add(_makeLabel(localizer.getMessage("lblCheckForUpdates")), constraintsLBL); + pnlContent.add(btnDownloadPics, constraintsBTN); pnlContent.add(_makeLabel(localizer.getMessage("lblDownloadPics")), constraintsLBL); @@ -162,6 +166,7 @@ public enum VSubmenuDownloaders implements IVSubmenu { return EMenuGroup.SETTINGS; } + public void setCheckForUpdatesCommand(UiCommand command) { btnCheckForUpdates.setCommand(command); } public void setDownloadPicsCommand(UiCommand command) { btnDownloadPics.setCommand(command); } public void setDownloadPicsHQCommand(UiCommand command) { btnDownloadPicsHQ.setCommand(command); } public void setDownloadSetPicsCommand(UiCommand command) { btnDownloadSetPics.setCommand(command); } diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/settings/VSubmenuPreferences.java b/forge-gui-desktop/src/main/java/forge/screens/home/settings/VSubmenuPreferences.java index e5d6c8658cf..567a017c0e1 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/home/settings/VSubmenuPreferences.java +++ b/forge-gui-desktop/src/main/java/forge/screens/home/settings/VSubmenuPreferences.java @@ -25,8 +25,8 @@ import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; -import java.util.*; import java.util.List; +import java.util.*; /** @@ -123,6 +123,7 @@ public enum VSubmenuPreferences implements IVSubmenu { private final FComboBoxPanel cbpCounterDisplayLocation =new FComboBoxPanel<>(localizer.getMessage("cbpCounterDisplayLocation")+":"); private final FComboBoxPanel cbpGraveyardOrdering = new FComboBoxPanel<>(localizer.getMessage("cbpGraveyardOrdering")+":"); private final FComboBoxPanel cbpDefaultLanguage = new FComboBoxPanel<>(localizer.getMessage("cbpSelectLanguage")+":"); + private final FComboBoxPanel cbpAutoUpdater = new FComboBoxPanel<>(localizer.getMessage("cbpAutoUpdater")+":"); /** * Constructor. @@ -157,6 +158,10 @@ public enum VSubmenuPreferences implements IVSubmenu { pnlPrefs.add(new SectionLabel(localizer.getMessage("GeneralConfiguration")), sectionConstraints); // language + + pnlPrefs.add(cbpAutoUpdater, comboBoxConstraints); + pnlPrefs.add(new NoteLabel(localizer.getMessage("nlAutoUpdater")), descriptionConstraints); + pnlPrefs.add(cbpDefaultLanguage, comboBoxConstraints); pnlPrefs.add(new NoteLabel(localizer.getMessage("nlSelectLanguage")), descriptionConstraints); @@ -531,6 +536,10 @@ public enum VSubmenuPreferences implements IVSubmenu { } } + public final FComboBoxPanel getCbpAutoUpdater() { + return cbpAutoUpdater; + } + /** @return {@link javax.swing.JCheckBox} */ public final JCheckBox getCbCompactMainMenu() { return cbCompactMainMenu; diff --git a/forge-gui-desktop/src/main/java/forge/view/Main.java b/forge-gui-desktop/src/main/java/forge/view/Main.java index 05675d2225d..de1bc65aafa 100644 --- a/forge-gui-desktop/src/main/java/forge/view/Main.java +++ b/forge-gui-desktop/src/main/java/forge/view/Main.java @@ -81,7 +81,7 @@ public final class Main { break; default: - System.out.println("Unknown mode.\nKnown mode is 'sim' "); + System.out.println("Unknown mode.\nKnown mode is 'sim', 'parse' "); break; } diff --git a/forge-gui/res/languages/en-US.properties b/forge-gui/res/languages/en-US.properties index 503298d25a2..7b149832456 100644 --- a/forge-gui/res/languages/en-US.properties +++ b/forge-gui/res/languages/en-US.properties @@ -50,6 +50,8 @@ btnResetJavaFutureCompatibilityWarnings=Reset Java Compatibility Warnings btnClearImageCache=Clear Image Cache btnTokenPreviewer=Token Previewer btnCopyToClipboard=Copy to Clipboard +cbpAutoUpdater=Auto updater +nlAutoUpdater=Select the release channel to use for updating Forge cbpSelectLanguage=Language nlSelectLanguage=Select Language (Excluded Game part. Still a work in progress) (RESTART REQUIRED) cbRemoveSmall=Remove Small Creatures @@ -180,6 +182,7 @@ KeyboardShortcuts=Keyboard Shortcuts #VSubmenuAchievements.java lblAchievements=Achievements #VSubmenuDownloaders.java +btnCheckForUpdates=Check for Updates btnDownloadSetPics=Download LQ Set Pictures btnDownloadPicsHQ=Download HQ Card Pictures (Very Slow!) btnDownloadPics=Download LQ Card Pictures @@ -192,6 +195,7 @@ btnImportPictures=Import Data btnHowToPlay=How To Play btnDownloadPrices=Download Card Prices btnLicensing=License Details +lblCheckForUpdates=Check Forge server to see if there's a more recent release lblDownloadPics=Download default card picture for each card. lblDownloadPicsHQ=Download default card HQ picture for each card. lblDownloadSetPics=Download all pictures of each card (one for each set the card appeared in) diff --git a/forge-gui/src/main/java/forge/download/AutoUpdater.java b/forge-gui/src/main/java/forge/download/AutoUpdater.java new file mode 100644 index 00000000000..8d050efecef --- /dev/null +++ b/forge-gui/src/main/java/forge/download/AutoUpdater.java @@ -0,0 +1,247 @@ +package forge.download; + +import com.google.common.collect.ImmutableList; +import forge.GuiBase; +import forge.model.FModel; +import forge.properties.ForgePreferences; +import forge.util.BuildInfo; +import forge.util.FileUtil; +import forge.util.WaitCallback; +import forge.util.gui.SOptionPane; +import org.apache.commons.lang3.StringUtils; + +import javax.swing.*; +import java.awt.*; +import java.io.File; +import java.io.IOException; +import java.net.*; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class AutoUpdater { + private final String SNAPSHOT_VERSION_INDEX = "https://snapshots.cardforge.org/"; + private final String SNAPSHOT_VERSION_URL = "https://snapshots.cardforge.org/version.txt"; + private final String SNAPSHOT_PACKAGE = "https://snapshots.cardforge.org/latest/"; + private final String RELEASE_VERSION_URL = "https://releases.cardforge.org/forge/forge-gui-desktop/version.txt"; + private final String RELEASE_PACKAGE = "https://releases.cardforge.org/latest/"; + private final String RELEASE_MAVEN_METADATA = "https://releases.cardforge.org/forge/forge-gui-desktop/maven-metadata.xml"; + private static final boolean VERSION_FROM_METADATA = true; + private static final String TMP_DIR = "tmp/"; + + public static String[] updateChannels = new String[]{ "none", "snapshot", "release"}; + + private boolean isLoading; + private String updateChannel; + private String version; + private String buildVersion; + private String versionUrlString; + private String packageUrl; + private String packagePath; + + public AutoUpdater(boolean loading) { + // What do I need? Preferences? Splashscreen? UI? Skins? + isLoading = loading; + updateChannel = FModel.getPreferences().getPref(ForgePreferences.FPref.AUTO_UPDATE); + buildVersion = BuildInfo.getVersionString(); + } + + public boolean attemptToUpdate() { + if (!verifyUpdateable()) { + return false; + } + try { + if (downloadUpdate()) { + extractAndRestart(); + } + } catch(IOException | URISyntaxException e) { + return false; + } + return true; + } + + private void extractAndRestart() { + extractUpdate(); + restartForge(); + } + + private boolean verifyUpdateable() { + if (buildVersion.contains("GIT")) { + //return false; + } + + if (isLoading) { + // TODO This doesn't work yet, because FSkin isn't loaded at the time. + return false; + } else if (updateChannel.equals("none")) { + String message = "You haven't set an update channel. Do you want to check a channel now?"; + List options = ImmutableList.of("Cancel", "release", "snapshot"); + int option = SOptionPane.showOptionDialog(message, "Manual Check", null, options, 0); + if (option == 0) { + return false; + } else { + updateChannel = options.get(option); + } + } + + if (buildVersion.contains("SNAPSHOT")) { + if (!updateChannel.equals("snapshot")) { + System.out.println("Snapshot build versions must use snapshot update channel to work"); + return false; + } + + versionUrlString = SNAPSHOT_VERSION_URL; + packageUrl = SNAPSHOT_PACKAGE; + } else { + versionUrlString = RELEASE_VERSION_URL; + packageUrl = RELEASE_PACKAGE; + } + + // Check the internet connection + if (!testNetConnection()) { + return false; + } + + // Download appropriate version file + return compareBuildWithLatestChannelVersion(); + } + + private boolean testNetConnection() { + try (Socket socket = new Socket()) { + InetSocketAddress address = new InetSocketAddress("releases.cardforge.org", 443); + socket.connect(address, 1000); + return true; + } catch (IOException e) { + return false; // Either timeout or unreachable or failed DNS lookup. + } + } + + private boolean compareBuildWithLatestChannelVersion() { + try { + retrieveVersion(); + + if (StringUtils.isEmpty(version) ) { + return false; + } + + if (buildVersion.equals(version)) { + return false; + } + } + catch (Exception e) { + e.printStackTrace(); + return false; + } + // If version doesn't match, it's assummably newer. + return true; + } + + private void retrieveVersion() throws MalformedURLException { + if (VERSION_FROM_METADATA) { + if (updateChannel.equals("release")) { + extractVersionFromMavenRelease(); + } else { + extractVersionFromSnapshotIndex(); + } + } else { + URL versionUrl = new URL(versionUrlString); + version = FileUtil.readFileToString(versionUrl); + } + } + + private void extractVersionFromSnapshotIndex() throws MalformedURLException { + URL metadataUrl = new URL(SNAPSHOT_VERSION_INDEX); + String index = FileUtil.readFileToString(metadataUrl); + + System.out.println(index); + Pattern p = Pattern.compile(">forge-(.*SNAPSHOT)"); + Matcher m = p.matcher(index); + while(m.find()){ + version = m.group(1); + } + } + + private void extractVersionFromMavenRelease() throws MalformedURLException { + URL metadataUrl = new URL(RELEASE_MAVEN_METADATA); + String xml = FileUtil.readFileToString(metadataUrl); + + Pattern p = Pattern.compile("(.*)"); + Matcher m = p.matcher(xml); + while(m.find()){ + version = m.group(1); + } + } + + private boolean downloadUpdate() throws URISyntaxException, IOException { + // TODO Change the "auto" to be more auto. + if (isLoading) { + // We need to preload enough of a Skins to show a dialog and a button if we're in loading + // splashScreen.prepareForDialogs(); + return downloadFromBrowser(); + } + + String message = "A new version of Forge is available (" + version + ").\n" + + "You are currently on version (" + buildVersion + ").\n\n" + + "Would you like to update to the new version now?"; + + final List options = ImmutableList.of("Update Now", "Update Later"); + if (SOptionPane.showOptionDialog(message, "New Version Available", null, options, 0) == 0) { + return downloadFromForge(); + } + + return false; + } + + private boolean downloadFromBrowser() throws URISyntaxException, IOException { + final Desktop desktop = Desktop.isDesktopSupported() ? Desktop.getDesktop() : null; + if (desktop != null && desktop.isSupported(Desktop.Action.BROWSE)) { + // Linking directly there will auto download, but won't auto-update + desktop.browse(new URI(packageUrl)); + return true; + } else { + System.out.println("Download latest version: " + packageUrl); + return false; + } + } + + private boolean downloadFromForge() { + WaitCallback callback = new WaitCallback() { + @Override + public void run() { + GuiBase.getInterface().download(new GuiDownloadZipService("Auto Updater", "Download the new version..", packageUrl, "tmp/", null, null) { + @Override + public void downloadAndUnzip() { + packagePath = download(version + "-upgrade.tar.bz2"); + if (packagePath != null) { + extractAndRestart(); + } + } + }, this); + } + }; + + SwingUtilities.invokeLater(callback); + // + return false; + } + + private void extractUpdate() { + // TODOD Something like https://stackoverflow.com/questions/315618/how-do-i-extract-a-tar-file-in-java + final Desktop desktop = Desktop.isDesktopSupported() ? Desktop.getDesktop() : null; + if (desktop != null) { + try { + desktop.open(new File(packagePath).getParentFile()); + } catch (IOException e) { + e.printStackTrace(); + } + } else { + System.out.println(packagePath); + } + } + + private void restartForge() { + if (isLoading || SOptionPane.showConfirmDialog("Forge has been downloaded. You should extract the package and restart Forge for the new version.", "Exit now?")) { + System.exit(0); + } + } +} diff --git a/forge-gui/src/main/java/forge/download/GuiDownloadZipService.java b/forge-gui/src/main/java/forge/download/GuiDownloadZipService.java index f1d1dc9b8d4..dd142b04cf4 100644 --- a/forge-gui/src/main/java/forge/download/GuiDownloadZipService.java +++ b/forge-gui/src/main/java/forge/download/GuiDownloadZipService.java @@ -73,72 +73,7 @@ public class GuiDownloadZipService extends GuiDownloadService { String zipFilename = download("temp.zip"); if (zipFilename == null) { return; } - //if assets.zip downloaded successfully, unzip into destination folder - try { - GuiBase.getInterface().preventSystemSleep(true); //prevent system from going into sleep mode while unzipping - - if (deleteFolder != null) { - final File deleteDir = new File(deleteFolder); - if (deleteDir.exists()) { - //attempt to delete previous res directory if to be rebuilt - progressBar.reset(); - progressBar.setDescription("Deleting old " + desc + "..."); - if (deleteFolder.equals(destFolder)) { //move zip file to prevent deleting it - final String oldZipFilename = zipFilename; - zipFilename = deleteDir.getParentFile().getAbsolutePath() + File.separator + "temp.zip"; - Files.move(new File(oldZipFilename), new File(zipFilename)); - } - FileUtil.deleteDirectory(deleteDir); - } - } - - final ZipFile zipFile = new ZipFile(zipFilename); - final Enumeration entries = zipFile.entries(); - - progressBar.reset(); - progressBar.setPercentMode(true); - progressBar.setDescription("Extracting " + desc); - progressBar.setMaximum(zipFile.size()); - - FileUtil.ensureDirectoryExists(destFolder); - - int count = 0; - int failedCount = 0; - while (entries.hasMoreElements()) { - if (cancel) { break; } - - try { - final ZipEntry entry = entries.nextElement(); - - final String path = destFolder + File.separator + entry.getName(); - if (entry.isDirectory()) { - new File(path).mkdir(); - progressBar.setValue(++count); - continue; - } - copyInputStream(zipFile.getInputStream(entry), path); - progressBar.setValue(++count); - filesExtracted++; - } - catch (final Exception e) { //don't quit out completely if an entry is not UTF-8 - progressBar.setValue(++count); - failedCount++; - } - } - - if (failedCount > 0) { - Log.error("Downloading " + desc, failedCount + " " + desc + " could not be extracted"); - } - - zipFile.close(); - new File(zipFilename).delete(); - } - catch (final Exception e) { - e.printStackTrace(); - } - finally { - GuiBase.getInterface().preventSystemSleep(false); - } + extract(zipFilename); } public String download(final String filename) { @@ -211,6 +146,75 @@ public class GuiDownloadZipService extends GuiDownloadService { } } + public void extract(String zipFilename) { + //if assets.zip downloaded successfully, unzip into destination folder + try { + GuiBase.getInterface().preventSystemSleep(true); //prevent system from going into sleep mode while unzipping + + if (deleteFolder != null) { + final File deleteDir = new File(deleteFolder); + if (deleteDir.exists()) { + //attempt to delete previous res directory if to be rebuilt + progressBar.reset(); + progressBar.setDescription("Deleting old " + desc + "..."); + if (deleteFolder.equals(destFolder)) { //move zip file to prevent deleting it + final String oldZipFilename = zipFilename; + zipFilename = deleteDir.getParentFile().getAbsolutePath() + File.separator + "temp.zip"; + Files.move(new File(oldZipFilename), new File(zipFilename)); + } + FileUtil.deleteDirectory(deleteDir); + } + } + + final ZipFile zipFile = new ZipFile(zipFilename); + final Enumeration entries = zipFile.entries(); + + progressBar.reset(); + progressBar.setPercentMode(true); + progressBar.setDescription("Extracting " + desc); + progressBar.setMaximum(zipFile.size()); + + FileUtil.ensureDirectoryExists(destFolder); + + int count = 0; + int failedCount = 0; + while (entries.hasMoreElements()) { + if (cancel) { break; } + + try { + final ZipEntry entry = entries.nextElement(); + + final String path = destFolder + File.separator + entry.getName(); + if (entry.isDirectory()) { + new File(path).mkdir(); + progressBar.setValue(++count); + continue; + } + copyInputStream(zipFile.getInputStream(entry), path); + progressBar.setValue(++count); + filesExtracted++; + } + catch (final Exception e) { //don't quit out completely if an entry is not UTF-8 + progressBar.setValue(++count); + failedCount++; + } + } + + if (failedCount > 0) { + Log.error("Downloading " + desc, failedCount + " " + desc + " could not be extracted"); + } + + zipFile.close(); + new File(zipFilename).delete(); + } + catch (final Exception e) { + e.printStackTrace(); + } + finally { + GuiBase.getInterface().preventSystemSleep(false); + } + } + protected void copyInputStream(final InputStream in, final String outPath) throws IOException { final byte[] buffer = new byte[1024]; int len; diff --git a/forge-gui/src/main/java/forge/model/FModel.java b/forge-gui/src/main/java/forge/model/FModel.java index d0c182e890c..a574d3cd493 100644 --- a/forge-gui/src/main/java/forge/model/FModel.java +++ b/forge-gui/src/main/java/forge/model/FModel.java @@ -28,6 +28,7 @@ import forge.card.CardType; import forge.deck.CardArchetypeLDAGenerator; import forge.deck.CardRelationMatrixGenerator; import forge.deck.io.DeckPreferences; +import forge.download.AutoUpdater; import forge.game.GameFormat; import forge.game.GameType; import forge.game.card.CardUtil; @@ -117,7 +118,6 @@ public final class FModel { Localizer.getInstance().initialize(FModel.getPreferences().getPref(FPref.UI_LANGUAGE), ForgeConstants.LANG_DIR); - //load card database final ProgressObserver progressBarBridge = (progressBar == null) ? ProgressObserver.emptyObserver : new ProgressObserver() { @Override @@ -143,6 +143,11 @@ public final class FModel { } }; + if (new AutoUpdater(true).attemptToUpdate()) { + // + } + + //load card database final CardStorageReader reader = new CardStorageReader(ForgeConstants.CARD_DATA_DIR, progressBarBridge, FModel.getPreferences().getPrefBoolean(FPref.LOAD_CARD_SCRIPTS_LAZILY)); final CardStorageReader tokenReader = new CardStorageReader(ForgeConstants.TOKEN_DATA_DIR, progressBarBridge, @@ -220,8 +225,6 @@ public final class FModel { achievements.put(GameType.Quest, new QuestAchievements()); achievements.put(GameType.PlanarConquest, new PlanarConquestAchievements()); achievements.put(GameType.Puzzle, new PuzzleAchievements()); - - //preload AI profiles AiProfileUtil.loadAllProfiles(ForgeConstants.AI_PROFILE_DIR); diff --git a/forge-gui/src/main/java/forge/properties/ForgePreferences.java b/forge-gui/src/main/java/forge/properties/ForgePreferences.java index f9b7c3329a4..c3001f43e0a 100644 --- a/forge-gui/src/main/java/forge/properties/ForgePreferences.java +++ b/forge-gui/src/main/java/forge/properties/ForgePreferences.java @@ -153,6 +153,7 @@ public class ForgePreferences extends PreferencesStore { //TODO This should be removed after the update that requires Java 8. DISABLE_DISPLAY_JAVA_8_UPDATE_WARNING("false"), + AUTO_UPDATE("none"), USE_SENTRY("false"), // this controls whether automated bug reporting is done or not MATCH_HOT_SEAT_MODE("false"), //this only applies to mobile game