diff --git a/forge-ai/src/main/java/forge/ai/GameState.java b/forge-ai/src/main/java/forge/ai/GameState.java index 9d71da36c6a..e07b65d95c4 100644 --- a/forge-ai/src/main/java/forge/ai/GameState.java +++ b/forge-ai/src/main/java/forge/ai/GameState.java @@ -981,14 +981,27 @@ public abstract class GameState { spellDef = spellDef.substring(0, spellDef.indexOf("->")).trim(); } - PaperCard pc = StaticData.instance().getCommonCards().getCard(spellDef); + Card c = null; - if (pc == null) { - System.err.println("ERROR: Could not find a card with name " + spellDef + " to precast!"); - return; + if (StringUtils.isNumeric(spellDef)) { + // Precast from a specific host + c = idToCard.get(Integer.parseInt(spellDef)); + if (c == null) { + System.err.println("ERROR: Could not find a card with ID " + spellDef + " to precast!"); + return; + } + } else { + // Precast from a card by name + PaperCard pc = StaticData.instance().getCommonCards().getCard(spellDef); + + if (pc == null) { + System.err.println("ERROR: Could not find a card with name " + spellDef + " to precast!"); + return; + } + + c = Card.fromPaperCard(pc, activator); } - Card c = Card.fromPaperCard(pc, activator); SpellAbility sa = null; if (!scriptID.isEmpty()) { diff --git a/forge-core/src/main/java/forge/card/CardEdition.java b/forge-core/src/main/java/forge/card/CardEdition.java index 9eca4eb84d2..66cb689feed 100644 --- a/forge-core/src/main/java/forge/card/CardEdition.java +++ b/forge-core/src/main/java/forge/card/CardEdition.java @@ -274,14 +274,24 @@ public final class CardEdition implements Comparable { // immutable it should also match the Un-set and older alternate art cards like Merseine from FEM (should the editions files ever be updated) */ - "(^(?[0-9]+.?) )?((?[SCURML]) )?(?.*)$" + //"(^(?[0-9]+.?) )?((?[SCURML]) )?(?.*)$" + /* Ideally we'd use the named group above, but Android 6 and + earlier don't appear to support named groups. + So, untill support for those devices is officially dropped, + we'll have to suffice with numbered groups. + We are looking for: + * cnum - grouping #2 + * rarity - grouping #4 + * name - grouping #5 + */ + "(^([0-9]+.?) )?(([SCURML]) )?(.*)$" ); for(String line : contents.get("cards")) { Matcher matcher = pattern.matcher(line); if (matcher.matches()) { - String collectorNumber = matcher.group("cnum"); - CardRarity r = CardRarity.smartValueOf(matcher.group("rarity")); - String cardName = matcher.group("name"); + String collectorNumber = matcher.group(2); + CardRarity r = CardRarity.smartValueOf(matcher.group(4)); + String cardName = matcher.group(5); CardInSet cis = new CardInSet(cardName, collectorNumber, r); processedCards.add(cis); } diff --git a/forge-gui-android/res/mipmap-hdpi/ic_launcher.png b/forge-gui-android/res/mipmap-hdpi/ic_launcher.png index 13ac6220632..4271e4c73a0 100644 Binary files a/forge-gui-android/res/mipmap-hdpi/ic_launcher.png and b/forge-gui-android/res/mipmap-hdpi/ic_launcher.png differ diff --git a/forge-gui-android/res/mipmap-hdpi/ic_launcher_foreground.png b/forge-gui-android/res/mipmap-hdpi/ic_launcher_foreground.png index a29e46aa510..a749b470515 100644 Binary files a/forge-gui-android/res/mipmap-hdpi/ic_launcher_foreground.png and b/forge-gui-android/res/mipmap-hdpi/ic_launcher_foreground.png differ diff --git a/forge-gui-android/res/mipmap-hdpi/ic_launcher_round.png b/forge-gui-android/res/mipmap-hdpi/ic_launcher_round.png index 07a75d76bfa..23880358c4f 100644 Binary files a/forge-gui-android/res/mipmap-hdpi/ic_launcher_round.png and b/forge-gui-android/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/forge-gui-android/res/mipmap-ldpi/ic_launcher.png b/forge-gui-android/res/mipmap-ldpi/ic_launcher.png index ee25ac432d9..ae40d73a33c 100644 Binary files a/forge-gui-android/res/mipmap-ldpi/ic_launcher.png and b/forge-gui-android/res/mipmap-ldpi/ic_launcher.png differ diff --git a/forge-gui-android/res/mipmap-mdpi/ic_launcher.png b/forge-gui-android/res/mipmap-mdpi/ic_launcher.png index 5fdd9db84cf..75cac9e8a25 100644 Binary files a/forge-gui-android/res/mipmap-mdpi/ic_launcher.png and b/forge-gui-android/res/mipmap-mdpi/ic_launcher.png differ diff --git a/forge-gui-android/res/mipmap-mdpi/ic_launcher_foreground.png b/forge-gui-android/res/mipmap-mdpi/ic_launcher_foreground.png index 524a6232021..bcb5f32aa66 100644 Binary files a/forge-gui-android/res/mipmap-mdpi/ic_launcher_foreground.png and b/forge-gui-android/res/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/forge-gui-android/res/mipmap-mdpi/ic_launcher_round.png b/forge-gui-android/res/mipmap-mdpi/ic_launcher_round.png index bb574ba21ae..fa0400329c5 100644 Binary files a/forge-gui-android/res/mipmap-mdpi/ic_launcher_round.png and b/forge-gui-android/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/forge-gui-android/res/mipmap-xhdpi/ic_launcher.png b/forge-gui-android/res/mipmap-xhdpi/ic_launcher.png index 5d5de8a444f..ad7c6ed96bb 100644 Binary files a/forge-gui-android/res/mipmap-xhdpi/ic_launcher.png and b/forge-gui-android/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/forge-gui-android/res/mipmap-xhdpi/ic_launcher_foreground.png b/forge-gui-android/res/mipmap-xhdpi/ic_launcher_foreground.png index 0e93289f2d1..25275afddb0 100644 Binary files a/forge-gui-android/res/mipmap-xhdpi/ic_launcher_foreground.png and b/forge-gui-android/res/mipmap-xhdpi/ic_launcher_foreground.png differ diff --git a/forge-gui-android/res/mipmap-xhdpi/ic_launcher_round.png b/forge-gui-android/res/mipmap-xhdpi/ic_launcher_round.png index 96328be12a9..42f78d72996 100644 Binary files a/forge-gui-android/res/mipmap-xhdpi/ic_launcher_round.png and b/forge-gui-android/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/forge-gui-android/res/mipmap-xxhdpi/ic_launcher.png b/forge-gui-android/res/mipmap-xxhdpi/ic_launcher.png index e6ea9ce1897..3f9d487ce92 100644 Binary files a/forge-gui-android/res/mipmap-xxhdpi/ic_launcher.png and b/forge-gui-android/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/forge-gui-android/res/mipmap-xxhdpi/ic_launcher_foreground.png b/forge-gui-android/res/mipmap-xxhdpi/ic_launcher_foreground.png index a01a5036f4f..a01aaa6e9df 100644 Binary files a/forge-gui-android/res/mipmap-xxhdpi/ic_launcher_foreground.png and b/forge-gui-android/res/mipmap-xxhdpi/ic_launcher_foreground.png differ diff --git a/forge-gui-android/res/mipmap-xxhdpi/ic_launcher_round.png b/forge-gui-android/res/mipmap-xxhdpi/ic_launcher_round.png index e4d1b24e68e..c1f4153cef3 100644 Binary files a/forge-gui-android/res/mipmap-xxhdpi/ic_launcher_round.png and b/forge-gui-android/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/forge-gui-android/res/mipmap-xxxhdpi/ic_launcher.png b/forge-gui-android/res/mipmap-xxxhdpi/ic_launcher.png index 3380a1063bb..6d186851cd6 100644 Binary files a/forge-gui-android/res/mipmap-xxxhdpi/ic_launcher.png and b/forge-gui-android/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/forge-gui-android/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/forge-gui-android/res/mipmap-xxxhdpi/ic_launcher_foreground.png index e8ccb890b9e..aaa2395dcb9 100644 Binary files a/forge-gui-android/res/mipmap-xxxhdpi/ic_launcher_foreground.png and b/forge-gui-android/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ diff --git a/forge-gui-android/res/mipmap-xxxhdpi/ic_launcher_round.png b/forge-gui-android/res/mipmap-xxxhdpi/ic_launcher_round.png index 68aca8009d4..8ad3506407f 100644 Binary files a/forge-gui-android/res/mipmap-xxxhdpi/ic_launcher_round.png and b/forge-gui-android/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/forge-gui-android/res/values/ic_launcher_background.xml b/forge-gui-android/res/values/ic_launcher_background.xml index 7f8bb682c03..ab983282473 100644 --- a/forge-gui-android/res/values/ic_launcher_background.xml +++ b/forge-gui-android/res/values/ic_launcher_background.xml @@ -1,4 +1,4 @@ - #f0f0f0 + #ffffff \ No newline at end of file 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-mobile/src/forge/assets/FSkin.java b/forge-gui-mobile/src/forge/assets/FSkin.java index 3eea1009c25..520c5e6a05c 100644 --- a/forge-gui-mobile/src/forge/assets/FSkin.java +++ b/forge-gui-mobile/src/forge/assets/FSkin.java @@ -209,7 +209,7 @@ public class FSkin { textures.put(f6.path(), textures.get(f3.path())); } if (f7.exists()){ - Texture t = new Texture(f7, false); + Texture t = new Texture(f7, true); //t.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear); textures.put(f7.path(), t); } diff --git a/forge-gui-mobile/src/forge/assets/FSkinImage.java b/forge-gui-mobile/src/forge/assets/FSkinImage.java index 5ed5abe8b8f..38daeb2ced1 100644 --- a/forge-gui-mobile/src/forge/assets/FSkinImage.java +++ b/forge-gui-mobile/src/forge/assets/FSkinImage.java @@ -193,6 +193,15 @@ public enum FSkinImage implements FImage { QUEST_BIG_SWORD (FSkinProp.ICO_QUEST_BIG_SWORD, SourceFile.ICONS), QUEST_BIG_BAG (FSkinProp.ICO_QUEST_BIG_BAG, SourceFile.ICONS), + //menu icon + MENU_GALAXY (FSkinProp.ICO_MENU_GALAXY, SourceFile.ICONS), + MENU_STATS (FSkinProp.ICO_MENU_STATS, SourceFile.ICONS), + MENU_PUZZLE (FSkinProp.ICO_MENU_PUZZLE, SourceFile.ICONS), + MENU_GAUNTLET (FSkinProp.ICO_MENU_GAUNTLET, SourceFile.ICONS), + MENU_SEALED (FSkinProp.ICO_MENU_SEALED, SourceFile.ICONS), + MENU_DRAFT (FSkinProp.ICO_MENU_DRAFT, SourceFile.ICONS), + MENU_CONSTRUCTED (FSkinProp.ICO_MENU_CONSTRUCTED, SourceFile.ICONS), + //Interface icons QUESTION (FSkinProp.ICO_QUESTION, SourceFile.ICONS), INFORMATION (FSkinProp.ICO_INFORMATION, SourceFile.ICONS), diff --git a/forge-gui-mobile/src/forge/screens/home/LoadGameMenu.java b/forge-gui-mobile/src/forge/screens/home/LoadGameMenu.java index 47f4707f310..a875ea6c3ec 100644 --- a/forge-gui-mobile/src/forge/screens/home/LoadGameMenu.java +++ b/forge-gui-mobile/src/forge/screens/home/LoadGameMenu.java @@ -20,11 +20,11 @@ import forge.util.Localizer; public class LoadGameMenu extends FPopupMenu { public enum LoadGameScreen { - BoosterDraft("lblBoosterDraft", FSkinImage.HAND, LoadDraftScreen.class), - SealedDeck("lblSealedDeck", FSkinImage.PACK, LoadSealedScreen.class), + BoosterDraft("lblBoosterDraft", FSkinImage.MENU_DRAFT, LoadDraftScreen.class), + SealedDeck("lblSealedDeck", FSkinImage.MENU_SEALED, LoadSealedScreen.class), QuestMode("lblQuestMode", FSkinImage.QUEST_ZEP, LoadQuestScreen.class), - PlanarConquest("lblPlanarConquest", FSkinImage.MULTIVERSE, LoadConquestScreen.class), - Gauntlet("lblGauntlet", FSkinImage.ALPHASTRIKE, LoadGauntletScreen.class); + PlanarConquest("lblPlanarConquest", FSkinImage.MENU_GALAXY, LoadConquestScreen.class), + Gauntlet("lblGauntlet", FSkinImage.MENU_GAUNTLET, LoadGauntletScreen.class); private final FMenuItem item; private final Class screenClass; diff --git a/forge-gui-mobile/src/forge/screens/home/NewGameMenu.java b/forge-gui-mobile/src/forge/screens/home/NewGameMenu.java index 0bd6829888b..af3cb2e1b74 100644 --- a/forge-gui-mobile/src/forge/screens/home/NewGameMenu.java +++ b/forge-gui-mobile/src/forge/screens/home/NewGameMenu.java @@ -24,13 +24,13 @@ public class NewGameMenu extends FPopupMenu { final static Localizer localizer = Localizer.getInstance(); public enum NewGameScreen { - Constructed(localizer.getMessage("lblConstructed"), FSkinImage.DECKLIST, ConstructedScreen.class), - BoosterDraft(localizer.getMessage("lblBoosterDraft"), FSkinImage.HAND, NewDraftScreen.class), - SealedDeck(localizer.getMessage("lblSealedDeck"), FSkinImage.PACK, NewSealedScreen.class), + Constructed(localizer.getMessage("lblConstructed"), FSkinImage.MENU_CONSTRUCTED, ConstructedScreen.class), + BoosterDraft(localizer.getMessage("lblBoosterDraft"), FSkinImage.MENU_DRAFT, NewDraftScreen.class), + SealedDeck(localizer.getMessage("lblSealedDeck"), FSkinImage.MENU_SEALED, NewSealedScreen.class), QuestMode(localizer.getMessage("lblQuestMode"), FSkinImage.QUEST_ZEP, NewQuestScreen.class), - PuzzleMode(localizer.getMessage("lblPuzzleMode"), FSkinImage.QUEST_BOOK, PuzzleScreen.class), - PlanarConquest(localizer.getMessage("lblPlanarConquest"), FSkinImage.MULTIVERSE, NewConquestScreen.class), - Gauntlet(localizer.getMessage("lblGauntlet"), FSkinImage.ALPHASTRIKE, NewGauntletScreen.class); + PuzzleMode(localizer.getMessage("lblPuzzleMode"), FSkinImage.MENU_PUZZLE, PuzzleScreen.class), + PlanarConquest(localizer.getMessage("lblPlanarConquest"), FSkinImage.MENU_GALAXY, NewConquestScreen.class), + Gauntlet(localizer.getMessage("lblGauntlet"), FSkinImage.MENU_GAUNTLET, NewGauntletScreen.class); private final FMenuItem item; private final Class screenClass; diff --git a/forge-gui-mobile/src/forge/screens/home/puzzle/PuzzleScreen.java b/forge-gui-mobile/src/forge/screens/home/puzzle/PuzzleScreen.java index 5e0dd1edfb1..0011ed4a6dc 100644 --- a/forge-gui-mobile/src/forge/screens/home/puzzle/PuzzleScreen.java +++ b/forge-gui-mobile/src/forge/screens/home/puzzle/PuzzleScreen.java @@ -54,43 +54,45 @@ public class PuzzleScreen extends LaunchScreen { final ArrayList puzzles = PuzzleIO.loadPuzzles(); Collections.sort(puzzles); - GuiChoose.one(Localizer.getInstance().getMessage("lblChooseAPuzzle"), puzzles, new Callback() { + GuiChoose.oneOrNone(Localizer.getInstance().getMessage("lblChooseAPuzzle"), puzzles, new Callback() { @Override public void run(final Puzzle chosen) { - LoadingOverlay.show(Localizer.getInstance().getMessage("lblLoadingThePuzzle"), new Runnable() { - @Override - public void run() { - // Load selected puzzle - final HostedMatch hostedMatch = GuiBase.getInterface().hostMatch(); - hostedMatch.setStartGameHook(new Runnable() { - @Override - public final void run() { - chosen.applyToGame(hostedMatch.getGame()); - } - }); + if (chosen != null) { + LoadingOverlay.show(Localizer.getInstance().getMessage("lblLoadingThePuzzle"), new Runnable() { + @Override + public void run() { + // Load selected puzzle + final HostedMatch hostedMatch = GuiBase.getInterface().hostMatch(); + hostedMatch.setStartGameHook(new Runnable() { + @Override + public final void run() { + chosen.applyToGame(hostedMatch.getGame()); + } + }); - hostedMatch.setEndGameHook((new Runnable() { - @Override - public void run() { - chosen.savePuzzleSolve(hostedMatch.getGame().getOutcome().isWinner(GamePlayerUtil.getGuiPlayer())); - } - })); + hostedMatch.setEndGameHook((new Runnable() { + @Override + public void run() { + chosen.savePuzzleSolve(hostedMatch.getGame().getOutcome().isWinner(GamePlayerUtil.getGuiPlayer())); + } + })); - final List players = new ArrayList<>(); - final RegisteredPlayer human = new RegisteredPlayer(new Deck()).setPlayer(GamePlayerUtil.getGuiPlayer()); - human.setStartingHand(0); - players.add(human); + final List players = new ArrayList<>(); + final RegisteredPlayer human = new RegisteredPlayer(new Deck()).setPlayer(GamePlayerUtil.getGuiPlayer()); + human.setStartingHand(0); + players.add(human); - final RegisteredPlayer ai = new RegisteredPlayer(new Deck()).setPlayer(GamePlayerUtil.createAiPlayer()); - ai.setStartingHand(0); - players.add(ai); + final RegisteredPlayer ai = new RegisteredPlayer(new Deck()).setPlayer(GamePlayerUtil.createAiPlayer()); + ai.setStartingHand(0); + players.add(ai); - GameRules rules = new GameRules(GameType.Puzzle); - rules.setGamesPerMatch(1); - hostedMatch.startMatch(rules, null, players, human, GuiBase.getInterface().getNewGuiGame()); - FOptionPane.showMessageDialog(chosen.getGoalDescription(), chosen.getName()); - } - }); + GameRules rules = new GameRules(GameType.Puzzle); + rules.setGamesPerMatch(1); + hostedMatch.startMatch(rules, null, players, human, GuiBase.getInterface().getNewGuiGame()); + FOptionPane.showMessageDialog(chosen.getGoalDescription(), chosen.getName()); + } + }); + } } }); diff --git a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestMenu.java b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestMenu.java index cffbd132a52..80ee1a8ff28 100644 --- a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestMenu.java +++ b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestMenu.java @@ -56,7 +56,7 @@ public class ConquestMenu extends FPopupMenu { setCurrentScreen(collectionScreen); } }); - private static final FMenuItem statsItem = new FMenuItem(Localizer.getInstance().getMessage("lblStatistics"), FSkinImage.HDMULTI, new FEventHandler() { + private static final FMenuItem statsItem = new FMenuItem(Localizer.getInstance().getMessage("lblStatistics"), FSkinImage.MENU_STATS, new FEventHandler() { @Override public void handleEvent(FEvent e) { setCurrentScreen(statsScreen); diff --git a/forge-gui-mobile/src/forge/screens/quest/QuestMenu.java b/forge-gui-mobile/src/forge/screens/quest/QuestMenu.java index 401852ee2e6..3cff3b41e84 100644 --- a/forge-gui-mobile/src/forge/screens/quest/QuestMenu.java +++ b/forge-gui-mobile/src/forge/screens/quest/QuestMenu.java @@ -79,7 +79,7 @@ public class QuestMenu extends FPopupMenu implements IVQuestStats { setCurrentScreen(bazaarScreen); } }); - private static final FMenuItem statsItem = new FMenuItem(Localizer.getInstance().getMessage("lblStatistics"), FSkinImage.HDMULTI, new FEventHandler() { + private static final FMenuItem statsItem = new FMenuItem(Localizer.getInstance().getMessage("lblStatistics"), FSkinImage.MENU_STATS, new FEventHandler() { @Override public void handleEvent(FEvent e) { setCurrentScreen(statsScreen); diff --git a/forge-gui/res/blockdata/printsheets.txt b/forge-gui/res/blockdata/printsheets.txt index 36558808c26..3dc9401f5dd 100644 --- a/forge-gui/res/blockdata/printsheets.txt +++ b/forge-gui/res/blockdata/printsheets.txt @@ -1909,7 +1909,6 @@ Knight of Sorrows Knight of the Skyward Eye Knight of the Tusk Kor Bladewhirl -Kor Chant Kor Firewalker Kor Hookmaster Kor Sky Climber @@ -2028,6 +2027,7 @@ Zealous Strike [MB1 Blue CommonUncommon] Academy Journeymage Aethersnipe +Aether Spellbomb Aether Tradewinds Amass the Components Amphin Pathmage @@ -2739,7 +2739,6 @@ Tibalt's Rager Torch Courier Uncaged Fury Undying Rage -Urza's Rage Valakut Invoker Valakut Predator Valley Dasher @@ -3615,3 +3614,21 @@ Minamo, School at Water's Edge+|FMB1 Mirrodin's Core+|FMB1 Shizo, Death's Storehouse+|FMB1 Stalking Stones+|FMB1 + +[CN2 Not In Normal Slots] +Adriana's Valor +#Assemble the Rank and Vile +Echoing Boon +#Emissary's Ploy +Hired Heist +#Hold the Permiter +Hymn of the Wilds +Incendiary Dissent +Natural Unity +#Sovereign's Realm +#Summoner's Bond +Weight Advantage +Kaya, Ghost Assassin|CN2|2 + +[CN2 Foil Kaya] +Kaya, Ghost Assassin|CN2|2 diff --git a/forge-gui/res/editions/Conspiracy Take the Crown.txt b/forge-gui/res/editions/Conspiracy Take the Crown.txt index d4c780dd130..7d2d59cfc7d 100644 --- a/forge-gui/res/editions/Conspiracy Take the Crown.txt +++ b/forge-gui/res/editions/Conspiracy Take the Crown.txt @@ -6,7 +6,8 @@ Code2=CN2 MciCode=cn2 Type=Other BoosterCovers=3 -Booster=10 Common:!fromSheet("CN2 Draft Matters"), 3 Uncommon:!fromSheet("CN2 Draft Matters"), 1 RareMythic:!fromSheet("CN2 Draft Matters"), 1 fromSheet("CN2 Draft Matters") +Booster=10 Common:!fromSheet("CN2 Not In Normal Slots"), 3 Uncommon:!fromSheet("CN2 Not In Normal Slots"), 1 RareMythic:!fromSheet("CN2 Not In Normal Slots"), 1 fromSheet("CN2 Draft Matters") +AdditionalSheetForFoils=fromSheet("CN2 Foil Kaya") [cards] 1 C Adriana's Valor @@ -243,4 +244,4 @@ r_1_1_goblin_noblock r_8_8_lizard g_3_3_beast g_1_1_insect -c_1_1_a_construct_defender \ No newline at end of file +c_1_1_a_construct_defender diff --git a/forge-gui/res/languages/en-US.properties b/forge-gui/res/languages/en-US.properties index e9b43276d00..d804d3f9c27 100644 --- a/forge-gui/res/languages/en-US.properties +++ b/forge-gui/res/languages/en-US.properties @@ -52,6 +52,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 @@ -182,6 +184,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 @@ -194,6 +197,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/res/puzzle/PS_THB6.pzl b/forge-gui/res/puzzle/PS_THB6.pzl new file mode 100644 index 00000000000..0fb3f36c66e --- /dev/null +++ b/forge-gui/res/puzzle/PS_THB6.pzl @@ -0,0 +1,18 @@ +[metadata] +Name:Possibility Storm - Theros Beyond Death #06 +URL:https://i0.wp.com/www.possibilitystorm.com/wp-content/uploads/2020/02/149.-THB6-1-scaled.jpg +Goal:Win +Turns:1 +Difficulty:Uncommon +Description:Win this turn. Assume any unknown cards drawn by either player are not relevant to solving the puzzle. Your opponent starts with 13 cards in their library. Your opponent has a Pollenbright Druid on top of their library, and twelve other unknown cards in it. +[state] +humanlife=20 +ailife=18 +turn=1 +activeplayer=human +activephase=MAIN1 +humanhand=Assassin's Trophy;Unmoored Ego;Applied Biomancy;Underworld Dreams;Tyrant's Scorn +humanlibrary=Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt +humanbattlefield=Ob Nixilis, the Hate-Twisted|Counters:LOYALTY=2;Nessian Boar;Thief of Sanity;Thief of Sanity;Watery Grave|NoETBTrigs;Watery Grave|NoETBTrigs;Watery Grave|NoETBTrigs;Watery Grave|NoETBTrigs;Breeding Pool|NoETBTrigs;Breeding Pool|NoETBTrigs;Breeding Pool|NoETBTrigs +ailibrary=Pollenbright Druid;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt +aibattlefield=Silhana Wayfinder;Silhana Wayfinder;Blightbeetle;Wavebreak Hippocamp diff --git a/forge-gui/res/puzzle/PS_THB7.pzl b/forge-gui/res/puzzle/PS_THB7.pzl new file mode 100644 index 00000000000..0f8ed430eb9 --- /dev/null +++ b/forge-gui/res/puzzle/PS_THB7.pzl @@ -0,0 +1,17 @@ +[metadata] +Name:Possibility Storm - Theros Beyond Death #07 +URL:https://i2.wp.com/www.possibilitystorm.com/wp-content/uploads/2020/03/150.-THB7-scaled.jpg +Goal:Win +Turns:100 +Difficulty:Mythic +Description:It's your OPPONENT'S turn (first main phase), and you need to win before you lose. Can you do it? Your opponent has no cards in hand and no available mana (assume they just tapped out to cast Goblin Assault Team). You control your opponent's Dreadhorde Butcher with The Akroan War's first chapter ability. Assume the puzzle starts with no cards in either player's graveyard. +[state] +humanlife=3 +ailife=11 +turn=1 +activeplayer=ai +activephase=MAIN1 +humanhand=Lazotep Plating;Slaying Fire;So Tiny;Shock;Gideon's Triumph;Aspect of Manticore +humanbattlefield=The Akroan War|Counters:LORE=2|Id:2;Blood Aspirant;Flux Channeler;Naiad of Hidden Coves;Temple of Enlightenment|NoETBTrigs;Temple of Enlightenment|NoETBTrigs;Sacred Foundry|NoETBTrigs;Sacred Foundry|NoETBTrigs +aibattlefield=Underworld Dreams;Underworld Dreams;Underworld Dreams;Ferocity of the Wilds;Goblin Assault Team;Temple Thief;Mire Triton;Dreadhorde Butcher|Id:1 +humanprecast=2:DBGainControl->1 diff --git a/forge-gui/res/skins/darkred/bg_match.jpg b/forge-gui/res/skins/darkred/bg_match.jpg index f926fee0812..fb7c0298072 100644 Binary files a/forge-gui/res/skins/darkred/bg_match.jpg and b/forge-gui/res/skins/darkred/bg_match.jpg differ diff --git a/forge-gui/res/skins/default/sprite_icons.png b/forge-gui/res/skins/default/sprite_icons.png index 7cff5a518d1..384ae908ccf 100644 Binary files a/forge-gui/res/skins/default/sprite_icons.png and b/forge-gui/res/skins/default/sprite_icons.png differ diff --git a/forge-gui/res/skins/default/sprite_manaicons.png b/forge-gui/res/skins/default/sprite_manaicons.png index 3b8f734e939..8cbbda13212 100644 Binary files a/forge-gui/res/skins/default/sprite_manaicons.png and b/forge-gui/res/skins/default/sprite_manaicons.png differ diff --git a/forge-gui/src/main/java/forge/assets/FSkinProp.java b/forge-gui/src/main/java/forge/assets/FSkinProp.java index 5468c1e2914..38edff0ea32 100644 --- a/forge-gui/src/main/java/forge/assets/FSkinProp.java +++ b/forge-gui/src/main/java/forge/assets/FSkinProp.java @@ -230,6 +230,15 @@ public enum FSkinProp { ICO_QUEST_BIG_SWORD (new int[] {320, 1360, 160, 160}, PropType.ICON), ICO_QUEST_BIG_BAG (new int[] {480, 1360, 160, 160}, PropType.ICON), + //menu icon + ICO_MENU_GALAXY (new int[] {0, 1520, 80, 80}, PropType.ICON), + ICO_MENU_STATS (new int[] {80, 1520, 80, 80}, PropType.ICON), + ICO_MENU_PUZZLE (new int[] {160, 1520, 80, 80}, PropType.ICON), + ICO_MENU_GAUNTLET (new int[] {240, 1520, 80, 80}, PropType.ICON), + ICO_MENU_SEALED (new int[] {320, 1520, 80, 80}, PropType.ICON), + ICO_MENU_DRAFT (new int[] {400, 1520, 80, 80}, PropType.ICON), + ICO_MENU_CONSTRUCTED (new int[] {480, 1520, 80, 80}, PropType.ICON), + //interface icons ICO_QUESTION (new int[] {560, 800, 32, 32}, PropType.ICON), ICO_INFORMATION (new int[] {592, 800, 32, 32}, PropType.ICON), 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