This commit is contained in:
parent
96bc39c035
commit
1c1563bbbf
@ -6,7 +6,7 @@ To communicate between Java and JS code, ScriptCraft utilizes a system called br
|
||||
### Define The Bridge
|
||||
```java
|
||||
import com.thebrokenrail.scriptcraft.core.ScriptCraftCore;
|
||||
import com.thebrokenrail.scriptcraft.core.ScriptCraftEntryPoint;
|
||||
import com.thebrokenrail.scriptcraft.core.util.ScriptCraftEntryPoint;
|
||||
|
||||
public class ExampleBridges implements ScriptCraftEntryPoint {
|
||||
@Override
|
||||
|
@ -3,7 +3,7 @@ To add an entry-point to your mod create a class implementing ```ScriptCraftEntr
|
||||
|
||||
## Example
|
||||
```java
|
||||
import com.thebrokenrail.scriptcraft.core.ScriptCraftEntryPoint;
|
||||
import com.thebrokenrail.scriptcraft.core.util.ScriptCraftEntryPoint;
|
||||
|
||||
public class ExampleMod implements ScriptCraftEntryPoint {
|
||||
@Override
|
||||
|
@ -98,11 +98,11 @@ class ScriptCraftPlugin : Plugin<Project> {
|
||||
}
|
||||
|
||||
val npmInstallTask = tasks.register<NPMInstallTask>("npmInstall") {
|
||||
group = "typescript"
|
||||
group = "scriptcraft"
|
||||
}
|
||||
|
||||
val extractTypescriptDependenciesTask = tasks.register<Sync>("extractTypescriptDependencies") {
|
||||
group = "typescript"
|
||||
group = "scriptcraft"
|
||||
|
||||
dependsOn(typescript)
|
||||
|
||||
@ -127,14 +127,14 @@ class ScriptCraftPlugin : Plugin<Project> {
|
||||
}
|
||||
|
||||
val typescriptTask = tasks.register<NPMTask>("typescript") {
|
||||
group = "typescript"
|
||||
group = "scriptcraft"
|
||||
|
||||
taskName = "build"
|
||||
outputDir = "build/ts"
|
||||
}
|
||||
|
||||
val apiJarTask = tasks.register<Jar>("apiJar") {
|
||||
group = "typescript"
|
||||
group = "scriptcraft"
|
||||
|
||||
into("/types") {
|
||||
from(Callable {
|
||||
|
@ -9,6 +9,12 @@
|
||||
#include "com_thebrokenrail_scriptcraft_core_quickjs_QuickJSNative.h"
|
||||
#include "console.h"
|
||||
|
||||
typedef struct {
|
||||
JSContext *ctx;
|
||||
JSRuntime *rt;
|
||||
JSValue bridges;
|
||||
} scriptcraft_ctx;
|
||||
|
||||
static JavaVM *jvm;
|
||||
|
||||
static const jint JNI_VERSION = JNI_VERSION_1_6;
|
||||
@ -287,16 +293,13 @@ static jobject js_object_to_java_object(JNIEnv *env, JSContext *ctx, JSValue inp
|
||||
}
|
||||
|
||||
static JSValue js_add_bridge(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
|
||||
JSValue global_obj = JS_GetGlobalObject(ctx);
|
||||
JSValue scriptcraft_obj = JS_GetPropertyStr(ctx, global_obj, "__scriptcraft_bridges__");
|
||||
scriptcraft_ctx *data = JS_GetContextOpaque(ctx);
|
||||
JSValue scriptcraft_obj = data->bridges;
|
||||
|
||||
const char *name = JS_ToCString(ctx, argv[0]);
|
||||
JS_SetPropertyStr(ctx, scriptcraft_obj, name, JS_DupValue(ctx, argv[1]));
|
||||
JS_FreeCString(ctx, name);
|
||||
|
||||
JS_FreeValue(ctx, scriptcraft_obj);
|
||||
JS_FreeValue(ctx, global_obj);
|
||||
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
@ -331,7 +334,8 @@ static JSValue js_use_bridge(JSContext *ctx, JSValueConst this_val, int argc, JS
|
||||
} else {
|
||||
jthrowable err = (*env)->ExceptionOccurred(env);
|
||||
if (err) {
|
||||
jmethodID to_string = (*env)->GetMethodID(env, (*env)->FindClass(env, "java/lang/Object"), "toString", "()Ljava/lang/String;");
|
||||
jclass exception_clazz = (*env)->FindClass(env, "com/thebrokenrail/scriptcraft/core/quickjs/JSException");
|
||||
jmethodID to_string = (*env)->GetMethodID(env, exception_clazz, "getStackTrace", "(Ljava/lang/Throwable;)Ljava/lang/String;");
|
||||
jstring java_string = (jstring) (*env)->CallObjectMethod(env, err, to_string);
|
||||
const char *str = (*env)->GetStringUTFChars(env, java_string, 0);
|
||||
|
||||
@ -350,7 +354,9 @@ static JSValue js_use_bridge(JSContext *ctx, JSValueConst this_val, int argc, JS
|
||||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL Java_com_thebrokenrail_scriptcraft_core_quickjs_QuickJSNative_bridge(JNIEnv *env, jobject this_val, jstring bridge_name, jobjectArray arr) {
|
||||
JSContext *ctx = (JSContext *) get_pointer(env, this_val, "ctx");
|
||||
scriptcraft_ctx *data = (scriptcraft_ctx *) get_pointer(env, this_val, "data");
|
||||
|
||||
JSContext *ctx = data->ctx;
|
||||
|
||||
int length = (*env)->GetArrayLength(env, arr);
|
||||
JSValue args[length];
|
||||
@ -359,15 +365,16 @@ JNIEXPORT jobject JNICALL Java_com_thebrokenrail_scriptcraft_core_quickjs_QuickJ
|
||||
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_bridges__");
|
||||
JSValue scriptcraft_obj = data->bridges;
|
||||
|
||||
const char *native_string = (*env)->GetStringUTFChars(env, bridge_name, 0);
|
||||
JSValue bridge = JS_GetPropertyStr(ctx, scriptcraft_obj, native_string);
|
||||
|
||||
JSValue out;
|
||||
if (JS_IsFunction(ctx, bridge)) {
|
||||
JSValue global_obj = JS_GetGlobalObject(ctx);
|
||||
out = JS_Call(ctx, bridge, global_obj, length, args);
|
||||
JS_FreeValue(ctx, global_obj);
|
||||
if (JS_IsException(out)) {
|
||||
js_std_dump_error(ctx);
|
||||
out = JS_NULL;
|
||||
@ -387,8 +394,6 @@ JNIEXPORT jobject JNICALL Java_com_thebrokenrail_scriptcraft_core_quickjs_QuickJ
|
||||
}
|
||||
|
||||
JS_FreeValue(ctx, bridge);
|
||||
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);
|
||||
@ -403,12 +408,6 @@ static int scriptcraft_core_init(JSContext *ctx, JSModuleDef *m) {
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_thebrokenrail_scriptcraft_core_quickjs_QuickJSNative_init(JNIEnv *env, jobject this_val) {
|
||||
jint rc = (*env)->GetJavaVM(env, &jvm);
|
||||
if (rc != JNI_OK) {
|
||||
throw_exception(env, "Unable To Cache JavaVM");
|
||||
return;
|
||||
}
|
||||
|
||||
JSRuntime *rt = JS_NewRuntime();
|
||||
if (!rt) {
|
||||
throw_exception(env, "Cannot Allocate JS Runtime");
|
||||
@ -417,6 +416,7 @@ JNIEXPORT void JNICALL Java_com_thebrokenrail_scriptcraft_core_quickjs_QuickJSNa
|
||||
JSContext *ctx = JS_NewContext(rt);
|
||||
if (!ctx) {
|
||||
throw_exception(env, "Cannot Allocate JS Context");
|
||||
JS_FreeRuntime(rt);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -431,26 +431,33 @@ JNIEXPORT void JNICALL Java_com_thebrokenrail_scriptcraft_core_quickjs_QuickJSNa
|
||||
JSModuleDef *m = JS_NewCModule(ctx, "scriptcraft-core", scriptcraft_core_init);
|
||||
if (!m) {
|
||||
throw_exception(env, "Unable To Allocate C Module");
|
||||
JS_FreeContext(ctx);
|
||||
JS_FreeRuntime(rt);
|
||||
return;
|
||||
}
|
||||
|
||||
JS_AddModuleExport(ctx, m, "useBridge");
|
||||
JS_AddModuleExport(ctx, m, "addBridge");
|
||||
|
||||
JSValue global_obj = JS_GetGlobalObject(ctx);
|
||||
JS_SetPropertyStr(ctx, global_obj, "__scriptcraft_bridges__", JS_NewObject(ctx));
|
||||
JS_FreeValue(ctx, global_obj);
|
||||
scriptcraft_ctx *data = malloc(sizeof (scriptcraft_ctx));
|
||||
data->ctx = ctx;
|
||||
data->rt = rt;
|
||||
data->bridges = JS_NewObject(ctx);
|
||||
|
||||
set_pointer(env, this_val, "rt", rt);
|
||||
set_pointer(env, this_val, "ctx", ctx);
|
||||
set_pointer(env, this_val, "data", data);
|
||||
|
||||
JS_SetContextOpaque(ctx, data);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_thebrokenrail_scriptcraft_core_quickjs_QuickJSNative_free(JNIEnv *env, jobject this_val) {
|
||||
JSContext *ctx = (JSContext *) get_pointer(env, this_val, "ctx");
|
||||
JSRuntime *rt = (JSRuntime *) get_pointer(env, this_val, "rt");
|
||||
scriptcraft_ctx *data = (scriptcraft_ctx *) get_pointer(env, this_val, "data");
|
||||
|
||||
JS_FreeContext(ctx);
|
||||
JS_FreeRuntime(rt);
|
||||
JS_FreeValue(data->ctx, data->bridges);
|
||||
|
||||
JS_FreeContext(data->ctx);
|
||||
JS_FreeRuntime(data->rt);
|
||||
|
||||
free(data);
|
||||
}
|
||||
|
||||
static int eval_buf(JNIEnv *env, JSContext *ctx, const void *buf, int buf_len, const char *filename, int eval_flags) {
|
||||
@ -479,7 +486,7 @@ static int eval_buf(JNIEnv *env, JSContext *ctx, const void *buf, int buf_len, c
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_thebrokenrail_scriptcraft_core_quickjs_QuickJSNative_run(JNIEnv *env, jobject this_val, jstring data) {
|
||||
JSContext *ctx = (JSContext *) get_pointer(env, this_val, "ctx");
|
||||
JSContext *ctx = ((scriptcraft_ctx *) get_pointer(env, this_val, "data"))->ctx;
|
||||
|
||||
JSValue module_name, json_str;
|
||||
char *init_js;
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.thebrokenrail.scriptcraft.api;
|
||||
|
||||
import com.thebrokenrail.scriptcraft.api.bridge.Bridges;
|
||||
import com.thebrokenrail.scriptcraft.core.ScriptCraftEntryPoint;
|
||||
import com.thebrokenrail.scriptcraft.core.util.ScriptCraftEntryPoint;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class ScriptCraftAPI implements ScriptCraftEntryPoint {
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.thebrokenrail.scriptcraft.api.block;
|
||||
|
||||
import com.thebrokenrail.scriptcraft.core.ScriptCraftCore;
|
||||
import com.thebrokenrail.scriptcraft.core.ValueUtil;
|
||||
import com.thebrokenrail.scriptcraft.api.util.ValueUtil;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.thebrokenrail.scriptcraft.api.bridge;
|
||||
|
||||
import com.thebrokenrail.scriptcraft.core.ScriptCraftCore;
|
||||
import com.thebrokenrail.scriptcraft.core.ValueUtil;
|
||||
import com.thebrokenrail.scriptcraft.api.util.ValueUtil;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.damage.DamageSource;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.thebrokenrail.scriptcraft.api.bridge;
|
||||
|
||||
import com.thebrokenrail.scriptcraft.core.ScriptCraftCore;
|
||||
import com.thebrokenrail.scriptcraft.core.ValueUtil;
|
||||
import com.thebrokenrail.scriptcraft.api.util.ValueUtil;
|
||||
import net.fabricmc.fabric.api.event.player.AttackBlockCallback;
|
||||
import net.fabricmc.fabric.api.event.player.UseBlockCallback;
|
||||
import net.fabricmc.fabric.api.event.player.UseItemCallback;
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.thebrokenrail.scriptcraft.api.bridge;
|
||||
|
||||
import com.thebrokenrail.scriptcraft.core.ScriptCraftCore;
|
||||
import com.thebrokenrail.scriptcraft.core.ValueUtil;
|
||||
import com.thebrokenrail.scriptcraft.api.util.ValueUtil;
|
||||
import net.minecraft.inventory.Inventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.thebrokenrail.scriptcraft.api.bridge;
|
||||
|
||||
import com.thebrokenrail.scriptcraft.core.ScriptCraftCore;
|
||||
import com.thebrokenrail.scriptcraft.core.ValueUtil;
|
||||
import com.thebrokenrail.scriptcraft.api.util.ValueUtil;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.thebrokenrail.scriptcraft.api.bridge;
|
||||
|
||||
import com.thebrokenrail.scriptcraft.core.ScriptCraftCore;
|
||||
import com.thebrokenrail.scriptcraft.core.ValueUtil;
|
||||
import com.thebrokenrail.scriptcraft.api.util.ValueUtil;
|
||||
import net.minecraft.nbt.AbstractListTag;
|
||||
import net.minecraft.nbt.AbstractNumberTag;
|
||||
import net.minecraft.nbt.ByteTag;
|
||||
|
@ -2,7 +2,7 @@ package com.thebrokenrail.scriptcraft.api.bridge;
|
||||
|
||||
import com.thebrokenrail.scriptcraft.api.block.CustomBlockEntity;
|
||||
import com.thebrokenrail.scriptcraft.core.ScriptCraftCore;
|
||||
import com.thebrokenrail.scriptcraft.core.ValueUtil;
|
||||
import com.thebrokenrail.scriptcraft.api.util.ValueUtil;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.entity.Entity;
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.thebrokenrail.scriptcraft.api.item;
|
||||
|
||||
import com.thebrokenrail.scriptcraft.core.ScriptCraftCore;
|
||||
import com.thebrokenrail.scriptcraft.core.ValueUtil;
|
||||
import com.thebrokenrail.scriptcraft.api.util.ValueUtil;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.Item;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.thebrokenrail.scriptcraft.core;
|
||||
package com.thebrokenrail.scriptcraft.api.util;
|
||||
|
||||
import java.util.Locale;
|
||||
|
@ -3,12 +3,13 @@ package com.thebrokenrail.scriptcraft.core;
|
||||
import com.thebrokenrail.scriptcraft.core.quickjs.JSException;
|
||||
import com.thebrokenrail.scriptcraft.core.quickjs.QuickJSNative;
|
||||
import com.thebrokenrail.scriptcraft.core.quickjs.QuickJSManager;
|
||||
import com.thebrokenrail.scriptcraft.core.util.Bridge;
|
||||
import com.thebrokenrail.scriptcraft.core.util.ScriptCraftEntryPoint;
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class ScriptCraftCore implements ModInitializer {
|
||||
@ -43,7 +44,6 @@ public class ScriptCraftCore implements ModInitializer {
|
||||
}
|
||||
|
||||
public static final String NAMESPACE = "scriptcraft";
|
||||
public static final Pattern MOD_ID_PATTERN = Pattern.compile("[a-z][a-z0-9-_]{1,63}");
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
|
@ -1,7 +1,17 @@
|
||||
package com.thebrokenrail.scriptcraft.core.quickjs;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
||||
public class JSException extends Exception {
|
||||
public JSException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public String getStackTrace(Throwable e) {
|
||||
StringWriter writer = new StringWriter();
|
||||
e.printStackTrace(new PrintWriter(writer));
|
||||
return writer.toString();
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
package com.thebrokenrail.scriptcraft.core.quickjs;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@ -39,7 +41,7 @@ public class QuickJSManager {
|
||||
}
|
||||
}
|
||||
if (task.err) {
|
||||
throw new RuntimeException("Java Exception While Executing Task");
|
||||
throw new RuntimeException("Java Exception While Executing Task: " + task.obj);
|
||||
} else {
|
||||
return task.obj;
|
||||
}
|
||||
@ -153,7 +155,7 @@ public class QuickJSManager {
|
||||
if (task.lastTask) {
|
||||
return null;
|
||||
} else {
|
||||
while (true) {
|
||||
do {
|
||||
try {
|
||||
lock.wait();
|
||||
} catch (InterruptedException e) {
|
||||
@ -165,18 +167,16 @@ public class QuickJSManager {
|
||||
outputTask.obj = outputTask.run(null);
|
||||
outputTask.err = false;
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
outputTask.obj = null;
|
||||
StringWriter writer = new StringWriter();
|
||||
e.printStackTrace(new PrintWriter(writer));
|
||||
outputTask.obj = writer.toString();
|
||||
outputTask.err = true;
|
||||
}
|
||||
outputTask.done = true;
|
||||
quickJSOutputTask.set(outputTask);
|
||||
}
|
||||
lock.notifyAll();
|
||||
if (task.done) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (!task.done);
|
||||
}
|
||||
lock.set(false);
|
||||
return task.obj;
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.thebrokenrail.scriptcraft.core.quickjs;
|
||||
|
||||
import com.thebrokenrail.scriptcraft.core.ScriptCraftCore;
|
||||
import com.thebrokenrail.scriptcraft.core.ScriptCraftEntryPoint;
|
||||
import com.thebrokenrail.scriptcraft.core.util.ScriptCraftEntryPoint;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
|
@ -1,6 +1,6 @@
|
||||
package com.thebrokenrail.scriptcraft.core.quickjs;
|
||||
|
||||
import com.thebrokenrail.scriptcraft.core.OSUtil;
|
||||
import com.thebrokenrail.scriptcraft.core.util.OSUtil;
|
||||
import com.thebrokenrail.scriptcraft.core.ScriptCraftCore;
|
||||
|
||||
import java.io.File;
|
||||
@ -9,14 +9,13 @@ import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class QuickJSNative {
|
||||
public QuickJSNative() throws JSException {
|
||||
init();
|
||||
}
|
||||
|
||||
private long ctx;
|
||||
private long rt;
|
||||
@SuppressWarnings("unused")
|
||||
private long data;
|
||||
|
||||
public native void init() throws JSException;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.thebrokenrail.scriptcraft.core;
|
||||
package com.thebrokenrail.scriptcraft.core.util;
|
||||
|
||||
public interface Bridge {
|
||||
Object use(Object... args);
|
@ -1,4 +1,4 @@
|
||||
package com.thebrokenrail.scriptcraft.core;
|
||||
package com.thebrokenrail.scriptcraft.core.util;
|
||||
|
||||
import java.util.Locale;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.thebrokenrail.scriptcraft.core;
|
||||
package com.thebrokenrail.scriptcraft.core.util;
|
||||
|
||||
public interface ScriptCraftEntryPoint {
|
||||
String getEntryPoint();
|
Reference in New Issue
Block a user