From c5cb63af37cd8931bbbc2e1e915650c3dc3bf27a Mon Sep 17 00:00:00 2001 From: Alexander Heistermann Date: Fri, 10 Jul 2026 14:46:53 -0500 Subject: [PATCH] Remove Java AI bindings (#3059) Unused maintenance burden --- AI/Interfaces/Java/CMakeLists.txt | 661 --------- AI/Interfaces/Java/VERSION | 1 - AI/Interfaces/Java/bin/ant.properties | 21 - AI/Interfaces/Java/bin/build.xml | 258 ---- AI/Interfaces/Java/bin/jni_wrappCallback.awk | 573 -------- AI/Interfaces/Java/bin/jni_wrappCommands.awk | 192 --- AI/Interfaces/Java/bin/jni_wrappEvents.awk | 570 -------- ...native_createCallbackFPInitializations.awk | 53 - .../native_createCallbackFunctionImpls.awk | 124 -- .../Java/bin/native_wrappCallback.awk | 290 ---- .../Java/bin/native_wrappCommands.awk | 384 ----- AI/Interfaces/Java/data/InterfaceInfo.lua | 51 - AI/Interfaces/Java/data/jvm.properties | 86 -- AI/Interfaces/Java/pom.xml | 49 - .../src/main/java/com/springrts/ai/Util.java | 55 - .../Java/src/main/native/InterfaceDefines.h | 23 - .../Java/src/main/native/InterfaceExport.c | 157 --- .../Java/src/main/native/InterfaceExport.h | 61 - .../Java/src/main/native/JavaBridge.c | 1219 ---------------- .../Java/src/main/native/JavaBridge.h | 73 - AI/Interfaces/Java/src/main/native/JniUtil.c | 288 ---- AI/Interfaces/Java/src/main/native/JniUtil.h | 80 -- .../Java/src/main/native/JvmLocater.h | 53 - .../Java/src/main/native/JvmLocater_common.c | 188 --- .../Java/src/main/native/JvmLocater_common.h | 38 - .../Java/src/main/native/JvmLocater_linux.c | 266 ---- .../Java/src/main/native/JvmLocater_windows.c | 181 --- AI/Skirmish/NullJavaAI/CMakeLists.txt | 4 - AI/Skirmish/NullJavaAI/VERSION | 1 - .../NullJavaAI/bin/ant.dependent.properties | 36 - .../NullJavaAI/bin/ant.independent.properties | 29 - AI/Skirmish/NullJavaAI/bin/build.xml | 279 ---- AI/Skirmish/NullJavaAI/data/AIInfo.lua | 53 - AI/Skirmish/NullJavaAI/data/AIOptions.lua | 15 - AI/Skirmish/NullJavaAI/manifest.mf | 2 - .../NullJavaAI/src/nulljavaai/NullJavaAI.java | 187 --- AI/Skirmish/NullOOJavaAI/CMakeLists.txt | 4 - AI/Skirmish/NullOOJavaAI/VERSION | 1 - .../NullOOJavaAI/bin/ant.dependent.properties | 40 - .../bin/ant.independent.properties | 30 - AI/Skirmish/NullOOJavaAI/bin/build.xml | 342 ----- AI/Skirmish/NullOOJavaAI/data/AIInfo.lua | 53 - AI/Skirmish/NullOOJavaAI/data/AIOptions.lua | 15 - AI/Skirmish/NullOOJavaAI/manifest.mf | 2 - .../main/java/nulloojavaai/NullOOJavaAI.java | 320 ----- AI/Wrappers/JavaOO/CMakeLists.txt | 379 ----- AI/Wrappers/JavaOO/bin/ant.properties | 26 - AI/Wrappers/JavaOO/bin/build.xml | 211 --- AI/Wrappers/JavaOO/bin/wrappCallback.awk | 1241 ----------------- AI/Wrappers/JavaOO/bin/wrappEvents.awk | 627 --------- AI/Wrappers/JavaOO/jlib/vecmath-src.jar | Bin 183017 -> 0 bytes AI/Wrappers/JavaOO/jlib/vecmath.jar | Bin 310293 -> 0 bytes AI/Wrappers/JavaOO/pom.xml | 66 - .../java/com/springrts/ai/oo/AIEvent.java | 28 - .../java/com/springrts/ai/oo/AIException.java | 35 - .../java/com/springrts/ai/oo/AIFloat3.java | 118 -- .../springrts/ai/oo/CallbackAIException.java | 59 - .../com/springrts/ai/oo/EventAIException.java | 85 -- CMakeLists.txt | 7 +- rts/build/cmake/UtilJava.cmake | 101 -- 60 files changed, 1 insertion(+), 10390 deletions(-) delete mode 100644 AI/Interfaces/Java/CMakeLists.txt delete mode 100644 AI/Interfaces/Java/VERSION delete mode 100644 AI/Interfaces/Java/bin/ant.properties delete mode 100644 AI/Interfaces/Java/bin/build.xml delete mode 100755 AI/Interfaces/Java/bin/jni_wrappCallback.awk delete mode 100755 AI/Interfaces/Java/bin/jni_wrappCommands.awk delete mode 100755 AI/Interfaces/Java/bin/jni_wrappEvents.awk delete mode 100755 AI/Interfaces/Java/bin/native_createCallbackFPInitializations.awk delete mode 100755 AI/Interfaces/Java/bin/native_createCallbackFunctionImpls.awk delete mode 100755 AI/Interfaces/Java/bin/native_wrappCallback.awk delete mode 100755 AI/Interfaces/Java/bin/native_wrappCommands.awk delete mode 100644 AI/Interfaces/Java/data/InterfaceInfo.lua delete mode 100644 AI/Interfaces/Java/data/jvm.properties delete mode 100644 AI/Interfaces/Java/pom.xml delete mode 100644 AI/Interfaces/Java/src/main/java/com/springrts/ai/Util.java delete mode 100644 AI/Interfaces/Java/src/main/native/InterfaceDefines.h delete mode 100644 AI/Interfaces/Java/src/main/native/InterfaceExport.c delete mode 100644 AI/Interfaces/Java/src/main/native/InterfaceExport.h delete mode 100644 AI/Interfaces/Java/src/main/native/JavaBridge.c delete mode 100644 AI/Interfaces/Java/src/main/native/JavaBridge.h delete mode 100644 AI/Interfaces/Java/src/main/native/JniUtil.c delete mode 100644 AI/Interfaces/Java/src/main/native/JniUtil.h delete mode 100644 AI/Interfaces/Java/src/main/native/JvmLocater.h delete mode 100644 AI/Interfaces/Java/src/main/native/JvmLocater_common.c delete mode 100644 AI/Interfaces/Java/src/main/native/JvmLocater_common.h delete mode 100644 AI/Interfaces/Java/src/main/native/JvmLocater_linux.c delete mode 100644 AI/Interfaces/Java/src/main/native/JvmLocater_windows.c delete mode 100644 AI/Skirmish/NullJavaAI/CMakeLists.txt delete mode 100644 AI/Skirmish/NullJavaAI/VERSION delete mode 100644 AI/Skirmish/NullJavaAI/bin/ant.dependent.properties delete mode 100644 AI/Skirmish/NullJavaAI/bin/ant.independent.properties delete mode 100644 AI/Skirmish/NullJavaAI/bin/build.xml delete mode 100644 AI/Skirmish/NullJavaAI/data/AIInfo.lua delete mode 100644 AI/Skirmish/NullJavaAI/data/AIOptions.lua delete mode 100755 AI/Skirmish/NullJavaAI/manifest.mf delete mode 100644 AI/Skirmish/NullJavaAI/src/nulljavaai/NullJavaAI.java delete mode 100644 AI/Skirmish/NullOOJavaAI/CMakeLists.txt delete mode 100644 AI/Skirmish/NullOOJavaAI/VERSION delete mode 100644 AI/Skirmish/NullOOJavaAI/bin/ant.dependent.properties delete mode 100644 AI/Skirmish/NullOOJavaAI/bin/ant.independent.properties delete mode 100644 AI/Skirmish/NullOOJavaAI/bin/build.xml delete mode 100644 AI/Skirmish/NullOOJavaAI/data/AIInfo.lua delete mode 100644 AI/Skirmish/NullOOJavaAI/data/AIOptions.lua delete mode 100755 AI/Skirmish/NullOOJavaAI/manifest.mf delete mode 100644 AI/Skirmish/NullOOJavaAI/src/main/java/nulloojavaai/NullOOJavaAI.java delete mode 100644 AI/Wrappers/JavaOO/CMakeLists.txt delete mode 100644 AI/Wrappers/JavaOO/bin/ant.properties delete mode 100644 AI/Wrappers/JavaOO/bin/build.xml delete mode 100755 AI/Wrappers/JavaOO/bin/wrappCallback.awk delete mode 100755 AI/Wrappers/JavaOO/bin/wrappEvents.awk delete mode 100644 AI/Wrappers/JavaOO/jlib/vecmath-src.jar delete mode 100755 AI/Wrappers/JavaOO/jlib/vecmath.jar delete mode 100644 AI/Wrappers/JavaOO/pom.xml delete mode 100644 AI/Wrappers/JavaOO/src/main/java/com/springrts/ai/oo/AIEvent.java delete mode 100644 AI/Wrappers/JavaOO/src/main/java/com/springrts/ai/oo/AIException.java delete mode 100644 AI/Wrappers/JavaOO/src/main/java/com/springrts/ai/oo/AIFloat3.java delete mode 100644 AI/Wrappers/JavaOO/src/main/java/com/springrts/ai/oo/CallbackAIException.java delete mode 100644 AI/Wrappers/JavaOO/src/main/java/com/springrts/ai/oo/EventAIException.java delete mode 100644 rts/build/cmake/UtilJava.cmake diff --git a/AI/Interfaces/Java/CMakeLists.txt b/AI/Interfaces/Java/CMakeLists.txt deleted file mode 100644 index 9220868084e..00000000000 --- a/AI/Interfaces/Java/CMakeLists.txt +++ /dev/null @@ -1,661 +0,0 @@ -### Java AI Interface -# -# Global variables set in this file: -# * BUILD_Java_AIINTERFACE -# * Java_AIINTERFACE_VERS -# * Java_AIINTERFACE_TARGET -# -# Functions and macros defined in this file: -# * configure_java_skirmish_ai -# - -#enable_language(Java) - - -################################################################################ -### BEGIN: MACROS_AND_FUNCTIONS -# Define macros and functions to be used in this file and by Java Skirmish AIs - -# includes rts/build/cmake/UtilJava.cmake -include(UtilJava) - -# Java Skirmish AI configuration macro. -# This will be called from Java AIs at AI/Skirmish/*/CMakeLists.txt. -macro (configure_java_skirmish_ai wrapperNames) - # Assemble meta data - set(myDir "${CMAKE_CURRENT_SOURCE_DIR}") - get_last_path_part(dirName ${myDir}) - set(myName "${dirName}") - set(myJarFile "SkirmishAI") - set(myBinJarFile "${myJarFile}.jar") - set(mySrcJarFile "${myJarFile}-src.jar") - set(myJLibDir "${myDir}/data/jlib") - get_version_plus_dep_file(myVersion myVersionDepFile) - set(myTarget "${myName}") - set(myInstLibsDir "${SKIRMISH_AI_LIBS}/${myName}/${myVersion}") - set(myInstDataDir "${SKIRMISH_AI_DATA}/${myName}/${myVersion}") - # CMAKE_CURRENT_BINARY_DIR: .../spring-build-dir/AI/Skirmish/${myName} - set(myBuildDir "${CMAKE_CURRENT_BINARY_DIR}") - - # Check if the user wants to compile the AI - set(BUILD_THIS_SKIRMISHAI FALSE) - if (BUILD_Java_AIINTERFACE AND NOT myName MATCHES "${AI_EXCLUDE_REGEX}") - set(BUILD_THIS_SKIRMISHAI TRUE) - endif (BUILD_Java_AIINTERFACE AND NOT myName MATCHES "${AI_EXCLUDE_REGEX}") - if (NOT BUILD_THIS_SKIRMISHAI) - message("warning: ${myName} Skirmish AI will not be built!") - endif (NOT BUILD_THIS_SKIRMISHAI) - - # Compile and install - if (BUILD_THIS_SKIRMISHAI) - file(MAKE_DIRECTORY "${myBuildDir}/jlib") - - set(configString "default") - skirmish_ai_message(STATUS "Found Skirmish AI: ${myName} ${myVersion} (config: ${configString})") - - # Assemble project generated targets (and their libraries) we depend on - set(myDependTargets "${Java_AIINTERFACE_TARGET}") - set(myDependLibFiles "${Java_AIINTERFACE_JAR_BIN}") - foreach (wrapperName ${wrapperNames}) - set(myDependTargets ${myDependTargets} "${${wrapperName}_AIWRAPPER_TARGET}") - set(myDependLibFiles ${myDependLibFiles} "${${wrapperName}_AIWRAPPER_JAR_BIN}") - endforeach (wrapperName) - set_source_files_properties(${myDependLibFiles} PROPERTIES GENERATED TRUE) - - # find java source root - if (EXISTS "${myDir}/src/main/java") - # default Maven source dir - set(mySourceDir "${myDir}/src/main/java") - elseif (EXISTS "${myDir}/src") - # simple java source dir path - set(mySourceDir "${myDir}/src") - else (EXISTS "${myDir}/src/main/java") - message(SEND_ERROR "No sources dir found for Skirmish AI: ${myName}") - endif (EXISTS "${myDir}/src/main/java") - - # Create a list of all the AIs source files (for compiling) - file(GLOB_RECURSE mySources RELATIVE "${mySourceDir}" FOLLOW_SYMLINKS "${mySourceDir}/*.java") - # Create a list of all the AIs source files (for dependency tracking) - file(GLOB_RECURSE mySourcesDep FOLLOW_SYMLINKS "${mySourceDir}/*.java") - - set_source_files_properties("${myBuildDir}/${myBinJarFile}" PROPERTIES GENERATED TRUE) - set_source_files_properties("${myBuildDir}/${mySrcJarFile}" PROPERTIES GENERATED TRUE) - - - # If main Java package is "my.ai.pkg", this has to be set to "my". - get_first_sub_dir_name(firstSrcSubDir ${mySourceDir}) - set(myJavaPkgFirstPart "${firstSrcSubDir}") - - # Assemble additional meta data - set(myBinaryTarget "${myTarget}-BIN") - set(mySourceTarget "${myTarget}-SRC") - set(myJavaBuildDir "${myBuildDir}/classes") - - add_custom_target(${myBinaryTarget} - DEPENDS "${myBuildDir}/${myBinJarFile}") - add_dependencies(${myBinaryTarget} ${myDependTargets}) - - add_custom_target(${mySourceTarget} - DEPENDS "${myBuildDir}/${mySrcJarFile}") - - add_custom_target(${myTarget} ALL DEPENDS ${myVersionDepFile}) - add_dependencies(${myTarget} ${myBinaryTarget} ${mySourceTarget}) - - # Create our full Java class-path - create_classpath(myJavaLibs ${myJLibDir}) - concat_classpaths(myClassPath "${CLASSPATH_Java_AIINTERFACE}" "${myJavaLibs}") - foreach (wrapperName ${wrapperNames}) - concat_classpaths(myClassPath "${myClassPath}" "${${wrapperName}_AIWRAPPER_JAR_CLASSPATH}") - endforeach (wrapperName) - - # Locate the manifest file - find_manifest_file("${myDir}" myManifestFile) - if (myManifestFile) - set(myBinJarArgs "cmf" "${myManifestFile}") - else (myManifestFile) - set(myBinJarArgs "cf") - endif (myManifestFile) - - # Write list of source files to an arg-file - set(mySrcArgFile "${myBuildDir}/sourceFiles.txt") - if (EXISTS "${mySrcArgFile}") - file(REMOVE "${mySrcArgFile}") - endif (EXISTS "${mySrcArgFile}") - set(mySrcArgFile "${myBuildDir}/sourceFiles.txt") - foreach (srcFile ${mySources}) - file(APPEND "${mySrcArgFile}" "\"${srcFile}\"\n") - endforeach (srcFile) - - # Compile and pack the library - add_custom_command( - OUTPUT - "${myBuildDir}/${myBinJarFile}" - DEPENDS - ${myDependLibFiles} - ${mySourcesDep} - COMMAND "${CMAKE_COMMAND}" - "-E" "remove_directory" "${myJavaBuildDir}" - COMMAND "${CMAKE_COMMAND}" - "-E" "make_directory" "${myJavaBuildDir}" - COMMAND "${Java_JAVAC_EXECUTABLE}" - "${JAVA_COMPILE_FLAG_CONDITIONAL}" - "-Xlint:deprecation" - "-cp" "${myClassPath}" - "-d" "${myJavaBuildDir}" - "@${mySrcArgFile}" - COMMAND "${Java_JAR_EXECUTABLE}" - ${myBinJarArgs} "${myBuildDir}/${myBinJarFile}" - "-C" "${myJavaBuildDir}" "${myJavaPkgFirstPart}" - WORKING_DIRECTORY - "${mySourceDir}" - COMMENT - " ${myTarget}: Compiling sources and packing library ${myBinJarFile}" VERBATIM - ) - - # Pack the sources - add_custom_command( - OUTPUT - "${myBuildDir}/${mySrcJarFile}" - COMMAND "${Java_JAR_EXECUTABLE}" - "cf" "${myBuildDir}/${mySrcJarFile}" - "-C" "${mySourceDir}" "${myJavaPkgFirstPart}" - DEPENDS - ${mySourcesDeps} - WORKING_DIRECTORY - "${mySourceDir}" - COMMENT - " ${myTarget}: Creating sources archive ${mySrcJarFile}" VERBATIM - ) - - # Install the data files - install(DIRECTORY "${myDir}/data/" DESTINATION ${myInstDataDir}) - # Install the library - install(FILES "${myBuildDir}/${myBinJarFile}" DESTINATION ${myInstDataDir}) - # Install the sources archive (optional) - install(FILES "${myBuildDir}/${mySrcJarFile}" DESTINATION ${myInstDataDir}/jlib OPTIONAL) - - # Install files generated/downloaded during buildtime - install(DIRECTORY "${myBuildDir}/jlib/" DESTINATION ${myInstDataDir}/jlib) - if (EXISTS "${myBuildDir}/resources") - install(DIRECTORY "${myBuildDir}/resources/" DESTINATION ${myInstDataDir}/resources) - endif (EXISTS "${myBuildDir}/resources") - if (EXISTS "${myBuildDir}/config") - install(DIRECTORY "${myBuildDir}/config/" DESTINATION ${myInstDataDir}/config) - endif (EXISTS "${myBuildDir}/config") - if (EXISTS "${myBuildDir}/script") - install(DIRECTORY "${myBuildDir}/script/" DESTINATION ${myInstDataDir}/script) - endif (EXISTS "${myBuildDir}/script") - - # Install special script and config files - if (EXISTS "${myDir}/src/main/groovy") - install(DIRECTORY "${myDir}/src/main/groovy/" DESTINATION ${myInstDataDir}/script) - endif (EXISTS "${myDir}/src/main/groovy") - if (EXISTS "${myDir}/src/main/ruby") - install(DIRECTORY "${myDir}/src/main/ruby/" DESTINATION ${myInstDataDir}/script) - endif (EXISTS "${myDir}/src/main/ruby") - if (EXISTS "${myDir}/src/main/bsh") - install(DIRECTORY "${myDir}/src/main/bsh/" DESTINATION ${myInstDataDir}/script) - endif (EXISTS "${myDir}/src/main/bsh") - if (EXISTS "${myDir}/src/main/config") - install(DIRECTORY "${myDir}/src/main/config/" DESTINATION ${myInstDataDir}/config) - endif (EXISTS "${myDir}/src/main/config") - - # Install jars of wrappers - foreach (wrapperName ${wrapperNames}) - # Install the wrappers main jar - install(FILES "${${wrapperName}_AIWRAPPER_JAR_BIN}" DESTINATION ${myInstDataDir}/jlib) - set(wrapperJLibDir "${CMAKE_SOURCE_DIR}/AI/Wrappers/${wrapperName}/jlib") - # Install the wrappers java libs, if there are any - if (EXISTS ${wrapperJLibDir}) - install(DIRECTORY "${wrapperJLibDir}/" DESTINATION ${myInstDataDir}/jlib) - endif (EXISTS ${wrapperJLibDir}) - endforeach (wrapperName) - endif (BUILD_THIS_SKIRMISHAI) -endmacro (configure_java_skirmish_ai wrapperNames) - - -### END: MACROS_AND_FUNCTIONS -################################################################################ - - -set(myName "Java") -set(myDir "${CMAKE_CURRENT_SOURCE_DIR}") -set(mySourceDirRel "src/main") -set(myJavaSourceDirRel "src/main/java") -set(myNativeSourceDirRel "src/main/native") -set(myPkgFirstPart "com") -set(myPkg "${myPkgFirstPart}/springrts/ai") - - -# Check if the user wants to compile the interface -if ("${AI_TYPES}" STREQUAL "ALL" OR "${AI_TYPES}" STREQUAL "JAVA") - set(AI_TYPES_JAVA TRUE) -else ("${AI_TYPES}" STREQUAL "ALL" OR "${AI_TYPES}" STREQUAL "JAVA") - set(AI_TYPES_JAVA FALSE) -endif ("${AI_TYPES}" STREQUAL "ALL" OR "${AI_TYPES}" STREQUAL "JAVA") - -if (AI_TYPES_JAVA AND myName MATCHES "${AI_EXCLUDE_REGEX}") - set(AI_TYPES_JAVA FALSE) -endif (AI_TYPES_JAVA AND myName MATCHES "${AI_EXCLUDE_REGEX}") - - -# Look for dependencies, but only if the user wants to build the interface -if (AI_TYPES_JAVA) - if (NOT JAVA_FOUND) - find_package(Java REQUIRED COMPONENTS Development) - endif (NOT JAVA_FOUND) - if (MINGW) - set (JNI_FOUND TRUE) - else (MINGW) - # this hack is needed for FindJNI.cmake to use the JDK we want it to use, - # as otherwise it might not find one at all (eg. in the case of OpenJDK) - if ( NOT ENV{JAVA_HOME} AND JAVA_HOME ) - set(ENV{JAVA_HOME} "${JAVA_HOME}") - endif ( NOT ENV{JAVA_HOME} AND JAVA_HOME ) - find_package(JNI REQUIRED) - if (JAVA_INCLUDE_PATH) - set (JNI_FOUND TRUE) - include_directories(${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH2} ${JNI_INCLUDE_DIRS}) - else (JAVA_INCLUDE_PATH) - set (JNI_FOUND FALSE) - message(WARNING "No Java includes found!") - endif (JAVA_INCLUDE_PATH) - endif (MINGW) -endif (AI_TYPES_JAVA) - - -# Check if dependencies of the interface are met -if (AI_TYPES_JAVA AND JNI_FOUND AND JAVA_FOUND AND EXISTS ${myDir} AND EXISTS ${myDir}/bin AND AWK_FOUND AND NOT myName MATCHES "${AI_EXCLUDE_REGEX}") - set_global(BUILD_${myName}_AIINTERFACE TRUE) -else (AI_TYPES_JAVA AND JNI_FOUND AND JAVA_FOUND AND EXISTS ${myDir} AND EXISTS ${myDir}/bin AND AWK_FOUND AND NOT myName MATCHES "${AI_EXCLUDE_REGEX}") - set_global(BUILD_${myName}_AIINTERFACE FALSE) - message("warning: Java AI Interface will not be built!") -endif (AI_TYPES_JAVA AND JNI_FOUND AND JAVA_FOUND AND EXISTS ${myDir} AND EXISTS ${myDir}/bin AND AWK_FOUND AND NOT myName MATCHES "${AI_EXCLUDE_REGEX}") - - -# Build -if (BUILD_${myName}_AIINTERFACE) - get_version_plus_dep_file(myVersion myVersionDepFile) - set(myTarget "${myName}-AIInterface") - set(myGenTarget "${myTarget}-generateSources") - set(myNativeTarget "${myTarget}-native") - set(myJavaTarget "${myTarget}-java") - set(myInstLibsDir ${AI_INTERFACES_LIBS}/${myName}/${myVersion}) - set(myInstDataDir ${AI_INTERFACES_DATA}/${myName}/${myVersion}) - set(myJavaSourceDirRel "${mySourceDirRel}/java") - set(myNativeSourceDirRel "${mySourceDirRel}/native") - make_absolute(mySourceDir "${myDir}" "${mySourceDirRel}") - make_absolute(myNativeSourceDir "${myDir}" "${myNativeSourceDirRel}") - make_absolute(myJavaSourceDir "${myDir}" "${myJavaSourceDirRel}") - - ai_interface_message(STATUS "Found AI Interface: ${myTarget} ${myVersion}") - - set_global(${myName}_AIINTERFACE_VERS ${myVersion}) - set_global(${myName}_AIINTERFACE_TARGET ${myTarget}) - set_global(${myName}_AIINTERFACE_TARGET_GENERATE_SOURCES ${myGenTarget}) - - - # Init some vars - # -------------- - set(myAwkScriptsDir "${myDir}/bin") - set(commonAwkScriptsDir "${CMAKE_SOURCE_DIR}/AI/Wrappers/CUtils/bin") - set(myBuildDir "${CMAKE_CURRENT_BINARY_DIR}") - set(springSourceDir "${PROJECT_SOURCE_DIR}") - set(springAIInterfaceSourceDir "${springSourceDir}/rts/ExternalAI/Interface") - set(myJavaBuildDir "${myBuildDir}/classes") - set(myJarFile "AIInterface") - set(myBinJarFile "${myJarFile}.jar") - set(mySrcJarFile "${myJarFile}-src.jar") - set(myGeneratedSourceDir "${myBuildDir}/src-generated/main") - set(myJavaGeneratedSourceDir "${myGeneratedSourceDir}/java") - set(myNativeGeneratedSourceDir "${myGeneratedSourceDir}/native") - set(myJLibDir "${myDir}/data/jlib") - create_classpath(myJavaLibs ${myJLibDir}) - set(myClassPath ".${PATH_DELIM_H}${myJavaLibs}${PATH_DELIM_H}${myJavaSourceDir}") - - # Used by Java Skirmish AIs - set_global(SOURCE_ROOT_${myName}_AIINTERFACE "${myDir}") - set_global(BUILD_ROOT_${myName}_AIINTERFACE "${myBuildDir}") - set_global(${myName}_AIINTERFACE_JAR_BIN "${myBuildDir}/${myBinJarFile}") - set_global(${myName}_AIINTERFACE_JAR_SRC "${myBuildDir}/${mySrcJarFile}") - set_global(${myName}_AIINTERFACE_POM "${myBuildDir}/pom-generated.xml") - set_global(CLASSPATH_${myName}_AIINTERFACE "${myJavaLibs}${PATH_DELIM_H}${myBuildDir}/${myBinJarFile}") - set_global(JAVA_SRC_DIR_${myName}_AIINTERFACE "${myJavaSourceDir}") - set_global(JAVA_GEN_SRC_DIR_${myName}_AIINTERFACE "${myJavaGeneratedSourceDir}") - - - # Generate sources - # ---------------- - - set(commonAwkScriptArgs - "-v" "SPRING_SOURCE_DIR=${springSourceDir}" - "-v" "INTERFACE_SOURCE_DIR=${myJavaSourceDir}" - "-v" "GENERATED_SOURCE_DIR=${myGeneratedSourceDir}" - "-v" "NATIVE_GENERATED_SOURCE_DIR=${myNativeGeneratedSourceDir}" - "-v" "JAVA_GENERATED_SOURCE_DIR=${myJavaGeneratedSourceDir}" - "-f" "${commonAwkScriptsDir}/common.awk" - "-f" "${commonAwkScriptsDir}/commonDoc.awk" - ) - - # A CMake Custom Target will always be built. - # from CMake docu: - # "add_custom_target is ALWAYS CONSIDERED OUT OF DATE" - - # Stub file for dependency tracking - set(myGeneratedSourceDirStubFile "${CMAKE_CURRENT_BINARY_DIR}/myGeneratedSourceDir.stub") - set_source_files_properties(${myGeneratedSourceDirStubFile} PROPERTIES GENERATED TRUE) - - - # source file lists (static and generated) - - set(myNativeSources - "${myNativeSourceDir}/InterfaceExport.c" - "${myNativeSourceDir}/JavaBridge.c" - "${myNativeSourceDir}/JniUtil.c" - "${myNativeSourceDir}/JvmLocater_common.c" - "${myNativeSourceDir}/JvmLocater_linux.c" - "${myNativeSourceDir}/JvmLocater_windows.c" - ) - set(myNativeGeneratedSources - "${myNativeGeneratedSourceDir}/CallbackFunctionPointerBridge.c" - "${myNativeGeneratedSourceDir}/CallbackJNIBridge.c" - "${myNativeGeneratedSourceDir}/EventsJNIBridge.c" - ) - set(myNativeGeneratedHeaders - "${myNativeGeneratedSourceDir}/CallbackFunctionPointerBridge.h" - "${myNativeGeneratedSourceDir}/CallbackJNIBridge.h" - "${myNativeGeneratedSourceDir}/EventsJNIBridge.h" - ) - - set(myJavaSources - "${myJavaSourceDir}/${myPkg}/Util.java" - ) - set(myJavaGeneratedSources - "${myJavaGeneratedSourceDir}/${myPkg}/AI.java" - "${myJavaGeneratedSourceDir}/${myPkg}/AbstractAI.java" - "${myJavaGeneratedSourceDir}/${myPkg}/AICallback.java" - "${myJavaGeneratedSourceDir}/${myPkg}/JniAICallback.java" - "${myJavaGeneratedSourceDir}/${myPkg}/Enumerations.java" - ) - - set(myGeneratedSources - ${myNativeGeneratedSources} - ${myNativeGeneratedHeaders} - ${myJavaGeneratedSources} - ) - set_source_files_properties(${myGeneratedSources} PROPERTIES GENERATED TRUE) - - - # remove all files in the generates sources dir, - # that are not generated sources (of this build) - file(GLOB_RECURSE allGeneratedSrcFiles "${myGeneratedSourceDir}/*") - foreach (genFile ${allGeneratedSrcFiles}) - list(FIND myGeneratedSources "${genFile}" isInList) - if (${isInList} EQUAL -1) - file(REMOVE "${genFile}") - endif () - endforeach (genFile) - - #cleanup generated dir if some input file changed - add_custom_command( - OUTPUT - ${myGeneratedSourceDirStubFile} - COMMAND "${CMAKE_COMMAND}" - "-E" "remove_directory" "${myGeneratedSourceDir}" - COMMAND "${CMAKE_COMMAND}" - "-E" "make_directory" "${myNativeGeneratedSourceDir}" - COMMAND "${CMAKE_COMMAND}" - "-E" "make_directory" "${myJavaGeneratedSourceDir}/${myPkg}" - COMMAND "${CMAKE_COMMAND}" - "-E" "touch" "${myGeneratedSourceDirStubFile}" - DEPENDS - "${commonAwkScriptsDir}/common.awk" - "${commonAwkScriptsDir}/commonDoc.awk" - "${myAwkScriptsDir}/native_wrappCallback.awk" - "${myAwkScriptsDir}/native_wrappCommands.awk" - "${myAwkScriptsDir}/jni_wrappCallback.awk" - "${myAwkScriptsDir}/jni_wrappCommands.awk" - "${myAwkScriptsDir}/jni_wrappEvents.awk" - "${springAIInterfaceSourceDir}/SSkirmishAICallback.h" - "${springAIInterfaceSourceDir}/AISCommands.h" - "${springAIInterfaceSourceDir}/AISEvents.h" - WORKING_DIRECTORY - "${myAwkScriptsDir}" - COMMENT - " ${myTarget}: Cleanup & create generated source directories" VERBATIM - ) - - # 1. & 2. Wrapp Callback (native->native) - add_custom_command( - OUTPUT - "${myNativeGeneratedSourceDir}/CallbackFunctionPointerBridge.h" - "${myNativeGeneratedSourceDir}/CallbackFunctionPointerBridge.c" - COMMAND "${AWK_BIN}" - ${commonAwkScriptArgs} - "-f" "${myAwkScriptsDir}/native_wrappCallback.awk" - "${springAIInterfaceSourceDir}/SSkirmishAICallback.h" - COMMAND "${AWK_BIN}" - ${commonAwkScriptArgs} - "-f" "${myAwkScriptsDir}/native_wrappCommands.awk" - "${springAIInterfaceSourceDir}/AISCommands.h" - DEPENDS - "${myGeneratedSourceDirStubFile}" - "${commonAwkScriptsDir}/common.awk" - "${commonAwkScriptsDir}/commonDoc.awk" - "${myAwkScriptsDir}/native_wrappCallback.awk" - "${myAwkScriptsDir}/native_wrappCommands.awk" - "${springAIInterfaceSourceDir}/SSkirmishAICallback.h" - "${springAIInterfaceSourceDir}/AISCommands.h" - WORKING_DIRECTORY - "${myAwkScriptsDir}" - COMMENT - " ${myTarget}: Generating native callback wrapper sources" VERBATIM - ) - - # 3. Wrapp AI Callback (native-JNI->Java) - add_custom_command( - OUTPUT - "${myNativeGeneratedSourceDir}/CallbackJNIBridge.h" - "${myNativeGeneratedSourceDir}/CallbackJNIBridge.c" - "${myJavaGeneratedSourceDir}/${myPkg}/AICallback.java" - "${myJavaGeneratedSourceDir}/${myPkg}/JniAICallback.java" - COMMAND "${AWK_BIN}" - ${commonAwkScriptArgs} - "-f" "${myAwkScriptsDir}/jni_wrappCallback.awk" - "${myNativeGeneratedSourceDir}/CallbackFunctionPointerBridge.h" - DEPENDS - "${myGeneratedSourceDirStubFile}" - "${commonAwkScriptsDir}/common.awk" - "${commonAwkScriptsDir}/commonDoc.awk" - "${myAwkScriptsDir}/jni_wrappCallback.awk" - "${myNativeGeneratedSourceDir}/CallbackFunctionPointerBridge.h" - WORKING_DIRECTORY - "${myAwkScriptsDir}" - COMMENT - " ${myTarget}: Generating JNI callback wrapper sources" VERBATIM - ) - - # 4. Wrapp AI Events (native-JNI->Java) - add_custom_command( - OUTPUT - "${myNativeGeneratedSourceDir}/EventsJNIBridge.h" - "${myNativeGeneratedSourceDir}/EventsJNIBridge.c" - "${myJavaGeneratedSourceDir}/${myPkg}/AI.java" - "${myJavaGeneratedSourceDir}/${myPkg}/AbstractAI.java" - COMMAND "${AWK_BIN}" - ${commonAwkScriptArgs} - "-f" "${myAwkScriptsDir}/jni_wrappEvents.awk" - "${springAIInterfaceSourceDir}/AISEvents.h" - DEPENDS - "${myGeneratedSourceDirStubFile}" - "${commonAwkScriptsDir}/common.awk" - "${commonAwkScriptsDir}/commonDoc.awk" - "${myAwkScriptsDir}/jni_wrappEvents.awk" - "${springAIInterfaceSourceDir}/AISEvents.h" - WORKING_DIRECTORY - "${myAwkScriptsDir}" - COMMENT - " ${myTarget}: Generating JNI events wrapper sources" VERBATIM - ) - # 5. Wrapp ENUMS - - add_custom_command( - OUTPUT - "${myJavaGeneratedSourceDir}/${myPkg}/Enumerations.java" - COMMAND "${AWK_BIN}" - ${commonAwkScriptArgs} - "-f" "${myAwkScriptsDir}/jni_wrappCommands.awk" - "${springAIInterfaceSourceDir}/AISCommands.h" - DEPENDS - "${myGeneratedSourceDirStubFile}" - "${commonAwkScriptsDir}/common.awk" - "${commonAwkScriptsDir}/commonDoc.awk" - "${myAwkScriptsDir}/jni_wrappCommands.awk" - "${springAIInterfaceSourceDir}/AISCommands.h" - WORKING_DIRECTORY - "${myAwkScriptsDir}" - COMMENT - " ${myTarget}: Generating enums wrapper sources" VERBATIM - ) - add_custom_target(${myGenTarget} DEPENDS ${myGeneratedSources}) - add_dependencies(generateSources ${myGenTarget}) - - # Locate the manifest file - find_manifest_file("${myDir}" myManifestFile) - if (myManifestFile) - set(myBinJarArgs "cmf" "${myManifestFile}") - else (myManifestFile) - set(myBinJarArgs "cf") - endif (myManifestFile) - - # Build the native part - # --------------------- - if (MINGW) - # It is important that this is used instead of the one - # from the installed JDK, as the jni_md.h is in here too, - # and this file contains OS (win32) specific information. - include_directories(BEFORE ${MINGWLIBS}/include/java) - endif (MINGW) - include_directories(BEFORE "${rts}/lib/streflop" "${myNativeSourceDir}" "${myNativeGeneratedSourceDir}") - add_library(${myNativeTarget} MODULE ${myNativeSources} ${myNativeGeneratedSources} ${ai_common_SRC} ${myVersionDepFile}) - add_dependencies(${myNativeTarget} generateVersionFiles) - target_link_libraries(${myNativeTarget} CUtils streflop) - set_target_properties(${myNativeTarget} PROPERTIES COMPILE_FLAGS "-DUSING_STREFLOP") - set_target_properties(${myNativeTarget} PROPERTIES OUTPUT_NAME "AIInterface") - fix_lib_name(${myNativeTarget}) - - - # Build the java part - # ------------------- - - # Write list of source files to an arg-file - set(mySrcArgFile "${myBuildDir}/sourceFiles.txt") - if (EXISTS "${mySrcArgFile}") - file(REMOVE "${mySrcArgFile}") - endif (EXISTS "${mySrcArgFile}") - foreach (srcFile ${myJavaSources} ${myJavaGeneratedSources}) - file(APPEND "${mySrcArgFile}" "\"${srcFile}\"\n") - endforeach (srcFile) - - add_custom_command( - OUTPUT - "${myBuildDir}/${myBinJarFile}" - COMMAND "${CMAKE_COMMAND}" - "-E" "remove_directory" "${myJavaBuildDir}" - COMMAND "${CMAKE_COMMAND}" - "-E" "make_directory" "${myJavaBuildDir}" - COMMAND "${Java_JAVAC_EXECUTABLE}" ARGS - "${JAVA_COMPILE_FLAG_CONDITIONAL}" - "-Xlint:deprecation" - "-cp" "${myClassPath}" - "-d" "${myJavaBuildDir}" - "@${mySrcArgFile}" - COMMAND "${Java_JAR_EXECUTABLE}" ARGS - ${myBinJarArgs} "${myBuildDir}/${myBinJarFile}" - "-C" "${myJavaBuildDir}" "${myPkgFirstPart}" - DEPENDS - ${myJavaSources} - # Using the native target reduces parallelism slightly - # (less then 1s per build => negliable), but prevetns multiple - # execution of the source generating custom-commands - # (which results in wrongly generated source files with "make -j ") - ${myJavaGeneratedSources} - ${myNativeTarget} - WORKING_DIRECTORY - "${myJavaGeneratedSourceDir}" - COMMENT - " ${myTarget}: Compiling sources and packing library ${myBinJarFile}" VERBATIM - ) - - add_custom_command( - OUTPUT - "${myBuildDir}/${mySrcJarFile}" - COMMAND "${Java_JAR_EXECUTABLE}" ARGS - "cf" "${myBuildDir}/${mySrcJarFile}" - "-C" "${myJavaSourceDir}" "${myPkgFirstPart}" - COMMAND "${Java_JAR_EXECUTABLE}" ARGS - "uf" "${myBuildDir}/${mySrcJarFile}" - "-C" "${myJavaGeneratedSourceDir}" "${myPkgFirstPart}" - COMMAND "${Java_JAR_EXECUTABLE}" ARGS - "uf" "${myBuildDir}/${mySrcJarFile}" - "-C" "${mySourceDir}" "native" - COMMAND "${Java_JAR_EXECUTABLE}" ARGS - "uf" "${myBuildDir}/${mySrcJarFile}" - "-C" "${myGeneratedSourceDir}" "native" - COMMAND "${Java_JAR_EXECUTABLE}" ARGS - "uf" "${myBuildDir}/${mySrcJarFile}" - "-C" "${myDir}" "VERSION" - DEPENDS - ${myJavaSources} - # Using the native target reduces parallelism slightly - # (less then 1s per build => negliable), but prevetns multiple - # execution of the source generating custom-commands - # (which results in wrongly generated source files with "make -j ") - ${myJavaGeneratedSources} - ${myNativeTarget} - WORKING_DIRECTORY - "${myBuildDir}" - COMMENT - " ${myTarget}: Creating sources archive ${mySrcJarFile}" VERBATIM - ) - - add_custom_target(${myJavaTarget} - DEPENDS - "${myBuildDir}/${myBinJarFile}" - "${myBuildDir}/${mySrcJarFile}" - ) - - add_custom_target(${myTarget} ALL) - add_dependencies(${myTarget} ${myNativeTarget}) - - # this sets the version in pom.xml - set(myMavenProperties "-Dmy.version=${myVersion}") - add_custom_command( - OUTPUT - "${myBuildDir}/pom-generated.xml" - COMMAND "${CMAKE_COMMAND}" - "-Dfile.in=${myDir}/pom.xml" - "-Dfile.out=${myBuildDir}/pom-generated.xml" - ${myMavenProperties} - "-P" "${CMAKE_MODULES_SPRING}/ConfigureFile.cmake" - DEPENDS - "${myDir}/pom.xml" - WORKING_DIRECTORY - "${myDir}" - COMMENT - " ${myTarget}: Configure pom.xml" VERBATIM - ) - set_source_files_properties("${myBuildDir}/pom-generated.xml" PROPERTIES GENERATED TRUE) - - add_dependencies(${myTarget} ${myJavaTarget}) - - # Install the native library - install(TARGETS ${myNativeTarget} DESTINATION ${myInstLibsDir}) - # Install the data files - install(DIRECTORY "${myDir}/data/" DESTINATION ${myInstLibsDir} FILES_MATCHING PATTERN REGEX "InterfaceInfo\\.lua$") - install(DIRECTORY "${myDir}/data/" DESTINATION ${myInstDataDir} FILES_MATCHING PATTERN REGEX "InterfaceInfo\\.lua$" EXCLUDE PATTERN "*") - # Install the library - install(FILES "${myBuildDir}/${myBinJarFile}" DESTINATION ${myInstDataDir}) - # Install the sources archive - install(FILES "${myBuildDir}/${mySrcJarFile}" DESTINATION ${myInstDataDir}/jlib) -endif (BUILD_${myName}_AIINTERFACE) diff --git a/AI/Interfaces/Java/VERSION b/AI/Interfaces/Java/VERSION deleted file mode 100644 index ceab6e11ece..00000000000 --- a/AI/Interfaces/Java/VERSION +++ /dev/null @@ -1 +0,0 @@ -0.1 \ No newline at end of file diff --git a/AI/Interfaces/Java/bin/ant.properties b/AI/Interfaces/Java/bin/ant.properties deleted file mode 100644 index b9c0a35d3ec..00000000000 --- a/AI/Interfaces/Java/bin/ant.properties +++ /dev/null @@ -1,21 +0,0 @@ -# Paths are relative to the project home (which is ../ from this file). -# All values are optional. - -;spring.home=../../.. - -# This is used only in the next property -;build.home=${spring.home}/build -# Where jar files will be built -;build.dir=${build.home}/AI/Interfaces/${interface.name} - -# Where generated sources shall be created in -;src.generated=${build.dir}/src-generated/main -;src.generated.native=${src.generated}/native -;src.generated.java=${src.generated}/java - -# This is used only in the next property -;dist.home=${spring.home}/dist -# Where jar files will be installed to -;dist.dir=${dist.home}/AI/Interfaces/${interface.name}/${interface.version} -# Where HTML JavaDoc files will be generated -;doc.dir=${dist.home}/AI/Interfaces/${interface.name}/${interface.version}/doc/jdoc diff --git a/AI/Interfaces/Java/bin/build.xml b/AI/Interfaces/Java/bin/build.xml deleted file mode 100644 index 86e0033068a..00000000000 --- a/AI/Interfaces/Java/bin/build.xml +++ /dev/null @@ -1,258 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/AI/Interfaces/Java/bin/jni_wrappCallback.awk b/AI/Interfaces/Java/bin/jni_wrappCallback.awk deleted file mode 100755 index 833bdb90ec3..00000000000 --- a/AI/Interfaces/Java/bin/jni_wrappCallback.awk +++ /dev/null @@ -1,573 +0,0 @@ -#!/usr/bin/awk -f -# -# This awk script creates a Java class with native/JNI functions, -# plus their respective native counterparts, -# to call to C functions in: -# NATIVE_GENERATED_SOURCE_DIR/CallbackFunctionPointerBridge.h -# -# This script uses functions from the following files: -# * common.awk -# * commonDoc.awk -# Variables that can be set on the command-line (with -v): -# * GENERATED_SOURCE_DIR: the generated sources root dir -# -# usage: -# awk -f thisScript.awk -f common.awk -f commonDoc.awk -# awk -f thisScript.awk -f common.awk -f commonDoc.awk \ -# -v 'GENERATED_SOURCE_DIR=/tmp/build/AI/Interfaces/Java/src-generated/main' -# - -BEGIN { - # initialize things - - # define the field splitter(-regex) - FS = "(,)|(\\()|(\\);)"; - - # Used by other scripts - JAVA_MODE = 1; - - # These vars can be assigned externally, see file header. - # Set the default values if they were not supplied on the command line. - if (!GENERATED_SOURCE_DIR) { - GENERATED_SOURCE_DIR = "../src-generated/main"; - } - if (!JAVA_GENERATED_SOURCE_DIR) { - JAVA_GENERATED_SOURCE_DIR = GENERATED_SOURCE_DIR "/java"; - } - if (!NATIVE_GENERATED_SOURCE_DIR) { - NATIVE_GENERATED_SOURCE_DIR = GENERATED_SOURCE_DIR "/native"; - } - - nativeBridge = "CallbackFunctionPointerBridge"; - bridgePrefix = "bridged__"; - - jniBridge = "CallbackJNIBridge"; - - myPkgA = "com.springrts.ai"; - myPkgD = convertJavaNameFormAToD(myPkgA); - myPkgC = convertJavaNameFormAToC(myPkgA); - myInterface = "AICallback"; - myClass = "JniAICallback"; - - fi = 0; -} - -function doWrapp(funcIndex_dw) { - - paramListJava_dw = funcParamList[funcIndex_dw]; - doWrapp_dw = 1; - - fullName_dw = funcFullName[funcIndex_dw]; - if (doWrapp_dw) { - metaInf_dw = funcMetaInf[funcIndex_dw]; - - if (match(metaInf_dw, /ARRAY:/)) { - #doWrapp_dw = 0; - } - if (match(metaInf_dw, /MAP:/)) { - #doWrapp_dw = 0; - } - if (match(fullName_dw, "^" bridgePrefix "File_")) { - doWrapp_dw = 0; - } - } else { - print("Java-AIInterface: NOTE: JNI level: Callback: intentionally not wrapped: " fullName_dw); - } - - return doWrapp_dw; -} - -function createNativeFileName(fileName_fn, isHeader_fn) { - - absFileName_fn = NATIVE_GENERATED_SOURCE_DIR "/" fileName_fn; - if (isHeader_fn) { - absFileName_fn = absFileName_fn ".h"; - } else { - absFileName_fn = absFileName_fn ".c"; - } - - return absFileName_fn; -} - -function printNativeJNI() { - - outFile_nh = createNativeFileName(jniBridge, 1); - outFile_nc = createNativeFileName(jniBridge, 0); - - printCommentsHeader(outFile_nh); - printCommentsHeader(outFile_nc); - - print("") >> outFile_nh; - print("#ifndef __CALLBACK_JNI_BRIDGE_H") >> outFile_nh; - print("#define __CALLBACK_JNI_BRIDGE_H") >> outFile_nh; - print("") >> outFile_nh; - print("#include ") >> outFile_nh; - print("") >> outFile_nh; - print("#ifdef __cplusplus") >> outFile_nh; - print("extern \"C\" {") >> outFile_nh; - print("#endif") >> outFile_nh; - print("") >> outFile_nh; - - print("") >> outFile_nc; - print("#include \"" jniBridge ".h\"") >> outFile_nc; - print("") >> outFile_nc; - print("#include \"" nativeBridge ".h\"") >> outFile_nc; - print("") >> outFile_nc; - print("") >> outFile_nc; - - # print the wrapping functions - for (i=0; i < fi; i++) { - fullName = funcFullName[i]; - retType = funcRetTypeC[i]; - paramList = funcParamListC[i]; - paramListNoTypes = removeParamTypes(paramList); - metaInf = funcMetaInf[i]; - - if (doWrapp(i)) { - isRetString = part_isRetString(fullName, metaInf); - if (isRetString) { - retString = part_getRetString(metaInf); - split(retString, retStringNames, ":"); # must return 2 elements - } - - javaName = fullName; - sub("^" bridgePrefix, "", javaName); - gsub(/_/, "_1", javaName); - jni_funcName = "Java_" myPkgC "_" myClass "_" javaName; - jni_retType = convertCToJNIType(retType); - jni_paramList = ""; - size_params = split(paramList, params, ","); - for (p=1; p <= size_params; p++) { - pType_c = params[p]; - sub(/ [^ ]+$/, "", pType_c); - pType_c = trim(pType_c); - - pName = params[p]; - sub(/^.* /, "", pName); - - pType_jni = convertCToJNIType(pType_c, pName); - - # these are later used for conversion - c_paramTypes[p] = pType_c; - c_paramNames[p] = pName; - jni_paramTypes[p] = pType_jni; - jni_paramNames[p] = pName; - - if (isRetString && (pName == retStringNames[1] || pName == retStringNames[2])) { - if (pName == retStringNames[1]) - jni_retType = convertCToJNIType(pType_c); - continue; - } - jni_paramList = jni_paramList ", " pType_jni " " pName; - } - jni_paramListNoTypes = removeParamTypes(jni_paramList); - isVoidRet = match(jni_retType, /^void$/); - - # print function declaration to *.h - #printFunctionComment_Common(outFile_nh, funcDocComment, i, ""); - print("JNIEXPORT " jni_retType " JNICALL " jni_funcName "(JNIEnv* __env, jobject __obj" jni_paramList ");") >> outFile_nh; - print("") >> outFile_nh; - - # print function definition to *.c - print("JNIEXPORT " jni_retType " JNICALL " jni_funcName "(JNIEnv* __env, jobject __obj" jni_paramList ") {") >> outFile_nc; - print("") >> outFile_nc; - - if (!isVoidRet) { - print("\t" jni_retType " _ret;") >> outFile_nc; - print("") >> outFile_nc; - } - - # Return value conversion - pre call - retType_isString = ((match(retType, /^(const )?char*/) || isRetString) && (jni_retType == "jstring")); - retTypeConv = 0; - if (retType_isString) { - if (isRetString) - print("\t" "char " retStringNames[1] "[2048] = {'\\0'};") >> outFile_nc; - print("\t" retType " _retNative;") >> outFile_nc; - retTypeConv = 1; - } - - hasRetParam = 0; - # Params conversion - pre call - for (p=1; p <= size_params; p++) { - pType_jni = jni_paramTypes[p]; - - if (pType_jni == "jstring") { - # jstring - if (!isRetString || c_paramNames[p] != retStringNames[1]) { - c_paramNames[p] = c_paramNames[p] "_native"; - sub(" " jni_paramNames[p], " " c_paramNames[p], paramListNoTypes); - print("\t" c_paramTypes[p] " " c_paramNames[p] " = (" c_paramTypes[p] ") (*__env)->GetStringUTFChars(__env, " jni_paramNames[p] ", NULL);") >> outFile_nc; - } - } else if (pType_jni == "jint") { - if (isRetString && c_paramNames[p] == retStringNames[2]) - sub(" " jni_paramNames[p], " sizeof(" retStringNames[1] ")", paramListNoTypes); - } else if (match(pType_jni, /^j.+Array$/)) { - # primitive array - c_paramNames[p] = c_paramNames[p] "_native"; - sub(" " jni_paramNames[p], " " c_paramNames[p], paramListNoTypes); - - capArrType = pType_jni; - sub(/^j/, "", capArrType); - sub(/Array$/, "", capArrType); - capArrType = capitalize(capArrType); - - _isPrimitive = (capArrType != "Object"); - _isString = !_isPrimitive && match(c_paramTypes[p], /(const )?char\*\*/); - - print("\t" c_paramTypes[p] " " c_paramNames[p] " = NULL;") >> outFile_nc; - print("\t" "if (" jni_paramNames[p] " != NULL) {") >> outFile_nc; - if (_isPrimitive) { - print("\t\t" c_paramNames[p] " = (" c_paramTypes[p] ") (*__env)->Get" capArrType "ArrayElements(__env, " jni_paramNames[p] ", NULL);") >> outFile_nc; - } else if (_isString) { - print("\t\t" "const int " c_paramNames[p] "_size = (int) (*__env)->GetArrayLength(__env, " jni_paramNames[p] ");") >> outFile_nc; - print("\t\t" c_paramNames[p] " = (" c_paramTypes[p] ") malloc(sizeof(char*) * " c_paramNames[p] "_size);") >> outFile_nc; - } else { - print("ERROR: do not know how to convert parameter type: " pType_jni); - exit(1); - } - print("\t" "}") >> outFile_nc; - } else if (pType_jni == "jobject") { - # StringBuffer - hasRetParam = 1; - cPaNa = c_paramNames[p]; - c_paramNames[p] = cPaNa "_native"; - sub(" " jni_paramNames[p], " " c_paramNames[p], paramListNoTypes); - print("\t" "char " c_paramNames[p] "[MAX_RESPONSE_SIZE];") >> outFile_nc; - retParamConversion = "\t" "jclass clazz = (*__env)->GetObjectClass(__env, " cPaNa ");" "\n"; - retParamConversion = retParamConversion "\t" "jmethodID mid = (*__env)->GetMethodID(__env, clazz, \"append\", \"(Ljava/lang/String;)Ljava/lang/StringBuffer;\");" "\n" - retParamConversion = retParamConversion "\t" "jstring " cPaNa "_jStr = (*__env)->NewStringUTF(__env, " c_paramNames[p] ");" "\n"; - retParamConversion = retParamConversion "\t" "(*__env)->CallObjectMethod(__env, " cPaNa ", mid, " cPaNa "_jStr);" - } - } - - condRet = ""; - if (!isVoidRet) { - if (retTypeConv) { - condRet = "_retNative = "; - } else { - condRet = "_ret = (" jni_retType ") "; - } - } - print("\t" condRet fullName "(" paramListNoTypes ");") >> outFile_nc; - if (hasRetParam) { - print(retParamConversion) >> outFile_nc; - } - - # Params conversion - post call - for (p=1; p <= size_params; p++) { - pType_jni = jni_paramTypes[p]; - - if (pType_jni == "jstring") { - # jstring - if (!isRetString || c_paramNames[p] != retStringNames[1]) - print("\t" "(*__env)->ReleaseStringUTFChars(__env, " jni_paramNames[p] ", " c_paramNames[p] ");") >> outFile_nc; - } else if (match(pType_jni, /^j.+Array$/)) { - # primitive array - capArrType = pType_jni; - sub(/^j/, "", capArrType); - sub(/Array$/, "", capArrType); - capArrType = capitalize(capArrType); - - _isPrimitive = (capArrType != "Object"); - _isString = !_isPrimitive && match(c_paramTypes[p], /(const )?char\*\*/); - - print("\t" "if (" jni_paramNames[p] " != NULL) {") >> outFile_nc; - if (_isPrimitive) { - _elementJNativeType = jni_paramTypes[p]; - sub(/Array$/, "", _elementJNativeType); # jfloatArray -> jfloat - print("\t\t" "(*__env)->Release" capArrType "ArrayElements(__env, " jni_paramNames[p] ", (" _elementJNativeType "*) " c_paramNames[p] ", 0 /* copy back changes and release */);") >> outFile_nc; - } else if (_isString) { - print("\t\t" "const int " c_paramNames[p] "_size = (int) (*__env)->GetArrayLength(__env, " jni_paramNames[p] ");") >> outFile_nc; - print("\t\t" "int " c_paramNames[p] "_i;") >> outFile_nc; - print("\t\t" "jstring " c_paramNames[p] "_jStr;") >> outFile_nc; - print("\t\t" "for (" c_paramNames[p] "_i=0; " c_paramNames[p] "_i < " c_paramNames[p] "_size; ++" c_paramNames[p] "_i) {") >> outFile_nc; - print("\t\t\t" c_paramNames[p] "_jStr = (jstring) (*__env)->NewStringUTF(__env, " c_paramNames[p] "[" c_paramNames[p] "_i]);") >> outFile_nc; - print("\t\t\t" "(*__env)->SetObjectArrayElement(__env, " jni_paramNames[p] ", " c_paramNames[p] "_i, " c_paramNames[p] "_jStr);") >> outFile_nc; - print("\t\t\t" "(*__env)->DeleteLocalRef(__env, " c_paramNames[p] "_jStr);") >> outFile_nc; - print("\t\t" "}") >> outFile_nc; - print("\t\t" "free(" c_paramNames[p] ");") >> outFile_nc; - } - print("\t" "}") >> outFile_nc; - } else if (pType_jni == "jobject" ) { - # StringBuffer - print("\t" "(*__env)->DeleteLocalRef(__env, " cPaNa "_jStr);") >> outFile_nc; - } - } - - # Return value conversion - post call - if (retType_isString) { - print("\t" "_ret = (*__env)->NewStringUTF(__env, " (isRetString ? retStringNames[1] : "_retNative") ");") >> outFile_nc; - } - - if (!isVoidRet) { - print("") >> outFile_nc; - print("\t" "return _ret;") >> outFile_nc; - } - print("" "}") >> outFile_nc; - print("") >> outFile_nc; - } else { - print("Note: The following function is intentionally not wrapped: " fullName); - } - } - - - print("#ifdef __cplusplus") >> outFile_nh; - print("} // extern \"C\"") >> outFile_nh; - print("#endif") >> outFile_nh; - print("") >> outFile_nh; - print("#endif // __CALLBACK_JNI_BRIDGE_H") >> outFile_nh; - print("") >> outFile_nh; - - close(outFile_nh); - close(outFile_nc); -} - - -function printHeader(outFile_h, javaPkg_h, javaClassName_h) { - - printCommentsHeader(outFile_h); - print("") >> outFile_h; - print("package " javaPkg_h ";") >> outFile_h; - print("") >> outFile_h; - print("") >> outFile_h; - print("/**") >> outFile_h; - print(" * Lets Java Skirmish AIs call back to the Spring engine.") >> outFile_h; - print(" * We are using JNI for best speed.") >> outFile_h; - print(" *") >> outFile_h; - print(" * @author AWK wrapper script") >> outFile_h; - print(" * @version GENERATED") >> outFile_h; - print(" */") >> outFile_h; - if (javaClassName_h == myClass) { - print("public class " javaClassName_h " implements " myInterface " {") >> outFile_h; - } else { - print("public interface " javaClassName_h " {") >> outFile_h; - } - print("") >> outFile_h; -} - -function createJavaFileName(clsName_f) { - return JAVA_GENERATED_SOURCE_DIR "/" myPkgD "/" clsName_f ".java"; -} - -function printJavaClsAndInt() { - - outFile_i = createJavaFileName(myInterface); - outFile_c = createJavaFileName(myClass); - - printHeader(outFile_i, myPkgA, myInterface); - printHeader(outFile_c, myPkgA, myClass); - - # print the static registrator - print("\tstatic {") >> outFile_c; - print("\t\tSystem.loadLibrary(\"AIInterface\");") >> outFile_c; - print("\t}") >> outFile_c; - print("") >> outFile_c; - - # print skirmishAIId getter in interface - print("\t" "public int SkirmishAI_getSkirmishAIId();") >> outFile_i; - print("") >> outFile_i; - - # print skirmishAIId member, constructor and getter - print("\t" "private int skirmishAIId;") >> outFile_c; - print("") >> outFile_c; - print("\t" "public " myClass "(int skirmishAIId) {") >> outFile_c; - print("\t\t" "this.skirmishAIId = skirmishAIId;") >> outFile_c; - print("\t}") >> outFile_c; - print("") >> outFile_c; - print("\t" "@Override") >> outFile_c; - print("\t" "public int SkirmishAI_getSkirmishAIId() {") >> outFile_c; - print("\t\t" "return this.skirmishAIId;") >> outFile_c; - print("\t}") >> outFile_c; - print("") >> outFile_c; - - # print the callback methods - for (i=0; i < fi; i++) { - if (doWrapp(i)) { - fullName = funcFullName[i]; - retType = funcRetTypeJ[i]; - paramList = funcParamListJ[i]; - metaInf = funcMetaInf[i]; - - isRetString = part_isRetString(fullName, metaInf); - if (isRetString) { - retString = part_getRetString(metaInf); - split(retString, retStringNames, ":"); # must return 2 elements - size_params = split(paramList, params, ","); - for (p=1; p <= size_params; p++) { - pName = params[p]; - sub(/^.* /, "", pName); - if (pName == retStringNames[1]) { - ps = 1; - } else if (pName == retStringNames[2]) { - ps = 2; - } else continue; - pType_c = params[p]; - sub(/ [^ ]+$/, "", pType_c); - pType_c = trim(pType_c); - retStringTypes[ps] = convertJNIToJavaType(convertCToJNIType(pType_c, pName)); - } - retType = retStringTypes[1]; - sub(", " retStringTypes[1] " " retStringNames[1] ", " retStringTypes[2] " " retStringNames[2], "", paramList); - } - - paramListNoSID = paramList; - sub(/int _skirmishAIId(, )?/, "", paramListNoSID); - paramListNoSIDNoTypes = removeParamTypes(paramListNoSID); - if (paramListNoSIDNoTypes != "") { - paramListNoSIDNoTypes = ", " paramListNoSIDNoTypes; - } - condRet = ""; - if (retType != "void") { - condRet = "return "; - } - - sub("^" bridgePrefix, "", fullName); - - metaInfCommand = ""; - if (metaInf != "") { - metaInfCommand = " // " metaInf; - } - - # print the interface function - printFunctionComment_Common(outFile_i, funcDocComment, i, "\t"); - print("\t" "public " retType " " fullName "(" paramListNoSID ");" metaInfCommand) >> outFile_i; - print("") >> outFile_i; - - # print the interface implementing function - commentText = getFunctionComment_Common(funcDocComment, i); - if (match(commentText, /@deprecated/)) { - # this prevents javac from outputting a warning - print("\t" "/** @deprecated */") >> outFile_c; - } - print("\t" "@Override") >> outFile_c; - print("\t" "public " retType " " fullName "(" paramListNoSID ") {") >> outFile_c; - print("\t\t" condRet "this." fullName "(this.skirmishAIId" paramListNoSIDNoTypes ");") >> outFile_c; - print("\t" "}") >> outFile_c; - - # print the private native function - print("\t" "private native " retType " " fullName "(" paramList ");") >> outFile_c; - print("") >> outFile_c; - } - } - - print("}") >> outFile_i; - print("") >> outFile_i; - close(outFile_i); - - print("}") >> outFile_c; - print("") >> outFile_c; - close(outFile_c); -} - - -function wrappFunction(funcDef, commentEol) { - - doParse = 1; - - if (doParse) { - size_funcParts = split(funcDef, funcParts, "(,)|(\\()|(\\))"); - # because the empty part after ");" would count as part as well - size_funcParts--; - retType_c = trim(funcParts[2]); - retType_j = convertJNIToJavaType(convertCToJNIType(retType_c)); - fullName = trim(funcParts[3]); - - # function parameters - paramList_c = ""; - paramList_j = ""; - paramList = ""; - - for (i=4; i<=size_funcParts && !match(funcParts[i], /.*\/\/.*/); i++) { - type_c = extractParamType(funcParts[i]); - type_c = cleanupCType(type_c); - name = extractParamName(funcParts[i]); - type_j = convertJNIToJavaType(convertCToJNIType(type_c, name)); - if (i == 4) { - cond_comma = ""; - } else { - cond_comma = ", "; - } - paramList_c = paramList_c cond_comma type_c " " name; - paramList_j = paramList_j cond_comma type_j " " name; - } - - funcFullName[fi] = fullName; - funcRetTypeC[fi] = retType_c; - funcRetTypeJ[fi] = retType_j; - funcParamListC[fi] = paramList_c; - funcParamListJ[fi] = paramList_j; - funcMetaInf[fi] = trim(commentEol); - storeDocLines(funcDocComment, fi); - fi++; - } else { - print("warning: function intentionally NOT wrapped: " funcDef); - } -} - - - -# This function has to return true (1) if a doc comment (eg: /** foo bar */) -# can be deleted. -# If there is no special condition you want to apply, -# it should always return true (1), -# cause there are additional mechanism to prevent accidental deleting. -# see: commonDoc.awk -function canDeleteDocumentation() { - return isMultiLineFunc != 1; -} - - - -# save function pointer info into arrays -# ... 2nd, 3rd, ... line of a function pointer definition -{ - if (isMultiLineFunc) { # function is defined on one single line - funcIntermLine = $0; - # separate possible comment at end of line: // fu bar - commentEol = funcIntermLine; - if (sub(/.*\/\//, "", commentEol)) { - commentEolTot = commentEolTot commentEol; - } - # remove possible comment at end of line: // fu bar - sub(/[ \t]*\/\/.*/, "", funcIntermLine); - funcIntermLine = trim(funcIntermLine); - funcSoFar = funcSoFar " " funcIntermLine; - if (match(funcSoFar, /;$/)) { - # function ends in this line - wrappFunction(funcSoFar, commentEolTot); - isMultiLineFunc = 0; - } - } -} -# 1st line of a function pointer definition -/^EXPORT\(/ { - - funcStartLine = $0; - # separate possible comment at end of line: // foo bar - commentEolTot = ""; - commentEol = funcStartLine; - if (sub(/.*\/\//, "", commentEol)) { - commentEolTot = commentEolTot commentEol; - } - # remove possible comment at end of line: // fu bar - sub(/\/\/.*$/, "", funcStartLine); - funcStartLine = trim(funcStartLine); - if (match(funcStartLine, /;$/)) { - # function ends in this line - wrappFunction(funcStartLine, commentEolTot); - } else { - funcSoFar = funcStartLine; - isMultiLineFunc = 1; - } -} - - - - -END { - # finalize things - - printNativeJNI(); - printJavaClsAndInt(); -} diff --git a/AI/Interfaces/Java/bin/jni_wrappCommands.awk b/AI/Interfaces/Java/bin/jni_wrappCommands.awk deleted file mode 100755 index abd4c0e62e1..00000000000 --- a/AI/Interfaces/Java/bin/jni_wrappCommands.awk +++ /dev/null @@ -1,192 +0,0 @@ -#!/usr/bin/awk -f -# -# This awk script creates a Java class containing important enumerations. -# These enumerations are taken from: rts/ExternalAI/Interface/AISCommands.h -# It currently only takes CommandTopic and UnitCommandOptions enumerations -# -# This script uses functions from the following files: -# * common.awk -# * commonDoc.awk -# Variables that can be set on the command-line (with -v): -# * GENERATED_SOURCE_DIR: the generated sources root dir -# -# usage: -# awk -f thisScript.awk -f common.awk -f commonDoc.awk -# awk -f thisScript.awk -f common.awk -f commonDoc.awk \ -# -v 'GENERATED_SOURCE_DIR=/tmp/build/AI/Interfaces/Java/src-generated/main' -# - -BEGIN { - # initialize things - - # define the field splitter(-regex) - FS = "[ \t]+"; - - # Used by other scripts - JAVA_MODE = 1; - - # These vars can be assigned externally, see file header. - # Set the default values if they were not supplied on the command line. - if (!GENERATED_SOURCE_DIR) { - GENERATED_SOURCE_DIR = "../src-generated/main"; - } - if (!JAVA_GENERATED_SOURCE_DIR) { - JAVA_GENERATED_SOURCE_DIR = GENERATED_SOURCE_DIR "/java"; - } - if (!NATIVE_GENERATED_SOURCE_DIR) { - NATIVE_GENERATED_SOURCE_DIR = GENERATED_SOURCE_DIR "/native"; - } - - myPkgA = "com.springrts.ai"; - myPkgD = convertJavaNameFormAToD(myPkgA); - myClass = "Enumerations"; - - #create empty arrays, holding names and values of the two enumerations - cmdsTopicNamesLength = 0; - split("", cmdsTopicNames); - cmdsTopicValuesLength = 0; - split("", cmdsTopicValues); - unitCmdsTopicNamesLength = 0; - split("", unitCmdsTopicNames); - unitCmdsTopicValuesLength = 0; - split("", unitCmdsTopicValues); -} - - -function createJavaFileName(fileName_fn) { - return JAVA_GENERATED_SOURCE_DIR "/" myPkgD "/" fileName_fn ".java"; -} - -function printGeneralJavaHeader(outFile_h, javaPkg_h, javaClassName_h) { - - printCommentsHeader(outFile_h); - print("") >> outFile_h; - print("package " javaPkg_h ";") >> outFile_h; - print("") >> outFile_h; - print("") >> outFile_h; - print("/**") >> outFile_h; - print(" * These are the Java exposed enumerations.") >> outFile_h; - print(" * We are not calling the engine, this is a pure Java class.") >> outFile_h; - print(" *") >> outFile_h; - print(" * @author AWK wrapper script") >> outFile_h; - print(" * @version GENERATED") >> outFile_h; - print(" */") >> outFile_h; - print("public abstract class " javaClassName_h " {") >> outFile_h; - print("") >> outFile_h; -} - -function printJavaHeader() { - - outFile_i = createJavaFileName(myClass); - - printGeneralJavaHeader(outFile_i, myPkgA, myClass); -} - -function printJavaEnums(enums) { - printJavaEnum("CommandTopic", cmdsTopicNames, cmdsTopicNamesLength, cmdsTopicValues); - print("") >> outFile_i; - printJavaEnum("UnitCommandOptions", unitCmdsTopicNames, unitCmdsTopicNamesLength, unitCmdsTopicValues); -} - -function printJavaEnum(enumName, names, namesLength, values) { - outFile_i = createJavaFileName(myClass); - printEnumHeader(enumName); - - # Prints the enum members and values - first = 0; - for (i=0; i> outFile_i; - } else { - printf(",\n\t\t") >> outFile_i; - } - printJavaEnumItem(names[i], values[i]); - } - - if (first != 0) { - print(";\n") >> outFile_i; - } - printEnumEnd(enumName); -} - -function printEnumHeader(name) { - outFile_i = createJavaFileName(myClass); - - # Prints the enum start - print("\tpublic enum " name " {") >> outFile_i; -} - -function printEnumEnd(name) { - outFile_i = createJavaFileName(myClass); - - # Prints the enum end - print("\t\tprivate final int id;") >> outFile_i; - print("\t\t" name "(int id) { this.id = id; }") >> outFile_i; - print("\t\tpublic int getValue() { return id; }") >> outFile_i; - print("\t}") >> outFile_i; -} - -function printJavaEnumItem(key, value) { - printf(key "(" value ")") >> outFile_i; -} - -function printJavaEnd() { - - outFile_i = createJavaFileName(myClass); - - print("}") >> outFile_i; - print("") >> outFile_i; - - close(outFile_i); -} - -/^[ \t]*COMMAND_.*$/ { - - doWrapp = !match(($0), /.*COMMAND_NULL.*/); - if (doWrapp) { - #parse enumeration of format x = number1, - sub(",", "", $4); - cmdsTopicNames[cmdsTopicNamesLength] = $2; - cmdsTopicNamesLength++; - cmdsTopicValues[cmdsTopicValuesLength] = $4; - cmdsTopicValuesLength++; - } else { - print("Java-AIInterface: NOTE: JNI level: COMMANDS: intentionally not wrapped: " $2); - } -} - -/^[ \t]*UNIT_COMMAND_.*$/ { - doWrapp = !match(($0), /.*COMMAND_NULL.*/); - if (doWrapp) { - unitCmdsTopicNames[unitCmdsTopicNamesLength] = $2; - unitCmdsTopicNamesLength++; - #parse enumeration of format x = (number1 << number2), - sub("[ \t]*//.*", "", $0); - sub(",", "", $0); - sub($3, "", $0); - sub($2, "", $0); - sub("[ \t]*", "", $0); - unitCmdsTopicValues[unitCmdsTopicValuesLength] = $0; - unitCmdsTopicValuesLength++; - } else { - print("Java-AIInterface: NOTE: JNI level: UNIT_COMMANDS: intentionally not wrapped: " $2); - } -} - -# This function has to return true (1) if a doc comment (eg: /** foo bar */) -# can be deleted. -# If there is no special condition you want to apply, -# it should always return true (1), -# cause there are additional mechanism to prevent accidental deleting. -# see: commonDoc.awk -function canDeleteDocumentation() { - return isInsideEvtStruct != 1; -} - -END { - # finalize things - printJavaHeader(); - printJavaEnums(); - printJavaEnd(); -} diff --git a/AI/Interfaces/Java/bin/jni_wrappEvents.awk b/AI/Interfaces/Java/bin/jni_wrappEvents.awk deleted file mode 100755 index a1907084b30..00000000000 --- a/AI/Interfaces/Java/bin/jni_wrappEvents.awk +++ /dev/null @@ -1,570 +0,0 @@ -#!/usr/bin/awk -f -# -# This awk script creates a Java class with one function per event, -# plus a C wrapper to easily/comfortably call these functions from C. -# input is taken from file: -# rts/ExternalAI/Interface/AISEvents.h -# -# This script uses functions from the following files: -# * common.awk -# * commonDoc.awk -# Variables that can be set on the command-line (with -v): -# * GENERATED_SOURCE_DIR: the generated sources root dir -# -# usage: -# awk -f thisScript.awk -f common.awk -f commonDoc.awk -# awk -f thisScript.awk -f common.awk -f commonDoc.awk \ -# -v 'GENERATED_SOURCE_DIR=/tmp/build/AI/Interfaces/Java/src-generated/main' -# - -BEGIN { - # initialize things - - # define the field splitter(-regex) - FS = "[ \t]+"; - - # Used by other scripts - JAVA_MODE = 1; - - # These vars can be assigned externally, see file header. - # Set the default values if they were not supplied on the command line. - if (!GENERATED_SOURCE_DIR) { - GENERATED_SOURCE_DIR = "../src-generated/main"; - } - if (!JAVA_GENERATED_SOURCE_DIR) { - JAVA_GENERATED_SOURCE_DIR = GENERATED_SOURCE_DIR "/java"; - } - if (!NATIVE_GENERATED_SOURCE_DIR) { - NATIVE_GENERATED_SOURCE_DIR = GENERATED_SOURCE_DIR "/native"; - } - - myWrapperName = "EventsJNIBridge"; - myWrapperPrefix = "eventsJniBridge_"; - - myPkgA = "com.springrts.ai"; - myPkgD = convertJavaNameFormAToD(myPkgA); - myAIClass = "AI"; - myAIAbstractClass = "AbstractAI"; - myAICallbackInt = "AICallback"; - - ind_evtTopics = 0; - ind_evtStructs = 0; - isInsideEvtStruct = 0; -} - - - -# Checks if a field is available and is no comment -function isFieldUsable(f) { - - valid = 0; - - if (f && !match(f, /.*\/\/.*/)) { - valid = 1; - } - - return valid; -} - -function createNativeFileName(fileName_fn, isHeader_fn) { - - absFileName_fn = NATIVE_GENERATED_SOURCE_DIR "/" fileName_fn; - if (isHeader_fn) { - absFileName_fn = absFileName_fn ".h"; - } else { - absFileName_fn = absFileName_fn ".c"; - } - - return absFileName_fn; -} -function createJavaFileName(fileName_fn) { - return JAVA_GENERATED_SOURCE_DIR "/" myPkgD "/" fileName_fn ".java"; -} - - -function printNativeHeader() { - - outFile_nh = createNativeFileName(myWrapperName, 1); - outFile_nc = createNativeFileName(myWrapperName, 0); - printCommentsHeader(outFile_nh); - printCommentsHeader(outFile_nc); - - # print includes (header) - print("") >> outFile_nh; - print("#ifndef __EVENTS_JNI_BRIDGE_H") >> outFile_nh; - print("#define __EVENTS_JNI_BRIDGE_H") >> outFile_nh; - print("") >> outFile_nh; - print("#include ") >> outFile_nh; - print("") >> outFile_nh; - print("#ifdef __cplusplus") >> outFile_nh; - print("extern \"C\" {") >> outFile_nh; - print("#endif") >> outFile_nh; - print("") >> outFile_nh; - - # print includes (source) - print("") >> outFile_nc; - print("#include \"" myWrapperName ".h\"") >> outFile_nc; - print("") >> outFile_nc; - print("#include \"JavaBridge.h\" // for INT_AI") >> outFile_nc; - print("#include \"JniUtil.h\"") >> outFile_nc; - print("#include \"ExternalAI/Interface/AISEvents.h\"") >> outFile_nc; - print("#include // for calloc(), free()") >> outFile_nc; - print("") >> outFile_nc; - print("") >> outFile_nc; - - # print global vars (source) - print("size_t skirmishAIId_size = 0;") >> outFile_nc; - print("jobject* skirmishAIId_callback = NULL;") >> outFile_nc; - print("") >> outFile_nc; -} - -function printNativeEventMethodVars() { - - for (e=0; e < ind_evtStructs; e++) { - printNativeEventMethodVar(e); - } - print("") >> outFile_nc; -} -function printNativeEventMethodVar(evtIndex) { - - outFile_nc = createNativeFileName(myWrapperName, 0); - - eName = evtsName[evtIndex]; - eNameLowerized = lowerize(eName); - - print("jmethodID m_ai_" eNameLowerized " = NULL;") >> outFile_nc; -} - -function printNativeStaticInitFuncHead() { - - # ... header - print("/**") >> outFile_nh; - print(" * Initialized stuff needed for sending events to an AI library instance.") >> outFile_nh; - print(" *") >> outFile_nh; - print(" * @author hoijui") >> outFile_nh; - print(" * @version GENERATED") >> outFile_nh; - print(" */") >> outFile_nh; - print("int " myWrapperPrefix "initStatic(JNIEnv* env, size_t skirmishAIId_size);") >> outFile_nh; - print("") >> outFile_nh; - # ... source - print("int " myWrapperPrefix "initStatic(JNIEnv* env, size_t _skirmishAIId_size) {") >> outFile_nc; - print("") >> outFile_nc; - print("\t" "skirmishAIId_size = _skirmishAIId_size;") >> outFile_nc; - print("\t" "skirmishAIId_callback = (jobject*) calloc(skirmishAIId_size, sizeof(jobject));") >> outFile_nc; - print("\t" "size_t t;") >> outFile_nc; - print("\t" "for (t=0; t < skirmishAIId_size; ++t) {") >> outFile_nc; - print("\t\t" "skirmishAIId_callback[t] = NULL;") >> outFile_nc; - print("\t" "}") >> outFile_nc; - print("") >> outFile_nc; - print("\t" "jobject c_aiInt = (*env)->FindClass(env, \"" myPkgD "/" myAIClass "\");") >> outFile_nc; - print("\t" "if (jniUtil_checkException(env, \"Failed fetching AI interface class " myPkgA "." myAIClass "\")) { return -2; }") >> outFile_nc; - print("") >> outFile_nc; -} - -function printNativeEventStaticInits() { - - for (e=0; e < ind_evtStructs; e++) { - printNativeEventStaticInit(e); - } - print("") >> outFile_nc; -} -function printNativeEventStaticInit(evtIndex) { - - outFile_nc = createNativeFileName(myWrapperName, 0); - - eName = evtsName[evtIndex]; - eNameLowerized = lowerize(eName); - eSignature = "("; - for (m=0; m < evtsNumMembers[evtIndex]; m++) { - type_c = evtsMembers_type_c[evtIndex, m]; - type_jni = convertCToJNIType(type_c); - type_sig = convertJNIToSignatureType(type_jni); - eSignature = eSignature type_sig; - } - eSignature = eSignature ")I"; - if (eNameLowerized == "init") { - eSignature = "(IL" myPkgD "/" myAICallbackInt ";)I"; - } - - print("\t" "m_ai_" eNameLowerized " = jniUtil_getMethodID(env, c_aiInt, \"" eNameLowerized "\", \"" eSignature "\");") >> outFile_nc; - print("\t" "if (jniUtil_checkException(env, \"Failed fetching Java AI method ID for: " eNameLowerized "\")) { return -3; }") >> outFile_nc; - print("") >> outFile_nc; -} - -function printNativeInitFunc() { - - print("\t" "return 0; // -> no error") >> outFile_nc; - print("}") >> outFile_nc; - print("") >> outFile_nc; - - # ... header - print("/**") >> outFile_nh; - print(" * Initialized stuff needed for an AI instance.") >> outFile_nh; - print(" *") >> outFile_nh; - print(" * @author hoijui") >> outFile_nh; - print(" * @version GENERATED") >> outFile_nh; - print(" */") >> outFile_nh; - print("int " myWrapperPrefix "initAI(JNIEnv* env, int skirmishAIId, jobject callback);") >> outFile_nh; - print("") >> outFile_nh; - # ... source - print("int " myWrapperPrefix "initAI(JNIEnv* env, int skirmishAIId, jobject callback) {") >> outFile_nc; - print("") >> outFile_nc; - print("\t" "int res = -1;") >> outFile_nc; - print("") >> outFile_nc; - print("\t" "skirmishAIId_callback[skirmishAIId] = callback;") >> outFile_nc; - print("\t" "res = 0;") >> outFile_nc; - print("") >> outFile_nc; - print("\t" "return res;") >> outFile_nc; - print("}") >> outFile_nc; - print("") >> outFile_nc; -} - -function printNativeHandleFuncHead() { - - # ... header - print("/**") >> outFile_nh; - print(" * For documentation, see SSkirmishAILibrary::handleEvent() in:") >> outFile_nh; - print(" * ExternalAI/Interface/SSkirmishAILibrary.h") >> outFile_nh; - print(" *") >> outFile_nh; - print(" * @author hoijui") >> outFile_nh; - print(" * @version GENERATED") >> outFile_nh; - print(" */") >> outFile_nh; - print("int " myWrapperPrefix "handleEvent(JNIEnv* env, jobject aiInstance, int skirmishAIId, int topic, const void* data);") >> outFile_nh; - print("") >> outFile_nh; - # ... source - print("int " myWrapperPrefix "handleEvent(JNIEnv* env, jobject aiInstance, int skirmishAIId, int topic, const void* data) {") >> outFile_nc; - print("") >> outFile_nc; - print("\t" "int _ret = -1;") >> outFile_nc; - print("") >> outFile_nc; -# print("\t" "jobject o_ai = skirmishAIId_aiObject[skirmishAIId];") >> outFile_nc; -# print("\t" "//assert(o_ai != NULL);") >> outFile_nc; -# print("") >> outFile_nc; - - # only add this for debugging purposes -# print("\t" "// in case we missed handling an exception elsewhere") >> outFile_nc; -# print("\t" "// and it is therefore still pending, we handle it here") >> outFile_nc; -# print("\t" "if ((*env)->ExceptionCheck(env)) {") >> outFile_nc; -# print("\t\t" "(*env)->ExceptionDescribe(env);") >> outFile_nc; -# print("\t\t" "_ret = -6;") >> outFile_nc; -# print("\t\t" "return _ret;") >> outFile_nc; -# print("\t" "}") >> outFile_nc; -# print("") >> outFile_nc; - - print("\t" "switch (topic) {") >> outFile_nc; -} - - -function printNativeEventCases() { - - for (e=0; e < ind_evtStructs; e++) { - printNativeEventCase(e); - } -} -function printNativeEventCase(evtIndex) { - - outFile_nc = createNativeFileName(myWrapperName, 0); - - topicName = evtsTopicName[evtIndex]; - topicValue = evtsTopicNameValue[topicName]; - eName = evtsName[evtIndex]; - eNameLowerized = lowerize(eName); - eStruct = "S" eName "Event"; - - print("\t\t" "case " topicName ": {") >> outFile_nc; - print("\t\t\t" "const struct " eStruct "* evt = (const struct "eStruct"*) data;") >> outFile_nc; - - paramsEvt = ""; - conversion_pre = ""; - for (m=0; m < evtsNumMembers[evtIndex]; m++) { - type_c = evtsMembers_type_c[evtIndex, m]; - name_c = evtsMembers_name[evtIndex, m]; - value_c = "evt->" name_c; - name_jni = value_c; - - type_jni = convertCToJNIType(type_c); - if (type_jni == "jstring") { - name_jni = name_c "_jni"; - conversion_pre = conversion_pre "\n\t\t\t" type_jni " " name_jni " = (*env)->NewStringUTF(env, " value_c ");"; - } else if (type_jni == "jfloatArray") { - name_jni = name_c "_jni"; - - array_size = "sizeof(" value_c ")"; - if (match(name_c, /_posF3$/)) { - array_size = "3"; - } - - conversion_pre = conversion_pre "\n\t\t\t" type_jni " " name_jni " = (*env)->NewFloatArray(env, " array_size ");"; - conversion_pre = conversion_pre "\n\t\t\t" "(*env)->SetFloatArrayRegion(env, " name_jni ", 0, " array_size ", " value_c ");"; - } else if (type_jni == "jintArray") { - name_jni = name_c "_jni"; - - array_size = "sizeof(" value_c ")"; - - conversion_pre = conversion_pre "\n\t\t\t" type_jni " " name_jni " = (*env)->NewIntArray(env, " array_size ");"; - conversion_pre = conversion_pre "\n\t\t\t" "(*env)->SetIntArrayRegion(env, " name_jni ", 0, " array_size ", " value_c ");"; - } - - paramsEvt = paramsEvt ", " name_jni; - } - sub(/^, /, "", paramsEvt); - if (eNameLowerized == "init") { - sub(/evt->callback/, "skirmishAIId_callback[evt->skirmishAIId]", paramsEvt); - } - - print(conversion_pre) >> outFile_nc; - print("\t\t\t" "_ret = (*env)->CallIntMethod(env, aiInstance, m_ai_" eNameLowerized ", " paramsEvt ");") >> outFile_nc; - - print("\t\t\t" "break;") >> outFile_nc; - print("\t\t" "}") >> outFile_nc; -} - -function printNativeEnd() { - - outFile_nh = createNativeFileName(myWrapperName, 1); - outFile_nc = createNativeFileName(myWrapperName, 0); - - print("#ifdef __cplusplus") >> outFile_nh; - print("} // extern \"C\"") >> outFile_nh; - print("#endif") >> outFile_nh; - print("") >> outFile_nh; - print("#endif // __EVENTS_JNI_BRIDGE_H") >> outFile_nh; - print("") >> outFile_nh; - - print("\t\t" "default: {") >> outFile_nc; - print("\t\t\t" "_ret = -4;") >> outFile_nc; - print("\t\t\t" "break;") >> outFile_nc; - print("\t\t" "}") >> outFile_nc; - print("\t" "}") >> outFile_nc; - print("") >> outFile_nc; - print("\t" "if ((*env)->ExceptionCheck(env)) {") >> outFile_nc; - print("\t\t" "(*env)->ExceptionDescribe(env);") >> outFile_nc; - print("\t\t" "_ret = -5;") >> outFile_nc; - print("\t" "}") >> outFile_nc; - print("") >> outFile_nc; - print("\t" "return _ret;") >> outFile_nc; - print("}") >> outFile_nc; - - close(outFile_nh); - close(outFile_nc); -} - - -function printGeneralJavaHeader(outFile_h, javaPkg_h, javaClassName_h) { - - printCommentsHeader(outFile_h); - print("") >> outFile_h; - print("package " javaPkg_h ";") >> outFile_h; - print("") >> outFile_h; - print("") >> outFile_h; - print("/**") >> outFile_h; - print(" * This is the Java entry point from events coming from the engine.") >> outFile_h; - print(" * We are using JNI for best in speed.") >> outFile_h; - print(" *") >> outFile_h; - print(" * @author AWK wrapper script") >> outFile_h; - print(" * @version GENERATED") >> outFile_h; - print(" */") >> outFile_h; - if (javaClassName_h == myAIAbstractClass) { - print("public abstract class " javaClassName_h " implements " myAIClass " {") >> outFile_h; - } else { - print("public interface " javaClassName_h " {") >> outFile_h; - } - print("") >> outFile_h; -} - -function printJavaHeader() { - - outFile_i = createJavaFileName(myAIClass); - outFile_a = createJavaFileName(myAIAbstractClass); - - printGeneralJavaHeader(outFile_i, myPkgA, myAIClass); - printGeneralJavaHeader(outFile_a, myPkgA, myAIAbstractClass); -} - -function printJavaEvents() { - - for (e=0; e < ind_evtStructs; e++) { - printJavaEvent(e); - } -} -function printJavaEvent(evtIndex) { - - outFile_i = createJavaFileName(myAIClass); - outFile_a = createJavaFileName(myAIAbstractClass); - - topicName = evtsTopicName[evtIndex]; - topicValue = evtsTopicNameValue[topicName]; - eName = evtsName[evtIndex]; - eMetaComment = evtsMetaComment[evtIndex]; - eNameLowerized = lowerize(eName); - eCls = eName "AIEvent"; - - # Add the member comments to the main comment as @param attributes - numEvtDocLines = evtsDocComment[evtIndex, "*"]; - for (m=firstMember; m < evtsNumMembers[evtIndex]; m++) { - numLines = evtMbrsDocComments[evtIndex*1000 + m, "*"]; - if (numLines > 0) { - evtsDocComment[evtIndex, numEvtDocLines] = "@param " evtsMembers_name[evtIndex, m]; - } - for (l=0; l < numLines; l++) { - if (l == 0) { - _preDocLine = "@param " evtsMembers_name[evtIndex, m] " "; - } else { - _preDocLine = " " lengtAsSpaces(evtsMembers_name[evtIndex, m]) " "; - } - evtsDocComment[evtIndex, numEvtDocLines] = _preDocLine evtMbrsDocComments[evtIndex*1000 + m, l]; - numEvtDocLines++; - } - } - evtsDocComment[evtIndex, "*"] = numEvtDocLines; - - paramsTypes = ""; - for (m=0; m < evtsNumMembers[evtIndex]; m++) { - name_c = evtsMembers_name[evtIndex, m]; - type_c = evtsMembers_type_c[evtIndex, m]; - type_java = convertJNIToJavaType(convertCToJNIType(type_c)); - - paramsTypes = paramsTypes ", " type_java " " name_c; - } - sub(/^, /, "", paramsTypes); - if (eNameLowerized == "init") { - paramsTypes = "int skirmishAIId, AICallback callback"; - } - - _condMetaComments = eMetaComment; - if (_condMetaComments != "") { - _condMetaComments = " // " _condMetaComments; - } - - print("") >> outFile_i; - printFunctionComment_Common(outFile_i, evtsDocComment, evtIndex, "\t"); - print("\t" "public int " eNameLowerized "(" paramsTypes ");" _condMetaComments) >> outFile_i; - - print("") >> outFile_a; - print("\t" "@Override") >> outFile_a; - print("\t" "public int " eNameLowerized "(" paramsTypes ") {") >> outFile_a; - print("") >> outFile_a; - print("\t\t" "// signal: event handled OK") >> outFile_a; - print("\t\t" "return 0;") >> outFile_a; - print("\t" "}") >> outFile_a; -} - -function printJavaEnd() { - - outFile_i = createJavaFileName(myAIClass); - outFile_a = createJavaFileName(myAIAbstractClass); - - print("}") >> outFile_i; - print("") >> outFile_i; - - print("}") >> outFile_a; - print("") >> outFile_a; - - close(outFile_i); - close(outFile_a); -} - - -function saveMember(ind_mem_s, member_s) { - - name_s = extractParamName(member_s); - type_c_s = extractCType(member_s); - - evtsMembers_name[ind_evtStructs, ind_mem_s] = name_s; - evtsMembers_type_c[ind_evtStructs, ind_mem_s] = type_c_s; -} - - -# aggare te los event defines in order -/^[ \t]*EVENT_.*$/ { - - doWrapp = !match(($0), /.*EVENT_NULL.*/) && !match(($0), /.*EVENT_TO_ID_ENGINE.*/); - if (doWrapp) { - sub(",", "", $4); - evtsTopicNameValue[$2] = $4; - } else { - print("Java-AIInterface: NOTE: JNI level: Events: intentionally not wrapped: " $2); - } -} - - -# This function has to return true (1) if a doc comment (eg: /** foo bar */) -# can be deleted. -# If there is no special condition you want to apply, -# it should always return true (1), -# cause there are additional mechanism to prevent accidental deleting. -# see: commonDoc.awk -function canDeleteDocumentation() { - return isInsideEvtStruct != 1; -} - -################################################################################ -### BEGIN: parsing and saving the event structs - -# end of struct S*Event -/^}; \/\/\$ EVENT_/ { - - evtsNumMembers[ind_evtStructs] = ind_evtMember; - evtsTopicName[ind_evtStructs] = $3; - _metaComment = $0; - sub("^.*" evtsTopicName[ind_evtStructs], "", _metaComment); - evtsMetaComment[ind_evtStructs] = trim(_metaComment); - - ind_evtStructs++; - isInsideEvtStruct = 0; -} - - -# inside of struct S*Event -{ - if (isInsideEvtStruct == 1) { - size_tmpMembers = split($0, tmpMembers, ";"); - # cause there is an empty part behind the ';' - size_tmpMembers--; - for (i=1; i<=size_tmpMembers; i++) { - tmpMembers[i] = trim(tmpMembers[i]); - if (tmpMembers[i] == "" || match(tmpMembers[i], /^\/\//)) { - break; - } - # This would bork with more then 1000 members in an event, - # or more then 1000 events - storeDocLines(evtMbrsDocComments, ind_evtStructs*1000 + ind_evtMember); - saveMember(ind_evtMember, tmpMembers[i]); - ind_evtMember++; - } - } -} - -# beginning of struct S*Event -/^struct S.*Event( \{)?/ { - - isInsideEvtStruct = 1; - ind_evtMember = 0; - eventName = $2; - sub(/^S/, "", eventName); - sub(/Event$/, "", eventName); - - evtsName[ind_evtStructs] = eventName; - storeDocLines(evtsDocComment, ind_evtStructs); -} - -### END: parsing and saving the event structs -################################################################################ - - - - -END { - # finalize things - printNativeHeader(); - printNativeEventMethodVars(); - printNativeStaticInitFuncHead(); - printNativeEventStaticInits(); - printNativeInitFunc(); - printNativeHandleFuncHead(); - printNativeEventCases(); - printNativeEnd(); - - printJavaHeader(); - printJavaEvents(); - printJavaEnd(); -} diff --git a/AI/Interfaces/Java/bin/native_createCallbackFPInitializations.awk b/AI/Interfaces/Java/bin/native_createCallbackFPInitializations.awk deleted file mode 100755 index c6aed9bdeef..00000000000 --- a/AI/Interfaces/Java/bin/native_createCallbackFPInitializations.awk +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/awk -f -# -# This awk script creates the function pointer initializations -# for the C callbacks; eg: -# rts/ExternalAI/Interface/SSkirmishAICallback.h -# rts/ExternalAI/Interface/SAIInterfaceCallback.h -# - -BEGIN { - # initialize things - - # define the field splitter(-regex) - #FS="[ \t]+" -} - - -# Some utility functions - -function ltrim(s) { sub(/^[ \t]+/, "", s); return s; } -function rtrim(s) { sub(/[ \t]+$/, "", s); return s; } -function trim(s) { return rtrim(ltrim(s)); } - - -function printInit(functionPointerName) { - - functionName = functionPointerName; - sub(/Clb_/, "skirmishAiCallback_", functionName); - - print(" callback->" functionPointerName " = &" functionName ";") -} - - -/^.*CALLING_CONV.*$/ { - - line = trim($0); - doWrapp = !match(line, /^[ \t]*\/\/.*/); - if (doWrapp) { - numParts = split(line, parts, /\(CALLING_CONV \*/); - if (numParts == 2) { - numParts2 = split(parts[2], parts2, /\)\(/); - if (numParts2 == 2) { - fn = parts2[1]; - printInit(fn); - } - } - } -} - - - -END { - # finalize things -} diff --git a/AI/Interfaces/Java/bin/native_createCallbackFunctionImpls.awk b/AI/Interfaces/Java/bin/native_createCallbackFunctionImpls.awk deleted file mode 100755 index c9a789ab005..00000000000 --- a/AI/Interfaces/Java/bin/native_createCallbackFunctionImpls.awk +++ /dev/null @@ -1,124 +0,0 @@ -#!/usr/bin/awk -f -# -# This awk script creates function impls that can be used in the C callbacks -# with some little adjustments; eg: -# rts/ExternalAI/SSkirmishAICallbackImpl.cpp -# rts/ExternalAI/SAIInterfaceCallbackImpl.cpp -# -# Accepts input like this: -# [code] -# bool requireSonarUnderWater; -# -# // construction related fields -# /// Should constructions without builders decay? -# bool constructionDecay; -# [/code] -# -# use like this: -# awk -f yourScript.awk -f common.awk -f commonDoc.awk [additional-params] -# this should work with all flavours of AWK (eg. gawk, mawk, nawk, ...) -# - -BEGIN { - # initialize things - - # define the field splitter(-regex) - #FS="[ \t]+" - - # 0 -> print impl - # 1 -> print impl header - # 2 -> print interface header - printingHeader = 1; -} - -function getCType(gct_type) { - - if (match(gct_type, /string/)) { - return "const char* const"; - } else { - return gct_type; - } -} -function getToCTypeConv(gtctc_type) { - - if (match(gtctc_type, /string/)) { - return ".c_str()"; - } else { - return ""; - } -} -function getFuncPrefix(gfp_type) { - - #if (match(gfp_type, /bool/)) { - # return "is"; - #} else { - return "get"; - #} -} - -function printFunc(pf_fieldName, pf_type, pf_header) { - - pf_cType = getCType(pf_type); - pf_toCTypeConv = getToCTypeConv(pf_type); - pf_funcPrefix = getFuncPrefix(pf_type); - - if (pf_header == 2 && hasStoredDoc()) { - printStoredDoc(""); - } - - if (pf_header != 0) { - pf_firstLineEnd = ";"; - pf_sizeToFill = length("const char* const") - length(pf_cType); - if (pf_sizeToFill < 0) { - pf_sizeToFill = 0; - } - pf_filler = ""; - for (pf_i = 0; pf_i < pf_sizeToFill; pf_i++) { - pf_filler = pf_filler " "; - } - } else { - pf_firstLineEnd = " {"; - pf_filler = ""; - } - - if (pf_header == 2) { - print(pf_cType pf_filler " (CALLING_CONV *PreFixName_" pf_funcPrefix capitalize(pf_fieldName) ")(int teamId)" pf_firstLineEnd); - } else { - print("EXPORT(" pf_cType pf_filler ") PreFixName_" pf_funcPrefix capitalize(pf_fieldName) "(int teamId)" pf_firstLineEnd); - } - if (!pf_header) { - print("\t" "return modInfo->" pf_fieldName pf_toCTypeConv ";"); - print("}"); - } -} - -# needed by commonDoc.awk -function canDeleteDocumentation() { - return 1; -} - - -{ - line = trim($0); - - if (line == "") { - print(line); - } else if (!isInsideDoc()) { - sub(/\;$/, "", line); - - name = line; - sub(/^.*[ \t]/, "", name); - - cppType = line; - sub(name, "", cppType); - cppType = rtrim(cppType); - - printFunc(name, cppType, printingHeader); - } -} - - - -END { - # finalize things -} diff --git a/AI/Interfaces/Java/bin/native_wrappCallback.awk b/AI/Interfaces/Java/bin/native_wrappCallback.awk deleted file mode 100755 index b920c196a6e..00000000000 --- a/AI/Interfaces/Java/bin/native_wrappCallback.awk +++ /dev/null @@ -1,290 +0,0 @@ -#!/usr/bin/awk -f -# -# This awk script creates C functions which call C function pointers in: -# rts/ExternalAI/Interface/SSkirmishAICallback.h -# -# Right after running this script, you have to wrap the native command structs -# into functions. -# -# This script uses functions from the following files: -# * common.awk -# * commonDoc.awk -# Variables that can be set on the command-line (with -v): -# * GENERATED_SOURCE_DIR the root generated sources dir -# default: "../src-generated/main" -# * NATIVE_GENERATED_SOURCE_DIR the native generated sources dir -# default: GENERATED_SOURCE_DIR + "/native" -# -# usage: -# awk -f thisScript.awk -f common.awk -f commonDoc.awk -# awk -f thisScript.awk -f common.awk -f commonDoc.awk \ -# -v 'NATIVE_GENERATED_SOURCE_DIR=/tmp/build/AI/Interfaces/Java/src-generated/main/native' -# - -BEGIN { - # initialize things - - # define the field splitter(-regex) - FS = "(,)|(\\()|(\\);)"; - - # These vars can be assigned externally, see file header. - # Set the default values if they were not supplied on the command line. - if (!GENERATED_SOURCE_DIR) { - GENERATED_SOURCE_DIR = "../src-generated/main"; - } - if (!NATIVE_GENERATED_SOURCE_DIR) { - NATIVE_GENERATED_SOURCE_DIR = GENERATED_SOURCE_DIR "/native"; - } - - nativeBridge = "CallbackFunctionPointerBridge"; - bridgePrefix = "bridged__"; - - fi = 0; -} - -function doWrapp(funcIndex_dw) { - - paramListC_dw = funcParamListC[funcIndex_dw]; - doWrapp_dw = 1; - - fullName_dw = funcFullName[funcIndex_dw]; - if (doWrapp_dw) { - metaInf_dw = funcMetaInf[funcIndex_dw]; - - if (match(metaInf_dw, /ARRAY:/)) { - #doWrapp_dw = 0; - } - if (match(metaInf_dw, /MAP:/)) { - #doWrapp_dw = 0; - } - if (match(fullName_dw, "^" bridgePrefix "File_")) { - doWrapp_dw = 0; - } - if (fullName_dw == "Engine_handleCommand") { - doWrapp_dw = 0; - } - # not wrapped, legacy C++ only - if (fullName_dw == "Engine_executeCommand") { - doWrapp_dw = 0; - } - } else { - print("Java-AIInterface: NOTE: native level: Callback: intentionally not wrapped: " fullName_dw); - } - - return doWrapp_dw; -} - -function createNativeFileName(fileName_fn, isHeader_fn) { - - absFileName_fn = NATIVE_GENERATED_SOURCE_DIR "/" fileName_fn; - if (isHeader_fn) { - absFileName_fn = absFileName_fn ".h"; - } else { - absFileName_fn = absFileName_fn ".c"; - } - - return absFileName_fn; -} - -function printNativeFP2F() { - - outFile_nh = createNativeFileName(nativeBridge, 1); - outFile_nc = createNativeFileName(nativeBridge, 0); - - printCommentsHeader(outFile_nh); - printCommentsHeader(outFile_nc); - - print("") >> outFile_nh; - print("#ifndef __CALLBACK_FUNCTION_POINTER_BRIDGE_H") >> outFile_nh; - print("#define __CALLBACK_FUNCTION_POINTER_BRIDGE_H") >> outFile_nh; - print("") >> outFile_nh; - print("#include \"ExternalAI/Interface/aidefines.h\"") >> outFile_nh; - print("") >> outFile_nh; - print("#include // size_t") >> outFile_nh; - print("#include // bool, true, false") >> outFile_nh; - print("") >> outFile_nh; - print("struct SSkirmishAICallback;") >> outFile_nh; - print("") >> outFile_nh; - print("#ifdef __cplusplus") >> outFile_nh; - print("extern \"C\" {") >> outFile_nh; - print("#endif") >> outFile_nh; - print("") >> outFile_nh; - print("void funcPntBrdg_addCallback(const size_t skirmishAIId, const struct SSkirmishAICallback* clb);") >> outFile_nh; - print("void funcPntBrdg_removeCallback(const size_t skirmishAIId);") >> outFile_nh; - print("") >> outFile_nh; - - print("") >> outFile_nc; - print("#include \"" nativeBridge ".h\"") >> outFile_nc; - print("") >> outFile_nc; - print("#include \"ExternalAI/Interface/SSkirmishAICallback.h\"") >> outFile_nc; - print("#include \"ExternalAI/Interface/AISCommands.h\"") >> outFile_nc; - print("") >> outFile_nc; - print("") >> outFile_nc; - print("#define id_clb_sizeMax 8192") >> outFile_nc; - print("static const struct SSkirmishAICallback* id_clb[id_clb_sizeMax];") >> outFile_nc; - print("") >> outFile_nc; - print("void funcPntBrdg_addCallback(const size_t skirmishAIId, const struct SSkirmishAICallback* clb) {") >> outFile_nc; - print(" //assert(skirmishAIId < id_clb_sizeMax);") >> outFile_nc; - print(" id_clb[skirmishAIId] = clb;") >> outFile_nc; - print("}") >> outFile_nc; - print("void funcPntBrdg_removeCallback(const size_t skirmishAIId) {") >> outFile_nc; - print(" //assert(skirmishAIId < id_clb_sizeMax);") >> outFile_nc; - print(" id_clb[skirmishAIId] = NULL;") >> outFile_nc; - print("}") >> outFile_nc; - print("") >> outFile_nc; - - # print the wrapping functions - for (i=0; i < fi; i++) { - fullName = funcFullName[i]; - retType = funcRetTypeC[i]; - paramList = funcParamListC[i]; - sub(/int skirmishAIId/, "int _skirmishAIId", paramList); - paramListNoTypes = removeParamTypes(paramList); - commentEol = funcCommentEol[i]; - - if (doWrapp(i)) { - # print function declaration to *.h - printFunctionComment_Common(outFile_nh, funcDocComment, i, ""); - - outName = bridgePrefix fullName; - - if (commentEol != "") { - commentEol = " // " commentEol; - } - print("EXPORT(" retType ") " outName "(" paramList ");" commentEol) >> outFile_nh; - print("") >> outFile_nh; - - # print function definition to *.c - print("EXPORT(" retType ") " outName "(" paramList ") {") >> outFile_nc; - - print(preConversion) >> outFile_nc; - if (hasRetParam) { - print("\t" retParamType " " retNameTmp " = id_clb[_skirmishAIId]->" fullName "(" paramListNoTypes ");") >> outFile_nc; - print(retParamConversion) >> outFile_nc; - } else { - condRet = "return "; - if (retType == "void") { - condRet = ""; - } - print("\t" condRet "id_clb[_skirmishAIId]->" fullName "(" paramListNoTypes ");") >> outFile_nc; - } - print("" "}") >> outFile_nc; - } else { - print("Note: The following function is intentionally not wrapped: " fullName); - } - } - - - print("") >> outFile_nh; - print("") >> outFile_nc; - - close(outFile_nh); - close(outFile_nc); -} - - -function wrappFunction(funcDef, commentEolTot) { - - doParse = 1; # add a function in case you want to exclude some - - if (doParse) { - size_funcParts = split(funcDef, funcParts, "(,)|(\\()|(\\);)"); - # because the empty part after ");" would count as part as well - size_funcParts--; - retType_c = trim(funcParts[1]); - fullName = funcParts[2]; - sub(/CALLING_CONV \*/, "", fullName); - sub(/\)/, "", fullName); - - # function parameters - paramList_c = ""; - paramList = ""; - - for (i=3; i<=size_funcParts && !match(funcParts[i], /.*\/\/.*/); i++) { - type_c = extractParamType(funcParts[i]); - type_c = cleanupCType(type_c); - name = extractParamName(funcParts[i]); - if (i == 3) { - cond_comma = ""; - } else { - cond_comma = ", "; - } - paramList_c = paramList_c cond_comma type_c " " name; - } - - funcFullName[fi] = fullName; - funcRetTypeC[fi] = retType_c; - funcParamListC[fi] = paramList_c; - funcParamList[fi] = paramList; - funcCommentEol[fi] = trim(commentEolTot); - storeDocLines(funcDocComment, fi); - fi++; - } else { - print("warninig: function intentionally NOT wrapped: " funcDef); - } -} - - - -# This function has to return true (1) if a doc comment (eg: /** foo bar */) -# can be deleted. -# If there is no special condition you want to apply, -# it should always return true (1), -# cause there are additional mechanism to prevent accidental deleting. -# see: commonDoc.awk -function canDeleteDocumentation() { - return isMultiLineFunc != 1; -} - - - -# save function pointer info into arrays -# ... 2nd, 3rd, ... line of a function pointer definition -{ - if (isMultiLineFunc) { # function is defined on one single line - funcIntermLine = $0; - # separate possible comment at end of line: //$ foo bar - commentEol = funcIntermLine; - if (sub(/.*\/\/\$/, "", commentEol)) { - commentEolTot = commentEolTot commentEol; - } - # remove possible comment at end of line: //$ foo bar - sub(/[ \t]*\/\/.*/, "", funcIntermLine); - funcIntermLine = trim(funcIntermLine); - funcSoFar = funcSoFar " " funcIntermLine; - if (match(funcSoFar, /;$/)) { - # function ends in this line - wrappFunction(funcSoFar, commentEolTot); - isMultiLineFunc = 0; - } - } -} -# 1st line of a function pointer definition -/^[^\/]*CALLING_CONV.*$/ { - - funcStartLine = $0; - # separate possible comment at end of line: //$ foo bar - commentEolTot = ""; - commentEol = funcStartLine; - if (sub(/.*\/\/\$/, "", commentEol)) { - commentEolTot = commentEolTot commentEol; - } - # remove possible comment at end of line: //$ foo bar - sub(/\/\/.*$/, "", funcStartLine); - funcStartLine = trim(funcStartLine); - if (match(funcStartLine, /;$/)) { - # function ends in this line - wrappFunction(funcStartLine, commentEolTot); - } else { - funcSoFar = funcStartLine; - isMultiLineFunc = 1; - } -} - - - -END { - # finalize things - - printNativeFP2F(); -} diff --git a/AI/Interfaces/Java/bin/native_wrappCommands.awk b/AI/Interfaces/Java/bin/native_wrappCommands.awk deleted file mode 100755 index 9de74c4a95f..00000000000 --- a/AI/Interfaces/Java/bin/native_wrappCommands.awk +++ /dev/null @@ -1,384 +0,0 @@ -#!/usr/bin/awk -f -# -# This awk script creates the C functions for wrapping the C command structs in: -# rts/ExternalAI/Interface/AISCommands.h -# -# Before running this script, you have to wrap the native callback struct -# into functions. -# -# This script uses functions from the following files: -# * common.awk -# * commonDoc.awk -# Variables that can be set on the command-line (with -v): -# * GENERATED_SOURCE_DIR the root generated sources dir -# default: "../src-generated/main" -# * NATIVE_GENERATED_SOURCE_DIR the native generated sources dir -# default: GENERATED_SOURCE_DIR + "/native" -# -# usage: -# awk -f thisScript.awk -f common.awk -f commonDoc.awk -# awk -f thisScript.awk -f common.awk -f commonDoc.awk \ -# -v 'NATIVE_GENERATED_SOURCE_DIR=/tmp/build/AI/Interfaces/Java/src-generated/main/native' -# - -BEGIN { - # initialize things - - # define the field splitter(-regex) - FS = "[ \t]+"; - - # These vars can be assigned externally, see file header. - # Set the default values if they were not supplied on the command line. - if (!GENERATED_SOURCE_DIR) { - GENERATED_SOURCE_DIR = "../src-generated/main"; - } - if (!NATIVE_GENERATED_SOURCE_DIR) { - NATIVE_GENERATED_SOURCE_DIR = GENERATED_SOURCE_DIR "/native"; - } - - nativeBridge = "CallbackFunctionPointerBridge"; - bridgePrefix = "bridged__"; - - indent = " "; - - ind_cmdTopics = 0; - ind_cmdStructs = 0; - insideCmdStruct = 0; -} - - -# Checks if a field is available and is no comment -function isFieldUsable(f) { - - valid = 0; - - if (f && !match(f, /.*\/\/.*/)) { - valid = 1; - } - - return valid; -} - - - - -function saveMember(ind_mem, member) { - - name = extractParamName(member); - type_c = extractCType(member); - - cmdsMembers_name[ind_cmdStructs, ind_mem] = name; - cmdsMembers_type_c[ind_cmdStructs, ind_mem] = type_c; -} - - -function doWrapp(ind_cmdStructs_dw) { - - doWrp_dw = 1; - - if (match(cmdsName[ind_cmdStructs_dw], /SharedMemArea/)) { - doWrp_dw = 0; - } else if (match(cmdsName[ind_cmdStructs_dw], /^SCallLuaRulesCommand$/)) { - doWrp_dw = 0; - } - - return doWrp_dw; -} - - -function createNativeFileName(fileName_fn, isHeader_fn) { - - absFileName_fn = NATIVE_GENERATED_SOURCE_DIR "/" fileName_fn; - if (isHeader_fn) { - absFileName_fn = absFileName_fn ".h"; - } else { - absFileName_fn = absFileName_fn ".c"; - } - - return absFileName_fn; -} - - -function printNativeFP2F() { - - outFile_nh = createNativeFileName(nativeBridge, 1); - outFile_nc = createNativeFileName(nativeBridge, 0); - - print("// END: COMMAND_WRAPPERS") >> outFile_nh; - print("") >> outFile_nh; - print("") >> outFile_nc; - - # print the command wrapping functions - for (cmdIndex=0; cmdIndex < ind_cmdStructs; cmdIndex++) { - topicName = cmdsTopicName[cmdIndex]; - topicValue = cmdsTopicNameValue[topicName]; - name = cmdsName[cmdIndex]; - metaInf = cmdsMetaInfo[cmdIndex]; - fullName = metaInf; - sub(/ .*$/, "", fullName); - sub(/^[^ \t]*/, "", metaInf); - - hasRetType = 0; - retType = "int"; - retParam = ""; - paramList = "int _skirmishAIId"; - firstMember = 0; - if (cmdsNumMembers[cmdIndex] > 0) { - for (m=firstMember; m < cmdsNumMembers[cmdIndex]; m++) { - memName = cmdsMembers_name[cmdIndex, m]; - memType_c = cmdsMembers_type_c[cmdIndex, m]; - - if (match(memName, /^ret_/) && !match(memType_c, /\*/)) { - retParam = memName; - retType = memType_c; - hasRetType = 1; - # rewrite the meta info - sub(memName, "RETURN", metaInf); - } else { - paramList = paramList ", " memType_c " " memName; - } - } - } - if (!hasRetType) { - metaInf = metaInf " error-return:0=OK"; - } - paramListNoTypes = removeParamTypes(paramList); - metaInf = trim(metaInf); - - - if (doWrapp(cmdIndex)) { - # print function declaration to *.h - - # Add the member comments to the main comment as @param attributes - numCmdDocLines = cmdsDocComment[cmdIndex, "*"]; - for (m=firstMember; m < cmdsNumMembers[cmdIndex]; m++) { - numLines = cmdMbrsDocComments[cmdIndex*1000 + m, "*"]; - if (numLines > 0) { - cmdsDocComment[cmdIndex, numCmdDocLines] = "@param " cmdsMembers_name[cmdIndex, m]; - } - for (l=0; l < numLines; l++) { - if (l == 0) { - _preDocLine = "@param " cmdsMembers_name[cmdIndex, m] " "; - } else { - _preDocLine = " " lengtAsSpaces(cmdsMembers_name[cmdIndex, m]) " "; - } - cmdsDocComment[cmdIndex, numCmdDocLines] = _preDocLine cmdMbrsDocComments[cmdIndex*1000 + m, l]; - numCmdDocLines++; - } - } - cmdsDocComment[cmdIndex, "*"] = numCmdDocLines; - - outName = bridgePrefix fullName; - - commentEol = ""; - if (metaInf != "") { - commentEol = " // " metaInf; - } - - if (match(fullName, /^Unit_/)) { - # To make this fit in smoothly with the OO structure, - # we want to present each unit command once for the unit class - # and once for the Group class. - - # An other thing we do, is move the common UnitAICommand params - # to the end of the params list, so we can supply default values - # for them more easily later on. - paramList_commonEnd = paramList; - sub(/, short options, int timeOut/, "", paramList_commonEnd); - paramList_commonEnd = paramList_commonEnd ", short options, int timeOut"; - - # Unit version: - paramList_unit = paramList_commonEnd; - sub(/int groupId, /, "", paramList_unit); - printFunctionComment_Common(outFile_nh, cmdsDocComment, cmdIndex, ""); - print("EXPORT(" retType ") " outName "(" paramList_unit ");" commentEol) >> outFile_nh; - print("") >> outFile_nh; - - # Group version: - paramList_group = paramList_commonEnd; - sub(/int unitId, /, "", paramList_group); - outName_group = outName; - sub(/Unit_/, "Group_", outName_group); - printFunctionComment_Common(outFile_nh, cmdsDocComment, cmdIndex, ""); - print("EXPORT(" retType ") " outName_group "(" paramList_group ");" commentEol) >> outFile_nh; - } else { - printFunctionComment_Common(outFile_nh, cmdsDocComment, cmdIndex, ""); - print("EXPORT(" retType ") " outName "(" paramList ");" commentEol) >> outFile_nh; - } - print("") >> outFile_nh; - - # print function definition to *.c - print("") >> outFile_nc; - if (match(fullName, /^Unit_/)) { - # inner version: - print("static " retType " _" outName "(" paramList ") {") >> outFile_nc; - } else { - print("EXPORT(" retType ") " outName "(" paramList ") {") >> outFile_nc; - } - print("") >> outFile_nc; - - print("\t" "struct S" name "Command commandData;") >> outFile_nc; - for (m=firstMember; m < cmdsNumMembers[cmdIndex]; m++) { - memName = cmdsMembers_name[cmdIndex, m]; - memType_c = cmdsMembers_type_c[cmdIndex, m]; - - if (memName == retParam) { - # do nothing - } else { - print("\t" "commandData." memName " = " memName ";") >> outFile_nc; - } - } - print("") >> outFile_nc; - - print("\t" "int _ret = id_clb[_skirmishAIId]->Engine_handleCommand(_skirmishAIId, COMMAND_TO_ID_ENGINE, -1, " topicName ", &commandData);") >> outFile_nc; - print("") >> outFile_nc; - - if (hasRetType) { - # this is unused, delete - print("\t" "if (_ret == 0) {") >> outFile_nc; - print("\t\t" "_ret = commandData." retParam ";") >> outFile_nc; - print("\t" "} else {") >> outFile_nc; - print("\t\t" "_ret = 0;") >> outFile_nc; - print("\t" "}") >> outFile_nc; - } - - print("\t" "return _ret;") >> outFile_nc; - print("}") >> outFile_nc; - - if (match(fullName, /^Unit_/)) { - paramListNoTypes = removeParamTypes(paramList); - - # Unit version: - print("") >> outFile_nc; - print("EXPORT(" retType ") " outName "(" paramList_unit ") {" commentEol) >> outFile_nc; - print("") >> outFile_nc; - print("\t" "const int groupId = -1;") >> outFile_nc; - print("\t" "return _" outName "(" paramListNoTypes ");") >> outFile_nc; - print("}") >> outFile_nc; - print("") >> outFile_nc; - - # Group version: - print("EXPORT(" retType ") " outName_group "(" paramList_group ") {" commentEol) >> outFile_nc; - print("") >> outFile_nc; - print("\t" "const int unitId = -1;") >> outFile_nc; - print("\t" "return _" outName "(" paramListNoTypes ");") >> outFile_nc; - print("}") >> outFile_nc; - } - } else { - print("Java-AIInterface: NOTE: native level: Commands: intentionally not wrapped: " fullName); - } - } - - print("// END: COMMAND_WRAPPERS") >> outFile_nh; - print("") >> outFile_nh; - print("#ifdef __cplusplus") >> outFile_nh; - print("} // extern \"C\"") >> outFile_nh; - print("#endif") >> outFile_nh; - print("") >> outFile_nh; - print("#endif // __CALLBACK_FUNCTION_POINTER_BRIDGE_H") >> outFile_nh; - print("") >> outFile_nh; - - print("") >> outFile_nc; - - close(outFile_nh); - close(outFile_nc); -} - - - - - - -# aggare te los command defines in order -/^[ \t]*COMMAND_.*$/ { - - sub(",", "", $4); - cmdsTopicNameValue[$2] = $4; -} - - - -# This function has to return true (1) if a doc comment (eg: /** foo bar */) -# can be deleted. -# If there is no special condition you want to apply, -# it should always return true (1), -# cause there are additional mechanism to prevent accidental deleting. -# see: commonDoc.awk -function canDeleteDocumentation() { - return isInsideCmdStruct != 1; -} - -################################################################################ -### BEGIN: parsing and saving the command structs - -# end of struct S*Command -/^}; \/\/\$ COMMAND_.*$/ { - - cmdsNumMembers[ind_cmdStructs] = ind_cmdMember; - cmdsTopicName[ind_cmdStructs] = $3; - metaInfo = $0; - sub(/^}; \/\/\$ COMMAND_[^ \t]+/, "", metaInfo); - metaInfo = trim(metaInfo); - cmdsMetaInfo[ind_cmdStructs] = metaInfo; - - if (doWrapp(ind_cmdStructs)) { - #printCommandJava(ind_cmdStructs); - } - - ind_cmdStructs++; - isInsideCmdStruct = 0; -} - - -# inside of struct S*Command -{ - if (isInsideCmdStruct == 1) { - size_tmpMembers = split($0, tmpMembers, ";"); - # cause there is an empty part behind the ';' - size_tmpMembers--; - for (i=1; i<=size_tmpMembers; i++) { - tmpMembers[i] = trim(tmpMembers[i]); - if (tmpMembers[i] == "" || match(tmpMembers[i], /^\/\//)) { - break; - } - # This would bork with more then 1000 members in a command, - # or more then 1000 commands - storeDocLines(cmdMbrsDocComments, ind_cmdStructs*1000 + ind_cmdMember); - saveMember(ind_cmdMember, tmpMembers[i]); - ind_cmdMember++; - } - } -} - -# beginning of struct S*Command -/^struct S.*Command( \{)?/ { - - isInsideCmdStruct = 1; - ind_cmdMember = 0; - commandName = $2; - sub(/^S/, "", commandName); - sub(/Command$/, "", commandName); - - isUnitCommand = match(commandName, /.*Unit$/); - - cmdsIsUnitCmd[ind_cmdStructs] = isUnitCommand; - cmdsName[ind_cmdStructs] = commandName; - storeDocLines(cmdsDocComment, ind_cmdStructs); -} - -# find COMMAND_TO_ID_ENGINE id -/COMMAND_TO_ID_ENGINE/ { - - cmdToIdEngine = $3; -} - -### END: parsing and saving the command structs -################################################################################ - - - -END { - # finalize things - - printNativeFP2F() -} diff --git a/AI/Interfaces/Java/data/InterfaceInfo.lua b/AI/Interfaces/Java/data/InterfaceInfo.lua deleted file mode 100644 index 13b586912a8..00000000000 --- a/AI/Interfaces/Java/data/InterfaceInfo.lua +++ /dev/null @@ -1,51 +0,0 @@ --- --- Info Definition Table format --- --- --- These keywords must be lowercase for LuaParser to read them. --- --- key: user defined or one of the AI_INTERFACE_PROPERTY_* defines in --- SAIInterfaceLibrary.h --- value: the value of the property --- desc: the description (could be used as a tooltip) --- --- --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- - -local infos = { - { - key = 'shortName', - value = 'Java', - desc = 'machine conform name.', - }, - { - key = 'version', - value = '0.1', - }, - { - key = 'name', - value = 'default Java AI Interface', - desc = 'human readable name.', - }, - { - key = 'description', - value = 'This interface is needed for Java AIs', - desc = 'tooltip.', - }, - { - key = 'url', - value = 'https://springrts.com/wiki/AIInterface:Java', - desc = 'URL with more detailed info about the AI', - }, - { - key = 'supportedLanguages', - value = 'Java (possily Groovy, JRuby, ...)', - }, - { - key = 'supportsLookup', - value = 'false', - }, -} - -return infos diff --git a/AI/Interfaces/Java/data/jvm.properties b/AI/Interfaces/Java/data/jvm.properties deleted file mode 100644 index a9642fc78ed..00000000000 --- a/AI/Interfaces/Java/data/jvm.properties +++ /dev/null @@ -1,86 +0,0 @@ -# These options are passed to the JVM instance in which all Java AIs run in. -# CAUTION: Please only change these settings if you know what you are doing!! -# For a list of possible options, please see: -# http://blogs.sun.com/watt/resource/jvm-options-list.html -# and: -# http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp -# If you use do not use the SUN JVM, -# the supported options may differ from this list. -# Each line that does not start with '#' or ';' and contains -# other characters then whitespaces is taken as an option. -# -# NOTE: When specifying relative paths to files (eg. log files), -# be aware that these files will likely end up in springs writable data dir, -# though this is not guaranteed, which means you may have to search for them -# in the CWD of the JVM, which differs between platforms. -# -# NOTE: When specifying paths to files (eg. log files), -# you can make use of ${home-dir}, which will be replaced with something like: -# "{abs-path-to-spring-writable-data-dir}/AI/Interfaces/Java/0.1" -# - -# NOTE: only really useful for debugging -# false: crash and report error when a JVM option was specified, -# that is unknown to the used JVM -# default: true -;jvm.arguments.ignoreUnrecognized=false - -# NOTE: change this if you need fancy stuff only -# specify as hex value, eg. 0x00010004 is JNI_VERSION_1_4 -# see jni.h (look for JNI_VERSION_* defines) -# default: 0x00010004 -;jvm.jni.version=0x00010002 - - -# NOTE: this should not be used, as it is auto-generated -;jvm.option.java.class.path=... -# you may simply store .jar and .class files in the jlib/ folder -# of the Java AI Interface or your Java Skirmish AI. -# the value of this property is appended to the generated java.class.path - -# NOTE: you shall NOT specify the following, as they are auto-generated: -;jvm.option.java.library.path=... -# simply store .dll, .so or .dylib files in the lib/ folder -# of the Java AI Interface or your Java Skirmish AI. -# the value of this property is appended to the generated java.library.path - -# Specify which type of the JVM to use -# possible values: client, server -# default: 32bit: client -# 64bit: server -;jvm.type=server - -# NOTE: do not use these, as the interface will ignore them; -# see jvm.option.java.*.path options above -;jvm.option.x=-Djava.class.path=... -;jvm.option.x=-Djava.library.path=... - -# footprint (memory) related -jvm.option.x=-Xms64M -jvm.option.x=-Xmx512M -jvm.option.x=-Xss512K -jvm.option.x=-Xoss400K - - -# Misc -;jvm.option.x=-XX:+AlwaysRestoreFPU -;jvm.option.x=-Djava.util.logging.config.file=./logging.properties - -# example settings for debugging -# logging related (only recommended when debugging) -;jvm.option.x=-Xcheck:jni -;jvm.option.x=-verbose:jni -;jvm.option.x=-XX:+UnlockDiagnosticVMOptions -;jvm.option.x=-XX:+LogVMOutput -;jvm.option.x=-XX:LogFile=${home-dir}/log/jvm-log.xml - -;jvm.option.x=-Xdebug -;jvm.option.x=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=7777 -# disable JIT (required for debugging under the classical VM) -;jvm.option.x=-Djava.compiler=NONE -# disables old JDB -;jvm.option.x=-Xnoagent - -;jvm.option.x=-XX:ErrorFile=./hs_err_pid.log -;jvm.option.x=-XX:+CheckJNICalls - diff --git a/AI/Interfaces/Java/pom.xml b/AI/Interfaces/Java/pom.xml deleted file mode 100644 index bddb566ede4..00000000000 --- a/AI/Interfaces/Java/pom.xml +++ /dev/null @@ -1,49 +0,0 @@ - - 4.0.0 - - - - - - 0.1 - - - - com.springrts - common-spring - 1.0 - ../../../rts/build/maven/support/common/spring/pom.xml - - - com.springrts - ai-interface-java - ${my.version} - - jar - - Java AI Interface - Java Artificial Intelligence interface plugin for the Spring RTS engine - https://springrts.com/wiki/AIInterface:Java - 2008 - - - - - scm:git:git://github.com/spring/spring.git - scm:git:git@github.com:spring/spring.git - http://github.com/spring/spring/tree/master/AI/Interfaces/Java/ - - - diff --git a/AI/Interfaces/Java/src/main/java/com/springrts/ai/Util.java b/AI/Interfaces/Java/src/main/java/com/springrts/ai/Util.java deleted file mode 100644 index e3a45ebcc99..00000000000 --- a/AI/Interfaces/Java/src/main/java/com/springrts/ai/Util.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - Copyright (c) 2009 Robin Vobruba - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -package com.springrts.ai; - - -import java.awt.Color; - -/** - * Contains utility functions used within all of the Java AI Interface code. - * - * @author hoijui.quaero@gmail.com - * @version 0.1 - */ -public final class Util { - - /** We need no instances of this class */ - private Util() {} - - public static short[] toShort3Array(final Color color) { - - short[] shortArr = new short[3]; - - shortArr[0] = (short) color.getRed(); - shortArr[1] = (short) color.getGreen(); - shortArr[2] = (short) color.getBlue(); - - return shortArr; - } - - public static Color toColor(final short[] shortArr) { - - Color color = new Color( - (int) shortArr[0], - (int) shortArr[1], - (int) shortArr[2] - ); - - return color; - } -} diff --git a/AI/Interfaces/Java/src/main/native/InterfaceDefines.h b/AI/Interfaces/Java/src/main/native/InterfaceDefines.h deleted file mode 100644 index ceb2ebcae59..00000000000 --- a/AI/Interfaces/Java/src/main/native/InterfaceDefines.h +++ /dev/null @@ -1,23 +0,0 @@ -/* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */ - -#ifndef _INTERFACE_DEFINES_H -#define _INTERFACE_DEFINES_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define JAVA_SKIRMISH_AI_PROPERTY_CLASS_NAME "className" - -#define MY_LOG_FILE "interface-log.txt" -#define JAVA_AI_INTERFACE_LIBRARY_FILE_NAME "AIInterface.jar" -#define NATIVE_LIBS_DIR "lib" -#define JRE_LOCATION_FILE "jre-location.txt" - -#include // for NULL - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // _INTERFACE_DEFINES_H diff --git a/AI/Interfaces/Java/src/main/native/InterfaceExport.c b/AI/Interfaces/Java/src/main/native/InterfaceExport.c deleted file mode 100644 index d68714c722e..00000000000 --- a/AI/Interfaces/Java/src/main/native/InterfaceExport.c +++ /dev/null @@ -1,157 +0,0 @@ -/* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */ - -#include "InterfaceExport.h" - -#include "InterfaceDefines.h" -#include "JavaBridge.h" - -// generated at build time -#include "CallbackFunctionPointerBridge.h" - -#include "CUtils/Util.h" -#include "CUtils/SimpleLog.h" - -#include "ExternalAI/Interface/SAIInterfaceLibrary.h" -#include "ExternalAI/Interface/SAIInterfaceCallback.h" -#include "ExternalAI/Interface/SSkirmishAICallback.h" -#include "ExternalAI/Interface/SSkirmishAILibrary.h" - -#include // bool, true, false -#include // strlen(), strcat(), strcpy() -#include // malloc(), calloc(), free() - -static int interfaceId = -1; - -static const struct SAIInterfaceCallback* callback = NULL; -static struct SSkirmishAILibrary jvmSSkirmishAILibrary = {NULL, NULL, NULL, NULL}; - - -EXPORT(int) initStatic(int _interfaceId, const struct SAIInterfaceCallback* _callback) -{ - simpleLog_initcallback(_interfaceId, "Java Interface", _callback->Log_logsl, LOG_LEVEL_INFO); - - // initialize C part of the interface - interfaceId = _interfaceId; - callback = _callback; - - const char* const myShortName = callback->AIInterface_Info_getValueByKey(interfaceId, AI_INTERFACE_PROPERTY_SHORT_NAME); - const char* const myVersion = callback->AIInterface_Info_getValueByKey(interfaceId, AI_INTERFACE_PROPERTY_VERSION); - - if (myShortName == NULL || myVersion == NULL) { - simpleLog_logL(LOG_LEVEL_ERROR, "Couldn't fetch AI Name / Version \"%d\"", _interfaceId); - return -1; - } - - simpleLog_log("Initialized %s v%s AI Interface", myShortName, myVersion); - - // initialize Java part of the interface and the JVM - if (java_initStatic(interfaceId, callback)) { - simpleLog_logL(LOG_LEVEL_NOTICE, "Initialization successful."); - return 0; - } - - simpleLog_logL(LOG_LEVEL_ERROR, "Initialization failed."); - return -1; -} - -EXPORT(int) releaseStatic() -{ - // release Java part of the interface - if (java_releaseStatic() && java_unloadJNIEnv()) - return 0; - - return -1; -} - -EXPORT(enum LevelOfSupport) getLevelOfSupportFor(const char* engineVersion, int engineAIInterfaceGeneratedVersion) -{ - return LOS_Unknown; -} - - -// skirmish AI methods -enum LevelOfSupport CALLING_CONV proxy_skirmishAI_getLevelOfSupportFor( - const char* aiShortName, - const char* aiVersion, - const char* engineVersionString, - int engineVersionNumber, - const char* aiInterfaceShortName, - const char* aiInterfaceVersion -) { - return LOS_Unknown; -} - - -int CALLING_CONV proxy_skirmishAI_init(int skirmishAIId, const struct SSkirmishAICallback* aiCallback) -{ - int ret = -1; - - const char* const shortName = aiCallback->SkirmishAI_Info_getValueByKey(skirmishAIId, SKIRMISH_AI_PROPERTY_SHORT_NAME); - const char* const version = aiCallback->SkirmishAI_Info_getValueByKey(skirmishAIId, SKIRMISH_AI_PROPERTY_VERSION); - const char* const className = aiCallback->SkirmishAI_Info_getValueByKey(skirmishAIId, JAVA_SKIRMISH_AI_PROPERTY_CLASS_NAME); - - if (className != NULL) - ret = java_initSkirmishAIClass(shortName, version, className, skirmishAIId) ? 0 : 1; - - if (ret == 0) { - // init OK - funcPntBrdg_addCallback(skirmishAIId, aiCallback); - ret = java_skirmishAI_init(skirmishAIId, aiCallback); - } - - return ret; -} - -int CALLING_CONV proxy_skirmishAI_release(int skirmishAIId) -{ - // does nothing - const int ret = java_skirmishAI_release(skirmishAIId); - funcPntBrdg_removeCallback(skirmishAIId); - return ret; -} - -int CALLING_CONV proxy_skirmishAI_handleEvent(int skirmishAIId, int topicId, const void* data) -{ - return java_skirmishAI_handleEvent(skirmishAIId, topicId, data); -} - - -EXPORT(const struct SSkirmishAILibrary*) loadSkirmishAILibrary( - const char* const shortName, - const char* const version -) { - // all Java AI's run inside a single JVM proxied by this lib - if (jvmSSkirmishAILibrary.init == NULL) { - jvmSSkirmishAILibrary.getLevelOfSupportFor = &proxy_skirmishAI_getLevelOfSupportFor; -/* - jvmSSkirmishAILibrary.getInfo = proxy_skirmishAI_getInfo; - jvmSSkirmishAILibrary.getOptions = proxy_skirmishAI_getOptions; -*/ - jvmSSkirmishAILibrary.init = &proxy_skirmishAI_init; - jvmSSkirmishAILibrary.release = &proxy_skirmishAI_release; - jvmSSkirmishAILibrary.handleEvent = &proxy_skirmishAI_handleEvent; - } - - return &jvmSSkirmishAILibrary; -} - -EXPORT(int) unloadSkirmishAILibrary( - const char* const shortName, - const char* const version -) { - const char* const className = callback->SkirmishAI_Info_getValueByKey(interfaceId, shortName, version, JAVA_SKIRMISH_AI_PROPERTY_CLASS_NAME); - - if (java_releaseSkirmishAIClass(className)) - return 0; - - return -1; -} - -EXPORT(int) unloadAllSkirmishAILibraries() -{ - if (java_releaseAllSkirmishAIClasses()) - return 0; - - return -1; -} - diff --git a/AI/Interfaces/Java/src/main/native/InterfaceExport.h b/AI/Interfaces/Java/src/main/native/InterfaceExport.h deleted file mode 100644 index 20920ccb563..00000000000 --- a/AI/Interfaces/Java/src/main/native/InterfaceExport.h +++ /dev/null @@ -1,61 +0,0 @@ -/* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */ - -#ifndef _INTERFACE_EXPORT_H -#define _INTERFACE_EXPORT_H - -// check if the correct defines are set by the build system -#if !defined BUILDING_AI_INTERFACE -# error BUILDING_AI_INTERFACE should be defined when building AI Interfaces -#endif -#if !defined BUILDING_AI -# error BUILDING_AI should be defined when building AI Interfaces -#endif -#if defined BUILDING_SKIRMISH_AI -# error BUILDING_SKIRMISH_AI should not be defined when building AI Interfaces -#endif -#if defined SYNCIFY -# error SYNCIFY should not be defined when building AI Interfaces -#endif - - -#include "ExternalAI/Interface/aidefines.h" - -#ifdef __cplusplus -extern "C" { -#endif - -//#include "ExternalAI/Interface/ELevelOfSupport.h" - -struct SSkirmishAILibrary; -struct SAIInterfaceCallback; - -// for a list of the functions that have to be exported, -// see struct SAIInterfaceLibrary in: -// "rts/ExternalAI/Interface/SAIInterfaceLibrary.h" - - -// static AI interface library functions - -EXPORT(int) initStatic(int interfaceId, - const struct SAIInterfaceCallback* callback); -EXPORT(int) releaseStatic(); -//EXPORT(enum LevelOfSupport) getLevelOfSupportFor( -// const char* engineVersion, int engineAIInterfaceGeneratedVersion); - - -// skirmish AI related methods - -EXPORT(const struct SSkirmishAILibrary*) loadSkirmishAILibrary( - const char* const shortName, - const char* const version); -EXPORT(int) unloadSkirmishAILibrary( - const char* const shortName, - const char* const version); -EXPORT(int) unloadAllSkirmishAILibraries(); - - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // _INTERFACE_EXPORT_H diff --git a/AI/Interfaces/Java/src/main/native/JavaBridge.c b/AI/Interfaces/Java/src/main/native/JavaBridge.c deleted file mode 100644 index 1827f63c806..00000000000 --- a/AI/Interfaces/Java/src/main/native/JavaBridge.c +++ /dev/null @@ -1,1219 +0,0 @@ -/* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */ - -#include "JavaBridge.h" - -#include "InterfaceDefines.h" -#include "JvmLocater.h" -#include "JniUtil.h" -#include "EventsJNIBridge.h" -#include "CUtils/Util.h" -#include "CUtils/SimpleLog.h" -#include "CUtils/SharedLibrary.h" - -#include "ExternalAI/Interface/aidefines.h" -#include "ExternalAI/Interface/SAIInterfaceLibrary.h" -#include "ExternalAI/Interface/SAIInterfaceCallback.h" -#include "ExternalAI/Interface/SSkirmishAILibrary.h" -#include "ExternalAI/Interface/SSkirmishAICallback.h" -#include "System/SafeCStrings.h" -#include "lib/streflop/streflopC.h" - -#include - -#include // strlen(), strcat(), strcpy() -#include // malloc(), calloc(), free() -#include - -struct Properties { - size_t size; - const char** keys; - const char** values; -}; - -static int interfaceId = -1; - -static const struct SAIInterfaceCallback* callback = NULL; -static struct Properties jvmCfgProps = {0, NULL, NULL}; - -static size_t numSkirmishAIs = 0; -// static const size_t maxSkirmishAIs = 255; // MAX_AIS -#define maxSkirmishAIs 255 - -static size_t skirmishAIId_skirmishAiImpl[maxSkirmishAIs] = {999999}; - -static char* jAIClassNames[maxSkirmishAIs] = {NULL}; - -static jobject jAIInstances[maxSkirmishAIs] = {NULL}; -static jobject jAIClassLoaders[maxSkirmishAIs] = {NULL}; -static jobject jAICallBacks[maxSkirmishAIs] = {NULL}; - -// vars used to integrate the JVM -// it is loaded at runtime, not at loadtime -static sharedLib_t jvmSharedLib = NULL; - -typedef jint (JNICALL JNI_GetDefaultJavaVMInitArgs_t)(void* vmArgs); -typedef jint (JNICALL JNI_CreateJavaVM_t)(JavaVM** vm, void** jniEnv, void* vmArgs); -typedef jint (JNICALL JNI_GetCreatedJavaVMs_t)(JavaVM** vms, jsize vms_sizeMax, jsize* vms_size); - -static JNI_GetDefaultJavaVMInitArgs_t* JNI_GetDefaultJavaVMInitArgs_f; -static JNI_CreateJavaVM_t* JNI_CreateJavaVM_f; -static JNI_GetCreatedJavaVMs_t* JNI_GetCreatedJavaVMs_f; - - -// ### JNI global vars ### - -/// Java VM instance reference -static JavaVM* g_jvm = NULL; - -/// AI Callback class -static jclass g_cls_aiCallback = NULL; -/// AI Callback Constructor: AICallback(int skirmishAIId) -static jmethodID g_m_aiCallback_ctor_I = NULL; - -/// Basic AI interface. -static jclass g_cls_ai_int = NULL; - - - -// ### General helper functions following ### - -/// Sets the FPU state to how spring likes it -static inline void java_establishSpringEnv() { - // only detach in java_unloadJNIEnv - // (*g_jvm)->DetachCurrentThread(g_jvm); - streflop_init_Simple(); -} - -/// The JVM sets the environment it wants automatically, so this is a no-op -static inline void java_establishJavaEnv() {} - - -static inline size_t minSize(size_t size1, size_t size2) { - return (size1 < size2) ? size1 : size2; -} - -static const char* java_getValueByKey(const struct Properties* props, const char* key) { - return util_map_getValueByKey(props->size, props->keys, props->values, key); -} - - -// /** -// * Called when the JVM loads this native library. -// */ -// JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) { -// return JNI_VERSION_1_6; -// } -// -// /** -// * Called when the JVM unloads this native library. -// */ -// JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved) {} - - - - -// ### JNI helper functions following ### - -/** - * Creates the AI Interface global Java class path. - * - * It will consist of the following: - * {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/{version}/AIInterface.jar - * {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/{version}/(j)?config/ - * {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/{version}/(j)?config/[*].jar - * {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/{version}/(j)?resources/ - * {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/{version}/(j)?resources/[*].jar - * {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/{version}/(j)?script/ - * {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/{version}/(j)?script/[*].jar - * {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/{version}/jlib/ - * {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/{version}/jlib/[*].jar - * TODO: {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/common/jlib/ - * TODO: {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/common/jlib/[*].jar - */ -static bool java_createClassPath(char* classPathStr, const size_t classPathStr_sizeMax) -{ - // the dirs and .jar files in the following array - // will be concatenated with intermediate path separators - // to form the classPathStr - static const size_t classPath_sizeMax = 128; - char** classPath = (char**) calloc(classPath_sizeMax, sizeof(char*)); - size_t classPath_size = 0; - - // the Java AI Interfaces java library file path (.../AIInterface.jar) - // We need to search for this jar, instead of looking only where - // the AIInterface.so/InterfaceInfo.lua is, because on some systems - // (eg. Debian), the .so is in /usr/lib, and the .jar's are in /usr/shared. - char mainJarPath[2048]; - const bool located = callback->DataDirs_locatePath(interfaceId, - mainJarPath, sizeof(mainJarPath), - JAVA_AI_INTERFACE_LIBRARY_FILE_NAME, - false, false, false, false); - - if (!located) { - simpleLog_logL(LOG_LEVEL_ERROR, "Couldn't find %s", JAVA_AI_INTERFACE_LIBRARY_FILE_NAME); - return false; - } - - classPath[classPath_size++] = util_allocStrCpy(mainJarPath); - - if (!util_getParentDir(mainJarPath)) { - simpleLog_logL(LOG_LEVEL_ERROR, "Retrieving the parent dir of the path to AIInterface.jar (%s) failed.", mainJarPath); - return false; - } - - char* jarsDataDir = mainJarPath; - - // the directories in the following list will be searched for .jar files - // which will then be added to the classPathStr, plus the dirs will be added - // to the classPathStr directly, so you can keep .class files in there - static const size_t jarDirs_sizeMax = 128; - char** jarDirs = (char**) calloc(jarDirs_sizeMax, sizeof(char*)); - size_t jarDirs_size = 0; - - // add to classpath: - // {spring-data-dir}/Interfaces/Java/0.1/${x}/ - jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, jarsDataDir, "jconfig"); - jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, jarsDataDir, "config"); - jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, jarsDataDir, "jresources"); - jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, jarsDataDir, "resources"); - jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, jarsDataDir, "jscript"); - jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, jarsDataDir, "script"); - jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, jarsDataDir, "jlib"); - // "lib" is for native libs only - - // add the jar dirs (for .class files) and all contained .jars recursively - size_t jd, jf; - for (jd = 0; (jd < jarDirs_size) && (classPath_size < classPath_sizeMax); ++jd) { - if (util_fileExists(jarDirs[jd])) { - // add the dir directly - // For this to work properly with URLClassPathHandler, - // we have to ensure there is a '/' at the end, - // for the class-path-part to be recognized as a directory. - classPath[classPath_size++] = util_allocStrCat(2, jarDirs[jd], "/"); - - // add the contained jars recursively - static const size_t jarFiles_sizeMax = 128; - char** jarFiles = (char**) calloc(jarFiles_sizeMax, sizeof(char*)); - const size_t jarFiles_size = util_listFiles(jarDirs[jd], ".jar", jarFiles, true, jarFiles_sizeMax); - - for (jf = 0; (jf < jarFiles_size) && (classPath_size < classPath_sizeMax); ++jf) { - classPath[classPath_size++] = util_allocStrCatFSPath(2, jarDirs[jd], jarFiles[jf]); - FREE(jarFiles[jf]); - } - - FREE(jarFiles); - } - - FREE(jarDirs[jd]); - } - - FREE(jarDirs); - - - // concat the classpath entries - classPathStr[0] = '\0'; - if (classPath[0] != NULL) { - STRCAT_T(classPathStr, classPathStr_sizeMax, classPath[0]); - FREE(classPath[0]); - } - - size_t cp; - - for (cp = 1; cp < classPath_size; ++cp) { - if (classPath[cp] == NULL) - continue; - - STRCAT_T(classPathStr, classPathStr_sizeMax, ENTRY_DELIM); - STRCAT_T(classPathStr, classPathStr_sizeMax, classPath[cp]); - FREE(classPath[cp]); - } - - FREE(classPath); - return true; -} - -/** - * Creates a Skirmish AI local Java class path. - * - * It will consist of the following: - * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/{ai-version}/SkirmishAI.jar - * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/{ai-version}/(j)?config/ - * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/{ai-version}/(j)?config/[*].jar - * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/{ai-version}/(j)?resources/ - * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/{ai-version}/(j)?resources/[*].jar - * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/{ai-version}/(j)?script/ - * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/{ai-version}/(j)?script/[*].jar - * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/{ai-version}/jlib/ - * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/{ai-version}/jlib/[*].jar - * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/common/(j)?config/ - * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/common/(j)?config/[*].jar - * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/common/(j)?resources/ - * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/common/(j)?resources/[*].jar - * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/common/(j)?script/ - * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/common/(j)?script/[*].jar - * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/common/jlib/ - * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/common/jlib/[*].jar - */ -static size_t java_createAIClassPath( - const char* shortName, - const char* version, - char** classPathParts, - const size_t classPathParts_sizeMax -) { - size_t classPathParts_size = 0; - - // the .jar files in the following list will be added to the classpath - const size_t jarFiles_sizeMax = classPathParts_sizeMax; - char** jarFiles = (char**) calloc(jarFiles_sizeMax, sizeof(char*)); - size_t jarFiles_size = 0; - - const char* const skirmDD = - callback->SkirmishAI_Info_getValueByKey(interfaceId, - shortName, version, - SKIRMISH_AI_PROPERTY_DATA_DIR); - if (skirmDD == NULL) { - simpleLog_logL(LOG_LEVEL_ERROR, - "Retrieving the data-dir of Skirmish AI %s-%s failed.", - shortName, version); - } - // {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/{ai-version}/SkirmishAI.jar - jarFiles[jarFiles_size++] = util_allocStrCatFSPath(2, - skirmDD, "SkirmishAI.jar"); - - // the directories in the following list will be searched for .jar files - // which then will be added to the classpath, plus they will be added - // to the classpath directly, so you can keep .class files in there - const size_t jarDirs_sizeMax = classPathParts_sizeMax; - char** jarDirs = (char**) calloc(jarDirs_sizeMax, sizeof(char*)); - size_t jarDirs_size = 0; - - // add to classpath ... - - // {spring-data-dir}/Skirmish/MyJavaAI/0.1/SkirmishAI/ - // this can be useful for AI devs while testing, - // if they do not want to put everything into a jar all the time - jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDD, "SkirmishAI"); - - // add to classpath: - // {spring-data-dir}/Skirmish/MyJavaAI/0.1/${x}/ - jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDD, "jconfig"); - jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDD, "config"); - jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDD, "jresources"); - jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDD, "resources"); - jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDD, "jscript"); - jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDD, "script"); - jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDD, "jlib"); - // "lib" is for native libs only - - // add the dir common for all versions of the Skirmish AI, - // if it is specified and exists - const char* const skirmDDCommon = - callback->SkirmishAI_Info_getValueByKey(interfaceId, - shortName, version, - SKIRMISH_AI_PROPERTY_DATA_DIR_COMMON); - - if (skirmDDCommon != NULL) { - // add to classpath: - // {spring-data-dir}/Skirmish/MyJavaAI/common/${x}/ - jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDDCommon, "jconfig"); - jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDDCommon, "config"); - jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDDCommon, "jresources"); - jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDDCommon, "resources"); - jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDDCommon, "jscript"); - jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDDCommon, "script"); - jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDDCommon, "jlib"); - // "lib" is for native libs only - } - - // add the directly specified .jar files - size_t jf; - for (jf = 0; (jf < jarFiles_size) && (classPathParts_size < classPathParts_sizeMax); ++jf) { - classPathParts[classPathParts_size++] = util_allocStrCpy(jarFiles[jf]); - FREE(jarFiles[jf]); - } - - // add the dirs and the contained .jar files - size_t jd, sjf; - for (jd = 0; (jd < jarDirs_size) && (classPathParts_size < classPathParts_sizeMax); ++jd) { - if (jarDirs[jd] != NULL && util_fileExists(jarDirs[jd])) { - // add the jar dir (for .class files) - // For this to work properly with URLClassPathHandler, - // we have to ensure there is a '/' at the end, - // for the class-path-part to be recognized as a directory. - classPathParts[classPathParts_size++] = util_allocStrCat(2, jarDirs[jd], "/"); - - // add the jars in the dir - const size_t subJarFiles_sizeMax = classPathParts_sizeMax - classPathParts_size; - char** subJarFiles = (char**) calloc(subJarFiles_sizeMax, sizeof(char*)); - const size_t subJarFiles_size = util_listFiles(jarDirs[jd], ".jar", subJarFiles, true, subJarFiles_sizeMax); - - for (sjf = 0; (sjf < subJarFiles_size) && (classPathParts_size < classPathParts_sizeMax); ++sjf) { - // .../[*].jar - classPathParts[classPathParts_size++] = util_allocStrCatFSPath(2, jarDirs[jd], subJarFiles[sjf]); - FREE(subJarFiles[sjf]); - } - - FREE(subJarFiles); - } - - FREE(jarDirs[jd]); - } - - FREE(jarDirs); - FREE(jarFiles); - - return classPathParts_size; -} - -static jobject java_createAIClassLoader(JNIEnv* env, const char* shortName, const char* version) -{ - static const size_t classPathParts_sizeMax = 512; - char** classPathParts = (char**) calloc(classPathParts_sizeMax, sizeof(char*)); - const size_t classPathParts_size = java_createAIClassPath(shortName, version, classPathParts, classPathParts_sizeMax); - - jobject o_jClsLoader = NULL; - jobjectArray o_cppURLs = jniUtil_createURLArray(env, classPathParts_size); - - if (o_cppURLs != NULL) { -#ifdef _WIN32 - static const char* FILE_URL_PREFIX = "file:///"; -#else // _WIN32 - static const char* FILE_URL_PREFIX = "file://"; -#endif // _WIN32 - size_t cpp; - for (cpp = 0; cpp < classPathParts_size; ++cpp) { - #ifdef _WIN32 - // we can not use windows path separators in file URLs - util_strReplaceChar(classPathParts[cpp], '\\', '/'); - #endif - - char* str_fileUrl = util_allocStrCat(2, FILE_URL_PREFIX, classPathParts[cpp]); - // TODO: check/test if this is allowed/ok - FREE(classPathParts[cpp]); - simpleLog_logL(LOG_LEVEL_INFO, - "Skirmish AI %s %s class-path part %i: \"%s\"", - shortName, version, cpp, str_fileUrl); - jobject jurl_fileUrl = jniUtil_createURLObject(env, str_fileUrl); - FREE(str_fileUrl); - if (jurl_fileUrl == NULL) { - simpleLog_logL(LOG_LEVEL_ERROR, - "Skirmish AI %s %s class-path part %i (\"%s\"): failed to create a URL", - shortName, version, cpp, str_fileUrl); - o_cppURLs = NULL; - break; - } - const bool inserted = jniUtil_insertURLIntoArray(env, o_cppURLs, cpp, jurl_fileUrl); - if (!inserted) { - simpleLog_logL(LOG_LEVEL_ERROR, - "Skirmish AI %s %s class-path part %i (\"%s\"): failed to insert", - shortName, version, cpp, str_fileUrl); - o_cppURLs = NULL; - break; - } - } - } - - if (o_cppURLs != NULL) { - if ((o_jClsLoader = jniUtil_createURLClassLoader(env, o_cppURLs)) != NULL) - o_jClsLoader = jniUtil_makeGlobalRef(env, o_jClsLoader, "Skirmish AI class-loader"); - } - - FREE(classPathParts); - return o_jClsLoader; -} - -/** - * Load the interfaces JVM properties file. - */ -static bool java_readJvmCfgFile(struct Properties* props) -{ - bool read = false; - - const size_t props_sizeMax = 256; - - props->size = 0; - props->keys = (const char**) calloc(props_sizeMax, sizeof(char*)); - props->values = (const char**) calloc(props_sizeMax, sizeof(char*)); - - // ### read JVM options config file ### - char jvmPropFile[2048]; - bool located = callback->DataDirs_locatePath(interfaceId, jvmPropFile, sizeof(jvmPropFile), JVM_PROPERTIES_FILE, false, false, false, false); - - // if the version specific file does not exist, - // try to get the common one - if (!located) - located = callback->DataDirs_locatePath(interfaceId, jvmPropFile, sizeof(jvmPropFile), JVM_PROPERTIES_FILE, false, false, false, true); - - if (located) { - props->size = util_parsePropertiesFile(jvmPropFile, props->keys, props->values, props_sizeMax); - read = true; - simpleLog_logL(LOG_LEVEL_INFO, "JVM: arguments loaded from: %s", jvmPropFile); - } else { - props->size = 0; - read = false; - simpleLog_logL(LOG_LEVEL_INFO, "JVM: arguments NOT loaded"); - } - - return read; -} - -/** - * Creates the Java library path. - * -> where native shared libraries are searched - * - * It will consist of the following: - * {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/{version}/ - * {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/{version}/lib/ - * {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/common/ - * {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/common/lib/ - */ -static bool java_createNativeLibsPath(char* libraryPath, const size_t libraryPath_sizeMax) -{ - // {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/{version}/ - const char* const dd_r = callback->AIInterface_Info_getValueByKey(interfaceId, AI_INTERFACE_PROPERTY_DATA_DIR); - - if (dd_r == NULL) { - simpleLog_logL(LOG_LEVEL_ERROR, "Unable to find read-only data-dir."); - return false; - } - - STRCPY_T(libraryPath, libraryPath_sizeMax, dd_r); - - // {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/{version}/lib/ - char dd_lib_r[2048]; - const bool located = callback->DataDirs_locatePath(interfaceId, dd_lib_r, sizeof(dd_lib_r), NATIVE_LIBS_DIR, false, false, true, false); - - if (!located) { - simpleLog_logL(LOG_LEVEL_NOTICE, "Unable to find read-only native libs data-dir (optional): %s", NATIVE_LIBS_DIR); - } else { - STRCAT_T(libraryPath, libraryPath_sizeMax, ENTRY_DELIM); - STRCAT_T(libraryPath, libraryPath_sizeMax, dd_lib_r); - } - - - // {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/common/ - const char* const dd_r_common = callback->AIInterface_Info_getValueByKey(interfaceId, AI_INTERFACE_PROPERTY_DATA_DIR_COMMON); - - if (dd_r_common == NULL || !util_fileExists(dd_r_common)) { - simpleLog_logL(LOG_LEVEL_NOTICE, "Unable to find common read-only data-dir (optional)."); - } else { - STRCAT_T(libraryPath, libraryPath_sizeMax, ENTRY_DELIM); - STRCAT_T(libraryPath, libraryPath_sizeMax, dd_r_common); - } - - - // {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/common/lib/ - if (dd_r_common != NULL) { - char dd_lib_r_common[2048]; - const bool located = callback->DataDirs_locatePath(interfaceId, dd_lib_r_common, sizeof(dd_lib_r_common), NATIVE_LIBS_DIR, false, false, true, true); - - if (!located || !util_fileExists(dd_lib_r_common)) { - simpleLog_logL(LOG_LEVEL_NOTICE, "Unable to find common read-only native libs data-dir (optional)."); - } else { - STRCAT_T(libraryPath, libraryPath_sizeMax, ENTRY_DELIM); - STRCAT_T(libraryPath, libraryPath_sizeMax, dd_lib_r_common); - } - } - - return true; -} - - -static bool java_createJavaVMInitArgs(struct JavaVMInitArgs* vm_args, const struct Properties* jvmProps) -{ - // jint jniVersion = JNI_VERSION_1_1; - // jint jniVersion = JNI_VERSION_1_2; - jint jniVersion = JNI_VERSION_1_4; - // jint jniVersion = JNI_VERSION_1_6; - - char classPath [8 * 1024] = {0}; - char classPathOpt[8 * 1024] = {0}; - char libraryPath [4 * 1024] = {0}; - char libraryPathOpt[4 * 1024] = {0}; - - bool ignoreUnrecognized = true; - - if (jvmProps != NULL) { - const char* jniVersionFromCfg = java_getValueByKey(jvmProps, "jvm.jni.version"); - const char* ignoreUnrecognizedFromCfg = java_getValueByKey(jvmProps, "jvm.arguments.ignoreUnrecognized"); - - // ### evaluate JNI version to use ### - if (jniVersionFromCfg != NULL) { - const unsigned long int jniVersion_tmp = strtoul(jniVersionFromCfg, NULL, 16); - - if (jniVersion_tmp != 0 /*&& jniVersion_tmp != ULONG_MAX*/) - jniVersion = (jint) jniVersion_tmp; - } - - // ### check if unrecognized JVM options should be ignored ### - // if false, the JVM creation will fail if an - // unknown or invalid option was specified - if (ignoreUnrecognizedFromCfg != NULL && !util_strToBool(ignoreUnrecognizedFromCfg)) - ignoreUnrecognized = false; - } - - simpleLog_logL(LOG_LEVEL_INFO, "JVM: JNI version: %#x", jniVersion); - vm_args->version = jniVersion; - - - if (ignoreUnrecognized) { - simpleLog_logL(LOG_LEVEL_INFO, "JVM: ignoring unrecognized options"); - vm_args->ignoreUnrecognized = JNI_TRUE; - } else { - simpleLog_logL(LOG_LEVEL_INFO, "JVM: NOT ignoring unrecognized options"); - vm_args->ignoreUnrecognized = JNI_FALSE; - } - - - // ### create the Java class-path option ### - // autogenerate the class path - if (!java_createClassPath(classPath, sizeof(classPath))) { - simpleLog_logL(LOG_LEVEL_ERROR, "Failed creating Java class-path."); - return false; - } - if (jvmProps != NULL) { - // ..., and append the part from the jvm options properties file, - // if it is specified there - const char* clsPathFromCfg = java_getValueByKey(jvmProps, "jvm.option.java.class.path"); - - if (clsPathFromCfg != NULL) { - STRCAT_T(classPath, sizeof(classPath), ENTRY_DELIM); - STRCAT_T(classPath, sizeof(classPath), clsPathFromCfg); - } - } - - - // create the java.class.path option - STRCPY_T(classPathOpt, sizeof(classPathOpt), "-Djava.class.path="); - STRCAT_T(classPathOpt, sizeof(classPathOpt), classPath); - - - // ### create the Java library-path option ### - // autogenerate the java library path - if (!java_createNativeLibsPath(libraryPath, sizeof(libraryPath))) { - simpleLog_logL(LOG_LEVEL_ERROR, "Failed creating Java library-path."); - return false; - } - if (jvmProps != NULL) { - // ..., and append the part from the jvm options properties file, - // if it is specified there - const char* libPathFromCfg = java_getValueByKey(jvmProps, "jvm.option.java.library.path"); - - if (libPathFromCfg != NULL) { - STRCAT_T(libraryPath, sizeof(libraryPath), ENTRY_DELIM); - STRCAT_T(libraryPath, sizeof(libraryPath), libPathFromCfg); - } - } - - // create the java.library.path option ... - // autogenerate it, and append the part from the jvm options file, - // if it is specified there - STRCPY_T(libraryPathOpt, sizeof(libraryPathOpt), "-Djava.library.path="); - STRCAT_T(libraryPathOpt, sizeof(libraryPathOpt), libraryPath); - - - // ### create and set all JVM options ### - const char* strOptions[64]; - size_t numOpts = 0; - - strOptions[numOpts++] = classPathOpt; - strOptions[numOpts++] = libraryPathOpt; - - static const char* const JCPVAL = "-Djava.class.path="; - static const char* const JLPVAL = "-Djava.library.path="; - const size_t JCPVAL_size = strlen(JCPVAL); - const size_t JLPVAL_size = strlen(JCPVAL); - - if (jvmProps != NULL) { - // ### add string options from the JVM config file with property name "jvm.option.x" ### - int i; - for (i = 0; i < jvmProps->size; ++i) { - if (strcmp(jvmProps->keys[i], "jvm.option.x") != 0) - continue; - - const char* const val = jvmProps->values[i]; - const size_t val_size = strlen(val); - // ignore "-Djava.class.path=..." - // and "-Djava.library.path=..." options - if (strncmp(val, JCPVAL, minSize(val_size, JCPVAL_size)) != 0 && - strncmp(val, JLPVAL, minSize(val_size, JLPVAL_size)) != 0) { - strOptions[numOpts++] = val; - } - } - } else { - // ### ... or set default ones, if the JVM config file was not found ### - simpleLog_logL(LOG_LEVEL_WARNING, "JVM: properties file ("JVM_PROPERTIES_FILE") not found; using default options."); - - strOptions[numOpts++] = "-Xms64M"; - strOptions[numOpts++] = "-Xmx512M"; - strOptions[numOpts++] = "-Xss512K"; - strOptions[numOpts++] = "-Xoss400K"; - - #if defined DEBUG - strOptions[numOpts++] = "-Xcheck:jni"; - strOptions[numOpts++] = "-verbose:jni"; - strOptions[numOpts++] = "-XX:+UnlockDiagnosticVMOptions"; - strOptions[numOpts++] = "-XX:+LogVMOutput"; - - strOptions[numOpts++] = "-Xdebug"; - strOptions[numOpts++] = "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=7777"; - // disable JIT (required for debugging under the classical VM) - strOptions[numOpts++] = "-Djava.compiler=NONE"; - // disable old JDB - strOptions[numOpts++] = "-Xnoagent"; - #endif // defined DEBUG - } - - vm_args->options = (struct JavaVMOption*) calloc(numOpts, sizeof(struct JavaVMOption)); - vm_args->nOptions = 0; - - // fill strOptions into the JVM options - simpleLog_logL(LOG_LEVEL_INFO, "JVM: options:", numOpts); - char dd_rw[2048] = {'\0'}; - callback->DataDirs_locatePath(interfaceId, dd_rw, sizeof(dd_rw), "", true, true, true, false); - size_t i; - - for (i = 0; i < numOpts; ++i) { - char* tmpOptionString = util_allocStrReplaceStr(strOptions[i], "${home-dir}", dd_rw); - - // do not add empty options - if (tmpOptionString == NULL) - continue; - - if (strlen(tmpOptionString) == 0) { - free(tmpOptionString); - tmpOptionString = NULL; - continue; - } - - vm_args->options[vm_args->nOptions ].optionString = tmpOptionString; - vm_args->options[vm_args->nOptions++].extraInfo = NULL; - - simpleLog_logL(LOG_LEVEL_INFO, "JVM option %ul: %s", vm_args->nOptions - 1, tmpOptionString); - } - - simpleLog_logL(LOG_LEVEL_INFO, ""); - return true; -} - - - -static JNIEnv* java_reattachCurrentThread(JavaVM* jvm) -{ - simpleLog_logL(LOG_LEVEL_DEBUG, "Reattaching current thread..."); - - JNIEnv* env = NULL; - - // const jint res = (*jvm)->AttachCurrentThreadAsDaemon(jvm, (void**) &env, NULL); - const jint res = (*jvm)->AttachCurrentThread(jvm, (void**) &env, NULL); - - if (res != 0) { - env = NULL; - simpleLog_logL(LOG_LEVEL_ERROR, "Failed attaching JVM to current thread(2): %i - %s", res, jniUtil_getJniRetValDescription(res)); - } - - return env; -} - -static JNIEnv* java_getJNIEnv(bool preload) -{ - if (g_jvm != NULL) - return java_reattachCurrentThread(g_jvm); - - assert(preload); - simpleLog_logL(LOG_LEVEL_INFO, "Creating the JVM."); - - JNIEnv* ret = NULL; - JNIEnv* env = NULL; - JavaVM* jvm = NULL; - - struct JavaVMInitArgs vm_args; - memset(&vm_args, 0, sizeof(vm_args)); - - jint res = 0; - - if (!java_createJavaVMInitArgs(&vm_args, &jvmCfgProps)) { - simpleLog_logL(LOG_LEVEL_ERROR, "Failed initializing JVM init-arguments."); - goto end; - } - - // Looking for existing JVMs might be problematic: they could - // have been initialized with other JVM-arguments then we need. - // But as we can not use DestroyJavaVM (it makes creating a new - // one for the same process impossible, a (SUN?) JVM limitation) - // we have to do this anyway to support /aireload and /aicontrol - // for Java Skirmish AIs. - // - simpleLog_logL(LOG_LEVEL_INFO, "looking for existing JVMs ..."); - jsize numJVMsFound = 0; - - // grab the first Java VM that has been created - if ((res = JNI_GetCreatedJavaVMs_f(&jvm, 1, &numJVMsFound)) != 0) { - jvm = NULL; - simpleLog_logL(LOG_LEVEL_ERROR, "Failed fetching list of running JVMs: %i - %s", res, jniUtil_getJniRetValDescription(res)); - goto end; - } - - simpleLog_logL(LOG_LEVEL_INFO, "number of existing JVMs: %i", numJVMsFound); - - if (numJVMsFound > 0) { - simpleLog_logL(LOG_LEVEL_INFO, "using an already running JVM."); - } else { - simpleLog_logL(LOG_LEVEL_INFO, "creating JVM..."); - - if ((res = JNI_CreateJavaVM_f(&jvm, (void**) &env, &vm_args)) != 0 || (*env)->ExceptionCheck(env)) { - simpleLog_logL(LOG_LEVEL_ERROR, "Failed to create Java VM: %i - %s", res, jniUtil_getJniRetValDescription(res)); - goto end; - } - } - - // free the JavaVMInitArgs content - jint i; - for (i = 0; i < vm_args.nOptions; ++i) { - FREE(vm_args.options[i].optionString); - } - FREE(vm_args.options); - - //res = (*jvm)->AttachCurrentThreadAsDaemon(jvm, (void**) &env, NULL); - res = (*jvm)->AttachCurrentThread(jvm, (void**) &env, NULL); - - if (res < 0 || (*env)->ExceptionCheck(env)) { - if ((*env)->ExceptionCheck(env)) - (*env)->ExceptionDescribe(env); - - simpleLog_logL(LOG_LEVEL_ERROR, "Failed to attach JVM to current thread: %i - %s", res, jniUtil_getJniRetValDescription(res)); - goto end; - } - -end: - if (env == NULL || jvm == NULL || (*env)->ExceptionCheck(env) || res != 0) { - simpleLog_logL(LOG_LEVEL_ERROR, "JVM: Failed creating."); - - if (env != NULL && (*env)->ExceptionCheck(env)) - (*env)->ExceptionDescribe(env); - - if (jvm != NULL) { - // never destroy the JVM, doing so prevents it from being created again for the same thread - // res = (*jvm)->DestroyJavaVM(jvm); - } - - g_jvm = NULL; - ret = NULL; - } else { - g_jvm = jvm; - ret = env; - } - - return ret; -} - - -bool java_unloadJNIEnv() -{ - if (g_jvm == NULL) - return true; - - simpleLog_logL(LOG_LEVEL_INFO, "JVM: Unloading ..."); - - #if 0 - // JNIEnv* jniEnv = java_getJNIEnv(false); - - // We have to be the ONLY running thread (native and Java) - // this may not help, but will not hurt either - // - // // jint res = (*g_jvm)->AttachCurrentThreadAsDaemon(g_jvm, (void**) &g_jniEnv, NULL); - // jint res = jvm->AttachCurrentThread((void**) &jniEnv, NULL); - #endif - - #if 0 - if (res < 0 || (*g_jniEnv)->ExceptionCheck(g_jniEnv)) { - if ((*g_jniEnv)->ExceptionCheck(g_jniEnv)) - (*g_jniEnv)->ExceptionDescribe(g_jniEnv); - - simpleLog_logL(LOG_LEVEL_ERROR, "JVM: Can not Attach to the current thread: %i - %s", res, jniUtil_getJniRetValDescription(res)); - return false; - } - #endif - - - const jint res = (*g_jvm)->DetachCurrentThread(g_jvm); - - if (res != 0) { - simpleLog_logL(LOG_LEVEL_ERROR, "JVM: Failed detaching current thread: %i - %s", res, jniUtil_getJniRetValDescription(res)); - return false; - } - - // never destroy the JVM because then it can not be created again - // in the same thread; will always fail with return value -1 (see - // java_getJNIEnv) - #if 0 - if ((res = (*g_jvm)->DestroyJavaVM(g_jvm)) != 0) { - simpleLog_logL(LOG_LEVEL_ERROR, "JVM: Failed destroying: %i - %s", res, jniUtil_getJniRetValDescription(res)); - return false; - } - - simpleLog_logL(LOG_LEVEL_NOTICE, "JVM: Successfully destroyed"); - g_jvm = NULL; - #endif - - java_establishSpringEnv(); - return true; -} - - -bool java_initStatic(int _interfaceId, const struct SAIInterfaceCallback* _callback) -{ - interfaceId = _interfaceId; - callback = _callback; - - // Read the jvm properties config file - java_readJvmCfgFile(&jvmCfgProps); - - size_t t; - for (t = 0; t < maxSkirmishAIs; ++t) { - skirmishAIId_skirmishAiImpl[t] = 999999; - } - - size_t sai; - for (sai = 0; sai < maxSkirmishAIs; ++sai) { - jAIClassNames[sai] = NULL; - jAIInstances[sai] = NULL; - jAIClassLoaders[sai] = NULL; - } - - // dynamically load the JVM - char jreLocationFile[2048]; - const bool located = callback->DataDirs_locatePath(interfaceId, jreLocationFile, sizeof(jreLocationFile), JRE_LOCATION_FILE, false, false, false, false); - char jrePath[1024]; - char jvmLibPath[1024]; - - if (!GetJREPath(jrePath, sizeof(jrePath), located ? jreLocationFile : NULL, NULL)) { - simpleLog_logL(LOG_LEVEL_ERROR, "Failed locating a JRE installation, you may specify the JAVA_HOME env var."); - return false; - } - - simpleLog_logL(LOG_LEVEL_NOTICE, "Using JRE (can be changed with JAVA_HOME): %s", jrePath); - -#if defined __arch64__ - static const char* defJvmType = "server"; -#else - static const char* defJvmType = "client"; -#endif - const char* jvmType = java_getValueByKey(&jvmCfgProps, "jvm.type"); - - if (jvmType == NULL) - jvmType = defJvmType; - - if (!GetJVMPath(jrePath, jvmType, jvmLibPath, sizeof(jvmLibPath), NULL)) { - simpleLog_logL(LOG_LEVEL_ERROR, "Failed locating the %s version of the JVM, please contact spring devs.", jvmType); - return false; - } - - if (!sharedLib_isLoaded(jvmSharedLib = sharedLib_load(jvmLibPath))) { - simpleLog_logL(LOG_LEVEL_ERROR, "Failed to load the JVM at \"%s\".", jvmLibPath); - return false; - } - - simpleLog_logL(LOG_LEVEL_NOTICE, "Successfully loaded the JVM shared library at \"%s\".", jvmLibPath); - - if ((JNI_GetDefaultJavaVMInitArgs_f = (JNI_GetDefaultJavaVMInitArgs_t*) sharedLib_findAddress(jvmSharedLib, "JNI_GetDefaultJavaVMInitArgs")) == NULL) { - simpleLog_logL(LOG_LEVEL_ERROR, "Failed to load the JVM, function \"%s\" not exported.", "JNI_GetDefaultJavaVMInitArgs"); - return false; - } - - if ((JNI_CreateJavaVM_f = (JNI_CreateJavaVM_t*) sharedLib_findAddress(jvmSharedLib, "JNI_CreateJavaVM")) == NULL) { - simpleLog_logL(LOG_LEVEL_ERROR, "Failed to load the JVM, function \"%s\" not exported.", "JNI_CreateJavaVM"); - return false; - } - - if ((JNI_GetCreatedJavaVMs_f = (JNI_GetCreatedJavaVMs_t*) sharedLib_findAddress(jvmSharedLib, "JNI_GetCreatedJavaVMs")) == NULL) { - simpleLog_logL(LOG_LEVEL_ERROR, "Failed to load the JVM, function \"%s\" not exported.", "JNI_GetCreatedJavaVMs"); - return false; - } - - java_establishJavaEnv(); - JNIEnv* env = java_getJNIEnv(true); - const bool loaded = (env != NULL); - const bool inited = (loaded && eventsJniBridge_initStatic(env, maxSkirmishAIs) == 0); - java_establishSpringEnv(); - - return inited; -} - -bool java_releaseStatic() -{ - sharedLib_unload(jvmSharedLib); - jvmSharedLib = NULL; - - FREE(jvmCfgProps.keys); - FREE(jvmCfgProps.values); - return true; -} - - - -static jobject java_createAICallback(JNIEnv* env, const struct SSkirmishAICallback* aiCallback, int skirmishAIId) { - (void) aiCallback; - - // initialize the AI Callback class, if not yet done - if (g_cls_aiCallback == NULL) { - // get the AI Callback class - if ((g_cls_aiCallback = jniUtil_findClass(env, CLS_AI_CALLBACK)) == NULL) - return NULL; - if ((g_cls_aiCallback = jniUtil_makeGlobalRef(env, g_cls_aiCallback, CLS_AI_CALLBACK)) == NULL) - return NULL; - // get (int skirmishAIId) constructor - if ((g_m_aiCallback_ctor_I = jniUtil_getMethodID(env, g_cls_aiCallback, "", "(I)V")) == NULL) - return NULL; - } - - #if 1 - // reuse callback if reloading - // this should be safe since the callback objects created in java_skirmishAI_init are not - // broken by java_skirmishAI_handleEvent, which also calls java_reattachCurrentThread and - // mightget a different env-pointer back - if (jAICallBacks[skirmishAIId] != NULL) - return jAICallBacks[skirmishAIId]; - #endif - - jobject o_clb = (*env)->NewObject(env, g_cls_aiCallback, g_m_aiCallback_ctor_I, skirmishAIId); - - if (jniUtil_checkException(env, "Failed creating Java AI Callback instance")) - return NULL; - - // return (jAICallBacks[skirmishAIId] = jniUtil_makeGlobalRef(env, o_clb, "AI callback instance")); - return (jAICallBacks[skirmishAIId] = o_clb); -} - - - -static bool java_loadSkirmishAI( - JNIEnv* env, - const char* shortName, - const char* version, - const char* className, - jobject* o_ai, - jobject* o_aiClassLoader -) { - #if 0 - // convert className from "com.myai.AI" to "com/myai/AI" - const size_t classNameP_sizeMax = strlen(className) + 1; - char classNameP[classNameP_sizeMax]; - STRCPY_T(classNameP, classNameP_sizeMax, className); - util_strReplaceChar(classNameP, '.', '/'); - #endif - - // get the AIs private class-loader - jobject o_global_aiClassLoader = java_createAIClassLoader(env, shortName, version); - - if (o_global_aiClassLoader == NULL) - return false; - - *o_aiClassLoader = o_global_aiClassLoader; - - // get the AI interface (from AIInterface.jar) - if (g_cls_ai_int == NULL) { - if ((g_cls_ai_int = jniUtil_findClass(env, INT_AI)) == NULL) - return false; - if ((g_cls_ai_int = jniUtil_makeGlobalRef(env, g_cls_ai_int, "AI interface class")) == NULL) - return false; - } - - // get the AI implementation class (from SkirmishAI.jar) - jclass cls_ai = jniUtil_findClassThroughLoader(env, o_global_aiClassLoader, className); - - if (cls_ai == NULL) - return false; - - const bool implementsAIInt = (bool) (*env)->IsAssignableFrom(env, cls_ai, g_cls_ai_int); - - if (!implementsAIInt || (*env)->ExceptionCheck(env)) { - simpleLog_logL(LOG_LEVEL_ERROR, "AI class not assignable from interface "INT_AI": %s", className); - simpleLog_logL(LOG_LEVEL_ERROR, "possible reasons (this list could be incomplete):"); - simpleLog_logL(LOG_LEVEL_ERROR, "* "INT_AI" interface not implemented"); - simpleLog_logL(LOG_LEVEL_ERROR, "* The AI is not compiled for the Java AI Interface version in use"); - - if (implementsAIInt) - (*env)->ExceptionDescribe(env); - - return false; - } - - - // get factory no-arg ctor - jmethodID m_ai_ctor = jniUtil_getMethodID(env, cls_ai, "", "()V"); - - if (m_ai_ctor == NULL) - return false; - - - // get AI instance - jobject o_local_ai = (*env)->NewObject(env, cls_ai, m_ai_ctor); - - if (o_local_ai == NULL || (*env)->ExceptionCheck(env)) { - simpleLog_logL(LOG_LEVEL_ERROR, "Failed fetching AI instance for class: %s", className); - - if (o_local_ai != NULL) - (*env)->ExceptionDescribe(env); - - return false; - } - - // make the AI a global reference, so it will not be garbage collected even after this method returns - *o_ai = jniUtil_makeGlobalRef(env, o_local_ai, "AI instance"); - return true; -} - - -bool java_initSkirmishAIClass( - const char* const shortName, - const char* const version, - const char* const className, - int skirmishAIId -) { - bool success = false; - - // see if an AI for className is instantiated already - size_t sai; - size_t firstFree = numSkirmishAIs; - - for (sai = 0; sai < numSkirmishAIs; ++sai) { - if (jAIClassNames[sai] == NULL) { - firstFree = sai; - break; - } - } - - // sai is now either the instantiated one, or a free one - // instantiate AI (if not already instantiated) - assert(sai < maxSkirmishAIs); - - if (jAIClassNames[sai] == NULL) { - sai = firstFree; - java_establishJavaEnv(); - JNIEnv* env = java_getJNIEnv(false); - - jobject instance = NULL; - jobject classLoader = NULL; - - success = java_loadSkirmishAI(env, shortName, version, className, &instance, &classLoader); - java_establishSpringEnv(); - - if (success) { - jAIInstances[sai] = instance; - jAIClassLoaders[sai] = classLoader; - jAIClassNames[sai] = util_allocStrCpy(className); - - numSkirmishAIs += (firstFree == numSkirmishAIs); - } else { - simpleLog_logL(LOG_LEVEL_ERROR, "Class loading failed for class: %s", className); - } - } else { - success = true; - } - - if (success) - skirmishAIId_skirmishAiImpl[skirmishAIId] = sai; - - return success; -} - -bool java_releaseSkirmishAIClass(const char* className) -{ - // see if an AI for className is instantiated - size_t sai; - for (sai = 0; sai < numSkirmishAIs; ++sai) { - if (jAIClassNames[sai] == NULL) - continue; - if (strcmp(jAIClassNames[sai], className) == 0) - break; - } - - // sai is now either the instantiated one, or a free one - // release AI (if its instance was found) - assert(sai < maxSkirmishAIs); - - if (jAIClassNames[sai] == NULL) - return false; - - java_establishJavaEnv(); - JNIEnv* env = java_getJNIEnv(false); - - - // delete the AI class-loader global reference, - // so it will be garbage collected - bool successPart = jniUtil_deleteGlobalRef(env, jAIClassLoaders[sai], "AI class-loader"); - bool success = successPart; - - // delete the AI global reference, - // so it will be garbage collected - successPart = jniUtil_deleteGlobalRef(env, jAIInstances[sai], "AI instance"); - success = success && successPart; - - java_establishSpringEnv(); - - if (success) { - jAIClassLoaders[sai] = NULL; - jAIInstances[sai] = NULL; - - FREE(jAIClassNames[sai]); - - // if it is the last implementation - numSkirmishAIs -= ((sai + 1) == numSkirmishAIs); - } - - return success; -} - -bool java_releaseAllSkirmishAIClasses() -{ - bool success = true; - - const char* className = ""; - size_t sai; - - for (sai = 0; sai < numSkirmishAIs; ++sai) { - if ((className = jAIClassNames[sai]) == NULL) - continue; - - success = success && java_releaseSkirmishAIClass(className); - } - - return success; -} - - - -int java_skirmishAI_init(int skirmishAIId, const struct SSkirmishAICallback* aiCallback) -{ - int res = -1; - - java_establishJavaEnv(); - - JNIEnv* env = java_getJNIEnv(false); - jobject global_javaAICallback = java_createAICallback(env, aiCallback, skirmishAIId); - - if (global_javaAICallback != NULL) - res = eventsJniBridge_initAI(env, skirmishAIId, global_javaAICallback); - - java_establishSpringEnv(); - return res; -} - -int java_skirmishAI_release(int skirmishAIId) -{ - return 0; -} - -int java_skirmishAI_handleEvent(int skirmishAIId, int topic, const void* data) -{ - java_establishJavaEnv(); - - JNIEnv* env = java_getJNIEnv(false); - const size_t sai = skirmishAIId_skirmishAiImpl[skirmishAIId]; - jobject aiInstance = jAIInstances[sai]; - const int res = eventsJniBridge_handleEvent(env, aiInstance, skirmishAIId, topic, data); - - java_establishSpringEnv(); - return res; -} diff --git a/AI/Interfaces/Java/src/main/native/JavaBridge.h b/AI/Interfaces/Java/src/main/native/JavaBridge.h deleted file mode 100644 index d742f47ef38..00000000000 --- a/AI/Interfaces/Java/src/main/native/JavaBridge.h +++ /dev/null @@ -1,73 +0,0 @@ -/* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */ - -#ifndef _JAVA_BRIDGE_H -#define _JAVA_BRIDGE_H - -#define JVM_PROPERTIES_FILE "jvm.properties" - -#define PKG_AI "com/springrts/ai/" -#define INT_AI PKG_AI"AI" -#define CLS_AI_CALLBACK PKG_AI"JniAICallback" - -// define path entry delimiter, used eg for the java class-path -#ifdef _WIN32 -#define ENTRY_DELIM ";" -#else -#define ENTRY_DELIM ":" -#endif -#define PATH_DELIM "/" - -#ifdef __cplusplus -extern "C" { -#endif - -#include // bool, true, false - -struct SAIInterfaceCallback; -struct SSkirmishAICallback; - -bool java_unloadJNIEnv(); - -bool java_initStatic(int interfaceId, const struct SAIInterfaceCallback* callback); -bool java_releaseStatic(); - -/** - * Instantiates an instance of the specified className. - * - * @param shortName further specifies the the AI to load - * @param version further specifies the the AI to load - * @param className fully qualified name of a Java class that implements - * interface com.springrts.ai.AI, eg: - * "com.myai.AI" - * @param teamId The team that will be using this AI. - * Multiple teams may use the same AI implementation. - * @return true, if the AI implementation is now loaded - */ -bool java_initSkirmishAIClass( - const char* const shortName, - const char* const version, - const char* const className, - int teamId -); - -/** - * Release the loaded AI specified through a class name. - * - * @param className fully qualified name of a Java class that implements - * interface com.springrts.ai.AI, eg: - * "com.myai.AI" - * @return true, if the AI implementation was loaded and is now - * successfully unloaded - */ -bool java_releaseSkirmishAIClass(const char* className); -bool java_releaseAllSkirmishAIClasses(); - -int java_skirmishAI_init(int teamId, const struct SSkirmishAICallback* callback); -int java_skirmishAI_release(int teamId); -int java_skirmishAI_handleEvent(int teamId, int topic, const void* data); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // _JAVA_BRIDGE_H diff --git a/AI/Interfaces/Java/src/main/native/JniUtil.c b/AI/Interfaces/Java/src/main/native/JniUtil.c deleted file mode 100644 index 909afc70bd3..00000000000 --- a/AI/Interfaces/Java/src/main/native/JniUtil.c +++ /dev/null @@ -1,288 +0,0 @@ -/* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */ - -#include "JniUtil.h" - -#include "CUtils/SimpleLog.h" - - -// JNI global vars -static jclass g_cls_url = NULL; -static jmethodID g_m_url_ctor = NULL; - -static jclass g_cls_urlClassLoader = NULL; -static jmethodID g_m_urlClassLoader_ctor = NULL; -static jmethodID g_m_urlClassLoader_findClass = NULL; - - -const char* jniUtil_getJniRetValDescription(const jint retVal) { - - switch (retVal) { - case JNI_OK: { return "JNI_OK - success"; break; } - case JNI_ERR: { return "JNI_ERR - unknown error"; break; } - case JNI_EDETACHED: { return "JNI_EDETACHED - thread detached from the VM"; break; } - case JNI_EVERSION: { return "JNI_EVERSION - JNI version error"; break; } -#ifdef JNI_ENOMEM - case JNI_ENOMEM: { return "JNI_ENOMEM - not enough (contiguous) memory"; break; } -#endif // JNI_ENOMEM -#ifdef JNI_EEXIST - case JNI_EEXIST: { return "JNI_EEXIST - VM already created"; break; } -#endif // JNI_EEXIST -#ifdef JNI_EINVAL - case JNI_EINVAL: { return "JNI_EINVAL - invalid arguments"; break; } -#endif // JNI_EINVAL - default: { return "UNKNOWN - unknown/invalid JNI return value"; break; } - } -} - -bool jniUtil_checkException(JNIEnv* env, const char* const errorMsg) { - - if ((*env)->ExceptionCheck(env)) { - simpleLog_logL(LOG_LEVEL_ERROR, errorMsg); - (*env)->ExceptionDescribe(env); - return true; - } - - return false; -} - -jclass jniUtil_findClass(JNIEnv* env, const char* const className) { - - jclass res = NULL; - - res = (*env)->FindClass(env, className); - const bool hasException = (*env)->ExceptionCheck(env); - if (res == NULL || hasException) { - simpleLog_logL(LOG_LEVEL_ERROR, "Class not found: \"%s\"", className); - if (hasException) { - (*env)->ExceptionDescribe(env); - } - res = NULL; - } - - return res; -} - -jobject jniUtil_makeGlobalRef(JNIEnv* env, jobject localObject, const char* objDesc) { - - jobject res = NULL; - - // Make the local class a global reference, - // so it will not be garbage collected, - // even after this method returned, - // but only if explicitly deleted with DeleteGlobalRef - res = (*env)->NewGlobalRef(env, localObject); - if ((*env)->ExceptionCheck(env)) { - simpleLog_logL(LOG_LEVEL_ERROR, - "Failed to make %s a global reference.", - ((objDesc == NULL) ? "" : objDesc)); - (*env)->ExceptionDescribe(env); - res = NULL; - } - - return res; -} - -bool jniUtil_deleteGlobalRef(JNIEnv* env, jobject globalObject, - const char* objDesc) { - - // delete the AI class-loader global reference, - // so it will be garbage collected - (*env)->DeleteGlobalRef(env, globalObject); - if ((*env)->ExceptionCheck(env)) { - simpleLog_logL(LOG_LEVEL_ERROR, - "Failed to delete global reference %s.", - ((objDesc == NULL) ? "" : objDesc)); - (*env)->ExceptionDescribe(env); - return false; - } - - return true; -} - -jmethodID jniUtil_getMethodID(JNIEnv* env, jclass cls, - const char* const name, const char* const signature) { - - jmethodID res = NULL; - - res = (*env)->GetMethodID(env, cls, name, signature); - const bool hasException = (*env)->ExceptionCheck(env); - if (res == NULL || hasException) { - simpleLog_logL(LOG_LEVEL_ERROR, "Method not found: %s(%s)", - name, signature); - if (hasException) { - (*env)->ExceptionDescribe(env); - } - res = NULL; - } - - return res; -} - -jmethodID jniUtil_getStaticMethodID(JNIEnv* env, jclass cls, - const char* const name, const char* const signature) { - - jmethodID res = NULL; - - res = (*env)->GetStaticMethodID(env, cls, name, signature); - const bool hasException = (*env)->ExceptionCheck(env); - if (res == NULL || hasException) { - simpleLog_logL(LOG_LEVEL_ERROR, "Method not found: %s(%s)", - name, signature); - if (hasException) { - (*env)->ExceptionDescribe(env); - } - res = NULL; - } - - return res; -} - - -static bool jniUtil_initURLClass(JNIEnv* env) { - - if (g_m_url_ctor == NULL) { - // get the URL class - static const char* const fcCls = "java/net/URL"; - - g_cls_url = jniUtil_findClass(env, fcCls); - if (g_cls_url == NULL) return false; - - g_cls_url = jniUtil_makeGlobalRef(env, g_cls_url, fcCls); - if (g_cls_url == NULL) return false; - - // get (String) constructor - g_m_url_ctor = jniUtil_getMethodID(env, g_cls_url, - "", "(Ljava/lang/String;)V"); - if (g_m_url_ctor == NULL) return false; - } - - return true; -} -jobject jniUtil_createURLObject(JNIEnv* env, const char* const url) { - - jobject jurl = NULL; - - bool ok = true; - if (g_cls_url == NULL) { - ok = jniUtil_initURLClass(env); - } - - if (ok) { - jstring jstrUrl = (*env)->NewStringUTF(env, url); - if (jniUtil_checkException(env, "Failed creating Java String.")) { jstrUrl = NULL; } - if (jstrUrl != NULL) { - jurl = (*env)->NewObject(env, g_cls_url, g_m_url_ctor, jstrUrl); - if (jniUtil_checkException(env, "Failed creating Java URL.")) { jurl = NULL; } - } - } else { - simpleLog_logL(LOG_LEVEL_ERROR, - "Failed creating Java URL; URL class not initialized."); - } - - return jurl; -} -jobjectArray jniUtil_createURLArray(JNIEnv* env, size_t size) { - - jobjectArray jurlArr = NULL; - - bool ok = true; - if (g_cls_url == NULL) { - ok = jniUtil_initURLClass(env); - } - - if (ok) { - jurlArr = (*env)->NewObjectArray(env, size, g_cls_url, NULL); - if (jniUtil_checkException(env, "Failed creating URL[].")) { jurlArr = NULL; } - } else { - simpleLog_logL(LOG_LEVEL_ERROR, - "Failed creating Java URL[]; URL class not initialized."); - } - - return jurlArr; -} -bool jniUtil_insertURLIntoArray(JNIEnv* env, jobjectArray arr, size_t index, jobject url) { - - bool ok = true; - - (*env)->SetObjectArrayElement(env, arr, index, url); - if (jniUtil_checkException(env, "Failed inserting Java URL into array.")) { ok = false; } - - return ok; -} - -static bool jniUtil_initURLClassLoaderClass(JNIEnv* env) { - - if (g_m_urlClassLoader_findClass == NULL) { - // get the URLClassLoader class - static const char* const fcCls = "java/net/URLClassLoader"; - - g_cls_urlClassLoader = jniUtil_findClass(env, fcCls); - if (g_cls_urlClassLoader == NULL) return false; - - g_cls_urlClassLoader = - jniUtil_makeGlobalRef(env, g_cls_urlClassLoader, fcCls); - if (g_cls_urlClassLoader == NULL) return false; - - // get (URL[]) constructor - g_m_urlClassLoader_ctor = jniUtil_getMethodID(env, - g_cls_urlClassLoader, "", "([Ljava/net/URL;)V"); - if (g_m_urlClassLoader_ctor == NULL) return false; - - // get the findClass(String) method - g_m_urlClassLoader_findClass = jniUtil_getMethodID(env, - g_cls_urlClassLoader, "findClass", - "(Ljava/lang/String;)Ljava/lang/Class;"); - if (g_m_urlClassLoader_findClass == NULL) return false; - } - - return true; -} -jobject jniUtil_createURLClassLoader(JNIEnv* env, jobject urlArray) { - - jobject classLoader = NULL; - - bool ok = true; - if (g_m_urlClassLoader_ctor == NULL) { - ok = jniUtil_initURLClassLoaderClass(env); - } - - if (ok) { - classLoader = (*env)->NewObject(env, g_cls_urlClassLoader, g_m_urlClassLoader_ctor, urlArray); - if (jniUtil_checkException(env, "Failed creating class-loader.")) { return NULL; } - } else { - simpleLog_logL(LOG_LEVEL_ERROR, - "Failed creating class-loader; class-loader class not initialized."); - } - - return classLoader; -} -jclass jniUtil_findClassThroughLoader(JNIEnv* env, jobject classLoader, const char* const className) { - - jclass cls = NULL; - - bool ok = true; - if (g_m_urlClassLoader_findClass == NULL) { - ok = jniUtil_initURLClassLoaderClass(env); - } - - if (ok) { - //cls = (*env)->FindClass(env, classNameP); - jstring jstr_className = (*env)->NewStringUTF(env, className); - cls = (*env)->CallObjectMethod(env, classLoader, g_m_urlClassLoader_findClass, jstr_className); - const bool hasException = (*env)->ExceptionCheck(env); - if (cls == NULL || hasException) { - simpleLog_logL(LOG_LEVEL_ERROR, - "Class not found \"%s\"", className); - if (hasException) { - (*env)->ExceptionDescribe(env); - } - cls = NULL; - } - } else { - simpleLog_logL(LOG_LEVEL_ERROR, - "Failed finding class; class-loader class not initialized."); - } - - return cls; -} - diff --git a/AI/Interfaces/Java/src/main/native/JniUtil.h b/AI/Interfaces/Java/src/main/native/JniUtil.h deleted file mode 100644 index 336f2fc4f1e..00000000000 --- a/AI/Interfaces/Java/src/main/native/JniUtil.h +++ /dev/null @@ -1,80 +0,0 @@ -/* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */ - -#ifndef _JNI_UTIL_H -#define _JNI_UTIL_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include // bool, true, false - -#include - -/** - * Takes a JNI function return value, and returns a short description for it. - * This can be used for getting a human readable string describing the - * return value of functions like AttachCurrentThread() and CreateJavaVM(). - * - * @return a short description for a JNI function return value - */ -const char* jniUtil_getJniRetValDescription(const jint retVal); - -/** - * Handles a possible JNI/Java exception. - * In case an exception is present, the supplied error message is written to - * the log file, and the whole exception info is written to stderr. - * - * @return true, if there was an exception - */ -bool jniUtil_checkException(JNIEnv* env, const char* const errorMsg); - -/** - * Tries to find a Java class. - * - * @return a local reference to the class if found, NULL otherwise - */ -jclass jniUtil_findClass(JNIEnv* env, const char* const className); - -/** - * Converts a local to a global reference. - * As jclass inherits from jobject, this can be used for jclass too. - * - * @return the global reference to localObject on success, NULL otherwise - */ -jobject jniUtil_makeGlobalRef(JNIEnv* env, jobject localObject, const char* objDesc); - -/** - * Deletes a global reference to an object. - * As jclass inherits from jobject, this can be used for jclass too. - * - * @return true on success, false if an error occurred - */ -bool jniUtil_deleteGlobalRef(JNIEnv* env, jobject globalObject, const char* objDesc); - -/** - * Retrieves a reference ID for calling a Java object method. - * - * @return the method ID on success, NULL otherwise - */ -jmethodID jniUtil_getMethodID(JNIEnv* env, jclass cls, const char* const name, const char* const signature); - -/** - * Retrieves a reference ID for calling a Java static method. - * - * @return the method ID on success, NULL otherwise - */ -jmethodID jniUtil_getStaticMethodID(JNIEnv* env, jclass cls, const char* const name, const char* const signature); - -jobject jniUtil_createURLObject(JNIEnv* env, const char* const url); -jobjectArray jniUtil_createURLArray(JNIEnv* env, size_t size); -bool jniUtil_insertURLIntoArray(JNIEnv* env, jobjectArray arr, size_t index, jobject url); - -jobject jniUtil_createURLClassLoader(JNIEnv* env, jobject urlArray); -jclass jniUtil_findClassThroughLoader(JNIEnv* env, jobject classLoader, const char* const className); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // _JNI_UTIL_H diff --git a/AI/Interfaces/Java/src/main/native/JvmLocater.h b/AI/Interfaces/Java/src/main/native/JvmLocater.h deleted file mode 100644 index 5032991d6a0..00000000000 --- a/AI/Interfaces/Java/src/main/native/JvmLocater.h +++ /dev/null @@ -1,53 +0,0 @@ -/* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */ - -#ifndef _JVM_LOCATER_H -#define _JVM_LOCATER_H - -#if !defined bool -#include -#endif -#if !defined size_t -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Returns the arch dir name, used eg here: - * .../jre/lib/${arch}/client/libjvm.so - * - * @return sparc, sparcv9, i386, amd64 or ia64 (windows only) - */ -const char* GetArchPath(); - -/* - * Given a JRE location and a JVM type, construct what the name the - * JVM shared library will be. - * - * @param jvmType "/", "\\", "client", "server" - * @param arch see GetArchPath(), use NULL for the default value - * @return true, if the JVM library was found, false otherwise. - */ -bool GetJVMPath(const char* jrePath, const char* jvmType, - char* jvmPath, size_t jvmPathSize, const char* arch); - -/** - * Find the path to a JRE install dir, using platform dependent means. - * - * @param path path of the JRE installation - * @param pathSize size of the path parameter - * @param configFile path to a simple text file containing only a path to the - * JRE installation to use, or NULL - * @param arch see GetArchPath(), use NULL for the default value - * @return true, if a JRE was found, false otherwise. - */ -bool GetJREPath(char* path, size_t pathSize, const char* configFile, - const char* arch); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // _JVM_LOCATER_H diff --git a/AI/Interfaces/Java/src/main/native/JvmLocater_common.c b/AI/Interfaces/Java/src/main/native/JvmLocater_common.c deleted file mode 100644 index a85f9d87a95..00000000000 --- a/AI/Interfaces/Java/src/main/native/JvmLocater_common.c +++ /dev/null @@ -1,188 +0,0 @@ -/* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */ - -#include -#include -#include -#include -#include - -#include "CUtils/Util.h" - -#include "JvmLocater.h" - -#define MAXPATHLEN 2048 -#define JRE_PATH_PROPERTY "jre.path" - -#include // for CHAR_BIT -#define CURRENT_DATA_MODEL (CHAR_BIT * sizeof(void*)) - -#include "CUtils/SimpleLog.h" -#include "System/MainDefines.h" -#include "System/SafeCStrings.h" - -// implemented in the OS specific files -const char* GetArchPath(); -bool GetJREPathFromBase(char* path, size_t pathSize, const char* basePath, - const char* arch); -bool GetJREPathOSSpecific(char* path, size_t pathSize, const char* arch); - -bool FileExists(const char* filePath) -{ - struct stat s; - return (stat(filePath, &s) == 0); -} - -//#define LOC_PROP_FILE -bool GetJREPathFromConfig(char* path, size_t pathSize, const char* configFile) -{ -#if defined LOC_PROP_FILE - // assume the config file is in properties file format - // and that the property JRE_PATH_PROPERTY contains - // the absolute path to the JRE to use - static const size_t props_sizeMax = 64; - - const char* props_keys[props_sizeMax]; - const char* props_values[props_sizeMax]; - - const size_t props_size = util_parsePropertiesFile(configFile, props_keys, - props_values, props_sizeMax); - - const char* jvmLocation = util_map_getValueByKey( - props_size, props_keys, props_values, - JRE_PATH_PROPERTY); - - if (jvmLocation == NULL) { - simpleLog_logL(LOG_LEVEL_DEBUG, "JRE not found in config file!"); - return false; - } else { - simpleLog_logL(LOG_LEVEL_NOTICE, "JRE found in config file!"); - STRCPY_T(path, pathSize, jvmLocation); - return true; - } -#else // defined LOC_PROP_FILE - // assume the config file is a plain text file containing nothing but - // the absolute path to the JRE to use in the first line - - bool found = false; - - FILE* cfp = fopen(configFile, "r"); - if (cfp == NULL) { - return found; - } - - // parse results - static const size_t line_sizeMax = 1024; - char line[line_sizeMax]; - if (fgets(line, line_sizeMax, cfp)) { - size_t line_size = strlen(line); - if (*(line+line_size-1) == '\n') { - // remove trailing '\n' - *(line+line_size-1) = '\0'; - line_size--; - } - - simpleLog_logL(LOG_LEVEL_NOTICE, - "Fetched JRE location from \"%s\"!", configFile); - - if (line_size > 0 && *line == '/') { - *(line+line_size-1) = '\0'; // remove trailing '/' - } - STRCPY_T(path, pathSize, line); - found = true; - } - fclose(cfp); - - return found; -#endif // defined LOC_PROP_FILE -} - - -bool GetJREPathFromEnvVars(char* path, size_t pathSize, const char* arch) -{ - bool found = false; - - static const size_t possLoc_sizeMax = 32; - char* possLoc[possLoc_sizeMax]; - size_t possLoc_i = 0; - - possLoc[possLoc_i++] = util_allocStrCpy("JAVA_HOME"); - possLoc[possLoc_i++] = util_allocStrCpy("JDK_HOME"); - possLoc[possLoc_i++] = util_allocStrCpy("JRE_HOME"); - - size_t l; - for (l=0; l < possLoc_i; ++l) { - const char* envPath = getenv(possLoc[l]); - if (envPath != NULL) { - found = GetJREPathFromBase(path, pathSize, envPath, arch); - if (found) { - simpleLog_logL(LOG_LEVEL_NOTICE, "JRE found in env var \"%s\"!", possLoc[l]); - goto locSearchEnd; - } else { - simpleLog_logL(LOG_LEVEL_WARNING, "Unusable JRE from env var \"%s\"=\"%s\"!", possLoc[l], envPath); - } - } - } - locSearchEnd: - - // cleanup - for (l=0; l < possLoc_i; ++l) { - free(possLoc[l]); - possLoc[l] = NULL; - } - - return found; -} - - - -bool GetJREPath(char* path, size_t pathSize, const char* configFile, - const char* arch) -{ - bool found = false; - - if (arch == NULL) { - arch = GetArchPath(); - } - - // check if a JRE location is specified in the config file - if (!found && configFile != NULL) { - found = GetJREPathFromConfig(path, pathSize, configFile); - } - - // check if a JRE is specified in an ENV var (eg. JAVA_HOME) - if (!found) { - found = GetJREPathFromEnvVars(path, pathSize, arch); - } - - // check if a JRE is located in a common location - if (!found) { - found = GetJREPathOSSpecific(path, pathSize, arch); - } - - return found; -} - -int main(int argc, const char* argv[]) { - - //simpleLog_init(NULL, false, LOG_LEVEL_DEBUG, false); - - static const size_t path_sizeMax = 1024; - char path[path_sizeMax]; - bool found = GetJREPath(path, path_sizeMax, NULL, NULL); - if (found) { - printf("JRE found: %s\n", path); - - static const size_t jvmPath_sizeMax = 1024; - char jvmPath[jvmPath_sizeMax]; - bool jvmFound = GetJVMPath(path, "client", jvmPath, jvmPath_sizeMax, NULL); - if (jvmFound) { - printf("JVM found: %s\n", jvmPath); - } else { - printf("JVM not found.\n"); - } - } else { - printf("JRE not found.\n"); - } - - return 0; -} diff --git a/AI/Interfaces/Java/src/main/native/JvmLocater_common.h b/AI/Interfaces/Java/src/main/native/JvmLocater_common.h deleted file mode 100644 index 45d81c2b9ac..00000000000 --- a/AI/Interfaces/Java/src/main/native/JvmLocater_common.h +++ /dev/null @@ -1,38 +0,0 @@ -/* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */ - -#ifndef _JVM_LOCATER_COMMON_H -#define _JVM_LOCATER_COMMON_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include "JvmLocater.h" - -#include -#include -#include -#include -#include -#include // for CHAR_BIT - -#include "CUtils/Util.h" -#include "CUtils/SimpleLog.h" - -#define MAXPATHLEN 2048 -#define JRE_PATH_PROPERTY "jre.path" -#define CURRENT_DATA_MODEL (CHAR_BIT * sizeof(void*)) - - -bool FileExists(const char* filePath); - -bool GetJREPathFromEnvVars(char* path, size_t pathSize, const char* arch); - -bool GetJREPath(char* path, size_t pathSize, const char* configFile, - const char* arch); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // _JVM_LOCATER_COMMON_H diff --git a/AI/Interfaces/Java/src/main/native/JvmLocater_linux.c b/AI/Interfaces/Java/src/main/native/JvmLocater_linux.c deleted file mode 100644 index ef1896be34b..00000000000 --- a/AI/Interfaces/Java/src/main/native/JvmLocater_linux.c +++ /dev/null @@ -1,266 +0,0 @@ -/* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */ - -#if !defined _WIN32 - -#include "JvmLocater_common.h" - -#include "System/MainDefines.h" -#include "System/SafeCStrings.h" - -#include - - -#if defined APPLE -#define JVM_LIB "libjvm.dylib" -#else -#define JVM_LIB "libjvm.so" -#endif - -#if defined APPLE -#define JAVA_LIB "libjava.dylib" -#else -#define JAVA_LIB "libjava.so" -#endif - -#ifdef SPARC -# define LIBARCH32NAME "sparc" -# define LIBARCH64NAME "sparcv9" -#else // not SPARC -> LINUX or APPLE -# define LIBARCH32NAME "i386" -# define LIBARCH64NAME "amd64" -#endif // SPARC -#if defined __arch64__ -# define LIBARCHNAME LIBARCH64NAME -#else // defined __arch64__ -# define LIBARCHNAME LIBARCH32NAME -#endif // defined __arch64__ -//LIBARCH32 solaris only: sparc or i386 -//LIBARCH64 solaris only: sparcv9 or amd64 -//LIBARCH sparc, sparcv9, i386, amd64, or ia64 // last one is windows only - - -const char* GetArchPath() -{ - switch(CURRENT_DATA_MODEL) { -#ifdef DUAL_MODE - case 32: - return LIBARCH32NAME; - case 64: - return LIBARCH64NAME; -#endif // DUAL_MODE - default: - return LIBARCHNAME; - } -} - -/* - * On Solaris VM choosing is done by the launcher (java.c). - */ -bool GetJVMPath(const char* jrePath, const char* jvmType, - char* jvmPath, size_t jvmPathSize, const char* arch) -{ - if (arch == NULL) { - arch = GetArchPath(); - } - - if (*jvmType == '/') { - SNPRINTF(jvmPath, jvmPathSize, "%s/"JVM_LIB, jvmType); - } else { - SNPRINTF(jvmPath, jvmPathSize, "%s/lib/%s/%s/"JVM_LIB, jrePath, arch, - jvmType); - } - - return FileExists(jvmPath); -} - - -static bool CheckIfJREPath(const char* path, const char* arch) -{ - bool found = false; - - if (path != NULL) { - char libJava[MAXPATHLEN]; - - // Is path a JRE path? - SNPRINTF(libJava, MAXPATHLEN, "%s/lib/%s/"JAVA_LIB, path, arch); - if (access(libJava, F_OK) == 0) { - found = true; - } - } - - return found; -} - -bool GetJREPathFromBase(char* path, size_t pathSize, const char* basePath, - const char* arch) -{ - bool found = false; - - if (basePath != NULL) { - char jrePath[MAXPATHLEN]; - - // Is basePath a JRE path? - STRCPY_T(jrePath, MAXPATHLEN, basePath); - if (CheckIfJREPath(jrePath, arch)) { - STRCPY_T(path, pathSize, basePath); - found = true; - } - - // Is basePath/jre a JRE path? - STRCAT_T(jrePath, MAXPATHLEN, "/jre"); - if (CheckIfJREPath(jrePath, arch)) { - STRCPY_T(path, pathSize, jrePath); - found = true; - } - } - - return found; -} - -static size_t ExecFileSystemGlob(char** pathHits, size_t pathHits_sizeMax, - const char* globPattern) -{ - size_t pathHits_size = 0; - - // assemble the command - static const size_t cmd_sizeMax = 512; - char cmd[cmd_sizeMax]; - SNPRINTF(cmd, cmd_sizeMax, "find %s/ -maxdepth 0 2> /dev/null", globPattern); - - // execute - FILE* cmd_fp = popen(cmd, "r"); - if (cmd_fp == NULL) { - return pathHits_size; - } - - // parse results - static const size_t line_sizeMax = 512; - char line[line_sizeMax]; - while (fgets(line, line_sizeMax, cmd_fp) && (pathHits_size < pathHits_sizeMax)) { - size_t line_size = strlen(line); - if (*(line+line_size-1) == '\n') { - // remove trailing '\n' - *(line+line_size-1) = '\0'; - line_size--; - } - - simpleLog_logL(LOG_LEVEL_DEBUG, - "glob-hit \"%s\"!", line); - - if (line_size > 0 && *line == '/') { - *(line+line_size-1) = '\0'; // remove trailing '/' - pathHits[pathHits_size++] = util_allocStrCpy(line); - } - } - pclose(cmd_fp); - - return pathHits_size; -} -static bool GetJREPathInCommonLocations(char* path, size_t pathSize, const char* arch) -{ - bool found = false; - - static const size_t possLoc_sizeMax = 32; - char* possLoc[possLoc_sizeMax]; - size_t possLoc_i = 0; - - possLoc[possLoc_i++] = util_allocStrCpy("/usr/local/jdk*"); - possLoc[possLoc_i++] = util_allocStrCpy("/usr/lib/jvm/default-java"); - possLoc[possLoc_i++] = util_allocStrCpy("/usr/lib/jvm/java-?-sun"); - possLoc[possLoc_i++] = util_allocStrCpy("/usr/lib/jvm/java-?-*"); - possLoc[possLoc_i++] = util_allocStrCpy("~/jdk*"); - possLoc[possLoc_i++] = util_allocStrCpy("~/bin/jdk*"); - possLoc[possLoc_i++] = util_allocStrCpy("~/jre*"); - possLoc[possLoc_i++] = util_allocStrCpy("~/bin/jre*"); - - static const size_t globHits_sizeMax = 32; - char* globHits[globHits_sizeMax]; - size_t l, g; - for (l=0; l < possLoc_i; ++l) { - const size_t globHits_size = ExecFileSystemGlob(globHits, globHits_sizeMax, possLoc[l]); - for (g=0; g < globHits_size; ++g) { - found = GetJREPathFromBase(path, pathSize, globHits[g], arch); - if (found) { - simpleLog_logL(LOG_LEVEL_NOTICE, - "JRE found common location env var \"%s\"!", - possLoc[l]); - goto locSearchEnd; - } - } - } - locSearchEnd: - - // cleanup - for (l=0; l < possLoc_i; ++l) { - free(possLoc[l]); - possLoc[l] = NULL; - } - - return found; -} - -static bool GetJREPathWhichJava(char* path, size_t pathSize, const char* arch) -{ - static const char* suf = "/bin/java"; - const size_t suf_size = strlen(suf); - - bool found = false; - - // execute - FILE* cmd_fp = popen("which java | sed 's/[\\n\\r]/K/g'", "r"); - if (cmd_fp == NULL) { - return found; - } - - // parse results - static const size_t line_sizeMax = 512; - char line[line_sizeMax]; - if (fgets(line, line_sizeMax, cmd_fp)) { - if (*line == '/') { // -> absolute path - size_t line_size = strlen(line); - if (*(line+line_size-1) == '\n') { - // remove trailing '\n' - *(line+line_size-1) = '\0'; - line_size--; - } - - simpleLog_logL(LOG_LEVEL_DEBUG, - "which line \"%s\"!", line); - - if (line_size > suf_size - && strcmp(line+(line_size-suf_size), suf) == 0) { - // line ends with suf - simpleLog_logL(LOG_LEVEL_NOTICE, - "JRE found with `which java`!"); - // remove suf - *(line+(line_size-suf_size)) = '\0'; - found = GetJREPathFromBase(path, pathSize, line, arch); - } - } - } - pclose(cmd_fp); - - return found; -} - -/* - * Find path to JRE based on .exe's location or registry settings. - */ -bool GetJREPathOSSpecific(char* path, size_t pathSize, const char* arch) -{ - bool found = false; - - // check if a JRE is located in a common location - if (!found) { - found = GetJREPathInCommonLocations(path, pathSize, arch); - } - - // check if a JRE is located in a common location - if (!found) { - found = GetJREPathWhichJava(path, pathSize, arch); - } - - return found; -} - -#endif // !defined _WIN32 diff --git a/AI/Interfaces/Java/src/main/native/JvmLocater_windows.c b/AI/Interfaces/Java/src/main/native/JvmLocater_windows.c deleted file mode 100644 index 6bb5367f2b6..00000000000 --- a/AI/Interfaces/Java/src/main/native/JvmLocater_windows.c +++ /dev/null @@ -1,181 +0,0 @@ -/* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */ - -#if defined _WIN32 - -#include "JvmLocater_common.h" - -#include "System/MainDefines.h" -#include "System/SafeCStrings.h" - -#include -#include -#include - - -#define JVM_LIB "jvm.dll" - -#define JAVA_LIB "java.dll" - -/* - * Returns the arch path, to get the current arch use the - * macro GetArch, nbits here is ignored for now. - */ -const char* GetArchPath() -{ -#ifdef _M_AMD64 - return "amd64"; -#elif defined(_M_IA64) - return "ia64"; -#else - return "i386"; -#endif -} - -/* - * Given a JRE location and a JVM type, construct what the name the - * JVM shared library will be. Return true, if such a library - * exists, false otherwise. - */ -bool GetJVMPath(const char* jrePath, const char* jvmType, - char* jvmPath, size_t jvmPathSize, const char* arch) -{ - if (arch == NULL) { - arch = GetArchPath(); - } - - if ((*jvmType == '/') || (*jvmType == '\\')) { - SNPRINTF(jvmPath, jvmPathSize, "%s\\"JVM_LIB, jvmType); - } else { - SNPRINTF(jvmPath, jvmPathSize, "%s\\bin\\%s\\"JVM_LIB, jrePath, - jvmType); - } - - return FileExists(jvmPath); -} - -static bool CheckIfJREPath(const char* path, const char* arch) -{ - bool found = false; - - if (path != NULL) { - char libJava[MAXPATHLEN]; - - // Is path a JRE path? - SNPRINTF(libJava, MAXPATHLEN, "%s\\bin\\"JAVA_LIB, path); - if (FileExists(libJava)) { - found = true; - } - } - - return found; -} - -bool GetJREPathFromBase(char* path, size_t pathSize, const char* basePath, - const char* arch) -{ - bool found = false; - - if (basePath != NULL) { - //if (GetApplicationHome(path, pathSize)) { - char jrePath[MAXPATHLEN]; - - // Is basePath a JRE path? - STRCPY_T(jrePath, MAXPATHLEN, basePath); - if (CheckIfJREPath(jrePath, arch)) { - STRCPY_T(path, pathSize, basePath); - found = true; - } - - // Is basePath/jre a JRE path? - STRCAT_T(jrePath, MAXPATHLEN, "\\jre"); - if (CheckIfJREPath(jrePath, arch)) { - STRCPY_T(path, pathSize, jrePath); - found = true; - } - } - - return found; -} - -/* - * Helpers to look in the registry for a public JRE. - */ - -/* Same for 1.5.0, 1.5.1, 1.5.2 etc. */ -#define JRE_REG_KEY "Software\\JavaSoft\\Java Runtime Environment" - -static bool GetStringFromRegistry(HKEY key, const char* name, char* buf, - size_t bufSize) -{ - DWORD type, size; - - if (RegQueryValueEx(key, name, 0, &type, 0, &size) == 0 - && type == REG_SZ - && (size < bufSize)) { - if (RegQueryValueEx(key, name, 0, 0, (LPBYTE)buf, &size) == 0) { - return true; - } - } - return false; -} - -static bool GetJREPathFromRegistry(char* path, size_t pathSize, const char* arch) -{ - HKEY key, subkey; - char version[MAXPATHLEN]; - - /* - * Note: There is a very similar implementation of the following - * registry reading code in the Windows java control panel (javacp.cpl). - * If there are bugs here, a similar bug probably exists there. Hence, - * changes here require inspection there. - */ - - // Find the current version of the JRE - if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, JRE_REG_KEY, 0, KEY_READ, &key) != 0) { - return false; - } - - if (!GetStringFromRegistry(key, "CurrentVersion", - version, sizeof(version))) { - RegCloseKey(key); - return false; - } - - /*if (strcmp(version, wantedVersion) != 0) { - RegCloseKey(key); - return false; - }*/ - - // Find directory where the current version is installed. - if (RegOpenKeyEx(key, version, 0, KEY_READ, &subkey) != 0) { - RegCloseKey(key); - return false; - } - - if (!GetStringFromRegistry(subkey, "JavaHome", path, pathSize)) { - RegCloseKey(key); - RegCloseKey(subkey); - return false; - } - - RegCloseKey(key); - RegCloseKey(subkey); - - simpleLog_logL(LOG_LEVEL_NOTICE, "JRE found in registry!"); - return true; -} - -bool GetJREPathOSSpecific(char* path, size_t pathSize, const char* arch) -{ - bool found = false; - - // check if a JRE is specified in the registry - if (!found) { - found = GetJREPathFromRegistry(path, pathSize, arch); - } - - return found; -} - -#endif // defined _WIN32 diff --git a/AI/Skirmish/NullJavaAI/CMakeLists.txt b/AI/Skirmish/NullJavaAI/CMakeLists.txt deleted file mode 100644 index ffac49c05b4..00000000000 --- a/AI/Skirmish/NullJavaAI/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -### Generic Java Skirmish AI config -# - -configure_java_skirmish_ai("") diff --git a/AI/Skirmish/NullJavaAI/VERSION b/AI/Skirmish/NullJavaAI/VERSION deleted file mode 100644 index ceab6e11ece..00000000000 --- a/AI/Skirmish/NullJavaAI/VERSION +++ /dev/null @@ -1 +0,0 @@ -0.1 \ No newline at end of file diff --git a/AI/Skirmish/NullJavaAI/bin/ant.dependent.properties b/AI/Skirmish/NullJavaAI/bin/ant.dependent.properties deleted file mode 100644 index 559cacc4e54..00000000000 --- a/AI/Skirmish/NullJavaAI/bin/ant.dependent.properties +++ /dev/null @@ -1,36 +0,0 @@ -# properties file for spring Java Skirmish AIs -# This is used when you do not use the spring repository for compiling. -# -# Paths are relative to the project home (which is ../ from this file). -# All values are optional, and listed here with their defaults. -# -# The default assumes that you have the spring source, -# and do a spring in-source build as it is the default with CMake and SCons, -# and as the buildbot does it. -# -# build-dir: ${spring.home}/AI/Skirmish/${ai.name}/ -# install-dir: ${spring.home}/dist/AI/Skirmish/${ai.name}/${ai.version}/ -# -# This file is loaded from within build.xml, -# but only if no "jlibs-interface/" dir is present. -# - -;spring.home=../../.. - -# This is used only in the next property -;build.home=${spring.home} -# Where jar files will be built -;build.dir=${build.home}/AI/Skirmish/${skirmish.ai.name} - -# This is used only in the next property -;dist.home=${spring.home}/dist -# Where jar files will be installed to -;dist.dir=${dist.home}/AI/Skirmish/${skirmish.ai.name}/${skirmish.ai.version} -# Where HTML JavaDoc files will be generated -;doc.dir=${dist.home}/AI/Skirmish/${skirmish.ai.name}/${skirmish.ai.version}/doc/jdoc - -# The following two are needed for compiling (to create the classpath) -# * Here we look for ./jlib/*.jar recursively -;ai.interface.src.home=${spring.home}/AI/Interfaces/Java -# * Here we look for AIInterface.jar -;ai.interface.build.home=${build.home}/AI/Interfaces/Java diff --git a/AI/Skirmish/NullJavaAI/bin/ant.independent.properties b/AI/Skirmish/NullJavaAI/bin/ant.independent.properties deleted file mode 100644 index 129a1589a21..00000000000 --- a/AI/Skirmish/NullJavaAI/bin/ant.independent.properties +++ /dev/null @@ -1,29 +0,0 @@ -# properties file for spring Java Skirmish AIs -# This is used when you do not use the spring repository for compiling. -# -# Paths are relative to the project home (which is ../ from this file). -# All values are optional, and listed here with their defaults. -# -# For the project, you do not need the spring sources, -# but you will need the "jlibs-interface/" instead, which contains -# the Java AI Interfaces jlibs plus its binary and source jar. -# -# build-dir: build/ -# install-dir: dist/ -# -# This file is loaded from within build.xml, -# but only if a "jlibs-interface/" dir is present. -# - -# This is used only in the next property -;build.home=build -# Where jar files will be built -;build.dir=${build.home} - -# This is used only in the next property. -# You will want to set dist.home to your spring install dir. -;dist.home=dist -# Where jar files will be installed to -;dist.dir=${dist.home}/AI/Skirmish/${skirmish.ai.name}/${skirmish.ai.version} -# Where HTML JavaDoc files will be generated -;doc.dir=${dist.home}/AI/Skirmish/${skirmish.ai.name}/${skirmish.ai.version}/doc/jdoc diff --git a/AI/Skirmish/NullJavaAI/bin/build.xml b/AI/Skirmish/NullJavaAI/bin/build.xml deleted file mode 100644 index 8d3b185b6bf..00000000000 --- a/AI/Skirmish/NullJavaAI/bin/build.xml +++ /dev/null @@ -1,279 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - . -File not found: ${ai.interface.jar} -Please make sure to compile the Java AI Interface -before trying to compile this AI, or request -an independent version of this project from -wherever you got this AI from. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Successfully bumped ${skirmish.ai.name} version from ${skirmish.ai.version} to ${skirmish.ai.version.new}. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - . -Please specify either home.new or name.new, for example: - ant create-independent -Dhome.new=~/projects/SpringSkirmishAIs/ -or - ant create-independent -Dname.new=MyJavaAI - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Spring source independant Java Skirmish AI project copied to: - ${project.dir.new} - -You may want to change your java source package structure -and the data/AIInto.lua file for the new project. - - - - - - - - - - - - - - - - - diff --git a/AI/Skirmish/NullJavaAI/data/AIInfo.lua b/AI/Skirmish/NullJavaAI/data/AIInfo.lua deleted file mode 100644 index 75f19a8632b..00000000000 --- a/AI/Skirmish/NullJavaAI/data/AIInfo.lua +++ /dev/null @@ -1,53 +0,0 @@ --- --- Info Definition Table format --- --- --- These keywords must be lowercase for LuaParser to read them. --- --- key: user defined or one of the SKIRMISH_AI_PROPERTY_* defines in --- SSkirmishAILibrary.h --- value: the value of the property --- desc: the description (could be used as a tooltip) --- --- --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- - -local infos = { - { - key = 'shortName', - value = 'NullJavaAI', - desc = 'machine conform name.', - }, - { - key = 'version', - value = '0.1', -- AI version - !This comment is used for parsing! - }, - { - key = 'className', - value = 'nulljavaai.NullJavaAI', - desc = 'fully qualified name of a class that implements interface com.springrts.ai.AI', - }, - { - key = 'name', - value = 'low-level Java test Skirmish AI', - desc = 'human readable name.', - }, - { - key = 'loadSupported', - value = 'no', - desc = 'whether this AI supports loading or not', - }, - { - key = 'interfaceShortName', - value = 'Java', -- AI Interface name - !This comment is used for parsing! - desc = 'the shortName of the AI interface this AI needs', - }, - { - key = 'interfaceVersion', - value = '0.1', -- AI Interface version - !This comment is used for parsing! - desc = 'the minimum version of the AI interface required by this AI', - }, -} - -return infos diff --git a/AI/Skirmish/NullJavaAI/data/AIOptions.lua b/AI/Skirmish/NullJavaAI/data/AIOptions.lua deleted file mode 100644 index d435d62e964..00000000000 --- a/AI/Skirmish/NullJavaAI/data/AIOptions.lua +++ /dev/null @@ -1,15 +0,0 @@ --- --- Custom Options Definition Table format --- --- A detailed example of how this format works can be found --- in the spring source under: --- AI/Skirmish/NullAI/data/AIOptions.lua --- --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- - -local options = { -} - -return options - diff --git a/AI/Skirmish/NullJavaAI/manifest.mf b/AI/Skirmish/NullJavaAI/manifest.mf deleted file mode 100755 index 59499bce4a2..00000000000 --- a/AI/Skirmish/NullJavaAI/manifest.mf +++ /dev/null @@ -1,2 +0,0 @@ -Manifest-Version: 1.0 - diff --git a/AI/Skirmish/NullJavaAI/src/nulljavaai/NullJavaAI.java b/AI/Skirmish/NullJavaAI/src/nulljavaai/NullJavaAI.java deleted file mode 100644 index 41c42c6c235..00000000000 --- a/AI/Skirmish/NullJavaAI/src/nulljavaai/NullJavaAI.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - Copyright (c) 2008 Robin Vobruba - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -package nulljavaai; - - -import com.springrts.ai.*; - -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.logging.*; - -/** - * Serves as Interface for a Java Skirmish AIs for the Spring engine. - * - * @author hoijui - * @version 0.1 - */ -public class NullJavaAI extends AbstractAI implements AI { - - private int skirmishAIId = -1; - private AICallback clb = null; - private String myLogFile = null; - private Logger log = null; - private int frame = -1; - - private static class MyCustomLogFormatter extends Formatter { - - private DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss:SSS dd.MM.yyyy"); - - public String format(LogRecord record) { - - // Create a StringBuffer to contain the formatted record - // start with the date. - StringBuffer sb = new StringBuffer(); - - // Get the date from the LogRecord and add it to the buffer - Date date = new Date(record.getMillis()); - sb.append(dateFormat.format(date)); - sb.append(" "); - - // Get the level name and add it to the buffer - sb.append(record.getLevel().getName()); - sb.append(": "); - - // Get the formatted message (includes localization - // and substitution of parameters) and add it to the buffer - sb.append(formatMessage(record)); - sb.append("\n"); - - return sb.toString(); - } - } - - public static boolean isDebugging() { - return true; - } - - public NullJavaAI() {} - - - @Override - public int init(int skirmishAIId, AICallback callback) { - - int ret = -1; - - this.clb = callback; - - // initialize the log - try { - int teamId = clb.SkirmishAI_getTeamId(); - myLogFile = callback.DataDirs_locatePath("log-team-" + teamId + "-" + skirmishAIId + ".txt", true, true, false, false); - FileHandler fileLogger = new FileHandler(myLogFile, false); - fileLogger.setFormatter(new MyCustomLogFormatter()); - fileLogger.setLevel(Level.ALL); - log = Logger.getLogger("nulljavaai"); - if (isDebugging()) { - log.setLevel(Level.ALL); - } else { - log.setLevel(Level.INFO); - } - log.addHandler(fileLogger); - } catch (Exception ex) { - System.out.println("NullJavaAI: Failed initializing the logger!"); - ex.printStackTrace(); - ret = -2; - } - - try { - int teamId = clb.SkirmishAI_getTeamId(); - log.info("initializing team " + teamId + ", id " + skirmishAIId); - - int numInfo = callback.SkirmishAI_Info_getSize(); - log.info("info (items: " + numInfo + ") ..."); - for (int i = 0; i < numInfo; i++) { - String key = callback.SkirmishAI_Info_getKey(i); - String value = callback.SkirmishAI_Info_getValue(i); - log.info(key + " = " + value); - } - - int numOptions = callback.SkirmishAI_OptionValues_getSize(); - log.info("options (items: " + numOptions + ") ..."); - for (int i = 0; i < numOptions; i++) { - String key = callback.SkirmishAI_OptionValues_getKey(i); - String value = callback.SkirmishAI_OptionValues_getValue(i); - log.info(key + " = " + value); - } - - ret = 0; - } catch (Exception ex) { - log.log(Level.SEVERE, "Failed initializing", ex); - log.log(Level.SEVERE, "msg: " + ex.getMessage()); - StackTraceElement[] stackTrace = ex.getStackTrace(); - for (int i = 0; i < stackTrace.length; i++) { - log.log(Level.SEVERE, "ste: " + stackTrace[i].toString()); - } - ret = -3; - } - - { - int numOptions = clb.SkirmishAI_OptionValues_getSize(); - log.info("sizeOptions: " + numOptions); - log.info("options:"); -// Pointer[] pKeys = evt.optionKeys.getPointerArray(0L, evt.sizeOptions); -// Pointer[] pValues = evt.optionValues.getPointerArray(0L, evt.sizeOptions); -// Properties options = new Properties(); -// for (int i = 0; i < evt.sizeOptions; i++) { -// options.setProperty(pKeys[i].getString(0L), pValues[i].getString(0L)); -// } - for (int i = 0; i < numOptions; i++) { - String key = clb.SkirmishAI_OptionValues_getKey(i); - String value = clb.SkirmishAI_OptionValues_getValue(i); - log.info(key + " = " + value); - } - log.info("stored"); - } - - return ret; - } - - @Override - public int update(int frame) { - - try { - log.finer("update event ..."); - log.finer("frame: " + frame); - } catch (Exception ex) { - log.log(Level.WARNING, "Failed handling event", ex); - return -1; - } - - return 0; - } - - @Override - public int release(int reason) { - - int ret = -1; - - try { - int teamId = clb.SkirmishAI_getTeamId(); - log.info("releasing team " + teamId + ", id " + skirmishAIId); - - ret = 0; - } catch (Exception ex) { - log.log(Level.WARNING, "Failed releasing", ex); - ret = -2; - } - - return ret; - } -} diff --git a/AI/Skirmish/NullOOJavaAI/CMakeLists.txt b/AI/Skirmish/NullOOJavaAI/CMakeLists.txt deleted file mode 100644 index 195bb8f6313..00000000000 --- a/AI/Skirmish/NullOOJavaAI/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -### Generic Java Skirmish AI config -# - -configure_java_skirmish_ai("JavaOO") diff --git a/AI/Skirmish/NullOOJavaAI/VERSION b/AI/Skirmish/NullOOJavaAI/VERSION deleted file mode 100644 index ceab6e11ece..00000000000 --- a/AI/Skirmish/NullOOJavaAI/VERSION +++ /dev/null @@ -1 +0,0 @@ -0.1 \ No newline at end of file diff --git a/AI/Skirmish/NullOOJavaAI/bin/ant.dependent.properties b/AI/Skirmish/NullOOJavaAI/bin/ant.dependent.properties deleted file mode 100644 index 71674185fe3..00000000000 --- a/AI/Skirmish/NullOOJavaAI/bin/ant.dependent.properties +++ /dev/null @@ -1,40 +0,0 @@ -# properties file for spring Java Skirmish AIs -# This is used when you do not use the spring repository for compiling. -# -# Paths are relative to the project home (which is ../ from this file). -# All values are optional, and listed here with their defaults. -# -# The default assumes that you have the spring source, -# and do a spring in-source build as it is the default with CMake and SCons, -# and as the buildbot does it. -# -# build-dir: ${spring.home}/AI/Skirmish/${ai.name}/ -# install-dir: ${spring.home}/dist/AI/Skirmish/${ai.name}/${ai.version}/ -# -# This file is loaded from within build.xml, -# but only if "Java-AIInterface/" and "JavaOO-AIWrapper/" dirs are not present. -# - -;spring.home=../../.. - -# This is used only in the next property -;build.home=${spring.home} -# Where jar files will be built -;build.dir=${build.home}/AI/Skirmish/${skirmish.ai.name} - -# This is used only in the next property -;dist.home=${spring.home}/dist -# Where jar files will be installed to -;dist.dir=${dist.home}/AI/Skirmish/${skirmish.ai.name}/${skirmish.ai.version} -# Where HTML JavaDoc files will be generated -;doc.dir=${dist.home}/AI/Skirmish/${skirmish.ai.name}/${skirmish.ai.version}/doc/jdoc - -# The following four are needed for compiling (to create the classpath) -# * Here we look for ./data/jlib/*.jar recursively -;ai.interface.src.home=${spring.home}/AI/Interfaces/Java -# * Here we look for AIInterface.jar -;ai.interface.build.home=${build.home}/AI/Interfaces/Java -# * Here we look for ./jlib/*.jar recursively -;ai.wrapper.oo.src.home=${spring.home}/AI/Wrappers/JavaOO -# * Here we look for JavaOO-AIWrapper.jar -;ai.wrapper.oo.build.home=${build.home}/AI/Wrappers/JavaOO diff --git a/AI/Skirmish/NullOOJavaAI/bin/ant.independent.properties b/AI/Skirmish/NullOOJavaAI/bin/ant.independent.properties deleted file mode 100644 index 4f5648f2935..00000000000 --- a/AI/Skirmish/NullOOJavaAI/bin/ant.independent.properties +++ /dev/null @@ -1,30 +0,0 @@ -# properties file for spring Java Skirmish AIs -# This is used when you do not use the spring repository for compiling. -# -# Paths are relative to the project home (which is ../ from this file). -# All values are optional, and listed here with their defaults. -# -# For the project, you do not need the spring sources, -# but you will need the "Java-AIInterface/" and "JavaOO-AIWrapper/" dirs -# instead, which contain the Java AI Interfaces jlibs plus its binary -# and source jar, and the Java OO Wrappers equal counterparts. -# -# build-dir: build/ -# install-dir: dist/ -# -# This file is loaded from within build.xml, -# but only if "Java-AIInterface/" and "JavaOO-AIWrapper/" dirs are present. -# - -# This is used only in the next property -;build.home=build -# Where jar files will be built -;build.dir=${build.home} - -# This is used only in the next property. -# You will want to set dist.home to your spring install dir. -;dist.home=dist -# Where jar files will be installed to -;dist.dir=${dist.home}/AI/Skirmish/${skirmish.ai.name}/${skirmish.ai.version} -# Where HTML JavaDoc files will be generated -;doc.dir=${dist.home}/AI/Skirmish/${skirmish.ai.name}/${skirmish.ai.version}/doc/jdoc diff --git a/AI/Skirmish/NullOOJavaAI/bin/build.xml b/AI/Skirmish/NullOOJavaAI/bin/build.xml deleted file mode 100644 index 32b0b4783eb..00000000000 --- a/AI/Skirmish/NullOOJavaAI/bin/build.xml +++ /dev/null @@ -1,342 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - . -File not found: ${ai.interface.build.home}/AIInterface.jar -Please make sure to compile the Java AI Interface -before trying to compile this AI, or request -an independent version of this project from -wherever you got this AI. - - - - . -File not found: ${ai.wrapper.oo.build.home}/JavaOO-AIWrapper.jar -Please make sure to compile the Java OO AI Wrapper -before trying to compile this AI, or request -an independent version of this project from -wherever you got this AI from. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Successfully bumped ${skirmish.ai.name} version from ${skirmish.ai.version} to ${skirmish.ai.version.new}. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - . -Please specify either home.new or name.new, for example: - ant create-independent -Dhome.new=~/projects/SpringSkirmishAIs/ -or - ant create-independent -Dname.new=MyJavaAI - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Spring source independant Java Skirmish AI project copied to: - ${project.dir.new} - -You may want to change your java source package structure -and the data/AIInto.lua file for the new project. - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/AI/Skirmish/NullOOJavaAI/data/AIInfo.lua b/AI/Skirmish/NullOOJavaAI/data/AIInfo.lua deleted file mode 100644 index 91420c5e704..00000000000 --- a/AI/Skirmish/NullOOJavaAI/data/AIInfo.lua +++ /dev/null @@ -1,53 +0,0 @@ --- --- Info Definition Table format --- --- --- These keywords must be lowercase for LuaParser to read them. --- --- key: user defined or one of the SKIRMISH_AI_PROPERTY_* defines in --- SSkirmishAILibrary.h --- value: the value of the property --- desc: the description (could be used as a tooltip) --- --- --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- - -local infos = { - { - key = 'shortName', - value = 'NullOOJavaAI', - desc = 'machine conform name.', - }, - { - key = 'version', - value = '0.1', -- AI version - !This comment is used for parsing! - }, - { - key = 'className', - value = 'nulloojavaai.NullOOJavaAI', - desc = 'fully qualified name of a class that implements interface com.springrts.ai.AI', - }, - { - key = 'name', - value = 'high-level Java stub Skirmish AI', - desc = 'human readable name.', - }, - { - key = 'loadSupported', - value = 'no', - desc = 'whether this AI supports loading or not', - }, - { - key = 'interfaceShortName', - value = 'Java', -- AI Interface name - !This comment is used for parsing! - desc = 'the shortName of the AI interface this AI needs', - }, - { - key = 'interfaceVersion', - value = '0.1', -- AI Interface version - !This comment is used for parsing! - desc = 'the minimum version of the AI interface required by this AI', - }, -} - -return infos diff --git a/AI/Skirmish/NullOOJavaAI/data/AIOptions.lua b/AI/Skirmish/NullOOJavaAI/data/AIOptions.lua deleted file mode 100644 index d435d62e964..00000000000 --- a/AI/Skirmish/NullOOJavaAI/data/AIOptions.lua +++ /dev/null @@ -1,15 +0,0 @@ --- --- Custom Options Definition Table format --- --- A detailed example of how this format works can be found --- in the spring source under: --- AI/Skirmish/NullAI/data/AIOptions.lua --- --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- - -local options = { -} - -return options - diff --git a/AI/Skirmish/NullOOJavaAI/manifest.mf b/AI/Skirmish/NullOOJavaAI/manifest.mf deleted file mode 100755 index 59499bce4a2..00000000000 --- a/AI/Skirmish/NullOOJavaAI/manifest.mf +++ /dev/null @@ -1,2 +0,0 @@ -Manifest-Version: 1.0 - diff --git a/AI/Skirmish/NullOOJavaAI/src/main/java/nulloojavaai/NullOOJavaAI.java b/AI/Skirmish/NullOOJavaAI/src/main/java/nulloojavaai/NullOOJavaAI.java deleted file mode 100644 index 9ffabe1eae6..00000000000 --- a/AI/Skirmish/NullOOJavaAI/src/main/java/nulloojavaai/NullOOJavaAI.java +++ /dev/null @@ -1,320 +0,0 @@ -/* - Copyright (c) 2008 Robin Vobruba - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -package nulloojavaai; - - -import com.springrts.ai.AI; -import com.springrts.ai.oo.AIFloat3; -import com.springrts.ai.oo.OOAI; -import com.springrts.ai.oo.clb.*; - -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Properties; -import java.util.List; -import java.util.logging.*; - -/** - * Serves as Interface for a Java Skirmish AIs for the Spring engine. - * - * @author hoijui - */ -public class NullOOJavaAI extends OOAI implements AI { - - private static class MyCustomLogFormatter extends Formatter { - - private DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss:SSS dd.MM.yyyy"); - - public String format(LogRecord record) { - - // Create a StringBuffer to contain the formatted record - // start with the date. - StringBuffer sb = new StringBuffer(); - - // Get the date from the LogRecord and add it to the buffer - Date date = new Date(record.getMillis()); - sb.append(dateFormat.format(date)); - sb.append(" "); - - // Get the level name and add it to the buffer - sb.append(record.getLevel().getName()); - sb.append(": "); - - // Get the formatted message (includes localization - // and substitution of parameters) and add it to the buffer - sb.append(formatMessage(record)); - sb.append("\n"); - - return sb.toString(); - } - } - - private static void logProperties(Logger log, Level level, Properties props) { - - log.log(level, "properties (items: " + props.size() + "):"); - for (String key : props.stringPropertyNames()) { - log.log(level, key + " = " + props.getProperty(key)); - } - } - - private int skirmishAIId = -1; - private int teamId = -1; - private Properties info = null; - private Properties optionValues = null; - private OOAICallback clb = null; - private String myLogFile = null; - private Logger log = null; - - private static final int DEFAULT_ZONE = 0; - - - public NullOOJavaAI() {} - - private int sendTextMsg(String msg) { - - try { - clb.getGame().sendTextMessage("/say " + msg, DEFAULT_ZONE); - } catch (Exception ex) { - ex.printStackTrace(); - return 1; - } - - return 0; - } - public boolean isDebugging() { - return true; - } - - @Override - public int init(int skirmishAIId, OOAICallback callback) { - - int ret = -1; - - this.skirmishAIId = skirmishAIId; - this.clb = callback; - - this.teamId = clb.getSkirmishAI().getTeamId(); - - info = new Properties(); - Info inf = clb.getSkirmishAI().getInfo(); - int numInfo = inf.getSize(); - for (int i = 0; i < numInfo; i++) { - String key = inf.getKey(i); - String value = inf.getValue(i); - info.setProperty(key, value); - } - - optionValues = new Properties(); - OptionValues opVals = clb.getSkirmishAI().getOptionValues(); - int numOpVals = opVals.getSize(); - for (int i = 0; i < numOpVals; i++) { - String key = opVals.getKey(i); - String value = opVals.getValue(i); - optionValues.setProperty(key, value); - } - - // initialize the log - try { - myLogFile = callback.getDataDirs().locatePath("log-team-" + teamId + ".txt", true, true, false, false); - FileHandler fileLogger = new FileHandler(myLogFile, false); - fileLogger.setFormatter(new MyCustomLogFormatter()); - fileLogger.setLevel(Level.ALL); - log = Logger.getLogger("nulloojavaai"); - log.addHandler(fileLogger); - if (isDebugging()) { - log.setLevel(Level.ALL); - } else { - log.setLevel(Level.INFO); - } - } catch (Exception ex) { - System.out.println("NullOOJavaAI: Failed initializing the logger!"); - ex.printStackTrace(); - ret = -2; - } - - try { - log.info("initializing team " + teamId); - - log.log(Level.FINE, "info:"); - logProperties(log, Level.FINE, info); - - log.log(Level.FINE, "options:"); - logProperties(log, Level.FINE, optionValues); - - ret = 0; - } catch (Exception ex) { - log.log(Level.SEVERE, "Failed initializing", ex); - ret = -3; - } - - return ret; - } - - @Override - public int release(int reason) { - return 0; // signaling: OK - } - - @Override - public int update(int frame) { - - if (frame % 300 == 0) { - sendTextMsg("listing resources ..."); - List resources = clb.getResources(); - for (Resource resource : resources) { - sendTextMsg("Resource " + resource.getName() + " optimum: " - + resource.getOptimum()); - sendTextMsg("Resource " + resource.getName() + " current: " - + clb.getEconomy().getCurrent(resource)); - sendTextMsg("Resource " + resource.getName() + " income: " - + clb.getEconomy().getIncome(resource)); - sendTextMsg("Resource " + resource.getName() + " storage: " - + clb.getEconomy().getStorage(resource)); - sendTextMsg("Resource " + resource.getName() + " usage: " - + clb.getEconomy().getUsage(resource)); - } - } - - return 0; // signaling: OK - } - - @Override - public int message(int player, String message) { - return 0; // signaling: OK - } - - @Override - public int unitCreated(Unit unit, Unit builder) { - - int ret = sendTextMsg("unitCreated: " + unit.toString()); - sendTextMsg("unitCreated def: " + unit.getDef().getName()); - List buildOptions = unit.getDef().getBuildOptions(); - for (UnitDef unitDef : buildOptions) { - sendTextMsg("\tbuildOption x: " + unitDef.getName() + "\t" + unitDef.getHumanName() + "\t" + unitDef.toString() + "\t" + unitDef.hashCode()); - } - - return ret; - } - - @Override - public int unitFinished(Unit unit) { - return 0; // signaling: OK - } - - @Override - public int unitIdle(Unit unit) { - return 0; // signaling: OK - } - - @Override - public int unitMoveFailed(Unit unit) { - return 0; // signaling: OK - } - - @Override - public int unitDamaged(Unit unit, Unit attacker, float damage, AIFloat3 dir, WeaponDef weaponDef, boolean paralyzed) { - return 0; // signaling: OK - } - - @Override - public int unitDestroyed(Unit unit, Unit attacker) { - return 0; // signaling: OK - } - - @Override - public int unitGiven(Unit unit, int oldTeamId, int newTeamId) { - return 0; // signaling: OK - } - - @Override - public int unitCaptured(Unit unit, int oldTeamId, int newTeamId) { - return 0; // signaling: OK - } - - @Override - public int enemyEnterLOS(Unit enemy) { - return 0; // signaling: OK - } - - @Override - public int enemyLeaveLOS(Unit enemy) { - return 0; // signaling: OK - } - - @Override - public int enemyEnterRadar(Unit enemy) { - return 0; // signaling: OK - } - - @Override - public int enemyLeaveRadar(Unit enemy) { - return 0; // signaling: OK - } - - @Override - public int enemyDamaged(Unit enemy, Unit attacker, float damage, AIFloat3 dir, WeaponDef weaponDef, boolean paralyzed) { - return 0; // signaling: OK - } - - @Override - public int enemyDestroyed(Unit enemy, Unit attacker) { - return 0; // signaling: OK - } - - @Override - public int weaponFired(Unit unit, WeaponDef weaponDef) { - return 0; // signaling: OK - } - - @Override - public int playerCommand(java.util.List units, int commandTopicId, int playerId) { - return 0; // signaling: OK - } - - @Override - public int commandFinished(Unit unit, int commandId, int commandTopicId) { - return 0; // signaling: OK - } - - @Override - public int seismicPing(AIFloat3 pos, float strength) { - return 0; // signaling: OK - } - - @Override - public int load(String file) { - return 0; // signaling: OK - } - - @Override - public int save(String file) { - return 0; // signaling: OK - } - - @Override - public int enemyCreated(Unit enemy) { - return 0; // signaling: OK - } - - @Override - public int enemyFinished(Unit enemy) { - return 0; // signaling: OK - } - -} diff --git a/AI/Wrappers/JavaOO/CMakeLists.txt b/AI/Wrappers/JavaOO/CMakeLists.txt deleted file mode 100644 index da45a64c6e6..00000000000 --- a/AI/Wrappers/JavaOO/CMakeLists.txt +++ /dev/null @@ -1,379 +0,0 @@ -### Java OO AI Wrapper -# -# Global variables set in this file: -# * BUILD_JavaOO_AIWRAPPER -# - -#enable_language(Java) - -# includes rts/build/cmake/UtilJava.cmake -include(UtilJava) - - -set(myName "JavaOO") - - -# Check if the user wants to compile the wrapper -if ("${AI_TYPES}" STREQUAL "ALL" OR "${AI_TYPES}" STREQUAL "JAVA") - set(AIWRAPPERS_JAVA TRUE) -else ("${AI_TYPES}" STREQUAL "ALL" OR "${AI_TYPES}" STREQUAL "JAVA") - set(AIWRAPPERS_JAVA FALSE) -endif ("${AI_TYPES}" STREQUAL "ALL" OR "${AI_TYPES}" STREQUAL "JAVA") - - -# Check dependencies of the wrapper are met -if (AIWRAPPERS_JAVA AND BUILD_Java_AIINTERFACE AND AWK_FOUND AND NOT myName MATCHES "${AI_EXCLUDE_REGEX}") - set_global(BUILD_${myName}_AIWRAPPER TRUE) -else (AIWRAPPERS_JAVA AND BUILD_Java_AIINTERFACE AND AWK_FOUND AND NOT myName MATCHES "${AI_EXCLUDE_REGEX}") - set_global(BUILD_${myName}_AIWRAPPER FALSE) - message("warning: Java OO AI Wrapper will not be built!") -endif (AIWRAPPERS_JAVA AND BUILD_Java_AIINTERFACE AND AWK_FOUND AND NOT myName MATCHES "${AI_EXCLUDE_REGEX}") - - -# Build -if (BUILD_${myName}_AIWRAPPER) - set(myDir "${CMAKE_CURRENT_SOURCE_DIR}") - get_last_path_part(dirName ${myDir}) - set(myName "${dirName}") - set(myTarget "${myName}-AIWrapper") - set(myGenTarget "${myTarget}-generateSources") - set(myJavaTarget "${myTarget}-java") - set(myPomTarget "${myTarget}-pom") - set(mySourceDirRel "src/main/java") - make_absolute(mySourceDir "${myDir}" "${mySourceDirRel}") - - ai_wrapper_message(STATUS "Found AI Wrapper: ${myName}") - - - # Build library - set(myPkgFirstPart "com") - set(myParentPkg "${myPkgFirstPart}/springrts/ai") - set(myPkg "${myParentPkg}/oo") - set(myBinDir "${myDir}/bin") - set(commonAwkScriptsDir "${CMAKE_SOURCE_DIR}/AI/Wrappers/CUtils/bin") - set(myBuildDir "${CMAKE_CURRENT_BINARY_DIR}") - set(myGeneratedSourceDir "${myBuildDir}/src-generated/main/java") - set(myJavaBuildDir "${myBuildDir}/classes") - set(myJarFile "${myName}-AIWrapper") - set(myBinJarFile "${myJarFile}.jar") - set(mySrcJarFile "${myJarFile}-src.jar") - set(myJLibDir "${myDir}/jlib") - find_java_lib(vecmath_jar "vecmath" "${myJLibDir}") - set(myJLibs "${vecmath_jar}") - set(jAiIntJavaSourceDir "${JAVA_SRC_DIR_Java_AIINTERFACE}") - set(jAiIntJavaGeneratedSourceDir "${JAVA_GEN_SRC_DIR_Java_AIINTERFACE}") - set(myClassPath "${myJLibs}${PATH_DELIM_H}${CLASSPATH_Java_AIINTERFACE}") - - set_global(${myName}_AIWRAPPER_JAR_BIN "${myBuildDir}/${myBinJarFile}") - set_global(${myName}_AIWRAPPER_JAR_SRC "${myBuildDir}/${mySrcJarFile}") - set_global(${myName}_AIWRAPPER_JAR_CLASSPATH "${myJLibs}${PATH_DELIM_H}${${myName}_AIWRAPPER_JAR_BIN}") - set_global(${myName}_AIWRAPPER_TARGET "${myTarget}") - set_global(SOURCE_ROOT_${myName}_AIWRAPPER "${myDir}") - set_global(BUILD_ROOT_${myName}_AIWRAPPER "${CMAKE_CURRENT_BINARY_DIR}") - - # Locate the manifest file - find_manifest_file("${myDir}" myManifestFile) - if (myManifestFile) - set(myBinJarArgs "cmf" "${myManifestFile}") - else (myManifestFile) - set(myBinJarArgs "cf") - endif (myManifestFile) - - # remove all generated sources from build dir, if it exists - # (required for build dirs of git:master from before 21. September 2010) - file(REMOVE_RECURSE "${myGeneratedSourceDir}/${myPkg}") - - - # Generate sources - # ---------------- - - set(commonAwkScriptArgs - "-v" "INTERFACE_SOURCE_DIR=${jAiIntJavaSourceDir}" - "-v" "INTERFACE_GENERATED_SOURCE_DIR=${jAiIntJavaGeneratedSourceDir}" - "-v" "JAVA_GENERATED_SOURCE_DIR=${myGeneratedSourceDir}" - "-f" "${commonAwkScriptsDir}/common.awk" - "-f" "${commonAwkScriptsDir}/commonDoc.awk" - ) - - set(mySources - "${mySourceDir}/${myPkg}/AIEvent.java" - "${mySourceDir}/${myPkg}/AIFloat3.java" - "${mySourceDir}/${myPkg}/AIException.java" - "${mySourceDir}/${myPkg}/CallbackAIException.java" - "${mySourceDir}/${myPkg}/EventAIException.java" - ) - - set(myGenClbClasses - "Cheats" - "CommandDescription" - "Command" - "Damage" - "DataDirs" - "Debug" - "Drawer" - "Economy" - "Engine" - "FeatureDef" - "Feature" - "Figure" - "FlankingBonus" - "Game" - "GraphDrawer" - "GraphLine" - "Group" - "Info" - "Line" - "Log" - "Lua" - "Map" - "Mod" - "MoveData" - "OOAICallback" - "OptionValues" - "OrderPreview" - "Pathing" - "PathDrawer" - "Point" - "Resource" - "Roots" - "Shield" - "SkirmishAI" - "Team" - "OverlayTexture" - "UnitDef" - "Unit" - "Version" - "WeaponDef" - "WeaponMount" - "Weapon" - ) - set(myGeneratedCallbackSources ) - foreach (className ${myGenClbClasses}) - list(APPEND myGeneratedCallbackSources - "${myGeneratedSourceDir}/${myPkg}/clb/${className}.java" - "${myGeneratedSourceDir}/${myPkg}/clb/Abstract${className}.java" - "${myGeneratedSourceDir}/${myPkg}/clb/Stub${className}.java" - ) - if ("${className}" STREQUAL "CommandDescription") - list(APPEND myGeneratedCallbackSources - "${myGeneratedSourceDir}/${myPkg}/clb/WrappGroupSupportedCommand.java" - "${myGeneratedSourceDir}/${myPkg}/clb/WrappUnitSupportedCommand.java" - ) - elseif ("${className}" STREQUAL "Command") - list(APPEND myGeneratedCallbackSources - "${myGeneratedSourceDir}/${myPkg}/clb/WrappCurrentCommand.java" - ) - else () - list(APPEND myGeneratedCallbackSources - "${myGeneratedSourceDir}/${myPkg}/clb/Wrapp${className}.java" - ) - endif () - endforeach (className) - - set(myGeneratedEventSources - "${myGeneratedSourceDir}/${myPkg}/AbstractOOAI.java" - "${myGeneratedSourceDir}/${myPkg}/IOOAI.java" - "${myGeneratedSourceDir}/${myPkg}/OOAI.java" - "${myGeneratedSourceDir}/${myPkg}/IOOEventAI.java" - "${myGeneratedSourceDir}/${myPkg}/OOEventAI.java" - "${myGeneratedSourceDir}/${myPkg}/evt/UnitAIEvent.java" - "${myGeneratedSourceDir}/${myPkg}/evt/UnitLifeStateAIEvent.java" - "${myGeneratedSourceDir}/${myPkg}/evt/UnitTeamChangeAIEvent.java" - "${myGeneratedSourceDir}/${myPkg}/evt/EnemyAIEvent.java" - "${myGeneratedSourceDir}/${myPkg}/evt/LoadSaveAIEvent.java" - "${myGeneratedSourceDir}/${myPkg}/evt/CommandFinishedAIEvent.java" - "${myGeneratedSourceDir}/${myPkg}/evt/EnemyCreatedAIEvent.java" - "${myGeneratedSourceDir}/${myPkg}/evt/EnemyDamagedAIEvent.java" - "${myGeneratedSourceDir}/${myPkg}/evt/EnemyDestroyedAIEvent.java" - "${myGeneratedSourceDir}/${myPkg}/evt/EnemyFinishedAIEvent.java" - "${myGeneratedSourceDir}/${myPkg}/evt/EnemyEnterLOSAIEvent.java" - "${myGeneratedSourceDir}/${myPkg}/evt/EnemyEnterRadarAIEvent.java" - "${myGeneratedSourceDir}/${myPkg}/evt/EnemyLeaveLOSAIEvent.java" - "${myGeneratedSourceDir}/${myPkg}/evt/EnemyLeaveRadarAIEvent.java" - "${myGeneratedSourceDir}/${myPkg}/evt/InitAIEvent.java" - "${myGeneratedSourceDir}/${myPkg}/evt/LoadAIEvent.java" - "${myGeneratedSourceDir}/${myPkg}/evt/MessageAIEvent.java" - "${myGeneratedSourceDir}/${myPkg}/evt/LuaMessageAIEvent.java" - "${myGeneratedSourceDir}/${myPkg}/evt/PlayerCommandAIEvent.java" - "${myGeneratedSourceDir}/${myPkg}/evt/ReleaseAIEvent.java" - "${myGeneratedSourceDir}/${myPkg}/evt/SaveAIEvent.java" - "${myGeneratedSourceDir}/${myPkg}/evt/SeismicPingAIEvent.java" - "${myGeneratedSourceDir}/${myPkg}/evt/UnitCapturedAIEvent.java" - "${myGeneratedSourceDir}/${myPkg}/evt/UnitCreatedAIEvent.java" - "${myGeneratedSourceDir}/${myPkg}/evt/UnitDamagedAIEvent.java" - "${myGeneratedSourceDir}/${myPkg}/evt/UnitDestroyedAIEvent.java" - "${myGeneratedSourceDir}/${myPkg}/evt/UnitFinishedAIEvent.java" - "${myGeneratedSourceDir}/${myPkg}/evt/UnitGivenAIEvent.java" - "${myGeneratedSourceDir}/${myPkg}/evt/UnitIdleAIEvent.java" - "${myGeneratedSourceDir}/${myPkg}/evt/UnitMoveFailedAIEvent.java" - "${myGeneratedSourceDir}/${myPkg}/evt/UpdateAIEvent.java" - "${myGeneratedSourceDir}/${myPkg}/evt/WeaponFiredAIEvent.java" - ) - - set(myGeneratedSources - ${myGeneratedCallbackSources} - ${myGeneratedEventSources} - ) - set_source_files_properties(${myGeneratedSources} PROPERTIES GENERATED TRUE) - - set(jAiIntJavaGeneratedSources - "${jAiIntJavaGeneratedSourceDir}/${myParentPkg}/AI.java" - "${jAiIntJavaGeneratedSourceDir}/${myParentPkg}/AICallback.java" - ) - set_source_files_properties(${jAiIntJavaGeneratedSources} PROPERTIES GENERATED TRUE) - - - # Assemble project generated targets (and their libraries) we depend on - set(myDependTargets "${Java_AIINTERFACE_TARGET}") - set(myDependLibFiles "${Java_AIINTERFACE_JAR_BIN}") - set_source_files_properties(${myDependLibFiles} PROPERTIES GENERATED TRUE) - - add_custom_target(${myJavaTarget} - DEPENDS - "${myBuildDir}/${myBinJarFile}" - "${myBuildDir}/${mySrcJarFile}") - add_dependencies(${myJavaTarget} ${myDependTargets}) - - - # generate sources: callback - add_custom_command( - OUTPUT - ${myGeneratedCallbackSources} - COMMAND "${CMAKE_COMMAND}" - "-E" "remove_directory" "${myGeneratedSourceDir}/${myPkg}/clb" - COMMAND "${CMAKE_COMMAND}" - "-E" "make_directory" "${myGeneratedSourceDir}/${myPkg}/clb" - COMMAND "${AWK_BIN}" - ${commonAwkScriptArgs} - "-f" "${commonAwkScriptsDir}/commonOOCallback.awk" - "-f" "${myBinDir}/wrappCallback.awk" - "${jAiIntJavaGeneratedSourceDir}/${myParentPkg}/AICallback.java" - DEPENDS - "${commonAwkScriptsDir}/common.awk" - "${commonAwkScriptsDir}/commonDoc.awk" - "${commonAwkScriptsDir}/commonOOCallback.awk" - "${myBinDir}/wrappCallback.awk" - # Handled through a target level dependency, see below - #"${jAiIntJavaGeneratedSourceDir}/${myParentPkg}/AICallback.java" - WORKING_DIRECTORY - "${myBinDir}" - COMMENT - " ${myTarget}: Generating callback sources" VERBATIM - ) - - # generate sources: events - add_custom_command( - OUTPUT - ${myGeneratedEventSources} - COMMAND "${CMAKE_COMMAND}" - "-E" "remove_directory" "${myGeneratedSourceDir}/${myPkg}/evt" - COMMAND "${CMAKE_COMMAND}" - "-E" "make_directory" "${myGeneratedSourceDir}/${myPkg}/evt" - COMMAND "${AWK_BIN}" - ${commonAwkScriptArgs} - "-f" "${myBinDir}/wrappEvents.awk" - "${jAiIntJavaGeneratedSourceDir}/${myParentPkg}/AI.java" - DEPENDS - "${commonAwkScriptsDir}/common.awk" - "${commonAwkScriptsDir}/commonDoc.awk" - "${myBinDir}/wrappEvents.awk" - "${jAiIntJavaGeneratedSourceDir}/${myParentPkg}/AI.java" - WORKING_DIRECTORY - "${myBinDir}" - COMMENT - " ${myTarget}: Generating event sources" VERBATIM - ) - - add_custom_target(${myGenTarget} DEPENDS ${myGeneratedSources}) - add_dependencies(${myGenTarget} ${Java_AIINTERFACE_TARGET_GENERATE_SOURCES}) # for AICallback.java - add_dependencies(generateSources ${myGenTarget}) - - - # Build the jars - # -------------- - - # Write list of source files to an arg-file - set(mySrcArgFile "${CMAKE_CURRENT_BINARY_DIR}/sourceFiles.txt") - if (EXISTS "${mySrcArgFile}") - file(REMOVE "${mySrcArgFile}") - endif (EXISTS "${mySrcArgFile}") - foreach (srcFile ${mySources} ${myGeneratedSources}) - file(APPEND "${mySrcArgFile}" "\"${srcFile}\"\n") - endforeach (srcFile) - - # compile and pack library - add_custom_command( - OUTPUT - "${myBuildDir}/${myBinJarFile}" - COMMAND "${CMAKE_COMMAND}" - "-E" "remove_directory" "${myJavaBuildDir}" - COMMAND "${CMAKE_COMMAND}" - "-E" "make_directory" "${myJavaBuildDir}" - COMMAND "${Java_JAVAC_EXECUTABLE}" - "${JAVA_COMPILE_FLAG_CONDITIONAL}" - "-Xlint:deprecation" - "-cp" "${myClassPath}" - "-d" "${myJavaBuildDir}" - "@${mySrcArgFile}" - COMMAND "${Java_JAR_EXECUTABLE}" ARGS - ${myBinJarArgs} "${myBuildDir}/${myBinJarFile}" - "-C" "${myJavaBuildDir}" "${myPkgFirstPart}" - DEPENDS - ${myDependLibFiles} - ${mySources} - ${myGeneratedSources} - WORKING_DIRECTORY - "${myBinDir}" - COMMENT - " ${myTarget}: Compiling sources and packing library ${myBinJarFile}" VERBATIM - ) - - # pack sources - add_custom_command( - OUTPUT - "${myBuildDir}/${mySrcJarFile}" - COMMAND "${Java_JAR_EXECUTABLE}" ARGS - "cf" "${${myName}_AIWRAPPER_JAR_SRC}" - "-C" "${mySourceDir}" "${myPkgFirstPart}" - COMMAND "${Java_JAR_EXECUTABLE}" ARGS - "uf" "${${myName}_AIWRAPPER_JAR_SRC}" - "-C" "${myGeneratedSourceDir}" "${myPkgFirstPart}" - DEPENDS - ${myJavaSources} - ${myJavaGeneratedSources} - WORKING_DIRECTORY - "${myBuildDir}" - COMMENT - " ${myTarget}: Creating sources archive ${mySrcJarFile}" VERBATIM - ) - - # This sets the version in pom.xml - # as we have no separate version for the wrapper, - # we use the one from the interface - set(myMavenProperties "-Dmy.version=${Java_AIINTERFACE_VERS}") - add_custom_command( - OUTPUT - "${myBuildDir}/pom-generated.xml" - COMMAND "${CMAKE_COMMAND}" - "-Dfile.in=${myDir}/pom.xml" - "-Dfile.out=${myBuildDir}/pom-generated.xml" - ${myMavenProperties} - "-P" "${CMAKE_MODULES_SPRING}/ConfigureFile.cmake" - DEPENDS - "${myDir}/pom.xml" - WORKING_DIRECTORY - "${myDir}" - COMMENT - " ${myTarget}: Configure pom.xml" VERBATIM - ) - set_source_files_properties("${myBuildDir}/pom-generated.xml" PROPERTIES GENERATED TRUE) - - add_custom_target(${myPomTarget} - DEPENDS - "${myBuildDir}/pom-generated.xml") - - add_custom_target(${myTarget} ALL) - - add_dependencies(${myTarget} ${myJavaTarget}) - -endif (BUILD_${myName}_AIWRAPPER) diff --git a/AI/Wrappers/JavaOO/bin/ant.properties b/AI/Wrappers/JavaOO/bin/ant.properties deleted file mode 100644 index 0807d79b8a8..00000000000 --- a/AI/Wrappers/JavaOO/bin/ant.properties +++ /dev/null @@ -1,26 +0,0 @@ -# Paths are relative to the project home (which is ../ from this file). -# All values are optional. - -;spring.home=../../.. - -# specify Java-AIInterface dirs -;spring.ai.interface.src.home=${spring.home}/AI/Interfaces/Java -;spring.ai.interface.src.dir=${spring.ai.interface.src.home}/src/main/java -;spring.ai.interface.build.home=${build.home}/AI/Interfaces/Java -;spring.ai.interface.build.dir=${spring.ai.interface.build.home}/src-generated/main/java - -# This is used only in the next property -;build.home=${spring.home}/build -# Where jar files will be built -;build.dir=${build.home}/AI/Wrappers/${wrapper.name} - -# Where generated sources shall be created in -;src.generated=${build.dir}/src-generated/main -;src.generated.java=${src.generated}/java - -# This is used only in the next property -;dist.home=${spring.home}/dist -# Where jar files will be installed to -;dist.dir=${dist.home}/AI/Wrappers/${wrapper.name} -# Where HTML JavaDoc files will be generated -;doc.dir=${dist.home}/AI/Wrappers/${wrapper.name}/doc/jdoc diff --git a/AI/Wrappers/JavaOO/bin/build.xml b/AI/Wrappers/JavaOO/bin/build.xml deleted file mode 100644 index 71e836bbb7a..00000000000 --- a/AI/Wrappers/JavaOO/bin/build.xml +++ /dev/null @@ -1,211 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/AI/Wrappers/JavaOO/bin/wrappCallback.awk b/AI/Wrappers/JavaOO/bin/wrappCallback.awk deleted file mode 100755 index 7824eb30137..00000000000 --- a/AI/Wrappers/JavaOO/bin/wrappCallback.awk +++ /dev/null @@ -1,1241 +0,0 @@ -#!/usr/bin/awk -f -# -# This awk script creates Java classes in OO style to wrap the C style -# JNI based AI Callback wrapper. -# In other words, the output of this file wraps: -# com/springrts/ai/AICallback.java -# which wraps: -# rts/ExternalAI/Interface/SSkirmishAICallback.h -# and -# rts/ExternalAI/Interface/AISCommands.h -# -# This script uses functions from the following files: -# * common.awk -# * commonDoc.awk -# * commonOOCallback.awk -# Variables that can be set on the command-line (with -v): -# * GENERATED_SOURCE_DIR : the generated sources root dir -# * JAVA_GENERATED_SOURCE_DIR : the generated java sources root dir -# * INTERFACE_SOURCE_DIR : the Java AI Interfaces static source files root dir -# * INTERFACE_GENERATED_SOURCE_DIR : the Java AI Interfaces generated source files root dir -# -# usage: -# awk -f thisScript.awk -f common.awk -f commonDoc.awk -f commonOOCallback.awk -# awk -f thisScript.awk -f common.awk -f commonDoc.awk -f commonOOCallback.awk \ -# -v 'GENERATED_SOURCE_DIR=/tmp/build/AI/Interfaces/Java/src-generated' -# - -BEGIN { - # initialize things - - # define the field splitter(-regex) - FS = "(\\()|(\\);)"; - IGNORECASE = 0; - - # Used by other scripts - JAVA_MODE = 1; - - # These vars can be assigned externally, see file header. - # Set the default values if they were not supplied on the command line. - if (!GENERATED_SOURCE_DIR) { - GENERATED_SOURCE_DIR = "../src-generated/main"; - } - if (!JAVA_GENERATED_SOURCE_DIR) { - JAVA_GENERATED_SOURCE_DIR = GENERATED_SOURCE_DIR "/java"; - } - if (!INTERFACE_SOURCE_DIR) { - INTERFACE_SOURCE_DIR = "../../../Interfaces/Java/src/main/java"; - } - if (!INTERFACE_GENERATED_SOURCE_DIR) { - INTERFACE_GENERATED_SOURCE_DIR = "../../../Interfaces/Java/src-generated/main/java"; - } - - myMainPkgA = "com.springrts.ai"; - myParentPkgA = myMainPkgA ".oo"; - myPkgA = myParentPkgA ".clb"; - myPkgD = convertJavaNameFormAToD(myPkgA); - myClassVar = "ooClb"; - myWrapClass = "AICallback"; - myWrapVar = "innerCallback"; - - myBufferedClasses["UnitDef"] = 1; - myBufferedClasses["WeaponDef"] = 1; - myBufferedClasses["FeatureDef"] = 1; - - retParamName = "__retVal"; -} - -function createJavaFileName(clsName_c) { - return JAVA_GENERATED_SOURCE_DIR "/" myPkgD "/" clsName_c ".java"; -} - - -function printHeader(outFile_h, javaPkg_h, javaClassName_h, isInterface_h, - implementsInterface_h, isJniBound_h, isAbstract_h, implementsClass_h) { - - if (isInterface_h) { - classOrInterface_h = "interface"; - } else if (isAbstract_h) { - classOrInterface_h = "abstract class"; - } else { - classOrInterface_h = "class"; - } - - extensionsPart_h = ""; - if (isInterface_h) { - extensionsPart_h = " extends Comparable<" javaClassName_h ">"; - } else if (isAbstract_h) { - extensionsPart_h = " implements " implementsInterface_h ""; - } else { - extensionsPart_h = " extends " implementsClass_h " implements " implementsInterface_h; - } - - printCommentsHeader(outFile_h); - print("") >> outFile_h; - print("package " javaPkg_h ";") >> outFile_h; - print("") >> outFile_h; - print("") >> outFile_h; - print("import " myParentPkgA ".CallbackAIException;") >> outFile_h; - print("import " myParentPkgA ".AIFloat3;") >> outFile_h; - if (isJniBound_h) { - print("import " myMainPkgA ".AICallback;") >> outFile_h; - print("import " myMainPkgA ".Util;") >> outFile_h; - } - print("") >> outFile_h; - print("/**") >> outFile_h; - print(" * @author AWK wrapper script") >> outFile_h; - print(" * @version GENERATED") >> outFile_h; - print(" */") >> outFile_h; - print("public " classOrInterface_h " " javaClassName_h extensionsPart_h " {") >> outFile_h; - print("") >> outFile_h; -} - - -function getNullTypeValue(fRet_ntv) { - - if (fRet_ntv == "void") { - return ""; - } else if (fRet_ntv == "String") { - return "\"\""; - } else if (fRet_ntv == "AIFloat3") { - #return "new AIFloat3(0.0f, 0.0f, 0.0f)"; - return "null"; - } else if (fRet_ntv == "java.awt.Color") { - #return "java.awt.Color.BLACK"; - return "null"; - } else if (startsWithCapital(fRet_ntv)) { - # must be a class - return "null"; - } else if (match(fRet_ntv, /^java.util.List/)) { - return "null"; - } else if (match(fRet_ntv, /^java.util.Map/)) { - return "null"; - } else if (fRet_ntv == "boolean") { - return "false"; - } else { - return "0"; - } -} -function printTripleFunc(fRet_tr, fName_tr, fParams_tr, thrownExceptions_tr, outFile_int_tr, outFile_stb_tr, outFile_jni_tr, printIntAndStb_tr, noOverride_tr, isDeprecated_tr) { - - _funcHdr_tr = "public " fRet_tr " " fName_tr "(" fParams_tr ")"; - if (thrownExceptions_tr != "") { - _funcHdr_tr = _funcHdr_tr " throws " thrownExceptions_tr; - } - - if (printIntAndStb_tr) { - print("\t" _funcHdr_tr ";") >> outFile_int_tr; - print("") >> outFile_int_tr; - - isSimpleGetter_tr = ((fRet_tr != "void") && (fParams_tr == "") && match(fName_tr, /^(get|is)/)); - if ((fName_tr == "isEnabled") && match(outFile_int_tr, /Cheats\.java$/)) { - # an exception, because this has a setter anyway - isSimpleGetter_tr = 0; - } - nullTypeValue_tr = getNullTypeValue(fRet_tr); - if (isSimpleGetter_tr) { - # create an additional private member and setter - propName_tr = fName_tr; - sub(/^get/, "", propName_tr); - propName_tr = lowerize(propName_tr); - fSetterName_tr = fName_tr; - sub(/^(get|is)/, "set", fSetterName_tr); - print("\t" "public void " fSetterName_tr "(" fRet_tr " " propName_tr ")" " {") >> outFile_stb_tr; - print("\t\t" "this." propName_tr " = " propName_tr ";") >> outFile_stb_tr; - print("\t" "}") >> outFile_stb_tr; - print("\t" "private " fRet_tr " " propName_tr " = " nullTypeValue_tr ";") >> outFile_stb_tr; - if (isDeprecated_tr) { - # this prevents javac from outputting a warning - print("\t" "/** @deprecated */") >> outFile_stb_tr; - } - print("\t" "@Override") >> outFile_stb_tr; - print("\t" _funcHdr_tr " {") >> outFile_stb_tr; - print("\t\t" "return " propName_tr ";") >> outFile_stb_tr; - } else { - print("\t" "@Override") >> outFile_stb_tr; - print("\t" _funcHdr_tr " {") >> outFile_stb_tr; - # simply return a null like value - if (fRet_tr == "void") { - # return nothing - } else { - print("\t\t" "return " nullTypeValue_tr ";") >> outFile_stb_tr; - } - } - print("\t" "}") >> outFile_stb_tr; - print("") >> outFile_stb_tr; - } - - if (!noOverride_tr) { - print("\t" "@Override") >> outFile_jni_tr; - } - print("\t" _funcHdr_tr " {") >> outFile_jni_tr; - print("") >> outFile_jni_tr; -} - - -function printClasses() { - - # look for AVAILABLE indicators - for (_memberId in cls_memberId_metaComment) { - if (match(cls_memberId_metaComment[_memberId], /AVAILABLE:/)) { - _availCls = cls_memberId_metaComment[_memberId]; - sub(/^.*AVAILABLE:/, "", _availCls); - sub(/[ \t].*$/, "", _availCls); - clsAvailInd_memberId_cls[_memberId] = _availCls; - } - } - - c_size_cs = cls_id_name["*"]; - for (c=0; c < c_size_cs; c++) { - cls_cs = cls_id_name[c]; - anc_size_cs = cls_name_implIds[cls_cs ",*"]; - - printIntAndStb_cs = 1; - for (a=0; a < anc_size_cs; a++) { - implId_cs = cls_name_implIds[cls_cs "," a]; - printClass(implId_cs, cls_cs, printIntAndStb_cs); - # only print interface and stub when printing the first impl-class - printIntAndStb_cs = 0; - } - } -} - - -function printClass(implId_c, clsName_c, printIntAndStb_c) { - - implCls_c = implId_c; - sub(/^.*,/, "", implCls_c); - - clsName_int_c = clsName_c; - clsName_abs_c = "Abstract" clsName_int_c; - clsName_stb_c = "Stub" clsName_int_c; - _fullClsName = cls_implId_fullClsName[implId_c]; - if (_fullClsName != clsName_c) { - lastAncName_c = implId_c; - sub(/,[^,]*$/, "", lastAncName_c); # remove class name - sub(/^.*,/, "", lastAncName_c); # remove pre last ancestor name - noInterfaceIndices_c = lowerize(lastAncName_c) "Id"; - } else { - noInterfaceIndices_c = 0; - } - clsName_jni_c = "Wrapp" _fullClsName; - - if (printIntAndStb_c) { - outFile_int_c = createJavaFileName(clsName_int_c); - outFile_abs_c = createJavaFileName(clsName_abs_c); - outFile_stb_c = createJavaFileName(clsName_stb_c); - } - outFile_jni_c = createJavaFileName(clsName_jni_c); - - if (printIntAndStb_c) { - printHeader(outFile_int_c, myPkgA, clsName_int_c, 1, 0, 0, 0, 0); - printHeader(outFile_abs_c, myPkgA, clsName_abs_c, 0, clsName_int_c, 0, 1, 0); - printHeader(outFile_stb_c, myPkgA, clsName_stb_c, 0, clsName_int_c, 0, 0, clsName_abs_c); - } - printHeader( outFile_jni_c, myPkgA, clsName_jni_c, 0, clsName_int_c, 1, 0, clsName_abs_c); - - # prepare additional indices names - addInds_size_c = split(cls_implId_indicesArgs[implId_c], addInds_c, ","); - for (ai=1; ai <= addInds_size_c; ai++) { - sub(/int /, "", addInds_c[ai]); - addInds_c[ai] = trim(addInds_c[ai]); - } - - myInnerClb = myClassVar ".getInnerCallback()"; - - - # print private vars - print("\t" "private " myWrapClass " " myWrapVar " = null;") >> outFile_jni_c; - # print additionalVars - for (ai=1; ai <= addInds_size_c; ai++) { - print("\t" "private int " addInds_c[ai] " = -1;") >> outFile_jni_c; - } - print("") >> outFile_jni_c; - - - # print constructor - ctorParams = myWrapClass " " myWrapVar; - addIndPars_c = ""; - for (ai=1; ai <= addInds_size_c; ai++) { - addIndPars_c = addIndPars_c ", int " addInds_c[ai]; - } - ctorParams = ctorParams addIndPars_c; - ctorParamsNoTypes = removeParamTypes(ctorParams); - sub(/^, /, "", addIndPars_c); - addIndParsNoTypes_c = removeParamTypes(addIndPars_c); - condAddIndPars_c = (addIndPars_c == "") ? "" : ", "; - print("\t" "public " clsName_jni_c "(" ctorParams ") {") >> outFile_jni_c; - print("") >> outFile_jni_c; - print("\t\t" "this." myWrapVar " = " myWrapVar ";") >> outFile_jni_c; - # init additionalVars - for (ai=1; ai <= addInds_size_c; ai++) { - addIndName = addInds_c[ai]; - print("\t\t" "this." addIndName " = " addIndName ";") >> outFile_jni_c; - } - print("\t" "}") >> outFile_jni_c; - print("") >> outFile_jni_c; - - - # print additional vars fetchers - for (ai=1; ai <= addInds_size_c; ai++) { - addIndName = addInds_c[ai]; - addIndNameCap = capitalize(addIndName); - - printIntAndStb_tmp_c = printIntAndStb_c; - _noOverride = 0; - if ((noInterfaceIndices_c != 0) && (addIndName == noInterfaceIndices_c)) { - printIntAndStb_tmp_c = 0; - _noOverride = 1; - } - - # Print the direct fetcher function, eg. "int getUnitId()" - _fRet = "int"; - _fName = "get" addIndNameCap; - _fParams = ""; - _fExceps = ""; - _fIsDeprecated = 0; - printTripleFunc(_fRet, _fName, _fParams, _fExceps, outFile_int_c, outFile_stb_c, outFile_jni_c, printIntAndStb_tmp_c, _noOverride, _fIsDeprecated); - print("\t\t" "return " addIndName ";") >> outFile_jni_c; - print("\t" "}") >> outFile_jni_c; - print("") >> outFile_jni_c; - - # Print the OO entity fetcher function if applicable, eg. "Unit getUnit()" - addIndNameCapOO = addIndNameCap; - _hadId = sub(/Id$/, "", addIndNameCapOO); - if (_hadId && (addIndNameCapOO in cls_name_id) && (addIndNameCapOO != clsName_int_c)) { - _refObj = addIndNameCapOO; # example: Unit - _implId = implId_m "," _refObj; - if (_implId in cls_implId_fullClsName) { - _fullClsName = cls_implId_fullClsName[_implId]; - } else if (cls_name_implIds[_refObj ",*"] == 1) { - _fullClsName = cls_name_implIds[_refObj ",0"]; - _fullClsName = cls_implId_fullClsName[_fullClsName]; - } else { - print("ERROR: failed finding the full class name for: " _refObj); - exit(1); - } - - _wrappGetInst_params = myWrapVar; - for (aij=1; aij <= ai; aij++) { - _wrappGetInst_params = _wrappGetInst_params ", " addInds_c[aij]; - } - - _fRet = addIndNameCapOO; - _fName = "get" addIndNameCapOO; - _fParams = ""; - _fExceps = ""; - _fIsDeprecated = 0; - printTripleFunc(_fRet, _fName, _fParams, _fExceps, outFile_int_c, outFile_stb_c, outFile_jni_c, printIntAndStb_tmp_c, _noOverride, _fIsDeprecated); - print("\t\t" "return Wrapp" _fullClsName ".getInstance(" _wrappGetInst_params ");") >> outFile_jni_c; - print("\t" "}") >> outFile_jni_c; - print("") >> outFile_jni_c; - } - } - - # print static instance fetcher method - { - clsIsBuffered_c = isBufferedClass(clsName_c); - _isAvailableMethod = ""; - for (_memId in clsAvailInd_memberId_cls) { - if (clsAvailInd_memberId_cls[_memId] == clsName_c) { - _isAvailableMethod = _memId; - gsub(/,/, "_", _isAvailableMethod); - } - } - - if (clsIsBuffered_c) { - print("\t" "private static java.util.Map _buffer_instances = new java.util.HashMap();") >> outFile_jni_c; - print("") >> outFile_jni_c; - } - print("\t" "public static " clsName_c " getInstance(" ctorParams ") {") >> outFile_jni_c; - print("") >> outFile_jni_c; - lastParamName = ctorParamsNoTypes; - sub(/^.*,[ \t]*/, "", lastParamName); - if (match(lastParamName, /^[^ \t]+Id$/)) { - # id's < 0 are invalid, return null - print("\t\t" "if (" lastParamName " < 0) {") >> outFile_jni_c; - print("\t\t\t" "return null;") >> outFile_jni_c; - print("\t\t" "}") >> outFile_jni_c; - print("") >> outFile_jni_c; - } - print("\t\t" clsName_c " _ret = null;") >> outFile_jni_c; - if (_isAvailableMethod == "") { - print("\t\t" "_ret = new " clsName_jni_c "(" ctorParamsNoTypes ");") >> outFile_jni_c; - } else { - print("\t\t" "boolean isAvailable = " myWrapVar "." _isAvailableMethod "(" addIndParsNoTypes_c ");") >> outFile_jni_c; - print("\t\t" "if (isAvailable) {") >> outFile_jni_c; - print("\t\t\t" "_ret = new " clsName_jni_c "(" ctorParamsNoTypes ");") >> outFile_jni_c; - print("\t\t" "}") >> outFile_jni_c; - } - if (clsIsBuffered_c) { - if (_isAvailableMethod == "") { - print("\t\t" "{") >> outFile_jni_c; - } else { - print("\t\t" "if (_ret != null) {") >> outFile_jni_c; - } - print("\t\t\t" "Integer indexHash = _ret.hashCode();") >> outFile_jni_c; - print("\t\t\t" "if (_buffer_instances.containsKey(indexHash)) {") >> outFile_jni_c; - print("\t\t\t\t" "_ret = _buffer_instances.get(indexHash);") >> outFile_jni_c; - print("\t\t\t" "} else {") >> outFile_jni_c; - print("\t\t\t\t" "_buffer_instances.put(indexHash, _ret);") >> outFile_jni_c; - print("\t\t\t" "}") >> outFile_jni_c; - print("\t\t" "}") >> outFile_jni_c; - } - print("\t\t" "return _ret;") >> outFile_jni_c; - print("\t" "}") >> outFile_jni_c; - print("") >> outFile_jni_c; - } - - - if (printIntAndStb_c) { - # print compareTo(other) method - { - print("\t" "@Override") >> outFile_abs_c; - print("\t" "public int compareTo(" clsName_c " other) {") >> outFile_abs_c; - print("\t\t" "final int BEFORE = -1;") >> outFile_abs_c; - print("\t\t" "final int EQUAL = 0;") >> outFile_abs_c; - print("\t\t" "final int AFTER = 1;") >> outFile_abs_c; - print("") >> outFile_abs_c; - print("\t\t" "if (this == other) return EQUAL;") >> outFile_abs_c; - print("") >> outFile_abs_c; - - if (isClbRootCls) { - print("\t\t" "if (this.skirmishAIId < other.skirmishAIId) return BEFORE;") >> outFile_abs_c; - print("\t\t" "if (this.skirmishAIId > other.skirmishAIId) return AFTER;") >> outFile_abs_c; - print("\t\t" "return EQUAL;") >> outFile_abs_c; - } else { - for (ai=1; ai <= addInds_size_c; ai++) { - addIndName = addInds_c[ai]; - if ((noInterfaceIndices_c == 0) || (addIndName != noInterfaceIndices_c)) { - print("\t\t" "if (this.get" capitalize(addIndName) "() < other.get" capitalize(addIndName) "()) return BEFORE;") >> outFile_abs_c; - print("\t\t" "if (this.get" capitalize(addIndName) "() > other.get" capitalize(addIndName) "()) return AFTER;") >> outFile_abs_c; - } - } - print("\t\t" "return 0;") >> outFile_abs_c; - } - print("\t" "}") >> outFile_abs_c; - print("") >> outFile_abs_c; - } - - - # print equals(other) method - if (!isClbRootCls) { - print("\t" "@Override") >> outFile_abs_c; - print("\t" "public boolean equals(Object otherObject) {") >> outFile_abs_c; - print("") >> outFile_abs_c; - print("\t\t" "if (this == otherObject) return true;") >> outFile_abs_c; - print("\t\t" "if (!(otherObject instanceof " clsName_c ")) return false;") >> outFile_abs_c; - print("\t\t" clsName_c " other = (" clsName_c ") otherObject;") >> outFile_abs_c; - print("") >> outFile_abs_c; - - #if (isClbRootCls) { - # print("\t\t" "if (this.skirmishAIId != other.skirmishAIId) return false;") >> outFile_abs_c; - # print("\t\t" "return true;") >> outFile_abs_c; - #} - #else - { - for (ai=1; ai <= addInds_size_c; ai++) { - addIndName = addInds_c[ai]; - if ((noInterfaceIndices_c == 0) || (addIndName != noInterfaceIndices_c)) { - print("\t\t" "if (this.get" capitalize(addIndName) "() != other.get" capitalize(addIndName) "()) return false;") >> outFile_abs_c; - } - } - print("\t\t" "return true;") >> outFile_abs_c; - } - print("\t" "}") >> outFile_abs_c; - print("") >> outFile_abs_c; - } - - - # print hashCode() method - if (!isClbRootCls) { - print("\t" "@Override") >> outFile_abs_c; - print("\t" "public int hashCode() {") >> outFile_abs_c; - print("") >> outFile_abs_c; - - if (isClbRootCls) { - print("\t\t" "int _res = 0;") >> outFile_abs_c; - print("") >> outFile_abs_c; - print("\t\t" "_res += this.skirmishAIId * 10E8;") >> outFile_abs_c; - } else { - print("\t\t" "int _res = 23;") >> outFile_abs_c; - print("") >> outFile_abs_c; - # NOTE: This could go wrong if we have more then 7 additional indices - # see 10E" (7-ai) below - # the conversion to int is nessesarry, - # as otherwise it would be a double, - # which would be higher then max int, - # and most hashes would end up being max int, - # when converted from double to int - for (ai=1; ai <= addInds_size_c; ai++) { - addIndName = addInds_c[ai]; - if ((noInterfaceIndices_c == 0) || (addIndName != noInterfaceIndices_c)) { - print("\t\t" "_res += this.get" capitalize(addIndName) "() * (int) (10E" (7-ai) ");") >> outFile_abs_c; - } - } - } - print("") >> outFile_abs_c; - print("\t\t" "return _res;") >> outFile_abs_c; - print("\t" "}") >> outFile_abs_c; - print("") >> outFile_abs_c; - } - - - # print toString() method - { - print("\t" "@Override") >> outFile_abs_c; - print("\t" "public String toString() {") >> outFile_abs_c; - print("") >> outFile_abs_c; - print("\t\t" "String _res = this.getClass().toString();") >> outFile_abs_c; - print("") >> outFile_abs_c; - - #if (isClbRootCls) { # NO FOLD - # print("\t\t" "_res = _res + \"(skirmishAIId=\" + this.skirmishAIId + \", \";") >> outFile_abs_c; - #} else { # NO FOLD - # print("\t\t" "_res = _res + \"(clbHash=\" + this." myWrapVar ".hashCode() + \", \";") >> outFile_abs_c; - # print("\t\t" "_res = _res + \"skirmishAIId=\" + this." myWrapVar ".SkirmishAI_getSkirmishAIId() + \", \";") >> outFile_abs_c; - for (ai=1; ai <= addInds_size_c; ai++) { - addIndName = addInds_c[ai]; - if ((noInterfaceIndices_c == 0) || (addIndName != noInterfaceIndices_c)) { - print("\t\t" "_res = _res + \"" addIndName "=\" + this.get" capitalize(addIndName) "() + \", \";") >> outFile_abs_c; - } - } - #} # NO FOLD - print("\t\t" "_res = _res + \")\";") >> outFile_abs_c; - print("") >> outFile_abs_c; - print("\t\t" "return _res;") >> outFile_abs_c; - print("\t" "}") >> outFile_abs_c; - print("") >> outFile_abs_c; - } - } - - # make these available in called functions - implId_c_ = implId_c; - clsName_c_ = clsName_c; - printIntAndStb_c_ = printIntAndStb_c; - - # print member functions - members_size = cls_name_members[clsName_int_c ",*"]; - for (m=0; m < members_size; m++) { - memName_c = cls_name_members[clsName_int_c "," m]; - fullName_c = implId_c "," memName_c; - gsub(/,/, "_", fullName_c); - if (doWrappMember(fullName_c)) { - printMember(fullName_c, memName_c, addInds_size_c); - } else { - print("JavaOO-AIWrapper: NOTE: intentionally not wrapped: " fullName_c); - } - } - - - # finnish up - if (printIntAndStb_c) { - print("}") >> outFile_int_c; - print("") >> outFile_int_c; - close(outFile_int_c); - - print("}") >> outFile_abs_c; - print("") >> outFile_abs_c; - close(outFile_abs_c); - - print("}") >> outFile_stb_c; - print("") >> outFile_stb_c; - close(outFile_stb_c); - } - print("}") >> outFile_jni_c; - print("") >> outFile_jni_c; - close(outFile_jni_c); -} - - -function isRetParamName(paramName_rp) { - return (match(paramName_rp, /_out(_|$)/) || match(paramName_rp, /(^|_)?ret_/)); -} - - -function printMember(fullName_m, memName_m, additionalIndices_m) { - - # use some vars from the printClass function (which called us) - implId_m = implId_c_; - clsName_m = clsName_c_; - printIntAndStb_m = printIntAndStb_c_; - implCls_m = implCls_c; - clsName_int_m = clsName_int_c; - clsName_stb_m = clsName_stb_c; - clsName_jni_m = clsName_jni_c; - outFile_int_m = outFile_int_c; - outFile_stb_m = outFile_stb_c; - outFile_jni_m = outFile_jni_c; - addInds_size_m = addInds_size_c; - for (ai=1; ai <= addInds_size_m; ai++) { - addInds_m[ai] = addInds_c[ai]; - } - - indent_m = "\t"; - memId_m = clsName_m "," memName_m; - retType = cls_memberId_retType[memId_m]; # this may be changed - retType_int = retType; # this is a const var - params = cls_memberId_params[memId_m]; - isFetcher = cls_memberId_isFetcher[memId_m]; - metaComment = cls_memberId_metaComment[memId_m]; - memName = fullName_m; - sub(/^.*_/, "", memName); - functionName_m = fullName_m; - sub(/^[^_]+_/, "", functionName_m); - - if (memId_m in clsAvailInd_memberId_cls) { - return; - } - - isVoid_int_m = (retType_int == "void"); - - retVar_int_m = "_ret_int"; # this is a const var - retVar_out_m = retVar_int_m; # this may be changed - declaredVarsCode = ""; - conversionCode_pre = ""; - conversionCode_post = ""; - thrownExceptions = ""; - ommitMainCall = 0; - - if (!isVoid_int_m) { - declaredVarsCode = "\t\t" retType_int " " retVar_int_m ";" "\n" declaredVarsCode; - } - - - # Rewrite meta comment - if (match(metaComment, /FETCHER:MULTI:IDs:/)) { - # convert this: FETCHER:MULTI:IDs:Group:groupIds - # to this: ARRAY:groupIds->Group - _mc_pre = metaComment; - sub(/FETCHER:MULTI:IDs:.*$/, "", _mc_pre); - _mc_fet = metaComment; - sub(/^.*FETCHER:MULTI:IDs:/, "", _mc_fet); - sub(/[ \t].*$/, "", _mc_fet); - _mc_post = metaComment; - sub(/^.*FETCHER:MULTI:IDs:[^ \t]*/, "", _mc_post); - - _refObj = _mc_fet; - sub(/:.*$/, "", _refObj); - _refPaNa = _mc_fet; - sub(/^.*:/, "", _refPaNa); - - _mc_newArr = "ARRAY:" _refPaNa "->" _refObj; - metaComment = _mc_pre _mc_newArr _mc_post; - } - if (match(metaComment, /FETCHER:MULTI:NUM:/)) { - # convert this: FETCHER:MULTI:NUM:Resource - # to this: ARRAY:RETURN_SIZE->Resource - sub(/FETCHER:MULTI:NUM:/, "ARRAY:RETURN_SIZE->", metaComment); - } - if (match(metaComment, /REF:MULTI:/)) { - # convert this: REF:MULTI:unitDefIds->UnitDef - # to this: ARRAY:unitDefIds->UnitDef - sub(/REF:MULTI:/, "ARRAY:", metaComment); - } - - # remove additional indices from the outer params - for (ai=1; ai <= addInds_size_m; ai++) { - _removed = sub(/[^,]+(, )?/, "", params); - if (!_removed && !part_isStatic(memName_m, metaComment)) { - addIndName = addInds_m[ai]; - print("ERROR: failed removing additional indices " addIndName " from method " memName_m " in class " clsName_int_m); - exit(1); - } - } - - innerParams = removeParamTypes(params); - - # add additional indices fetcher calls to inner params - addInnerParams = ""; - addInds_real_size_m = addInds_size_m; - if (part_isStatic(memName_m, metaComment)) { - addInds_real_size_m--; - } - for (ai=1; ai <= addInds_real_size_m; ai++) { - addIndName = addInds_m[ai]; - _condComma = ""; - if (addInnerParams != "") { - _condComma = ", "; - } - addInnerParams = addInnerParams _condComma "this.get" capitalize(addIndName) "()"; - } - _condComma = ""; - if ((addInnerParams != "") && (innerParams != "")) { - _condComma = ", "; - } - innerParams = addInnerParams _condComma innerParams; - - - # convert param types - paramNames_size = split(innerParams, paramNames, ", "); - for (prm = 1; prm <= paramNames_size; prm++) { - paNa = paramNames[prm]; - if (!isRetParamName(paNa)) { - if (match(paNa, /_posF3/)) { - # convert float[3] to AIFloat3 - paNaNew = paNa; - sub(/_posF3/, "", paNaNew); - sub("float\\[\\] " paNa, "AIFloat3 " paNaNew, params); - conversionCode_pre = conversionCode_pre "\t\t" "float[] " paNa " = " paNaNew ".toFloatArray();" "\n"; - } else if (match(paNa, /_colorS3/)) { - # convert short[3] to java.awt.Color - paNaNew = paNa; - sub(/_colorS3/, "", paNaNew); - sub("short\\[\\] " paNa, "java.awt.Color " paNaNew, params); - conversionCode_pre = conversionCode_pre "\t\t" "short[] " paNa " = Util.toShort3Array(" paNaNew ");" "\n"; - } - } - } - - # convert an error return int value to an Exception - # "error-return:0=OK" - if (part_isErrorReturn(metaComment) && retType == "int") { - errorRetValueOk_m = part_getErrorReturnValueOk(metaComment); - - conversionCode_post = conversionCode_post "\t\t" "if (" retVar_out_m " != " errorRetValueOk_m ") {" "\n"; - conversionCode_post = conversionCode_post "\t\t\t" "throw new CallbackAIException(\"" memName_m "\", " retVar_out_m ");" "\n"; - conversionCode_post = conversionCode_post "\t\t" "}" "\n"; - thrownExceptions = thrownExceptions ", CallbackAIException" thrownExceptions; - - retType = "void"; - } - - # convert out params to return values - paramTypeNames_size = split(params, paramTypeNames, ", "); - hasRetParam = 0; - for (prm = 1; prm <= paramTypeNames_size; prm++) { - paNa = extractParamName(paramTypeNames[prm]); - if (isRetParamName(paNa)) { - if (retType == "void") { - paTy = extractParamType(paramTypeNames[prm]); - hasRetParam = 1; - if (match(paNa, /_posF3/)) { - # convert float[3] to AIFloat3 - retParamType = "AIFloat3"; - retVar_out_m = "_ret"; - conversionCode_pre = conversionCode_pre "\t\t" "float[] " paNa " = new float[3];" "\n"; - conversionCode_post = conversionCode_post "\t\t" retVar_out_m " = new AIFloat3(" paNa "[0], " paNa "[1]," paNa "[2]);" "\n"; - declaredVarsCode = "\t\t" retParamType " " retVar_out_m ";" "\n" declaredVarsCode; - sub("(, )?float\\[\\] " paNa, "", params); - retType = retParamType; - } else if (match(paNa, /_colorS3/)) { - retParamType = "java.awt.Color"; - retVar_out_m = "_ret"; - conversionCode_pre = conversionCode_pre "\t\t" "short[] " paNa " = new short[3];" "\n"; - conversionCode_post = conversionCode_post "\t\t" retVar_out_m " = Util.toColor(" paNa ");" "\n"; - declaredVarsCode = "\t\t" retParamType " " retVar_out_m ";" "\n" declaredVarsCode; - sub("(, )?short\\[\\] " paNa, "", params); - retType = retParamType; - } else if (match(paTy, /StringBuffer/)) { - retParamType = "String"; - retVar_out_m = "_ret"; - conversionCode_pre = conversionCode_pre "\t\t" "StringBuffer " paNa " = new StringBuffer();" "\n"; - conversionCode_post = conversionCode_post "\t\t" retParamType " " retVar_out_m " = " paNa ".toString();" "\n"; - sub("(, )?StringBuffer " paNa, "", params); - retType = retParamType; - } else { - print("FAILED converting return param: " paramTypeNames[prm] " / " fullName_m); - exit(1); - } - } else { - print("FAILED converting return param: return type should be \"void\", but is \"" retType "\""); - exit(1); - } - } - } - - # REF: - refObjs_size_m = split(metaComment, refObjs_m, "REF:"); - for (ro=2; ro <= refObjs_size_m; ro++) { - _ref = refObjs_m[ro]; - sub(/[ \t].*$/, "", _ref); # remove parts after this REF part - _isMulti = match(_ref, /MULTI:/); - _isReturn = match(_ref, /RETURN->/); - - if (!_isMulti && !_isReturn) { - # convert single param reference - _refRel = _ref; - sub(/^.*:/, "", _refRel); - _paNa = _refRel; # example: resourceId - sub(/->.*$/, "", _paNa); - _refObj = _refRel; # example: Resource - sub(/^.*->/, "", _refObj); - _paNaNew = _paNa; - if (!sub(/Id$/, "", _paNaNew)) { - _paNaNew = "oo_" _paNaNew; - } - - if (_refObj == "Team" || _refObj == "FigureGroup" || _refObj == "Path") { - print("note: ignoring meta comment: REF:" _ref); - } else { - _paNa_found = sub("int " _paNa, _refObj " " _paNaNew, params); - # it may not be found if it is an output parameter - if (_paNa_found) { - conversionCode_pre = conversionCode_pre "\t\t" "int " _paNa " = " _paNaNew ".get" _refObj "Id();" "\n"; - } - } - } else if (!_isMulti && _isReturn) { - _refObj = _ref; # example: Resource - sub(/^.*->/, "", _refObj); - - if (_refObj == "Team" || _refObj == "FigureGroup" || _refObj == "Path") { - print("note: ignoring meta comment: REF:" _ref); - continue; - } - - _implId = implId_m "," _refObj; - if (_implId in cls_implId_fullClsName) { - _fullClsName = cls_implId_fullClsName[_implId]; - } else if (cls_name_implIds[_refObj ",*"] == 1) { - _fullClsName = cls_name_implIds[_refObj ",0"]; - _fullClsName = cls_implId_fullClsName[_fullClsName]; - } else { - print("ERROR: failed finding the full class name for: " _refObj); - exit(1); - } - - _retVar_out_new = retVar_out_m "_out"; - _wrappGetInst_params = myWrapVar; - _hasRetInd = 0; - _inPa_size = split(innerParams, _, ","); - if (retType != "void" && (_inPa_size == addInds_size_m || _inPa_size == 0)) { - _hasRetInd = 1; - } - for (ai=1; ai <= (addInds_size_m-_hasRetInd); ai++) { - # Very hacky! too unmotivated for proper fix, sorry. - # proper fix would involve getting the parent of the wrapped - # class and using its additional indices - if ((functionName_m != "UnitDef_WeaponMount_getWeaponDef") && (functionName_m != "Unit_Weapon_getDef")) { - _wrappGetInst_params = _wrappGetInst_params ", " addInds_m[ai]; - } - } - if (retType != "void") { - _wrappGetInst_params = _wrappGetInst_params ", " retVar_out_m; - } else { - ommitMainCall = 1; - } - conversionCode_post = conversionCode_post "\t\t" _retVar_out_new " = Wrapp" _fullClsName ".getInstance(" _wrappGetInst_params ");" "\n"; - declaredVarsCode = "\t\t" _refObj " " _retVar_out_new ";" "\n" declaredVarsCode; - retVar_out_m = _retVar_out_new; - retType = _refObj; - } else { - print("WARNING: unsupported: REF:" _ref); - } - } - - - isMap = part_isMap(fullName_m, metaComment); - if (isMap) { - - _isFetching = 1; - _isRetSize = 0; - _isObj = 0; - _mapVar_size = "_size"; - _mapVar_keys = "keys"; - _mapVar_values = "values"; - _mapType_key = "String"; - _mapType_value = "String"; - _mapType_oo_key = "String"; - _mapType_oo_value = "String"; - _mapVar_oo = "_map"; - _mapType_int = "java.util.Map<" _mapType_oo_key ", " _mapType_oo_value ">"; - _mapType_impl = "java.util.HashMap<" _mapType_oo_key ", " _mapType_oo_value ">"; - - sub("(, )?" _mapType_key "\\[\\] " _mapVar_keys, "", params); - sub("(, )?" _mapType_value "\\[\\] " _mapVar_values, "", params); - sub(/, $/ , "", params); - - declaredVarsCode = "\t\t" "int " _mapVar_size ";" "\n" declaredVarsCode; - if (_isFetching) { - declaredVarsCode = "\t\t" _mapType_int " " _mapVar_oo ";" "\n" declaredVarsCode; - } - if (!_isRetSize) { - declaredVarsCode = "\t\t" _mapType_key "[] " _mapVar_keys ";" "\n" declaredVarsCode; - declaredVarsCode = "\t\t" _mapType_value "[] " _mapVar_values ";" "\n" declaredVarsCode; - if (_isFetching) { - conversionCode_pre = conversionCode_pre "\t\t" _mapVar_keys " = null;" "\n"; - conversionCode_pre = conversionCode_pre "\t\t" _mapVar_values " = null;" "\n"; - conversionCode_pre = conversionCode_pre "\t\t" _mapVar_size " = " myWrapVar "." functionName_m "(" innerParams ");" "\n"; - } else { - #conversionCode_pre = conversionCode_pre "\t\t" _arraySizeVar " = " _arrayListVar ".size();" "\n"; - #conversionCode_pre = conversionCode_pre "\t\t" "int _size = " _arraySizeVar ";" "\n"; - } - } - - if (_isRetSize) { - #conversionCode_post = conversionCode_post "\t\t" _arraySizeVar " = " retVar_out_m ";" "\n"; - #_arraySizeMaxPaNa = _arraySizeVar; - } else { - conversionCode_pre = conversionCode_pre "\t\t" _mapVar_keys " = new " _mapType_key "[" _mapVar_size "];" "\n"; - conversionCode_pre = conversionCode_pre "\t\t" _mapVar_values " = new " _mapType_value "[" _mapVar_size "];" "\n"; - } - - if (_isFetching) { - # convert to a HashMap - conversionCode_post = conversionCode_post "\t\t" _mapVar_oo " = new " _mapType_impl "();" "\n"; - conversionCode_post = conversionCode_post "\t\t" "for (int i=0; i < " _mapVar_size "; i++) {" "\n"; -# if (_isObj) { -# if (_isRetSize) { - conversionCode_post = conversionCode_post "\t\t\t" _mapVar_oo ".put(" _mapVar_keys "[i], " _mapVar_values "[i]);" "\n"; -# } else { - #conversionCode_post = conversionCode_post "\t\t\t" _mapVar_oo ".put(" myPkgA ".Wrapp" _refObj ".getInstance(" myWrapVar _addWrappVars ", " _arrayPaNa "[i]));" "\n"; -# } -# } else if (_isNative) { - #conversionCode_post = conversionCode_post "\t\t\t" _arrayListVar ".add(" _arrayPaNa "[i]);" "\n"; -# } - conversionCode_post = conversionCode_post "\t\t" "}" "\n"; - - retParamType = _mapType_int; - retVar_out_m = _mapVar_oo; - retType = retParamType; - } else { - # convert from a HashMap - } - } - - - isArray = part_isArray(fullName_m, metaComment); - if (isArray) { - _refObj = ""; - _arrayPaNa = metaComment; - _addWrappVars = ""; - sub(/^.*ARRAY:/, "", _arrayPaNa); - sub(/[ \t].*$/, "", _arrayPaNa); - if (match(_arrayPaNa, /->/)) { - _refObj = _arrayPaNa; - sub(/->.*$/, "", _arrayPaNa); - sub(/^.*->/, "", _refObj); - _refObjInt = _refObj; - - if (match(_refObj, /-/)) { - sub(/-.*$/, "", _refObj); - sub(/^.*-/, "", _refObjInt); - } - _implId = implId_m "," _refObj; - if (_implId in cls_implId_fullClsName) { - _fullClsName = cls_implId_fullClsName[_implId]; - } else if ((myRootClass "," _refObj) in cls_implId_fullClsName) { - _implId = myRootClass "," _refObj; - _fullClsName = cls_implId_fullClsName[_implId]; - } else { - print("ERROR: failed to find the full class name for " _refObj " in " fullName_m); - exit(1); - } - _refObj = _fullClsName; - _addWrappVars = cls_implId_indicesArgs[_implId]; - sub(/(,)?[^,]*$/, "", _addWrappVars); # remove last index - _addWrappVars = trim(removeParamTypes(_addWrappVars)); - if (_addWrappVars != "") { - _addWrappVars = ", " _addWrappVars; - } - } - - _isF3 = match(_arrayPaNa, /_AposF3/); - _isObj = (_refObj != ""); - _isNative = (!_refObj && !_isObjc); - - _isRetSize = 0; - if (_isObj) { - _isRetSize = (_arrayPaNa == "RETURN_SIZE"); - } - - _arrayType = params; - sub("\\[\\][ \t]" _arrayPaNa ".*$", "", _arrayType); - sub("^.*[ \t]", "", _arrayType); - _arraySizeMaxPaNa = _arrayPaNa "_sizeMax"; - _arraySizeVar = _arrayPaNa "_size"; - _arraySizeRaw = _arrayPaNa "_raw_size"; - - _arrayListVar = _arrayPaNa "_list"; - if (_isF3) { - _arrListGenType = "AIFloat3"; - } else if (_isObj) { - _arrListGenType = _refObjInt; - } else if (_isNative) { - _arrListGenType = convertJavaBuiltinTypeToClass(_arrayType); - } - _arrListType = "java.util.List<" _arrListGenType ">"; - _arrListImplType = "java.util.ArrayList<" _arrListGenType ">"; - - _isFetching = sub("(, )?int " _arraySizeMaxPaNa, "", params); - if (_isRetSize) { - _isFetching = 1; - } else { - if (!_isFetching && !_isRetSize) { - _isNonFetcher = sub("(, )?int " _arraySizeVar, "", params); - if (!_isNonFetcher) { - print("ERROR: neither propper fetcher nor supplier ARRAY syntax in function: " fullName_m); - exit(1); - } - } - if (_isFetching) { - sub(_arrayType "\\[\\] " _arrayPaNa, "", params); - } else { - sub(_arrayType "\\[\\] " _arrayPaNa, _arrListType " " _arrayListVar, params); - } - sub(/^, /, "", params); - sub(/, $/, "", params); - } - - declaredVarsCode = "\t\t" "int " _arraySizeVar ";" "\n" declaredVarsCode; - if (_isFetching) { - declaredVarsCode = "\t\t" _arrListType " " _arrayListVar ";" "\n" declaredVarsCode; - } - if (!_isRetSize) { - declaredVarsCode = "\t\t" _arrayType "[] " _arrayPaNa ";" "\n" declaredVarsCode; - declaredVarsCode = "\t\t" "int " _arraySizeRaw ";" "\n" declaredVarsCode; - if (_isFetching) { - declaredVarsCode = "\t\t" "int " _arraySizeMaxPaNa ";" "\n" declaredVarsCode; - conversionCode_pre = conversionCode_pre "\t\t" _arraySizeMaxPaNa " = Integer.MAX_VALUE;" "\n"; - conversionCode_pre = conversionCode_pre "\t\t" _arrayPaNa " = null;" "\n"; - conversionCode_pre = conversionCode_pre "\t\t" _arraySizeVar " = " myWrapVar "." functionName_m "(" innerParams ");" "\n"; - conversionCode_pre = conversionCode_pre "\t\t" _arraySizeMaxPaNa " = " _arraySizeVar ";" "\n"; - conversionCode_pre = conversionCode_pre "\t\t" _arraySizeRaw " = " _arraySizeVar ";" "\n"; - if (_isF3) { - conversionCode_pre = conversionCode_pre "\t\t" "if (" _arraySizeVar " % 3 != 0) {" "\n"; - conversionCode_pre = conversionCode_pre "\t\t\t" "throw new RuntimeException(\"returned AIFloat3 array has incorrect size (\" + " _arraySizeVar "+ \"), should be a multiple of 3.\");" "\n"; - conversionCode_pre = conversionCode_pre "\t\t" "}" "\n"; - conversionCode_pre = conversionCode_pre "\t\t" _arraySizeVar " /= 3;" "\n"; - } - } else { - conversionCode_pre = conversionCode_pre "\t\t" _arraySizeVar " = " _arrayListVar ".size();" "\n"; - conversionCode_pre = conversionCode_pre "\t\t" "int _size = " _arraySizeVar ";" "\n"; - if (_isF3) { - conversionCode_pre = conversionCode_pre "\t\t" _arraySizeVar " *= 3;" "\n"; - } - conversionCode_pre = conversionCode_pre "\t\t" _arraySizeRaw " = " _arraySizeVar ";" "\n"; - } - } - - if (_isRetSize) { - conversionCode_post = conversionCode_post "\t\t" _arraySizeVar " = " retVar_out_m ";" "\n"; - _arraySizeMaxPaNa = _arraySizeVar; - } else { - conversionCode_pre = conversionCode_pre "\t\t" _arrayPaNa " = new " _arrayType "[" _arraySizeRaw "];" "\n"; - } - - if (_isFetching) { - # convert to an ArrayList - conversionCode_post = conversionCode_post "\t\t" _arrayListVar " = new " _arrListImplType "(" _arraySizeVar ");" "\n"; - conversionCode_post = conversionCode_post "\t\t" "for (int i=0; i < " _arraySizeMaxPaNa "; i++) {" "\n"; - if (_isF3) { - conversionCode_post = conversionCode_post "\t\t\t" _arrayListVar ".add(new AIFloat3(" _arrayPaNa "[i], " _arrayPaNa "[++i], " _arrayPaNa "[++i]));" "\n"; - } else if (_isObj) { - if (_isRetSize) { - conversionCode_post = conversionCode_post "\t\t\t" _arrayListVar ".add(" myPkgA ".Wrapp" _refObj ".getInstance(" myWrapVar _addWrappVars ", i));" "\n"; - } else { - conversionCode_post = conversionCode_post "\t\t\t" _arrayListVar ".add(" myPkgA ".Wrapp" _refObj ".getInstance(" myWrapVar _addWrappVars ", " _arrayPaNa "[i]));" "\n"; - } - } else if (_isNative) { - conversionCode_post = conversionCode_post "\t\t\t" _arrayListVar ".add(" _arrayPaNa "[i]);" "\n"; - } - conversionCode_post = conversionCode_post "\t\t" "}" "\n"; - - retParamType = _arrListType; - retVar_out_m = _arrayListVar; - retType = retParamType; - } else { - # convert from an ArrayList - conversionCode_pre = conversionCode_pre "\t\t" "for (int i=0; i < _size; i++) {" "\n"; - if (_isF3) { - conversionCode_pre = conversionCode_pre "\t\t\t" "int arrInd = i*3;" "\n"; - conversionCode_pre = conversionCode_pre "\t\t\t" "AIFloat3 aif3 = " _arrayListVar ".get(i);" "\n"; - conversionCode_pre = conversionCode_pre "\t\t\t" _arrayPaNa "[arrInd] = aif3.x;" "\n"; - conversionCode_pre = conversionCode_pre "\t\t\t" _arrayPaNa "[arrInd+1] = aif3.y;" "\n"; - conversionCode_pre = conversionCode_pre "\t\t\t" _arrayPaNa "[arrInd+2] = aif3.z;" "\n"; - } else if (_isObj) { - conversionCode_pre = conversionCode_pre "\t\t\t" _arrayPaNa "[i] = " _arrayListVar ".get(i).get" _refObj "Id();" "\n"; - } else if (_isNative) { - conversionCode_pre = conversionCode_pre "\t\t\t" _arrayPaNa "[i] = " _arrayListVar ".get(i);" "\n"; - } - conversionCode_pre = conversionCode_pre "\t\t" "}" "\n"; - } - } - - firstLineEnd = ";"; - mod_m = ""; - if (!isInterface_m) { - firstLineEnd = " {"; - mod_m = "public "; - } - - sub(/^, /, "", thrownExceptions); - - print("") >> outFile_jni_m; - - isBuffered_m = !isVoid_m && isBufferedFunc(fullName_m) && (params == ""); - if (!isInterface_m && isBuffered_m) { - print(indent_m retType " _buffer_" memName ";") >> outFile_jni_m; - print(indent_m "boolean _buffer_isInitialized_" memName " = false;") >> outFile_jni_m; - } - - # print method doc comment - fullName_doc_m = fullName_m; - sub(/^[^_]*_/, "", fullName_doc_m); # remove OOAICallback_ - if (printIntAndStb_m) { - printFunctionComment_Common(outFile_int_m, funcDocComment, fullName_doc_m, indent_m); - printFunctionComment_Common(outFile_stb_m, funcDocComment, fullName_doc_m, indent_m); - } - printFunctionComment_Common(outFile_jni_m, funcDocComment, fullName_doc_m, indent_m); - - _fNoOverride = 0; - commentText = getFunctionComment_Common(funcDocComment, fullName_doc_m); - _fIsDeprecated = match(commentText, /@deprecated/); - printTripleFunc(retType, memName, params, thrownExceptions, outFile_int_m, outFile_stb_m, outFile_jni_m, printIntAndStb_m, _fNoOverride, _fIsDeprecated); - - isVoid_m = (retType == "void"); - - if (!isInterface_m) { - condRet_int_m = isVoid_int_m ? "" : retVar_int_m " = "; - indent_m = indent_m "\t"; - - if (isBuffered_m) { - print(indent_m "if (!_buffer_isInitialized_" memName ") {") >> outFile_jni_m; - indent_m = indent_m "\t"; - } - if (declaredVarsCode != "") { - print(declaredVarsCode) >> outFile_jni_m; - } - if (conversionCode_pre != "") { - print(conversionCode_pre) >> outFile_jni_m; - } - if (!ommitMainCall) { - print(indent_m condRet_int_m myWrapVar "." functionName_m "(" innerParams ");") >> outFile_jni_m; - } - if (conversionCode_post != "") { - print(conversionCode_post) >> outFile_jni_m; - } - if (isBuffered_m) { - print(indent_m "_buffer_" memName " = " retVar_out_m ";") >> outFile_jni_m; - print(indent_m "_buffer_isInitialized_" memName " = true;") >> outFile_jni_m; - sub(/\t/, "", indent_m); - print(indent_m "}") >> outFile_jni_m; - print("") >> outFile_jni_m; - retVar_out_m = "_buffer_" memName; - } - if (!isVoid_m) { - print(indent_m "return " retVar_out_m ";") >> outFile_jni_m; - } - sub(/\t/, "", indent_m); - print(indent_m "}") >> outFile_jni_m; - } -} - - -function doWrappMember(fullName_dwm) { - - doWrapp_dwm = 1; - - return doWrapp_dwm; -} - -# Used by the common OO AWK script -function doWrappOO(funcFullName_dw, params_dw, metaComment_dw) { - - doWrapp_dw = 1; - - #doWrapp_dw = doWrapp_dw && !match(funcFullName_dw, /Lua_callRules/) && !match(funcFullName_dw, /Lua_callUI/); - - return doWrapp_dw; -} - -function wrappFunctionDef(funcDef, commentEolTot) { - - size_funcParts = split(funcDef, funcParts, "(\\()|(\\);)"); - # because the empty part after ");" would count as part as well - size_funcParts--; - - fullName = funcParts[1]; - fullName = trim(fullName); - sub(/.*[ \t]+/, "", fullName); - - retType = funcParts[1]; - sub(/[ \t]*public/, "", retType); - sub(fullName, "", retType); - retType = trim(retType); - - params = funcParts[2]; - - wrappFunctionPlusMeta(retType, fullName, params, commentEolTot); -} - -# This function has to return true (1) if a doc comment (eg: /** foo bar */) -# can be deleted. -# If there is no special condition you want to apply, -# it should always return true (1), -# cause there are additional mechanism to prevent accidental deleting. -# see: commonDoc.awk -function canDeleteDocumentation() { - return isMultiLineFunc != 1; -} - - -# grab callback functions info -# 2nd, 3rd, ... line of a function definition -{ - if (isMultiLineFunc) { # function is defined on one single line - funcIntermLine = $0; - # separate possible comment at end of line: // fu bar - commentEol = funcIntermLine; - if (sub(/.*\/\//, "", commentEol)) { - commentEolTot = commentEolTot commentEol; - } - sub(/[ \t]*\/\/.*$/, "", funcIntermLine); - funcIntermLine = trim(funcIntermLine); - funcSoFar = funcSoFar " " funcIntermLine; - if (match(funcSoFar, /;$/)) { - # function ends in this line - wrappFunctionDef(funcSoFar, commentEolTot); - isMultiLineFunc = 0; - } - } -} -# 1st line of a function definition -/\tpublic .*\);/ { - - funcStartLine = $0; - # separate possible comment at end of line: // foo bar - commentEolTot = ""; - commentEol = funcStartLine; - if (sub(/.*\/\//, "", commentEol)) { - commentEolTot = commentEolTot commentEol; - } - # remove possible comment at end of line: // foo bar - sub(/\/\/.*$/, "", funcStartLine); - funcStartLine = trim(funcStartLine); - if (match(funcStartLine, /;$/)) { - # function ends in this line - wrappFunctionDef(funcStartLine, commentEolTot); - } else { - funcSoFar = funcStartLine; - isMultiLineFunc = 1; - } -} - - - -END { - # finalize things - store_everything(); - printClasses(); -} diff --git a/AI/Wrappers/JavaOO/bin/wrappEvents.awk b/AI/Wrappers/JavaOO/bin/wrappEvents.awk deleted file mode 100755 index d044b135740..00000000000 --- a/AI/Wrappers/JavaOO/bin/wrappEvents.awk +++ /dev/null @@ -1,627 +0,0 @@ -#!/usr/bin/awk -f -# -# This awk script creates a java class in OO style to wrap the C style -# JNI based AI Events wrapper interface. -# In other words, the output of this file wraps: -# com/springrts/ai/AI.java -# which wraps: -# rts/ExternalAI/Interface/AISEvents.h -# -# This script uses functions from the following files: -# * common.awk -# * commonDoc.awk -# * commonOOCallback.awk -# Variables that can be set on the command-line (with -v): -# * GENERATED_SOURCE_DIR : the generated sources root dir -# * JAVA_GENERATED_SOURCE_DIR : the generated java sources root dir -# * INTERFACE_SOURCE_DIR : the Java AI Interfaces static source files root dir -# * INTERFACE_GENERATED_SOURCE_DIR : the Java AI Interfaces generated source files root dir -# - -BEGIN { - # initialize things - - # define the field splitter(-regex) - FS = "(\\()|(\\);)"; - IGNORECASE = 0; - - # Used by other scripts - JAVA_MODE = 1; - - # These vars can be assigned externally, see file header. - # Set the default values if they were not supplied on the command line. - if (!GENERATED_SOURCE_DIR) { - GENERATED_SOURCE_DIR = "../src-generated/main"; - } - if (!JAVA_GENERATED_SOURCE_DIR) { - JAVA_GENERATED_SOURCE_DIR = GENERATED_SOURCE_DIR "/java"; - } - if (!INTERFACE_SOURCE_DIR) { - INTERFACE_SOURCE_DIR = "../../../Interfaces/Java/src/main/java"; - } - if (!INTERFACE_GENERATED_SOURCE_DIR) { - INTERFACE_GENERATED_SOURCE_DIR = "../../../Interfaces/Java/src-generated/main/java"; - } - - javaSrcRoot = "../src/main/java"; - - myParentPkgA = "com.springrts.ai"; - myMainPkgA = myParentPkgA ".oo"; - myPkgClbA = myMainPkgA ".clb"; - myPkgEvtA = myMainPkgA ".evt"; - myMainPkgD = convertJavaNameFormAToD(myMainPkgA); - myPkgEvtD = convertJavaNameFormAToD(myPkgEvtA); - - aiFloat3Class = "AIFloat3"; - - myOOAIClass = "OOAI"; - myOOAIInterface = "I" myOOAIClass; - myOOAIAbstractClass = "AbstractOOAI"; - myOOEventAIClass = "OOEventAI"; - myOOEventAIInterface = "I" myOOEventAIClass; - myOOAIFile = JAVA_GENERATED_SOURCE_DIR "/" myMainPkgD "/" myOOAIClass ".java"; - myOOAIInterfaceFile = JAVA_GENERATED_SOURCE_DIR "/" myMainPkgD "/" myOOAIInterface ".java"; - myOOAIAbstractFile = JAVA_GENERATED_SOURCE_DIR "/" myMainPkgD "/" myOOAIAbstractClass ".java"; - myOOEventAIFile = JAVA_GENERATED_SOURCE_DIR "/" myMainPkgD "/" myOOEventAIClass ".java"; - myOOEventAIInterfaceFile = JAVA_GENERATED_SOURCE_DIR "/" myMainPkgD "/" myOOEventAIInterface ".java"; - - printOOAIHeader(myOOAIFile, myOOAIClass); - printOOAIHeader(myOOAIInterfaceFile, myOOAIInterface); - printOOAIHeader(myOOAIAbstractFile, myOOAIAbstractClass); - printOOEventAIHeader(myOOEventAIFile); - printOOEventAIHeader(myOOEventAIInterfaceFile); - - ind_evt = 0; -} - - - -function printOOAIHeader(outFile, clsName) { - - printCommentsHeader(outFile); - print("") >> outFile; - print("package " myMainPkgA ";") >> outFile; - print("") >> outFile; - print("") >> outFile; - if (clsName != myOOAIInterface) { - print("import " myParentPkgA ".AI;") >> outFile; - } - if (clsName == myOOAIClass) { - print("import " myParentPkgA ".AICallback;") >> outFile; - print("import " myMainPkgA ".clb.WrappOOAICallback;") >> outFile; - print("import " myMainPkgA ".clb.WrappUnit;") >> outFile; - print("import " myMainPkgA ".clb.WrappWeaponDef;") >> outFile; - } - print("import " myMainPkgA ".AIFloat3;") >> outFile; - print("import " myMainPkgA ".clb.OOAICallback;") >> outFile; - print("import " myMainPkgA ".clb.Unit;") >> outFile; - print("import " myMainPkgA ".clb.WeaponDef;") >> outFile; - print("") >> outFile; - print("/**") >> outFile; - print(" * TODO: Add description here") >> outFile; - print(" *") >> outFile; - print(" * @author hoijui") >> outFile; - print(" * @version GENERATED") >> outFile; - print(" */") >> outFile; - - _type = "abstract class"; - _extends = ""; - _implements = " implements " myOOAIInterface ", AI"; - if (clsName == myOOAIAbstractClass) { - _extends = " extends " myOOAIClass; - } - if (clsName == myOOAIInterface) { - _type = "interface"; - _implements = ""; - } - print("public " _type " " clsName _extends _implements " {") >> outFile; - print("") >> outFile; - - if (clsName == myOOAIClass) { - print("\t" "private AICallback clb = null;") >> outFile; - print("\t" "private OOAICallback clbOO = null;") >> outFile; - print("") >> outFile; - } -} -function printOOAIEnd(outFile) { - - print("}") >> outFile; - print("") >> outFile; -} - -function printOOEventAIHeader(outFile) { - - printCommentsHeader(outFile); - print("") >> outFile; - print("package " myMainPkgA ";") >> outFile; - print("") >> outFile; - print("") >> outFile; - print("import " myParentPkgA ".AI;") >> outFile; - print("import " myMainPkgA "." myOOAIClass ";") >> outFile; - print("import " myPkgEvtA ".*;") >> outFile; - print("import " myPkgClbA ".*;") >> outFile; - print("") >> outFile; - print("/**") >> outFile; - print(" * TODO: Add description here") >> outFile; - print(" *") >> outFile; - print(" * @author hoijui") >> outFile; - print(" * @version GENERATED") >> outFile; - print(" */") >> outFile; - if (outFile == myOOEventAIFile) { - print("public abstract class " myOOEventAIClass " extends " myOOAIClass " implements " myOOEventAIInterface ", AI {") >> outFile; - } else { - print("public interface " myOOEventAIInterface " {") >> outFile; - } - print("") >> outFile; - - print("\t" "/**") >> outFile; - print("\t" " * TODO: Add description here") >> outFile; - print("\t" " *") >> outFile; - print("\t" " * @param event the AI event to handle, sent by the engine") >> outFile; - print("\t" " * @throws AIException") >> outFile; - print("\t" " */") >> outFile; - _modifyer = ""; - if (outFile == myOOEventAIFile) { - _modifyer = " abstract"; - } - print("\t" "public" _modifyer " void handleEvent(AIEvent event) throws EventAIException;") >> outFile; - print("") >> outFile; -} -function printOOEventAIEnd(outFile) { - - print("}") >> outFile; - print("") >> outFile; -} - - -function convertJavaSimpleTypeToOO(paType_sto, paName_sto, - paTypeNew_sto, paNameNew_sto, convPre_sto, convPost_sto) { - - _change = 1; - - # uses this global vars: - # - paramTypeNew - # - paramNameNew - # - conversionCode_pre - # - conversionCode_post - - paramTypeNew = paType_sto; - paramNameNew = paName_sto; - - if (match(paName_sto, /_posF3/)) { - # convert float[3] to AIFloat3 - sub(/_posF3/, "", paramNameNew); - paramTypeNew = "AIFloat3"; - conversionCode_pre = conversionCode_pre "\t\t" paramTypeNew " " paramNameNew " = new " paramTypeNew "(" paName_sto ");" "\n"; - #conversionCode_pre = conversionCode_pre "\t\t" paType_sto " " paName_sto " = " paNameNew_sto ".toFloatArray();" "\n"; - } else if (match(paName_sto, /_colorS3/)) { - # convert short[3] to java.awt.Color - sub(/_colorS3/, "", paramNameNew); - paramTypeNew = "java.awt.Color"; - conversionCode_pre = conversionCode_pre "\t\t" paramTypeNew " " paramNameNew " = Util.toColor(" paName_sto ");" "\n"; - #conversionCode_pre = conversionCode_pre "\t\t" paType_sto " " paName_sto " = Util.toShort3Array(" paNameNew_sto ");" "\n"; - } else if ((paType_sto == "int") && match(paName_sto, /(unit|builder|attacker|enemy)(Id)?$/)) { - # convert int to Unit - sub(/Id$/, "", paramNameNew); - paramNameNew = "oo_" paramNameNew; - paramTypeNew = "Unit"; - conversionCode_pre = conversionCode_pre "\t\t" paramTypeNew " " paramNameNew " = Wrapp" paramTypeNew ".getInstance(this.clb, " paName_sto ");" "\n"; - } else if ((paType_sto == "int[]") && match(paName_sto, /unit(s|Ids)$/)) { - # convert int[] to List - sub(/(Id)?s$/, "s", paramNameNew); - paramNameNew = "oo_" paramNameNew; - paramTypeNew = "java.util.List"; - conversionCode_pre = conversionCode_pre "\t\t" paramTypeNew " " paramNameNew " = new java.util.ArrayList();" "\n"; - conversionCode_pre = conversionCode_pre "\t\t" "for (int u=0; u < " paName_sto ".length; u++) {" "\n"; - conversionCode_pre = conversionCode_pre "\t\t\t" paramNameNew ".add(WrappUnit.getInstance(this.clb, " paName_sto "[u]));" "\n"; - conversionCode_pre = conversionCode_pre "\t\t" "}" "\n"; - } else if ((paType_sto == "int") && match(paName_sto, /(weaponDef)(Id)?$/)) { - # convert int to WeaponDef - sub(/Id$/, "", paramNameNew); - paramNameNew = "oo_" paramNameNew; - paramTypeNew = "WeaponDef"; - conversionCode_pre = conversionCode_pre "\t\t" paramTypeNew " " paramNameNew " = Wrapp" paramTypeNew ".getInstance(this.clb, " paName_sto ");" "\n"; - } else if (paType_sto == "AICallback") { - # convert AICallback to OOAICallback - paramNameNew = "oo_" paramNameNew; - paramTypeNew = "OOAICallback"; - conversionCode_pre = conversionCode_pre "\t\t" "this.clb = " paName_sto ";" "\n"; - conversionCode_pre = conversionCode_pre "\t\t" "this.clbOO = Wrapp" paramTypeNew ".getInstance(" paName_sto ");" "\n"; - conversionCode_pre = conversionCode_pre "\t\t" paramTypeNew " " paramNameNew " = this.clbOO;" "\n"; - } else { - _change = 0; - } - - return _change; -} - - -function printEventsOO() { - - # agarra te los event interfaces - for (e=0; e < evts_size; e++) { - meta_es = evts_meta[e]; - - interfList_size_es = 0; - if (match(meta_es, /INTERFACES:/)) { - interfMeta_es = meta_es; - sub(/^.*INTERFACES:/, "", interfMeta_es); - sub(/[ \t].*$/, "", interfMeta_es); - interfList_size_es = split(interfMeta_es, interfList_es, /\),/); - - for (i=1; i <= interfList_size_es; i++) { - _intName = interfList_es[i]; - sub(/\(.*$/, "", _intName); - _intParams = interfList_es[i]; - sub(/^.*\(/, "", _intParams); - sub(/\)$/, "", _intParams); - - if (!(_intName in int_names)) { - int_names[_intName] = _intParams; - } - evts_intNames[e "," (i-1)] = _intName; - evts_intParams[e "," (i-1)] = _intParams; - } - } - evts_intNames[e ",*"] = interfList_size_es; - } - - # print the event classes - for (e=0; e < evts_size; e++) { - printEventOO(e); - } - - # print the event interfaces - for (intName in int_names) { - printOOEventInterface(intName); - } -} - -function printEventOO(ind_evt_em) { - - retType_em = evts_retType[ind_evt_em]; - name_em = evts_name[ind_evt_em]; - params_em = evts_params[ind_evt_em]; - meta_em = evts_meta[ind_evt_em]; - - paramsList_size_em = split(params_em, paramsList_em, ", "); - - conversionCode_pre = ""; - conversionCode_post = ""; - ooParams_em = ""; - - for (p=1; p <= paramsList_size_em; p++) { - _param = paramsList_em[p]; - _paramType = _param; - sub(/ [^ ]*$/, "", _paramType); - _paramName = _param; - sub(/^[^ ]* /, "", _paramName); - - paramTypeNew = ""; - paramNameNew = ""; - convertJavaSimpleTypeToOO(_paramType, _paramName); - - if (!match(_paramName, /_size$/)) { - ooParams_em = ooParams_em ", " paramTypeNew " " paramNameNew; - } - } - sub(/^, /, "", ooParams_em); - - _equalMethod = (ooParams_em == params_em); - _isVoid = (retType_em == "void"); - if (_isVoid) { - _condRet = ""; - } else { - _condRet = "_ret = "; - } - - print("") >> myOOAIFile; - - if (!_equalMethod) { - ooParamNames_em = removeParamTypes(ooParams_em); - print("\t" "@Override") >> myOOAIFile; - print("\t" "public final " retType_em " " name_em "(" params_em ") {") >> myOOAIFile; - print("") >> myOOAIFile; - - if (!_isVoid) { - print("\t\t" retType_em " _ret;") >> myOOAIFile; - print("") >> myOOAIFile; - } - if (conversionCode_pre != "") { - print(conversionCode_pre) >> myOOAIFile; - } - - print("\t\t" _condRet "this." name_em "(" ooParamNames_em ");") >> myOOAIFile; - - if (conversionCode_post != "") { - print(conversionCode_post) >> myOOAIFile; - } - if (!_isVoid) { - print("") >> myOOAIFile; - print("\t\t" "return _ret;") >> myOOAIFile; - } - - print("\t" "}") >> myOOAIFile; - } - - printFunctionComment_Common(myOOAIFile, evts_docComment, ind_evt_em, "\t"); - print("\t" "@Override") >> myOOAIFile; - if (retType_em == "int") { - print("\t" "public " retType_em " " name_em "(" ooParams_em ") { return 0; }") >> myOOAIFile; - } else { - print("Warning: No default return value given for event return-type " retType_em); - print("\t" "public abstract " retType_em " " name_em "(" ooParams_em ");") >> myOOAIFile; - } - - ooParamsCleaned_em = ooParams_em; - gsub(/ oo_/, " ", ooParamsCleaned_em); - - print("") >> myOOAIInterfaceFile; - printFunctionComment_Common(myOOAIInterfaceFile, evts_docComment, ind_evt_em, "\t"); - print("\t" "public " retType_em " " name_em "(" ooParamsCleaned_em ");") >> myOOAIInterfaceFile; - - print("") >> myOOAIAbstractFile; - printFunctionComment_Common(myOOAIAbstractFile, evts_docComment, ind_evt_em, "\t"); - print("\t" "@Override") >> myOOAIAbstractFile; - print("\t" "public " retType_em " " name_em "(" ooParamsCleaned_em ") {") >> myOOAIAbstractFile; - print("\t\t" "return 0; // signaling: OK") >> myOOAIAbstractFile; - print("\t" "}") >> myOOAIAbstractFile; - - printOOEventWrapper(retType_em, name_em, ooParamsCleaned_em, meta_em, ind_evt_em); -} - -function printOOEventWrapper(retType_ei, mthName_ei, ooParams_ei, meta_ei, ind_evt_ei) { - - outFile = myOOEventAIFile; - ooParamsNoTypes_ei = removeParamTypes(ooParams_ei); - evtName_ei = capitalize(mthName_ei) "AIEvent"; - - print("\t" "@Override") >> outFile; - print("\t" "public final " retType_ei " " mthName_ei "(" ooParams_ei ") {") >> outFile; - print("") >> outFile; - print("\t\t" "AIEvent evt = new " evtName_ei "(" ooParamsNoTypes_ei ");") >> outFile; - print("\t\t" "try {") >> outFile; - print("\t\t\t" "this.handleEvent(evt);") >> outFile; - print("\t\t\t" "return 0; // everything OK") >> outFile; - print("\t\t" "} catch (EventAIException ex) {") >> outFile; - print("\t\t\t" "return ex.getErrorNumber();") >> outFile; - print("\t\t" "}") >> outFile; - print("\t" "}") >> outFile; - print("") >> outFile; - - printOOEventClass(retType_ei, evtName_ei, ooParams_ei, meta_ei, ind_evt_ei); -} - -function printOOEventClass(retType_ec, evtName_ec, ooParams_ec, meta_ec, ind_evt_ec) { - - outFile = JAVA_GENERATED_SOURCE_DIR "/" myPkgEvtD "/" evtName_ec ".java"; - - ooParamsList_size_ec = split(ooParams_ec, ooParamsList_ec, ", "); - int_size_ec = evts_intNames[ind_evt_ec ",*"]; - - # list up interface parameters - # clear arrays - split("", intParams_toPrint_ec); - split("", myIntParams_intParams_ec); - split("", myIntParams_int_ec); - for (_ii=0; _ii < int_size_ec; _ii++) { - _name = evts_intNames[ind_evt_ec "," _ii]; - _myIntParams = evts_intParams[ind_evt_ec "," _ii]; - _intParams = int_names[_name]; - - _myIntParamsList_size = split(_myIntParams, _myIntParamsList, ","); - _intParamsList_size = split(_intParams, _intParamsList, ","); - - for (_p=1; _p <= _intParamsList_size; _p++) { - _myIntParam = _myIntParamsList[_p]; - _intParam = _intParamsList[_p]; - - intParams_toPrint_ec[_intParam] = 1; - myIntParams_int_ec[_myIntParam] = _name; - if (_myIntParam != _intParam) { - myIntParams_intParams_ec[_myIntParam] = _intParam; - } - } - } - - _addIntLst = ""; - for (i=0; i < int_size_ec; i++) { - _addIntLst = _addIntLst ", " evts_intNames[ind_evt_ec "," i] "AIEvent"; - } - - # print comments header - printCommentsHeader(outFile); - print("") >> outFile; - - print("package " myPkgEvtA ";") >> outFile; - print("") >> outFile; - print("") >> outFile; - - # print imports - print("import " myMainPkgA ".AIEvent;") >> outFile; - print("import " myMainPkgA ".AIFloat3;") >> outFile; - print("import " myPkgClbA ".*;") >> outFile; - print("") >> outFile; - - # print class header - printFunctionComment_Common(outFile, evts_docComment, ind_evt_ec, ""); - print("public class " evtName_ec " implements AIEvent" _addIntLst " {") >> outFile; - print("") >> outFile; - - # print member vars - for (_p=1; _p <= ooParamsList_size_ec; _p++) { - print("\t" "private " ooParamsList_ec[_p] ";") >> outFile; - } - print("") >> outFile; - - # print constructor - print("\t" "public " evtName_ec "(" ooParams_ec ") {") >> outFile; - print("") >> outFile; - for (_p=1; _p <= ooParamsList_size_ec; _p++) { - _name = extractParamName(ooParamsList_ec[_p]); - print("\t\t" "this." _name " = " _name ";") >> outFile; - } - print("\t" "}") >> outFile; - print("") >> outFile; - - # print member getters - for (_p=1; _p <= ooParamsList_size_ec; _p++) { - _type = extractParamType(ooParamsList_ec[_p]); - _name = extractParamName(ooParamsList_ec[_p]); - - # save the type for later writing of interfaces, - # in case it is a ninterface param - if (_name in intParams_toPrint_ec) { - _intName = _name; - if (_name in myIntParams_intParams_ec) { - _intName = myIntParams_intParams_ec[_name]; - } - _int = myIntParams_int_ec[_name]; - - int_name_param_type[_int "," _intName] = _type; - # hacky - int_name_param_type[_int "," _name] = _type; - } - - # print out @Override if this is an interface member - if (_name in intParams_toPrint_ec && intParams_toPrint_ec[_name] == 1) { - print("\t" "@Override") >> outFile; - intParams_toPrint_ec[_name] = 0; - } - - print("\t" "public " _type " get" capitalize(_name) "() {") >> outFile; - print("\t\t" "return this." _name ";") >> outFile; - print("\t" "}") >> outFile; - - # print out another getter if the interface param name is different - if (_name in myIntParams_intParams_ec) { - _intName = myIntParams_intParams_ec[_name]; - intParams_toPrint_ec[_intName] = 0; - - print("\t" "@Override") >> outFile; - print("\t" "public " _type " get" capitalize(_intName) "() {") >> outFile; - print("\t\t" "return this.get" capitalize(_name) "();") >> outFile; - print("\t" "}") >> outFile; - } - - print("") >> outFile; - } - - print("}") >> outFile; - - close(outFile); -} - -function printOOEventInterface(int_name_ei) { - - outFile = JAVA_GENERATED_SOURCE_DIR "/" myPkgEvtD "/" int_name_ei "AIEvent.java"; - - int_params_ei = int_names[int_name_ei]; - - int_paramsList_size_ei = split(int_params_ei, int_paramsList_ei, ","); - int_size_ei = evts_intNames[ind_evt_ec ",*"]; - - _addIntLst = ""; - for (i=0; i < int_size_ei; i++) { - _addIntLst = _addIntLst ", " evts_intNames[ind_evt_ec "," i] "AIEvent"; - } - - # print comments header - printCommentsHeader(outFile); - print("") >> outFile; - - print("package " myPkgEvtA ";") >> outFile; - print("") >> outFile; - print("") >> outFile; - - # print imports - print("import " myMainPkgA ".AIEvent;") >> outFile; - print("import " myMainPkgA ".AIFloat3;") >> outFile; - print("import " myPkgClbA ".*;") >> outFile; - print("") >> outFile; - - # print class header - print("public interface " int_name_ei "AIEvent extends AIEvent {") >> outFile; - print("") >> outFile; - - # print getters - for (_p=1; _p <= int_paramsList_size_ei; _p++) { - _name = int_paramsList_ei[_p]; - _type = int_name_param_type[int_name_ei "," _name]; - - print("\t" "public " _type " get" capitalize(_name) "();") >> outFile; - } - print("") >> outFile; - - print("}") >> outFile; -} - - - -# This function has to return true (1) if a doc comment (eg: /** foo bar */) -# can be deleted. -# If there is no special condition you want to apply, -# it should always return true (1), -# cause there are additional mechanism to prevent accidental deleting. -# see: commonDoc.awk -function canDeleteDocumentation() { - return 1; -} - -################################################################################ -### BEGIN: parsing and saving the event methods - -# beginning of struct S*Event -/^\tpublic .+\);/ { - - _head = $1; - _params = $2; - _tail = $3; - - _retType = _head; - sub(/^\tpublic /, "", _retType); # remove pre - sub(/ .*$/, "", _retType); # remove post - - _name = _head; - sub(/^\tpublic [^ ]+ /, "", _name); # remove pre - - _meta = $0; - _hasMeta = sub(/.*\);[ \t]*\/\/[ \t]*/, "", _meta); # remove pre - if (!_hasMeta) { - _meta = ""; - } - - evts_retType[ind_evt] = _retType; - evts_name[ind_evt] = _name; - evts_params[ind_evt] = _params; - evts_meta[ind_evt] = _meta; - storeDocLines(evts_docComment, ind_evt); -#print(_retType " " _name "(" _params ") // " _meta); - ind_evt++; -} - -### END: parsing and saving the event methods -################################################################################ - - - - -END { - # finalize things - - evts_size = ind_evt; - - printEventsOO(); - - printOOAIEnd(myOOAIFile); - printOOAIEnd(myOOAIInterfaceFile); - printOOAIEnd(myOOAIAbstractFile); - printOOEventAIEnd(myOOEventAIFile); - printOOEventAIEnd(myOOEventAIInterfaceFile); - - close(myOOAIFile); - close(myOOAIInterfaceFile); - close(myOOAIAbstractFile); - close(myOOEventAIFile); - close(myOOEventAIInterfaceFile); -} diff --git a/AI/Wrappers/JavaOO/jlib/vecmath-src.jar b/AI/Wrappers/JavaOO/jlib/vecmath-src.jar deleted file mode 100644 index 4f66594635f784da70817fee98ebc6bb52db0d5e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 183017 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%0DqRNwh+>h1nLb1k)uYG&jotYyuUgY-9d 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

~$9-_LL;s_CJzdidj86~|=WrK@9 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%0DS~Nj{|5_2uNK_joS(Ay8~=U}Kr*b_+n2ln($a zP4f}}UIu_utEiSH`L)!ev9Fd}rwRq7%1Gtl@EX$g>ns$cG#HH^i0h#O;d&?xi1oD~ z#0sTyK)eHpZvf((fEb73z=4Pac87(8CR@o46-h?_1@)`>6${!AB%T0()OI z+*3uD118q!HZQPu0rne!{TE=Elzd<_AWh>2Vq!V=v3R$NXG}t1pD~r)s$3c?du6w3 z($AQrv$CseSu4Bw3tv0Mgivb%n)<|W91~KZW5PWgAPQ1K?4C3^J&>mdGNfwrV}`{pZDsJ&t0Jr`QuHmI!f#FB(Vy{Gr}@ifyLY7K%M897!aDsS^e= zZdY|=WF3sxB(u9As)Hn|gPy1kRI|a1zsqOYG&S&`#$Z_&-NUL%H}?TGcnJY|DL&el zX$3jv?S+anpyEs@IEy+w7YfcpN4S;t55GOo2XTaxRz|EF*EuY1K{CvJ2 zK7SZKKR~Z^t~=^M>8AH?GQHO_wDgEf@7?`gZf8ZDIN~^QRG^RW%nZJcnVFfU_ru<- z-?J}ajQ$EpkP|j!ZE0OBfp20J1Ii>_4%cOJ!W>b}fHASsOwsRDU8YrTD;j3a znkC_-+Jy(oE?Gmc9J_3ii;&P!1~$xrmiI zpOAKtZtzr>gcXTY!&35lmW0J+fcCi-bx%i4As=)cwnO*y;S3mu<|{ve9T-I=tP~xM zWBUHDl&p}Qv~w@Urlg+CcXd{V!su&zprk0dqf2(8X6!GO!>{IF&Db8JD*9}`*IZd^ zJ-0*2p|L+P2iz)L6YKzA&JW=( z;{4>mn+Lr4I5IAvhb{!~MHZeM!31xvKh*XQe9F`1D$N|_c|aZm$W@4xt6|I<7@+-x zG*KUjK> zXCNe<3ASg^Amm@}q%5&AP^I?H7L;_K$wmk2QUs>U5ST8fRb2t7Mk}yofU*|6U=Fu+ zoFCMUfcgNSZUWTJ7F5t+Lh3LT7i%mIr4K>fJy3Tq)ZGW~n-F(gLs>?xmO-WUij(&A z9_zPf-E-Z_)yAwyU%A@48%BMqGl=_c!|mfddBVaT<-^|W!yeCixO3WiSW0PsJ*=g% zjh>laK(I6xmRcG&vHYs>%X0KQ&wTX)Z(rig%e-+Ck60|>O>N6s^VD9-&Inpkm&!9P zP;q+NrOO!?IEUP*`Mk-840v1xD18?1qFKBfO|^S8i+3fTzIC$g_dw|TG{YbAbUaUE zWevrQZ++DOQq@1?+#r~t28?+%`PQ(r|F0HnA6b;B+MB!dwqMBE@$iF&g52#==;6Q z1-e|Q%SF0eESxS$m`f81zhAFijF%_O6$x`?sf&Xpzc~A%3)OF^M&-zc{lL+ACA=gRoW;$7)=K}3t&z}Yw?;EM~7U`%)+b+0h&>X6Ks) zY_dwR$LfYdUDVRf53s0RVU9_$&Y78Fkux)4ZcH)7-jw3xV5}Fb%q%_Ta)K-iCn%Qw zDQ5lufJJZ?v#k%X;%I2k=b@V(itXMk<^WlEC+Pw9eD-4ch}pHE7TqIQ9BDP82~#T) z&Er~hYd4#IX?Xl<>!x!;n#kQz%b`r1Ms(Ty@(eW%qCooS>WLZ1O zg3^X8fy!QWv;9*h41Tog=BL~(6C-#>0`DlM(xX{*PiNIV!@`^F!<*|bIZIe|MtNw2tmW6U4xMWE%Lu>aRcaV9Q0iTLbuG?2P#3arx(IYG zrX^ltQ3|-O-B$wDPoNISaR==hc(f15*RsCTo}y`X-=BCS(NEBPNhH`{>Ld|=pJ{~E zZM5#&;WZj6wuuT(4uQobkq8t@FwPV1!Y0u=yGhh}WC^9vQ_b>9y33Y89FgLb8{4$( z(wv*L=H-a}7)|R*^wdw$mE}ouWQe37i`a(3`&jkHN)`DaKM&*=fczqmwT<*>`kSlY zT%5P04v@bAL*Naz)Ctnqz(40S|e9E*xUKp+cpk$VD2ih>}W2+6c<#`&F=k}%!^m?ON?*kKN zTLp=VXhdie6FN5zf6i1MKk5?(vrlzIv)hDzO`+$M`H9U3?3!eOs;_ zxp}c0i8JXa{4+=687BJ%s~{i#68I@;cH(m;iTIi7*6A5Ag}H3{?AFDlu}_8Ra;4cF z%4X4SPCKH(z-mXZpLonMQWJ^pll;1xDAQ5*V83qLUyyNjKvHwuB4UlSFK`{@Ro*w-MIru2RneZ8`zEp8M}7*m>s@UPft=R z%2mX%7#EJW;FtQ~bwr84PeRGiD^xNBWoR%XZOb5Co>4}iXV9vn4iKZ6A%o&sGuDw^HCT8*xGWyP0Au_}vsxRdC~PKx(lJmi~en%AKY{T(C#?5Q;lVDDFX+ zT1H}OndMz*mSSpYVVi4Lma!`te}&>OziC%D4%t_~k2B(XXE$rkKEbLIG;7wyK2Lw{ z6L-bGZo9A`mxnu4%l*B@<>8KAp18fmk%mq5FJl2>2pL|D0jCB7PCpDdgK!qD$60ig zcQ1R3?_+QA{kX?|n7zdhu(x!FxCPCEffLjOV1UKU(>S(w2GO`@vz2zSr|<`B z3Q^WKo3igf*>^+Akc#qB7VLS>p)7cjLs{^m7-c_$vY$g48*T9$?d|;v%6<)H??Tyc zpzL>0_TNzUdno$@l>HgX)`s)zJZelc_h7q@dDh5Qtt6wDyqWAAYm?ctPOQu%W96nN z+hzyF61LwQ>$iiU{?J%u`^__^e-^u9olRw|CS(_KqtCAWGy_dn>og{WZ5wtS-0o|Q zhvC<-PG8$rVmCjh5n`K0j4+9~pLUM*F@0iv&4AcprXehMSWKb*)B!yie>9pMeR8ea0M?P3ky&TgQi_A|3mrF8BM2U5Tm%r)|s*?i5WW zFWz=+jS-|fHqG=Sc6B3htJPfd<1`=}r@7!XFT@F9Jugnd_Hb)ojy8*1oPu|0ymUA% z1E=NSv;v$~g45b?>7|CIDQU33ecU!QfCUXraPv2`<7sFo(9lk#p`8TG6L4B|1CAP+ z29B!6rjbM8{=jTXTWDw-LrT#|_>`_gL{LMUTG}>rKUcZkneGmQjY@Kaci;=X17GOV zXf!)5k|+B}Mx$a=Jva`EzO*xP>`ar0ot1{84z|INB}j2iVo_=i-EDEsO2Z zzfnmJ$4kKRQgFNs951I7^fG=~>AL#C($&|qSQ;AX>W7d|vxn8y6L2~nyO}n0D^Htw z8Z#R*b@d~9P2bwJmX#iVg>?1Vo89+Tla(-mUCl~ej?raR6(jH(UDoPyY(fD7E6s{Z z#R#l4C+MOmft898SgB(jPf6GyfoXdB4W>oGmNp6e=7f!prm$Hn5~ej_wg086-RC}1 z`L}a#+;i{6swk$cKIA>{VN~MbX0$>F z*5e=)(6OvT%yvEDGK^zRiu+agN4OGoF;qp5K~y|MzY4UnMODxVb6U#mG`kXJ zcgkRhBX%eY`2X{M7I{_7=+m_u{?Jv-#dfwAQ!y9XV_#6g>~_OD%rPyB@3%~N3aPA2sxXbkF7@`$rz1EULL)}Fqx$^0kyEDrOlD19> zQnr3MZBMsOM9l+Fv2%__zdRj{%?!qQt;C00)wtjtgjYv|qKk)~LL%oB4j3cBc{onS z4#iyka56MAQ>Fuc;8|AHIyjfH zAi5kHuRyPRrNu-R4`C8|m{=hukYEDwC4*%SRJL2lxUf1i^o@#p;7kQ1@>QjS_Cc8c zA==wL^qhM^YldgvwC-h0#!%bRib4b2IoBb@R+RxEiKW`xiND6YM z64*ixl)x5ppajkb`7I#74dgEa`71!4L<@8En~SrJ03b0{I4c5x6;y>YH#s=FBQ^Wr zU^3kNz(OvJvxOYsY#|3Y=Y#wo;QUK){!bwP3do0tL(L3$A#PX;NM^7Biz`6`a`5~E z4e5_GhCk7eB&Hu8jt7FKUhEXt8IcF9;yMpB&qFZ~Gu^y0&c7-Lnsa+s8<_340ru>} zvaB!!_E|Y`1+vleYS0>WLC@S3HDxyoP%6;?pokq{Z5CNU39RB;&vF3v17Lpu9tOYx z0Gx`g#sNGA3^lfl_A!)Z$hIaS9EB+Gag`P*PmA)JP;rd}_9#?aqb+>dr-ZQJs}}%Y zV_~7F1@^5ytT!+GslcBGd`^$@WMpyXA;FglQSd{ZEujEHovj}t!0IeBLIeQ9>1?}@ zQfGEL+eK({mRRuec@+4-d0#r)uA$C0C_^j?%21ccC?j2G+XYb4+3J9YaP07oLuY$D zI@=Rb9!X%H&P3{py%MTaE60mx(nRNtG@uDZU9-?jOLyLvzMfX7I6dul8b~`%y*ton zorXL7F1GIPHphCWgV0Q?w-7f@VS*8}CugeS?M9AB7oT=3WqkJ54i)OO@t2^Dcd-r! zvUPt9TlWK#iVFL_&x7;TB*UHT=&1e~p$ycJLzv|bX1TVm+wcfH$kJ~LX{XV>h0cB} zTEN?I$-kYArgxwPypwkGL4qE9h@c1ez`1+T>fT4tgZl}3u-}~QJ;+Ih51DqfySvct zo{n}`T3zir54y=seluR8VIsuC>M!+#i9>BId|~yMdcuIrPZs8Sk}(K4&Fm+^{8M25 z9Qw;oqrZF+%wM9uUk3Zn&;&n+{_^u?hW7>ZmtRDGsV)EW3SbxnN65i2c#(r)@WS%8 z0EX{?;WxmLODf=N}RVYeRC`vn_C?zU3>fMtGim0{} z%n{3dKG-EpSV&fI24NJwOGCh}JNS|UB=UxS)Qp$eC~@E zUbmWQN`HkkiP_N~n&oCYw~Ce7JYDANf>+!^?a`TQLq5a}`+MR#aAawvS*GOjgfxN* z_K>DJ#Ihw&;SnW0w2kMuggKs_^QCGHfB&^FZh7>PyN~m=hJFZ$EUn?f_Z0_X!lA^0 z;G?{1ze9-w;UiFT9Ejp&A6T^+DhB^)aUgsOO3>!HnmPo}&>$Yf5W|re1I$33*uiD6 z8F&EInvKwKBGYxGT4Tp-j`OJVXZ$Awg>Vj=DXp*m2dLBzU2XP0fApISU)>F^(RH;k@i%7_LnN;cK}bM9FuA+TLqSHW79BlIThG=N|}J%xV%I?IT8KTCnW`~l+eFx|S+PqLMIvo4n4mZ%M0AKojg0`=7_uu}rBsYn z4o-BQMh_bdvN2>+i7KTCrRZ#pI;-Vs%0ret+j}qtx8u5*Q8fmp$Y6Q6o6&nE{P^c)FK&VjRCasA%zTL@`dKVqz zZipnv7?8C!Er6`mZsfgaAqNT-3pr4zj$8p9Zo5OpY#svxOYsY#|3Y=Y#wrkY57w%RpAdNjBm8IAG6Gmw z{_-RT&sXUkuhGt5XV{UK<(ROaWh#L(qFGoaP(Em11KQVt_72b#i_-1SQcXolpgf^1 zY>YI z9;!F^I}e3(p^bq$TRYeosB&D)3{EEY2H_Pq1ZwJ0ehkBkr>V%rw@}$@SuR_yN!!vT zEoO#GD`rOUygXaUqH>&)WfDr3!;z^cqpvuEz;sinnQ17{T+MvTp9jvAk|hYHfOz}9 zV`!+61n|loymDeE*eDd-XQ@|&u2ZkfCF;REd|2lbr(ppKDHr6T!CMM@mJzFAIpY5c zVr{G>*2Xc!+E`imMI0Jo}q9p_k@CLsc7gA3L6@x?dnt`?+ zWb`ekTiFcSTR{6%oJ(6leH*LI?Sz4NKJ9on{mXxoN*SAyPEptle7t_8j8K<|3c(dMCdNW;Wc(1UQ`Avo|b)IUPI`UuoNj#}xXw5cahcs|7<{Nu!pc-kD}J%i$tFdDR< zV8lHRY~5t*+D{aKBq-48Jc66F(w%zsB}#vp(qAE#2R0qlY=cp=4M)wUW{|&>yg@=N zjsBaQQr@PNFH_1_DdlUF@(!hZgHlkZQJcXcGF!=FYZJIAS!`{p2%AiUZxG(S+KA)0ml)sf>8@ zTTk3Fx{~>VzXHmLiP?cf&@S{)_>dYiS(hVpnWD?ogqfxz+7Bmyh<*tnQelp+G}9~1 z3?*kK6mW934IyF`5A%p0QZ4ZyVYL|v1+nO|Ytzow=51>??cCMc(Y|IOeg+JX-PuXg84bOuz9w;73goFU zLm*c?XDS$56Ws_aQpHdmbCE`>wVc(xABiNqw=pExCltJo2l-Rvf5vojo+qjn=XtW5 zxuPkof^eItlc=*IlQdOOVB8N-A`ni^auI^{#Sn4{t?N?wqcbd>kS;lC& zcu7wCb08ms0Uv<@kHdhE!T`k@8D%{T!~pq@Ygs=@wI^inLDHt;)cTxYVePg~u!yS- zrVAFf5h!3`XHw$1wOpI$c=CcRM%%Jf%xQixMr# zNv&d?)GF3VZ5ZpMR!kLd5bNZHx>aBJK--Lu`%4$CZ~Q=LSxXn< zoxGobCliYWJelbGLN{3dYa0UXz{j@(F`t3OFX-ToZ}&ecIp9h0vI|7@@C!M}fG43X zCcj6!fEHP}m3H(yK-|&q2kWHmlT;|+iT}C;tB*U;?hrznP(*=NP$Z;D;g5=hG~uHn zUgEqx#E>QvgODZ@%+#!qCR&E(iEEb;oO)QB zku;ZA@!QufXNPO4tOM6w^o+*3M7W?moJ?+YKbZyX5qva-g~L=PsA)Wx&T#^Z1-HW~ zdv%{1PlMGJ593a7h(PO{=6S5{=d%V`!0H|iq1`J!!MZ95-<9BdkgNL${4s#f3@uoX z?M#@C560D$aqtl4bE#;CD64;%itI@3SD~0Vn(x`dl4U z+5%n`=D^;<0{&L8ybY3Xr!CxJ!3LETG_#=sTY5z~(D%c!57W#ZV0pNoRW)v3wBm>f zE?7!`Cmdx3OL4-HA2TJw_G2*NNto~yO!zoVc-n%@VM1xbQ3MtRBUZ64SjFnhD=^`+ zfISM;qT}t!RHhR-V1hk^yd{u#B?)j7S@gJZlCPuzZsJk@b4+=Ymirdn`E6vcFVnof zVv7nWP*Li8ldOZXinB!pCO%tKVB)hyabty?d_{emqP{~>_yC&kQIyU}o?e8iE$LKo z6H&!YL=`tVRAu^?PsC8Bq6$-GiwdZ+MFmvZq5`V&74;{m`ZHAh1*+bIs=rdyjIgMT z23sHwi`sI0Z!Q&H90$q@Jkb+)qE`}XKzlo9grkZ;Yg8F(cLwu)Oo=iQW!9`oqFjl* zpt}OP8=$)bx)#tq0PPgOZpd{Tghv#Q&|=@l39S;(YE|Aq9FPa$p*|Q5AU+gcy#+tp zZ@?@420X&Hs)F%a^fs=yIp9YFehlEp0-lXE-gv;zvHB)q-wJpMUo#IjdW%nwqPgVj zE8fxATc(?V-VAIkGqJ7Avc*bSredQF%QlRIAIn9ZI&eo%5Zrw}_r`uV%jd=>kS*ug zQ3n;v#b%Bxv`b!8*I->;3wMsi9(f#*DdcVF&YBXcX@PJ{5AWiKeTnCUdJ&0MzV})v zWswaercxA)SL4(aDGfAs5CladVGw{tj{R0S;s;8x14l-n6u>d|peRu2@`#f=@Z;KL zi;{c4irV8BH52tnZKxgz%G0Pw+LlLJ!B`ZSC9W|sqr5;xq74U__5z-E+J}(hk|v5PfNSsL1)QU-7^T%Qzr|xyTiJa zc2}Np7q@pAA$x>}vy(rG{rV}o(Z^|&!lcl~MttkigK5NhU4D()=? z>9^_3UnSJc*XYn+N8)>jP&3~k)XX>WtNk{iX1+tHneVb8;d_Ld`97Nxen6<19~05? zC*~F$?Cs*k@qIt9!OZX!0XCG^O#A)C=H z_$}@0v@=cW=W2KjI~8pHr^dL^tPlc+@d9oeqYX2YMyq50df4C0{)Y|h>}X+U$7XhR zY++}|srdJ|va@3wJ3F?sv!k7z9UbiK*l9M$cA2)=ZnHPG$D9*81KzB*CIq#lAwK&v zLgGZ6IUk4r3qsDIaPc|Q3}?b=wzQBqg{X2hcm)()$&QYzXhc_=BVyNpr3;dii=`hV zC&KarV0lxBB^sf;SkkuB0`~-WE^tq9S8lNk?$UVgu)GT_?*_{cf+ah(V%kBxHe4L5 zDQodC$}W!mrVPN`usL>#oWChQOjCY@ru-;P`7xUET(D`-s)dtPR%$!FMV@(NAyvoyiaS=<#|M<_&V)%4&x z5$dlq*u9a4`nojKHQs~zAqLm+KaAUWJNZ%n2B?1%)V~Gl{|4&crf?T?N2sS;jS9uw z5g~4;%+J{=^9!2fFM-j_)0~()Z$9zu_22DjjQ$E)jk06z5UIYug6woRt92pLPIpDx z!7ICp@#=V8PSE8vi}Txs~e zC(XPGPYHz)NT4i@(nx3|5Ee4Z(kKv=0K*zaqmh`Pd13;HjErq^&e(V{7Rh9L0g=;U zV_{%zuxlM)7l$I)Y;A3=*DM%zzrXwDckgHsk(3a-PiY=PWPNX|LH!Rb2fz> zMugh0z>aAaqZXoy*RQlhPj4;m`N( z>}?1hw=sI`zUfH_p7aLm&bhMJA$VqPa#tNqat>6io$-0V7d|-QG7mOB-UPZC=d|lK zAJzJp=(O*~uhOBgI2}$`XfYC?+ur(Ba53yA7!UDxPBrIXE(IN79N zJTq|;{Y?eq8Hn7>vao3cbH<@gaBx!AEOBDMpb8W>#{SpAsQRu$N^MXcd*0|2zD1Wp zjS4csYd{@gln{qN}ZV-q2Hx7*wu(DD^+7l`woiU`b z0WE16gAlU55)#%|l0>>Mr29d-KcojhdLKy7HvVHPaqS43=!V=;N7!gPBCeDP3S?3x zMDr;s`Tih%2jI+LVQyw5&WurpynM$Vc{Pglm86CUGJ{FK7LlI}`6-aMf!?d}n|M2h zM81(hYn=}&X|@^UsRsdr+{y^1N*KJEIpCIuQk%Kpm7fQz6v{NmZ!odcD>--4p2QF` znM)LKD3RrISgwHON?5LfrBHe6F;y+K;X~a&?{TMsHHMY@uw1r}MgkG*_vvTT1atG# zy+djI9eow@z7Lxp?ebc^I@aGIaLR`H5f>TPJ`f{+2LXh9e}@}n$h`e-kRb!%M}iEQ zLdxHvrH^7`Jx3eycWgGS=JP35T`sHnlb>-0`u+}&AC06yM!vtp*4E$AiNB)@f5$c^!l&`e0t4u%2=`G0jhs`|j;d{9Xd=C3{J0lEjd;>DP$Jph z_rTef)A~0qW|UvTMxe{sAaglBg)52Ma}^tZu5s!!*E*fV_{q2)LY2K86|bIJBLBu< z&%aS+w&2;X;6&lCcsRmeadGHt#K)mFvp$X;_&9DO=FRQSNMZ#|W24gN*{GzjD@!Q_ z{4=B6w!2HOTR0BQUpE+%-d~?PXs5WBD2$8=o5YP6^sXve?*yyOaohA|U)6qurXN8d zqR|8*nv{8p{S{BM`|KH-|5-c~&k;81dBP@rk3D_gCv4J-xSM`J*rZ)}DPF=u@d_S_ zSDj1nY}~+Jr<(~Oe+wRtJMnA`U~;QfAL_0r-O=7C5#^W9KaVEkuj$d>5XI|Lt+9#M?m=k546XC86m7qSg% z1#XhHL>@Xe^9Sd6;>K^xd`MO5QmW!bQ7Wp6_d`)tydQe2b5uDLm#K>PgXuN{p$ezmjn8*qKeB5P^~J~yRB%PTd^Xh(yKA48`e3od>f?CMh3F=#k+Lj9)q$NLrw_+;35zZJ3D2)jnu zZGzoq*fqg!xo^yAj7af%FuWNfV&;w!lHM2*o8&QaGGnBjG19>p>12#_LDEJ}QUi9O zg)AhUAGb+*$i#ZeD%Mlh4gb{3-0G!Uy%HiqxwlG8t`g-cs^xYd=`R6EpGO~mnZA|l zf2DE#dqt2sS+&=JqTB~dOzf!SB3wxkuA&H6Q-o_M!gUnEdhAt%Fe<*U_EHREo-;hy zOQDmcCB7{x{w+}P9ZqTXcJ3a<-K?`Zx|iajXXnnnkr{!mG*mnuKWbwI78p^Z`Z~+> zQKygP`dE>3R%&bJQsPGGKYKe%og+*<`lFOwofELVHs`DhA>iwsqeagR8&!eDyENw< zmospBPr>iP?-u^s8-IHJ3cxFE;ADw($}R{3N!9Ic1ECh&33>Jgo)`j$i7SyDPHJXT4?yGHfW!59u(1XmXUgWC z&m0u~Ou|X^<^9isa_(n9++jdQ+QlkqbpR=Wy0QW2MDw41H2>*J{*T}n!Mp-_;~;MO ze%5O8S`c?OI^_^RMGlKGYrzhs912xC4v^T=^x!oQ#4V1R1Q^IoSC<5&(?HyDfS{K2 zUhHQL$ftq0411S+6k%nS9Ev*?+Rqx0EIx^IDDxKW*Yp}VKv=tPT#KV^p+noSZ3`f* zTR{U)HnhBk^}$6pY4)H|Ey>fJ9D&mN0^AM;xE&5~tKxYLx`zm>YHrDX6>#xkP@FlJ*P+4ag>Ke6^?3 z>jfx=K?(U|XY1Gsz4#I=uI5XyxSB5|){F>P-3^L&5AVsnyj%By;@wXTYW%h?hCvN0 z4=^;WJQ&ol;)^l#lUO|hD{M?+u}^RwgB8JU!MBA?Cf90XxK?}#YQ>kJR(vU{)eErt z9;^uD;k*c|9~f3%zZBQXu<~kUSb4QFth`z!vHCHrUW3)^u=)wCWbGd4H((S7O%8r# zU{HQ4s>PegtbYN!`B$cGZ=u$HWk`E(eiQ~xj)Y~_!z7V@7t-%R`gf52J){-4-EQVp zUuc((=D-t8Sg9-#tFk85i&U>5ES5=?aIdK3e?%aB0Q&UbNcRu%3VmeAE0n!QK7c_} zgJc;PRKLc_g9}%H3l9PpJ|L3=Wi5le4LK$90Svk)A+y}d2sKFTrxuP{`HX2!wHhQCrRLojGG>Od%>05GT@ zT>u!=PXmKi2sRC(3`ii9Lf^^AH)aD}iOXpyXpIDIRqyL#lkT>7NgH=tyg-T`Y*p_E zDQ~N~SXzv24!9(HcYu~>XV?Tuv83USP`oXhw(+)XTJg5L zJSA~lFW`wg@@uah`kUBu}+g%wGxWyqZFoSQkr`AX(Y=Zef(&b67d!S&7o)7wrn9fr5h zzRZuhBcz@o@TtV_((4eZrfx)pfW`7Irka;f%}ZHE0l4@Q>=%}ly>NQmLdPdU? z1kSpV>fS_EZ>Fl>aMrO>{+P@y%>8#zjd>~6_!Q!NnQFLnOmA_ccS1GpqZ;>9jR&a4 zgH+=msK!H7<6)}t2-SFuYCKLgo}d~}QjKS*#}*lGvO8Ah!}AcL+f4D1h840J(ZE7PuY$vfJTZfIQ*%;?oKbChRCQ z>_t}N!Nm0n71a)cU(kBLr1jpQ<=$khzeUUa3NZKAjPu_hO5SFB#5=?edzaW@@8Lpt z-#Gz*cOw9A0f4uYI9D3Wo?_bKww{Uq;qf$hn)f9dODv^m){F5WMf-@NeN4!&Pk-oM3p)rHx_i;TlW}pwQXT}Uka6L0-#MLB2EG<$w0$gt-xZWsmz0u%$V<2hI z;FkOjBU*!mXbl0;stOP-?aPq>vxwGo5G|bSPI-J$*2BZDsl9#?CdJ?M-c) z39MFa5T0qR^=+G{*_(4F7T?M^6>ADz?G24fngk5>57)p({`21UEs;;|Q%ikhzgF+AKcn>TGJAwyLS4gYv9y>@ZyX2XoG(Ji}m0H*m>_ zP+2}Va&dcmp?zd)q0j=kkzHFqH!_b2#mRY`wUyKIJrk2F`9L=H2XzaU#2vArxv`-$ z;|vW7>XmRoSKCIlgxbY}7ssSp7++GX{7e29Qz&ZoRQ3+U9Ph zw>-XP0!QbUX#lucPhj4}TjEUKC%Y5*|FF}0KnB&g! zlU7cCz|gLMcL^yGwlGQ+lltM@<(y#dOu%xOXi74e9E2*1zM}WtdG^y!Qbt{=ujo1k zXY3W-w}M&@sDSN2ok=h#=M2uFik!5A{8C@T{u>Kj8(JIJ7FHJ8HZN%E?8rEZ9YbWm z*o&O_>Y0+M(+~-H8a9`6hUTe%Wu7H-QA5#iifXrB>}-E>$5!+WAWCh23cKBnkns+9 z?Q829N+9>u$0bLfK}ecf8MuF#eVL2u+}*1B8QsNRn&B>!x3QNt78pKhJRk$aT-w^$ zwz=~pqpJAY$9`RNa#wwOBddSQ+Y0Sl>RX#mSC!CAs#@eN=;PJLU71Z7!aN|_e)`y7 zAH;(k;*7{UtenaNs~$oe&phj5=lWRum^`ab=DK>Ns3j;v(#qr++#lpg$~7jcXVdAn z<&DpWs>tV4barR&j+5JI6TRMK>0RGYz`Mv0>Bk6`$kcR4i*U3HIE!S|7*}LP{i2;( zc87Ux(u9e=IAzzSJJv_@dT263_1yiCYx=3Qro<|(Eirrx zbwcP$s|j8}m-CBKxu9Rn;wr)^?n^kuF(AxSL6}9~Yd_JK3a;swT(811Azh^kj!>#p zPN^dLS3>`4=wAcZ%7hl{b9d$?>nQx*wbG zO8V7R?{xYE&0&jv3vbCck=3`-oZq5PTwgt9kGE>C~wLVm*0hiz^1L`0YmIawK`OGuf5gDL+PbQgtiVDZ!GcSm*0r zi*;|q&8IEaH>HSm?sq5FsmfnOtlNn%8*s<|zgTAr$R3GxyR{=K*6oUTU#vGvFiRXZ zZ@3SE5fKvTjNtVY zuj(wpJKY!T%_^@gvp5&7SZqZ5Sk_uw(XLdH=>00H;(P@91!$-X4F^xOi-UCCbYHZG z3THViGQwS}xvg+ls))l?aJU8z*TO+Q#6Y+ofoPX-pBxeH&25*aO7~E6TJio(2;PdN z_AMAFG)SU&AAZ@Lr#w^YIJ(lrdu@EyzDULz)Aat%RDIOwgK2tyXS$-hAE=KR`lzh{ z=bEMI{6YFSI5c&i>CDb){-{v!J)OGGoK^e8Ijg1-THKfMrPV!+eVQW1YppO&`?b5d zdu_KrhJ}1dLwlhEL$o&8LZA$>1wmE;xn&Da+k17VE|i~%a9lrtTXEO74Z558)6<%V z=b0p9_EtH=^uc_;N;Cf|o!Mq4`%Llkz^8L_&OCEgn%3To69xqkwa^cJ8K3^wZcNq_ zx}T;e6!4b9>&!rz0zEVVJj6uvSO5ja{vckZEYAAAq^TR9nv9Oa*v|3491~z@iLWgb zZ`~TaW0}Iq{YFc;k3=Tvt`QLAuR$)zv0cTxWLZS=yOZ=F|7`MWfpnDtR8*u$es_`{ z3ZUKX8bLO%7WHGBxR+!Z%WBf*Mc4zhrqyWUSOvSKM{036~9KYPo@yj%`FEc73 zakj4-+qEQTG7~?GnfTe*Zs%Z+or{begArsKSA3;-7Dz3W>5?U5O_~NNK3%eD%I)00 zOf&wnbSog>dl6hNhVLcty%fHe!IyW=<$Dm8fYi|eVri-?wyJWAVXG>8MwnETW zVUxFpO+IYc^bN>a&9@U(^eCg@G1};H%BDkCv(DtGVKaQvhJoKl>*-3>d~w6(GtzwD zXu9GTzkKuX$0C}qr@M*XF0KHea$KONnz=1Z}VYI|lON&9`uns2N-y=3RW*l~%95BC>u z&fkdQD^g@DP-KcL$n3?HP2DS2&rD*Da(x>jGc4O7aZ zw0YBPvns&oYvnZhx|zMdWr~ncYIfMWri(aQEqpdw_#A}xxoF|-XyGrRh0miDVU1!f zN7E#R5%qGdFg1xOglj_vHBq3dYG0GLQV(g=MM$E=n@-f*!S;6OBFT^)i`#MVxoQ`F1$p0p~m6tc`^e zeJvU>{e1Q3ntqA;FEkvi0@SwrhnQ173?ts|WCeIz9_%ng}? zY+B7Zhhb0TocTR92M@ZVwBeRXC;Ta-6mv2Mdv+E^ir(X}0Bzk!`?Wih&yC5GtTJ7? z$v?V=o?T#IV=MV8(pqmtdbB$`P`ogjdaC;TQw~_2pU2Qa;SFMeB^aTHsgO=-*Xj4n1~Owie3D|9fMIrkuL{3-fOlJ7_NQ;ff)?6MWZ zJ|SZma*$gO)uZ)~Yt_lnkS9p{6XY`rb|(;$(KuNvjbS)6=W9qEv*nqF6-GnSUOcKT z4G|6FnubAs&omrnG)z%`SAzxl4@UmXHieQVD$4JghCzPMKSZzfD1ROFmmB(HlJXao zXEpiPnEYei{53R@B;-C4v0D8twUX`np3DQVeRUQ$Dk@rsIO)o8IMY{ z*_WUMtbrp|4`Hy2-9s#35X*;H6G;UAycO`GV+H&vm}9463T&gdPlK)8KMYfs=0ew4 znT#;kF{cq()mqp6ZqrAg&UIp$>wFJ~;)7h9s zY9Ucml?^p&X^Tg~EgmVic%&#^oSI_pPw~gvmt2c@z4U0gE?LACx>{rrSL!mUJSkgS zYa5r#A~x+^p_FOyN~J2*_Iag34R7ZLw_~Z^fu(vUmg-#yg>U0oyxWw=>wlF;dVRgL zYfl=B*0(luxoqZg>DCIRDwL{Js#2-EQbpx?i1Iu_d3I8sM=8%^lt;S|rkb^IYVC;0 z*%yR3`Gjv!(xZ|T2NDnVuf3o&{i7}ZjGj` zJb~M-!rg+xZR3%!!p$012S~^#D%{G5oV5z~bfo$j2*NW_xM!howSg~CxQku$cB&`x zWg;7e+q{94QMe{$6t3|R_HiwnKuMkt$*{_`K0;sR?uMlG8wS*_f?8PR+F6FLat$>a zpu!fARHZGTG@ob92h?tcTA*^jOm9iW9pkIqW|6YwL`qll20o3-we@w4*m4=HR_Q8b zm9A1&=_*yEh^9t_HRQE2ypd&UAFsnE{l9XCyZ!6$ygy&5Rg2fopIUeLl4+mp;yl+C z!J}Jvbok%TI{E&Ll4Kiz-k6nEu&{Mp)3gQqR%CqIOPogMt`*nYhK?7}0CJa%>6(q(IF zI=6Mk34DF%na6Kh%0hcCE%WvMc5HujfLGv^bqg0CzGm^%<%?D(k;tFCS_wC3%35>j_qIQjFCtx!MRVLvg=4#>(WwW?{CNU;ir0!do4JB zTT{n;t%&phk9doW`0bqR@etA#C3e>(>BQW*T%6d3ujId$XAJ66WDf6d$Myxc#)&N~ zv=-WH-J{jxgf8eBbo#vz(G?|h{_V+xQc5(qroDL`M07<7ZMi#-ffPfD_Xv~7vp4?vYn*8X~AseflEmPWibJP=mY&q>BHk5KjDc$gF3Z;}XRkgK03%VqP39~Ku z+p&Gc%3kp@HFa#M?`$}!apM|RJNv^UxdVRo(X8peWw`2!_T-zZ;)IVZuyey(#U5|} zkkQ>J*UZNY0ymH9LOsjQ83Dtig zkx<&u`sp2~4f-F5=!z1${={TLDOEeX^u|~EP%T|iLa(x`D=HsMW7nos?fIjtr@W6c z)fFW)xG9lP+6cYi!}pgb6PmL%nNUjAt{;B;$Nj06u4swsPfaG2Qnf4JciqhG2Z6ckNidFw;*Llfr-k9&i>8xRcSXXO( zyOj#NdGjus@RM8XX)RrvMtgrdwm;H`{irq31>> z6G~~LSAO=ubv10~(iJ6i#DR%~(k52l{qV - 4.0.0 - - - - - - 0.1 - - - - com.springrts - common-spring - 1.0 - ../../../rts/build/maven/support/common/spring/pom.xml - - - com.springrts - ai-wrapper-javaoo - ${my.version} - - jar - - Java OO AI Wrapper - Java Object Oriented Artificial Intelligence interface wrapper for the Spring RTS engine - https://springrts.com/wiki/AIWrapper:JavaOO - 2008 - - - - - scm:git:git://github.com/spring/spring.git - scm:git:git@github.com:spring/spring.git - http://github.com/spring/spring/tree/master/AI/Wrappers/JavaOO/ - - - - - - - com.springrts - ai-interface-java - ${my.version} - - - - java3d - vecmath - 1.3.1 - - - - - diff --git a/AI/Wrappers/JavaOO/src/main/java/com/springrts/ai/oo/AIEvent.java b/AI/Wrappers/JavaOO/src/main/java/com/springrts/ai/oo/AIEvent.java deleted file mode 100644 index 796112ef8a1..00000000000 --- a/AI/Wrappers/JavaOO/src/main/java/com/springrts/ai/oo/AIEvent.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - Copyright (c) 2008 Robin Vobruba - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -package com.springrts.ai.oo; - -/** - * An AI event is sent form the engine to Java Skirmish AIs. - * - * @author hoijui - * @version 0.1 - */ -public interface AIEvent { - -} diff --git a/AI/Wrappers/JavaOO/src/main/java/com/springrts/ai/oo/AIException.java b/AI/Wrappers/JavaOO/src/main/java/com/springrts/ai/oo/AIException.java deleted file mode 100644 index 2c3a9ddb927..00000000000 --- a/AI/Wrappers/JavaOO/src/main/java/com/springrts/ai/oo/AIException.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - Copyright (c) 2009 Robin Vobruba - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -package com.springrts.ai.oo; - -/** - * Common base interface for AI related Exceptions. - * - * @author hoijui - * @version 0.1 - */ -public interface AIException { - - /** - * Returns the error associated with this Exception. - * This is used to send over low-level language interfaces, - * for example C, where exceptions are not supported. - * @return should be != 0, as this value is reserved for the no-error state - */ - public int getErrorNumber(); -} diff --git a/AI/Wrappers/JavaOO/src/main/java/com/springrts/ai/oo/AIFloat3.java b/AI/Wrappers/JavaOO/src/main/java/com/springrts/ai/oo/AIFloat3.java deleted file mode 100644 index 7865eac461c..00000000000 --- a/AI/Wrappers/JavaOO/src/main/java/com/springrts/ai/oo/AIFloat3.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - Copyright (c) 2008 Robin Vobruba - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -package com.springrts.ai.oo; - - -import javax.vecmath.Tuple3d; -import javax.vecmath.Tuple3f; -import javax.vecmath.Vector3d; -import javax.vecmath.Vector3f; -import java.awt.Color; - -/** - * Represents a position on the map. - * - * @author hoijui.quaero@gmail.com - * @version 0.1 - */ -public class AIFloat3 extends Vector3f { - - public AIFloat3() { - super(0.0f, 0.0f, 0.0f); - } - public AIFloat3(float x, float y, float z) { - super(x, y, z); - } - public AIFloat3(float[] xyz) { - super(xyz); - } - public AIFloat3(AIFloat3 other) { - super(other); - } - public AIFloat3(Tuple3d tub3d) { - super(tub3d); - } - public AIFloat3(Tuple3f tub3f) { - super(tub3f); - } - public AIFloat3(Vector3d vec3d) { - super(vec3d); - } - public AIFloat3(Vector3f vec3f) { - super(vec3f); - } - public AIFloat3(Color color) { - - this.x = color.getRed() / 255.0F; - this.y = color.getGreen() / 255.0F; - this.z = color.getBlue() / 255.0F; - } - - public Color toColor() { - return new Color(x, y, z); - } - @Override - public String toString() { - return "(" + this.x + ", " + this.y + ", " + this.z + ")"; - } - public float[] toFloatArray() { - - float[] floatArr = new float[3]; - loadInto(floatArr); - return floatArr; - } - public void loadInto(float[] xyz) { - - xyz[0] = x; - xyz[1] = y; - xyz[2] = z; - } - - @Override - public int hashCode() { - - final int prime = 31; - int result = super.hashCode(); - result = prime * result + Float.floatToIntBits(x); - result = prime * result + Float.floatToIntBits(y); - result = prime * result + Float.floatToIntBits(z); - return result; - } - @Override - public boolean equals(Object obj) { - - if (this == obj) { - return true; - } else if (!super.equals(obj)) { - return false; - } else if (getClass() != obj.getClass()) { - return false; - } - - AIFloat3 other = (AIFloat3) obj; - if (Float.floatToIntBits(x) != Float.floatToIntBits(other.x)) { - return false; - } else if (Float.floatToIntBits(y) != Float.floatToIntBits(other.y)) { - return false; - } else if (Float.floatToIntBits(z) != Float.floatToIntBits(other.z)) { - return false; - } else { - return true; - } - } -} diff --git a/AI/Wrappers/JavaOO/src/main/java/com/springrts/ai/oo/CallbackAIException.java b/AI/Wrappers/JavaOO/src/main/java/com/springrts/ai/oo/CallbackAIException.java deleted file mode 100644 index 309663ef976..00000000000 --- a/AI/Wrappers/JavaOO/src/main/java/com/springrts/ai/oo/CallbackAIException.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - Copyright (c) 2009 Robin Vobruba - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -package com.springrts.ai.oo; - -/** - * An exception of this type may be thrown while from an AI callback method. - * - * @author hoijui - */ -public class CallbackAIException extends RuntimeException implements AIException { - - private String methodName; - private int errorNumber; - - public CallbackAIException(String methodName, int errorNumber) { - super("Error calling method \"" + methodName + "\": " + errorNumber); - - this.methodName = methodName; - this.errorNumber = errorNumber; - } - public CallbackAIException(String methodName, int errorNumber, Throwable cause) { - super("Error calling method \"" + methodName + "\": " + errorNumber, cause); - - this.methodName = methodName; - this.errorNumber = errorNumber; - } - - /** - * Returns the name of the method in which the exception occurred. - */ - public String getMethodName() { - return methodName; - } - - /** - * Returns the error number that will be sent to the engine, - * and consequently appear in the engines main log file. - * @return should be != 0, as this value is reserved for the no-error state - */ - @Override - public int getErrorNumber() { - return errorNumber; - } -} diff --git a/AI/Wrappers/JavaOO/src/main/java/com/springrts/ai/oo/EventAIException.java b/AI/Wrappers/JavaOO/src/main/java/com/springrts/ai/oo/EventAIException.java deleted file mode 100644 index 8486a33f23f..00000000000 --- a/AI/Wrappers/JavaOO/src/main/java/com/springrts/ai/oo/EventAIException.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - Copyright (c) 2009 Robin Vobruba - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -package com.springrts.ai.oo; - -/** - * An exception of this type may be thrown while handling an AI event. - * - * @author hoijui - * @version 0.1 - */ -public class EventAIException extends Exception implements AIException { - - public static final int DEFAULT_ERROR_NUMBER = 10; - - private int errorNumber; - - public EventAIException() { - super(); - - this.errorNumber = DEFAULT_ERROR_NUMBER; - } - public EventAIException(int errorNumber) { - super(); - - this.errorNumber = errorNumber; - } - - public EventAIException(String message) { - super(message); - - this.errorNumber = DEFAULT_ERROR_NUMBER; - } - public EventAIException(String message, int errorNumber) { - super(message); - - this.errorNumber = errorNumber; - } - - public EventAIException(String message, Throwable cause) { - super(message, cause); - - this.errorNumber = DEFAULT_ERROR_NUMBER; - } - public EventAIException(String message, Throwable cause, int errorNumber) { - super(message, cause); - - this.errorNumber = errorNumber; - } - - public EventAIException(Throwable cause) { - super(cause); - - this.errorNumber = DEFAULT_ERROR_NUMBER; - } - public EventAIException(Throwable cause, int errorNumber) { - super(cause); - - this.errorNumber = errorNumber; - } - - /** - * Returns the error number that will be sent to the engine, - * and consequently appear in the engines main log file. - * @return should be != 0, as this value is reserved for the no-error state - */ - @Override - public int getErrorNumber() { - return errorNumber; - } -} diff --git a/CMakeLists.txt b/CMakeLists.txt index d016d27287c..243ef8cb697 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -73,11 +73,6 @@ else() set(DEBUG_BUILD FALSE) endif() -if(DEBUG_BUILD) - set(JAVA_COMPILE_FLAG_CONDITIONAL "-g:lines,source,vars") -else() - set(JAVA_COMPILE_FLAG_CONDITIONAL "-g:lines,source") -endif() # By default, the libraries that don't explicitly specify SHARED/STATIC are build statically. # See https://cmake.org/cmake/help/latest/variable/BUILD_SHARED_LIBS.html @@ -211,7 +206,7 @@ endif (UNIX AND NOT MINGW) # (next two are relative to CMAKE_INSTALL_PREFIX) set(AI_LIBS_DIR "${DATADIR}" CACHE STRING "Where to install Skirmish AI libraries") set(AI_DATA_DIR "${AI_LIBS_DIR}" CACHE STRING "Where to install Skirmish AI additional files (eg. configuration)") -set(AI_TYPES "NATIVE" CACHE STRING "Which AI Interfaces (and Skirmish AIs using them) to build [ALL|NATIVE|JAVA|NONE]") +set(AI_TYPES "NATIVE" CACHE STRING "Which AI Interfaces (and Skirmish AIs using them) to build [ALL|NATIVE|NONE]") ## DataDirs set(BUILTIN_DATADIRS "") diff --git a/rts/build/cmake/UtilJava.cmake b/rts/build/cmake/UtilJava.cmake deleted file mode 100644 index 71874cc4966..00000000000 --- a/rts/build/cmake/UtilJava.cmake +++ /dev/null @@ -1,101 +0,0 @@ -# This file is part of the Spring engine (GPL v2 or later), see LICENSE.html - -# -# Spring Java related CMake utilities -# ----------------------------------- -# -# Variables set in this file: -# * JAVA_GLOBAL_LIBS_DIRS -# -# Functions and macros defined in this file: -# * find_java_lib -# * get_first_sub_dir_name -# * create_classpath -# * concat_classpaths -# * find_manifest_file -# - - -if (CMAKE_HOST_WIN32) - set(JAVA_GLOBAL_LIBS_DIRS "${MINGWLIBS}") -else (CMAKE_HOST_WIN32) - set(JAVA_GLOBAL_LIBS_DIRS "/usr/share/java" "/usr/local/share/java") -endif (CMAKE_HOST_WIN32) -make_global(JAVA_GLOBAL_LIBS_DIRS) - - -# Looks for a Java library (Jar file) in system wide search paths and in -# additional dirs supplied as argument. -macro (find_java_lib path_var libName additionalSearchDirs) - find_file(${path_var} "${libName}.jar" - PATHS ${additionalSearchDirs} ${JAVA_GLOBAL_LIBS_DIRS} - DOC "Path to the Java library ${libName}.jar" - NO_DEFAULT_PATH - NO_CMAKE_FIND_ROOT_PATH - ) - if (NOT ${path_var}) - message(SEND_ERROR "${libName}.jar not found!") - else (NOT ${path_var}) - ai_message(STATUS "Found ${libName}.jar: ${${path_var}}") - endif (NOT ${path_var}) -endmacro (find_java_lib path_var libName additionalSearchDirs) - - -# Returns the name of the first sub-dir (in alphabetical descending order) -# under dir. -macro (get_first_sub_dir_name name_var dir) - file(GLOB dirContent RELATIVE "${dir}" "${dir}/*") - foreach (dirPart ${dirContent}) - if (IS_DIRECTORY "${dir}/${dirPart}") - set(${name_var} ${dirPart}) - break() - endif (IS_DIRECTORY "${dir}/${dirPart}") - endforeach (dirPart) -endmacro (get_first_sub_dir_name name_var dir) - - -# Recursively lists all JAR files in a given directory -# and concatenates them in a Java Classpath compatible way into a single string. -macro (create_classpath classPath_var dir) - file(GLOB_RECURSE ${classPath_var} FOLLOW_SYMLINKS "${dir}/*.jar") - # Make sure we use the correct path delimiter for the compiling system - string(REPLACE ";" "${PATH_DELIM_H}" ${classPath_var} "${${classPath_var}}") -endmacro (create_classpath classPath_var dir) - - -# Concatenates an arbitrary number of Java ClassPaths (may be empty). -function (concat_classpaths resultingCP_var) - set(${resultingCP_var} "") - foreach (cpPart ${ARGN}) - set(${resultingCP_var} "${${resultingCP_var}}${cpPart}${PATH_DELIM_H}") - endforeach (cpPart) - string(REGEX REPLACE "${PATH_DELIM_H}\$" "" ${resultingCP_var} "${${resultingCP_var}}") - set(${resultingCP_var} "${${resultingCP_var}}" PARENT_SCOPE) -endfunction (concat_classpaths) - -# Look for a manifest.mf file in a few specific sub-dirs. -# This could be done with a simple find_file call, -# but that strangely does not find the file under win32, -# so we use this workaround -function (find_manifest_file srcDir result_var) - set(manifestSubdirs - "/src/main/resources/META-INF/" - "/src/" - "/") - set(${result_var} "${result_var}-NOTFOUND") - if (CMAKE_HOST_WIN32) - foreach(subDir_var ${manifestSubdirs}) - if (EXISTS "${srcDir}${subDir_var}manifest.mf") - set(${result_var} "${srcDir}${subDir_var}manifest.mf") - break() - endif (EXISTS "${srcDir}${subDir_var}manifest.mf") - endforeach(subDir_var) - else (CMAKE_HOST_WIN32) - find_file(${result_var} - NAMES "manifest.mf" "MANIFEST.MF" - PATHS "${srcDir}" - PATH_SUFFIXES ${manifestSubdirs} - NO_DEFAULT_PATH) - endif (CMAKE_HOST_WIN32) - set(${result_var} ${${result_var}} PARENT_SCOPE) -endfunction (find_manifest_file)