Initial Commit
This commit is contained in:
commit
6b6c4a91b8
35
.gitignore
vendored
Normal file
35
.gitignore
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
# gradle
|
||||
|
||||
.gradle/
|
||||
build/
|
||||
out/
|
||||
classes/
|
||||
|
||||
# idea
|
||||
|
||||
.idea/
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
|
||||
# vscode
|
||||
|
||||
.settings/
|
||||
.vscode/
|
||||
bin/
|
||||
.classpath
|
||||
.project
|
||||
|
||||
# fabric
|
||||
|
||||
run/
|
||||
|
||||
remappedSrc/
|
||||
|
||||
src/main/c/build-*
|
||||
src/main/c/quickjs
|
||||
src/main/c/jni
|
||||
|
||||
scripts/jdk.tar.gz
|
||||
scripts/jdk
|
||||
scripts/quickjs.tar.xz
|
4
CHANGELOG.md
Normal file
4
CHANGELOG.md
Normal file
|
@ -0,0 +1,4 @@
|
|||
# Changelog
|
||||
|
||||
**1.0**
|
||||
* Initial Release
|
4
Dockerfile
Normal file
4
Dockerfile
Normal file
|
@ -0,0 +1,4 @@
|
|||
FROM openjdk:8-jdk-alpine
|
||||
|
||||
RUN apk add --no-cache npm
|
||||
RUN npm install -g typescript typedoc
|
22
Jenkinsfile
vendored
Normal file
22
Jenkinsfile
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
pipeline {
|
||||
agent {
|
||||
dockerfile true
|
||||
}
|
||||
stages {
|
||||
stage('Setup') {
|
||||
steps {
|
||||
sh 'cd scripts; ./setup.sh'
|
||||
}
|
||||
}
|
||||
stage('Build') {
|
||||
steps {
|
||||
sh './gradlew build'
|
||||
}
|
||||
post {
|
||||
success {
|
||||
archiveArtifacts artifacts: 'build/libs/*', fingerprint: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2020 TheBrokenRail
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
5
README.md
Normal file
5
README.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
# ScriptCraft
|
||||
JS API for Minecraft
|
||||
|
||||
## Changelog
|
||||
[View Changelog](CHANGELOG.md)
|
218
build.gradle
Normal file
218
build.gradle
Normal file
|
@ -0,0 +1,218 @@
|
|||
plugins {
|
||||
id 'fabric-loom' version '0.2.7-SNAPSHOT'
|
||||
id 'com.matthewprenger.cursegradle' version '1.4.0'
|
||||
}
|
||||
|
||||
def cDir = new File(rootProject.projectDir.absolutePath, 'src/main/c')
|
||||
|
||||
class JNIPlatform {
|
||||
String name
|
||||
String[] cmakeArgs
|
||||
String libExtension
|
||||
|
||||
JNIPlatform(String name, String[] cmakeArgs, String libExtension) {
|
||||
this.name = name
|
||||
this.cmakeArgs = cmakeArgs
|
||||
this.libExtension = libExtension
|
||||
}
|
||||
}
|
||||
|
||||
JNIPlatform[] jniPlatforms = [
|
||||
new JNIPlatform("linux-x86_64", [] as String[], ".so"),
|
||||
new JNIPlatform("linux-i686", ["-DCMAKE_TOOLCHAIN_FILE=${rootDir.absolutePath}/cmake/linux_i686_toolchain.cmake"] as String[], ".so"),
|
||||
new JNIPlatform("windows-x86_64", ["-DCMAKE_TOOLCHAIN_FILE=${rootDir.absolutePath}/cmake/windows_x86_64_toolchain.cmake"] as String[], ".dll"),
|
||||
new JNIPlatform("windows-i686", ["-DCMAKE_TOOLCHAIN_FILE=${rootDir.absolutePath}/cmake/windows_i686_toolchain.cmake"] as String[], ".dll")
|
||||
]
|
||||
|
||||
for (JNIPlatform platform : jniPlatforms) {
|
||||
def buildDir = new File(cDir, "build-${platform.name}")
|
||||
if (!buildDir.exists()) {
|
||||
buildDir.mkdir()
|
||||
}
|
||||
|
||||
tasks.create(name: "cmake-${platform.name}", type: Exec) {
|
||||
workingDir buildDir
|
||||
|
||||
executable 'cmake'
|
||||
args platform.cmakeArgs + ['..']
|
||||
}
|
||||
|
||||
tasks.create(name: "compileJNI-${platform.name}", type: Exec) {
|
||||
workingDir buildDir
|
||||
|
||||
executable 'make'
|
||||
|
||||
dependsOn tasks.getByName("cmake-${platform.name}")
|
||||
}
|
||||
|
||||
processResources.dependsOn tasks.getByName("compileJNI-${platform.name}")
|
||||
|
||||
tasks.create(name: "cleanJNI-${platform.name}", type: Delete) {
|
||||
delete buildDir.absolutePath
|
||||
}
|
||||
|
||||
clean.dependsOn tasks.getByName("cleanJNI-${platform.name}")
|
||||
}
|
||||
|
||||
compileJava {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
archivesBaseName = project.archives_base_name
|
||||
def mod_version = project.mod_version as Object
|
||||
version = "${mod_version}+${project.minecraft_version}"
|
||||
group = project.maven_group as Object
|
||||
|
||||
minecraft {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
minecraft "com.mojang:minecraft:${project.minecraft_version}"
|
||||
mappings "net.fabricmc:yarn:${project.minecraft_version}+build.${project.yarn_build}:v2"
|
||||
modImplementation "net.fabricmc:fabric-loader:${project.fabric_loader_version}"
|
||||
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_api_version}"
|
||||
}
|
||||
|
||||
def typescriptOut = new File(buildDir, 'generated/typescript')
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
resources {
|
||||
srcDir typescriptOut
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def typescriptRoot = rootProject.typescript_root as String
|
||||
def resources = new File(rootProject.rootDir, 'src/main/resources')
|
||||
def typescriptRootFile = new File(resources, typescriptRoot)
|
||||
|
||||
task compileTypescript {
|
||||
inputs.dir typescriptRootFile
|
||||
outputs.dir typescriptOut
|
||||
|
||||
doFirst {
|
||||
project.delete {
|
||||
delete typescriptOut
|
||||
}
|
||||
typescriptOut.mkdirs()
|
||||
|
||||
project.exec {
|
||||
executable 'tsc'
|
||||
|
||||
args '--outDir', new File(typescriptOut, typescriptRoot).absolutePath
|
||||
args '--project', typescriptRootFile.absolutePath
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
processResources.dependsOn compileTypescript
|
||||
|
||||
def typedocOut = new File(buildDir, 'typedoc')
|
||||
|
||||
task typedoc {
|
||||
inputs.dir typescriptRootFile
|
||||
outputs.dir typedocOut
|
||||
|
||||
doFirst {
|
||||
project.delete {
|
||||
delete typedocOut
|
||||
}
|
||||
typedocOut.mkdirs()
|
||||
|
||||
project.exec {
|
||||
workingDir typescriptRootFile
|
||||
executable 'typedoc'
|
||||
|
||||
args '--out', typedocOut.absolutePath
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
processResources {
|
||||
inputs.property 'version', mod_version
|
||||
inputs.property 'name', rootProject.name
|
||||
|
||||
from(sourceSets.main.resources.srcDirs) {
|
||||
include 'fabric.mod.json'
|
||||
expand 'version': mod_version, 'name': rootProject.name
|
||||
}
|
||||
|
||||
from(sourceSets.main.resources.srcDirs) {
|
||||
exclude 'fabric.mod.json'
|
||||
}
|
||||
|
||||
exclude typescriptRoot + '/**/*.ts'
|
||||
exclude typescriptRoot + '/types'
|
||||
|
||||
for (JNIPlatform platform : jniPlatforms) {
|
||||
def buildDir = new File(cDir, "build-${platform.name}")
|
||||
if (!buildDir.exists()) {
|
||||
buildDir.mkdir()
|
||||
}
|
||||
|
||||
def file = new File(buildDir, 'libscriptcraft' + platform.libExtension)
|
||||
inputs.files file
|
||||
|
||||
from(file.absolutePath) {
|
||||
into new File('natives', platform.name).path
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ensure that the encoding is set to UTF-8, no matter what the system default is
|
||||
// this fixes some edge cases with special characters not displaying correctly
|
||||
// see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html
|
||||
tasks.withType(JavaCompile) {
|
||||
options.encoding = 'UTF-8'
|
||||
}
|
||||
|
||||
// Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task
|
||||
// if it is present.
|
||||
// If you remove this task, sources will not be generated.
|
||||
task sourcesJar(type: Jar, dependsOn: classes) {
|
||||
classifier 'sources'
|
||||
from sourceSets.main.allSource
|
||||
}
|
||||
|
||||
task typedocJar(type: Jar) {
|
||||
classifier 'typedoc'
|
||||
from typedocOut
|
||||
}
|
||||
|
||||
typedocJar.dependsOn typedoc
|
||||
|
||||
artifacts {
|
||||
archives sourcesJar
|
||||
archives typedocJar
|
||||
}
|
||||
|
||||
jar {
|
||||
from 'LICENSE'
|
||||
}
|
||||
|
||||
if (project.hasProperty('curseforge.api_key')) {
|
||||
curseforge {
|
||||
apiKey = project.getProperty('curseforge.api_key')
|
||||
project {
|
||||
id = project.curseforge_id
|
||||
changelog = 'A changelog can be found at https://gitea.thebrokenrail.com/TheBrokenRail/ScriptCraft/src/branch/master/CHANGELOG.md'
|
||||
releaseType = 'release'
|
||||
addGameVersion project.simple_minecraft_version
|
||||
addGameVersion 'Fabric'
|
||||
mainArtifact(remapJar) {
|
||||
displayName = "ScriptCraft v${mod_version} for ${project.minecraft_version}"
|
||||
}
|
||||
afterEvaluate {
|
||||
uploadTask.dependsOn('remapJar')
|
||||
}
|
||||
relations {
|
||||
requiredDependency 'fabric-api'
|
||||
}
|
||||
}
|
||||
options {
|
||||
forgeGradleIntegration = false
|
||||
}
|
||||
}
|
||||
}
|
7
cmake/linux_i686_toolchain.cmake
Normal file
7
cmake/linux_i686_toolchain.cmake
Normal file
|
@ -0,0 +1,7 @@
|
|||
set(CMAKE_SYSTEM_NAME Linux)
|
||||
set(CMAKE_SYSTEM_PROCESSOR i686)
|
||||
|
||||
set(CMAKE_C_FLAGS "-m32 -march=i686")
|
||||
set(CMAKE_CXX_FLAGS "-m32 -march=i686")
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS "-m32 -march=i686")
|
14
cmake/windows_i686_toolchain.cmake
Normal file
14
cmake/windows_i686_toolchain.cmake
Normal file
|
@ -0,0 +1,14 @@
|
|||
set(CMAKE_SYSTEM_NAME Windows)
|
||||
set(CMAKE_SYSTEM_PROCESSOR x86)
|
||||
set(TOOLCHAIN_PREFIX i686-w64-mingw32)
|
||||
|
||||
set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc)
|
||||
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++)
|
||||
set(CMAKE_Fortran_COMPILER ${TOOLCHAIN_PREFIX}-gfortran)
|
||||
set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres)
|
||||
|
||||
set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX})
|
||||
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
14
cmake/windows_x86_64_toolchain.cmake
Normal file
14
cmake/windows_x86_64_toolchain.cmake
Normal file
|
@ -0,0 +1,14 @@
|
|||
set(CMAKE_SYSTEM_NAME Windows)
|
||||
set(CMAKE_SYSTEM_PROCESSOR amd64)
|
||||
set(TOOLCHAIN_PREFIX x86_64-w64-mingw32)
|
||||
|
||||
set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc)
|
||||
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++)
|
||||
set(CMAKE_Fortran_COMPILER ${TOOLCHAIN_PREFIX}-gfortran)
|
||||
set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres)
|
||||
|
||||
set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX})
|
||||
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
21
gradle.properties
Normal file
21
gradle.properties
Normal file
|
@ -0,0 +1,21 @@
|
|||
# Done to increase the memory available to gradle.
|
||||
org.gradle.jvmargs = -Xmx1G
|
||||
|
||||
typescript_root = scriptcraft
|
||||
|
||||
# Fabric Properties
|
||||
# check these on https://fabricmc.net/use
|
||||
minecraft_version = 1.15.2
|
||||
curseforge_id = TBD
|
||||
simple_minecraft_version = 1.15.2
|
||||
yarn_build = 15
|
||||
fabric_loader_version = 0.8.2+build.194
|
||||
|
||||
# Mod Properties
|
||||
mod_version = 1.0.0
|
||||
maven_group = com.thebrokenrail
|
||||
archives_base_name = scriptcraft
|
||||
|
||||
# Dependencies
|
||||
# currently not on the main fabric site, check on the maven: https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api
|
||||
fabric_api_version = 0.5.12+build.296-1.15
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
6
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
#Sat Feb 29 21:58:32 EST 2020
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.2.2-all.zip
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStorePath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
188
gradlew
vendored
Executable file
188
gradlew
vendored
Executable file
|
@ -0,0 +1,188 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=$(save "$@")
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
fi
|
||||
|
||||
exec "$JAVACMD" "$@"
|
100
gradlew.bat
vendored
Normal file
100
gradlew.bat
vendored
Normal file
|
@ -0,0 +1,100 @@
|
|||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
33
scripts/download-jni-headers.sh
Executable file
33
scripts/download-jni-headers.sh
Executable file
|
@ -0,0 +1,33 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
if [ -e jdk.tar.gz ]; then
|
||||
rm -f jdk.tar.gz
|
||||
fi
|
||||
curl -o jdk.tar.gz https://hg.openjdk.java.net/jdk/jdk11/archive/tip.tar.gz
|
||||
|
||||
if [ -d ../src/main/c/jni ]; then
|
||||
rm -rf ../src/main/c/jni
|
||||
fi
|
||||
mkdir ../src/main/c/jni
|
||||
|
||||
if [ -d jdk ]; then
|
||||
rm -rf jdk
|
||||
fi
|
||||
mkdir jdk
|
||||
tar -zxf jdk.tar.gz --strip-components=1 -C jdk
|
||||
|
||||
rm -f jdk.tar.gz
|
||||
|
||||
cp -r jdk/src/java.base/share/native/include/. ../src/main/c/jni
|
||||
|
||||
copy_jni() {
|
||||
mkdir "../src/main/c/jni/$1"
|
||||
cp -r "jdk/src/java.base/$1/native/include/." "../src/main/c/jni/$1"
|
||||
}
|
||||
|
||||
copy_jni unix
|
||||
copy_jni windows
|
||||
|
||||
rm -rf jdk
|
17
scripts/download-quickjs.sh
Executable file
17
scripts/download-quickjs.sh
Executable file
|
@ -0,0 +1,17 @@
|
|||
#!/bin/sh
|
||||
|
||||
QUICKJS_VERSION='2020-04-12'
|
||||
|
||||
set -e
|
||||
|
||||
if [ -e quickjs.tar.xz ]; then
|
||||
rm -f quickjs.tar.xz
|
||||
fi
|
||||
curl -L -o quickjs.tar.xz https://bellard.org/quickjs/quickjs-${QUICKJS_VERSION}.tar.xz
|
||||
|
||||
if [ -d ../src/main/c/quickjs ]; then
|
||||
rm -rf ../src/main/c/quickjs
|
||||
fi
|
||||
mkdir ../src/main/c/quickjs
|
||||
tar -Jxf quickjs.tar.xz --strip-components=1 -C ../src/main/c/quickjs
|
||||
rm -f quickjs.tar.xz
|
6
scripts/setup.sh
Executable file
6
scripts/setup.sh
Executable file
|
@ -0,0 +1,6 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
./download-quickjs.sh
|
||||
./download-jni-headers.sh
|
12
settings.gradle
Normal file
12
settings.gradle
Normal file
|
@ -0,0 +1,12 @@
|
|||
pluginManagement {
|
||||
repositories {
|
||||
jcenter()
|
||||
maven {
|
||||
name = 'Fabric'
|
||||
url = 'https://maven.fabricmc.net/'
|
||||
}
|
||||
gradlePluginPortal()
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.name = 'ScriptCraft'
|
31
src/main/c/CMakeLists.txt
Normal file
31
src/main/c/CMakeLists.txt
Normal file
|
@ -0,0 +1,31 @@
|
|||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
project(scriptcraft C)
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror -Wno-int-to-pointer-cast -Wno-pointer-to-int-cast")
|
||||
|
||||
add_library(
|
||||
scriptcraft
|
||||
SHARED
|
||||
quickjs/quickjs.c
|
||||
quickjs/libregexp.c
|
||||
quickjs/libunicode.c
|
||||
quickjs/cutils.c
|
||||
quickjs/libbf.c
|
||||
console.c
|
||||
com_thebrokenrail_scriptcraft_quickjs_QuickJS.c
|
||||
)
|
||||
|
||||
file(STRINGS "quickjs/VERSION" QUICKJS_VERSION)
|
||||
target_compile_definitions(scriptcraft PUBLIC -D_GNU_SOURCE PUBLIC -DCONFIG_VERSION=\"${QUICKJS_VERSION}\" -DCONFIG_BIGNUM -DDUMP_LEAKS)
|
||||
|
||||
target_include_directories(scriptcraft PUBLIC quickjs)
|
||||
|
||||
include_directories(jni)
|
||||
if(UNIX)
|
||||
include_directories(jni/unix)
|
||||
elseif(WIN32)
|
||||
include_directories(jni/windows)
|
||||
endif()
|
||||
|
||||
target_link_libraries(scriptcraft m pthread)
|
62
src/main/c/asprintf.h
Normal file
62
src/main/c/asprintf.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
#ifndef ASPRINTF_H
|
||||
#define ASPRINTF_H
|
||||
|
||||
#if defined(__GNUC__) && ! defined(_GNU_SOURCE)
|
||||
#define _GNU_SOURCE /* needed for (v)asprintf, affects '#include <stdio.h>' */
|
||||
#endif
|
||||
#include <stdio.h> /* needed for vsnprintf */
|
||||
#include <stdlib.h> /* needed for malloc, free */
|
||||
#include <stdarg.h> /* needed for va_* */
|
||||
|
||||
/*
|
||||
* vscprintf:
|
||||
* MSVC implements this as _vscprintf, thus we just 'symlink' it here
|
||||
* GNU-C-compatible compilers do not implement this, thus we implement it here
|
||||
*/
|
||||
#ifdef _MSC_VER
|
||||
#define vscprintf _vscprintf
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
inline static int vscprintf(const char *format, va_list ap) {
|
||||
va_list ap_copy;
|
||||
va_copy(ap_copy, ap);
|
||||
int retval = vsnprintf(NULL, 0, format, ap_copy);
|
||||
va_end(ap_copy);
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* asprintf, vasprintf:
|
||||
* MSVC does not implement these, thus we implement them here
|
||||
* GNU-C-compatible compilers implement these with the same names, thus we
|
||||
* don't have to do anything
|
||||
*/
|
||||
#ifdef _MSC_VER
|
||||
inline static int vasprintf(char **strp, const char *format, va_list ap) {
|
||||
int len = vscprintf(format, ap);
|
||||
if (len == -1)
|
||||
return -1;
|
||||
char *str = (char*)malloc((size_t) len + 1);
|
||||
if (!str)
|
||||
return -1;
|
||||
int retval = vsnprintf(str, len + 1, format, ap);
|
||||
if (retval == -1) {
|
||||
free(str);
|
||||
return -1;
|
||||
}
|
||||
*strp = str;
|
||||
return retval;
|
||||
}
|
||||
|
||||
inline static int asprintf(char **strp, const char *format, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
int retval = vasprintf(strp, format, ap);
|
||||
va_end(ap);
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // ASPRINTF_H
|
464
src/main/c/com_thebrokenrail_scriptcraft_quickjs_QuickJS.c
Normal file
464
src/main/c/com_thebrokenrail_scriptcraft_quickjs_QuickJS.c
Normal file
|
@ -0,0 +1,464 @@
|
|||
#include <limits.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <cutils.h>
|
||||
#include <quickjs.h>
|
||||
|
||||
#include "com_thebrokenrail_scriptcraft_quickjs_QuickJS.h"
|
||||
#include "console.h"
|
||||
|
||||
static JavaVM *jvm;
|
||||
|
||||
static void *get_pointer(JNIEnv *env, jobject obj, char *name) {
|
||||
jclass clazz = (*env)->FindClass(env, "com/thebrokenrail/scriptcraft/quickjs/QuickJS");
|
||||
jfieldID field = (*env)->GetFieldID(env, clazz, name, "J");
|
||||
return (void *) (long) (*env)->GetLongField(env, obj, field);
|
||||
}
|
||||
|
||||
static void set_pointer(JNIEnv *env, jobject obj, char *name, void *value) {
|
||||
jclass clazz = (*env)->FindClass(env, "com/thebrokenrail/scriptcraft/quickjs/QuickJS");
|
||||
jfieldID field = (*env)->GetFieldID(env, clazz, name, "J");
|
||||
(*env)->SetLongField(env, obj, field, (jlong) (long) value);
|
||||
}
|
||||
|
||||
static char *js_module_normalize_name(JSContext *ctx, const char *base_name, const char *name, void *opaque) {
|
||||
JNIEnv *env;
|
||||
(*jvm)->AttachCurrentThread(jvm, (void **) &env, NULL);
|
||||
|
||||
jclass clazz = (*env)->FindClass(env, "com/thebrokenrail/scriptcraft/quickjs/QuickJS");
|
||||
jmethodID methodID = (*env)->GetStaticMethodID(env, clazz, "normalizeModule", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
|
||||
|
||||
jstring java_name = (*env)->NewStringUTF(env, name);
|
||||
jstring java_base_name = (*env)->NewStringUTF(env, base_name);
|
||||
jstring java_string = (jstring) (*env)->CallStaticObjectMethod(env, clazz, methodID, java_base_name, java_name);
|
||||
(*env)->DeleteLocalRef(env, java_name);
|
||||
(*env)->DeleteLocalRef(env, java_base_name);
|
||||
|
||||
if (java_string) {
|
||||
const char *native_string = (*env)->GetStringUTFChars(env, java_string, 0);
|
||||
char *new_string = js_strdup(ctx, native_string);
|
||||
(*env)->ReleaseStringUTFChars(env, java_string, native_string);
|
||||
|
||||
(*env)->DeleteLocalRef(env, java_string);
|
||||
|
||||
(*jvm)->DetachCurrentThread(jvm);
|
||||
return new_string;
|
||||
} else {
|
||||
jthrowable err = (*env)->ExceptionOccurred(env);
|
||||
if (err) {
|
||||
jmethodID to_string = (*env)->GetMethodID(env, (*env)->FindClass(env, "java/lang/Object"), "toString", "()Ljava/lang/String;");
|
||||
jstring java_string = (jstring) (*env)->CallObjectMethod(env, err, to_string);
|
||||
const char *str = (*env)->GetStringUTFChars(env, java_string, 0);
|
||||
|
||||
JS_ThrowReferenceError(ctx, "could not normalize module name '%s': %s", name, str);
|
||||
|
||||
(*env)->ExceptionClear(env);
|
||||
} else {
|
||||
JS_ThrowReferenceError(ctx, "could not normalize module name '%s'", name);
|
||||
}
|
||||
(*jvm)->DetachCurrentThread(jvm);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val, JS_BOOL use_realpath, JS_BOOL is_main) {
|
||||
JSModuleDef *m;
|
||||
char buf[PATH_MAX + 16];
|
||||
JSValue meta_obj;
|
||||
JSAtom module_name_atom;
|
||||
const char *module_name;
|
||||
|
||||
assert(JS_VALUE_GET_TAG(func_val) == JS_TAG_MODULE);
|
||||
m = JS_VALUE_GET_PTR(func_val);
|
||||
|
||||
module_name_atom = JS_GetModuleName(ctx, m);
|
||||
module_name = JS_AtomToCString(ctx, module_name_atom);
|
||||
JS_FreeAtom(ctx, module_name_atom);
|
||||
if (!module_name) {
|
||||
return -1;
|
||||
}
|
||||
if (!strchr(module_name, ':')) {
|
||||
strcpy(buf, "file://");
|
||||
}
|
||||
pstrcpy(buf, sizeof(buf), module_name);
|
||||
JS_FreeCString(ctx, module_name);
|
||||
|
||||
meta_obj = JS_GetImportMeta(ctx, m);
|
||||
if (JS_IsException(meta_obj)) {
|
||||
return -1;
|
||||
}
|
||||
JS_DefinePropertyValueStr(ctx, meta_obj, "url", JS_NewString(ctx, buf), JS_PROP_C_W_E);
|
||||
JS_DefinePropertyValueStr(ctx, meta_obj, "main", JS_NewBool(ctx, is_main), JS_PROP_C_W_E);
|
||||
JS_FreeValue(ctx, meta_obj);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *js_load_file(JSContext *ctx, const char *filename) {
|
||||
JNIEnv *env;
|
||||
(*jvm)->AttachCurrentThread(jvm, (void **) &env, NULL);
|
||||
|
||||
jclass clazz = (*env)->FindClass(env, "com/thebrokenrail/scriptcraft/quickjs/QuickJS");
|
||||
jmethodID methodID = (*env)->GetStaticMethodID(env, clazz, "loadModule", "(Ljava/lang/String;)Ljava/lang/String;");
|
||||
|
||||
jstring java_filename = (*env)->NewStringUTF(env, filename);
|
||||
jstring java_string = (jstring) (*env)->CallStaticObjectMethod(env, clazz, methodID, java_filename);
|
||||
(*env)->DeleteLocalRef(env, java_filename);
|
||||
|
||||
if (java_string) {
|
||||
const char *native_string = (*env)->GetStringUTFChars(env, java_string, 0);
|
||||
char *new_string = js_strdup(ctx, native_string);
|
||||
(*env)->ReleaseStringUTFChars(env, java_string, native_string);
|
||||
|
||||
(*env)->DeleteLocalRef(env, java_string);
|
||||
|
||||
(*jvm)->DetachCurrentThread(jvm);
|
||||
return new_string;
|
||||
} else {
|
||||
jthrowable err = (*env)->ExceptionOccurred(env);
|
||||
if (err) {
|
||||
jmethodID to_string = (*env)->GetMethodID(env, (*env)->FindClass(env, "java/lang/Object"), "toString", "()Ljava/lang/String;");
|
||||
jstring java_string = (jstring) (*env)->CallObjectMethod(env, err, to_string);
|
||||
const char *str = (*env)->GetStringUTFChars(env, java_string, 0);
|
||||
|
||||
JS_ThrowReferenceError(ctx, "could not load module filename '%s': %s", filename, str);
|
||||
|
||||
(*env)->ExceptionClear(env);
|
||||
} else {
|
||||
JS_ThrowReferenceError(ctx, "could not load module filename '%s'", filename);
|
||||
}
|
||||
(*jvm)->DetachCurrentThread(jvm);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static JSModuleDef *js_module_loader(JSContext *ctx, const char *module_name, void *opaque) {
|
||||
JSModuleDef *m;
|
||||
|
||||
char *buf;
|
||||
JSValue func_val;
|
||||
|
||||
buf = js_load_file(ctx, module_name);
|
||||
if (!buf) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int is_json = has_suffix(module_name, ".json");
|
||||
if (is_json) {
|
||||
asprintf(&buf, "export default JSON.parse(`%s`);", buf);
|
||||
}
|
||||
|
||||
/* compile the module */
|
||||
func_val = JS_Eval(ctx, buf, strlen(buf), module_name, JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);
|
||||
js_free(ctx, buf);
|
||||
if (JS_IsException(func_val)) {
|
||||
return NULL;
|
||||
}
|
||||
/* XXX: could propagate the exception */
|
||||
js_module_set_import_meta(ctx, func_val, 1, 0);
|
||||
/* the module is already referenced, so we must free it */
|
||||
m = JS_VALUE_GET_PTR(func_val);
|
||||
JS_FreeValue(ctx, func_val);
|
||||
return m;
|
||||
}
|
||||
|
||||
static void throw_exception(JNIEnv *env, char *message) {
|
||||
jclass exception_clazz = (*env)->FindClass(env, "com/thebrokenrail/scriptcraft/quickjs/JSException");
|
||||
(*env)->ThrowNew(env, exception_clazz, message);
|
||||
}
|
||||
|
||||
static JSClassID JS_CLASS_JAVA_OBJECT_ID;
|
||||
|
||||
typedef struct java_object_data {
|
||||
jobject obj;
|
||||
} java_object_data;
|
||||
|
||||
static void java_object_finalizer(JSRuntime *rt, JSValue val) {
|
||||
java_object_data *data = JS_GetOpaque(val, JS_CLASS_JAVA_OBJECT_ID);
|
||||
if (data) {
|
||||
JNIEnv *env;
|
||||
(*jvm)->AttachCurrentThread(jvm, (void **) &env, NULL);
|
||||
|
||||
(*env)->DeleteGlobalRef(env, data->obj);
|
||||
js_free_rt(rt, data);
|
||||
|
||||
(*jvm)->DetachCurrentThread(jvm);
|
||||
}
|
||||
}
|
||||
|
||||
static JSClassDef JS_CLASS_JAVA_OBJECT = {
|
||||
"JavaObject",
|
||||
.finalizer = java_object_finalizer
|
||||
};
|
||||
|
||||
static JSValue java_object_to_js_object(JNIEnv *env, JSContext *ctx, jobject obj) {
|
||||
JSValue out = JS_NULL;
|
||||
|
||||
jclass boolean_clazz = (*env)->FindClass(env, "java/lang/Boolean");
|
||||
jclass double_clazz = (*env)->FindClass(env, "java/lang/Double");
|
||||
jclass string_clazz = (*env)->FindClass(env, "java/lang/String");
|
||||
jclass array_clazz = (*env)->FindClass(env, "[Ljava/lang/Object;");
|
||||
if ((*env)->IsInstanceOf(env, obj, string_clazz)) {
|
||||
const char *native_string = (*env)->GetStringUTFChars(env, (jstring) obj, 0);
|
||||
out = JS_NewString(ctx, native_string);
|
||||
(*env)->ReleaseStringUTFChars(env, (jstring) obj, native_string);
|
||||
} else if ((*env)->IsInstanceOf(env, obj, boolean_clazz)) {
|
||||
jmethodID boolean_methodID = (*env)->GetMethodID(env, boolean_clazz, "booleanValue", "()Z");
|
||||
jboolean val = (*env)->CallBooleanMethod(env, obj, boolean_methodID);
|
||||
out = JS_NewBool(ctx, val);
|
||||
} else if ((*env)->IsInstanceOf(env, obj, double_clazz)) {
|
||||
jmethodID double_methodID = (*env)->GetMethodID(env, double_clazz, "doubleValue", "()D");
|
||||
jdouble val = (*env)->CallDoubleMethod(env, obj, double_methodID);
|
||||
out = JS_NewFloat64(ctx, val);
|
||||
} else if ((*env)->IsInstanceOf(env, obj, array_clazz)) {
|
||||
out = JS_NewArray(ctx);
|
||||
|
||||
int length = (*env)->GetArrayLength(env, (jobjectArray) obj);
|
||||
for (uint32_t i = 0; i < length; i++) {
|
||||
JS_SetPropertyUint32(ctx, out, i, java_object_to_js_object(env, ctx, (*env)->GetObjectArrayElement(env, obj, i)));
|
||||
}
|
||||
} else {
|
||||
java_object_data *data = js_mallocz(ctx, sizeof (java_object_data));
|
||||
data->obj = (*env)->NewGlobalRef(env, obj);
|
||||
out = JS_NewObjectClass(ctx, JS_CLASS_JAVA_OBJECT_ID);
|
||||
JS_SetOpaque(out, data);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static jobject js_object_to_java_object(JNIEnv *env, JSContext *ctx, JSValue input) {
|
||||
jobject obj = NULL;
|
||||
if (JS_IsBool(input)) {
|
||||
int val = JS_ToBool(ctx, input);
|
||||
|
||||
jclass boolean_clazz = (*env)->FindClass(env, "java/lang/Boolean");
|
||||
jmethodID methodID = (*env)->GetMethodID(env, boolean_clazz, "<init>", "(Z)V");
|
||||
obj = (*env)->NewObject(env, boolean_clazz, methodID, val);
|
||||
} else if (JS_IsNumber(input)) {
|
||||
double val;
|
||||
JS_ToFloat64(ctx, &val, input);
|
||||
|
||||
jclass double_clazz = (*env)->FindClass(env, "java/lang/Double");
|
||||
jmethodID methodID = (*env)->GetMethodID(env, double_clazz, "<init>", "(D)V");
|
||||
obj = (*env)->NewObject(env, double_clazz, methodID, val);
|
||||
} else if (JS_IsString(input)) {
|
||||
const char *val = JS_ToCString(ctx, input);
|
||||
obj = (*env)->NewStringUTF(env, val);
|
||||
JS_FreeCString(ctx, val);
|
||||
} else if (JS_IsArray(ctx, input)) {
|
||||
uint32_t length;
|
||||
|
||||
JSValue js_length = JS_GetPropertyStr(ctx, input, "length");
|
||||
JS_ToUint32(ctx, &length, js_length);
|
||||
JS_FreeValue(ctx, js_length);
|
||||
|
||||
jclass obj_clazz = (*env)->FindClass(env, "java/lang/Object");
|
||||
jobjectArray arr = (*env)->NewObjectArray(env, length, obj_clazz, NULL);
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
JSValue element = JS_GetPropertyUint32(ctx, input, i);
|
||||
jobject obj = js_object_to_java_object(env, ctx, element);
|
||||
(*env)->SetObjectArrayElement(env, arr, i - 1, obj);
|
||||
(*env)->DeleteLocalRef(env, obj);
|
||||
JS_FreeValue(ctx, element);
|
||||
}
|
||||
|
||||
obj = arr;
|
||||
} else {
|
||||
java_object_data *data = JS_GetOpaque(input, JS_CLASS_JAVA_OBJECT_ID);
|
||||
if (data) {
|
||||
obj = (*env)->NewLocalRef(env, data->obj);
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
static JSValue js_bridge(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
|
||||
JNIEnv *env;
|
||||
(*jvm)->AttachCurrentThread(jvm, (void **) &env, NULL);
|
||||
|
||||
jclass obj_clazz = (*env)->FindClass(env, "java/lang/Object");
|
||||
jobjectArray arr = (*env)->NewObjectArray(env, argc - 1, obj_clazz, NULL);
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
jobject obj = js_object_to_java_object(env, ctx, argv[i]);
|
||||
(*env)->SetObjectArrayElement(env, arr, i - 1, obj);
|
||||
(*env)->DeleteLocalRef(env, obj);
|
||||
}
|
||||
|
||||
jclass clazz = (*env)->FindClass(env, "com/thebrokenrail/scriptcraft/bridge/Bridges");
|
||||
jmethodID methodID = (*env)->GetStaticMethodID(env, clazz, "useBridge", "(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/Object;");
|
||||
|
||||
const char *js_bridge_name = JS_ToCString(ctx, argv[0]);
|
||||
jstring bridge_name = (*env)->NewStringUTF(env, js_bridge_name);
|
||||
|
||||
jobject out = (*env)->CallStaticObjectMethod(env, clazz, methodID, bridge_name, arr);
|
||||
|
||||
(*env)->DeleteLocalRef(env, bridge_name);
|
||||
(*env)->DeleteLocalRef(env, arr);
|
||||
|
||||
JSValue js_out;
|
||||
if (out) {
|
||||
js_out = java_object_to_js_object(env, ctx, out);
|
||||
(*env)->DeleteLocalRef(env, out);
|
||||
} else {
|
||||
jthrowable err = (*env)->ExceptionOccurred(env);
|
||||
if (err) {
|
||||
jmethodID to_string = (*env)->GetMethodID(env, (*env)->FindClass(env, "java/lang/Object"), "toString", "()Ljava/lang/String;");
|
||||
jstring java_string = (jstring) (*env)->CallObjectMethod(env, err, to_string);
|
||||
const char *str = (*env)->GetStringUTFChars(env, java_string, 0);
|
||||
|
||||
js_out = JS_ThrowReferenceError(ctx, "unable to use bridge '%s': %s", js_bridge_name, str);
|
||||
|
||||
(*env)->ExceptionClear(env);
|
||||
} else {
|
||||
js_out = JS_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
JS_FreeCString(ctx, js_bridge_name);
|
||||
|
||||
(*jvm)->DetachCurrentThread(jvm);
|
||||
|
||||
return js_out;
|
||||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL Java_com_thebrokenrail_scriptcraft_quickjs_QuickJS_bridge(JNIEnv *env, jobject this_val, jstring bridge_name, jobjectArray arr) {
|
||||
JSContext *ctx = (JSContext *) get_pointer(env, this_val, "ctx");
|
||||
|
||||
int length = (*env)->GetArrayLength(env, arr);
|
||||
JSValue args[length];
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
args[i] = java_object_to_js_object(env, ctx, (*env)->GetObjectArrayElement(env, arr, i));
|
||||
}
|
||||
|
||||
JSValue global_obj = JS_GetGlobalObject(ctx);
|
||||
JSValue scriptcraft_obj = JS_GetPropertyStr(ctx, global_obj, "__scriptcraft__");
|
||||
JSValue bridges = JS_GetPropertyStr(ctx, scriptcraft_obj, "bridges");
|
||||
|
||||
const char *native_string = (*env)->GetStringUTFChars(env, bridge_name, 0);
|
||||
JSValue bridge = JS_GetPropertyStr(ctx, bridges, native_string);
|
||||
(*env)->ReleaseStringUTFChars(env, bridge_name, native_string);
|
||||
|
||||
JSValue out;
|
||||
if (JS_IsFunction(ctx, bridge)) {
|
||||
out = JS_Call(ctx, bridge, global_obj, length, args);
|
||||
if (JS_IsException(out)) {
|
||||
js_std_dump_error(ctx);
|
||||
out = JS_NULL;
|
||||
}
|
||||
} else {
|
||||
out = JS_NULL;
|
||||
throw_exception(env, "Invalid Bridge");
|
||||
}
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
JS_FreeValue(ctx, args[i]);
|
||||
}
|
||||
|
||||
JS_FreeValue(ctx, bridge);
|
||||
JS_FreeValue(ctx, bridges);
|
||||
JS_FreeValue(ctx, scriptcraft_obj);
|
||||
JS_FreeValue(ctx, global_obj);
|
||||
|
||||
jobject java_out = js_object_to_java_object(env, ctx, out);
|
||||
JS_FreeValue(ctx, out);
|
||||
|
||||
return java_out;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_thebrokenrail_scriptcraft_quickjs_QuickJS_init(JNIEnv *env, jobject this_val) {
|
||||
jint rc = (*env)->GetJavaVM(env, &jvm);
|
||||
if (rc != JNI_OK) {
|
||||
throw_exception(env, "qjs: unable to cache JavaVM");
|
||||
return;
|
||||
}
|
||||
|
||||
JSRuntime *rt = JS_NewRuntime();
|
||||
if (!rt) {
|
||||
throw_exception(env, "qjs: cannot allocate JS runtime");
|
||||
return;
|
||||
}
|
||||
JSContext *ctx = JS_NewContext(rt);
|
||||
if (!ctx) {
|
||||
throw_exception(env, "qjs: cannot allocate JS context");
|
||||
return;
|
||||
}
|
||||
|
||||
JS_SetModuleLoaderFunc(rt, js_module_normalize_name, js_module_loader, NULL);
|
||||
|
||||
js_console_init(ctx);
|
||||
|
||||
JSValue global_obj = JS_GetGlobalObject(ctx);
|
||||
|
||||
JSValue scriptcraft_obj = JS_NewObject(ctx);
|
||||
JS_SetPropertyStr(ctx, scriptcraft_obj, "bridges", JS_NewObject(ctx));
|
||||
JS_SetPropertyStr(ctx, scriptcraft_obj, "useBridge", JS_NewCFunction(ctx, js_bridge, "useBridge", 1));
|
||||
JS_SetPropertyStr(ctx, global_obj, "__scriptcraft__", scriptcraft_obj);
|
||||
|
||||
JS_FreeValue(ctx, global_obj);
|
||||
|
||||
JS_NewClassID(&JS_CLASS_JAVA_OBJECT_ID);
|
||||
JS_NewClass(JS_GetRuntime(ctx), JS_CLASS_JAVA_OBJECT_ID, &JS_CLASS_JAVA_OBJECT);
|
||||
JS_SetClassProto(ctx, JS_CLASS_JAVA_OBJECT_ID, JS_NewObject(ctx));
|
||||
|
||||
set_pointer(env, this_val, "rt", rt);
|
||||
set_pointer(env, this_val, "ctx", ctx);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_thebrokenrail_scriptcraft_quickjs_QuickJS_free(JNIEnv *env, jobject this_val) {
|
||||
JSContext *ctx = (JSContext *) get_pointer(env, this_val, "ctx");
|
||||
JSRuntime *rt = (JSRuntime *) get_pointer(env, this_val, "rt");
|
||||
|
||||
JS_FreeContext(ctx);
|
||||
JS_FreeRuntime(rt);
|
||||
}
|
||||
|
||||
static int eval_buf(JNIEnv *env, JSContext *ctx, const void *buf, int buf_len, const char *filename, int eval_flags) {
|
||||
JSValue val;
|
||||
int ret;
|
||||
|
||||
if ((eval_flags & JS_EVAL_TYPE_MASK) == JS_EVAL_TYPE_MODULE) {
|
||||
/* for the modules, we compile then run to be able to set
|
||||
import.meta */
|
||||
val = JS_Eval(ctx, buf, buf_len, filename, eval_flags | JS_EVAL_FLAG_COMPILE_ONLY);
|
||||
if (!JS_IsException(val)) {
|
||||
js_module_set_import_meta(ctx, val, TRUE, TRUE);
|
||||
val = JS_EvalFunction(ctx, val);
|
||||
}
|
||||
} else {
|
||||
val = JS_Eval(ctx, buf, buf_len, filename, eval_flags);
|
||||
}
|
||||
if (JS_IsException(val)) {
|
||||
js_std_dump_error(ctx);
|
||||
ret = -1;
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
JS_FreeValue(ctx, val);
|
||||
return ret;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_thebrokenrail_scriptcraft_quickjs_QuickJS_run(JNIEnv *env, jobject this_val, jstring data) {
|
||||
JSContext *ctx = (JSContext *) get_pointer(env, this_val, "ctx");
|
||||
|
||||
const char *native_string = (*env)->GetStringUTFChars(env, data, 0);
|
||||
eval_buf(env, ctx, native_string, strlen(native_string), "<init>", JS_EVAL_TYPE_MODULE);
|
||||
(*env)->ReleaseStringUTFChars(env, data, native_string);
|
||||
}
|
||||
|
||||
void print_data(char *data, int err) {
|
||||
JNIEnv *env;
|
||||
(*jvm)->AttachCurrentThread(jvm, (void **) &env, NULL);
|
||||
|
||||
jclass clazz = (*env)->FindClass(env, "com/thebrokenrail/scriptcraft/quickjs/QuickJS");
|
||||
jmethodID print_methodID = (*env)->GetStaticMethodID(env, clazz, "print", "(Ljava/lang/String;Z)V");
|
||||
jstring str = (*env)->NewStringUTF(env, data);
|
||||
(*env)->CallStaticVoidMethod(env, clazz, print_methodID, str, err);
|
||||
(*env)->DeleteLocalRef(env, str);
|
||||
|
||||
(*jvm)->DetachCurrentThread(jvm);
|
||||
}
|
47
src/main/c/com_thebrokenrail_scriptcraft_quickjs_QuickJS.h
Normal file
47
src/main/c/com_thebrokenrail_scriptcraft_quickjs_QuickJS.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||
#include <jni.h>
|
||||
/* Header for class com_thebrokenrail_scriptcraft_quickjs_QuickJS */
|
||||
|
||||
#ifndef _Included_com_thebrokenrail_scriptcraft_quickjs_QuickJS
|
||||
#define _Included_com_thebrokenrail_scriptcraft_quickjs_QuickJS
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*
|
||||
* Class: com_thebrokenrail_scriptcraft_quickjs_QuickJS
|
||||
* Method: init
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_com_thebrokenrail_scriptcraft_quickjs_QuickJS_init
|
||||
(JNIEnv *, jobject);
|
||||
|
||||
/*
|
||||
* Class: com_thebrokenrail_scriptcraft_quickjs_QuickJS
|
||||
* Method: free
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_com_thebrokenrail_scriptcraft_quickjs_QuickJS_free
|
||||
(JNIEnv *, jobject);
|
||||
|
||||
/*
|
||||
* Class: com_thebrokenrail_scriptcraft_quickjs_QuickJS
|
||||
* Method: bridge
|
||||
* Signature: (Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/Object;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_com_thebrokenrail_scriptcraft_quickjs_QuickJS_bridge
|
||||
(JNIEnv *, jobject, jstring, jobjectArray);
|
||||
|
||||
/*
|
||||
* Class: com_thebrokenrail_scriptcraft_quickjs_QuickJS
|
||||
* Method: run
|
||||
* Signature: (Ljava/lang/String;Ljava/lang/String;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_com_thebrokenrail_scriptcraft_quickjs_QuickJS_run
|
||||
(JNIEnv *, jobject, jstring);
|
||||
|
||||
void print_data(char *data, int err);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
119
src/main/c/console.c
Normal file
119
src/main/c/console.c
Normal file
|
@ -0,0 +1,119 @@
|
|||
#include "asprintf.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <quickjs.h>
|
||||
|
||||
#include "com_thebrokenrail_scriptcraft_quickjs_QuickJS.h"
|
||||
|
||||
static JSValue js_print_internal(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int err, int prepend_throw) {
|
||||
int i;
|
||||
char *out;
|
||||
if (prepend_throw) {
|
||||
out = "Throw: ";
|
||||
} else {
|
||||
out = "";
|
||||
}
|
||||
const char *str;
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
if (i != 0) {
|
||||
asprintf(&out, "%s ", out);
|
||||
}
|
||||
str = JS_ToCString(ctx, argv[i]);
|
||||
if (!str) {
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
asprintf(&out, "%s%s", out, str);
|
||||
JS_FreeCString(ctx, str);
|
||||
}
|
||||
print_data(out, err);
|
||||
free(out);
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
static JSValue js_print(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
|
||||
return js_print_internal(ctx, this_val, argc, argv, 0, 0);
|
||||
}
|
||||
|
||||
static JSValue js_print_err(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
|
||||
return js_print_internal(ctx, this_val, argc, argv, 1, 0);
|
||||
}
|
||||
|
||||
static JSValue js_assert(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
|
||||
int i;
|
||||
const char *str;
|
||||
|
||||
if (argc < 1) {
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
int bool_val = JS_ToBool(ctx, argv[0]);
|
||||
if (bool_val == -1) {
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
|
||||
if (!bool_val) {
|
||||
char *out = "Assertion failed";
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (i != 1) {
|
||||
asprintf(&out, "%s ", out);
|
||||
} else {
|
||||
asprintf(&out, "%s: ", out);
|
||||
}
|
||||
str = JS_ToCString(ctx, argv[i]);
|
||||
if (!str) {
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
asprintf(&out, "%s%s", out, str);
|
||||
JS_FreeCString(ctx, str);
|
||||
}
|
||||
print_data(out, 1);
|
||||
free(out);
|
||||
}
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
static const JSCFunctionListEntry js_console_funcs[] = {
|
||||
JS_CFUNC_DEF("log", 1, js_print),
|
||||
JS_CFUNC_DEF("info", 1, js_print),
|
||||
JS_CFUNC_DEF("warn", 1, js_print),
|
||||
JS_CFUNC_DEF("error", 1, js_print_err),
|
||||
JS_CFUNC_DEF("dir", 1, js_print),
|
||||
JS_CFUNC_DEF("debug", 1, js_print),
|
||||
JS_CFUNC_DEF("trace", 1, js_print),
|
||||
JS_CFUNC_DEF("assert", 1, js_assert),
|
||||
JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Console", JS_PROP_CONFIGURABLE)
|
||||
};
|
||||
|
||||
void js_console_init(JSContext *ctx) {
|
||||
JSValue global_obj, console;
|
||||
|
||||
/* XXX: should t |