From 7f30ceed94dadc1c6806f77434f22914b09dbfcb Mon Sep 17 00:00:00 2001 From: Lance Ewing Date: Wed, 18 Sep 2024 17:55:03 +0100 Subject: [PATCH] Implemented new /play/ seo friendly urls for launching games. --- .../main/java/com/agifans/agile/Agile.java | 16 +++++++++--- .../java/com/agifans/agile/AgileRunner.java | 2 ++ .../java/com/agifans/agile/HomeScreen.java | 25 +++++++++++-------- .../com/agifans/agile/gwt/GwtAgileRunner.java | 25 ++++++++++++++++++- .../com/agifans/agile/gwt/GwtLauncher.java | 12 ++++----- .../agile/lwjgl3/DesktopAgileRunner.java | 23 +++++++++++++++++ 6 files changed, 82 insertions(+), 21 deletions(-) diff --git a/core/src/main/java/com/agifans/agile/Agile.java b/core/src/main/java/com/agifans/agile/Agile.java index 475e123..744b21d 100644 --- a/core/src/main/java/com/agifans/agile/Agile.java +++ b/core/src/main/java/com/agifans/agile/Agile.java @@ -79,11 +79,10 @@ public void create() { } } + setScreen(homeScreen); + if (appConfigItem != null) { - gameScreen.initGame(appConfigItem, false); - setScreen(gameScreen); - } else { - setScreen(homeScreen); + homeScreen.processGameSelection(appConfigItem); } // Stop the Android back key from immediately exiting the app. @@ -117,6 +116,15 @@ public Preferences getPreferences() { return preferences; } + /** + * Gets the AgileRunner. + * + * @return the AgileRunner. + */ + public AgileRunner getAgileRunner() { + return agileRunner; + } + @Override public void dispose() { super.dispose(); diff --git a/core/src/main/java/com/agifans/agile/AgileRunner.java b/core/src/main/java/com/agifans/agile/AgileRunner.java index 73b34cc..2920c23 100644 --- a/core/src/main/java/com/agifans/agile/AgileRunner.java +++ b/core/src/main/java/com/agifans/agile/AgileRunner.java @@ -185,4 +185,6 @@ private void updateGameClock() { public abstract boolean hasTouchScreen(); public abstract boolean isMobile(); + + public abstract String slugify(String input); } diff --git a/core/src/main/java/com/agifans/agile/HomeScreen.java b/core/src/main/java/com/agifans/agile/HomeScreen.java index a8b29db..be12091 100644 --- a/core/src/main/java/com/agifans/agile/HomeScreen.java +++ b/core/src/main/java/com/agifans/agile/HomeScreen.java @@ -695,7 +695,8 @@ public AppConfigItem getAppConfigItemByGameId(String gameId) { */ public AppConfigItem getAppConfigItemByGameUri(String gameUri) { for (AppConfigItem appConfigItem : appConfigMap.values()) { - if (appConfigItem.getFilePath().equalsIgnoreCase(gameUri)) { + String uri = agile.getAgileRunner().slugify(appConfigItem.getName()); + if (uri.equalsIgnoreCase(gameUri)) { return appConfigItem; } } @@ -812,15 +813,7 @@ public void clicked(InputEvent event, float x, float y) { if ((appName != null) && (!appName.equals(""))) { final AppConfigItem appConfigItem = appConfigMap.get(appName); if (appConfigItem != null) { - if ("UNK".equals(appConfigItem.getFileType())) { - // Known game but hasn't yet been imported. - importGame(appConfigItem); - } else { - lastGameLaunched = appConfigItem; - GameScreen gameScreen = agile.getGameScreen(); - gameScreen.initGame(appConfigItem, true); - agile.setScreen(gameScreen); - } + processGameSelection(appConfigItem); } else if (appName.equals("INFO")) { showAboutAgileDialog(); } @@ -833,6 +826,18 @@ public void clicked(InputEvent event, float x, float y) { } }; + public void processGameSelection(AppConfigItem appConfigItem) { + if ("UNK".equals(appConfigItem.getFileType())) { + // Known game but hasn't yet been imported. + importGame(appConfigItem); + } else { + lastGameLaunched = appConfigItem; + GameScreen gameScreen = agile.getGameScreen(); + gameScreen.initGame(appConfigItem, true); + agile.setScreen(gameScreen); + } + } + private void showAboutAgileDialog() { dialogHandler.showAboutDialog( "AGILE v1.0.0\n\n" + diff --git a/html/src/main/java/com/agifans/agile/gwt/GwtAgileRunner.java b/html/src/main/java/com/agifans/agile/gwt/GwtAgileRunner.java index 8b791e8..a63b365 100644 --- a/html/src/main/java/com/agifans/agile/gwt/GwtAgileRunner.java +++ b/html/src/main/java/com/agifans/agile/gwt/GwtAgileRunner.java @@ -69,7 +69,7 @@ public void start(AppConfigItem appConfigItem) { // For embedded ZIP games, and original Sierra games, we use a URL path. newURL = Window.Location.createUrlBuilder() .setHash(null) - .setPath("/play/" + appConfigItem.getGameId().toLowerCase() + "/") + .setPath("/play/" + slugify(appConfigItem.getName()) + "/") .buildString(); } else { // Otherwise use id hash. @@ -327,4 +327,27 @@ private native boolean isMobileHtml() /*-{ } } }-*/; + + @Override + public String slugify(String input) { + return slugifyHtml(input); + } + + private native String slugifyHtml(String input) /*-{ + if (!input) return ''; + + // Make lower case and trim. + var slug = input.toLowerCase().trim(); + + // Remove accents from characters. + slug = slug.normalize('NFD').replace(/[\u0300-\u036f]/g, '') + + // Replace invalid chars with spaces. + slug = slug.replace(/[^a-z0-9\s-]/g, '').trim(); + + // Replace multiple spaces or hyphens with a single hyphen. + slug = slug.replace(/[\s-]+/g, '-'); + + return slug; + }-*/; } diff --git a/html/src/main/java/com/agifans/agile/gwt/GwtLauncher.java b/html/src/main/java/com/agifans/agile/gwt/GwtLauncher.java index 26d20ea..b1532a8 100644 --- a/html/src/main/java/com/agifans/agile/gwt/GwtLauncher.java +++ b/html/src/main/java/com/agifans/agile/gwt/GwtLauncher.java @@ -51,21 +51,21 @@ public ApplicationListener createApplicationListener () { } } } else { - String gameId = ""; + String uri = ""; // If a path is included, assume it is to launch a game. if (urlPath.startsWith("/play/")) { - gameId = urlPath.substring(6); + uri = urlPath.substring(6); } else { - gameId = urlPath.substring(1); + uri = urlPath.substring(1); } // Check for and remove trailing slash - if (gameId.endsWith("/")) { - gameId = gameId.substring(0, gameId.lastIndexOf('/')); + if (uri.endsWith("/")) { + uri = uri.substring(0, uri.lastIndexOf('/')); } - argsMap.put("id", gameId); + argsMap.put("uri", uri); } GwtDialogHandler gwtDialogHandler = new GwtDialogHandler(); diff --git a/lwjgl3/src/main/java/com/agifans/agile/lwjgl3/DesktopAgileRunner.java b/lwjgl3/src/main/java/com/agifans/agile/lwjgl3/DesktopAgileRunner.java index 3b9007c..65f81bb 100644 --- a/lwjgl3/src/main/java/com/agifans/agile/lwjgl3/DesktopAgileRunner.java +++ b/lwjgl3/src/main/java/com/agifans/agile/lwjgl3/DesktopAgileRunner.java @@ -1,5 +1,7 @@ package com.agifans.agile.lwjgl3; +import java.text.Normalizer; +import java.text.Normalizer.Form; import java.util.HashMap; import java.util.Map; @@ -144,4 +146,25 @@ public boolean isMobile() { // Desktop/Java/LWJGL platform is obviously not mobile. return false; } + + @Override + public String slugify(String input) { + if ((input == null) | (input.isEmpty())) { + return ""; + } + + // Make lower case and trim. + String slug = input.toLowerCase().trim(); + + // Remove accents from characters. + slug = Normalizer.normalize(slug, Form.NFD).replaceAll("[\u0300-\u036f]", ""); + + // Remove invalid chars. + slug = slug.replaceAll("[^a-z0-9\\s-]", "").trim(); + + // Replace multiple spaces or hyphens with a single hyphen. + slug = slug.replaceAll("[\\s-]+", "-"); + + return slug; + } }