update to latest engine release candidate

This commit is contained in:
2025-10-11 18:10:45 +02:00
parent 04bd2ee3e4
commit e020b64c86
74 changed files with 3862 additions and 889 deletions

2
.gitattributes vendored
View File

@@ -3,8 +3,10 @@
# #
# Linux start script should use lf # Linux start script should use lf
/gradlew text eol=lf /gradlew text eol=lf
# These are Windows script files and should use crlf # These are Windows script files and should use crlf
*.bat text eol=crlf *.bat text eol=crlf
# Binary files should be left untouched # Binary files should be left untouched
*.jar binary *.jar binary
*.bin filter=lfs diff=lfs merge=lfs -text *.bin filter=lfs diff=lfs merge=lfs -text

View File

@@ -13,10 +13,6 @@ jobs:
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with:
lfs: true
fetch-depth: 1
- name: Set up JDK 21 - name: Set up JDK 21
uses: actions/setup-java@v3 uses: actions/setup-java@v3
@@ -35,6 +31,37 @@ jobs:
path: dist/portable/*-portable.jar path: dist/portable/*-portable.jar
retention-days: 7 retention-days: 7
build-web:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
id-token: write
pages: write
steps:
- uses: actions/checkout@v3
- name: Set up JDK 21
uses: actions/setup-java@v3
with:
java-version: '21'
distribution: 'temurin'
cache: gradle
- name: Build Web Application
run: ./gradlew buildBundledWebApp
- name: Upload pages artifact
uses: actions/upload-pages-artifact@v3
with:
path: 'dist/web-bundle'
- name: Deploy to GitHub Pages
if: github.event_name == 'release'
id: deployment
uses: actions/deploy-pages@v4
build-native: build-native:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
@@ -51,9 +78,6 @@ jobs:
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with:
lfs: true
fetch-depth: 1
- name: Set up GraalVM - name: Set up GraalVM
uses: graalvm/setup-graalvm@v1 uses: graalvm/setup-graalvm@v1
@@ -63,15 +87,6 @@ jobs:
github-token: ${{ secrets.GITHUB_TOKEN }} github-token: ${{ secrets.GITHUB_TOKEN }}
native-image-job-reports: 'true' native-image-job-reports: 'true'
- name: Build Installer for ${{ matrix.platform }}
shell: bash
run: |
if [[ "${{ matrix.platform }}" == "linux" ]]; then
sudo apt-get install -y rpm
fi
./gradlew buildInstaller
ls -R dist
- name: Build Native Executable for ${{ matrix.platform }} - name: Build Native Executable for ${{ matrix.platform }}
shell: bash shell: bash
run: | run: |

11
.gitignore vendored
View File

@@ -1,10 +1,15 @@
# Ignore Gradle project-specific cache directory
.gradle .gradle
# Ignore Gradle build output directory
build build
bin bin
dist dist
*.hprof *.hprof
.idea .idea
.DS_Store .DS_Store
gradle-local.properties
.idea/
node_modules/
*.map
.sourcemaps
.settings
platform-web/.env.nostr-deploy.local
local.properties

16
.vscode/launch.json vendored
View File

@@ -4,22 +4,22 @@
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0", "version": "0.2.0",
"configurations": [ "configurations": [
{ {
"type": "java", "type": "java",
"name": "Current File", "name": "Debug Application",
"request": "launch",
"mainClass": "${file}"
},
{
"type": "java",
"name": "DesktopLauncher",
"request": "launch", "request": "launch",
"mainClass": "org.ngengine.platform.DesktopLauncher", "mainClass": "org.ngengine.platform.DesktopLauncher",
"projectName": "platform-desktop", "projectName": "platform-desktop",
"osx": { "osx": {
"vmArgs": "-XstartOnFirstThread" "vmArgs": "-XstartOnFirstThread"
},
"linux": {
"env": {
"__GL_THREADED_OPTIMIZATIONS": "0"
} }
},
"vmArgs": "-ea -Dthreadwarden=true -Djava.util.logging.config.file=${workspaceFolder}/dev-logging.properties",
} }
] ]
} }

15
.vscode/settings.json vendored
View File

@@ -1,3 +1,16 @@
{ {
"java.configuration.updateBuildConfiguration": "automatic" "java.configuration.updateBuildConfiguration": "automatic",
"files.exclude": {
"**/.git": true,
"**/.svn": true,
"**/.hg": true,
"**/.DS_Store": true,
"**/Thumbs.db": true,
"**/gradle": true,
"**/.gradle": true,
// "**/build": true,
"**/bin": true,
// "platform-*": true
}
} }

View File

