Add get location
This commit is contained in:
parent
609f894c56
commit
a8b14af252
@ -15,6 +15,7 @@ public class NativePatchBukkit {
|
||||
private static MethodHandle registerEventNative;
|
||||
private static MethodHandle getAbilitiesNative;
|
||||
private static MethodHandle setAbilitiesNative;
|
||||
private static MethodHandle getLocationNative;
|
||||
|
||||
// Struct layout matching Rust's #[repr(C)] AbilitiesFFI
|
||||
private static final StructLayout ABILITIES_LAYOUT = MemoryLayout.structLayout(
|
||||
@ -44,6 +45,25 @@ public class NativePatchBukkit {
|
||||
private static final VarHandle WALK_SPEED = ABILITIES_LAYOUT.varHandle(
|
||||
MemoryLayout.PathElement.groupElement("walk_speed"));
|
||||
|
||||
|
||||
// Struct layout for Vec3
|
||||
private static final StructLayout VEC3_LAYOUT = MemoryLayout.structLayout(
|
||||
ValueLayout.JAVA_DOUBLE.withName("x"),
|
||||
ValueLayout.JAVA_DOUBLE.withName("y"),
|
||||
ValueLayout.JAVA_DOUBLE.withName("z")
|
||||
);
|
||||
|
||||
// VarHandles for Vec3 fields
|
||||
private static final VarHandle VEC3_X = VEC3_LAYOUT.varHandle(
|
||||
MemoryLayout.PathElement.groupElement("x"));
|
||||
private static final VarHandle VEC3_Y = VEC3_LAYOUT.varHandle(
|
||||
MemoryLayout.PathElement.groupElement("y"));
|
||||
private static final VarHandle VEC3_Z = VEC3_LAYOUT.varHandle(
|
||||
MemoryLayout.PathElement.groupElement("z"));
|
||||
|
||||
public record Vec3(double x, double y, double z) {}
|
||||
|
||||
|
||||
/**
|
||||
* Java record to hold player abilities.
|
||||
*/
|
||||
@ -89,7 +109,7 @@ public class NativePatchBukkit {
|
||||
/**
|
||||
* Called from Rust during initialization to register native function pointers.
|
||||
*/
|
||||
public static void initCallbacks(long sendMessageAddr, long registerEventAddr, long getAbilitiesAddr, long setAbilitiesAddr) {
|
||||
public static void initCallbacks(long sendMessageAddr, long registerEventAddr, long getAbilitiesAddr, long setAbilitiesAddr, long getLocationAddr) {
|
||||
// void rust_send_message(const char* uuid, const char* message)
|
||||
sendMessageNative = LINKER.downcallHandle(
|
||||
MemorySegment.ofAddress(sendMessageAddr),
|
||||
@ -121,6 +141,16 @@ public class NativePatchBukkit {
|
||||
ValueLayout.ADDRESS // pointer to AbilitiesFFI
|
||||
)
|
||||
);
|
||||
|
||||
// bool rust_get_location(const char* uuid, Vec3FFI* out)
|
||||
getLocationNative = LINKER.downcallHandle(
|
||||
MemorySegment.ofAddress(getLocationAddr),
|
||||
FunctionDescriptor.of(
|
||||
ValueLayout.JAVA_BOOLEAN, // return type
|
||||
ValueLayout.ADDRESS, // uuid string
|
||||
ValueLayout.ADDRESS // out pointer to Vec3FFI
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -205,4 +235,30 @@ public class NativePatchBukkit {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a player's location by UUID.
|
||||
*
|
||||
* @param uuid The player's UUID
|
||||
* @return The player's position, or null if player not found
|
||||
*/
|
||||
public static Vec3 getLocation(UUID uuid) {
|
||||
try (Arena arena = Arena.ofConfined()) {
|
||||
MemorySegment uuidStr = arena.allocateFrom(uuid.toString());
|
||||
MemorySegment outStruct = arena.allocate(VEC3_LAYOUT);
|
||||
|
||||
boolean success = (boolean) getLocationNative.invokeExact(uuidStr, outStruct);
|
||||
|
||||
if (!success) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Vec3(
|
||||
(double) VEC3_X.get(outStruct, 0L),
|
||||
(double) VEC3_Y.get(outStruct, 0L),
|
||||
(double) VEC3_Z.get(outStruct, 0L)
|
||||
);
|
||||
} catch (Throwable t) {
|
||||
throw new RuntimeException("Failed to call native getLocation", t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,6 +37,7 @@ import org.bukkit.util.BoundingBox;
|
||||
import org.bukkit.util.Vector;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.patchbukkit.bridge.NativePatchBukkit;
|
||||
|
||||
import io.papermc.paper.datacomponent.DataComponentType;
|
||||
import io.papermc.paper.datacomponent.DataComponentType.Valued;
|
||||
@ -259,14 +260,19 @@ public class PatchBukkitEntity implements Entity {
|
||||
|
||||
@Override
|
||||
public @NotNull Location getLocation() {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'getLocation'");
|
||||
var loc = NativePatchBukkit.getLocation(this.uuid);
|
||||
return new Location(this.getWorld(), loc.x(), loc.y(), loc.z());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Location getLocation(@Nullable Location loc) {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'getLocation'");
|
||||
if (loc == null) {
|
||||
return this.getLocation();
|
||||
}
|
||||
|
||||
var newLoc = this.getLocation();
|
||||
loc.set(newLoc.x(), newLoc.y(), newLoc.z());
|
||||
return newLoc;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
use std::ffi::{CStr, c_char};
|
||||
use std::ffi::c_char;
|
||||
|
||||
use pumpkin::entity::player::Abilities;
|
||||
use tokio::sync::MutexGuard;
|
||||
|
||||
use crate::java::native_callbacks::CALLBACK_CONTEXT;
|
||||
use crate::java::native_callbacks::{CALLBACK_CONTEXT, utils::get_string};
|
||||
|
||||
#[repr(C)]
|
||||
pub struct AbilitiesFFI {
|
||||
@ -34,7 +34,7 @@ pub extern "C" fn rust_set_abilities(
|
||||
uuid_ptr: *const c_char,
|
||||
abilities: *mut AbilitiesFFI,
|
||||
) -> bool {
|
||||
let uuid_str = unsafe { CStr::from_ptr(uuid_ptr).to_string_lossy().into_owned() };
|
||||
let uuid_str = get_string(uuid_ptr);
|
||||
if let Some(ctx) = CALLBACK_CONTEXT.get() {
|
||||
let uuid = uuid::Uuid::parse_str(&uuid_str).unwrap();
|
||||
let player = ctx.plugin_context.server.get_player_by_uuid(uuid);
|
||||
@ -62,7 +62,7 @@ pub extern "C" fn rust_set_abilities(
|
||||
}
|
||||
|
||||
pub extern "C" fn rust_get_abilities(uuid_ptr: *const c_char, out: *mut AbilitiesFFI) -> bool {
|
||||
let uuid_str = unsafe { CStr::from_ptr(uuid_ptr).to_string_lossy().into_owned() };
|
||||
let uuid_str = get_string(uuid_ptr);
|
||||
if let Some(ctx) = CALLBACK_CONTEXT.get() {
|
||||
let uuid = uuid::Uuid::parse_str(&uuid_str).unwrap();
|
||||
let player = ctx.plugin_context.server.get_player_by_uuid(uuid);
|
||||
|
||||
32
rust/src/java/native_callbacks/location.rs
Normal file
32
rust/src/java/native_callbacks/location.rs
Normal file
@ -0,0 +1,32 @@
|
||||
use std::ffi::c_char;
|
||||
|
||||
use crate::java::native_callbacks::{CALLBACK_CONTEXT, utils::get_string};
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Vec3FFI {
|
||||
pub x: f64,
|
||||
pub y: f64,
|
||||
pub z: f64,
|
||||
}
|
||||
|
||||
pub extern "C" fn rust_get_location(uuid_ptr: *const c_char, out: *mut Vec3FFI) -> bool {
|
||||
let uuid_str = get_string(uuid_ptr);
|
||||
if let Some(ctx) = CALLBACK_CONTEXT.get() {
|
||||
let uuid = uuid::Uuid::parse_str(&uuid_str).unwrap();
|
||||
let player = ctx.plugin_context.server.get_player_by_uuid(uuid);
|
||||
if let Some(player) = player {
|
||||
let position =
|
||||
tokio::task::block_in_place(|| ctx.runtime.block_on(async { player.position() }));
|
||||
|
||||
unsafe {
|
||||
(*out).x = position.x;
|
||||
(*out).y = position.y;
|
||||
(*out).z = position.z;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
@ -1,14 +1,13 @@
|
||||
use std::ffi::{CStr, c_char};
|
||||
use std::ffi::c_char;
|
||||
|
||||
use pumpkin_util::text::TextComponent;
|
||||
|
||||
use crate::java::native_callbacks::CALLBACK_CONTEXT;
|
||||
use crate::java::native_callbacks::{CALLBACK_CONTEXT, utils::get_string};
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn rust_send_message(uuid_ptr: *const c_char, message_ptr: *const c_char) {
|
||||
// This into_owned might not seem to make any sense, but it's necessary to ensure that the string is owned by the Rust code and can move into the runtime.
|
||||
let uuid_str = unsafe { CStr::from_ptr(uuid_ptr).to_string_lossy().into_owned() };
|
||||
let message = unsafe { CStr::from_ptr(message_ptr).to_string_lossy().into_owned() };
|
||||
let uuid_str = get_string(uuid_ptr);
|
||||
let message = get_string(message_ptr);
|
||||
|
||||
if let Some(ctx) = CALLBACK_CONTEXT.get() {
|
||||
let uuid = uuid::Uuid::parse_str(&uuid_str).unwrap();
|
||||
|
||||
@ -6,7 +6,9 @@ use pumpkin::plugin::Context;
|
||||
|
||||
pub mod abilities;
|
||||
pub mod events;
|
||||
pub mod location;
|
||||
pub mod message;
|
||||
pub mod utils;
|
||||
|
||||
static CALLBACK_CONTEXT: OnceLock<CallbackContext> = OnceLock::new();
|
||||
|
||||
@ -35,6 +37,7 @@ pub fn initialize_callbacks(jvm: &Jvm) -> Result<()> {
|
||||
let register_event_addr = events::rust_register_event 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 get_location_addr = location::rust_get_location as *const () as i64;
|
||||
|
||||
jvm.invoke_static(
|
||||
"org.patchbukkit.bridge.NativePatchBukkit",
|
||||
@ -44,6 +47,7 @@ pub fn initialize_callbacks(jvm: &Jvm) -> Result<()> {
|
||||
InvocationArg::try_from(register_event_addr)?.into_primitive()?,
|
||||
InvocationArg::try_from(get_abilities_addr)?.into_primitive()?,
|
||||
InvocationArg::try_from(set_abilities_addr)?.into_primitive()?,
|
||||
InvocationArg::try_from(get_location_addr)?.into_primitive()?,
|
||||
],
|
||||
)?;
|
||||
|
||||
|
||||
5
rust/src/java/native_callbacks/utils.rs
Normal file
5
rust/src/java/native_callbacks/utils.rs
Normal file
@ -0,0 +1,5 @@
|
||||
use std::ffi::{CStr, c_char};
|
||||
|
||||
pub fn get_string(str_ptr: *const c_char) -> String {
|
||||
unsafe { CStr::from_ptr(str_ptr).to_string_lossy().into_owned() }
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user