Add get world and free string
This commit is contained in:
parent
4a906ae3dc
commit
03e762cd45
@ -16,6 +16,8 @@ public class NativePatchBukkit {
|
||||
private static MethodHandle getAbilitiesNative;
|
||||
private static MethodHandle setAbilitiesNative;
|
||||
private static MethodHandle getLocationNative;
|
||||
private static MethodHandle getWorldNative;
|
||||
private static MethodHandle freeStringNative;
|
||||
|
||||
// Struct layout matching Rust's #[repr(C)] AbilitiesFFI
|
||||
private static final StructLayout ABILITIES_LAYOUT =
|
||||
@ -223,6 +225,19 @@ public class NativePatchBukkit {
|
||||
ValueLayout.ADDRESS // out pointer to Vec3FFI
|
||||
)
|
||||
);
|
||||
|
||||
// const char* rust_get_world(const char* uuid)
|
||||
getWorldNative = LINKER.downcallHandle(
|
||||
MemorySegment.ofAddress(getWorldAddr),
|
||||
FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.ADDRESS)
|
||||
);
|
||||
|
||||
// void rust_free_string(const char* str)
|
||||
freeStringNative = LINKER.downcallHandle(
|
||||
MemorySegment.ofAddress(freeStringAddr),
|
||||
FunctionDescriptor.ofVoid(ValueLayout.ADDRESS)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -348,4 +363,40 @@ public class NativePatchBukkit {
|
||||
throw new RuntimeException("Failed to call native getLocation", t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Free a string allocated by the Rust side.
|
||||
*/
|
||||
private static void freeRustString(MemorySegment ptr) {
|
||||
try {
|
||||
freeStringNative.invokeExact(ptr);
|
||||
} catch (Throwable t) {
|
||||
throw new RuntimeException("Failed to free Rust string", t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the world UUID for an entity.
|
||||
*/
|
||||
public static String getWorld(UUID entityUuid) {
|
||||
try (Arena arena = Arena.ofConfined()) {
|
||||
MemorySegment uuidStr = arena.allocateFrom(entityUuid.toString());
|
||||
MemorySegment resultPtr = (MemorySegment) getWorldNative.invokeExact(uuidStr);
|
||||
|
||||
if (resultPtr.equals(MemorySegment.NULL)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Read the string, then free the Rust-allocated memory
|
||||
try {
|
||||
String result = resultPtr.reinterpret(Long.MAX_VALUE).getString(0);
|
||||
return result;
|
||||
} finally {
|
||||
freeRustString(resultPtr);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
throw new RuntimeException("Failed to call native getWorld", t);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
9
rust/src/java/native_callbacks/memory.rs
Normal file
9
rust/src/java/native_callbacks/memory.rs
Normal file
@ -0,0 +1,9 @@
|
||||
use std::ffi::{CString, c_char};
|
||||
|
||||
pub extern "C" fn rust_free_string(ptr: *mut c_char) {
|
||||
if !ptr.is_null() {
|
||||
unsafe {
|
||||
drop(CString::from_raw(ptr));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -7,6 +7,7 @@ use pumpkin::plugin::Context;
|
||||
pub mod abilities;
|
||||
pub mod events;
|
||||
pub mod location;
|
||||
pub mod memory;
|
||||
pub mod message;
|
||||
pub mod utils;
|
||||
pub mod world;
|
||||
@ -39,6 +40,8 @@ pub fn initialize_callbacks(jvm: &Jvm) -> Result<()> {
|
||||
let get_abilities_addr = abilities::rust_get_abilities as *const () as i64;
|
||||
let set_abilities_addr = abilities::rust_set_abilities as *const () as i64;
|
||||
let get_location_addr = location::rust_get_location as *const () as i64;
|
||||
let free_string_addr = memory::rust_free_string as *const () as i64;
|
||||
let get_world_addr = world::rust_get_world as *const () as i64;
|
||||
|
||||
jvm.invoke_static(
|
||||
"org.patchbukkit.bridge.NativePatchBukkit",
|
||||
@ -49,6 +52,8 @@ pub fn initialize_callbacks(jvm: &Jvm) -> Result<()> {
|
||||
InvocationArg::try_from(get_abilities_addr)?.into_primitive()?,
|
||||
InvocationArg::try_from(set_abilities_addr)?.into_primitive()?,
|
||||
InvocationArg::try_from(get_location_addr)?.into_primitive()?,
|
||||
InvocationArg::try_from(free_string_addr)?.into_primitive()?,
|
||||
InvocationArg::try_from(get_world_addr)?.into_primitive()?,
|
||||
],
|
||||
)?;
|
||||
|
||||
|
||||
@ -4,24 +4,36 @@ use pumpkin::command::args::entities::{EntitySelectorType, TargetSelector};
|
||||
|
||||
use crate::java::native_callbacks::{CALLBACK_CONTEXT, utils::get_string};
|
||||
|
||||
pub extern "C" fn rust_get_world(uuid_ptr: *const c_char) -> *const c_char {
|
||||
let uuid_str = get_string(uuid_ptr);
|
||||
if let Some(ctx) = CALLBACK_CONTEXT.get() {
|
||||
let uuid = uuid::Uuid::parse_str(&uuid_str).unwrap();
|
||||
let entity = ctx
|
||||
.plugin_context
|
||||
.server
|
||||
.select_entities(&TargetSelector::new(EntitySelectorType::Uuid(uuid)), None);
|
||||
if entity.len() == 1 {
|
||||
let entity = entity.first().unwrap().get_entity();
|
||||
let world = entity.world.load();
|
||||
|
||||
let cstring = match CString::new(world.dimension.minecraft_name) {
|
||||
Ok(s) => s,
|
||||
Err(_) => return std::ptr::null(),
|
||||
};
|
||||
}
|
||||
pub extern "C" fn rust_get_world(entity_uuid_ptr: *const c_char) -> *mut c_char {
|
||||
if entity_uuid_ptr.is_null() {
|
||||
return std::ptr::null_mut();
|
||||
}
|
||||
|
||||
std::ptr::null()
|
||||
let entity_uuid = get_string(entity_uuid_ptr);
|
||||
|
||||
let Some(ctx) = CALLBACK_CONTEXT.get() else {
|
||||
return std::ptr::null_mut();
|
||||
};
|
||||
|
||||
let Ok(uuid) = uuid::Uuid::parse_str(&entity_uuid) else {
|
||||
return std::ptr::null_mut();
|
||||
};
|
||||
|
||||
let entities = ctx
|
||||
.plugin_context
|
||||
.server
|
||||
.select_entities(&TargetSelector::new(EntitySelectorType::Uuid(uuid)), None);
|
||||
|
||||
if entities.len() != 1 {
|
||||
return std::ptr::null_mut();
|
||||
}
|
||||
|
||||
let entity = entities.first().unwrap().get_entity();
|
||||
let world = entity.world.load();
|
||||
let world_uuid = world.uuid.to_string();
|
||||
|
||||
match CString::new(world_uuid) {
|
||||
Ok(cstring) => cstring.into_raw(), // Transfers ownership to caller
|
||||
Err(_) => std::ptr::null_mut(),
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user