Refactor get location

This commit is contained in:
Bjorn Beishline 2026-02-03 17:12:09 -07:00
parent 605858e14f
commit 4829d59c1e
7 changed files with 65 additions and 67 deletions

View File

@ -14,7 +14,6 @@ public class NativePatchBukkit {
private static final Linker LINKER = Linker.nativeLinker();
private static MethodHandle getLocationNative;
private static MethodHandle getWorldNative;
private static MethodHandle freeStringNative;
private static MethodHandle getRegistryDataNative;
@ -180,22 +179,12 @@ public class NativePatchBukkit {
* Called from Rust during initialization to register native function pointers.
*/
public static void initCallbacks(
long getLocationAddr,
long freeStringAddr,
long getWorldAddr,
long getRegistryDataAddr,
long playerEntityPlaySoundAddr,
long playerPlaySoundAddr
) {
// 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
)
);
// const char* rust_get_world(const char* uuid)
getWorldNative = LINKER.downcallHandle(
@ -246,36 +235,6 @@ 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);
}
}
/**
* Free a string allocated by the Rust side.
*/

View File

@ -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.BridgeUtils;
import org.patchbukkit.bridge.NativePatchBukkit;
import org.patchbukkit.world.PatchBukkitWorld;
@ -47,6 +48,7 @@ import io.papermc.paper.entity.TeleportFlag;
import io.papermc.paper.threadedregions.scheduler.EntityScheduler;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.util.TriState;
import patchbukkit.bridge.NativeBridgeFfi;
public class PatchBukkitEntity implements Entity {
@ -262,8 +264,10 @@ public class PatchBukkitEntity implements Entity {
@Override
public @NotNull Location getLocation() {
var loc = NativePatchBukkit.getLocation(this.uuid);
return new Location(this.getWorld(), loc.x(), loc.y(), loc.z());
var location = NativeBridgeFfi.getLocation(BridgeUtils.convertUuid(this.uuid));
var world = PatchBukkitWorld.getOrCreate(BridgeUtils.convertUuid(location.getWorld().getUuid()));
var position = location.getPosition();
return new Location(world, position.getX(), position.getY(), position.getZ(), location.getYaw(), location.getPitch());
}
@Override

View File

@ -11,7 +11,11 @@ import "patchbukkit/message.proto";
service NativeBridge {
rpc GetAbilities(patchbukkit.common.UUID) returns (patchbukkit.abilities.Abilities);
rpc SetAbilities(patchbukkit.abilities.SetAbilitiesRequest) returns (patchbukkit.abilities.SetAbilitiesResponse);
rpc RegisterEvent(patchbukkit.events.RegisterEventRequest) returns (google.protobuf.Empty);
rpc CallEvent(patchbukkit.events.CallEventRequest) returns (patchbukkit.events.CallEventResponse);
rpc SendMessage(patchbukkit.message.SendMessageRequest) returns (google.protobuf.Empty);
rpc GetLocation(patchbukkit.common.UUID) returns (patchbukkit.common.Location);
}

View File

@ -8,3 +8,20 @@ option java_package = "patchbukkit.common";
message UUID {
string value = 1;
}
message Vec3 {
double x = 1;
double y = 2;
double z = 3;
}
message World {
UUID uuid = 1;
}
message Location {
World world = 1;
Vec3 position = 2;
float yaw = 3;
float pitch = 4;
}

View File

@ -6,7 +6,7 @@ use crate::proto::patchbukkit::{
pub fn ffi_native_bridge_get_abilities_impl(request: Uuid) -> Option<Abilities> {
let ctx = CALLBACK_CONTEXT.get()?;
let player_uuid = uuid::Uuid::parse_str(&request.value).unwrap();
let player_uuid = uuid::Uuid::parse_str(&request.value).ok()?;
let mut abilities = Abilities::default();
let player = ctx.plugin_context.server.get_player_by_uuid(player_uuid)?;
let pumpkin_abilities = tokio::task::block_in_place(|| {

View File

@ -2,7 +2,10 @@ use std::ffi::c_char;
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},
proto::patchbukkit::common::{Location, Uuid, Vec3, World},
};
#[repr(C)]
pub struct Vec3FFI {
@ -11,28 +14,41 @@ pub struct Vec3FFI {
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 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 position =
tokio::task::block_in_place(|| ctx.runtime.block_on(async { entity.pos.load() }));
pub fn ffi_native_bridge_get_location_impl(entity_uuid: Uuid) -> Option<Location> {
let ctx = CALLBACK_CONTEXT.get()?;
let uuid = uuid::Uuid::parse_str(&entity_uuid.value).ok()?;
unsafe {
(*out).x = position.x;
(*out).y = position.y;
(*out).z = position.z;
}
let entity = ctx
.plugin_context
.server
.select_entities(&TargetSelector::new(EntitySelectorType::Uuid(uuid)), None);
return true;
}
if entity.len() == 1 {
let entity = entity.first().unwrap().get_entity();
let position = entity.pos.load();
let world = entity.world.load().uuid;
let yaw = entity.yaw.load();
let pitch = entity.pitch.load();
let mut response_position = Vec3::default();
response_position.x = position.x;
response_position.y = position.y;
response_position.z = position.z;
let mut world_uuid = Uuid::default();
world_uuid.value = world.to_string();
let mut response_world = World::default();
response_world.uuid = Some(world_uuid);
let mut location = Location::default();
location.pitch = pitch;
location.position = Some(response_position);
location.world = Some(response_world);
location.yaw = yaw;
return Some(location);
}
false
None
}

View File

@ -79,7 +79,6 @@ pub extern "C" fn rust_free_bytes(ptr: *mut u8, len: u32) {
}
pub fn initialize_callbacks(jvm: &Jvm) -> Result<()> {
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;
let rust_get_registry_data_addr = registry::rust_get_registry_data as *const () as i64;
@ -91,7 +90,6 @@ pub fn initialize_callbacks(jvm: &Jvm) -> Result<()> {
"org.patchbukkit.bridge.NativePatchBukkit",
"initCallbacks",
&[
InvocationArg::try_from(get_location_addr)?.into_primitive()?,
InvocationArg::try_from(free_string_addr)?.into_primitive()?,
InvocationArg::try_from(get_world_addr)?.into_primitive()?,
InvocationArg::try_from(rust_get_registry_data_addr)?.into_primitive()?,