add mobile updater, update gdx natives

This commit is contained in:
Anthony Calosa
2024-10-25 11:41:06 +08:00
parent a0c865b4b3
commit 8c085bbd33
20 changed files with 1628 additions and 174 deletions

View File

@@ -1626,7 +1626,7 @@ public class ComputerUtil {
for (final Card c : all) {
// check if card is at least available to be played
// further improvements might consider if AI has options to steal the spell by making it playable first
if (c.getZone().getPlayer() != null && c.getZone().getPlayer() != defender && c.mayPlay(defender).isEmpty()) {
if (c.getZone() != null && c.getZone().getPlayer() != null && c.getZone().getPlayer() != defender && c.mayPlay(defender).isEmpty()) {
continue;
}
for (final SpellAbility sa : c.getSpellAbilities()) {

View File

@@ -26,6 +26,9 @@ public class CreatureEvaluator implements Function<Card, Integer> {
return evaluateCreature(c, true, true);
}
public int evaluateCreature(final Card c, final boolean considerPT, final boolean considerCMC) {
//Card shouldn't be null and AI shouldn't crash since this is just score
if (c == null)
return 0;
int value = 80;
if (!c.isToken()) {
value += addValue(20, "non-token"); // tokens should be worth less than actual cards

View File

@@ -34,6 +34,11 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.apptasticsoftware</groupId>
<artifactId>rssreader</artifactId>
<version>3.6.0</version>
</dependency>
</dependencies>
</project>

View File

@@ -12,11 +12,9 @@ import java.util.Date;
import java.util.List;
public class RSSReader {
public static String getCommitLog(Date buildDateOriginal, SimpleDateFormat dateFormat, Date max) {
public static String getCommitLog(Date buildDateOriginal, Date maxDate) {
String message = "";
SimpleDateFormat simpleDate = dateFormat;
if (simpleDate == null)
simpleDate = new SimpleDateFormat("E, MMM dd, yyyy - hh:mm:ss a");
SimpleDateFormat simpleDate = TextUtil.getSimpleDate();
try {
RssReader reader = new RssReader();
URL url = new URL("https://github.com/Card-Forge/forge/commits/master.atom");
@@ -36,7 +34,7 @@ public class RSSReader {
Date feedDate = Date.from(zonedDateTime.toInstant());
if (buildDateOriginal != null && feedDate.before(buildDateOriginal))
continue;
if (max != null && feedDate.after(max))
if (maxDate != null && feedDate.after(maxDate))
continue;
logs.append(simpleDate.format(feedDate)).append(" | ").append(StringEscapeUtils.unescapeXml(title).replace("\n", "").replace(" ", "")).append("\n\n");
if (c >= 15)

View File

@@ -29,6 +29,7 @@ import forge.item.PaperCard;
*/
public class TextUtil {
private static final StringBuilder changes = new StringBuilder();
private static SimpleDateFormat simpleDate;
static ImmutableSortedMap<Integer,String> romanMap = ImmutableSortedMap.<Integer,String>naturalOrder()
.put(1000, "M").put(900, "CM")
@@ -392,6 +393,11 @@ public class TextUtil {
}
return out.toString();
}
public static SimpleDateFormat getSimpleDate() {
if (simpleDate == null)
simpleDate = new SimpleDateFormat("E, MMM dd, yyyy - hh:mm:ss a");
return simpleDate;
}
//format changelog
public static String getFormattedChangelog(File changelog, String defaultLog) {
if (!changelog.exists())
@@ -400,30 +406,9 @@ public class TextUtil {
try {
Calendar calendar = Calendar.getInstance();
SimpleDateFormat original = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
SimpleDateFormat formatted = new SimpleDateFormat("E, MMM dd, yyyy - hh:mm:ss a");
SimpleDateFormat formatted = getSimpleDate();
String offset = " GMT " + OffsetDateTime.now().getOffset();
List<String> toformat = FileUtil.readAllLines(changelog, false);
/*for (String line : toformat) {
if (line.isEmpty() || line.startsWith("#") || line.length() < 4)
continue;
if (line.startsWith("[")) {
String datestring = line.substring(line.lastIndexOf(" *")+1).replace("*", "");
try {
original.setTimeZone(TimeZone.getTimeZone("UTC"));
Date toDate = original.parse(datestring);
calendar.setTime(toDate);
formatted.setTimeZone(TimeZone.getDefault());
changes += "\n(" + formatted.format(calendar.getTime()) + offset + ")\n\n";
} catch (Exception e2) {
changes += "\n(" + datestring + ")\n\n";
}
} else {
if (line.startsWith(" * "))
changes += "\n"+ StringEscapeUtils.unescapeXml(line);
else
changes += StringEscapeUtils.unescapeXml(line);
}
}*/
boolean skip = false;
int count = 0;
for (String line : toformat) {

View File

@@ -0,0 +1,113 @@
package forge.app;
import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
public class AtomReader {
private static final String ns = null;
public List<Entry> parse(InputStream in) throws Exception {
try {
XmlPullParser parser = Xml.newPullParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
parser.setInput(in, "UTF-8");
parser.nextTag();
return readFeed(parser);
} finally {
in.close();
}
}
private List<Entry> readFeed(XmlPullParser parser) throws Exception {
List<Entry> entries = new ArrayList<>();
parser.require(XmlPullParser.START_TAG, ns, "feed");
while (parser.next() != XmlPullParser.END_TAG) {
if (parser.getEventType() != XmlPullParser.START_TAG) {
continue;
}
String name = parser.getName();
// Starts by looking for the entry tag.
if (name.equals("entry")) {
entries.add(readEntry(parser));
} else {
skip(parser);
}
}
return entries;
}
private void skip(XmlPullParser parser) throws Exception {
if (parser.getEventType() != XmlPullParser.START_TAG) {
throw new IllegalStateException();
}
int depth = 1;
while (depth != 0) {
switch (parser.next()) {
case XmlPullParser.END_TAG:
depth--;
break;
case XmlPullParser.START_TAG:
depth++;
break;
}
}
}
public static class Entry {
public final String title;
public final String updated;
private Entry(String title, String updated) {
this.title = title;
this.updated = updated;
}
}
private Entry readEntry(XmlPullParser parser) throws Exception {
parser.require(XmlPullParser.START_TAG, ns, "entry");
String title = null;
String updated = null;
while (parser.next() != XmlPullParser.END_TAG) {
if (parser.getEventType() != XmlPullParser.START_TAG) {
continue;
}
String name = parser.getName();
if (name.equals("title")) {
title = readTitle(parser);
} else if (name.equals("updated")) {
updated = readUpdated(parser);
} else {
skip(parser);
}
}
return new Entry(title, updated);
}
private String readTitle(XmlPullParser parser) throws Exception {
parser.require(XmlPullParser.START_TAG, ns, "title");
String title = readText(parser);
parser.require(XmlPullParser.END_TAG, ns, "title");
return title;
}
private String readUpdated(XmlPullParser parser) throws Exception {
parser.require(XmlPullParser.START_TAG, ns, "updated");
String updated = readText(parser);
parser.require(XmlPullParser.END_TAG, ns, "updated");
return updated;
}
private String readText(XmlPullParser parser) throws Exception {
String result = "";
if (parser.next() == XmlPullParser.TEXT) {
result = parser.getText();
parser.nextTag();
}
return result;
}
}

View File

@@ -0,0 +1,49 @@
package forge.app;
import forge.util.TextUtil;
import org.apache.commons.text.StringEscapeUtils;
import java.io.InputStream;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
public class GitLogs {
public String getLatest(Date buildDateOriginal, Date maxDate) {
String message = "";
try {
URL url = new URL("https://github.com/Card-Forge/forge/commits/master.atom");
InputStream inputStream = url.openStream();
List<AtomReader.Entry> entries = new AtomReader().parse(inputStream);
StringBuilder logs = new StringBuilder();
SimpleDateFormat simpleDate = TextUtil.getSimpleDate();
SimpleDateFormat atomDate = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss");
int c = 0;
for (AtomReader.Entry entry : entries) {
if (entry.title == null)
continue;
String title = TextUtil.stripNonValidXMLCharacters(entry.title);
if (title.contains("Merge"))
continue;
if (entry.updated == null)
continue;
Date feedDate = atomDate.parse(entry.updated);
if (buildDateOriginal != null && feedDate.before(buildDateOriginal))
continue;
if (maxDate != null && feedDate.after(maxDate))
continue;
logs.append(simpleDate.format(feedDate)).append(" | ").append(StringEscapeUtils.unescapeXml(title).replace("\n", "").replace(" ", "")).append("\n\n");
if (c >= 15)
break;
c++;
}
if (logs.length() > 0)
message += ("\n\nLatest Changes:\n\n" + logs);
inputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
return message;
}
}

View File

@@ -71,6 +71,7 @@ import java.io.InputStreamReader;
import java.io.OutputStream;
import java.text.Normalizer;
import java.util.ArrayList;
import java.util.Date;
public class Main extends ForgeAndroidApplication {
private AndroidAdapter Gadapter;
@@ -633,6 +634,11 @@ public class Main extends ForgeAndroidApplication {
return versionString;
}
@Override
public String getLatestChanges(Date buildDateOriginal, Date maxDate) {
return new GitLogs().getLatest(buildDateOriginal, maxDate);
}
@Override
public boolean openFile(String filename) {
try {

View File

@@ -436,11 +436,6 @@
<artifactId>imageio-jpeg</artifactId>
<version>3.12.0</version>
</dependency>
<dependency>
<groupId>com.apptasticsoftware</groupId>
<artifactId>rssreader</artifactId>
<version>3.6.0</version>
</dependency>
</dependencies>
<profiles>

View File

@@ -30,7 +30,7 @@ public enum CSubmenuDownloaders implements ICDoc {
SINGLETON_INSTANCE;
private final UiCommand cmdLicensing = VSubmenuDownloaders.SINGLETON_INSTANCE::showLicensing;
private final UiCommand cmdCheckForUpdates = () -> new AutoUpdater(false).attemptToUpdate(CompletableFuture.supplyAsync(() -> RSSReader.getCommitLog(null, null, null)));
private final UiCommand cmdCheckForUpdates = () -> new AutoUpdater(false).attemptToUpdate(CompletableFuture.supplyAsync(() -> RSSReader.getCommitLog(null, null)));
private final UiCommand cmdPicDownload = () -> new GuiDownloader(new GuiDownloadPicturesLQ()).show();
private final UiCommand cmdPicDownloadHQ = () -> new GuiDownloader(new GuiDownloadPicturesHQ()).show();

View File

@@ -420,7 +420,7 @@ public abstract class FTitleBarBase extends SkinnedMenuBar {
}
}
public class UpdaterButton extends TitleBarButton {
final int MARQUEE_SPEED_DIV = 25;
final int MARQUEE_SPEED_DIV = 15;
final int REPAINT_WITHIN_MS = 25;
final String displayText = FControl.instance.compareVersion(BuildInfo.getVersionString());
private UpdaterButton() {
@@ -431,7 +431,7 @@ public abstract class FTitleBarBase extends SkinnedMenuBar {
@Override
protected void onClick() {
try {
new AutoUpdater(false).attemptToUpdate(CompletableFuture.supplyAsync(() -> RSSReader.getCommitLog(null, null, null)));
new AutoUpdater(false).attemptToUpdate(CompletableFuture.supplyAsync(() -> RSSReader.getCommitLog(null, null)));
} catch (Exception e) {
e.printStackTrace();
}

View File

@@ -4,6 +4,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Date;
import org.apache.commons.lang3.tuple.Pair;
import org.robovm.apple.foundation.NSAutoreleasePool;
@@ -78,6 +79,11 @@ public class Main extends IOSApplication.Delegate {
return "0.0";
}
@Override
public String getLatestChanges(Date buildDateOriginal, Date maxDate) {
return "";
}
@Override
public boolean openFile(final String filename) {
return new IOSFiles().local(filename).exists();

View File

@@ -9,8 +9,6 @@ import com.badlogic.gdx.graphics.glutils.HdpiMode;
import com.badlogic.gdx.utils.SharedLibraryLoader;
import forge.Forge;
import forge.adventure.util.Config;
import forge.assets.AssetsDownloader;
import forge.util.FileUtil;
import org.lwjgl.system.Configuration;
import java.nio.file.Files;
@@ -28,16 +26,9 @@ public class GameLauncher {
if (!Files.exists(Paths.get(desktopModeAssetsDir + "res")))
desktopModeAssetsDir = "../forge-gui/";//try IDE run
// Assets directory used when the game fully emulates smartphone/tablet mode (desktopMode = false), useful when debugging from IDE
String assetsDir;
if (!AssetsDownloader.SHARE_DESKTOP_ASSETS) {
assetsDir = "testAssets/";
FileUtil.ensureDirectoryExists(assetsDir);
} else {
assetsDir = "./";
String assetsDir = "./";
if (!Files.exists(Paths.get(assetsDir + "res")))
assetsDir = "../forge-gui/";
}
// Place the file "switch_orientation.ini" to your assets folder to make the game switch to landscape orientation (unless desktopMode = true)
String switchOrientationFile = assetsDir + "switch_orientation.ini";

View File

@@ -2,10 +2,7 @@ package forge.app;
import com.badlogic.gdx.Gdx;
import forge.interfaces.IDeviceAdapter;
import forge.util.BuildInfo;
import forge.util.FileUtil;
import forge.util.OperatingSystem;
import forge.util.RestartUtil;
import forge.util.*;
import org.apache.commons.lang3.tuple.Pair;
import javax.imageio.ImageIO;
@@ -17,6 +14,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.Optional;
public class Main {
@@ -53,10 +51,23 @@ public class Main {
return versionString;
}
@Override
public String getLatestChanges(Date buildDateOriginal, Date max) {
return RSSReader.getCommitLog(buildDateOriginal, max);
}
@Override
public boolean openFile(String filename) {
try {
Desktop.getDesktop().open(new File(filename));
File installer = new File(filename);
if (installer.exists()) {
if (filename.endsWith(".jar")) {
installer.setExecutable(true, false);
Desktop.getDesktop().open(installer);
} else {
Desktop.getDesktop().open(installer.getParentFile());
}
}
return true;
} catch (IOException e) {
e.printStackTrace();

Binary file not shown.

View File

@@ -76,7 +76,7 @@ public class Forge implements ApplicationListener {
protected static ClosingScreen closingScreen;
protected static TransitionScreen transitionScreen;
public static KeyInputAdapter keyInputAdapter;
private static boolean exited;
private static boolean exited, initialized;
public boolean needsUpdate = false;
public static boolean advStartup = false;
public static boolean safeToClose = true;
@@ -199,7 +199,8 @@ public class Forge implements ApplicationListener {
} else {
skinName = "default"; //use default skin if preferences file doesn't exist yet
}
FSkin.loadLight(skinName, splashScreen);
if (!initialized)
FSkin.loadLight(skinName, getSplashScreen());
textureFiltering = getForgePreferences().getPrefBoolean(FPref.UI_LIBGDX_TEXTURE_FILTERING);
showFPS = getForgePreferences().getPrefBoolean(FPref.UI_SHOW_FPS);
@@ -223,40 +224,33 @@ public class Forge implements ApplicationListener {
if (totalDeviceRAM > 5000) //devices with more than 10GB RAM will have 600 Cache size, 400 Cache size for morethan 5GB RAM
cacheSize = totalDeviceRAM > 10000 ? 600 : 400;
}
//init cache
ImageCache.initCache(cacheSize);
//load model on background thread (using progress bar to report progress)
FThreads.invokeInBackgroundThread(() -> {
//see if app or assets need updating
AssetsDownloader.checkForUpdates(splashScreen);
if (exited) {
return;
} //don't continue if user chose to exit or couldn't download required assets
if (!initialized) {
initialized = true;
Runnable runnable = () -> {
safeToClose = false;
ImageKeys.setIsLibGDXPort(GuiBase.getInterface().isLibgdxPort());
FModel.initialize(splashScreen.getProgressBar(), null);
FModel.initialize(getSplashScreen().getProgressBar(), null);
splashScreen.getProgressBar().setDescription(getLocalizer().getMessage("lblLoadingFonts"));
getSplashScreen().getProgressBar().setDescription(getLocalizer().getMessage("lblLoadingFonts"));
FSkinFont.preloadAll(locale);
splashScreen.getProgressBar().setDescription(getLocalizer().getMessage("lblLoadingCardTranslations"));
getSplashScreen().getProgressBar().setDescription(getLocalizer().getMessage("lblLoadingCardTranslations"));
CardTranslation.preloadTranslation(locale, ForgeConstants.LANG_DIR);
splashScreen.getProgressBar().setDescription(getLocalizer().getMessage("lblFinishingStartup"));
getSplashScreen().getProgressBar().setDescription(getLocalizer().getMessage("lblFinishingStartup"));
//add reminder to preload
if (enablePreloadExtendedArt) {
if (autoCache)
splashScreen.getProgressBar().setDescription(getLocalizer().getMessage("lblPreloadExtendedArt") + "\nDetected RAM: " + totalDeviceRAM + "MB. Cache size: " + cacheSize);
getSplashScreen().getProgressBar().setDescription(getLocalizer().getMessage("lblPreloadExtendedArt") + "\nDetected RAM: " + totalDeviceRAM + "MB. Cache size: " + cacheSize);
else
splashScreen.getProgressBar().setDescription(getLocalizer().getMessage("lblPreloadExtendedArt"));
getSplashScreen().getProgressBar().setDescription(getLocalizer().getMessage("lblPreloadExtendedArt"));
} else {
if (autoCache)
splashScreen.getProgressBar().setDescription(getLocalizer().getMessage("lblFinishingStartup") + "\nDetected RAM: " + totalDeviceRAM + "MB. Cache size: " + cacheSize);
getSplashScreen().getProgressBar().setDescription(getLocalizer().getMessage("lblFinishingStartup") + "\nDetected RAM: " + totalDeviceRAM + "MB. Cache size: " + cacheSize);
else
splashScreen.getProgressBar().setDescription(getLocalizer().getMessage("lblFinishingStartup"));
getSplashScreen().getProgressBar().setDescription(getLocalizer().getMessage("lblFinishingStartup"));
}
Gdx.app.postRunnable(() -> {
@@ -265,7 +259,10 @@ public class Forge implements ApplicationListener {
* get error: No OpenGL context found in the current thread. */
preloadExtendedArt();
});
});
};
//see if app or assets need updating
FThreads.invokeInBackgroundThread(() -> AssetsDownloader.checkForUpdates(exited, runnable));
}
}
public static boolean hasGamepad() {
//Classic Mode Various Screen GUI are not yet supported, needs control mapping for each screens
@@ -282,6 +279,11 @@ public class Forge implements ApplicationListener {
public static Graphics getGraphics() {
return graphics;
}
public static SplashScreen getSplashScreen() {
if (splashScreen == null)
splashScreen = new SplashScreen();
return splashScreen;
}
public static Scene getCurrentScene() {
return currentScene;
@@ -447,10 +449,10 @@ public class Forge implements ApplicationListener {
String path = "skin/cursor" + name + ".png";
Pixmap pm = new Pixmap(Config.instance().getFile(path));
if (name == "0") {
if ("0".equals(name)) {
cursorA0 = Gdx.graphics.newCursor(pm, 0, 0);
setGdxCursor(cursorA0);
} else if (name == "1") {
} else if ("1".equals(name)) {
cursorA1 = Gdx.graphics.newCursor(pm, 0, 0);
setGdxCursor(cursorA1);
} else {
@@ -461,20 +463,20 @@ public class Forge implements ApplicationListener {
pm.dispose();
return;
}
if (!FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_ENABLE_MAGNIFIER) && name != "0")
if (!FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_ENABLE_MAGNIFIER) && !"0".equals(name))
return; //don't change if it's disabled
if (currentScreen != null && !currentScreen.toString().toLowerCase().contains("match") && name != "0")
if (currentScreen != null && !currentScreen.toString().toLowerCase().contains("match") && !"0".equals(name))
return; // cursor indicator should be during matches
if (textureRegion == null) {
return;
}
if (cursor0 != null && name == "0") {
if (cursor0 != null && "0".equals(name)) {
setGdxCursor(cursor0);
return;
} else if (cursor1 != null && name == "1") {
} else if (cursor1 != null && "1".equals(name)) {
setGdxCursor(cursor1);
return;
} else if (cursor2 != null && name == "2") {
} else if (cursor2 != null && "2".equals(name)) {
setGdxCursor(cursor2);
return;
}
@@ -496,10 +498,10 @@ public class Forge implements ApplicationListener {
textureRegion.getRegionWidth(), // The width of the area from the other Pixmap in pixels
textureRegion.getRegionHeight() // The height of the area from the other Pixmap in pixels
);
if (name == "0") {
if ("0".equals(name)) {
cursor0 = Gdx.graphics.newCursor(pm, 0, 0);
setGdxCursor(cursor0);
} else if (name == "1") {
} else if ("1".equals(name)) {
cursor1 = Gdx.graphics.newCursor(pm, 0, 0);
setGdxCursor(cursor1);
} else {
@@ -829,8 +831,10 @@ public class Forge implements ApplicationListener {
endKeyInput(); //end key input before switching screens
ForgeAnimation.endAll(); //end all active animations before switching screens
currentScreen = screen0;
if (currentScreen != null) {
currentScreen.setSize(screenWidth, screenHeight);
currentScreen.onActivate();
}
} catch (Exception ex) {
graphics.end();
//check if sentry is enabled, if not it will call the gui interface but here we end the graphics so we only send it via sentry..

View File

@@ -1,15 +1,18 @@
package forge.assets;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import com.badlogic.gdx.files.FileHandle;
import forge.gui.GuiBase;
import forge.util.TextUtil;
import org.apache.commons.lang3.StringUtils;
import com.badlogic.gdx.Application.ApplicationType;
import com.badlogic.gdx.Gdx;
import com.google.common.collect.ImmutableList;
@@ -18,26 +21,27 @@ import forge.gui.FThreads;
import forge.gui.download.GuiDownloadZipService;
import forge.gui.util.SOptionPane;
import forge.localinstance.properties.ForgeConstants;
import forge.screens.SplashScreen;
import forge.util.FileUtil;
public class AssetsDownloader {
public static final boolean SHARE_DESKTOP_ASSETS = true; //change to false to test downloading separate assets for desktop version
private final static ImmutableList<String> downloadIgnoreExit = ImmutableList.of("Download", "Ignore", "Exit");
private final static ImmutableList<String> downloadExit = ImmutableList.of("Download", "Exit");
//if not sharing desktop assets, check whether assets are up to date
public static void checkForUpdates(final SplashScreen splashScreen) {
if (Gdx.app.getType() == ApplicationType.Desktop && SHARE_DESKTOP_ASSETS) { return; }
public static void checkForUpdates(boolean exited, Runnable runnable) {
if (exited)
return;
final String packageSize = GuiBase.isAndroid() ? "160MB" : "270MB";
final String apkSize = "12MB";
final String versionString = Forge.getDeviceAdapter().getVersionString();
final boolean isSnapshots = versionString.contains("SNAPSHOT");
final String snapsURL = "https://downloads.cardforge.org/dailysnapshots/";
final String releaseURL = "https://releases.cardforge.org/forge/forge-gui-android/";
final String versionText = isSnapshots ? snapsURL + "version.txt" : releaseURL + "version.txt";
splashScreen.getProgressBar().setDescription("Checking for updates...");
FileHandle assetsDir = Gdx.files.absolute(ForgeConstants.ASSETS_DIR);
FileHandle resDir = Gdx.files.absolute(ForgeConstants.RES_DIR);
boolean mandatory = false;
Forge.getSplashScreen().getProgressBar().setDescription("Checking for updates...");
String message;
boolean connectedToInternet = Forge.getDeviceAdapter().isConnectedToInternet();
@@ -45,40 +49,96 @@ public class AssetsDownloader {
try {
URL versionUrl = new URL(versionText);
String version = FileUtil.readFileToString(versionUrl);
String filename = "forge-android-" + version + "-signed-aligned.apk";
String apkURL = isSnapshots ? snapsURL + filename : releaseURL + version + "/" + filename;
if (!StringUtils.isEmpty(version) && !versionString.equals(version)) {
splashScreen.prepareForDialogs();
String filename = "";
String installerURL = "";
if (GuiBase.isAndroid()) {
filename = "forge-android-" + version + "-signed-aligned.apk";
installerURL = isSnapshots ? snapsURL + filename : releaseURL + version + "/" + filename;
} else {
filename = isSnapshots ? "forge-installer-" + version + ".jar" : "forge-gui-desktop-" + version + ".tar.bz2";
String releaseBZ2URL = "https://github.com/Card-Forge/forge/releases/download/forge-" + version + "/";
String snapsBZ2URL = "https://downloads.cardforge.org/dailysnapshots/";
installerURL = isSnapshots ? snapsBZ2URL : releaseBZ2URL;
}
//TODO build version
/*String buildver = "";
SimpleDateFormat DateFor = TextUtil.getSimpleDate();
Calendar calendar = Calendar.getInstance();
Date buildDateOriginal = null;
try {
FileHandle build = Gdx.files.classpath("build.txt");
if (build.exists()) {
SimpleDateFormat original = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
original.setTimeZone(TimeZone.getTimeZone("UTC"));
Date buildDate = original.parse(build.readString());
buildDateOriginal = original.parse(build.readString());
calendar.setTime(buildDate);
DateFor.setTimeZone(TimeZone.getDefault());
buildver = "\nForge Build: " + DateFor.format(calendar.getTime());
}
} catch (Exception e) {
e.printStackTrace();
}*/
if (!StringUtils.isEmpty(version) && !versionString.equals(version) && !versionString.equalsIgnoreCase("GIT")) {
Forge.getSplashScreen().prepareForDialogs();
message = "A new version of Forge is available (" + version + ").\n" +
"You are currently on an older version (" + versionString + ").\n\n" +
"Would you like to update to the new version now?";
if (!Forge.getDeviceAdapter().isConnectedToWifi()) {
message += " If so, you may want to connect to wifi first. The download is around 12MB.";
message += " If so, you may want to connect to wifi first. The download is around " + (GuiBase.isAndroid() ? apkSize : packageSize) + ".";
}
if (!GuiBase.isAndroid()) {
message += Forge.getDeviceAdapter().getLatestChanges(null, null);
}
if (SOptionPane.showConfirmDialog(message, "New Version Available", "Update Now", "Update Later", true, true)) {
String apkFile = new GuiDownloadZipService("", "update", apkURL,
Forge.getDeviceAdapter().getDownloadsDir(), null, splashScreen.getProgressBar()).download(filename);
if (apkFile != null) {
Forge.getDeviceAdapter().openFile(apkFile);
String installer = new GuiDownloadZipService("", "update", installerURL,
Forge.getDeviceAdapter().getDownloadsDir(), null, Forge.getSplashScreen().getProgressBar()).download(filename);
if (installer != null) {
Forge.getDeviceAdapter().openFile(installer);
Forge.isMobileAdventureMode = Forge.advStartup;
Forge.exitAnimation(false);
return;
}
SOptionPane.showOptionDialog("Could not download update. " +
"Press OK to proceed without update.", "Update Failed", null, ImmutableList.of("Ok"));
switch (SOptionPane.showOptionDialog("Could not download update. " +
"Press OK to proceed without update.", "Update Failed", null, ImmutableList.of("Ok"))) {
default:
if (!GuiBase.isAndroid()) {
run(runnable);
return;
}
break;
}
}
} else {
if (!GuiBase.isAndroid())
run(runnable);
}
}
catch (Exception e) {
e.printStackTrace();
if (!GuiBase.isAndroid()) {
run(runnable);
return;
}
}
} else {
if (!GuiBase.isAndroid()) {
run(runnable);
return;
}
}
// non android don't have seperate package to check
if (!GuiBase.isAndroid()) {
run(runnable);
return;
}
// Android assets fallback
String build = "";
String log = "";
//see if assets need updating
if (GuiBase.isAndroid()) {
FileHandle resDir = Gdx.files.absolute(ForgeConstants.RES_DIR);
FileHandle assetsDir = Gdx.files.absolute(ForgeConstants.ASSETS_DIR);
FileHandle advBG = Gdx.files.absolute(ForgeConstants.DEFAULT_SKINS_DIR).child(ForgeConstants.ADV_TEXTURE_BG_FILE);
if (!advBG.exists()) {
FileHandle deleteVersion = assetsDir.child("version.txt");
@@ -88,25 +148,57 @@ public class AssetsDownloader {
if (deleteBuild.exists())
deleteBuild.delete();
}
}
File versionFile = new File(ForgeConstants.ASSETS_DIR + "version.txt");
FileHandle versionFile = assetsDir.child("version.txt");
if (!versionFile.exists()) {
try {
versionFile.createNewFile();
versionFile.file().createNewFile();
}
catch (IOException e) {
e.printStackTrace();
Forge.isMobileAdventureMode = Forge.advStartup;
Forge.exitAnimation(false); //can't continue if this fails
return;
}
}
else if (versionString.equals(FileUtil.readFileToString(versionFile)) && FSkin.getSkinDir() != null) {
} else if (versionString.equals(FileUtil.readFileToString(versionFile.file())) && FSkin.getSkinDir() != null) {
run(runnable);
return; //if version matches what had been previously saved and FSkin isn't requesting assets download, no need to download assets
}
splashScreen.prepareForDialogs(); //ensure colors set up for showing message dialogs
FileHandle f = Gdx.files.classpath("build.txt");
FileHandle t = resDir.child("build.txt");
if (f.exists() && t.exists()) {
String buildString = f.readString();
String target = t.readString();
try {
Date buildDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(buildString);
Date targetDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(target);
// if res folder has same build date then continue loading assets
if (buildDate.equals(targetDate) && versionString.equals(FileUtil.readFileToString(versionFile.file()))) {
run(runnable);
return;
}
mandatory = true;
//format to local date
SimpleDateFormat original = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
original.setTimeZone(TimeZone.getTimeZone("UTC"));
targetDate = original.parse(target);
Calendar calendar = Calendar.getInstance();
calendar.setTime(targetDate);
SimpleDateFormat simpleDate = TextUtil.getSimpleDate();
simpleDate.setTimeZone(TimeZone.getDefault());
build += "Installed resources date: " + simpleDate.format(calendar.getTime()) + "\n\n";
log = Forge.getDeviceAdapter().getLatestChanges(null, null);
} catch (Exception e) {
e.printStackTrace();
}
}
boolean canIgnoreDownload = FSkin.getAllSkins() != null; //don't allow ignoring download if resource files haven't been previously loaded
Forge.getSplashScreen().prepareForDialogs(); //ensure colors set up for showing message dialogs
boolean canIgnoreDownload = resDir.exists() && FSkin.getAllSkins() != null && !FileUtil.readFileToString(versionFile.file()).isEmpty(); //don't allow ignoring download if resource files haven't been previously loaded
if (mandatory && connectedToInternet)
canIgnoreDownload = false;
if (!connectedToInternet) {
message = "Updated resource files cannot be downloaded due to lack of internet connection.\n\n";
@@ -119,6 +211,7 @@ public class AssetsDownloader {
switch (SOptionPane.showOptionDialog(message, "No Internet Connection", null, ImmutableList.of("Ok"))) {
default: {
if (!canIgnoreDownload) {
Forge.isMobileAdventureMode = Forge.advStartup;
Forge.exitAnimation(false); //exit if can't ignore download
}
}
@@ -128,7 +221,7 @@ public class AssetsDownloader {
//prompt user whether they wish to download the updated resource files
message = "There are updated resource files to download. " +
"This download is around 50MB, ";
"This download is around " + packageSize + ", ";
if (Forge.getDeviceAdapter().isConnectedToWifi()) {
message += "which shouldn't take long if your wifi connection is good.";
}
@@ -145,13 +238,18 @@ public class AssetsDownloader {
options = downloadExit;
}
switch (SOptionPane.showOptionDialog(message, "", null, options)) {
switch (SOptionPane.showOptionDialog(message + build + log, "", null, options)) {
case 1:
if (!canIgnoreDownload) {
Forge.isMobileAdventureMode = Forge.advStartup;
Forge.exitAnimation(false); //exit if can't ignore download
}
return;
} else {
run(runnable);
return;
}
case 2:
Forge.isMobileAdventureMode = Forge.advStartup;
Forge.exitAnimation(false);
return;
}
@@ -160,7 +258,7 @@ public class AssetsDownloader {
boolean allowDeletion = Forge.androidVersion < 30 || GuiBase.isUsingAppDirectory();
String assetURL = isSnapshots ? snapsURL + "assets.zip" : releaseURL + versionString + "/" + "assets.zip";
new GuiDownloadZipService("", "resource files", assetURL,
ForgeConstants.ASSETS_DIR, ForgeConstants.RES_DIR, splashScreen.getProgressBar(), allowDeletion).downloadAndUnzip();
ForgeConstants.ASSETS_DIR, ForgeConstants.RES_DIR, Forge.getSplashScreen().getProgressBar(), allowDeletion).downloadAndUnzip();
if (allowDeletion)
FSkinFont.deleteCachedFiles(); //delete cached font files in case any skin's .ttf file changed
@@ -168,18 +266,37 @@ public class AssetsDownloader {
//reload light version of skin after assets updated
FThreads.invokeInEdtAndWait(() -> {
FSkinFont.updateAll(); //update all fonts used by splash screen
FSkin.loadLight(FSkin.getName(), splashScreen);
FSkin.loadLight(FSkin.getName(), Forge.getSplashScreen());
});
//save version string to file once assets finish downloading
//so they don't need to be re-downloaded until you upgrade again
FileUtil.writeFile(versionFile, versionString);
//add restart after assets update
String msg = allowDeletion ? "Resource update finished..." : "Forge misses some files for deletion.\nIf you encounter issues, try deleting the Forge/res folder and/or deleting Forge/cache/fonts folder and try to download and update the assets.";
switch (SOptionPane.showOptionDialog(msg, "", null, ImmutableList.of("Restart"))) {
default:
if (connectedToInternet) {
if (versionFile.exists())
FileUtil.writeFile(versionFile.file(), versionString);
}
//final check if temp.zip exists then extraction is not complete...
FileHandle check = assetsDir.child("temp.zip");
if (check.exists()) {
if (versionFile.exists())
versionFile.delete();
check.delete();
}
// auto restart after update
Forge.isMobileAdventureMode = Forge.advStartup;
Forge.exitAnimation(true);
}
private static void run(Runnable toRun) {
if (toRun != null) {
if (!GuiBase.isAndroid()) {
Forge.getSplashScreen().getProgressBar().setDescription("Loading game resources...");
}
FThreads.invokeInBackgroundThread(toRun);
return;
}
if (!GuiBase.isAndroid()) {
Forge.isMobileAdventureMode = Forge.advStartup;
Forge.exitAnimation(false);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -88,7 +88,7 @@ public class AutoUpdater {
return false;
} else if (updateChannel.equals("none")) {
String message = localizer.getMessage("lblYouHaventSetUpdateChannel");
List<String> options = ImmutableList.of(localizer.getMessage("lblCancel"), localizer.getMessage("lblRelease"), localizer.getMessage("lblSnapshot"));
List<String> options = ImmutableList.of(localizer.getMessageorUseDefault("lblCancel", "Cancel"), localizer.getMessageorUseDefault("lblRelease", "Release"), localizer.getMessageorUseDefault("lblSnapshot", "Snapshot"));
int option = SOptionPane.showOptionDialog(message, localizer.getMessage("lblManualCheck"), null, options, 0);
if (option < 1) {
return false;
@@ -97,14 +97,14 @@ public class AutoUpdater {
}
if (buildVersion.contains("SNAPSHOT")) {
if (!updateChannel.equalsIgnoreCase(localizer.getMessage("lblSnapshot"))) {
if (!updateChannel.equalsIgnoreCase(localizer.getMessageorUseDefault("lblSnapshot", "Snapshot"))) {
System.out.println("Snapshot build versions must use snapshot update channel to work");
return false;
}
versionUrlString = SNAPSHOT_VERSION_INDEX + "version.txt";
} else {
if (!updateChannel.equalsIgnoreCase(localizer.getMessage("lblRelease"))) {
if (!updateChannel.equalsIgnoreCase(localizer.getMessageorUseDefault("lblRelease", "Release"))) {
System.out.println("Release build versions must use release update channel to work");
return false;
}
@@ -151,13 +151,13 @@ public class AutoUpdater {
}
private void retrieveVersion() throws MalformedURLException {
if (VERSION_FROM_METADATA && updateChannel.equalsIgnoreCase(localizer.getMessage("lblRelease"))) {
if (VERSION_FROM_METADATA && updateChannel.equalsIgnoreCase(localizer.getMessageorUseDefault("lblRelease", "Release"))) {
extractVersionFromMavenRelease();
} else {
URL versionUrl = new URL(versionUrlString);
version = FileUtil.readFileToString(versionUrl);
}
if (updateChannel.equalsIgnoreCase(localizer.getMessage("lblRelease"))) {
if (updateChannel.equalsIgnoreCase(localizer.getMessageorUseDefault("lblRelease", "Release"))) {
packageUrl = RELEASE_VERSION_INDEX + "forge/forge-gui-desktop/" + version + "/forge-gui-desktop-" + version + ".tar.bz2";
} else {
packageUrl = SNAPSHOT_VERSION_INDEX + "forge-installer-" + version + ".jar";

View File

@@ -6,6 +6,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Date;
public interface IDeviceAdapter {
boolean isConnectedToInternet();
@@ -13,6 +14,7 @@ public interface IDeviceAdapter {
boolean isTablet();
String getDownloadsDir();
String getVersionString();
String getLatestChanges(Date buildDateOriginal, Date maxDate);
boolean openFile(String filename);
void setLandscapeMode(boolean landscapeMode);
void preventSystemSleep(boolean preventSleep);