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 e10f1dc3d4c..2a1c4d8ab59 100644 --- a/forge-gui-desktop/src/main/java/forge/view/Main.java +++ b/forge-gui-desktop/src/main/java/forge/view/Main.java @@ -23,8 +23,17 @@ import forge.error.ExceptionHandler; import forge.gui.GuiBase; import forge.gui.card.CardReaderExperiments; import forge.util.BuildInfo; +import forge.util.JVMOptions; import io.sentry.Sentry; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JOptionPane; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.util.ArrayList; +import java.util.List; + /** * Main class for Forge's swing application view. */ @@ -33,12 +42,45 @@ public final class Main { * Main entry point for Forge */ public static void main(final String[] args) { + String javaVersion = System.getProperty("java.version"); + checkJVMArgs(javaVersion, args); + } + static void checkJVMArgs(String javaVersion, String[] args) { + RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean(); + List arguments = runtimeMxBean.getInputArguments(); + List options = new ArrayList<>(); + JButton ok = new JButton("OK"); + options.add(ok); + JVMOptions.getStringBuilder().append("Java Version: ").append(javaVersion).append("\nArguments: \n"); + for (String a : arguments) { + if (a.startsWith("-agent") || a.startsWith("-javaagent")) + continue; + JVMOptions.getStringBuilder().append(a).append("\n"); + } + JOptionPane pane = new JOptionPane(JVMOptions.getStringBuilder(), JOptionPane.PLAIN_MESSAGE, JOptionPane.DEFAULT_OPTION, null, options.toArray()); + JDialog dlg = pane.createDialog(JOptionPane.getRootFrame(), "Error"); + ok.addActionListener(e -> { + dlg.setVisible(false); + System.exit(0); + }); + dlg.setResizable(false); + + if (!JVMOptions.checkRuntime(arguments)) { + dlg.setVisible(true); + } else { + start(args); + } + } + static void start(final String[] args) { Sentry.init(options -> { options.setEnableExternalConfiguration(true); options.setRelease(BuildInfo.getVersionString()); options.setEnvironment(System.getProperty("os.name")); options.setTag("Java Version", System.getProperty("java.version")); + options.setShutdownTimeoutMillis(5000); + if (options.getDsn() == null) + options.setDsn("https://87bc8d329e49441895502737c069067b@sentry.cardforge.org//3"); }, true); // HACK - temporary solution to "Comparison method violates it's general contract!" crash @@ -67,28 +109,27 @@ public final class Main { // command line startup here String mode = args[0].toLowerCase(); - + switch(mode) { case "sim": SimulateMatch.simulate(args); break; case "parse": - CardReaderExperiments.parseAllCards(args); + CardReaderExperiments.parseAllCards(args); break; case "server": System.out.println("Dedicated server mode.\nNot implemented."); break; - + default: System.out.println("Unknown mode.\nKnown mode is 'sim', 'parse' "); break; } - + System.exit(0); } - @SuppressWarnings("deprecation") @Override protected void finalize() throws Throwable { diff --git a/forge-gui-mobile-dev/src/forge/app/DialogWindow.java b/forge-gui-mobile-dev/src/forge/app/DialogWindow.java new file mode 100644 index 00000000000..428767dd500 --- /dev/null +++ b/forge-gui-mobile-dev/src/forge/app/DialogWindow.java @@ -0,0 +1,23 @@ +package forge.app; + +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JOptionPane; +import java.util.ArrayList; +import java.util.List; + +public class DialogWindow { + public DialogWindow(String title, String message) { + List options = new ArrayList<>(); + JButton ok = new JButton("OK"); + options.add(ok); + JOptionPane pane = new JOptionPane(message, JOptionPane.PLAIN_MESSAGE, JOptionPane.DEFAULT_OPTION, null, options.toArray()); + JDialog dlg = pane.createDialog(JOptionPane.getRootFrame(), title); + ok.addActionListener(e -> { + dlg.setVisible(false); + System.exit(0); + }); + dlg.setResizable(false); + dlg.setVisible(true); + } +} diff --git a/forge-gui-mobile-dev/src/forge/app/GameLauncher.java b/forge-gui-mobile-dev/src/forge/app/GameLauncher.java new file mode 100644 index 00000000000..5c5f38562f5 --- /dev/null +++ b/forge-gui-mobile-dev/src/forge/app/GameLauncher.java @@ -0,0 +1,70 @@ +package forge.app; + +import com.badlogic.gdx.ApplicationListener; +import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application; +import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration; +import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Clipboard; +import com.badlogic.gdx.backends.lwjgl3.Lwjgl3WindowAdapter; +import com.badlogic.gdx.graphics.glutils.HdpiMode; +import forge.Forge; +import forge.adventure.util.Config; +import forge.util.BuildInfo; +import forge.util.FileUtil; + +import java.nio.file.Files; +import java.nio.file.Paths; + +public class GameLauncher { + public GameLauncher() { + // Set this to "true" to make the mobile game port run as a full-screen desktop application + boolean desktopMode = true;//cmd.hasOption("fullscreen"); + // Set this to the location where you want the mobile game port to look for assets when working as a full-screen desktop application + // (uncomment the bottom version and comment the top one to load the res folder from the current folder the .jar is in if you would + // like to make the game load from a desktop game folder configuration). + //String desktopModeAssetsDir = "../forge-gui/"; + String desktopModeAssetsDir = "./"; + 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 = "./"; + 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"; + + Lwjgl3ApplicationConfiguration config = new Lwjgl3ApplicationConfiguration(); + config.setResizable(false); + ApplicationListener start = Forge.getApp(new Lwjgl3Clipboard(), new Main.DesktopAdapter(switchOrientationFile),//todo get totalRAM && isTabletDevice + desktopMode ? desktopModeAssetsDir : assetsDir, false, false, 0, false, 0, "", ""); + if (Config.instance().getSettingData().fullScreen) { + config.setFullscreenMode(Lwjgl3ApplicationConfiguration.getDisplayMode()); + config.setAutoIconify(true); + config.setHdpiMode(HdpiMode.Logical); + } else { + config.setWindowedMode(Config.instance().getSettingData().width, Config.instance().getSettingData().height); + } + config.setTitle("Forge - " + BuildInfo.getVersionString()); + config.setWindowListener(new Lwjgl3WindowAdapter() { + @Override + public boolean closeRequested() { + //use the device adpater to exit properly + if (Forge.safeToClose) + Forge.exit(true); + return false; + } + }); + + if (desktopMode) + config.setHdpiMode(HdpiMode.Logical); + + new Lwjgl3Application(start, config); + } +} diff --git a/forge-gui-mobile-dev/src/forge/app/Main.java b/forge-gui-mobile-dev/src/forge/app/Main.java index fbbcd511b87..547c7bcef29 100644 --- a/forge-gui-mobile-dev/src/forge/app/Main.java +++ b/forge-gui-mobile-dev/src/forge/app/Main.java @@ -1,143 +1,50 @@ package forge.app; -import com.badlogic.gdx.ApplicationListener; import com.badlogic.gdx.Gdx; -import com.badlogic.gdx.backends.lwjgl3.*; -import com.badlogic.gdx.graphics.glutils.HdpiMode; -import forge.Forge; -import forge.adventure.util.Config; -import forge.assets.AssetsDownloader; import forge.interfaces.IDeviceAdapter; -import forge.localinstance.properties.ForgePreferences; -import forge.model.FModel; import forge.util.FileUtil; +import forge.util.JVMOptions; import forge.util.OperatingSystem; import forge.util.RestartUtil; -import forge.util.Utils; -import org.apache.commons.cli.*; import org.apache.commons.lang3.tuple.Pair; import javax.imageio.ImageIO; -import java.awt.*; +import java.awt.Desktop; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.nio.file.Files; -import java.nio.file.Paths; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; import java.util.ArrayList; +import java.util.List; public class Main { + public static void main(String[] args) { - Options options = new Options(); - options.addOption("h","help", false, "Show help."); - options.addOption("f","fullscreen", false,"fullscreen mode"); - options.addOption("l","landscape", false,"landscape mode"); - options.addOption("r","resolution", true,"resolution (WxH)"); - - CommandLineParser parser = new DefaultParser(); - HelpFormatter formatter = new HelpFormatter(); - CommandLine cmd; - - try { - cmd = parser.parse(options, args); - } catch (ParseException e) { - System.out.println(e.getMessage()); - formatter.printHelp("forge-mobile-dev", options); - - System.exit(1); - return; - } - - // Set this to "true" to make the mobile game port run as a full-screen desktop application - boolean desktopMode = true;//cmd.hasOption("fullscreen"); - // Set this to the location where you want the mobile game port to look for assets when working as a full-screen desktop application - // (uncomment the bottom version and comment the top one to load the res folder from the current folder the .jar is in if you would - // like to make the game load from a desktop game folder configuration). - //String desktopModeAssetsDir = "../forge-gui/"; - String desktopModeAssetsDir = "./"; - 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= "./"; - 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"; - boolean landscapeMode = FileUtil.doesFileExist(switchOrientationFile) || cmd.hasOption("landscape"); - String[] res; - - // Width and height for standard smartphone/tablet mode (desktopMode = false) - int screenWidth = landscapeMode ? (int)(Utils.BASE_HEIGHT * 16 / 9) : (int)Utils.BASE_WIDTH; - int screenHeight = (int)Utils.BASE_HEIGHT; - if (cmd.hasOption("resolution")) { - res = cmd.getOptionValue("resolution").split("x"); - if (res.length >= 2) { - screenWidth = Integer.parseInt(res[0].trim()); - screenHeight = Integer.parseInt(res[1].trim()); - } - desktopMode=false; - } - - // Fullscreen width and height for desktop mode (desktopMode = true) - // Can be specified inside the file fullscreen_resolution.ini to override default (in the format WxH, e.g. 1920x1080) - int desktopScreenWidth = Lwjgl3ApplicationConfiguration.getDisplayMode().width; - int desktopScreenHeight = Lwjgl3ApplicationConfiguration.getDisplayMode().height; - boolean fullscreenFlag = true; - if (FileUtil.doesFileExist(desktopModeAssetsDir + "screen_resolution.ini")) { - res = FileUtil.readFileToString(desktopModeAssetsDir + "screen_resolution.ini").split("x"); - fullscreenFlag = res.length != 3 || Integer.parseInt(res[2].trim()) > 0; - if (res.length >= 2) { - desktopScreenWidth = Integer.parseInt(res[0].trim()); - desktopScreenHeight = Integer.parseInt(res[1].trim()); - } - } - - Lwjgl3ApplicationConfiguration config = new Lwjgl3ApplicationConfiguration(); - config.setResizable(false); - ForgePreferences prefs = FModel.getPreferences(); - boolean propertyConfig = prefs != null && prefs.getPrefBoolean(ForgePreferences.FPref.UI_NETPLAY_COMPAT); - ApplicationListener start = Forge.getApp(new Lwjgl3Clipboard(), new DesktopAdapter(switchOrientationFile),//todo get totalRAM && isTabletDevice - desktopMode ? desktopModeAssetsDir : assetsDir, propertyConfig, false, 0, false, 0, "", ""); - if (Config.instance().getSettingData().fullScreen) { - config.setFullscreenMode(Lwjgl3ApplicationConfiguration.getDisplayMode()); - config.setAutoIconify(true); - config.setHdpiMode(HdpiMode.Logical); - } else { - config.setWindowedMode(Config.instance().getSettingData().width, Config.instance().getSettingData().height); - } - config.setTitle("Forge"); - config.setWindowListener(new Lwjgl3WindowAdapter(){ - @Override - public boolean closeRequested() { - //use the device adpater to exit properly - if (Forge.safeToClose) - Forge.exit(true); - return false; - } - }); - - if (desktopMode) - config.setHdpiMode(HdpiMode.Logical); - - new Lwjgl3Application(start, config); + checkJVMArgs(System.getProperty("java.version")); } - private static class DesktopAdapter implements IDeviceAdapter { + static void checkJVMArgs(String javaVersion) { + RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean(); + List arguments = runtimeMxBean.getInputArguments(); + JVMOptions.getStringBuilder().append("Java Version: ").append(javaVersion).append("\nArguments: \n"); + for (String a : arguments) { + if (a.startsWith("-agent") || a.startsWith("-javaagent")) + continue; + JVMOptions.getStringBuilder().append(a).append("\n"); + } + if (!JVMOptions.checkRuntime(arguments)) { + new DialogWindow("Error", JVMOptions.getStringBuilder().toString()); + } else + new GameLauncher(); + } + + public static class DesktopAdapter implements IDeviceAdapter { private final String switchOrientationFile; - private DesktopAdapter(String switchOrientationFile0) { + DesktopAdapter(String switchOrientationFile0) { switchOrientationFile = switchOrientationFile0; } @@ -162,8 +69,7 @@ public class Main { try { Desktop.getDesktop().open(new File(filename)); return true; - } - catch (IOException e) { + } catch (IOException e) { e.printStackTrace(); } return false; @@ -193,8 +99,7 @@ public class Main { //create file to indicate that landscape mode should be used if (landscapeMode) { FileUtil.writeFile(switchOrientationFile, "1"); - } - else { + } else { FileUtil.deleteFile(switchOrientationFile); } } diff --git a/forge-gui/src/main/java/forge/util/JVMOptions.java b/forge-gui/src/main/java/forge/util/JVMOptions.java new file mode 100644 index 00000000000..684a574ac6c --- /dev/null +++ b/forge-gui/src/main/java/forge/util/JVMOptions.java @@ -0,0 +1,57 @@ +package forge.util; + +import com.google.common.collect.Sets; + +import java.util.HashSet; +import java.util.List; + +public class JVMOptions { + + static StringBuilder sb; + static HashSet mandatoryArgs = Sets.newHashSet( + "--add-opens=java.base/java.util=ALL-UNNAMED", + "--add-opens=java.base/java.lang=ALL-UNNAMED", + "--add-opens=java.base/java.lang.reflect=ALL-UNNAMED", + "--add-opens=java.base/java.text=ALL-UNNAMED", + "--add-opens=java.desktop/java.awt.font=ALL-UNNAMED", + "--add-opens=java.base/jdk.internal.misc=ALL-UNNAMED", + "--add-opens=java.base/sun.nio.ch=ALL-UNNAMED", + "--add-opens=java.base/java.nio=ALL-UNNAMED", + "--add-opens=java.base/java.math=ALL-UNNAMED", + "--add-opens=java.base/java.util.concurrent=ALL-UNNAMED", + "--add-opens=java.desktop/java.awt=ALL-UNNAMED", + "--add-opens=java.base/java.net=ALL-UNNAMED", + "--add-opens=java.desktop/javax.swing=ALL-UNNAMED", + "--add-opens=java.desktop/java.beans=ALL-UNNAMED", + "--add-opens=java.desktop/javax.swing.border=ALL-UNNAMED" + ); + public static StringBuilder getStringBuilder() { + if (sb == null) { + sb = new StringBuilder(); + sb.append("Forge failed to initialize JVM arguments.\n" + + "Use either Forge.exe | Forge.sh | Forge.cmd to run properly.\n" + + "Alternatively, add all these JVM Options in your Command line: \n" + + " --add-opens java.base/java.util=ALL-UNNAMED\n" + + " --add-opens java.base/java.lang=ALL-UNNAMED\n" + + " --add-opens java.base/java.lang.reflect=ALL-UNNAMED\n" + + " --add-opens java.base/java.text=ALL-UNNAMED\n" + + " --add-opens java.base/java.nio=ALL-UNNAMED\n" + + " --add-opens java.base/java.math=ALL-UNNAMED\n" + + " --add-opens java.base/java.util.concurrent=ALL-UNNAMED\n" + + " --add-opens java.base/java.net=ALL-UNNAMED\n" + + " --add-opens java.base/jdk.internal.misc=ALL-UNNAMED\n" + + " --add-opens java.base/sun.nio.ch=ALL-UNNAMED\n" + + " --add-opens java.desktop/java.awt=ALL-UNNAMED\n" + + " --add-opens java.desktop/java.awt.font=ALL-UNNAMED\n" + + " --add-opens java.desktop/java.beans=ALL-UNNAMED\n" + + " --add-opens java.desktop/javax.swing=ALL-UNNAMED\n" + + " --add-opens java.desktop/javax.swing.border=ALL-UNNAMED\n"); + } + return sb; + } + public static boolean checkRuntime(List arguments) { + if (arguments.isEmpty()) + return false; + return Sets.newHashSet(arguments).containsAll(mandatoryArgs); + } +}