@@ -23,6 +23,7 @@ dependencies {
java { java {
sourceCompatibility = JavaVersion.VERSION_11 toolchain {
targetCompatibility = JavaVersion.VERSION_11 languageVersion = JavaLanguageVersion.of(21)
}
} }

View File

@@ -12,34 +12,15 @@ import org.ngengine.demo.adc.PhysicsComponent;
import org.ngengine.demo.adc.PostprocessingComponent; import org.ngengine.demo.adc.PostprocessingComponent;
import org.ngengine.demo.adc.SoundComponent; import org.ngengine.demo.adc.SoundComponent;
import org.ngengine.gui.win.NWindowManagerComponent; import org.ngengine.gui.win.NWindowManagerComponent;
import org.ngengine.nostr4j.keypair.NostrPublicKey;
import com.jme3.system.AppSettings;
public class Main { public class Main {
public static NGEAppRunner main(String arg[]){ public static NGEAppRunner main(String arg[]){
AppSettings settings = new AppSettings(true);
settings.setRenderer(AppSettings.LWJGL_OPENGL32);
settings.setWidth(1280);
settings.setHeight(720);
settings.setGammaCorrection(true);
settings.setSamples(2);
settings.setStencilBits(8);
settings.setDepthBits(24);
settings.setVSync(true);
settings.setGraphicsDebug(false);
settings.setX11PlatformPreferred(true);
settings.setTitle("Nostr Game Engine Demo");
settings.setEmulateMouse(true);
settings.setEmulateKeyboard(true);
NostrPublicKey appId = NostrPublicKey.fromBech32("npub1tc32kq8hr992tzvt09rwuc5wk6aa08pquqawasv20acjp4umny5q6axr4t"); NGEAppRunner appRunner = NGEApplication.createApp( app -> {
NGEAppRunner appRunner = NGEApplication.createApp(appId, settings, app -> {
ImmersiveAdComponent dep = app.enableAds(); ImmersiveAdComponent dep = app.enableAds();
ComponentManager mng = app.getComponentManager(); ComponentManager mng = app.getComponentManager();

View File

@@ -15,7 +15,7 @@ import com.simsilica.lemur.HAlignment;
import com.simsilica.lemur.VAlignment; import com.simsilica.lemur.VAlignment;
public class HudComponent implements Component<Object>, InputHandlerFragment { public class HudComponent implements Component<Object>, InputHandlerFragment {
private Runnable closeHud; private NHud hud;
@Override @Override
public void onEnable(ComponentManager mng, Runner runner, DataStoreProvider dataStore, boolean firstTime, public void onEnable(ComponentManager mng, Runner runner, DataStoreProvider dataStore, boolean firstTime,
@@ -26,22 +26,18 @@ public class HudComponent implements Component<Object>, InputHandlerFragment {
windowManager.showCursor(false); windowManager.showCursor(false);
this.closeHud= windowManager.showWindow( this.hud = windowManager.showWindow( NHud.class );
NHud.class, hud.setFitContent(false);
(win, err) -> { hud.setFullscreen(true);
win.setFitContent(false);
win.setFullscreen(true);
NLabel crossair = new NLabel("+"); NLabel crossair = new NLabel("+");
crossair.setTextVAlignment(VAlignment.Center); crossair.setTextVAlignment(VAlignment.Center);
crossair.setTextHAlignment(HAlignment.Center); crossair.setTextHAlignment(HAlignment.Center);
win.getCenter().addChild(crossair); hud.getCenter().addChild(crossair);
}
);
} }
@Override @Override
public void onDisable(ComponentManager mng, Runner runner, DataStoreProvider dataStore) { public void onDisable(ComponentManager mng, Runner runner, DataStoreProvider dataStore) {
this.closeHud.run(); hud.close();
} }
@Override @Override

View File

@@ -16,7 +16,7 @@ import com.simsilica.lemur.HAlignment;
import com.simsilica.lemur.VAlignment; import com.simsilica.lemur.VAlignment;
public class LoadingScreenComponent implements Component<Object>, LogicFragment { public class LoadingScreenComponent implements Component<Object>, LogicFragment {
private Runnable closeHud; private NHud hud;
private NLabel txt; private NLabel txt;
@Override @Override
public void onEnable(ComponentManager mng, Runner runner, DataStoreProvider dataStore, boolean firstTime, public void onEnable(ComponentManager mng, Runner runner, DataStoreProvider dataStore, boolean firstTime,
@@ -29,22 +29,19 @@ public class LoadingScreenComponent implements Component<Object>, LogicFragment
txt = new NLabel("Loading"); txt = new NLabel("Loading");
this.closeHud= windowManager.showWindow( hud = windowManager.showWindow(NHud.class);
NHud.class, hud.setFitContent(false);
(win, err) -> { hud.setFullscreen(true);
win.setFitContent(false);
win.setFullscreen(true);
txt.setFontSize(32); txt.setFontSize(32);
txt.setTextVAlignment(VAlignment.Center); txt.setTextVAlignment(VAlignment.Center);
txt.setTextHAlignment(HAlignment.Center); txt.setTextHAlignment(HAlignment.Center);
win.getCenter().addChild(txt); hud.getCenter().addChild(txt);
}
);
} }
@Override @Override
public void onDisable(ComponentManager mng, Runner runner, DataStoreProvider dataStore) { public void onDisable(ComponentManager mng, Runner runner, DataStoreProvider dataStore) {
this.closeHud.run(); hud.close();
} }
float time = 0; float time = 0;

View File

@@ -83,7 +83,6 @@ public class MapComponent implements Component<Object>, AsyncAssetLoadingFragmen
preload.accept(sky); preload.accept(sky);
} catch(Exception e){ } catch(Exception e){
e.printStackTrace(); e.printStackTrace();
System.exit(1);
} }
} }

View File

@@ -0,0 +1,47 @@
{
"AppId": "npub146wutmuxfmnlx9fcty0lkns2rpwhnl57kpes26mmt4hygalsakrsdllryz",
"Display": 0,
"Width": 1280,
"Height": 720,
"Fullscreen": false,
"Resizable": true,
"Title": "AdCity",
"Version": "1.0.0",
"VersionCode": 1,
"ShortName": "adc",
"Namespace":"org.ngengine.adc",
"Copyright": "",
"VSync": true,
"GammaCorrection": true,
"ScreenOrientation": "landscape",
"relays": {
"blossom": {
"default": [
"https://blossom.primal.net",
"https://blossom.band/"
]
},
"nostr": {
"ads":[
"wss://nostr.rblb.it",
"wss://relay.damus.io"
],
"default": [
"wss://relay.ngengine.org",
"wss://relay2.ngengine.org",
"wss://relay.damus.io",
"wss://relay.primal.net",
"wss://relay.nostr.band",
"wss://relay.snort.social",
"wss://nos.lol"
],
"nip46": [
"wss://relay.nsec.app",
"wss://relay.ngengine.org",
"wss://relay2.ngengine.org"
]
}
}
}

View File

@@ -2,19 +2,8 @@
org.gradle.configuration-cache=false org.gradle.configuration-cache=false
org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=1g -XX:+HeapDumpOnOutOfMemoryError org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=1g -XX:+HeapDumpOnOutOfMemoryError
android.useAndroidX=true android.useAndroidX=true
teaVmVersion=0.12.3
# NGE versions # NGE versions
ngePlatformVersion=0.1.3 ngePlatformVersion=0.2.1
ngeVersion=0.1 ngeVersion=0.2-rc3
# Build targets
withDesktopPlatform=true
withAndroidPlatform=false
# Project settings
version=1.0.0
versionCode=1
projectName=adcity
applicationId=org.ngengine.demo.AdcDemo
copyright=Copyright (c) 2025
javaOptions=

View File

@@ -8,9 +8,8 @@ constraintlayout = "2.2.1"
espressoCore = "3.7.0" espressoCore = "3.7.0"
guava = "33.3.1-jre" guava = "33.3.1-jre"
junit = "4.13.2" junit = "4.13.2"
junitVersion = "4.13.3-SNAPSHOT" junitVersion = "4.13.2"
material = "1.12.0" material = "1.12.0"
ngePlatformAndroid = "0.1.0-SNAPSHOT"
navigationFragment = "2.6.0" navigationFragment = "2.6.0"
navigationUi = "2.6.0" navigationUi = "2.6.0"

View File

@@ -0,0 +1,54 @@
import javax.imageio.ImageIO
import java.awt.Image
import java.awt.image.BufferedImage
import java.awt.geom.Ellipse2D
gradle.ext.generateAndroidIcons = { inputLogoPath, outputDirPath ->
def inputLogo = file(inputLogoPath)
def outputDir = file(outputDirPath)
def densities = [
mdpi : 48,
hdpi : 72,
xhdpi: 96,
xxhdpi: 144,
xxxhdpi: 192
]
if (!inputLogo.exists()) {
throw new GradleException("Logo file not found at ${inputLogo}")
}
def original = ImageIO.read(inputLogo)
densities.each { name, size ->
def dir = new File(outputDir, "mipmap-${name}")
dir.mkdirs()
// --- Regular square launcher ---
def square = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB)
def g = square.createGraphics()
g.drawImage(original.getScaledInstance(size, size, Image.SCALE_SMOOTH), 0, 0, null)
g.dispose()
def launcherFile = new File(dir, "ic_launcher.png")
ImageIO.write(square, "png", launcherFile)
def launcherFileF = new File(dir, "ic_launcher_foreground.png")
ImageIO.write(square, "png", launcherFileF)
println "Generated ${launcherFile} (${size}x${size})"
// --- Round launcher ---
def round = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB)
def gr = round.createGraphics()
// Create circular clipping mask
gr.setClip(new Ellipse2D.Float(0, 0, size, size))
gr.drawImage(original.getScaledInstance(size, size, Image.SCALE_SMOOTH), 0, 0, null)
gr.dispose()
def roundFile = new File(dir, "ic_launcher_round.png")
ImageIO.write(round, "png", roundFile)
println "Generated ${roundFile} (circular ${size}x${size})"
}
}

View File

@@ -0,0 +1,231 @@
project.ext {
dynamicTargetTypes = [
'com.jme3.export.Savable',
'com.jme3.asset.AssetLoader',
'com.jme3.asset.plugins.FileLocator',
'com.jme3.network.Message',
// 'com.jme3.network.serializing.Serializable',
// 'org.ngengine.network.protocol.NetworkSafe',
'org.ngengine.components.fragments.Fragment',
'org.ngengine.components.Component',
'com.jme3.asset.cache.AssetCache',
'com.jme3.asset.AssetProcessor',
'com.jme3.post.Filter',
'com.jme3.util.BufferAllocator',
'com.jme3.asset.AssetLocator',
'com.jme3.anim.util.JointModelTransform',
'com.jme3.material.logic.TechniqueDefLogic',
'com.jme3.material.Technique',
'com.jme3.material.TechniqueDef',
'com.jme3.util.clone.JmeCloneable',
'com.jme3.system.JmeSystem',
'com.jme3.system.JmeSystemDelegate',
'com.jme3.util.SafeArrayList',
'com.jme3.plugins.json.JsonParser',
'java.lang.Cloneable',
'com.jme3.asset.CloneableSmartAsset',
'com.jme3.post.SceneProcessor',
'com.jme3.util.res.ResourceLoader',
'org.ngengine.nostr4j.listeners.NostrRelayComponent',
'org.ngengine.auth.Auth',
'org.ngengine.gui.win.NWindow',
'org.ngengine.auth.AuthStrategy',
'org.ngengine.auth.AuthConfig',
'com.simsilica.lemur.core.GuiComponent',
'com.simsilica.lemur.Panel',
'com.simsilica.lemur.style.Styles',
'com.simsilica.lemur.style.StyleTree',
// 'com.simsilica.lemur.style.StyleDefaults',
// 'com.simsilica.lemur.style.StyleAttribute',
'com.simsilica.lemur.style.Selector',
'com.simsilica.lemur.style.ElementId',
'com.simsilica.lemur.style.Attributes',
]
dynamicAdditionalClasses = [
]
dynamicScanSubclasses = true
dynamicExcludePatterns = [
'org\\.teavm\\..*',
'java\\.lang\\..*',
'org\\.joda\\.time\\..*',
'java\\..*',
'javax\\..*',
'kotlin\\..*',
'com\\.google\\.gson\\..*',
'org\\.threeten\\..*',
'org\\.apache\\..*',
'com\\.simsilica\\.lemur\\.ColorChooser.*',
'org\\.slf4j\\..*'
]
dynamicClassesFound = new TreeSet<String>()
dynamicReflectionClasses = new TreeSet<String>()
}
ext.scanClasspathForClasses = { project ->
// Create a collection to hold all classpath entries
Set<File> classpath = new LinkedHashSet<>()
// Add project's compiled classes
if (project.sourceSets.findByName('main')) {
classpath.addAll(project.sourceSets.main.output.classesDirs.files)
classpath.addAll(project.sourceSets.main.output.resourcesDir)
}
// Add runtime dependencies
if (project.configurations.findByName('runtimeClasspath')) {
classpath.addAll(project.configurations.runtimeClasspath.files)
}
// Add compile dependencies (some may not be in runtime)
if (project.configurations.findByName('compileClasspath')) {
classpath.addAll(project.configurations.compileClasspath.files)
}
// Keep only existing dirs/jars
classpath = classpath.findAll {
it.exists() && (it.isDirectory() || it.name.endsWith('.jar'))
} as LinkedHashSet<File>
println "Scanning ${classpath.size()} classpath entries"
// Build a single loader for EVERYTHING
URL[] urls = classpath.collect { it.toURI().toURL() } as URL[]
ClassLoader scanLoader = new URLClassLoader(urls, this.class.classLoader)
// println "Target types: ${project.ext.dynamicTargetTypes}"
// Reset results
project.ext.dynamicClassesFound.clear()
project.ext.dynamicReflectionClasses.clear()
// Check target types loadable with the same loader
project.ext.dynamicTargetTypes.each { targetType ->
try {
Class.forName(targetType, false, scanLoader)
// println "✓ Target type $targetType is loadable"
} catch (Throwable t) {
println "✗ Target type $targetType is not loadable: ${t.class.simpleName}: ${t.message}"
}
}
// Seed manual classes
project.ext.dynamicAdditionalClasses.each { cn ->
project.ext.dynamicClassesFound.add(cn)
project.ext.dynamicReflectionClasses.add(cn)
}
int totalProcessed = 0
int totalMatched = 0
classpath.each { file ->
if (file.isDirectory()) {
def r = scanDirectory(file, file, project.ext.dynamicTargetTypes,
project.ext.dynamicClassesFound, project.ext.dynamicReflectionClasses,
project.ext.dynamicScanSubclasses, project.ext.dynamicExcludePatterns,
scanLoader)
totalProcessed += r.processed; totalMatched += r.matched
} else {
def r = scanJar(file, project.ext.dynamicTargetTypes,
project.ext.dynamicClassesFound, project.ext.dynamicReflectionClasses,
project.ext.dynamicScanSubclasses, project.ext.dynamicExcludePatterns,
scanLoader)
totalProcessed += r.processed; totalMatched += r.matched
}
}
println "Processed ${totalProcessed} classes total"
println "Matched ${totalMatched} classes"
println "Found ${project.ext.dynamicClassesFound.size()} dynamic classes"
[classes: project.ext.dynamicClassesFound, reflectionClasses: project.ext.dynamicReflectionClasses]
}
def scanDirectory(baseDir, dir, targetTypes, classesFound, reflectionClasses, scanSubclasses, excludePatterns, ClassLoader scanLoader) {
int processed = 0, matched = 0
dir.eachFileRecurse { file ->
if (file.isFile() && file.name.endsWith('.class')) {
def rel = baseDir.toPath().relativize(file.toPath()).toString()
def className = rel.substring(0, rel.length() - 6).replace(File.separator, '.')
processed++
if (!className.contains('$') && className != 'module-info' && className != 'package-info' && !isExcluded(className, excludePatterns)) {
try {
Class<?> clazz = Class.forName(className, false, scanLoader)
if (isCompatibleType(clazz, targetTypes, scanSubclasses, scanLoader)) {
classesFound.add(className)
reflectionClasses.add(className)
matched++
}
} catch (Throwable ignored) {}
}
}
}
[processed: processed, matched: matched]
}
def scanJar(jarFile, targetTypes, classesFound, reflectionClasses, scanSubclasses, excludePatterns, ClassLoader scanLoader) {
int processed = 0, matched = 0
try {
new java.util.jar.JarFile(jarFile).withCloseable { jar ->
jar.entries().findAll { !it.isDirectory() && it.name.endsWith('.class') }.each { e ->
def className = e.name.substring(0, e.name.length() - 6).replace('/', '.')
processed++
if (!className.contains('$') && className != 'module-info' && className != 'package-info' && !isExcluded(className, excludePatterns)) {
try {
Class<?> clazz = Class.forName(className, false, scanLoader)
if (isCompatibleType(clazz, targetTypes, scanSubclasses, scanLoader)) {
classesFound.add(className)
reflectionClasses.add(className)
matched++
}
} catch (Throwable ignored) {}
}
}
}
} catch (Throwable t) {
println "Error scanning JAR ${jarFile.name}: ${t.message}"
}
[processed: processed, matched: matched]
}
def isCompatibleType(Class<?> clazz, Collection<String> targetTypes, boolean scanSubclasses, ClassLoader scanLoader) {
if (clazz == null) return false
// Assignable to any target class/interface
for (def targetType : targetTypes) {
try {
Class<?> targetClass = Class.forName(targetType, false, scanLoader)
if (targetClass.isAssignableFrom(clazz)) return true
} catch (Throwable ignored) {}
}
// Traverse interfaces
for (def iface : clazz.interfaces) {
if (targetTypes.contains(iface.name) || (scanSubclasses && isCompatibleType(iface, targetTypes, scanSubclasses, scanLoader))) {
return true
}
}
// Traverse superclass
scanSubclasses && isCompatibleType(clazz.superclass, targetTypes, scanSubclasses, scanLoader)
}
// Helper to check if a class should be excluded
def isExcluded(String className, Collection<String> excludePatterns) {
for (def pattern : excludePatterns) {
if (className.matches(pattern)) {
return true
}
}
return false
}

15
gradle/libs/props.gradle Normal file
View File

@@ -0,0 +1,15 @@
import groovy.json.JsonSlurper
gradle.ext.loadNgeAppProperties = { path ->
def ngeappFile = file(path)
if (ngeappFile.exists()) {
def jsonSlurper = new JsonSlurper()
def fileContent = ngeappFile.text.replaceAll(/\/\/.*?$/, '').trim()
def ngeappConfig = jsonSlurper.parseText(fileContent)
return ngeappConfig
} else {
logger.warn(path+" file not found")
return [:]
}
}

BIN
icon.icns

Binary file not shown.

View File

@@ -1,8 +1 @@
## This file must *NOT* be checked into Version Control Systems,
# as it contains information specific to your local configuration.
#
# Location of the SDK. This is only used by Gradle.
# For customization when using a Version Control System, please read the
# header note.
#Mon Sep 01 09:13:24 CEST 2025
sdk.dir=/home/riccardobl/Android/Sdk sdk.dir=/home/riccardobl/Android/Sdk

View File

@@ -2,19 +2,31 @@ plugins {
id 'com.android.application' id 'com.android.application'
} }
def localPropsFile = file("${rootDir}/local.properties")
if (!localPropsFile.exists()) {
def userHome = System.getProperty('user.home')
localPropsFile.text = "sdk.dir=${userHome}/Android/Sdk"
println "Created local.properties with sdk.dir=${userHome}/Android/Sdk"
}
android { android {
compileSdk 36 compileSdk 36
namespace "${project.applicationId}" namespace "${project.Namespace}"
defaultConfig { defaultConfig {
applicationId "${project.applicationId}" applicationId "${project.Namespace}"
minSdk 33 minSdk 33
targetSdk 33 targetSdk 33
versionCode project.versionCode.toInteger() versionCode project.VersionCode.toInteger()
versionName project.version versionName project.Version
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
manifestPlaceholders = [
appLabel : (project.findProperty('Title') ?: "NGE Unnamed App"),
screenOrientation: (project.findProperty('ScreenOrientation') ?: "landscape")
]
} }
packagingOptions { packagingOptions {
jniLibs { jniLibs {
useLegacyPackaging = true useLegacyPackaging = true
@@ -27,14 +39,17 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
} }
} }
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_11 sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11 targetCompatibility JavaVersion.VERSION_11
} }
buildFeatures { buildFeatures {
viewBinding true viewBinding true
} }
} }
@@ -52,7 +67,19 @@ dependencies {
implementation project(':app') implementation project(':app')
implementation "org.ngengine:nge-platform-android:${ngePlatformVersion}" implementation "org.ngengine:nge-platform-android:${ngePlatformVersion}"
implementation "org.ngengine:nge-app:${ngeVersion}" implementation "org.ngengine:nge-app:${ngeVersion}"
implementation "org.ngengine:jme3-android:${ngeVersion}" implementation "org.ngengine:nge-android:${ngeVersion}"
implementation "org.ngengine:jme3-android-native:${ngeVersion}"
} }
apply from: "${rootDir}/gradle/libs/android-icon-gen.gradle"
task generateAndroidLauncherIcons (){
doLast {
gradle.ext.generateAndroidIcons("${rootDir}/icon.png", "${projectDir}/src/main/res")
}
}
android.applicationVariants.all { variant ->
variant.mergeResourcesProvider.configure { dependsOn(generateAndroidLauncherIcons) }
}

View File

@@ -5,7 +5,7 @@
<application <application
android:allowBackup="true" android:allowBackup="true"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="Nostr Game Engine App" android:label="${appLabel}"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:largeHeap="true" android:largeHeap="true"
@@ -13,8 +13,9 @@
<activity <activity
android:name="org.ngengine.platform.AndroidLauncherActivity" android:name="org.ngengine.platform.AndroidLauncherActivity"
android:exported="true" android:exported="true"
android:screenOrientation="landscape" android:screenOrientation="${screenOrientation}"
android:theme="@style/Theme.AppCompat.NoActionBar"> android:theme="@style/Theme.AppCompat.NoActionBar"
>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />

View File

@@ -13,22 +13,22 @@ import androidx.navigation.Navigation;
import androidx.navigation.ui.AppBarConfiguration; import androidx.navigation.ui.AppBarConfiguration;
import androidx.navigation.ui.NavigationUI; import androidx.navigation.ui.NavigationUI;
import org.ngengine.app.Main;
import org.ngengine.platform.android.AndroidThreadedPlatform;
import org.ngengine.demo.AdcDemo.R;
public class AndroidLauncherActivity extends AppCompatActivity { public class AndroidLauncherActivity extends AppCompatActivity {
private AndroidLauncherFragment launcherFragment;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_android_launcher); int layoutId = getResources().getIdentifier("activity_android_launcher", "layout", getPackageName());
setContentView(layoutId);
launcherFragment = new AndroidLauncherFragment(); int containerId = getResources().getIdentifier("fragment_container", "id", getPackageName());
getSupportFragmentManager() getSupportFragmentManager()
.beginTransaction() .beginTransaction()
.add(R.id.fragment_container, launcherFragment) .add(containerId, new AndroidLauncherFragment(Main::main, AndroidThreadedPlatform::new))
.commit(); .commit();
} }

View File

@@ -1,308 +0,0 @@
package org.ngengine.platform;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;
import com.jme3.audio.AudioRenderer;
import com.jme3.input.JoyInput;
import com.jme3.input.android.AndroidSensorJoyInput;
import com.jme3.system.AppSettings;
import com.jme3.system.SystemListener;
import com.jme3.system.android.JmeAndroidSystem;
import com.jme3.system.android.OGLESContext;
import com.jme3.util.AndroidLogHandler;
import com.jme3.util.AndroidNativeBufferAllocator;
import com.jme3.util.BufferAllocatorFactory;
import android.app.AlertDialog;
import org.ngengine.NGEApplication.NGEAppRunner;
import org.ngengine.NGEApplication;
import org.ngengine.app.Main;
import org.ngengine.platform.android.AndroidThreadedPlatform;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;
public class AndroidLauncherFragment extends Fragment implements
SystemListener {
private static final Logger logger = Logger.getLogger(AndroidLauncherFragment.class.getName());
protected GLSurfaceView view = null;
private NGEApplication app = null;
private boolean finishOnAppStop = true;
@Override
public void onAttach(Context context) {
super.onAttach(context);
}
public void setCloseActivityOnAppStop(boolean close){
this.finishOnAppStop = close;
}
/**
* onCreate is called once for this Fragment instance.
* Note: AppSettings configuration has been removed. Configure settings in your app.
*/
@Override
@SuppressWarnings("unchecked")
public void onCreate(Bundle savedInstanceState) {
initializeLogHandler();
logger.fine("onCreate");
super.onCreate(savedInstanceState);
System.setProperty( BufferAllocatorFactory.PROPERTY_BUFFER_ALLOCATOR_IMPLEMENTATION, AndroidNativeBufferAllocator.class.getName());
NGEPlatform.set(new AndroidThreadedPlatform(this.getContext()));
NGEAppRunner runner = Main.main(new String[0]);
app = runner.app();
AppSettings settings = app.getSettings();
settings.setAudioRenderer(AppSettings.ANDROID_OPENAL_SOFT);
app.start();
OGLESContext ctx = (OGLESContext) app.getJme3App().getContext();
ctx.setSystemListener(this);
}
/**
* Create the GLSurfaceView and return it as the Fragment's view.
*/
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
logger.fine("onCreateView");
view = ((OGLESContext) app.getJme3App().getContext()).createView(requireActivity());
JmeAndroidSystem.setView(view);
return view;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
logger.fine("onActivityCreated");
super.onActivityCreated(savedInstanceState);
}
@Override
public void onStart() {
logger.fine("onStart");
super.onStart();
}
/**
* When the Fragment resumes, call gainFocus() in the jME application.
*/
@Override
public void onResume() {
logger.fine("onResume");
super.onResume();
gainFocus();
}
/**
* When the Fragment pauses, call loseFocus() in the jME application.
*/
@Override
public void onPause() {
logger.fine("onPause");
loseFocus();
super.onPause();
}
@Override
public void onStop() {
logger.fine("onStop");
super.onStop();
}
/**
* Clear references to the GLSurfaceView.
*/
@Override
public void onDestroyView() {
logger.fine("onDestroyView");
if (view != null) {
if (view.getParent() instanceof ViewGroup) {
((ViewGroup) view.getParent()).removeView(view);
}
}
view = null;
JmeAndroidSystem.setView(null);
super.onDestroyView();
}
/**
* Called by the system when the application is being destroyed.
*/
@Override
public void onDestroy() {
logger.fine("onDestroy");
if (app != null) {
app.stop();
}
app = null;
super.onDestroy();
}
/**
* Called when an error has occurred. Shows an error message and logs the exception.
*/
@Override
public void handleError(final String errorMsg, final Throwable t) {
String stackTrace = "";
String title = "Error";
if (t != null) {
// Convert exception to string
StringWriter sw = new StringWriter(100);
t.printStackTrace(new PrintWriter(sw));
stackTrace = sw.toString();
title = t.toString();
}
final String finalTitle = title;
final String finalMsg = (errorMsg != null ? errorMsg : "Uncaught Exception")
+ "\n" + stackTrace;
logger.log(Level.SEVERE, finalMsg);
requireActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity());
builder.setTitle(finalTitle);
builder.setMessage(finalMsg);
AlertDialog dialog = builder.create();
dialog.show();
}
});
}
/**
* Removes the standard Android log handler due to an issue with not logging
* entries lower than INFO level and adds a handler that produces
* JME formatted log messages.
*/
protected void initializeLogHandler() {
Logger log = LogManager.getLogManager().getLogger("");
for (Handler handler : log.getHandlers()) {
if (log.getLevel() != null && log.getLevel().intValue() <= Level.FINE.intValue()) {
Log.v("AndroidHarness", "Removing Handler class: " + handler.getClass().getName());
}
log.removeHandler(handler);
}
Handler handler = new AndroidLogHandler();
log.addHandler(handler);
handler.setLevel(Level.ALL);
}
@Override
public void initialize() {
app.getJme3App().initialize();
}
@Override
public void reshape(int width, int height) {
app.getJme3App().reshape(width, height);
}
@Override
public void rescale(float x, float y) {
app.getJme3App().rescale(x, y);
}
@Override
public void update() {
app.getJme3App().update();
}
@Override
public void requestClose(boolean esc) {
app.getJme3App().requestClose(esc);
}
@Override
public void destroy() {
if (app != null) {
app.getJme3App().destroy();
}
if (finishOnAppStop) {
requireActivity().finish();
}
}
@Override
public void gainFocus() {
logger.fine("gainFocus");
if (view != null) {
view.onResume();
}
if (app != null) {
// resume the audio
AudioRenderer audioRenderer = app.getJme3App().getAudioRenderer();
if (audioRenderer != null) {
audioRenderer.resumeAll();
}
// resume the sensors (aka joysticks)
if (app.getJme3App().getContext() != null) {
JoyInput joyInput = app.getJme3App().getContext().getJoyInput();
if (joyInput instanceof AndroidSensorJoyInput) {
((AndroidSensorJoyInput) joyInput).resumeSensors();
}
}
app.getJme3App().gainFocus();
}
}
@Override
public void loseFocus() {
logger.fine("loseFocus");
if (app != null) {
app.getJme3App().loseFocus();
}
if (view != null) {
view.onPause();
}
if (app != null) {
// pause the audio
AudioRenderer audioRenderer = app.getJme3App().getAudioRenderer();
if (audioRenderer != null) {
audioRenderer.pauseAll();
}
// pause the sensors (aka joysticks)
if (app.getJme3App().getContext() != null) {
JoyInput joyInput = app.getJme3App().getContext().getJoyInput();
if (joyInput instanceof AndroidSensorJoyInput) {
((AndroidSensorJoyInput) joyInput).pauseSensors();
}
}
}
}
}

