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 getAbilitiesNative;
|
||||||
private static MethodHandle setAbilitiesNative;
|
private static MethodHandle setAbilitiesNative;
|
||||||
private static MethodHandle getLocationNative;
|
private static MethodHandle getLocationNative;
|
||||||
|
private static MethodHandle getWorldNative;
|
||||||
|
private static MethodHandle freeStringNative;
|
||||||
|
|
||||||
// Struct layout matching Rust's #[repr(C)] AbilitiesFFI
|
// Struct layout matching Rust's #[repr(C)] AbilitiesFFI
|
||||||
private static final StructLayout ABILITIES_LAYOUT =
|
private static final StructLayout ABILITIES_LAYOUT =
|
||||||
@ -223,6 +225,19 @@ public class NativePatchBukkit {
|
|||||||
ValueLayout.ADDRESS // out pointer to Vec3FFI
|
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);
|
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 abilities;
|
||||||
pub mod events;
|
pub mod events;
|
||||||
pub mod location;
|
pub mod location;
|
||||||
|
pub mod memory;
|
||||||
pub mod message;
|
pub mod message;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
pub mod world;
|
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 get_abilities_addr = abilities::rust_get_abilities as *const () as i64;
|
||||||
let set_abilities_addr = abilities::rust_set_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 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(
|
jvm.invoke_static(
|
||||||
"org.patchbukkit.bridge.NativePatchBukkit",
|
"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(get_abilities_addr)?.into_primitive()?,
|
||||||
InvocationArg::try_from(set_abilities_addr)?.into_primitive()?,
|
InvocationArg::try_from(set_abilities_addr)?.into_primitive()?,
|
||||||
InvocationArg::try_from(get_location_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};
|
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 {
|
pub extern "C" fn rust_get_world(entity_uuid_ptr: *const c_char) -> *mut c_char {
|
||||||
let uuid_str = get_string(uuid_ptr);
|
if entity_uuid_ptr.is_null() {
|
||||||
if let Some(ctx) = CALLBACK_CONTEXT.get() {
|
return std::ptr::null_mut();
|
||||||
let uuid = uuid::Uuid::parse_str(&uuid_str).unwrap();
|
}
|
||||||
let entity = ctx
|
|
||||||
|
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
|
.plugin_context
|
||||||
.server
|
.server
|
||||||
.select_entities(&TargetSelector::new(EntitySelectorType::Uuid(uuid)), None);
|
.select_entities(&TargetSelector::new(EntitySelectorType::Uuid(uuid)), None);
|
||||||
if entity.len() == 1 {
|
|
||||||
let entity = entity.first().unwrap().get_entity();
|
if entities.len() != 1 {
|
||||||
|
return std::ptr::null_mut();
|
||||||
|
}
|
||||||
|
|
||||||
|
let entity = entities.first().unwrap().get_entity();
|
||||||
let world = entity.world.load();
|
let world = entity.world.load();
|
||||||
|
let world_uuid = world.uuid.to_string();
|
||||||
|
|
||||||
let cstring = match CString::new(world.dimension.minecraft_name) {
|
match CString::new(world_uuid) {
|
||||||
Ok(s) => s,
|
Ok(cstring) => cstring.into_raw(), // Transfers ownership to caller
|
||||||
Err(_) => return std::ptr::null(),
|
Err(_) => std::ptr::null_mut(),
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
std::ptr::null()
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user