From 6b089fbd2144e1dd156891b189939b129321d2bf Mon Sep 17 00:00:00 2001 From: Riccardo Balbo Date: Tue, 26 May 2026 08:55:03 +0200 Subject: [PATCH 1/2] update to new libjglios --- gradle/libs.versions.toml | 2 +- jme3-ios-examples/build.gradle | 6 +- .../jme3/asset/plugins/IosBundleLocator.java | 131 ++++++++++++++++++ .../src/main/resources/com/jme3/asset/IOS.cfg | 1 + 4 files changed, 136 insertions(+), 4 deletions(-) create mode 100644 jme3-ios/src/main/java/com/jme3/asset/plugins/IosBundleLocator.java diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index bad03ab3db..968b70afd4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -6,7 +6,7 @@ checkstyle = "13.3.0" jacoco = "0.8.12" lwjgl3 = "3.4.1" angle = "2026-05-09" -libjglios = "0.3" +libjglios = "0.4" saferalloc = "0.0.8" nifty = "1.4.3" spotbugs = "4.9.8" diff --git a/jme3-ios-examples/build.gradle b/jme3-ios-examples/build.gradle index 10b1192788..139a193728 100644 --- a/jme3-ios-examples/build.gradle +++ b/jme3-ios-examples/build.gradle @@ -280,11 +280,13 @@ def generateIosNativeImageMetadata = tasks.register('generateIosNativeImageMetad } } -libJGLIOS { +iOS { mainClass = iosChooserLauncherClass bundleId = 'org.jmonkeyengine.jme3iosexamples' appName = 'JmeIosExamples' simulatorDevice = (findProperty('iosSimulatorDevice') ?: 'iPhone 16').toString() + appIcon = file('../jme3-android-examples/src/main/res/mipmap-xxxhdpi/mipmap_monkey.png') + assets.from '../jme3-testdata/src/main/resources', '../jme3-examples/src/main/resources' } sourceSets { @@ -294,8 +296,6 @@ sourceSets { resources { srcDir iosNativeImageMetadataDir srcDir generatedExamplesTestChooserResourcesDir - srcDir '../jme3-testdata/src/main/resources' - srcDir '../jme3-examples/src/main/resources' } } } diff --git a/jme3-ios/src/main/java/com/jme3/asset/plugins/IosBundleLocator.java b/jme3-ios/src/main/java/com/jme3/asset/plugins/IosBundleLocator.java new file mode 100644 index 0000000000..741310b295 --- /dev/null +++ b/jme3-ios/src/main/java/com/jme3/asset/plugins/IosBundleLocator.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2009-2026 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.asset.plugins; + +import com.jme3.asset.AssetInfo; +import com.jme3.asset.AssetKey; +import com.jme3.asset.AssetLoadException; +import com.jme3.asset.AssetLocator; +import com.jme3.asset.AssetManager; +import org.ngengine.libjglios.core.LibJGLIOSBundleBridge; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; + +/** + * Locates assets inside the iOS application bundle resource directory. + */ +public class IosBundleLocator implements AssetLocator { + + private File root; + + @Override + public void setRootPath(String rootPath) { + String resourcePath = LibJGLIOSBundleBridge.resourcePath(); + if (resourcePath == null || resourcePath.isEmpty()) { + throw new AssetLoadException("Unable to resolve iOS bundle resource path"); + } + + String relativeRoot = normalizeRootPath(rootPath); + try { + root = new File(resourcePath, relativeRoot).getCanonicalFile(); + if (!root.isDirectory()) { + throw new IllegalArgumentException("Given iOS bundle root path \"" + root + "\" is not a directory"); + } + } catch (IOException ex) { + throw new AssetLoadException("iOS bundle root path is invalid", ex); + } + } + + private static String normalizeRootPath(String rootPath) { + if (rootPath == null || rootPath.isEmpty() || rootPath.equals("/") || rootPath.equals(".")) { + return ""; + } + + String normalized = rootPath.replace('\\', '/'); + while (normalized.startsWith("/")) { + normalized = normalized.substring(1); + } + return normalized; + } + + @Override + public AssetInfo locate(AssetManager manager, AssetKey key) { + String name = key.getName(); + if (name.startsWith("/")) { + name = name.substring(1); + } + + File file = new File(root, name); + if (!file.exists() || !file.isFile()) { + return null; + } + + try { + File canonicalFile = file.getCanonicalFile(); + if (!isInsideRoot(canonicalFile)) { + return null; + } + return new BundleAssetInfo(manager, key, canonicalFile); + } catch (IOException ex) { + throw new AssetLoadException("Failed to resolve iOS bundle asset path " + file, ex); + } + } + + private boolean isInsideRoot(File file) throws IOException { + String rootPath = root.getCanonicalPath(); + String filePath = file.getCanonicalPath(); + return filePath.equals(rootPath) || filePath.startsWith(rootPath + File.separator); + } + + private static final class BundleAssetInfo extends AssetInfo { + + private final File file; + + private BundleAssetInfo(AssetManager manager, AssetKey key, File file) { + super(manager, key); + this.file = file; + } + + @Override + public InputStream openStream() { + try { + return new FileInputStream(file); + } catch (FileNotFoundException ex) { + throw new AssetLoadException("Failed to open iOS bundle asset: " + file, ex); + } + } + } +} diff --git a/jme3-ios/src/main/resources/com/jme3/asset/IOS.cfg b/jme3-ios/src/main/resources/com/jme3/asset/IOS.cfg index ad3217add4..28adbb9a70 100644 --- a/jme3-ios/src/main/resources/com/jme3/asset/IOS.cfg +++ b/jme3-ios/src/main/resources/com/jme3/asset/IOS.cfg @@ -1,3 +1,4 @@ INCLUDE com/jme3/asset/General.cfg # IOS specific loaders +LOCATOR / com.jme3.asset.plugins.IosBundleLocator From 40b73b121b7e9c57eb753e3238ab717558b15079 Mon Sep 17 00:00:00 2001 From: Riccardo Balbo Date: Tue, 26 May 2026 09:12:01 +0200 Subject: [PATCH 2/2] Update jme3-ios/src/main/java/com/jme3/asset/plugins/IosBundleLocator.java Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- .../main/java/com/jme3/asset/plugins/IosBundleLocator.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jme3-ios/src/main/java/com/jme3/asset/plugins/IosBundleLocator.java b/jme3-ios/src/main/java/com/jme3/asset/plugins/IosBundleLocator.java index 741310b295..00f772af67 100644 --- a/jme3-ios/src/main/java/com/jme3/asset/plugins/IosBundleLocator.java +++ b/jme3-ios/src/main/java/com/jme3/asset/plugins/IosBundleLocator.java @@ -104,9 +104,9 @@ public AssetInfo locate(AssetManager manager, AssetKey key) { } } - private boolean isInsideRoot(File file) throws IOException { - String rootPath = root.getCanonicalPath(); - String filePath = file.getCanonicalPath(); + private boolean isInsideRoot(File file) { + String rootPath = root.getPath(); + String filePath = file.getPath(); return filePath.equals(rootPath) || filePath.startsWith(rootPath + File.separator); }