Use entity instead of player
This commit is contained in:
parent
26b9727166
commit
4a906ae3dc
@ -4,11 +4,11 @@ import java.lang.foreign.*;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
public class NativePatchBukkit {
|
||||
|
||||
private static final Linker LINKER = Linker.nativeLinker();
|
||||
|
||||
private static MethodHandle sendMessageNative;
|
||||
@ -18,33 +18,41 @@ public class NativePatchBukkit {
|
||||
private static MethodHandle getLocationNative;
|
||||
|
||||
// Struct layout matching Rust's #[repr(C)] AbilitiesFFI
|
||||
private static final StructLayout ABILITIES_LAYOUT = MemoryLayout.structLayout(
|
||||
ValueLayout.JAVA_BOOLEAN.withName("invulnerable"),
|
||||
ValueLayout.JAVA_BOOLEAN.withName("flying"),
|
||||
ValueLayout.JAVA_BOOLEAN.withName("allow_flying"),
|
||||
ValueLayout.JAVA_BOOLEAN.withName("creative"),
|
||||
ValueLayout.JAVA_BOOLEAN.withName("allow_modify_world"),
|
||||
MemoryLayout.paddingLayout(3), // Padding to align f32 to 4-byte boundary
|
||||
ValueLayout.JAVA_FLOAT.withName("fly_speed"),
|
||||
ValueLayout.JAVA_FLOAT.withName("walk_speed")
|
||||
);
|
||||
private static final StructLayout ABILITIES_LAYOUT =
|
||||
MemoryLayout.structLayout(
|
||||
ValueLayout.JAVA_BOOLEAN.withName("invulnerable"),
|
||||
ValueLayout.JAVA_BOOLEAN.withName("flying"),
|
||||
ValueLayout.JAVA_BOOLEAN.withName("allow_flying"),
|
||||
ValueLayout.JAVA_BOOLEAN.withName("creative"),
|
||||
ValueLayout.JAVA_BOOLEAN.withName("allow_modify_world"),
|
||||
MemoryLayout.paddingLayout(3), // Padding to align f32 to 4-byte boundary
|
||||
ValueLayout.JAVA_FLOAT.withName("fly_speed"),
|
||||
ValueLayout.JAVA_FLOAT.withName("walk_speed")
|
||||
);
|
||||
|
||||
// VarHandles for accessing struct fields
|
||||
private static final VarHandle INVULNERABLE = ABILITIES_LAYOUT.varHandle(
|
||||
MemoryLayout.PathElement.groupElement("invulnerable"));
|
||||
MemoryLayout.PathElement.groupElement("invulnerable")
|
||||
);
|
||||
private static final VarHandle FLYING = ABILITIES_LAYOUT.varHandle(
|
||||
MemoryLayout.PathElement.groupElement("flying"));
|
||||
MemoryLayout.PathElement.groupElement("flying")
|
||||
);
|
||||
private static final VarHandle ALLOW_FLYING = ABILITIES_LAYOUT.varHandle(
|
||||
MemoryLayout.PathElement.groupElement("allow_flying"));
|
||||
MemoryLayout.PathElement.groupElement("allow_flying")
|
||||
);
|
||||
private static final VarHandle CREATIVE = ABILITIES_LAYOUT.varHandle(
|
||||
MemoryLayout.PathElement.groupElement("creative"));
|
||||
private static final VarHandle ALLOW_MODIFY_WORLD = ABILITIES_LAYOUT.varHandle(
|
||||
MemoryLayout.PathElement.groupElement("allow_modify_world"));
|
||||
MemoryLayout.PathElement.groupElement("creative")
|
||||
);
|
||||
private static final VarHandle ALLOW_MODIFY_WORLD =
|
||||
ABILITIES_LAYOUT.varHandle(
|
||||
MemoryLayout.PathElement.groupElement("allow_modify_world")
|
||||
);
|
||||
private static final VarHandle FLY_SPEED = ABILITIES_LAYOUT.varHandle(
|
||||
MemoryLayout.PathElement.groupElement("fly_speed"));
|
||||
MemoryLayout.PathElement.groupElement("fly_speed")
|
||||
);
|
||||
private static final VarHandle WALK_SPEED = ABILITIES_LAYOUT.varHandle(
|
||||
MemoryLayout.PathElement.groupElement("walk_speed"));
|
||||
|
||||
MemoryLayout.PathElement.groupElement("walk_speed")
|
||||
);
|
||||
|
||||
// Struct layout for Vec3
|
||||
private static final StructLayout VEC3_LAYOUT = MemoryLayout.structLayout(
|
||||
@ -55,61 +63,125 @@ public class NativePatchBukkit {
|
||||
|
||||
// VarHandles for Vec3 fields
|
||||
private static final VarHandle VEC3_X = VEC3_LAYOUT.varHandle(
|
||||
MemoryLayout.PathElement.groupElement("x"));
|
||||
MemoryLayout.PathElement.groupElement("x")
|
||||
);
|
||||
private static final VarHandle VEC3_Y = VEC3_LAYOUT.varHandle(
|
||||
MemoryLayout.PathElement.groupElement("y"));
|
||||
MemoryLayout.PathElement.groupElement("y")
|
||||
);
|
||||
private static final VarHandle VEC3_Z = VEC3_LAYOUT.varHandle(
|
||||
MemoryLayout.PathElement.groupElement("z"));
|
||||
MemoryLayout.PathElement.groupElement("z")
|
||||
);
|
||||
|
||||
public record Vec3(double x, double y, double z) {}
|
||||
|
||||
|
||||
/**
|
||||
* Java record to hold player abilities.
|
||||
*/
|
||||
public record Abilities(
|
||||
boolean invulnerable,
|
||||
boolean flying,
|
||||
boolean allowFlying,
|
||||
boolean creative,
|
||||
boolean allowModifyWorld,
|
||||
float flySpeed,
|
||||
float walkSpeed
|
||||
) {
|
||||
// "Wither" methods - return a copy with one field changed
|
||||
public Abilities withInvulnerable(boolean value) {
|
||||
return new Abilities(value, flying, allowFlying, creative, allowModifyWorld, flySpeed, walkSpeed);
|
||||
}
|
||||
public record Abilities(
|
||||
boolean invulnerable,
|
||||
boolean flying,
|
||||
boolean allowFlying,
|
||||
boolean creative,
|
||||
boolean allowModifyWorld,
|
||||
float flySpeed,
|
||||
float walkSpeed
|
||||
) {
|
||||
// "Wither" methods - return a copy with one field changed
|
||||
public Abilities withInvulnerable(boolean value) {
|
||||
return new Abilities(
|
||||
value,
|
||||
flying,
|
||||
allowFlying,
|
||||
creative,
|
||||
allowModifyWorld,
|
||||
flySpeed,
|
||||
walkSpeed
|
||||
);
|
||||
}
|
||||
|
||||
public Abilities withFlying(boolean value) {
|
||||
return new Abilities(invulnerable, value, allowFlying, creative, allowModifyWorld, flySpeed, walkSpeed);
|
||||
}
|
||||
public Abilities withFlying(boolean value) {
|
||||
return new Abilities(
|
||||
invulnerable,
|
||||
value,
|
||||
allowFlying,
|
||||
creative,
|
||||
allowModifyWorld,
|
||||
flySpeed,
|
||||
walkSpeed
|
||||
);
|
||||
}
|
||||
|
||||
public Abilities withAllowFlying(boolean value) {
|
||||
return new Abilities(invulnerable, flying, value, creative, allowModifyWorld, flySpeed, walkSpeed);
|
||||
}
|
||||
public Abilities withAllowFlying(boolean value) {
|
||||
return new Abilities(
|
||||
invulnerable,
|
||||
flying,
|
||||
value,
|
||||
creative,
|
||||
allowModifyWorld,
|
||||
flySpeed,
|
||||
walkSpeed
|
||||
);
|
||||
}
|
||||
|
||||
public Abilities withCreative(boolean value) {
|
||||
return new Abilities(invulnerable, flying, allowFlying, value, allowModifyWorld, flySpeed, walkSpeed);
|
||||
}
|
||||
public Abilities withCreative(boolean value) {
|
||||
return new Abilities(
|
||||
invulnerable,
|
||||
flying,
|
||||
allowFlying,
|
||||
value,
|
||||
allowModifyWorld,
|
||||
flySpeed,
|
||||
walkSpeed
|
||||
);
|
||||
}
|
||||
|
||||
public Abilities withAllowModifyWorld(boolean value) {
|
||||
return new Abilities(invulnerable, flying, allowFlying, creative, value, flySpeed, walkSpeed);
|
||||
}
|
||||
public Abilities withAllowModifyWorld(boolean value) {
|
||||
return new Abilities(
|
||||
invulnerable,
|
||||
flying,
|
||||
allowFlying,
|
||||
creative,
|
||||
value,
|
||||
flySpeed,
|
||||
walkSpeed
|
||||
);
|
||||
}
|
||||
|
||||
public Abilities withFlySpeed(float value) {
|
||||
return new Abilities(invulnerable, flying, allowFlying, creative, allowModifyWorld, value, walkSpeed);
|
||||
}
|
||||
public Abilities withFlySpeed(float value) {
|
||||
return new Abilities(
|
||||
invulnerable,
|
||||
flying,
|
||||
allowFlying,
|
||||
creative,
|
||||
allowModifyWorld,
|
||||
value,
|
||||
walkSpeed
|
||||
);
|
||||
}
|
||||
|
||||
public Abilities withWalkSpeed(float value) {
|
||||
return new Abilities(invulnerable, flying, allowFlying, creative, allowModifyWorld, flySpeed, value);
|
||||
}
|
||||
}
|
||||
public Abilities withWalkSpeed(float value) {
|
||||
return new Abilities(
|
||||
invulnerable,
|
||||
flying,
|
||||
allowFlying,
|
||||
creative,
|
||||
allowModifyWorld,
|
||||
flySpeed,
|
||||
value
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from Rust during initialization to register native function pointers.
|
||||
*/
|
||||
public static void initCallbacks(long sendMessageAddr, long registerEventAddr, long getAbilitiesAddr, long setAbilitiesAddr, long getLocationAddr) {
|
||||
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),
|
||||
@ -126,9 +198,9 @@ public class NativePatchBukkit {
|
||||
getAbilitiesNative = LINKER.downcallHandle(
|
||||
MemorySegment.ofAddress(getAbilitiesAddr),
|
||||
FunctionDescriptor.of(
|
||||
ValueLayout.JAVA_BOOLEAN, // return type
|
||||
ValueLayout.ADDRESS, // uuid string
|
||||
ValueLayout.ADDRESS // out pointer to AbilitiesFFI
|
||||
ValueLayout.JAVA_BOOLEAN, // return type
|
||||
ValueLayout.ADDRESS, // uuid string
|
||||
ValueLayout.ADDRESS // out pointer to AbilitiesFFI
|
||||
)
|
||||
);
|
||||
|
||||
@ -136,9 +208,9 @@ public class NativePatchBukkit {
|
||||
setAbilitiesNative = LINKER.downcallHandle(
|
||||
MemorySegment.ofAddress(setAbilitiesAddr),
|
||||
FunctionDescriptor.of(
|
||||
ValueLayout.JAVA_BOOLEAN, // return type
|
||||
ValueLayout.ADDRESS, // uuid string
|
||||
ValueLayout.ADDRESS // pointer to AbilitiesFFI
|
||||
ValueLayout.JAVA_BOOLEAN, // return type
|
||||
ValueLayout.ADDRESS, // uuid string
|
||||
ValueLayout.ADDRESS // pointer to AbilitiesFFI
|
||||
)
|
||||
);
|
||||
|
||||
@ -146,9 +218,9 @@ public class NativePatchBukkit {
|
||||
getLocationNative = LINKER.downcallHandle(
|
||||
MemorySegment.ofAddress(getLocationAddr),
|
||||
FunctionDescriptor.of(
|
||||
ValueLayout.JAVA_BOOLEAN, // return type
|
||||
ValueLayout.ADDRESS, // uuid string
|
||||
ValueLayout.ADDRESS // out pointer to Vec3FFI
|
||||
ValueLayout.JAVA_BOOLEAN, // return type
|
||||
ValueLayout.ADDRESS, // uuid string
|
||||
ValueLayout.ADDRESS // out pointer to Vec3FFI
|
||||
)
|
||||
);
|
||||
}
|
||||
@ -177,7 +249,9 @@ public class NativePatchBukkit {
|
||||
// Simple approach - pass plugin name, handle lookup in Rust
|
||||
try (Arena arena = Arena.ofConfined()) {
|
||||
MemorySegment pluginName = arena.allocateFrom(plugin.getName());
|
||||
MemorySegment listenerClass = arena.allocateFrom(listener.getClass().getName());
|
||||
MemorySegment listenerClass = arena.allocateFrom(
|
||||
listener.getClass().getName()
|
||||
);
|
||||
registerEventNative.invokeExact(listenerClass, pluginName);
|
||||
} catch (Throwable t) {
|
||||
throw new RuntimeException("Failed to register event", t);
|
||||
@ -195,7 +269,10 @@ public class NativePatchBukkit {
|
||||
MemorySegment uuidStr = arena.allocateFrom(uuid.toString());
|
||||
MemorySegment outStruct = arena.allocate(ABILITIES_LAYOUT);
|
||||
|
||||
boolean success = (boolean) getAbilitiesNative.invokeExact(uuidStr, outStruct);
|
||||
boolean success = (boolean) getAbilitiesNative.invokeExact(
|
||||
uuidStr,
|
||||
outStruct
|
||||
);
|
||||
|
||||
if (!success) {
|
||||
return null;
|
||||
@ -225,11 +302,18 @@ public class NativePatchBukkit {
|
||||
FLYING.set(abilitiesStruct, 0L, abilities.flying());
|
||||
ALLOW_FLYING.set(abilitiesStruct, 0L, abilities.allowFlying());
|
||||
CREATIVE.set(abilitiesStruct, 0L, abilities.creative());
|
||||
ALLOW_MODIFY_WORLD.set(abilitiesStruct, 0L, abilities.allowModifyWorld());
|
||||
ALLOW_MODIFY_WORLD.set(
|
||||
abilitiesStruct,
|
||||
0L,
|
||||
abilities.allowModifyWorld()
|
||||
);
|
||||
FLY_SPEED.set(abilitiesStruct, 0L, abilities.flySpeed());
|
||||
WALK_SPEED.set(abilitiesStruct, 0L, abilities.walkSpeed());
|
||||
|
||||
return (boolean) setAbilitiesNative.invokeExact(uuidStr, abilitiesStruct);
|
||||
return (boolean) setAbilitiesNative.invokeExact(
|
||||
uuidStr,
|
||||
abilitiesStruct
|
||||
);
|
||||
} catch (Throwable t) {
|
||||
throw new RuntimeException("Failed to call native setAbilities", t);
|
||||
}
|
||||
@ -246,7 +330,10 @@ public class NativePatchBukkit {
|
||||
MemorySegment uuidStr = arena.allocateFrom(uuid.toString());
|
||||
MemorySegment outStruct = arena.allocate(VEC3_LAYOUT);
|
||||
|
||||
boolean success = (boolean) getLocationNative.invokeExact(uuidStr, outStruct);
|
||||
boolean success = (boolean) getLocationNative.invokeExact(
|
||||
uuidStr,
|
||||
outStruct
|
||||
);
|
||||
|
||||
if (!success) {
|
||||
return null;
|
||||
|
||||
8
rust/Cargo.lock
generated
8
rust/Cargo.lock
generated
@ -1875,15 +1875,15 @@ checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.13.0"
|
||||
version = "1.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950"
|
||||
checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic-util"
|
||||
version = "0.2.4"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507"
|
||||
checksum = "7a9db96d7fa8782dd8c15ce32ffe8680bbd1e978a43bf51a34d39483540495f5"
|
||||
dependencies = [
|
||||
"portable-atomic",
|
||||
]
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
use std::ffi::c_char;
|
||||
|
||||
use pumpkin::command::args::entities::{EntitySelectorType, TargetSelector};
|
||||
|
||||
use crate::java::native_callbacks::{CALLBACK_CONTEXT, utils::get_string};
|
||||
|
||||
#[repr(C)]
|
||||
@ -13,10 +15,14 @@ pub extern "C" fn rust_get_location(uuid_ptr: *const c_char, out: *mut Vec3FFI)
|
||||
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 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 { player.position() }));
|
||||
tokio::task::block_in_place(|| ctx.runtime.block_on(async { entity.pos.load() }));
|
||||
|
||||
unsafe {
|
||||
(*out).x = position.x;
|
||||
|
||||
@ -9,6 +9,7 @@ pub mod events;
|
||||
pub mod location;
|
||||
pub mod message;
|
||||
pub mod utils;
|
||||
pub mod world;
|
||||
|
||||
static CALLBACK_CONTEXT: OnceLock<CallbackContext> = OnceLock::new();
|
||||
|
||||
|
||||
27
rust/src/java/native_callbacks/world.rs
Normal file
27
rust/src/java/native_callbacks/world.rs
Normal file
@ -0,0 +1,27 @@
|
||||
use std::ffi::{CString, c_char};
|
||||
|
||||
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(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
std::ptr::null()
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user