View File

@@ -1,30 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" <inset xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt" android:insetLeft="12dp"
android:width="108dp" android:insetTop="12dp"
android:height="108dp" android:insetRight="12dp"
android:viewportWidth="108" android:insetBottom="12dp">
android:viewportHeight="108"> <bitmap
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z"> android:src="@mipmap/ic_launcher_foreground"
<aapt:attr name="android:fillColor"> android:gravity="center"
<gradient android:filter="true"
android:endX="85.84757" android:antialias="true" />
android:endY="92.4963" </inset>
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

View File

@@ -1,170 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android" <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
android:width="108dp" <solid android:color="#0f0113ff"/>
android:height="108dp" </shape>
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -6,6 +6,12 @@ plugins {
} }
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
dependencies { dependencies {
testImplementation libs.junit testImplementation libs.junit
@@ -16,11 +22,17 @@ dependencies {
implementation project(':app') implementation project(':app')
} }
application { application {
mainClass = "org.ngengine.platform.DesktopLauncher" mainClass = "org.ngengine.platform.DesktopLauncher"
} }
configurations {
nativeImageCompileOnly {
canBeResolved = true
}
}
run { run {
jvmArgs = [ jvmArgs = [
"-Djava.util.logging.config.file=${rootProject.projectDir}/dev-logging.properties", "-Djava.util.logging.config.file=${rootProject.projectDir}/dev-logging.properties",
@@ -43,8 +55,6 @@ shadowJar {
} }
build.dependsOn shadowJar
graalvmNative { graalvmNative {
toolchainDetection = true toolchainDetection = true
metadataRepository { metadataRepository {
@@ -84,9 +94,9 @@ graalvmNative {
] ]
// Add G1 GC only if linux // Add G1 GC only if linux
if (org.gradle.internal.os.OperatingSystem.current().isLinux()) { // if (org.gradle.internal.os.OperatingSystem.current().isLinux()) {
arguments.add('--gc=G1') // arguments.add('--gc=G1')
} // }
buildArgs.addAll(arguments) buildArgs.addAll(arguments)
sharedLibrary = false sharedLibrary = false
@@ -94,11 +104,6 @@ graalvmNative {
} }
} }
configurations {
nativeImageCompileOnly {
canBeResolved = true
}
}
def getOsName(){ def getOsName(){
def osName = org.gradle.internal.os.OperatingSystem.current().getName().toLowerCase() def osName = org.gradle.internal.os.OperatingSystem.current().getName().toLowerCase()
@@ -116,8 +121,6 @@ def getOsName(){
task traceNative(type: JavaExec) { task traceNative(type: JavaExec) {
group = 'graalvm'
description = 'Trace reflection and resource usage'
mainClass = application.mainClass.get() mainClass = application.mainClass.get()
classpath = sourceSets.main.runtimeClasspath classpath = sourceSets.main.runtimeClasspath
jvmArgs = [ jvmArgs = [
@@ -152,8 +155,6 @@ task traceNative(type: JavaExec) {
task buildNativeExecutable { task buildNativeExecutable {
group = 'graalvm'
description = 'Build native executable for current platform'
dependsOn 'nativeCompile' dependsOn 'nativeCompile'
doLast { doLast {
def buildDirNative = "${project.buildDir}/native/nativeCompile" def buildDirNative = "${project.buildDir}/native/nativeCompile"
@@ -185,84 +186,10 @@ task buildNativeExecutable {
def jpackage(installerType, distDir){ task buildPortable {
def os = org.gradle.internal.os.OperatingSystem.current()
def jarFile = shadowJar.archiveFile.get().asFile
def jarDir = jarFile.parentFile
def mainClass = application.mainClass.get()
def shadowJarFile = shadowJar.archiveFile.get().asFile
def commandLine = [
'jpackage',
'--input', jarDir.absolutePath,
'--main-jar', jarFile.name,
'--main-class', mainClass,
'--name', rootProject.name,
'--app-version', project.version,
'--type', installerType,
'--dest', distDir,
'--java-options', project.findProperty('javaOptions') ?: '',
'--copyright', project.findProperty('copyright')
]
// Optional: platform-specific flags
if (os.isWindows()) {
commandLine += ['--win-menu', '--win-shortcut']
} else if (os.isMacOsX()) {
commandLine += ['--icon', "${rootProject.projectDir}/icon.icns"]
} else if (os.isLinux()) {
commandLine += ['--icon', "${rootProject.projectDir}/icon.png"]
}
return commandLine
}
task buildInstaller(type: DefaultTask) {
group = 'distribution'
description = 'Create native installer using jpackage'
dependsOn shadowJar dependsOn shadowJar
def os = org.gradle.internal.os.OperatingSystem.current()
def osName = getOsName()
def osArch = System.getProperty("os.arch").toLowerCase()
def buildName = "${rootProject.name}-${project.version}-${osName}-${osArch}-SETUP";
def distDir = file("${rootProject.projectDir}/dist/${buildName}.setup")
doLast { doLast {
if (distDir.exists()) { println "Portable JAR created: ${shadowJar.destinationDirectory}/${shadowJar.archiveFileName.get()}"
println "Deleting existing output directory: ${distDir}"
delete distDir
}
if(os.isWindows()){
exec {
commandLine jpackage('exe', distDir)
}
} else if(os.isMacOsX()){
exec {
commandLine jpackage('dmg', distDir)
}
} else if(os.isLinux()){
exec {
commandLine jpackage('deb', distDir)
}
exec {
commandLine jpackage('rpm', distDir)
}
}
} }
} }
java {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}

View File

@@ -2,10 +2,12 @@ package org.ngengine.platform;
import org.ngengine.app.Main; import org.ngengine.app.Main;
import org.ngengine.platform.jvm.JVMAsyncPlatform; import org.ngengine.platform.jvm.JVMAsyncPlatform;
import java.io.IOException;
import org.ngengine.NGEApplication.NGEAppRunner; import org.ngengine.NGEApplication.NGEAppRunner;
public class DesktopLauncher { public class DesktopLauncher {
public static void main(String[] args) { public static void main(String[] args) throws IOException {
NGEPlatform.set(new JVMAsyncPlatform()); NGEPlatform.set(new JVMAsyncPlatform());
NGEAppRunner runner = Main.main(args); NGEAppRunner runner = Main.main(args);
runner.start(); runner.start();

View File

@@ -57,12 +57,6 @@
{ {
"type": "[Lcom.simsilica.lemur.focus.FocusChangeListener;" "type": "[Lcom.simsilica.lemur.focus.FocusChangeListener;"
}, },
{
"type": "[Lcom.simsilica.lemur.input.AnalogFunctionListener;"
},
{
"type": "[Lcom.simsilica.lemur.input.StateFunctionListener;"
},
{ {
"type": "[Ljava.awt.event.MouseMotionListener;" "type": "[Ljava.awt.event.MouseMotionListener;"
}, },
@@ -75,24 +69,6 @@
} }
] ]
}, },
{
"type": "com.bulletphysics.collision.dispatch.CompoundCollisionAlgorithm",
"methods": [
{
"name": "<init>",
"parameterTypes": []
}
]
},
{
"type": "com.bulletphysics.collision.dispatch.ConvexConvexAlgorithm",
"methods": [
{
"name": "<init>",
"parameterTypes": []
}
]
},
{ {
"type": "com.bulletphysics.collision.dispatch.UnionFind$Element", "type": "com.bulletphysics.collision.dispatch.UnionFind$Element",
"methods": [ "methods": [
@@ -102,87 +78,6 @@
} }
] ]
}, },
{
"type": "com.bulletphysics.collision.narrowphase.DiscreteCollisionDetectorInterface$ClosestPointInput",
"methods": [
{
"name": "<init>",
"parameterTypes": []
}
]
},
{
"type": "com.bulletphysics.collision.narrowphase.GjkEpaSolver$Face",
"methods": [
{
"name": "<init>",
"parameterTypes": []
}
]
},
{
"type": "com.bulletphysics.collision.narrowphase.GjkEpaSolver$He",
"methods": [
{
"name": "<init>",
"parameterTypes": []
}
]
},
{
"type": "com.bulletphysics.collision.narrowphase.GjkEpaSolver$Mkv",
"methods": [
{
"name": "<init>",
"parameterTypes": []
}
]
},
{
"type": "com.bulletphysics.collision.narrowphase.ManifoldPoint",
"methods": [
{
"name": "<init>",
"parameterTypes": []
}
]
},
{
"type": "com.bulletphysics.collision.narrowphase.PersistentManifold",
"methods": [
{
"name": "<init>",
"parameterTypes": []
}
]
},
{
"type": "com.bulletphysics.collision.narrowphase.VoronoiSimplexSolver$SubSimplexClosestResult",
"methods": [
{
"name": "<init>",
"parameterTypes": []
}
]
},
{
"type": "com.bulletphysics.dynamics.constraintsolver.SolverBody",
"methods": [
{
"name": "<init>",
"parameterTypes": []
}
]
},
{
"type": "com.bulletphysics.dynamics.constraintsolver.SolverConstraint",
"methods": [
{
"name": "<init>",
"parameterTypes": []
}
]
},
{ {
"type": "com.jme3.asset.CloneableAssetProcessor", "type": "com.jme3.asset.CloneableAssetProcessor",
"methods": [ "methods": [
@@ -273,15 +168,6 @@
{ {
"type": "com.jme3.cursors.plugins.CursorLoader" "type": "com.jme3.cursors.plugins.CursorLoader"
}, },
{
"type": "com.jme3.export.SavableWrapSerializable",
"methods": [
{
"name": "<init>",
"parameterTypes": []
}
]
},
{ {
"type": "com.jme3.export.binary.BinaryLoader" "type": "com.jme3.export.binary.BinaryLoader"
}, },
@@ -294,24 +180,6 @@
} }
] ]
}, },
{
"type": "com.jme3.light.PointLight",
"methods": [
{
"name": "clone",
"parameterTypes": []
}
]
},
{
"type": "com.jme3.light.SpotLight",
"methods": [
{
"name": "clone",
"parameterTypes": []
}
]
},
{ {
"type": "com.jme3.material.Material", "type": "com.jme3.material.Material",
"methods": [ "methods": [
@@ -482,15 +350,6 @@
} }
] ]
}, },
{
"type": "com.jme3.scene.plugins.gltf.LightsPunctualExtensionLoader",
"methods": [
{
"name": "<init>",
"parameterTypes": []
}
]
},
{ {
"type": "com.jme3.scene.plugins.gltf.UserDataLoader", "type": "com.jme3.scene.plugins.gltf.UserDataLoader",
"methods": [ "methods": [
@@ -578,9 +437,6 @@
{ {
"type": "com.jme3.texture.plugins.AWTLoader" "type": "com.jme3.texture.plugins.AWTLoader"
}, },
{
"type": "com.jme3.texture.plugins.AWTWebpImageLoader"
},
{ {
"type": "com.jme3.texture.plugins.DDSLoader" "type": "com.jme3.texture.plugins.DDSLoader"
}, },
@@ -1230,8 +1086,7 @@
}, },
{ {
"type": "java.nio.DirectFloatBufferU", "type": "java.nio.DirectFloatBufferU",
"allDeclaredFields": true, "allDeclaredFields": true
"unsafeAllocated": true
}, },
{ {
"type": "java.nio.DirectIntBufferU", "type": "java.nio.DirectIntBufferU",
@@ -3152,9 +3007,6 @@
}, },
{ {
"type": "org.ngengine.nostr4j.signer.NostrNIP46Signer" "type": "org.ngengine.nostr4j.signer.NostrNIP46Signer"
},
{
"type": "org.ngengine.store.DataStore$SerializableEntry"
} }
], ],
"jni": [ "jni": [
@@ -3784,12 +3636,6 @@
{ {
"type": "java.lang.System", "type": "java.lang.System",
"methods": [ "methods": [
{
"name": "getProperty",
"parameterTypes": [
"java.lang.String"
]
},
{ {
"name": "load", "name": "load",
"parameterTypes": [ "parameterTypes": [

File diff suppressed because one or more lines are too long

445
platform-web/build.gradle Normal file
View File

@@ -0,0 +1,445 @@
plugins {
id 'com.github.node-gradle.node' version '7.1.0'
id "java"
id "war"
id "org.teavm" version "${teaVmVersion}"
}
import java.security.MessageDigest
import java.nio.file.Files
import java.nio.file.Paths
apply from: "${rootDir}/gradle/libs/class-finder.gradle"
configurations {
withResources {
canBeResolved = true
}
}
node {
download = true
distBaseUrl = null
version = "22.18.0"
}
configurations.configureEach {
exclude group: 'org.ngengine', module: 'jme3-jbullet'
}
dependencies {
implementation "org.teavm:teavm-jso:${teaVmVersion}"
implementation "org.teavm:teavm-jso-apis:${teaVmVersion}"
implementation "org.teavm:teavm-metaprogramming-api:${teaVmVersion}"
implementation "org.teavm:teavm-classlib:${teaVmVersion}"
implementation "org.teavm:teavm-tooling:${teaVmVersion}"
implementation "org.teavm:teavm-core:${teaVmVersion}"
implementation "org.ngengine:nge-platform-teavm:${ngePlatformVersion}"
implementation "org.ngengine:nge-app:${ngeVersion}"
implementation "org.ngengine:jme3-plugins-json:${ngeVersion}"
implementation "org.ngengine:nge-web:${ngeVersion}"
implementation "org.ngengine:nge-web-bullet:${ngeVersion}"
implementation project(':app')
withResources project(':app')
withResources "org.ngengine:nge-platform-teavm:${ngePlatformVersion}"
withResources "org.ngengine:nge-web:${ngeVersion}"
withResources "org.ngengine:nge-web-bullet:${ngeVersion}"
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
sourceSets {
test {
resources {
srcDirs = ['src/test/resources', 'src/main/resources']
}
}
}
def binaryExclusions = [
'**/*.class',
'**/*.dll',
'**/*.so',
'**/*.dylib',
'**/package.html',
"**/*.kotlin_builtins",
"**/build.data",
"**/*.xml",
"**/test*.png",
// '**/*.java'
]
def generateHashes(File dir) {
def hashes = []
Files.walk(Paths.get(dir.toURI())).filter {
Files.isRegularFile(it)
}.forEach { file ->
def relativePath = dir.toPath().relativize(file).toString()
if(relativePath.endsWith(".class")) return;
if(relativePath.endsWith(".java")) return;
def hash = generateSHA256(file.toFile())
def size = file.toFile().length()
hashes << "$hash $size $relativePath"
}
return hashes.join('\n')
}
def generateSHA256(file) {
def messageDigest = MessageDigest.getInstance("SHA-256")
file.eachByte(4096) { bytes, len ->
messageDigest.update(bytes, 0, len)
}
return messageDigest.digest().collect { String.format("%02x", it) }.join()
}
task copyAllResources {
dependsOn configurations.runtimeClasspath.getTaskDependencyFromProjectDependency(true, 'jar')
dependsOn 'jar'
['compileTeavmJava','processTeavmResources','compileJava','processResources']
.each { tn -> if (tasks.findByName(tn) != null) dependsOn tn }
doLast {
def dest = file("${rootDir}/dist/web")
dest.mkdirs()
def safeCopy = { spec ->
copy {
into dest
from spec
exclude(*binaryExclusions)
exclude '**/module-info.class'
includeEmptyDirs = false
duplicatesStrategy = DuplicatesStrategy.INCLUDE
}
}
safeCopy('src/main/resources')
def runtimeFiles = configurations.runtimeClasspath.resolvedConfiguration.lenientConfiguration.files
runtimeFiles.each { f ->
if (!f.exists()) return
if (f.isDirectory()) {
safeCopy(f)
} else if (f.name.endsWith('.jar')) {
safeCopy(project.zipTree(f))
}
}
println "Resource aggregation complete. Total files: " + fileTree(dest).matching { exclude(*binaryExclusions) }.files.size()
def manifestFile = file("${rootDir}/dist/web/manifest.json")
if (manifestFile.exists()) {
def manifest = new groovy.json.JsonSlurper().parseText(manifestFile.text)
manifest.name = Title
manifest.short_name = ShortName
manifestFile.text = groovy.json.JsonOutput.prettyPrint(groovy.json.JsonOutput.toJson(manifest))
println "Updated manifest.json: name=$Title, short_name=$ShortName"
}
def outputDir = file("${rootDir}/dist/web/")
def outputFile = file("${rootDir}/dist/web/resources.index.txt")
outputFile.text = generateHashes(outputDir)
}
}
def generateClassListFile(File outputFile, Collection<String> classes, Closure<String> lineFormatter) {
outputFile.parentFile.mkdirs()
outputFile.text = classes.collect(lineFormatter).join('\n')
println "Generated class list at ${outputFile.absolutePath}"
}
def generateCodeFromTemplate(File outputFile, String template, Map<String, Object> vars) {
outputFile.parentFile.mkdirs()
String result = template
vars.each { key, value ->
result = result.replace("{{$key}}", value.toString())
}
outputFile.text = result
println "Generated code at ${outputFile.absolutePath}"
}
task scanClasspathForTeaVM {
dependsOn configurations.compileClasspath.getTaskDependencyFromProjectDependency(true, 'classes')
doLast {
def scanResults = project.scanClasspathForClasses(project)
def preserveListFile = file("${buildDir}/generated/teaReflectList.txt")
generateClassListFile(preserveListFile, scanResults.classes) { className ->
"**/${className.replace('.', '/')}.java"
}
def reflectionSupplierFile = file("${buildDir}/generated/teaReflect.java")
def template = """private static void initGenerated() {
{{classInitializers}}
}"""
generateCodeFromTemplate(reflectionSupplierFile, template, [
classInitializers: scanResults.reflectionClasses.collect {
" TeaReflectionSupplier.addReflectionClass(\"${it}\");"
}.join('\n')
])
}
}
task updateTeaReflectionSupplier {
dependsOn scanClasspathForTeaVM
doLast {
def reflectionSupplierFile = file("${buildDir}/generated/teaReflect.java")
def teaReflectionSupplierFile = file("${projectDir}/src/main/java/org/ngengine/platform/TeaReflectionSupplier.java")
if (reflectionSupplierFile.exists() && teaReflectionSupplierFile.exists()) {
def content = teaReflectionSupplierFile.text
def initGeneratedContent = reflectionSupplierFile.text
content = content.replaceAll(/(?s)private static void initGenerated\(\)\s*\{.*?\}/, initGeneratedContent)
teaReflectionSupplierFile.text = content
println "Updated TeaReflectionSupplier.java with generated initGenerated() method"
}
}
}
tasks.named('compileJava').configure {
dependsOn 'updateTeaReflectionSupplier'
}
teavm.js {
addedToWebApp = false
mainClass = "org.ngengine.platform.WebLauncher"
obfuscated = false
debugInformation = true
strict= false
outOfProcess=false
// optimization=org.teavm.gradle.api.OptimizationLevel.NONE
sourceMap=true
moduleType = org.teavm.gradle.api.JSModuleType.ES2015
def classesToPreserve=[]
def preserveListFile = file("${buildDir}/generated/teaReflectList.txt")
if (preserveListFile.exists()) {
preserveListFile.readLines().each { line ->
if (line.trim()) {
classesToPreserve.add(line.trim())
}
}
}
def fqcnToPreserve = new LinkedHashSet<String>()
def toFqcn = { File baseDir, File f ->
def rel = f.path.substring(baseDir.path.length() + 1)
rel = rel.replaceAll(/\.java$/, '').replaceAll(/\.class$/, '')
rel.replace('/', '.')
}
rootProject.allprojects.each { prj ->
def ss = prj.extensions.findByName('sourceSets')
def mainSS = ss?.findByName('main')
if (mainSS == null) return
mainSS.java.srcDirs.each { srcDir ->
if (!srcDir.exists()) return
fileTree(srcDir).matching { include classesToPreserve }.forEach { f ->
def fqcn = toFqcn(srcDir, f)
fqcnToPreserve.add(fqcn)
}
}
}
def rtArtifacts = configurations.runtimeClasspath.resolvedConfiguration.lenientConfiguration.files
rtArtifacts.each { artifact ->
if (!artifact.exists()) return
if (artifact.isDirectory()) {
fileTree(artifact).matching { include classesToPreserve.collect { it.replace('.java', '.class') } }.forEach { f ->
def fqcn = toFqcn(artifact, f)
fqcnToPreserve.add(fqcn)
}
} else if (artifact.name.endsWith('.jar')) {
def classFilePatterns = classesToPreserve.collect { it.replace('.java', '.class') }
.collect { it.replace('**/', '') }
try {
def jarFile = new java.util.jar.JarFile(artifact)
def entries = jarFile.entries()
while (entries.hasMoreElements()) {
def entry = entries.nextElement()
if (entry.isDirectory()) continue
def entryName = entry.getName()
if (classFilePatterns.any { pattern ->
entryName.endsWith(pattern) || entryName.matches(pattern.replace("*", ".*"))
}) {
def fqcn = entryName.replaceAll(/\.class$/, '').replace('/', '.')
fqcnToPreserve.add(fqcn)
}
}
jarFile.close()
} catch (Exception e) {
println "WARNING: Could not process JAR file: ${artifact.name} - ${e.message}"
}
}
}
fqcnToPreserve.each {
preservedClasses.add(it)
}
targetFileName = "webapp.js"
}
task buildWebApp {
dependsOn 'compileJava', 'generateJavaScript', 'copyAllResources'
doLast {
def jsDir = file("$buildDir/generated/teavm/js")
def distDir = file("${rootDir}/dist/web")
distDir.mkdirs()
copy {
from jsDir
into distDir
}
println "Copied web app to: $distDir"
}
}
task buildBundledWebApp {
dependsOn buildWebApp
doLast {
def jsDir = file("$rootDir/dist/web")
def bundledJsDir = file("$rootDir/dist/web-bundle")
def bundleIgnoreFile = file("$jsDir/bundle-ignore.txt")
def zipFile = file("$bundledJsDir/ngeapp-bundle.zip")
def configFile = file("$bundledJsDir/ngeapp.json")
bundledJsDir.mkdirs()
// Read ignore patterns from bundle-ignore.txt
def ignorePatterns = []
if (bundleIgnoreFile.exists()) {
bundleIgnoreFile.eachLine { line ->
if (line.trim() && !line.startsWith('//')) ignorePatterns.add(line.trim())
}
println "Found ${ignorePatterns.size()} patterns to exclude from bundle"
} else {
println "Warning: bundle-ignore.txt not found at ${bundleIgnoreFile}. No files will be excluded from the bundle."
}
// Create zip with everything except ignored files
ant.zip(destfile: zipFile) {
fileset(dir: jsDir) {
ignorePatterns.each { pattern ->
if (pattern.endsWith('/')) {
exclude(name: "${pattern}**")
} else {
exclude(name: pattern)
}
}
}
}
// Copy ignored files to bundledjs directory
if (!ignorePatterns.isEmpty()) {
println "Copying excluded files to bundled directory..."
delete fileTree(bundledJsDir).matching { include '**/*' exclude 'ngeapp-bundle.zip', 'ngeapp-config.json' }
fileTree(jsDir).visit { fileDetails ->
if (fileDetails.isDirectory()) return
def relativePath = fileDetails.relativePath.toString()
def matchesPattern = false
for (pattern in ignorePatterns) {
if (pattern.endsWith('/')) {
if (relativePath.startsWith(pattern) || relativePath.startsWith(pattern.substring(0, pattern.length() - 1))) {
matchesPattern = true
break
}
} else {
if (relativePath == pattern) {
matchesPattern = true
break
}
}
}
if (matchesPattern) {
println "Copying excluded file: $relativePath"
copy {
from fileDetails.file
into new File(bundledJsDir, fileDetails.relativePath.parent.toString())
}
}
}
println "Finished copying excluded files"
}
// Calculate hash of zip file
def hash = generateSHA256(zipFile)
// Set bundle in config file
def config = [:]
if (configFile.exists()) {
try {
config = new groovy.json.JsonSlurper().parseText(configFile.text)
println "Updating existing config file: $configFile.path"
} catch (Exception e) {
println "Warning: Could not parse existing config file: $e.message"
config = [:]
}
}
config.bundle = "ngeapp-bundle.zip"
config.bundleHash = hash
configFile.text = groovy.json.JsonOutput.prettyPrint(groovy.json.JsonOutput.toJson(config))
println "Created bundle: $zipFile.path"
println "Bundle hash: $hash"
println "Config written to: $configFile.path"
}
}
task npmCi(type: NpmTask) {
workingDir = file("${projectDir}")
args = ['ci']
}
task runWebApp(type: NpxTask) {
dependsOn buildWebApp
workingDir = file("$rootDir/dist/web")
command = 'http-server'
args = [ '.', '-p', '8000']
}
task runBundledWebApp(type: NpxTask) {
dependsOn buildBundledWebApp
workingDir = file("$rootDir/dist/web-bundle")
command = 'http-server'
args = [ '.', '-p', '8000']
}
task deployWebApp(type: NpxTask) {
dependsOn buildBundledWebApp
dependsOn npmCi
command = 'nostr-deploy-cli'
args = ['deploy','--skip-setup', '-d', "${rootDir}/dist/web-bundle"]
workingDir = file("${projectDir}")
}

2033
platform-web/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,5 @@
{
"devDependencies": {
"nostr-deploy-cli": "^0.7.6"
}
}

View File

@@ -0,0 +1,744 @@
package org.ngengine.platform;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;
import org.teavm.classlib.ReflectionContext;
import org.teavm.classlib.ReflectionSupplier;
import org.teavm.model.ClassReader;
import org.teavm.model.FieldReader;
import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodReader;
import org.teavm.model.ValueType;
public class TeaReflectionSupplier implements ReflectionSupplier {
private static ArrayList<Pattern> regexPatterns = new ArrayList<>();
private static ArrayList<Class<?>> clazzList = new ArrayList<>();
private static ArrayList<String> clazzNameList = new ArrayList<>();
static {
init();
}
private static void initGenerated() {
TeaReflectionSupplier.addReflectionClass("com.jcraft.jzlib.Deflate");
TeaReflectionSupplier.addReflectionClass("com.jcraft.jzlib.GZIPHeader");
TeaReflectionSupplier.addReflectionClass("com.jme3.anim.AnimClip");
TeaReflectionSupplier.addReflectionClass("com.jme3.anim.AnimComposer");
TeaReflectionSupplier.addReflectionClass("com.jme3.anim.AnimLayer");
TeaReflectionSupplier.addReflectionClass("com.jme3.anim.AnimTrack");
TeaReflectionSupplier.addReflectionClass("com.jme3.anim.Armature");
TeaReflectionSupplier.addReflectionClass("com.jme3.anim.ArmatureMask");
TeaReflectionSupplier.addReflectionClass("com.jme3.anim.Joint");
TeaReflectionSupplier.addReflectionClass("com.jme3.anim.MatrixJointModelTransform");
TeaReflectionSupplier.addReflectionClass("com.jme3.anim.MorphControl");
TeaReflectionSupplier.addReflectionClass("com.jme3.anim.MorphTrack");
TeaReflectionSupplier.addReflectionClass("com.jme3.anim.SeparateJointModelTransform");
TeaReflectionSupplier.addReflectionClass("com.jme3.anim.SingleLayerInfluenceMask");
TeaReflectionSupplier.addReflectionClass("com.jme3.anim.SkinningControl");
TeaReflectionSupplier.addReflectionClass("com.jme3.anim.TransformTrack");
TeaReflectionSupplier.addReflectionClass("com.jme3.anim.tween.AbstractTween");
TeaReflectionSupplier.addReflectionClass("com.jme3.anim.tween.Tween");
TeaReflectionSupplier.addReflectionClass("com.jme3.anim.tween.action.Action");
TeaReflectionSupplier.addReflectionClass("com.jme3.anim.tween.action.BaseAction");
TeaReflectionSupplier.addReflectionClass("com.jme3.anim.tween.action.BlendAction");
TeaReflectionSupplier.addReflectionClass("com.jme3.anim.tween.action.BlendableAction");
TeaReflectionSupplier.addReflectionClass("com.jme3.anim.tween.action.ClipAction");
TeaReflectionSupplier.addReflectionClass("com.jme3.anim.util.HasLocalTransform");
TeaReflectionSupplier.addReflectionClass("com.jme3.anim.util.JointModelTransform");
TeaReflectionSupplier.addReflectionClass("com.jme3.animation.AnimControl");
TeaReflectionSupplier.addReflectionClass("com.jme3.animation.Animation");
TeaReflectionSupplier.addReflectionClass("com.jme3.animation.AudioTrack");
TeaReflectionSupplier.addReflectionClass("com.jme3.animation.Bone");
TeaReflectionSupplier.addReflectionClass("com.jme3.animation.BoneTrack");
TeaReflectionSupplier.addReflectionClass("com.jme3.animation.ClonableTrack");
TeaReflectionSupplier.addReflectionClass("com.jme3.animation.CompactArray");
TeaReflectionSupplier.addReflectionClass("com.jme3.animation.CompactFloatArray");
TeaReflectionSupplier.addReflectionClass("com.jme3.animation.CompactQuaternionArray");
TeaReflectionSupplier.addReflectionClass("com.jme3.animation.CompactVector3Array");
TeaReflectionSupplier.addReflectionClass("com.jme3.animation.EffectTrack");
TeaReflectionSupplier.addReflectionClass("com.jme3.animation.Pose");
TeaReflectionSupplier.addReflectionClass("com.jme3.animation.PoseTrack");
TeaReflectionSupplier.addReflectionClass("com.jme3.animation.Skeleton");
TeaReflectionSupplier.addReflectionClass("com.jme3.animation.SkeletonControl");
TeaReflectionSupplier.addReflectionClass("com.jme3.animation.SpatialTrack");
TeaReflectionSupplier.addReflectionClass("com.jme3.animation.Track");
TeaReflectionSupplier.addReflectionClass("com.jme3.animation.TrackInfo");
TeaReflectionSupplier.addReflectionClass("com.jme3.app.StatsView");
TeaReflectionSupplier.addReflectionClass("com.jme3.app.state.ScreenshotAppState");
TeaReflectionSupplier.addReflectionClass("com.jme3.asset.AssetKey");
TeaReflectionSupplier.addReflectionClass("com.jme3.asset.AssetLoader");
TeaReflectionSupplier.addReflectionClass("com.jme3.asset.AssetLocator");
TeaReflectionSupplier.addReflectionClass("com.jme3.asset.AssetProcessor");
TeaReflectionSupplier.addReflectionClass("com.jme3.asset.CloneableAssetProcessor");
TeaReflectionSupplier.addReflectionClass("com.jme3.asset.CloneableSmartAsset");
TeaReflectionSupplier.addReflectionClass("com.jme3.asset.FilterKey");
TeaReflectionSupplier.addReflectionClass("com.jme3.asset.MaterialKey");
TeaReflectionSupplier.addReflectionClass("com.jme3.asset.ModelKey");
TeaReflectionSupplier.addReflectionClass("com.jme3.asset.ShaderNodeDefinitionKey");
TeaReflectionSupplier.addReflectionClass("com.jme3.asset.TextureKey");
TeaReflectionSupplier.addReflectionClass("com.jme3.asset.cache.AssetCache");
TeaReflectionSupplier.addReflectionClass("com.jme3.asset.cache.SimpleAssetCache");
TeaReflectionSupplier.addReflectionClass("com.jme3.asset.cache.WeakRefAssetCache");
TeaReflectionSupplier.addReflectionClass("com.jme3.asset.cache.WeakRefCloneAssetCache");
TeaReflectionSupplier.addReflectionClass("com.jme3.asset.plugins.ClasspathLocator");
TeaReflectionSupplier.addReflectionClass("com.jme3.asset.plugins.FileLocator");
TeaReflectionSupplier.addReflectionClass("com.jme3.asset.plugins.HttpZipLocator");
TeaReflectionSupplier.addReflectionClass("com.jme3.asset.plugins.UrlLocator");
TeaReflectionSupplier.addReflectionClass("com.jme3.asset.plugins.ZipLocator");
TeaReflectionSupplier.addReflectionClass("com.jme3.audio.AudioBuffer");
TeaReflectionSupplier.addReflectionClass("com.jme3.audio.AudioData");
TeaReflectionSupplier.addReflectionClass("com.jme3.audio.AudioKey");
TeaReflectionSupplier.addReflectionClass("com.jme3.audio.AudioNode");
TeaReflectionSupplier.addReflectionClass("com.jme3.audio.AudioStream");
TeaReflectionSupplier.addReflectionClass("com.jme3.audio.BandPassFilter");
TeaReflectionSupplier.addReflectionClass("com.jme3.audio.Filter");
TeaReflectionSupplier.addReflectionClass("com.jme3.audio.HighPassFilter");
TeaReflectionSupplier.addReflectionClass("com.jme3.audio.LowPassFilter");
TeaReflectionSupplier.addReflectionClass("com.jme3.audio.plugins.OGGLoader");
TeaReflectionSupplier.addReflectionClass("com.jme3.audio.plugins.WAVLoader");
TeaReflectionSupplier.addReflectionClass("com.jme3.bounding.BoundingBox");
TeaReflectionSupplier.addReflectionClass("com.jme3.bounding.BoundingSphere");
TeaReflectionSupplier.addReflectionClass("com.jme3.bounding.BoundingVolume");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.animation.BoneLink");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.animation.DacConfiguration");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.animation.DacLinks");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.animation.DynamicAnimControl");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.animation.PhysicsLink");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.animation.RangeOfMotion");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.animation.TorsoLink");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.collision.PhysicsCollisionObject");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.collision.shapes.BoxCollisionShape");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.collision.shapes.CapsuleCollisionShape");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.collision.shapes.CollisionShape");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.collision.shapes.CompoundCollisionShape");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.collision.shapes.ConeCollisionShape");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.collision.shapes.CylinderCollisionShape");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.collision.shapes.GImpactCollisionShape");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.collision.shapes.HeightfieldCollisionShape");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.collision.shapes.HullCollisionShape");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.collision.shapes.MeshCollisionShape");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.collision.shapes.PlaneCollisionShape");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.collision.shapes.SimplexCollisionShape");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.collision.shapes.SphereCollisionShape");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.collision.shapes.infos.ChildCollisionShape");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.control.AbstractPhysicsControl");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.control.BetterCharacterControl");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.control.CharacterControl");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.control.GhostControl");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.control.KinematicRagdollControl");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.control.PhysicsControl");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.control.RigidBodyControl");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.control.VehicleControl");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.debug.AbstractPhysicsDebugControl");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.debug.BulletCharacterDebugControl");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.debug.BulletGhostObjectDebugControl");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.debug.BulletJointDebugControl");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.debug.BulletRigidBodyDebugControl");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.debug.BulletVehicleDebugControl");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.joints.ConeJoint");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.joints.HingeJoint");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.joints.PhysicsJoint");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.joints.Point2PointJoint");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.joints.SixDofJoint");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.joints.SliderJoint");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.objects.PhysicsCharacter");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.objects.PhysicsGhostObject");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.objects.PhysicsRigidBody");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.objects.PhysicsVehicle");
TeaReflectionSupplier.addReflectionClass("com.jme3.bullet.objects.VehicleWheel");
TeaReflectionSupplier.addReflectionClass("com.jme3.cinematic.Cinematic");
TeaReflectionSupplier.addReflectionClass("com.jme3.cinematic.KeyFrame");
TeaReflectionSupplier.addReflectionClass("com.jme3.cinematic.MotionPath");
TeaReflectionSupplier.addReflectionClass("com.jme3.cinematic.TimeLine");
TeaReflectionSupplier.addReflectionClass("com.jme3.cinematic.events.AbstractCinematicEvent");
TeaReflectionSupplier.addReflectionClass("com.jme3.cinematic.events.AnimEvent");
TeaReflectionSupplier.addReflectionClass("com.jme3.cinematic.events.AnimationEvent");
TeaReflectionSupplier.addReflectionClass("com.jme3.cinematic.events.AnimationTrack");
TeaReflectionSupplier.addReflectionClass("com.jme3.cinematic.events.CameraEvent");
TeaReflectionSupplier.addReflectionClass("com.jme3.cinematic.events.CinematicEvent");
TeaReflectionSupplier.addReflectionClass("com.jme3.cinematic.events.MotionEvent");
TeaReflectionSupplier.addReflectionClass("com.jme3.cinematic.events.MotionTrack");
TeaReflectionSupplier.addReflectionClass("com.jme3.cinematic.events.SoundEvent");
TeaReflectionSupplier.addReflectionClass("com.jme3.cinematic.events.SoundTrack");
TeaReflectionSupplier.addReflectionClass("com.jme3.collision.bih.BIHNode");
TeaReflectionSupplier.addReflectionClass("com.jme3.collision.bih.BIHTree");
TeaReflectionSupplier.addReflectionClass("com.jme3.effect.ParticleEmitter");
TeaReflectionSupplier.addReflectionClass("com.jme3.effect.ParticleMesh");
TeaReflectionSupplier.addReflectionClass("com.jme3.effect.ParticlePointMesh");
TeaReflectionSupplier.addReflectionClass("com.jme3.effect.ParticleTriMesh");
TeaReflectionSupplier.addReflectionClass("com.jme3.effect.influencers.DefaultParticleInfluencer");
TeaReflectionSupplier.addReflectionClass("com.jme3.effect.influencers.EmptyParticleInfluencer");
TeaReflectionSupplier.addReflectionClass("com.jme3.effect.influencers.NewtonianParticleInfluencer");
TeaReflectionSupplier.addReflectionClass("com.jme3.effect.influencers.ParticleInfluencer");
TeaReflectionSupplier.addReflectionClass("com.jme3.effect.influencers.RadialParticleInfluencer");
TeaReflectionSupplier.addReflectionClass("com.jme3.effect.shapes.EmitterBoxShape");
TeaReflectionSupplier.addReflectionClass("com.jme3.effect.shapes.EmitterMeshConvexHullShape");
TeaReflectionSupplier.addReflectionClass("com.jme3.effect.shapes.EmitterMeshFaceShape");
TeaReflectionSupplier.addReflectionClass("com.jme3.effect.shapes.EmitterMeshVertexShape");
TeaReflectionSupplier.addReflectionClass("com.jme3.effect.shapes.EmitterPointShape");
TeaReflectionSupplier.addReflectionClass("com.jme3.effect.shapes.EmitterShape");
TeaReflectionSupplier.addReflectionClass("com.jme3.effect.shapes.EmitterSphereShape");
TeaReflectionSupplier.addReflectionClass("com.jme3.environment.EnvironmentProbeControl");
TeaReflectionSupplier.addReflectionClass("com.jme3.environment.util.BoundingSphereDebug");
TeaReflectionSupplier.addReflectionClass("com.jme3.environment.util.Circle");
TeaReflectionSupplier.addReflectionClass("com.jme3.export.JmeImporter");
TeaReflectionSupplier.addReflectionClass("com.jme3.export.NullSavable");
TeaReflectionSupplier.addReflectionClass("com.jme3.export.Savable");
TeaReflectionSupplier.addReflectionClass("com.jme3.export.binary.BinaryImporter");
TeaReflectionSupplier.addReflectionClass("com.jme3.export.binary.BinaryLoader");
TeaReflectionSupplier.addReflectionClass("com.jme3.export.xml.XMLImporter");
TeaReflectionSupplier.addReflectionClass("com.jme3.font.BitmapCharacter");
TeaReflectionSupplier.addReflectionClass("com.jme3.font.BitmapCharacterSet");
TeaReflectionSupplier.addReflectionClass("com.jme3.font.BitmapFont");
TeaReflectionSupplier.addReflectionClass("com.jme3.font.BitmapText");
TeaReflectionSupplier.addReflectionClass("com.jme3.font.BitmapTextPage");
TeaReflectionSupplier.addReflectionClass("com.jme3.font.GlyphParser");
TeaReflectionSupplier.addReflectionClass("com.jme3.font.Kerning");
TeaReflectionSupplier.addReflectionClass("com.jme3.font.Rectangle");
TeaReflectionSupplier.addReflectionClass("com.jme3.font.StringBlock");
TeaReflectionSupplier.addReflectionClass("com.jme3.font.plugins.BitmapFontLoader");
TeaReflectionSupplier.addReflectionClass("com.jme3.input.ChaseCamera");
TeaReflectionSupplier.addReflectionClass("com.jme3.light.AmbientLight");
TeaReflectionSupplier.addReflectionClass("com.jme3.light.DirectionalLight");
TeaReflectionSupplier.addReflectionClass("com.jme3.light.Light");
TeaReflectionSupplier.addReflectionClass("com.jme3.light.LightList");
TeaReflectionSupplier.addReflectionClass("com.jme3.light.LightProbe");
TeaReflectionSupplier.addReflectionClass("com.jme3.light.OrientedBoxProbeArea");
TeaReflectionSupplier.addReflectionClass("com.jme3.light.PointLight");
TeaReflectionSupplier.addReflectionClass("com.jme3.light.ProbeArea");
TeaReflectionSupplier.addReflectionClass("com.jme3.light.SphereProbeArea");
TeaReflectionSupplier.addReflectionClass("com.jme3.light.SpotLight");
TeaReflectionSupplier.addReflectionClass("com.jme3.material.MatParam");
TeaReflectionSupplier.addReflectionClass("com.jme3.material.MatParamOverride");
TeaReflectionSupplier.addReflectionClass("com.jme3.material.MatParamTexture");
TeaReflectionSupplier.addReflectionClass("com.jme3.material.Material");
TeaReflectionSupplier.addReflectionClass("com.jme3.material.MaterialList");
TeaReflectionSupplier.addReflectionClass("com.jme3.material.MaterialProcessor");
TeaReflectionSupplier.addReflectionClass("com.jme3.material.RenderState");
TeaReflectionSupplier.addReflectionClass("com.jme3.material.ShaderGenerationInfo");
TeaReflectionSupplier.addReflectionClass("com.jme3.material.Technique");
TeaReflectionSupplier.addReflectionClass("com.jme3.material.TechniqueDef");
TeaReflectionSupplier.addReflectionClass("com.jme3.material.logic.DefaultTechniqueDefLogic");
TeaReflectionSupplier.addReflectionClass("com.jme3.material.logic.MultiPassLightingLogic");
TeaReflectionSupplier.addReflectionClass("com.jme3.material.logic.SinglePassAndImageBasedLightingLogic");
TeaReflectionSupplier.addReflectionClass("com.jme3.material.logic.SinglePassLightingLogic");
TeaReflectionSupplier.addReflectionClass("com.jme3.material.logic.StaticPassLightingLogic");
TeaReflectionSupplier.addReflectionClass("com.jme3.material.logic.TechniqueDefLogic");
TeaReflectionSupplier.addReflectionClass("com.jme3.material.plugins.J3MLoader");
TeaReflectionSupplier.addReflectionClass("com.jme3.material.plugins.ShaderNodeDefinitionLoader");
TeaReflectionSupplier.addReflectionClass("com.jme3.math.ColorRGBA");
TeaReflectionSupplier.addReflectionClass("com.jme3.math.Line");
TeaReflectionSupplier.addReflectionClass("com.jme3.math.LineSegment");
TeaReflectionSupplier.addReflectionClass("com.jme3.math.Matrix3f");
TeaReflectionSupplier.addReflectionClass("com.jme3.math.Matrix4f");
TeaReflectionSupplier.addReflectionClass("com.jme3.math.Plane");
TeaReflectionSupplier.addReflectionClass("com.jme3.math.Quaternion");
TeaReflectionSupplier.addReflectionClass("com.jme3.math.Ray");
TeaReflectionSupplier.addReflectionClass("com.jme3.math.Rectangle");
TeaReflectionSupplier.addReflectionClass("com.jme3.math.Ring");
TeaReflectionSupplier.addReflectionClass("com.jme3.math.Spline");
TeaReflectionSupplier.addReflectionClass("com.jme3.math.Transform");
TeaReflectionSupplier.addReflectionClass("com.jme3.math.Triangle");
TeaReflectionSupplier.addReflectionClass("com.jme3.math.Vector2f");
TeaReflectionSupplier.addReflectionClass("com.jme3.math.Vector3f");
TeaReflectionSupplier.addReflectionClass("com.jme3.math.Vector4f");
TeaReflectionSupplier.addReflectionClass("com.jme3.network.AbstractMessage");
TeaReflectionSupplier.addReflectionClass("com.jme3.network.Message");
TeaReflectionSupplier.addReflectionClass("com.jme3.network.message.ChannelInfoMessage");
TeaReflectionSupplier.addReflectionClass("com.jme3.network.message.ClientRegistrationMessage");
TeaReflectionSupplier.addReflectionClass("com.jme3.network.message.CompressedMessage");
TeaReflectionSupplier.addReflectionClass("com.jme3.network.message.DisconnectMessage");
TeaReflectionSupplier.addReflectionClass("com.jme3.network.message.GZIPCompressedMessage");
TeaReflectionSupplier.addReflectionClass("com.jme3.network.message.SerializerRegistrationsMessage");
TeaReflectionSupplier.addReflectionClass("com.jme3.network.message.ZIPCompressedMessage");
TeaReflectionSupplier.addReflectionClass("com.jme3.network.rmi.RemoteMethodCallMessage");
TeaReflectionSupplier.addReflectionClass("com.jme3.network.rmi.RemoteMethodReturnMessage");
TeaReflectionSupplier.addReflectionClass("com.jme3.network.rmi.RemoteObjectDefMessage");
TeaReflectionSupplier.addReflectionClass("com.jme3.network.service.rpc.msg.RpcCallMessage");
TeaReflectionSupplier.addReflectionClass("com.jme3.network.service.rpc.msg.RpcResponseMessage");
TeaReflectionSupplier.addReflectionClass("com.jme3.plugins.gson.GsonParser");
TeaReflectionSupplier.addReflectionClass("com.jme3.plugins.json.JsonParser");
TeaReflectionSupplier.addReflectionClass("com.jme3.post.Filter");
TeaReflectionSupplier.addReflectionClass("com.jme3.post.FilterPostProcessor");
TeaReflectionSupplier.addReflectionClass("com.jme3.post.HDRRenderer");
TeaReflectionSupplier.addReflectionClass("com.jme3.post.PreDepthProcessor");
TeaReflectionSupplier.addReflectionClass("com.jme3.post.SceneProcessor");
TeaReflectionSupplier.addReflectionClass("com.jme3.post.filters.BloomFilter");
TeaReflectionSupplier.addReflectionClass("com.jme3.post.filters.CartoonEdgeFilter");
TeaReflectionSupplier.addReflectionClass("com.jme3.post.filters.ColorOverlayFilter");
TeaReflectionSupplier.addReflectionClass("com.jme3.post.filters.ComposeFilter");
TeaReflectionSupplier.addReflectionClass("com.jme3.post.filters.ContrastAdjustmentFilter");
TeaReflectionSupplier.addReflectionClass("com.jme3.post.filters.CrossHatchFilter");
TeaReflectionSupplier.addReflectionClass("com.jme3.post.filters.DepthOfFieldFilter");
TeaReflectionSupplier.addReflectionClass("com.jme3.post.filters.FXAAFilter");
TeaReflectionSupplier.addReflectionClass("com.jme3.post.filters.FadeFilter");
TeaReflectionSupplier.addReflectionClass("com.jme3.post.filters.FogFilter");
TeaReflectionSupplier.addReflectionClass("com.jme3.post.filters.GammaCorrectionFilter");
TeaReflectionSupplier.addReflectionClass("com.jme3.post.filters.KHRToneMapFilter");
TeaReflectionSupplier.addReflectionClass("com.jme3.post.filters.LightScatteringFilter");
TeaReflectionSupplier.addReflectionClass("com.jme3.post.filters.PosterizationFilter");
TeaReflectionSupplier.addReflectionClass("com.jme3.post.filters.RadialBlurFilter");
TeaReflectionSupplier.addReflectionClass("com.jme3.post.filters.SoftBloomFilter");
TeaReflectionSupplier.addReflectionClass("com.jme3.post.filters.ToneMapFilter");
TeaReflectionSupplier.addReflectionClass("com.jme3.post.filters.TranslucentBucketFilter");
TeaReflectionSupplier.addReflectionClass("com.jme3.post.ssao.SSAOFilter");
TeaReflectionSupplier.addReflectionClass("com.jme3.renderer.Camera");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.AssetLinkNode");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.BatchNode");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.CameraNode");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.CollisionData");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.Geometry");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.GeometryGroupNode");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.LightNode");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.Mesh");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.Node");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.SimpleBatchNode");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.Spatial");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.UserData");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.VertexBuffer");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.control.AbstractControl");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.control.BillboardControl");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.control.CameraControl");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.control.Control");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.control.LightControl");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.control.LodControl");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.control.UpdateControl");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.debug.Arrow");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.debug.Grid");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.debug.SkeletonDebugger");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.debug.SkeletonInterBoneWire");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.debug.SkeletonPoints");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.debug.SkeletonWire");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.debug.WireBox");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.debug.WireFrustum");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.debug.WireSphere");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.debug.custom.ArmatureDebugger");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.debug.custom.ArmatureInterJointsWire");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.debug.custom.ArmatureNode");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.debug.custom.JointShape");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.instancing.InstancedGeometry");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.instancing.InstancedNode");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.mesh.MorphTarget");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.plugins.IrBoneWeightIndex");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.plugins.IrVertex");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.plugins.MTLLoader");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.plugins.OBJLoader");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.plugins.fbx.ContentTextureKey");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.plugins.fbx.ContentTextureLocator");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.plugins.fbx.FbxLoader");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.plugins.fbx.SceneKey");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.plugins.fbx.SceneLoader");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.plugins.fbx.SceneWithAnimationLoader");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.plugins.gltf.BinDataKey");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.plugins.gltf.BinLoader");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.plugins.gltf.GlbLoader");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.plugins.gltf.GltfLoader");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.plugins.gltf.GltfModelKey");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.plugins.ogre.MaterialLoader");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.plugins.ogre.MeshLoader");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.plugins.ogre.OgreMeshKey");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.plugins.ogre.SceneLoader");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.plugins.ogre.SceneMeshLoader");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.plugins.ogre.SkeletonLoader");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.plugins.ogre.matext.OgreMaterialKey");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.shape.AbstractBox");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.shape.Box");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.shape.CenterQuad");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.shape.Curve");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.shape.Cylinder");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.shape.Dome");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.shape.Line");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.shape.PQTorus");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.shape.Quad");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.shape.RectangleMesh");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.shape.Sphere");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.shape.StripBox");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.shape.Surface");
TeaReflectionSupplier.addReflectionClass("com.jme3.scene.shape.Torus");
TeaReflectionSupplier.addReflectionClass("com.jme3.shader.Shader");
TeaReflectionSupplier.addReflectionClass("com.jme3.shader.ShaderNode");
TeaReflectionSupplier.addReflectionClass("com.jme3.shader.ShaderNodeDefinition");
TeaReflectionSupplier.addReflectionClass("com.jme3.shader.ShaderNodeVariable");
TeaReflectionSupplier.addReflectionClass("com.jme3.shader.VariableMapping");
TeaReflectionSupplier.addReflectionClass("com.jme3.shader.bufferobject.BufferObject");
TeaReflectionSupplier.addReflectionClass("com.jme3.shader.bufferobject.BufferRegion");
TeaReflectionSupplier.addReflectionClass("com.jme3.shader.plugins.GLSLLoader");
TeaReflectionSupplier.addReflectionClass("com.jme3.shader.plugins.ShaderAssetKey");
TeaReflectionSupplier.addReflectionClass("com.jme3.shadow.AbstractShadowFilter");
TeaReflectionSupplier.addReflectionClass("com.jme3.shadow.AbstractShadowRenderer");
TeaReflectionSupplier.addReflectionClass("com.jme3.shadow.BasicShadowRenderer");
TeaReflectionSupplier.addReflectionClass("com.jme3.shadow.DirectionalLightShadowFilter");
TeaReflectionSupplier.addReflectionClass("com.jme3.shadow.DirectionalLightShadowRenderer");
TeaReflectionSupplier.addReflectionClass("com.jme3.shadow.PointLightShadowFilter");
TeaReflectionSupplier.addReflectionClass("com.jme3.shadow.PointLightShadowRenderer");
TeaReflectionSupplier.addReflectionClass("com.jme3.shadow.PssmShadowFilter");
TeaReflectionSupplier.addReflectionClass("com.jme3.shadow.PssmShadowRenderer");
TeaReflectionSupplier.addReflectionClass("com.jme3.shadow.SpotLightShadowFilter");
TeaReflectionSupplier.addReflectionClass("com.jme3.shadow.SpotLightShadowRenderer");
TeaReflectionSupplier.addReflectionClass("com.jme3.system.AppSettings");
TeaReflectionSupplier.addReflectionClass("com.jme3.system.JmeSystem");
TeaReflectionSupplier.addReflectionClass("com.jme3.system.JmeSystemDelegate");
TeaReflectionSupplier.addReflectionClass("com.jme3.terrain.GeoMap");
TeaReflectionSupplier.addReflectionClass("com.jme3.terrain.geomipmap.LODGeomap");
TeaReflectionSupplier.addReflectionClass("com.jme3.terrain.geomipmap.MultiTerrainLodControl");
TeaReflectionSupplier.addReflectionClass("com.jme3.terrain.geomipmap.NormalRecalcControl");
TeaReflectionSupplier.addReflectionClass("com.jme3.terrain.geomipmap.TerrainGrid");
TeaReflectionSupplier.addReflectionClass("com.jme3.terrain.geomipmap.TerrainGridLodControl");
TeaReflectionSupplier.addReflectionClass("com.jme3.terrain.geomipmap.TerrainGridTileLoader");
TeaReflectionSupplier.addReflectionClass("com.jme3.terrain.geomipmap.TerrainLodControl");
TeaReflectionSupplier.addReflectionClass("com.jme3.terrain.geomipmap.TerrainPatch");
TeaReflectionSupplier.addReflectionClass("com.jme3.terrain.geomipmap.TerrainQuad");
TeaReflectionSupplier.addReflectionClass("com.jme3.terrain.geomipmap.grid.AssetTileLoader");
TeaReflectionSupplier.addReflectionClass("com.jme3.terrain.geomipmap.grid.FractalTileLoader");
TeaReflectionSupplier.addReflectionClass("com.jme3.terrain.geomipmap.grid.ImageTileLoader");
TeaReflectionSupplier.addReflectionClass("com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator");
TeaReflectionSupplier.addReflectionClass("com.jme3.terrain.geomipmap.lodcalc.LodCalculator");
TeaReflectionSupplier.addReflectionClass("com.jme3.terrain.geomipmap.lodcalc.LodThreshold");
TeaReflectionSupplier.addReflectionClass("com.jme3.terrain.geomipmap.lodcalc.PerspectiveLodCalculator");
TeaReflectionSupplier.addReflectionClass("com.jme3.terrain.geomipmap.lodcalc.SimpleLodThreshold");
TeaReflectionSupplier.addReflectionClass("com.jme3.texture.FrameBuffer");
TeaReflectionSupplier.addReflectionClass("com.jme3.texture.Image");
TeaReflectionSupplier.addReflectionClass("com.jme3.texture.Texture");
TeaReflectionSupplier.addReflectionClass("com.jme3.texture.Texture2D");
TeaReflectionSupplier.addReflectionClass("com.jme3.texture.Texture3D");
TeaReflectionSupplier.addReflectionClass("com.jme3.texture.TextureArray");
TeaReflectionSupplier.addReflectionClass("com.jme3.texture.TextureCubeMap");
TeaReflectionSupplier.addReflectionClass("com.jme3.texture.TextureProcessor");
TeaReflectionSupplier.addReflectionClass("com.jme3.texture.plugins.DDSLoader");
TeaReflectionSupplier.addReflectionClass("com.jme3.texture.plugins.PFMLoader");
TeaReflectionSupplier.addReflectionClass("com.jme3.texture.plugins.SVGTextureKey");
TeaReflectionSupplier.addReflectionClass("com.jme3.texture.plugins.TGALoader");
TeaReflectionSupplier.addReflectionClass("com.jme3.texture.plugins.ktx.KTXLoader");
TeaReflectionSupplier.addReflectionClass("com.jme3.ui.Picture");
TeaReflectionSupplier.addReflectionClass("com.jme3.util.BufferAllocator");
TeaReflectionSupplier.addReflectionClass("com.jme3.util.IntMap");
TeaReflectionSupplier.addReflectionClass("com.jme3.util.ListMap");
TeaReflectionSupplier.addReflectionClass("com.jme3.util.NativeObject");
TeaReflectionSupplier.addReflectionClass("com.jme3.util.PrimitiveAllocator");
TeaReflectionSupplier.addReflectionClass("com.jme3.util.ReflectionAllocator");
TeaReflectionSupplier.addReflectionClass("com.jme3.util.SafeArrayList");
TeaReflectionSupplier.addReflectionClass("com.jme3.util.clone.JmeCloneable");
TeaReflectionSupplier.addReflectionClass("com.jme3.util.res.DefaultResourceLoader");
TeaReflectionSupplier.addReflectionClass("com.jme3.util.res.ResourceLoader");
TeaReflectionSupplier.addReflectionClass("com.jme3.util.struct.StructStd140BufferObject");
TeaReflectionSupplier.addReflectionClass("com.jme3.water.ReflectionProcessor");
TeaReflectionSupplier.addReflectionClass("com.jme3.water.SimpleWaterProcessor");
TeaReflectionSupplier.addReflectionClass("com.jme3.water.WaterFilter");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.ActionButton");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.Button");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.Checkbox");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.Container");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.GridPanel");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.Insets3f");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.Label");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.ListBox");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.OptionPanel");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.Panel");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.PasswordField");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.ProgressBar");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.RollupPanel");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.Selector");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.Slider");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.Spinner");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.TabbedPanel");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.TextField");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.component.AbstractGuiComponent");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.component.BorderLayout");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.component.BoxLayout");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.component.DynamicInsetsComponent");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.component.IconComponent");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.component.InsetsComponent");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.component.QuadBackgroundComponent");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.component.SpringGridLayout");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.component.TbtQuadBackgroundComponent");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.component.Text2d");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.component.TextComponent");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.component.TextEntryComponent");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.core.AbstractNodeControl");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.core.CommandMap");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.core.GuiComponent");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.core.GuiControl");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.core.GuiLayout");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.core.GuiMaterial");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.core.LightingMaterialAdapter");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.core.UnshadedMaterialAdapter");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.dnd.DragAndDropControl");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.effect.EffectControl");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.event.CursorEventControl");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.event.MouseEventControl");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.focus.DefaultFocusTraversalControl");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.geom.DMesh");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.geom.MBox");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.geom.TbtQuad");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.list.DefaultCellRenderer");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.style.Attributes");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.style.ContainsSelector");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.style.ElementId");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.style.ElementSelector");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.style.Selector");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.style.StyleTree");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.style.Styles");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.text.DefaultDocumentModel");
TeaReflectionSupplier.addReflectionClass("com.simsilica.lemur.value.DefaultValueRenderer");
TeaReflectionSupplier.addReflectionClass("de.jarnbjo.vorbis.Floor1");
TeaReflectionSupplier.addReflectionClass("org.ngengine.ads.ImmersiveAdComponent");
TeaReflectionSupplier.addReflectionClass("org.ngengine.ads.ImmersiveAdControl");
TeaReflectionSupplier.addReflectionClass("org.ngengine.auth.Auth");
TeaReflectionSupplier.addReflectionClass("org.ngengine.auth.AuthConfig");
TeaReflectionSupplier.addReflectionClass("org.ngengine.auth.AuthSelectionWindow");
TeaReflectionSupplier.addReflectionClass("org.ngengine.auth.AuthStrategy");
TeaReflectionSupplier.addReflectionClass("org.ngengine.auth.Nip46AuthStrategy");
TeaReflectionSupplier.addReflectionClass("org.ngengine.auth.nip07.Nip07Auth");
TeaReflectionSupplier.addReflectionClass("org.ngengine.auth.nip07.Nip07AuthWindow");
TeaReflectionSupplier.addReflectionClass("org.ngengine.auth.nip46.Nip46Auth");
TeaReflectionSupplier.addReflectionClass("org.ngengine.auth.nip46.Nip46AuthWindow");
TeaReflectionSupplier.addReflectionClass("org.ngengine.auth.nip46.Nip46ChallengeWindow");
TeaReflectionSupplier.addReflectionClass("org.ngengine.auth.nsec.NsecAuth");
TeaReflectionSupplier.addReflectionClass("org.ngengine.auth.nsec.NsecAuthWindow");
TeaReflectionSupplier.addReflectionClass("org.ngengine.auth.stored.StoredAuthSelectionWindow");
TeaReflectionSupplier.addReflectionClass("org.ngengine.components.Component");
TeaReflectionSupplier.addReflectionClass("org.ngengine.components.StallingComponent");
TeaReflectionSupplier.addReflectionClass("org.ngengine.components.fragments.AppFragment");
TeaReflectionSupplier.addReflectionClass("org.ngengine.components.fragments.AssetLoadingFragment");
TeaReflectionSupplier.addReflectionClass("org.ngengine.components.fragments.AsyncAssetLoadingFragment");
TeaReflectionSupplier.addReflectionClass("org.ngengine.components.fragments.Fragment");
TeaReflectionSupplier.addReflectionClass("org.ngengine.components.fragments.GuiViewPortFragment");
TeaReflectionSupplier.addReflectionClass("org.ngengine.components.fragments.InputHandlerFragment");
TeaReflectionSupplier.addReflectionClass("org.ngengine.components.fragments.LogicFragment");
TeaReflectionSupplier.addReflectionClass("org.ngengine.components.fragments.MainViewPortFragment");
TeaReflectionSupplier.addReflectionClass("org.ngengine.components.fragments.RenderFragment");
TeaReflectionSupplier.addReflectionClass("org.ngengine.demo.adc.CharacterComponent");
TeaReflectionSupplier.addReflectionClass("org.ngengine.demo.adc.HudComponent");
TeaReflectionSupplier.addReflectionClass("org.ngengine.demo.adc.LoadingScreenComponent");
TeaReflectionSupplier.addReflectionClass("org.ngengine.demo.adc.MapComponent");
TeaReflectionSupplier.addReflectionClass("org.ngengine.demo.adc.PhysicsComponent");
TeaReflectionSupplier.addReflectionClass("org.ngengine.demo.adc.PostprocessingComponent");
TeaReflectionSupplier.addReflectionClass("org.ngengine.demo.adc.SoundComponent");
TeaReflectionSupplier.addReflectionClass("org.ngengine.export.CollectionSavableWrapper");
TeaReflectionSupplier.addReflectionClass("org.ngengine.export.MapSavableWrapper");
TeaReflectionSupplier.addReflectionClass("org.ngengine.export.Nip46MetadataSavableWrapper");
TeaReflectionSupplier.addReflectionClass("org.ngengine.export.Nip46SignerSavableWrapper");
TeaReflectionSupplier.addReflectionClass("org.ngengine.export.NostrEventSavableWrapper");
TeaReflectionSupplier.addReflectionClass("org.ngengine.export.NostrKeyPairSavableWrapper");
TeaReflectionSupplier.addReflectionClass("org.ngengine.export.NostrPrivateKeySavableWrapper");
TeaReflectionSupplier.addReflectionClass("org.ngengine.export.NostrPublicKeySavableWrapper");
TeaReflectionSupplier.addReflectionClass("org.ngengine.export.NostrRelayInfoSavableWrapper");
TeaReflectionSupplier.addReflectionClass("org.ngengine.export.NumberSavableWrapper");
TeaReflectionSupplier.addReflectionClass("org.ngengine.export.SavableWrapper");
TeaReflectionSupplier.addReflectionClass("org.ngengine.export.StringSavableWrapper");
TeaReflectionSupplier.addReflectionClass("org.ngengine.gui.components.NAspectPreservingQuadBackground");
TeaReflectionSupplier.addReflectionClass("org.ngengine.gui.components.NButton");
TeaReflectionSupplier.addReflectionClass("org.ngengine.gui.components.NIconButton");
TeaReflectionSupplier.addReflectionClass("org.ngengine.gui.components.NLabel");
TeaReflectionSupplier.addReflectionClass("org.ngengine.gui.components.NLoadingSpinner");
TeaReflectionSupplier.addReflectionClass("org.ngengine.gui.components.NQrViewer");
TeaReflectionSupplier.addReflectionClass("org.ngengine.gui.components.NSVGIcon");
TeaReflectionSupplier.addReflectionClass("org.ngengine.gui.components.NTextInput");
TeaReflectionSupplier.addReflectionClass("org.ngengine.gui.components.NVSpacer");
TeaReflectionSupplier.addReflectionClass("org.ngengine.gui.components.containers.NColumn");
TeaReflectionSupplier.addReflectionClass("org.ngengine.gui.components.containers.NContainer");
TeaReflectionSupplier.addReflectionClass("org.ngengine.gui.components.containers.NMultiPageList");
TeaReflectionSupplier.addReflectionClass("org.ngengine.gui.components.containers.NPanel");
TeaReflectionSupplier.addReflectionClass("org.ngengine.gui.components.containers.NRow");
TeaReflectionSupplier.addReflectionClass("org.ngengine.gui.qr.BitBuffer");
TeaReflectionSupplier.addReflectionClass("org.ngengine.gui.win.NToast");
TeaReflectionSupplier.addReflectionClass("org.ngengine.gui.win.NWindow");
TeaReflectionSupplier.addReflectionClass("org.ngengine.gui.win.NWindowManagerComponent");
TeaReflectionSupplier.addReflectionClass("org.ngengine.gui.win.std.NConfirmDialogWindow");
TeaReflectionSupplier.addReflectionClass("org.ngengine.gui.win.std.NErrorWindow");
TeaReflectionSupplier.addReflectionClass("org.ngengine.gui.win.std.NHud");
TeaReflectionSupplier.addReflectionClass("org.ngengine.lnurl.LnUrlPayerData");
TeaReflectionSupplier.addReflectionClass("org.ngengine.network.Lobby");
TeaReflectionSupplier.addReflectionClass("org.ngengine.network.LocalLobby");
TeaReflectionSupplier.addReflectionClass("org.ngengine.network.protocol.messages.BinaryMessage");
TeaReflectionSupplier.addReflectionClass("org.ngengine.network.protocol.messages.ByteDataMessage");
TeaReflectionSupplier.addReflectionClass("org.ngengine.network.protocol.messages.ClassRegistrationAckMessage");
TeaReflectionSupplier.addReflectionClass("org.ngengine.network.protocol.messages.CompressedMessage");
TeaReflectionSupplier.addReflectionClass("org.ngengine.network.protocol.messages.TextDataMessage");
TeaReflectionSupplier.addReflectionClass("org.ngengine.network.protocol.messages.TextMessage");
TeaReflectionSupplier.addReflectionClass("org.ngengine.nostr4j.NostrFilter");
TeaReflectionSupplier.addReflectionClass("org.ngengine.nostr4j.NostrRelayInfo");
TeaReflectionSupplier.addReflectionClass("org.ngengine.nostr4j.NostrRelayLifecycleManager");
TeaReflectionSupplier.addReflectionClass("org.ngengine.nostr4j.NostrRelaySubManager");
TeaReflectionSupplier.addReflectionClass("org.ngengine.nostr4j.event.NostrEvent");
TeaReflectionSupplier.addReflectionClass("org.ngengine.nostr4j.event.SignedNostrEvent");
TeaReflectionSupplier.addReflectionClass("org.ngengine.nostr4j.event.UnsignedNostrEvent");
TeaReflectionSupplier.addReflectionClass("org.ngengine.nostr4j.keypair.NostrKey");
TeaReflectionSupplier.addReflectionClass("org.ngengine.nostr4j.keypair.NostrKeyPair");
TeaReflectionSupplier.addReflectionClass("org.ngengine.nostr4j.keypair.NostrPrivateKey");
TeaReflectionSupplier.addReflectionClass("org.ngengine.nostr4j.keypair.NostrPublicKey");
TeaReflectionSupplier.addReflectionClass("org.ngengine.nostr4j.listeners.NostrRelayComponent");
TeaReflectionSupplier.addReflectionClass("org.ngengine.nostr4j.nip01.Nip01UserMetadataFilter");
TeaReflectionSupplier.addReflectionClass("org.ngengine.nostr4j.nip05.Nip05Nip46Data");
TeaReflectionSupplier.addReflectionClass("org.ngengine.nostr4j.nip46.BunkerUrl");
TeaReflectionSupplier.addReflectionClass("org.ngengine.nostr4j.nip46.Nip46AppMetadata");
TeaReflectionSupplier.addReflectionClass("org.ngengine.nostr4j.nip46.NostrconnectUrl");
TeaReflectionSupplier.addReflectionClass("org.ngengine.nostr4j.nip50.NostrSearchFilter");
TeaReflectionSupplier.addReflectionClass("org.ngengine.nostr4j.rtc.turn.NostrTURNSettings");
TeaReflectionSupplier.addReflectionClass("org.ngengine.nostr4j.signer.NostrKeyPairSigner");
TeaReflectionSupplier.addReflectionClass("org.ngengine.nostr4j.signer.NostrNIP07Signer");
TeaReflectionSupplier.addReflectionClass("org.ngengine.nostr4j.signer.NostrNIP46Signer");
TeaReflectionSupplier.addReflectionClass("org.ngengine.nostr4j.signer.NostrSigner");
TeaReflectionSupplier.addReflectionClass("org.ngengine.nostrads.protocol.AdBidEvent");
TeaReflectionSupplier.addReflectionClass("org.ngengine.nostrads.protocol.AdBidFilter");
TeaReflectionSupplier.addReflectionClass("org.ngengine.nostrads.protocol.AdEvent");
TeaReflectionSupplier.addReflectionClass("org.ngengine.nostrads.protocol.negotiation.AdAcceptOfferEvent");
TeaReflectionSupplier.addReflectionClass("org.ngengine.nostrads.protocol.negotiation.AdBailEvent");
TeaReflectionSupplier.addReflectionClass("org.ngengine.nostrads.protocol.negotiation.AdNegotiationEvent");
TeaReflectionSupplier.addReflectionClass("org.ngengine.nostrads.protocol.negotiation.AdOfferEvent");
TeaReflectionSupplier.addReflectionClass("org.ngengine.nostrads.protocol.negotiation.AdPaymentRequestEvent");
TeaReflectionSupplier.addReflectionClass("org.ngengine.nostrads.protocol.negotiation.AdPayoutEvent");
TeaReflectionSupplier.addReflectionClass("org.ngengine.nostrads.protocol.negotiation.AdPowNegotiationEvent");
TeaReflectionSupplier.addReflectionClass("org.ngengine.platform.RTCSettings");
TeaReflectionSupplier.addReflectionClass("org.ngengine.player.PlayerManagerComponent");
TeaReflectionSupplier.addReflectionClass("org.ngengine.web.context.HeapAllocator");
TeaReflectionSupplier.addReflectionClass("org.ngengine.web.context.WebSystem");
TeaReflectionSupplier.addReflectionClass("org.ngengine.web.filesystem.WebImageLoader");
TeaReflectionSupplier.addReflectionClass("org.ngengine.web.filesystem.WebLocator");
TeaReflectionSupplier.addReflectionClass("org.ngengine.web.filesystem.WebResourceLoader");
TeaReflectionSupplier.addReflectionClass("org.ngengine.web.json.TeaJSONParser");
}
private static void init() {
initGenerated();
}
public static void addReflectionClass(Class<?> c) {
clazzList.add(c);
}
public static void addReflectionClass(String className) {
clazzNameList.add(className);
}
public static void addRegex(String regex) {
regexPatterns.add(Pattern.compile(regex));
}
public TeaReflectionSupplier() {
System.out.println("TeaReflectionSupplier initialized");
}
@Override
public Collection<String> getAccessibleFields(ReflectionContext context, String className) {
Set<String> fields = new HashSet<>();
ClassReader cls = context.getClassSource().get(className);
if (cls == null) {
return Collections.emptyList();
}
try {
Class<?> clazz = context.getClassLoader().loadClass(className);
if (cls != null) {
if (canHaveReflection(clazz)) {
for (FieldReader field : cls.getFields()) {
String name = field.getName();
fields.add(name);
}
}
}
} catch (ClassNotFoundException e) {
new RuntimeException(e);
}
return fields;
}
private boolean isWhitelistedType(ReflectionContext context, ValueType t) throws ClassNotFoundException{
boolean canHaveReflection = false;
if (t instanceof ValueType.Void) {
return true;
}
if (t instanceof ValueType.Array) {
ValueType.Array a = (ValueType.Array) t;
t = a.getItemType();
}
if (t instanceof ValueType.Object) {
ValueType.Object obj = (ValueType.Object) t;
if(obj.getClassName().startsWith("java.lang")) {
canHaveReflection = true;
} else {
Class<?> sc = context.getClassLoader().loadClass(obj.getClassName());
canHaveReflection = canHaveReflection(sc);
}
} else if (t instanceof ValueType.Primitive) {
canHaveReflection = true;
}
return canHaveReflection;
}
@Override
public Collection<MethodDescriptor> getAccessibleMethods(ReflectionContext context, String className) {
Set<MethodDescriptor> methods = new HashSet<>();
ClassReader cls = context.getClassSource().get(className);
if (cls == null) {
return Collections.emptyList();
}
try {
Class<?> clazz = context.getClassLoader().loadClass(className);
if (canHaveReflection(clazz)) {
Collection<? extends MethodReader> methods2 = cls.getMethods();
int constructors = 0;
for (MethodReader method : methods2) {
boolean isConstructor = method.getName().equals("<init>");
if(isConstructor) {
constructors++;
}
boolean canHaveReflection = true;
if (canHaveReflection && !isConstructor) {
ValueType t = method.getResultType();
canHaveReflection = isWhitelistedType(context, t);
}
if (!canHaveReflection) {
continue;
}
MethodDescriptor descriptor = method.getDescriptor();
methods.add(descriptor);
}
}
} catch (ClassNotFoundException e) {
new RuntimeException(e);
}
return methods;
}
private boolean canHaveReflection(Class<?> clazz) {
for (Class<?> c : clazzList) {
if (c.isAssignableFrom(clazz) || c.equals(clazz)) {
return true;
}
}
String className = clazz.getName();
for(String cn : clazzNameList) {
if(cn.equals(className)) {
return true;
}
}
for (Pattern pattern : regexPatterns) {
if (pattern.matcher(className).matches()) {
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,21 @@
package org.ngengine.platform;
import org.ngengine.NGEApplication.NGEAppRunner;
import org.ngengine.app.Main;
import org.ngengine.platform.teavm.TeaVMPlatform;
import org.ngengine.web.context.WebSystem;
import com.jme3.system.JmeSystem;
public class WebLauncher {
public static void main(String[] args) {
new Thread(()->{ // must be a thread to run in a suspendable context in teavm
NGEPlatform.set(new TeaVMPlatform());
JmeSystem.setSystemDelegate(new WebSystem());
NGEAppRunner runner = Main.main(args);
runner.start();
}).start();
}
}

View File

@@ -0,0 +1 @@
org.ngengine.platform.TeaReflectionSupplier

View File

@@ -0,0 +1,13 @@
{
"name": "Nostr Game Engine Web App",
"short_name": "ngewebapp",
"start_url": "index.html",
"display": "standalone",
"icons": [{
"src": "logo.webp",
"sizes": "4096x4096",
"type": "image/webp"
}],
"background_color": "#08020c",
"theme_color": "#08020c"
}

View File

@@ -0,0 +1,11 @@
# Global logging level - set to a higher threshold
.level = INFO
# Handler (console or file)
handlers = java.util.logging.ConsoleHandler
java.util.logging.ConsoleHandler.level = INFO
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
# Set FINEST logging only for org.ngengine.nostr4j and its children
org.ngengine.nostr4j.level = INFO
org.ngengine.level = INFO

View File

@@ -5,9 +5,11 @@ pluginManagement {
google() google()
mavenCentral() mavenCentral()
gradlePluginPortal() gradlePluginPortal()
maven { url = uri("https://teavm.org/maven/repository") }
mavenLocal()
} }
plugins { plugins {
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.9.0' id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0"
id("com.android.application") version '8.12.2' apply false id("com.android.application") version '8.12.2' apply false
id("com.android.library") version '8.12.2' apply false id("com.android.library") version '8.12.2' apply false
id("org.jetbrains.kotlin.android") version "2.1.20" apply false id("org.jetbrains.kotlin.android") version "2.1.20" apply false
@@ -16,8 +18,19 @@ pluginManagement {
plugins {
id("org.gradle.toolchains.foojay-resolver") version "1.0.0"
}
toolchainManagement {
jvm {
javaRepositories {
repository("foojay") {
resolverClass = org.gradle.toolchains.foojay.FoojayToolchainResolver
}
}
}
}
dependencyResolutionManagement { dependencyResolutionManagement {
repositories { repositories {
@@ -27,18 +40,58 @@ dependencyResolutionManagement {
maven { maven {
url = uri("https://central.sonatype.com/repository/maven-snapshots") url = uri("https://central.sonatype.com/repository/maven-snapshots")
} }
maven { url = uri("https://teavm.org/maven/repository") }
ivy {
name = "Node.js"
setUrl("https://nodejs.org/dist/")
patternLayout {
artifact("v[revision]/[artifact](-v[revision]-[classifier]).[ext]")
}
metadataSources {
artifact()
}
content {
includeModule("org.nodejs", "node")
}
}
} }
} }
if (!gradle.hasProperty('ext')) {
rootProject.name = settings.projectName gradle.ext {}
include('app')
if(withDesktopPlatform) {
include('platform-desktop')
} }
// if (withAndroidPlatform) { gradle.beforeProject { p ->
// include('platform-android') if (p == p.rootProject) {
// } p.tasks.register("cleanDist", org.gradle.api.tasks.Delete) {
delete p.layout.projectDirectory.dir("dist")
}
p.gradle.projectsEvaluated {
def cleanTask = p.tasks.findByName("clean") ?: p.tasks.register("clean")
cleanTask.configure { dependsOn("cleanDist") }
}
}
}
// import json properties
apply from: "${rootDir}/gradle/libs/props.gradle"
def ngeConfig = gradle.ext.loadNgeAppProperties("${rootDir}/app/src/main/resources/ngeapp.json")
gradle.beforeProject { p ->
ngeConfig.each { k, v -> p.ext.set(k, v) }
if (ngeConfig.Version) p.version = ngeConfig.Version.toString()
if (ngeConfig.Namespace) p.group = ngeConfig.Namespace.toString()
}
print("Build with config: "+ngeConfig)
rootProject.name = ngeConfig.ShortName
include('app')
// ENABLE DESKTOP BUILD TARGET
include('platform-desktop')
// ENABLE ANDROID BUILD TARGET
include('platform-android')
// ENABLE WEB BUILD TARGET
include('platform-web')