diff --git a/docs/JAVA_OBJECT_WRAPPERS.md b/docs/JAVA_OBJECT_WRAPPERS.md new file mode 100644 index 0000000..23b7b2b --- /dev/null +++ b/docs/JAVA_OBJECT_WRAPPERS.md @@ -0,0 +1,7 @@ +# Java Object Wrappers +When the JS environment receives a Java object through a [bridge](BRIDGES.md), it is converted into a ```JavaObject```. A ```JavaObject``` cannot be used directly in the JS environment, but it can be stored and passed back to the Java environment using another [bridge](BRIDGES.md). + +To make interacting wit Java object easier, they are placed in a wrapper class. An example of a wrapper class is ```World```, it can be interacted with like any other JS object, but internally it uses its ```JavaObject``` to execute code in the Java environment. + +## Casting +In Java, if you are given a ```LivingEntity```, you can use ```instanceof``` to check if it is a ```PlayerEntity``` and then cast it. However, because the JS environment only knows the class of the ```JavaObject```'s wrapper, it can't do this. However, you can manually cast a JS object wrapper to another wrapper type using the new wrapper type's constructor, like ```new PlayerEntity(livingEntity);```, if this operation is not possible (ie. The ```LivingEntity``` is not a ```PlayerEntity```), it will throw an ```Error```. \ No newline at end of file diff --git a/docs/README.md b/docs/README.md index d85bb69..8f4e0a2 100644 --- a/docs/README.md +++ b/docs/README.md @@ -7,6 +7,8 @@ [View Architecture](ARCHITECTURE.md) +[View Java Object Wrappers](JAVA_OBJECT_WRAPPERS.md) + [View Tutorials](tutorials/README.md) [View TypeDoc](https://jenkins.thebrokenrail.com/job/ScriptCraft/job/master/TypeDoc/) \ No newline at end of file diff --git a/scriptcraft/src/main/c/com_thebrokenrail_scriptcraft_core_quickjs_QuickJSNative.c b/scriptcraft/src/main/c/com_thebrokenrail_scriptcraft_core_quickjs_QuickJSNative.c index a78495b..5fe8ded 100644 --- a/scriptcraft/src/main/c/com_thebrokenrail_scriptcraft_core_quickjs_QuickJSNative.c +++ b/scriptcraft/src/main/c/com_thebrokenrail_scriptcraft_core_quickjs_QuickJSNative.c @@ -11,6 +11,19 @@ static JavaVM *jvm; +static const jint JNI_VERSION = JNI_VERSION_1_6; + +JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { + jvm = vm; + JNIEnv *env = NULL; + + if (jvm && (*jvm)->GetEnv(jvm, (void **) &env, JNI_VERSION) == JNI_OK) { + return JNI_VERSION; + } else { + return -1; + } +} + static void *get_pointer(JNIEnv *env, jobject obj, const char *name) { jclass clazz = (*env)->FindClass(env, "com/thebrokenrail/scriptcraft/core/quickjs/QuickJSNative"); jfieldID field = (*env)->GetFieldID(env, clazz, name, "J"); @@ -25,7 +38,7 @@ static void set_pointer(JNIEnv *env, jobject obj, const char *name, void *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); + (*jvm)->GetEnv(jvm, (void**) &env, JNI_VERSION); jclass clazz = (*env)->FindClass(env, "com/thebrokenrail/scriptcraft/core/quickjs/QuickJSModules"); jmethodID methodID = (*env)->GetStaticMethodID(env, clazz, "normalizeModule", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"); @@ -43,7 +56,6 @@ static char *js_module_normalize_name(JSContext *ctx, const char *base_name, con (*env)->DeleteLocalRef(env, java_string); - (*jvm)->DetachCurrentThread(jvm); return new_string; } else { jthrowable err = (*env)->ExceptionOccurred(env); @@ -54,11 +66,11 @@ static char *js_module_normalize_name(JSContext *ctx, const char *base_name, con JS_ThrowReferenceError(ctx, "could not normalize module name '%s': %s", name, str); + (*env)->ReleaseStringUTFChars(env, java_string, str); (*env)->ExceptionClear(env); } else { JS_ThrowReferenceError(ctx, "could not normalize module name '%s'", name); } - (*jvm)->DetachCurrentThread(jvm); return NULL; } } @@ -97,7 +109,7 @@ static int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val, JS_B static char *js_load_file(JSContext *ctx, const char *filename) { JNIEnv *env; - (*jvm)->AttachCurrentThread(jvm, (void **) &env, NULL); + (*jvm)->GetEnv(jvm, (void**) &env, JNI_VERSION); jclass clazz = (*env)->FindClass(env, "com/thebrokenrail/scriptcraft/core/quickjs/QuickJSModules"); jmethodID methodID = (*env)->GetStaticMethodID(env, clazz, "loadModule", "(Ljava/lang/String;)Ljava/lang/String;"); @@ -113,7 +125,6 @@ static char *js_load_file(JSContext *ctx, const char *filename) { (*env)->DeleteLocalRef(env, java_string); - (*jvm)->DetachCurrentThread(jvm); return new_string; } else { jthrowable err = (*env)->ExceptionOccurred(env); @@ -124,11 +135,11 @@ static char *js_load_file(JSContext *ctx, const char *filename) { JS_ThrowReferenceError(ctx, "could not load module filename '%s': %s", filename, str); + (*env)->ReleaseStringUTFChars(env, java_string, str); (*env)->ExceptionClear(env); } else { JS_ThrowReferenceError(ctx, "could not load module filename '%s'", filename); } - (*jvm)->DetachCurrentThread(jvm); return NULL; } } @@ -178,12 +189,10 @@ 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); + (*jvm)->GetEnv(jvm, (void**) &env, JNI_VERSION); (*env)->DeleteGlobalRef(env, data->obj); js_free_rt(rt, data); - - (*jvm)->DetachCurrentThread(jvm); } } @@ -293,7 +302,7 @@ static JSValue js_add_bridge(JSContext *ctx, JSValueConst this_val, int argc, JS static JSValue js_use_bridge(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { JNIEnv *env; - (*jvm)->AttachCurrentThread(jvm, (void **) &env, NULL); + (*jvm)->GetEnv(jvm, (void**) &env, JNI_VERSION); jclass obj_clazz = (*env)->FindClass(env, "java/lang/Object"); jobjectArray arr = (*env)->NewObjectArray(env, argc - 1, obj_clazz, NULL); @@ -328,6 +337,7 @@ static JSValue js_use_bridge(JSContext *ctx, JSValueConst this_val, int argc, JS js_out = JS_ThrowReferenceError(ctx, "unable to use bridge '%s': %s", js_bridge_name, str); + (*env)->ReleaseStringUTFChars(env, java_string, str); (*env)->ExceptionClear(env); } else { js_out = JS_NULL; @@ -336,8 +346,6 @@ static JSValue js_use_bridge(JSContext *ctx, JSValueConst this_val, int argc, JS JS_FreeCString(ctx, js_bridge_name); - (*jvm)->DetachCurrentThread(jvm); - return js_out; } @@ -356,7 +364,6 @@ JNIEXPORT jobject JNICALL Java_com_thebrokenrail_scriptcraft_core_quickjs_QuickJ const char *native_string = (*env)->GetStringUTFChars(env, bridge_name, 0); JSValue bridge = JS_GetPropertyStr(ctx, scriptcraft_obj, native_string); - (*env)->ReleaseStringUTFChars(env, bridge_name, native_string); JSValue out; if (JS_IsFunction(ctx, bridge)) { @@ -367,9 +374,14 @@ JNIEXPORT jobject JNICALL Java_com_thebrokenrail_scriptcraft_core_quickjs_QuickJ } } else { out = JS_NULL; - throw_exception(env, "Invalid Bridge"); + char *err; + asprintf(&err, "Invalid Bridge: %s", native_string); + throw_exception(env, err); + free(err); } + (*env)->ReleaseStringUTFChars(env, bridge_name, native_string); + for (int i = 0; i < length; i++) { JS_FreeValue(ctx, args[i]); } @@ -393,18 +405,18 @@ 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, "qjs: unable to cache JavaVM"); + throw_exception(env, "Unable To Cache JavaVM"); return; } JSRuntime *rt = JS_NewRuntime(); if (!rt) { - throw_exception(env, "qjs: cannot allocate JS runtime"); + throw_exception(env, "Cannot Allocate JS Runtime"); return; } JSContext *ctx = JS_NewContext(rt); if (!ctx) { - throw_exception(env, "qjs: cannot allocate JS context"); + throw_exception(env, "Cannot Allocate JS Context"); return; } @@ -418,7 +430,7 @@ 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, "qjs: unable to allocate C module"); + throw_exception(env, "Unable To Allocate C Module"); return; } @@ -492,13 +504,11 @@ JNIEXPORT void JNICALL Java_com_thebrokenrail_scriptcraft_core_quickjs_QuickJSNa void print_data(char *data, int err) { JNIEnv *env; - (*jvm)->AttachCurrentThread(jvm, (void **) &env, NULL); + (*jvm)->GetEnv(jvm, (void**) &env, JNI_VERSION); jclass clazz = (*env)->FindClass(env, "com/thebrokenrail/scriptcraft/core/quickjs/QuickJSNative"); 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); } \ No newline at end of file diff --git a/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/BlockEntityBridges.java b/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/BlockEntityBridges.java index 0ac4211..0a52f0e 100644 --- a/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/BlockEntityBridges.java +++ b/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/BlockEntityBridges.java @@ -22,5 +22,7 @@ class BlockEntityBridges { ((BlockEntity) args[0]).markDirty(); return null; }); + + ScriptCraftCore.addBridge("BlockEntity.isValid", args -> args[0] instanceof BlockEntity); } } diff --git a/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/BlockStateBridges.java b/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/BlockStateBridges.java index 8147c93..bf86a4d 100644 --- a/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/BlockStateBridges.java +++ b/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/BlockStateBridges.java @@ -9,5 +9,7 @@ class BlockStateBridges { static void register() { ScriptCraftCore.addBridge("BlockState.getDefaultState", args -> Registry.BLOCK.get(new Identifier((String) args[0])).getDefaultState()); ScriptCraftCore.addBridge("BlockState.getBlock", args -> Registry.BLOCK.getId(((BlockState) args[0]).getBlock()).toString()); + + ScriptCraftCore.addBridge("BlockState.isValid", args -> args[0] instanceof BlockState); } } diff --git a/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/DamageSourceBridges.java b/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/DamageSourceBridges.java index f067768..3890179 100644 --- a/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/DamageSourceBridges.java +++ b/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/DamageSourceBridges.java @@ -20,5 +20,7 @@ class DamageSourceBridges { ScriptCraftCore.addBridge("DamageSource.createFromPlayer", args -> DamageSource.player((PlayerEntity) args[1])); ScriptCraftCore.addBridge("DamageSource.createFromMob", args -> DamageSource.mob((LivingEntity) args[1])); + + ScriptCraftCore.addBridge("DamageSource.isValid", args -> args[0] instanceof DamageSource); } } diff --git a/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/EntityBridges.java b/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/EntityBridges.java index 695a2cc..ce40b96 100644 --- a/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/EntityBridges.java +++ b/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/EntityBridges.java @@ -53,5 +53,7 @@ class EntityBridges { ((Entity) args[0]).fromTag((CompoundTag) args[1]); return null; }); + + ScriptCraftCore.addBridge("Entity.isValid", args -> args[0] instanceof Entity); } } diff --git a/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/InventoryBridges.java b/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/InventoryBridges.java index 2b97b01..42e0253 100644 --- a/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/InventoryBridges.java +++ b/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/InventoryBridges.java @@ -15,5 +15,7 @@ class InventoryBridges { }); ScriptCraftCore.addBridge("Inventory.size", args -> ((Inventory) args[0]).getInvSize()); ScriptCraftCore.addBridge("Inventory.getMaxStackSize", args -> ((Inventory) args[0]).getInvMaxStackAmount()); + + ScriptCraftCore.addBridge("Inventory.isValid", args -> args[0] instanceof Inventory); } } diff --git a/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/ItemStackBridges.java b/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/ItemStackBridges.java index 0d39d92..2ced408 100644 --- a/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/ItemStackBridges.java +++ b/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/ItemStackBridges.java @@ -36,5 +36,7 @@ class ItemStackBridges { ScriptCraftCore.addBridge("ItemStack.fromTag", args -> ItemStack.fromTag((CompoundTag) args[1])); ScriptCraftCore.addBridge("ItemStack.split", args -> ((ItemStack) args[0]).split((int) ValueUtil.toDouble(args[1], 0))); + + ScriptCraftCore.addBridge("ItemStack.isValid", args -> args[0] instanceof ItemStack); } } diff --git a/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/LivingEntityBridges.java b/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/LivingEntityBridges.java index 2313c5c..1dd7241 100644 --- a/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/LivingEntityBridges.java +++ b/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/LivingEntityBridges.java @@ -8,5 +8,7 @@ class LivingEntityBridges { static void register() { ScriptCraftCore.addBridge("LivingEntity.getStackInHand", args -> ((LivingEntity) args[0]).getStackInHand((Hand) args[1])); ScriptCraftCore.addBridge("LivingEntity.getHealth", args -> ((LivingEntity) args[0]).getHealth()); + + ScriptCraftCore.addBridge("LivingEntity.isValid", args -> args[0] instanceof LivingEntity); } } diff --git a/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/PlayerEntityBridges.java b/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/PlayerEntityBridges.java index 60037af..2c37d7a 100644 --- a/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/PlayerEntityBridges.java +++ b/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/PlayerEntityBridges.java @@ -6,5 +6,6 @@ import net.minecraft.entity.player.PlayerEntity; class PlayerEntityBridges { static void register() { ScriptCraftCore.addBridge("PlayerEntity.getInventory", args -> ((PlayerEntity) args[0]).inventory); + ScriptCraftCore.addBridge("PlayerEntity.isValid", args -> args[0] instanceof PlayerEntity); } } diff --git a/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/TagBridges.java b/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/TagBridges.java index d11e59c..6eab4f1 100644 --- a/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/TagBridges.java +++ b/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/TagBridges.java @@ -2,7 +2,6 @@ package com.thebrokenrail.scriptcraft.api.bridge; import com.thebrokenrail.scriptcraft.core.ScriptCraftCore; import com.thebrokenrail.scriptcraft.core.ValueUtil; -import net.minecraft.entity.Entity; import net.minecraft.nbt.AbstractListTag; import net.minecraft.nbt.AbstractNumberTag; import net.minecraft.nbt.ByteTag; @@ -92,6 +91,8 @@ class TagBridges { return tag.getKeys().toArray(new String[0]); }); + ScriptCraftCore.addBridge("CompoundTag.isValid", args -> args[0] instanceof CompoundTag); + ScriptCraftCore.addBridge("ListTag.get", args -> { AbstractListTag tag = (AbstractListTag) args[0]; Tag obj = tag.get((int) ValueUtil.toDouble(args[1], 0)); @@ -107,6 +108,8 @@ class TagBridges { return tag.size(); }); + ScriptCraftCore.addBridge("ListTag.isValid", args -> args[0] instanceof ListTag); + ScriptCraftCore.addBridge("CompoundTag.create", args -> new CompoundTag()); ScriptCraftCore.addBridge("ListTag.create", args -> new ListTag()); } diff --git a/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/WorldBridges.java b/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/WorldBridges.java index b78a4bd..7627b8c 100644 --- a/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/WorldBridges.java +++ b/scriptcraft/src/main/java/com/thebrokenrail/scriptcraft/api/bridge/WorldBridges.java @@ -45,5 +45,7 @@ class WorldBridges { }); ScriptCraftCore.addBridge("World.isClient", args -> ((World) args[0]).isClient()); + + ScriptCraftCore.addBridge("World.isValid", args -> args[0] instanceof World); } } diff --git a/scriptcraft/src/main/ts/src/minecraft/block.ts b/scriptcraft/src/main/ts/src/minecraft/block.ts index 96abd58..cf855a4 100644 --- a/scriptcraft/src/main/ts/src/minecraft/block.ts +++ b/scriptcraft/src/main/ts/src/minecraft/block.ts @@ -1,6 +1,6 @@ import { World } from './world'; import { PlayerEntity } from './entity'; -import { Identifier, Hand, Pos, ActionResult, Direction, SimpleRegistry } from './core'; +import { Identifier, Hand, Pos, ActionResult, Direction, SimpleRegistry, JavaObjectWrapper } from './core'; import { CompoundTag } from './tag'; import { useBridge, addBridge } from 'scriptcraft-core'; import { Inventory } from './inventory'; @@ -9,8 +9,8 @@ import { Inventory } from './inventory'; * Settings for {@link CustomBlock} */ export class BlockSettings { - readonly #material: string; - readonly #materialColor: string; + #material: string; + #materialColor: string; #resistance: number; #hardness: number; @@ -60,10 +60,61 @@ export class BlockSettings { } /** - * @internal + * Get Material + * @returns Material + */ + getMaterial(): string { + return this.#material; + } + + /** + * Set Material + * @param material Material + */ + setMaterial(material: string): BlockSettings { + this.#material = material; + return this; + } + + /** + * Set Material Color + * @param materialColor Material Color + */ + setMaterialColor(materialColor: string): BlockSettings { + this.#materialColor = materialColor; + return this; + } + + /** + * Get Material Color + * @returns Material Color + */ + getMaterialColor(): string { + return this.#materialColor; + } + + /** + * Get Blast Resistance + * @returns Blast Resistance + */ + getResistance(): number { + return this.#resistance; + } + + /** + * Get Hardness + * @returns Hardness + */ + getHardness(): number { + return this.#hardness; + } + + /** + * Create Java Object + * @returns Java Object */ createJavaObject(): JavaObject { - return useBridge('BlockSettings.create', this.#material, this.#materialColor, this.#hardness, this.#resistance) as JavaObject; + return useBridge('BlockSettings.create', this.getMaterial(), this.getMaterialColor(), this.getHardness(), this.getResistance()) as JavaObject; } } @@ -71,17 +122,22 @@ export class BlockSettings { * Custom Block */ export class CustomBlock { - /** - * @internal - */ - readonly settings: BlockSettings; + readonly #settings: Readonly; /** * Create Custom Block * @param settings Block Settings */ constructor(settings: BlockSettings) { - this.settings = settings; + this.#settings = Object.freeze(settings); + } + + /** + * Get Block Settings + * @returns Block Settings + */ + getSettings(): Readonly { + return this.#settings; } /** @@ -174,17 +230,14 @@ export class CustomBlockEntity { /** * Block State */ -export class BlockState { +export class BlockState extends JavaObjectWrapper { /** - * @internal + * Create Block State Wrapper From Java Object + * @param javaObject Java Object */ - readonly javaObject: JavaObject; - - /** - * @internal - */ - constructor(javaObject: JavaObject) { - this.javaObject = javaObject; + constructor(javaObject: JavaObject | JavaObjectWrapper) { + super(javaObject); + this.assertValidJavaObject('BlockState'); } /** @@ -206,7 +259,7 @@ export class BlockState { * @returns Block ID */ getBlock(): Identifier { - const obj = useBridge('BlockState.getBlock', this.javaObject) as string; + const obj = useBridge('BlockState.getBlock', this.getJavaObject()) as string; if (obj) { return new Identifier(obj); } else { @@ -227,17 +280,14 @@ export class BlockState { /** * Block Entity */ -export class BlockEntity { +export class BlockEntity extends JavaObjectWrapper { /** - * @internal + * Create Block Entity Wrapper From Java Object + * @param javaObject Java Object */ - readonly javaObject: JavaObject; - - /** - * @internal - */ - constructor(object: JavaObject) { - this.javaObject = object; + constructor(javaObject: JavaObject | JavaObjectWrapper) { + super(javaObject); + this.assertValidJavaObject('BlockEntity'); } /** @@ -245,7 +295,7 @@ export class BlockEntity { * @returns ID */ getID(): Identifier { - const obj = useBridge('BlockEntity.getID', this.javaObject) as string; + const obj = useBridge('BlockEntity.getID', this.getJavaObject()) as string; if (obj !== null) { return new Identifier(obj); } else { @@ -258,7 +308,7 @@ export class BlockEntity { * @returns Inventory If Block Entity Has One, Otherwise NULL */ getInventory(): Inventory { - const obj = useBridge('BlockEntity.getInventory', this.javaObject) as JavaObject; + const obj = useBridge('BlockEntity.getInventory', this.getJavaObject()) as JavaObject; if (obj !== null) { return new Inventory(obj); } else { @@ -270,7 +320,7 @@ export class BlockEntity { * Mark Dirty */ markDirty(): void { - useBridge('BlockEntity.markDirty', this.javaObject); + useBridge('BlockEntity.markDirty', this.getJavaObject()); } } @@ -305,9 +355,9 @@ export class BlockRegistry implements SimpleRegistry { register(id: Identifier, obj: CustomBlock): void { this.#blocks.set(id.toString(), obj); if (obj instanceof CustomBlockWithEntity) { - useBridge('Registry.registerBlockWithEntity', id.toString(), obj.settings.createJavaObject()); + useBridge('Registry.registerBlockWithEntity', id.toString(), obj.getSettings().createJavaObject()); } else { - useBridge('Registry.registerBlock', id.toString(), obj.settings.createJavaObject()); + useBridge('Registry.registerBlock', id.toString(), obj.getSettings().createJavaObject()); } } @@ -351,7 +401,7 @@ addBridge('CustomBlockEntity.fromTag', (i: number, tag: JavaObject) => { }); addBridge('CustomBlockEntity.toTag', (i: number, tag: JavaObject): JavaObject => { - return BlockRegistry.INSTANCE.getCustomBlockEntity(i).toTag(new CompoundTag(tag)).javaObject; + return BlockRegistry.INSTANCE.getCustomBlockEntity(i).toTag(new CompoundTag(tag)).getJavaObject(); }); addBridge('CustomBlockEntity.tick', (i: number) => { diff --git a/scriptcraft/src/main/ts/src/minecraft/core.ts b/scriptcraft/src/main/ts/src/minecraft/core.ts index 72f21a8..b0ba931 100644 --- a/scriptcraft/src/main/ts/src/minecraft/core.ts +++ b/scriptcraft/src/main/ts/src/minecraft/core.ts @@ -1,3 +1,43 @@ +import { useBridge } from 'scriptcraft-core'; + +/** + * Base Class For Objects Wrapping A Java Object + */ +export class JavaObjectWrapper { + readonly #javaObject: JavaObject; + + /** + * Get Java Object + * @returns Java Object + */ + getJavaObject(): JavaObject { + return this.#javaObject; + } + + /** + * Create Object Wrapper From A Java Object Or Another Object Wrapper + * @param javaObject Java Object + */ + constructor(javaObject: JavaObject | JavaObjectWrapper) { + if (javaObject instanceof JavaObjectWrapper) { + this.#javaObject = javaObject.getJavaObject(); + } else { + this.#javaObject = javaObject; + } + } + + /** + * Assert Provided Java Object Is Valid + * @param type Object Type + */ + protected assertValidJavaObject(type: string): void { + const valid = useBridge(type + '.isValid', this.getJavaObject()) as boolean; + if (!valid) { + throw new Error('Provided Java Object Is Not A Valid ' + type); + } + } +} + /** * Action Result */ diff --git a/scriptcraft/src/main/ts/src/minecraft/entity.ts b/scriptcraft/src/main/ts/src/minecraft/entity.ts index cd3996c..01f4556 100644 --- a/scriptcraft/src/main/ts/src/minecraft/entity.ts +++ b/scriptcraft/src/main/ts/src/minecraft/entity.ts @@ -1,45 +1,39 @@ import { ItemStack } from './item'; -import { Hand, Identifier, Pos } from './core'; +import { Hand, Identifier, Pos, JavaObjectWrapper } from './core'; import { World } from './world'; import { CompoundTag } from './tag'; import { useBridge } from 'scriptcraft-core'; import { Inventory } from './inventory'; +function buildDamageSource(bridge: string, value: BridgeValueType): DamageSource { + const obj = useBridge(bridge, value) as JavaObject; + if (obj !== null) { + return new DamageSource(obj); + } else { + return null; + } +} + /** * Damage Source */ -export class DamageSource { +export class DamageSource extends JavaObjectWrapper { /** - * @internal + * Create Damage Source Wrapper From Java Object + * @param javaObject Java Object */ - readonly javaObject: JavaObject; - - /** - * @internal - */ - constructor(javaObject: JavaObject) { - this.javaObject = javaObject; + constructor(javaObject: JavaObject | JavaObjectWrapper) { + super(javaObject); + this.assertValidJavaObject('DamageSource'); } /** - * @internal - */ - private static build(bridge: string, value: BridgeValueType): DamageSource { - const obj = useBridge(bridge, value) as JavaObject; - if (obj !== null) { - return new DamageSource(obj); - } else { - return null; - } - } - - /** - * Create Damage Source from a name - * @param value Name + * Create Damage Source from type + * @param value Type * @returns Damage Source */ static create(value: string): DamageSource { - return this.build('DamageSource.create', value); + return buildDamageSource('DamageSource.create', value); } /** @@ -48,7 +42,7 @@ export class DamageSource { * @returns Damage Source */ static createFromPlayer(value: PlayerEntity): DamageSource { - return this.build('DamageSource.createFromPlayer', value.javaObject); + return buildDamageSource('DamageSource.createFromPlayer', value.getJavaObject()); } /** @@ -57,29 +51,21 @@ export class DamageSource { * @returns Damage Source */ static createFromMob(value: LivingEntity): DamageSource { - return this.build('DamageSource.createFromMob', value.javaObject); + return buildDamageSource('DamageSource.createFromMob', value.getJavaObject()); } } /** * Entity */ -export class Entity { +export class Entity extends JavaObjectWrapper { /** - * @internal + * Create Entity Wrapper Class From Existing Entity Or Java Object + * @param object Existing Entity Or Java Object */ - readonly javaObject: JavaObject; - - /** - * Cast Existing Entity To This Class (Use With Caution) - * @param object Existing Entity - */ - constructor(object: JavaObject | Entity) { - if (object instanceof Entity) { - this.javaObject = object.javaObject; - } else { - this.javaObject = object; - } + constructor(javaObject: JavaObject | JavaObjectWrapper) { + super(javaObject); + this.assertValidJavaObject('Entity'); } /** @@ -87,7 +73,7 @@ export class Entity { * @returns Entity World */ getEntityWorld(): World { - const obj = useBridge('Entity.getEntityWorld', this.javaObject) as JavaObject; + const obj = useBridge('Entity.getEntityWorld', this.getJavaObject()) as JavaObject; if (obj !== null) { return new World(obj); } else { @@ -100,7 +86,7 @@ export class Entity { * @returns Entity ID */ getID(): Identifier { - const obj = useBridge('Entity.getID', this.javaObject) as string; + const obj = useBridge('Entity.getID', this.getJavaObject()) as string; if (obj !== null) { return new Identifier(obj); } else { @@ -113,7 +99,7 @@ export class Entity { * @returns Entity Name */ getName(): string { - return useBridge('Entity.getName', this.javaObject) as string; + return useBridge('Entity.getName', this.getJavaObject()) as string; } /** @@ -121,7 +107,7 @@ export class Entity { * @returns Entity Display Name */ getDisplayName(): string { - return useBridge('Entity.getDisplayName', this.javaObject) as string; + return useBridge('Entity.getDisplayName', this.getJavaObject()) as string; } /** @@ -129,7 +115,7 @@ export class Entity { * @returns Entity Custom Name */ getCustomName(): string { - return useBridge('Entity.getCustomName', this.javaObject) as string; + return useBridge('Entity.getCustomName', this.getJavaObject()) as string; } /** @@ -144,14 +130,14 @@ export class Entity { * Kill Entity */ kill(): void { - useBridge('Entity.kill', this.javaObject); + useBridge('Entity.kill', this.getJavaObject()); } /** * Remove Entity */ remove(): void { - useBridge('Entity.remove', this.javaObject); + useBridge('Entity.remove', this.getJavaObject()); } /** @@ -159,7 +145,7 @@ export class Entity { * @param ticks Fire Ticks */ setFireTicks(ticks: number): void { - useBridge('Entity.setFireTicks', this.javaObject, ticks); + useBridge('Entity.setFireTicks', this.getJavaObject(), ticks); } /** @@ -167,7 +153,7 @@ export class Entity { * @returns Fire Ticks */ getFireTicks(): number { - return useBridge('Entity.getFireTicks', this.javaObject) as number; + return useBridge('Entity.getFireTicks', this.getJavaObject()) as number; } /** @@ -176,7 +162,7 @@ export class Entity { * @param amount Damage Amount */ damage(source: DamageSource, amount: number): void { - useBridge('Entity.damage', source.javaObject, amount); + useBridge('Entity.damage', source.getJavaObject(), amount); } /** @@ -184,7 +170,7 @@ export class Entity { * @returns Entity Position */ getPosition(): Pos { - const pos: number[] = useBridge('Entity.getPosition', this.javaObject) as number[]; + const pos: number[] = useBridge('Entity.getPosition', this.getJavaObject()) as number[]; if (pos !== null && pos.length === 3) { return new Pos(pos[0], pos[1], pos[2]); } else { @@ -197,7 +183,7 @@ export class Entity { * @param pos Entity Position */ setPosition(pos: Pos): void { - useBridge('Entity.setPosition', this.javaObject, pos.getX(), pos.getY(), pos.getZ()); + useBridge('Entity.setPosition', this.getJavaObject(), pos.getX(), pos.getY(), pos.getZ()); } /** @@ -205,7 +191,7 @@ export class Entity { * @returns Tag */ toTag(): CompoundTag { - const obj = useBridge('Entity.toTag', this.javaObject) as JavaObject; + const obj = useBridge('Entity.toTag', this.getJavaObject()) as JavaObject; if (obj !== null) { return new CompoundTag(obj); } else { @@ -218,7 +204,7 @@ export class Entity { * @param tag Tag */ fromTag(tag: CompoundTag): void { - useBridge('Entity.fromTag', this.javaObject, tag.javaObject); + useBridge('Entity.fromTag', this.getJavaObject(), tag.getJavaObject()); } } @@ -226,13 +212,18 @@ export class Entity { * Living Entity */ export class LivingEntity extends Entity { + constructor(javaObject: JavaObject | JavaObjectWrapper) { + super(javaObject); + this.assertValidJavaObject('LivingEntity'); + } + /** * Get Stack in {@link Hand} * @param hand Hand * @returns Item Stack */ getStackInHand(hand: Hand): ItemStack { - const obj = useBridge('LivingEntity.getStackInHand', this.javaObject, hand.toString()) as JavaObject; + const obj = useBridge('LivingEntity.getStackInHand', this.getJavaObject(), hand.toString()) as JavaObject; if (obj) { return new ItemStack(obj); } else { @@ -245,7 +236,7 @@ export class LivingEntity extends Entity { * @returns Entity Health */ getHealth(): number { - return useBridge('LivingEntity.getHealth', this.javaObject) as number; + return useBridge('LivingEntity.getHealth', this.getJavaObject()) as number; } } @@ -253,8 +244,13 @@ export class LivingEntity extends Entity { * Player Entity */ export class PlayerEntity extends LivingEntity { + constructor(javaObject: JavaObject | JavaObjectWrapper) { + super(javaObject); + this.assertValidJavaObject('PlayerEntity'); + } + getInventory(): Inventory { - const obj = useBridge('PlayerEntity.getInventory', this.javaObject) as JavaObject; + const obj = useBridge('PlayerEntity.getInventory', this.getJavaObject()) as JavaObject; if (obj !== null) { return new Inventory(obj); } else { diff --git a/scriptcraft/src/main/ts/src/minecraft/event.ts b/scriptcraft/src/main/ts/src/minecraft/event.ts index 6f5e70c..d981203 100644 --- a/scriptcraft/src/main/ts/src/minecraft/event.ts +++ b/scriptcraft/src/main/ts/src/minecraft/event.ts @@ -5,19 +5,16 @@ import { ActionResult, Hand, Pos, Direction } from './core'; /** * Event + * @typeParam T Event Data Type + * @typeParam K Event Return Type */ -class Event { - /** - * @internal - */ +export class Event { #listeners: ((obj: T) => K)[] = []; - /** - * @internal - */ #defaultValue: K; /** - * @internal + * Create Event + * @param defaultValue Default Return Value If There Are No Events (Can be Null) */ constructor(defaultValue: K) { this.#defaultValue = defaultValue; @@ -43,9 +40,11 @@ class Event { } /** - * @internal + * Trigger Event + * @param obj Event Data + * @returns Event Return Value */ - run(obj: T): K { + trigger(obj: T): K { for (const listener of this.#listeners) { const value = listener(obj); if (this.#defaultValue !== null && value != this.#defaultValue) { @@ -57,12 +56,9 @@ class Event { } /** - * Tick Event + * World Event */ -class WorldTickEvent { - /** - * @internal - */ +export class WorldEvent { readonly #world: World; /** @@ -74,7 +70,8 @@ class WorldTickEvent { } /** - * @internal + * Create World Event + * @param world World */ constructor(world: World) { this.#world = world; @@ -84,26 +81,11 @@ class WorldTickEvent { /** * Block Event */ -class BlockEvent { - /** - * @internal - */ +export class BlockEvent { readonly #world: World; - /** - * @internal - */ readonly #player: PlayerEntity; - /** - * @internal - */ readonly #hand: Hand; - /** - * @internal - */ readonly #pos: Pos; - /** - * @internal - */ readonly #side: Direction; /** @@ -147,7 +129,12 @@ class BlockEvent { } /** - * @internal + * Create Block Event + * @param player Player + * @param world World + * @param hand Hand + * @param pos Position + * @param side Block Side */ constructor(player: PlayerEntity, world: World, hand: Hand, pos: Pos, side: Direction) { this.#player = player; @@ -161,18 +148,9 @@ class BlockEvent { /** * Item Event */ -class ItemEvent { - /** - * @internal - */ +export class ItemEvent { readonly #world: World; - /** - * @internal - */ readonly #player: PlayerEntity; - /** - * @internal - */ readonly #hand: Hand; /** @@ -200,7 +178,10 @@ class ItemEvent { } /** - * @internal + * Create Item Event + * @param player Player + * @param world World + * @param hand Hand */ constructor(player: PlayerEntity, world: World, hand: Hand) { this.#player = player; @@ -216,7 +197,7 @@ export class Events { /** * World Tick Event */ - static WORLD_TICK = new Event(null); + static WORLD_TICK = new Event(null); /** * Attack Block Event */ @@ -231,7 +212,7 @@ export class Events { static USE_ITEM = new Event(ActionResult.PASS); } -addBridge('Event.worldTick', (world: JavaObject) => Events.WORLD_TICK.run(new WorldTickEvent(new World(world)))); -addBridge('Event.attackBlock', (player: JavaObject, world: JavaObject, hand: keyof typeof Hand, x: number, y: number, z: number, side: keyof typeof Direction) => Events.ATTACK_BLOCK.run(new BlockEvent(new PlayerEntity(player), new World(world), Hand[hand], new Pos(x, y, z), Direction[side]))); -addBridge('Event.useBlock', (player: JavaObject, world: JavaObject, hand: keyof typeof Hand, x: number, y: number, z: number, side: keyof typeof Direction) => Events.USE_BLOCK.run(new BlockEvent(new PlayerEntity(player), new World(world), Hand[hand], new Pos(x, y, z), Direction[side]))); -addBridge('Event.useItem', (player: JavaObject, world: JavaObject, hand: keyof typeof Hand) => Events.USE_ITEM.run(new ItemEvent(new PlayerEntity(player), new World(world), Hand[hand]))); +addBridge('Event.worldTick', (world: JavaObject) => Events.WORLD_TICK.trigger(new WorldEvent(new World(world)))); +addBridge('Event.attackBlock', (player: JavaObject, world: JavaObject, hand: keyof typeof Hand, x: number, y: number, z: number, side: keyof typeof Direction) => Events.ATTACK_BLOCK.trigger(new BlockEvent(new PlayerEntity(player), new World(world), Hand[hand], new Pos(x, y, z), Direction[side]))); +addBridge('Event.useBlock', (player: JavaObject, world: JavaObject, hand: keyof typeof Hand, x: number, y: number, z: number, side: keyof typeof Direction) => Events.USE_BLOCK.trigger(new BlockEvent(new PlayerEntity(player), new World(world), Hand[hand], new Pos(x, y, z), Direction[side]))); +addBridge('Event.useItem', (player: JavaObject, world: JavaObject, hand: keyof typeof Hand) => Events.USE_ITEM.trigger(new ItemEvent(new PlayerEntity(player), new World(world), Hand[hand]))); diff --git a/scriptcraft/src/main/ts/src/minecraft/inventory.ts b/scriptcraft/src/main/ts/src/minecraft/inventory.ts index 4f4ba4e..8d3f38b 100644 --- a/scriptcraft/src/main/ts/src/minecraft/inventory.ts +++ b/scriptcraft/src/main/ts/src/minecraft/inventory.ts @@ -1,20 +1,18 @@ import { useBridge } from 'scriptcraft-core'; import { ItemStack } from './item'; +import { JavaObjectWrapper } from './core'; /** * Inventory */ -export class Inventory { +export class Inventory extends JavaObjectWrapper { /** - * @internal + * Create Inventory Wrapper From Java Object + * @param object Java Object */ - readonly javaObject: JavaObject; - - /** - * @internal - */ - constructor(object: JavaObject) { - this.javaObject = object; + constructor(javaObject: JavaObject | JavaObjectWrapper) { + super(javaObject); + this.assertValidJavaObject('Inventory'); } /** @@ -22,7 +20,7 @@ export class Inventory { * @returns Inventory Size */ size(): number { - return useBridge('Inventory.size', this.javaObject) as number; + return useBridge('Inventory.size', this.getJavaObject()) as number; } /** @@ -30,7 +28,7 @@ export class Inventory { * @returns Inventory Maximum Stack Size */ getMaxStackSize(): number { - return useBridge('Inventory.getMaxStackSize', this.javaObject) as number; + return useBridge('Inventory.getMaxStackSize', this.getJavaObject()) as number; } /** @@ -39,7 +37,7 @@ export class Inventory { * @returns Item Stack */ get(slot: number): ItemStack { - const obj = useBridge('Inventory.get', this.javaObject, slot) as JavaObject; + const obj = useBridge('Inventory.get', this.getJavaObject(), slot) as JavaObject; if (obj !== null) { return new ItemStack(obj); } else { @@ -54,7 +52,7 @@ export class Inventory { * @returns Item Stack */ take(slot: number, count: number): ItemStack { - const obj = useBridge('Inventory.take', this.javaObject, slot, count) as JavaObject; + const obj = useBridge('Inventory.take', this.getJavaObject(), slot, count) as JavaObject; if (obj !== null) { return new ItemStack(obj); } else { @@ -68,6 +66,6 @@ export class Inventory { * @param item Item Stack */ set(slot: number, item: ItemStack): void { - useBridge('Inventory.set', this.javaObject, slot, item.javaObject); + useBridge('Inventory.set', this.getJavaObject(), slot, item.getJavaObject()); } } diff --git a/scriptcraft/src/main/ts/src/minecraft/item.ts b/scriptcraft/src/main/ts/src/minecraft/item.ts index fbe94ff..45e8bc0 100644 --- a/scriptcraft/src/main/ts/src/minecraft/item.ts +++ b/scriptcraft/src/main/ts/src/minecraft/item.ts @@ -1,4 +1,4 @@ -import { Identifier, Hand, ActionResult, Pos, Direction, SimpleRegistry } from './core'; +import { Identifier, Hand, ActionResult, Pos, Direction, SimpleRegistry, JavaObjectWrapper } from './core'; import { World } from './world'; import { PlayerEntity, LivingEntity } from './entity'; import { CompoundTag } from './tag'; @@ -7,17 +7,14 @@ import { useBridge, addBridge } from 'scriptcraft-core'; /** * Item Stack */ -export class ItemStack { +export class ItemStack extends JavaObjectWrapper { /** - * @internal + * Create Item Stack Wrapper From Java Object + * @param object Java Object */ - readonly javaObject: JavaObject; - - /** - * @internal - */ - constructor(obj: JavaObject) { - this.javaObject = obj; + constructor(javaObject: JavaObject | JavaObjectWrapper) { + super(javaObject); + this.assertValidJavaObject('ItemStack'); } /** @@ -39,7 +36,7 @@ export class ItemStack { * @returns Item ID */ getItem(): Identifier { - const obj = useBridge('ItemStack.getItem', this.javaObject) as string; + const obj = useBridge('ItemStack.getItem', this.getJavaObject()) as string; if (obj !== null) { return new Identifier(obj); } else { @@ -60,7 +57,7 @@ export class ItemStack { * @returns Item Count */ getCount(): number { - return useBridge('ItemStack.getCount', this.javaObject) as number; + return useBridge('ItemStack.getCount', this.getJavaObject()) as number; } /** @@ -68,7 +65,7 @@ export class ItemStack { * @param count New Count */ setCount(count: number): void { - useBridge('ItemStack.setCount', this.javaObject, count); + useBridge('ItemStack.setCount', this.getJavaObject(), count); } /** @@ -76,7 +73,7 @@ export class ItemStack { * @returns Item Damage */ getDamage(): number { - return useBridge('ItemStack.getDamage', this.javaObject) as number; + return useBridge('ItemStack.getDamage', this.getJavaObject()) as number; } /** @@ -84,7 +81,7 @@ export class ItemStack { * @param count New Damage */ setDamage(damage: number): void { - useBridge('ItemStack.setDamage', this.javaObject, damage); + useBridge('ItemStack.setDamage', this.getJavaObject(), damage); } /** @@ -92,7 +89,7 @@ export class ItemStack { * @returns TRUE If Item Is Damageable, Otherwise FALSE */ isDamageable(): boolean { - return useBridge('ItemStack.isDamageable', this.javaObject) as boolean; + return useBridge('ItemStack.isDamageable', this.getJavaObject()) as boolean; } /** @@ -100,7 +97,7 @@ export class ItemStack { * @returns Item Tag */ getTag(): CompoundTag { - const obj = useBridge('ItemStack.getTag', this.javaObject) as JavaObject; + const obj = useBridge('ItemStack.getTag', this.getJavaObject()) as JavaObject; if (obj !== null) { return new CompoundTag(obj); } else { @@ -113,7 +110,7 @@ export class ItemStack { * @param tag New Item Tag */ setTag(tag: CompoundTag): void { - useBridge('ItemStack.setTag', this.javaObject, tag.javaObject); + useBridge('ItemStack.setTag', this.getJavaObject(), tag.getJavaObject()); } /** @@ -121,7 +118,7 @@ export class ItemStack { * @returns Item Tag */ toTag(): CompoundTag { - const obj = useBridge('ItemStack.toTag', this.javaObject) as JavaObject; + const obj = useBridge('ItemStack.toTag', this.getJavaObject()) as JavaObject; if (obj !== null) { return new CompoundTag(obj); } else { @@ -135,7 +132,7 @@ export class ItemStack { * @returns Item Stack */ static fromTag(tag: CompoundTag): ItemStack { - const obj = useBridge('ItemStack.fromTag', tag.javaObject) as JavaObject; + const obj = useBridge('ItemStack.fromTag', tag.getJavaObject()) as JavaObject; if (obj !== null) { return new ItemStack(obj); } else { @@ -149,7 +146,7 @@ export class ItemStack { * @returns New Item Stack */ split(amount: number): ItemStack { - const obj = useBridge('ItemStack.split', this.javaObject, amount) as JavaObject; + const obj = useBridge('ItemStack.split', this.getJavaObject(), amount) as JavaObject; if (obj !== null) { return new ItemStack(obj); } else { @@ -212,7 +209,8 @@ export class ItemSettings { } /** - * @internal + * Create Java Object + * @returns Java Object */ createJavaObject(): JavaObject { return useBridge('ItemSettings.create', this.#maxCount, this.#rarity, this.#itemGroup) as JavaObject; @@ -223,17 +221,22 @@ export class ItemSettings { * Custom Item */ export class CustomItem { + readonly #settings: Readonly; + /** - * @internal + * Get Item Settings + * @returns Item Settings */ - readonly settings: ItemSettings; + getSettings(): Readonly { + return this.#settings; + } /** * Create Custom Item * @param settings Item Settings */ constructor(settings: ItemSettings) { - this.settings = settings; + this.#settings = Object.freeze(settings); } /** @@ -276,14 +279,25 @@ export class CustomItem { * Block Item */ export class BlockItem { + readonly #settings: Readonly; + /** - * @internal + * Get Item Settings + * @returns Item Settings */ - readonly settings: ItemSettings; + getSettings(): Readonly { + return this.#settings; + } + + readonly #block: Identifier; + /** - * @internal + * Get Block ID + * @returns Block ID */ - readonly block: Identifier; + getBlock(): Identifier { + return this.#block; + } /** * Create Block Item @@ -291,8 +305,8 @@ export class BlockItem { * @param settings Item Settings */ constructor(block: Identifier, settings: ItemSettings) { - this.settings = settings; - this.block = block; + this.#settings = Object.freeze(settings); + this.#block = block; } } @@ -311,9 +325,9 @@ export class ItemRegistry implements SimpleRegistry { register(id: Identifier, obj: CustomItem | BlockItem): void { if (obj instanceof CustomItem) { this.#items.set(id.toString(), obj); - useBridge('Registry.registerItem', id.toString(), obj.settings.createJavaObject()); + useBridge('Registry.registerItem', id.toString(), obj.getSettings().createJavaObject()); } else { - useBridge('Registry.registerBlockItem', id.toString(), obj.settings.createJavaObject(), obj.block.toString()); + useBridge('Registry.registerBlockItem', id.toString(), obj.getSettings().createJavaObject(), obj.getBlock().toString()); } } diff --git a/scriptcraft/src/main/ts/src/minecraft/tag.ts b/scriptcraft/src/main/ts/src/minecraft/tag.ts index c855bb0..703bafe 100644 --- a/scriptcraft/src/main/ts/src/minecraft/tag.ts +++ b/scriptcraft/src/main/ts/src/minecraft/tag.ts @@ -1,4 +1,5 @@ import { useBridge } from 'scriptcraft-core'; +import { JavaObjectWrapper } from './core'; type TagType = number | boolean | string | CompoundTag | ListTag; @@ -55,17 +56,14 @@ export enum NumberType { /** * Compound Tag */ -export class CompoundTag { +export class CompoundTag extends JavaObjectWrapper { /** - * @internal + * Create Compound Tag Wrapper From Java Object + * @param javaObject Java Object */ - readonly javaObject: JavaObject; - - /** - * @internal - */ - constructor(javaObject: JavaObject) { - this.javaObject = javaObject; + constructor(javaObject: JavaObject | JavaObjectWrapper) { + super(javaObject); + this.assertValidJavaObject('CompoundTag'); } /** @@ -76,7 +74,7 @@ export class CompoundTag { * @returns Value */ get(key: string): Exclude { - const obj = useBridge('CompoundTag.get', this.javaObject, key) as [boolean, BridgeValueType]; + const obj = useBridge('CompoundTag.get', this.getJavaObject(), key) as [boolean, BridgeValueType]; return getTagValue(obj); } @@ -89,7 +87,7 @@ export class CompoundTag { set(key: string, value: number, numberType: NumberType): void; set(key: string, value: Exclude): void; set(key: string, value: TagType, numberType?: NumberType): void { - useBridge('CompoundTag.set', this.javaObject, key, value instanceof CompoundTag || value instanceof ListTag ? value.javaObject : value, numberType !== null ? numberType : NumberType.DOUBLE); + useBridge('CompoundTag.set', this.getJavaObject(), key, value instanceof CompoundTag || value instanceof ListTag ? value.getJavaObject() : value, numberType !== null ? numberType : NumberType.DOUBLE); } /** @@ -97,7 +95,7 @@ export class CompoundTag { * @returns List Of Keys */ keys(): string[] { - return useBridge('CompoundTag.keys', this.javaObject) as string[]; + return useBridge('CompoundTag.keys', this.getJavaObject()) as string[]; } /** @@ -138,17 +136,14 @@ export class CompoundTag { /** * List Tag */ -export class ListTag { +export class ListTag extends JavaObjectWrapper { /** - * @internal + * Create List Tag Wrapper From Java Object + * @param javaObject Java Object */ - readonly javaObject: JavaObject; - - /** - * @internal - */ - constructor(javaObject: JavaObject) { - this.javaObject = javaObject; + constructor(javaObject: JavaObject | JavaObjectWrapper) { + super(javaObject); + this.assertValidJavaObject('ListTag'); } /** @@ -159,7 +154,7 @@ export class ListTag { * @returns Value */ get(key: number): Exclude { - const obj = useBridge('ListTag.get', this.javaObject, key) as [boolean, BridgeValueType]; + const obj = useBridge('ListTag.get', this.getJavaObject(), key) as [boolean, BridgeValueType]; return getTagValue(obj); } @@ -172,7 +167,7 @@ export class ListTag { set(key: number, value: number, numberType: NumberType): void; set(key: number, value: Exclude): void; set(key: number, value: TagType, numberType?: NumberType): void { - useBridge('ListTag.set', this.javaObject, key, value instanceof CompoundTag || value instanceof ListTag ? value.javaObject : value, numberType !== null ? numberType : NumberType.DOUBLE); + useBridge('ListTag.set', this.getJavaObject(), key, value instanceof CompoundTag || value instanceof ListTag ? value.getJavaObject() : value, numberType !== null ? numberType : NumberType.DOUBLE); } /** @@ -180,7 +175,7 @@ export class ListTag { * @returns Size */ size(): number { - return useBridge('ListTag.size', this.javaObject) as number; + return useBridge('ListTag.size', this.getJavaObject()) as number; } /** diff --git a/scriptcraft/src/main/ts/src/minecraft/world.ts b/scriptcraft/src/main/ts/src/minecraft/world.ts index c713117..d514510 100644 --- a/scriptcraft/src/main/ts/src/minecraft/world.ts +++ b/scriptcraft/src/main/ts/src/minecraft/world.ts @@ -1,22 +1,19 @@ import { BlockState, CustomBlockEntity, BlockRegistry, BlockEntity } from './block'; import { Entity } from './entity'; -import { Pos, Identifier } from './core'; +import { Pos, Identifier, JavaObjectWrapper } from './core'; import { useBridge } from 'scriptcraft-core'; /** * World */ -export class World { +export class World extends JavaObjectWrapper { /** - * @internal + * Create World Wrapper From Java Object + * @param javaObject Java Object */ - readonly javaObject: JavaObject; - - /** - * @internal - */ - constructor(javaObject: JavaObject) { - this.javaObject = javaObject; + constructor(javaObject: JavaObject | JavaObjectWrapper) { + super(javaObject); + this.assertValidJavaObject('World'); } /** @@ -26,7 +23,7 @@ export class World { * @returns TRUE If Successful, Otherwise FALSE */ setBlockState(pos: Pos, state: BlockState): boolean { - return useBridge('World.setBlockState', this.javaObject, pos.getX(), pos.getY(), pos.getZ(), state.javaObject) as boolean; + return useBridge('World.setBlockState', this.getJavaObject(), pos.getX(), pos.getY(), pos.getZ(), state.getJavaObject()) as boolean; } /** @@ -35,7 +32,7 @@ export class World { * @returns Block State */ getBlockState(pos: Pos): BlockState { - const obj = useBridge('World.getBlockState', this.javaObject, pos.getX(), pos.getY(), pos.getZ()) as JavaObject; + const obj = useBridge('World.getBlockState', this.getJavaObject(), pos.getX(), pos.getY(), pos.getZ()) as JavaObject; if (obj !== null) { return new BlockState(obj); } else { @@ -49,7 +46,7 @@ export class World { * @param pos Position */ spawnEntity(id: Identifier, pos: Pos): Entity { - const obj = useBridge('World.spawnEntity', this.javaObject, pos.getX(), pos.getY(), pos.getZ(), id.toString()) as JavaObject; + const obj = useBridge('World.spawnEntity', this.getJavaObject(), pos.getX(), pos.getY(), pos.getZ(), id.toString()) as JavaObject; if (obj !== null) { return new Entity(obj); } else { @@ -63,7 +60,7 @@ export class World { * @returns Custom Block Entity At Position */ getCustomBlockEntity(pos: Pos): CustomBlockEntity { - const obj = useBridge('World.getCustomBlockEntity', this.javaObject, pos.getX(), pos.getY(), pos.getZ()) as number; + const obj = useBridge('World.getCustomBlockEntity', this.getJavaObject(), pos.getX(), pos.getY(), pos.getZ()) as number; if (obj !== null) { return BlockRegistry.INSTANCE.getCustomBlockEntity(obj); } else { @@ -77,7 +74,7 @@ export class World { * @returns Block Entity ID At Position */ getBlockEntity(pos: Pos): BlockEntity { - const obj = useBridge('World.getBlockEntity', this.javaObject, pos.getX(), pos.getY(), pos.getZ()) as JavaObject; + const obj = useBridge('World.getBlockEntity', this.getJavaObject(), pos.getX(), pos.getY(), pos.getZ()) as JavaObject; if (obj !== null) { return new BlockEntity(obj); } else { @@ -86,6 +83,6 @@ export class World { } isClient(): boolean { - return useBridge('World.isClient', this.javaObject) as boolean; + return useBridge('World.isClient', this.getJavaObject()) as boolean; } }