tirbofish/dropbear · commit
563bf9a1ba928e93134295c4996390ecf14398e3
added new native functions for player manipulation
specifics:
- JNINative.getEntity now queries and searches
- JNINative.getTransform now fetches transforms successfully
- JNINative.setTransform now sets transform for that specific entity.
Signature present but could not be verified.
Unverified
@@ -45,7 +45,7 @@ git clone git@github.com:4tkbytes/dropbear cd dropbear # eucalyptus-editor requires dropbear-1.0-SNAPSHOT-all.jar to be built first -./gradlew build +./gradlew build fatJar # this will build all the projects in the workspace cargo build ``` @@ -4,13 +4,13 @@ pub mod exception; use std::fs; -use dropbear_engine::entity::AdoptedEntity; +use dropbear_engine::entity::{AdoptedEntity, Transform}; use hecs::World; -use jni::objects::{GlobalRef, JClass, JString, JValue}; -use jni::sys::jlong; -use jni::sys::jobject; +use jni::objects::{GlobalRef, JClass, JObject, JString, JValue}; +use jni::sys::{jclass, jlong}; use jni::{InitArgsBuilder, JNIEnv, JNIVersion, JavaVM}; use std::path::{PathBuf}; +use glam::{DQuat, DVec3}; use crate::{success, APP_INFO}; use sha2::{Digest, Sha256}; use crate::logging::{LOG_LEVEL}; @@ -267,7 +267,7 @@ impl JavaContext { let result = get_exception_info(&mut env); if result.is_some() { return Err(anyhow::anyhow!("{}", result.unwrap())); } - log::debug!("Updated all systems with dt: {}", dt); + log::trace!("Updated all systems with dt: {}", dt); } else { return Err(anyhow::anyhow!("SystemManager not initialised when updating systems.")); } @@ -384,12 +384,12 @@ impl Drop for JavaContext { } } -#[unsafe(no_mangle)] // JNIEXPORT jlong JNICALL Java_com_dropbear_ffi_JNINative_getEntity -// (JNIEnv *, jobject, jlong, jstring); +// (JNIEnv *, jclass, jlong, jstring); +#[unsafe(no_mangle)] pub fn Java_com_dropbear_ffi_JNINative_getEntity( mut env: JNIEnv, - _obj: jobject, + _obj: jclass, world_handle: jlong, label: JString, ) -> jlong { @@ -413,7 +413,7 @@ pub fn Java_com_dropbear_ffi_JNINative_getEntity( let world = world_handle as *mut World; if world.is_null() { - println!("[Java_com_dropbear_ffi_JNINative_getEntity] [ERROR] World pointer is null in Java_com_dropbear_ffi_JNINative_getEntity"); + println!("[Java_com_dropbear_ffi_JNINative_getEntity] [ERROR] World pointer is null"); return -1; } @@ -425,4 +425,159 @@ pub fn Java_com_dropbear_ffi_JNINative_getEntity( } } -1 +} + +// JNIEXPORT jobject JNICALL Java_com_dropbear_ffi_JNINative_getTransform +// (JNIEnv *, jclass, jlong, jlong); +#[unsafe(no_mangle)] +pub fn Java_com_dropbear_ffi_JNINative_getTransform( + mut env: JNIEnv, + _class: jclass, + world_handle: jlong, + entity_id: jlong, +) -> JObject { + let world = world_handle as *mut World; + + if world.is_null() { + println!("[Java_com_dropbear_ffi_JNINative_getTransform] [ERROR] World pointer is null"); + return JObject::null(); + } + + let world = unsafe { &mut *world }; + + let entity = unsafe { world.find_entity_from_id(entity_id as u32) }; + + if let Ok(mut q) = world.query_one::<(&AdoptedEntity, &Transform)>(entity) + && let Some((_, transform)) = q.get() + { + let new_transform = *transform; + + let transform_class = match env.find_class("com/dropbear/math/Transform") { + Ok(c) => c, + Err(_) => return JObject::null(), + }; + + return match env.new_object( + &transform_class, + "(DDDDDDDDDD)V", + &[ + new_transform.position.x.into(), + new_transform.position.y.into(), + new_transform.position.z.into(), + new_transform.rotation.x.into(), + new_transform.rotation.y.into(), + new_transform.rotation.z.into(), + new_transform.rotation.w.into(), + new_transform.scale.x.into(), + new_transform.scale.y.into(), + new_transform.scale.z.into(), + ], + ) { + Ok(java_transform) => java_transform, + Err(_) => { + println!("[Java_com_dropbear_ffi_JNINative_getTransform] [ERROR] Failed to create Transform object"); + JObject::null() + } + }; + } + + println!("[Java_com_dropbear_ffi_JNINative_getTransform] [ERROR] Failed to query for transform value for entity: {}", entity_id); + JObject::null() +} + +// JNIEXPORT void JNICALL Java_com_dropbear_ffi_JNINative_setTransform +// (JNIEnv *, jclass, jlong, jlong, jobject); +#[unsafe(no_mangle)] +pub fn Java_com_dropbear_ffi_JNINative_setTransform( + mut env: JNIEnv, + _class: jclass, + world_handle: jlong, + entity_id: jlong, + transform_obj: JObject, +) { + let world = world_handle as *mut World; + + if world.is_null() { + println!("[Java_com_dropbear_ffi_JNINative_setTransform] [ERROR] World pointer is null"); + return; + } + + let world = unsafe { &mut *world }; + let entity = unsafe { world.find_entity_from_id(entity_id as u32) }; + + let get_number_field = |env: &mut JNIEnv, obj: &JObject, field_name: &str| -> f64 { + match env.get_field(obj, field_name, "Ljava/lang/Number;") { + Ok(v) => match v.l() { + Ok(num_obj) => { + match env.call_method(&num_obj, "doubleValue", "()D", &[]) { + Ok(result) => result.d().unwrap_or_else(|_| { + println!("[Java_com_dropbear_ffi_JNINative_setTransform] [ERROR] Failed to extract double from {}", field_name); + 0.0 + }), + Err(_) => { + println!("[Java_com_dropbear_ffi_JNINative_setTransform] [ERROR] Failed to call doubleValue on {}", field_name); + 0.0 + } + } + } + Err(_) => { + println!("[Java_com_dropbear_ffi_JNINative_setTransform] [ERROR] Failed to extract Number object for {}", field_name); + 0.0 + } + }, + Err(_) => { + println!("[Java_com_dropbear_ffi_JNINative_setTransform] [ERROR] Failed to get field {}", field_name); + 0.0 + } + } + }; + + let position_obj: JObject = match env.get_field(&transform_obj, "position", "Lcom/dropbear/math/Vector3;") { + Ok(v) => v.l().unwrap_or_else(|_| JObject::null()), + Err(_) => JObject::null(), + }; + + let rotation_obj: JObject = match env.get_field(&transform_obj, "rotation", "Lcom/dropbear/math/Quaternion;") { + Ok(v) => v.l().unwrap_or_else(|_| JObject::null()), + Err(_) => JObject::null(), + }; + + let scale_obj: JObject = match env.get_field(&transform_obj, "scale", "Lcom/dropbear/math/Vector3;") { + Ok(v) => v.l().unwrap_or_else(|_| JObject::null()), + Err(_) => JObject::null(), + }; + + if position_obj.is_null() || rotation_obj.is_null() || scale_obj.is_null() { + println!("[Java_com_dropbear_ffi_JNINative_setTransform] [ERROR] Failed to extract position/rotation/scale objects"); + return; + } + + let px = get_number_field(&mut env, &position_obj, "x"); + let py = get_number_field(&mut env, &position_obj, "y"); + let pz = get_number_field(&mut env, &position_obj, "z"); + + let rx = get_number_field(&mut env, &rotation_obj, "x"); + let ry = get_number_field(&mut env, &rotation_obj, "y"); + let rz = get_number_field(&mut env, &rotation_obj, "z"); + let rw = get_number_field(&mut env, &rotation_obj, "w"); + + let sx = get_number_field(&mut env, &scale_obj, "x"); + let sy = get_number_field(&mut env, &scale_obj, "y"); + let sz = get_number_field(&mut env, &scale_obj, "z"); + + let new_transform = Transform { + position: DVec3::new(px, py, pz), + rotation: DQuat::from_axis_angle(DVec3::new(rx, ry, rz), rw), + scale: DVec3::new(sx, sy, sz), + }; + + if let Ok(mut q) = world.query_one::<&mut Transform>(entity) { + if let Some(transform) = q.get() { + *transform = new_transform; + } else { + println!("[Java_com_dropbear_ffi_JNINative_setTransform] [ERROR] Failed to query for transform component"); + } + } else { + println!("[Java_com_dropbear_ffi_JNINative_setTransform] [ERROR] Failed to query entity for transform component"); + } } @@ -123,6 +123,7 @@ impl Scene for Editor { "Failed to update script: {}", e ); + self.signal = Signal::StopPlaying; } } @@ -1,18 +1,22 @@ package com.dropbear import com.dropbear.ffi.NativeEngine +import com.dropbear.math.Transform class DropbearEngine(val native: NativeEngine) { - - fun getEntity(label: String): Result<EntityRef> { + public fun getEntity(label: String): EntityRef? { val entityId = native.getEntity(label) - return (when (entityId) { - null -> { - Result.failure(Exception("JNI returned null")) - } - else -> { - Result.success(EntityRef(EntityId(entityId))) - } - }) + val entityRef = if (entityId != null) EntityRef(EntityId(entityId)) else null + entityRef?.engine = this + return entityRef + } + + internal fun getTransform(entityId: EntityId): Transform? { + val result = native.getTransform(entityId) + return result + } + + internal fun setTransform(entityId: EntityId, transform: Transform) { + native.setTransform(entityId, transform) } } @@ -1,25 +1,20 @@ package com.dropbear -import com.dropbear.math.Vector3D +import com.dropbear.math.Transform -/** - * A class to hold a reference to an entity. - * - * The dropbear engine interface is made in Rust, which uses a - * borrow checker paradigm, which heavily utilises immutability - * unless explicitly provided with the `mut` keyword. - * - * Because of this, the primary source of the World (place to store - * entities) is stored in Rust, and passing an EntityRef (which contains - * an ID) follows Rust's ideologies of passing references instead of the entire entity, - * which provides immutability. - * - * To edit any values part of the entity, take a look at the functions provided - * by [EntityRef], which will require a reference to [DropbearEngine] to push the commands. - */ class EntityRef(val id: EntityId = EntityId(0L)) { + lateinit var engine: DropbearEngine + override fun toString(): String { return "EntityRef(id=$id)" } - fun setPosition(position: Vector3D, engine: DropbearEngine) {} + + fun getTransform(): Transform? { + return engine.getTransform(id) + } + + fun setTransform(transform: Transform?) { + if (transform == null) return + return engine.setTransform(id, transform) + } } @@ -0,0 +1,20 @@ +import com.dropbear.DropbearEngine +import com.dropbear.Runnable +import com.dropbear.System + +@Runnable +class Example: System() { + override fun load(engine: DropbearEngine) { + val entity = engine.getEntity("example") + val transform = entity?.getTransform() + transform?.position?.x = 10.0 + entity?.setTransform(transform) + } + + override fun update(engine: DropbearEngine, deltaTime: Float) { + } + + override fun destroy(engine: DropbearEngine) { + + } +} @@ -1,5 +1,10 @@ package com.dropbear.ffi +import com.dropbear.EntityId +import com.dropbear.math.Transform + expect class NativeEngine { fun getEntity(label: String): Long? + fun getTransform(entityId: EntityId): Transform? + fun setTransform(entityId: EntityId, transform: Transform) } @@ -1,8 +1,15 @@ package com.dropbear.math +import kotlin.jvm.JvmField + typealias QuaternionD = Quaternion<Double> -class Quaternion<T: Number>(var x: T, var y: T, var z: T, var w: T) { +class Quaternion<T: Number>( + @JvmField var x: T, + @JvmField var y: T, + @JvmField var z: T, + @JvmField var w: T +) { companion object { fun identity(): Quaternion<Double> { return Quaternion(0.0, 0.0, 0.0, 1.0) @@ -0,0 +1,20 @@ +package com.dropbear.math + +class Transform( + var position: Vector3D, + var rotation: QuaternionD, + var scale: Vector3D +) { + constructor(px: Double, py: Double, pz: Double, + rx: Double, ry: Double, rz: Double, rw: Double, + sx: Double, sy: Double, sz: Double) + : this( + Vector3D(px, py, pz), + QuaternionD(rx, ry, rz, rw), + Vector3D(sx, sy, sz) + ) + + override fun toString(): String { + return "Transform(position=$position, rotation=$rotation, scale=$scale)" + } +} @@ -1,9 +1,15 @@ package com.dropbear.math +import kotlin.jvm.JvmField + /** * A class for holding a vector of `3` values of the same type. */ -class Vector3<T: Number>(var x: T, var y: T, var z: T) { +class Vector3<T: Number>( + @JvmField var x: T, + @JvmField var y: T, + @JvmField var z: T, +) { companion object { /** * Creates a new [com.dropbear.math.Vector3] of type `T` with one value. @@ -1,9 +1,14 @@ package com.dropbear.ffi; +import com.dropbear.math.Transform; + public class JNINative { static { System.loadLibrary("eucalyptus_core"); } public static native long getEntity(long handle, String label); + + public static native Transform getTransform(long handle, long entityHandle); + public static native void setTransform(long worldHandle, long id, Transform transform); } @@ -1,15 +1,13 @@ package com.dropbear.ffi +import com.dropbear.EntityId +import com.dropbear.math.Transform + actual class NativeEngine { private var worldHandle: Long = 0L actual fun getEntity(label: String): Long? { - val result = JNINative.getEntity(worldHandle, label) - return if (result < 0) { - null - } else { - result - } + return JNINative.getEntity(worldHandle, label) } @JvmName("init") @@ -20,4 +18,12 @@ actual class NativeEngine { return } } + + actual fun getTransform(entityId: EntityId): Transform? { + return JNINative.getTransform(worldHandle, entityId.id) + } + + actual fun setTransform(entityId: EntityId, transform: Transform) { + return JNINative.setTransform(worldHandle, entityId.id, transform) + } } @@ -3,8 +3,10 @@ package com.dropbear.ffi +import com.dropbear.EntityId import com.dropbear.ffi.generated.dropbear_get_entity import com.dropbear.logging.Logger +import com.dropbear.math.Transform import kotlinx.cinterop.* import kotlin.experimental.ExperimentalNativeApi @@ -31,4 +33,11 @@ actual class NativeEngine { return if (result == 0) outEntity.value else null } } + + actual fun getTransform(entityId: EntityId): Transform? { + TODO("Not yet implemented") + } + + actual fun setTransform(entityId: EntityId, transform: Transform) { + } }