more stuff

This commit is contained in:
Alexander Medvedev 2026-07-31 20:45:09 +02:00
parent d48fc61f75
commit 3e3a48e0c1
12 changed files with 404 additions and 27 deletions

View File

@ -641,10 +641,7 @@ public class PatchBukkitServer implements Server {
@Override
public @NotNull WorldBorder createWorldBorder() {
// TODO Auto-generated method stub
throw new UnsupportedOperationException(
"Unimplemented method 'createWorldBorder'"
);
return new org.patchbukkit.world.PatchBukkitWorldBorder(null);
}
@Override

View File

@ -287,6 +287,10 @@ public class PatchBukkitEntity implements Entity {
@Override
public @NotNull Vector getVelocity() {
var resp = NativeBridgeFfi.getEntityVelocity(BridgeUtils.convertUuid(this.uuid));
if (resp != null) {
return new Vector(resp.getX(), resp.getY(), resp.getZ());
}
return this.velocity.clone();
}

View File

@ -50,6 +50,8 @@ import org.checkerframework.checker.index.qual.NonNegative;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Range;
import org.patchbukkit.bridge.BridgeUtils;
import patchbukkit.bridge.NativeBridgeFfi;
import com.destroystokyo.paper.block.TargetBlockInfo;
import com.destroystokyo.paper.block.TargetBlockInfo.FluidMode;
@ -1128,14 +1130,21 @@ public class PatchBukkitHumanEntity
@Override
public GameMode getGameMode() {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'getGameMode'");
var resp = NativeBridgeFfi.getGamemode(BridgeUtils.convertUuid(this.getUniqueId()));
if (resp != null) {
return GameMode.getByValue(resp.getGamemode());
}
return GameMode.SURVIVAL;
}
@Override
public void setGameMode(GameMode mode) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'setGameMode'");
if (mode == null) return;
var request = patchbukkit.entity.SetGamemodeRequest.newBuilder()
.setUuid(BridgeUtils.convertUuid(this.getUniqueId()))
.setGamemode(mode.getValue())
.build();
NativeBridgeFfi.setGamemode(request);
}
@Override

View File

@ -1402,16 +1402,16 @@ public class PatchBukkitPlayer
throw new UnsupportedOperationException("Unimplemented method 'setScoreboard'");
}
private WorldBorder customWorldBorder;
@Override
public @org.jspecify.annotations.Nullable WorldBorder getWorldBorder() {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'getWorldBorder'");
return this.customWorldBorder != null ? this.customWorldBorder : getWorld().getWorldBorder();
}
@Override
public void setWorldBorder(@org.jspecify.annotations.Nullable WorldBorder border) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'setWorldBorder'");
this.customWorldBorder = border;
}
@Override

View File

@ -1379,10 +1379,7 @@ public class PatchBukkitWorld
@Override
public @NotNull WorldBorder getWorldBorder() {
// TODO Auto-generated method stub
throw new UnsupportedOperationException(
"Unimplemented method 'getWorldBorder'"
);
return new PatchBukkitWorldBorder(this);
}
@Override

View File

@ -0,0 +1,222 @@
package org.patchbukkit.world;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.WorldBorder;
import patchbukkit.bridge.NativeBridgeFfi;
import patchbukkit.world.GetWorldBorderRequest;
import patchbukkit.world.SetWorldBorderRequest;
import patchbukkit.world.WorldBorderData;
import org.patchbukkit.bridge.BridgeUtils;
import java.util.concurrent.TimeUnit;
public class PatchBukkitWorldBorder implements WorldBorder {
private final World world;
public PatchBukkitWorldBorder(World world) {
this.world = world;
}
private WorldBorderData getData() {
if (this.world == null) {
return WorldBorderData.newBuilder()
.setCenterX(0.0)
.setCenterZ(0.0)
.setSize(59999968.0)
.setTargetSize(59999968.0)
.setSpeed(0)
.setWarningTime(15)
.setWarningBlocks(5)
.setDamagePerBlock(0.2)
.setDamageBuffer(5.0)
.setMaxCenterCoordinate(29999984)
.build();
}
return NativeBridgeFfi.getWorldBorder(
GetWorldBorderRequest.newBuilder()
.setWorldUuid(BridgeUtils.convertUuid(this.world.getUID()))
.build()
);
}
private void updateData(WorldBorderData.Builder builder) {
if (this.world == null) {
return;
}
NativeBridgeFfi.setWorldBorder(
SetWorldBorderRequest.newBuilder()
.setWorldUuid(BridgeUtils.convertUuid(this.world.getUID()))
.setBorder(builder)
.build()
);
}
@Override
public World getWorld() {
return this.world;
}
@Override
public void reset() {
if (this.world == null) return;
WorldBorderData.Builder builder = getData().toBuilder();
builder.setCenterX(0.0);
builder.setCenterZ(0.0);
builder.setSize(59999968.0);
builder.setTargetSize(59999968.0);
builder.setSpeed(0);
builder.setWarningTime(15);
builder.setWarningBlocks(5);
builder.setDamagePerBlock(0.2);
builder.setDamageBuffer(5.0);
updateData(builder);
}
@Override
public double getSize() {
return getData().getSize();
}
@Override
public void setSize(double newSize) {
if (this.world == null) return;
WorldBorderData.Builder builder = getData().toBuilder();
builder.setSize(newSize);
builder.setTargetSize(newSize);
builder.setSpeed(0);
updateData(builder);
}
@Override
public void setSize(double newSize, long seconds) {
setSize(newSize, TimeUnit.SECONDS, seconds);
}
@Override
public void setSize(double newSize, TimeUnit unit, long time) {
if (this.world == null) return;
long timeInMillis = unit.toMillis(time);
WorldBorderData.Builder builder = getData().toBuilder();
builder.setTargetSize(newSize);
builder.setSpeed(timeInMillis);
updateData(builder);
}
@Override
public void changeSize(double newSize, long seconds) {
setSize(getSize() + newSize, seconds);
}
public void changeSize(double newSize, TimeUnit unit, long time) {
setSize(getSize() + newSize, unit, time);
}
@Override
public Location getCenter() {
WorldBorderData data = getData();
return new Location(this.world, data.getCenterX(), 0.0, data.getCenterZ());
}
@Override
public void setCenter(double x, double z) {
if (this.world == null) return;
WorldBorderData.Builder builder = getData().toBuilder();
builder.setCenterX(x);
builder.setCenterZ(z);
updateData(builder);
}
@Override
public void setCenter(Location location) {
setCenter(location.getX(), location.getZ());
}
@Override
public double getDamageBuffer() {
return getData().getDamageBuffer();
}
@Override
public void setDamageBuffer(double blocks) {
if (this.world == null) return;
WorldBorderData.Builder builder = getData().toBuilder();
builder.setDamageBuffer(blocks);
updateData(builder);
}
@Override
public double getDamageAmount() {
return getData().getDamagePerBlock();
}
@Override
public void setDamageAmount(double damage) {
if (this.world == null) return;
WorldBorderData.Builder builder = getData().toBuilder();
builder.setDamagePerBlock(damage);
updateData(builder);
}
@Override
public int getWarningTime() {
return getData().getWarningTime();
}
@Override
public void setWarningTime(int seconds) {
if (this.world == null) return;
WorldBorderData.Builder builder = getData().toBuilder();
builder.setWarningTime(seconds);
updateData(builder);
}
@Override
public int getWarningTimeTicks() {
return getWarningTime() * 20;
}
@Override
public void setWarningTimeTicks(int ticks) {
setWarningTime(ticks / 20);
}
@Override
public int getWarningDistance() {
return getData().getWarningBlocks();
}
@Override
public void setWarningDistance(int distance) {
if (this.world == null) return;
WorldBorderData.Builder builder = getData().toBuilder();
builder.setWarningBlocks(distance);
updateData(builder);
}
@Override
public boolean isInside(Location location) {
if (location == null) return false;
if (this.world != null && location.getWorld() != null && !this.world.equals(location.getWorld())) {
return false;
}
WorldBorderData data = getData();
double radius = data.getSize() / 2.0;
double minX = data.getCenterX() - radius;
double maxX = data.getCenterX() + radius;
double minZ = data.getCenterZ() - radius;
double maxZ = data.getCenterZ() + radius;
return location.getX() >= minX && location.getX() <= maxX && location.getZ() >= minZ && location.getZ() <= maxZ;
}
@Override
public double getMaxCenterCoordinate() {
return getData().getMaxCenterCoordinate();
}
@Override
public double getMaxSize() {
return getData().getMaxCenterCoordinate() * 2.0;
}
}

View File

@ -21,13 +21,19 @@ service NativeBridge {
rpc GetEntityHealth(patchbukkit.common.UUID) returns (patchbukkit.entity.EntityHealthResponse);
rpc SetEntityHealth(patchbukkit.entity.SetEntityHealthRequest) returns (google.protobuf.Empty);
rpc DamageEntity(patchbukkit.entity.DamageEntityRequest) returns (google.protobuf.Empty);
rpc GetEntityVelocity(patchbukkit.common.UUID) returns (patchbukkit.entity.EntityVelocityResponse);
rpc SetEntityVelocity(patchbukkit.entity.SetEntityVelocityRequest) returns (google.protobuf.Empty);
rpc SetEntityPose(patchbukkit.entity.SetEntityPoseRequest) returns (google.protobuf.Empty);
rpc TeleportEntity(patchbukkit.entity.TeleportEntityRequest) returns (google.protobuf.Empty);
rpc GetGamemode(patchbukkit.common.UUID) returns (patchbukkit.entity.GetGamemodeResponse);
rpc SetGamemode(patchbukkit.entity.SetGamemodeRequest) returns (google.protobuf.Empty);
rpc GetBlockData(patchbukkit.world.GetBlockDataRequest) returns (patchbukkit.world.GetBlockDataResponse);
rpc SetBlockData(patchbukkit.world.SetBlockDataRequest) returns (google.protobuf.Empty);
rpc SpawnParticle(patchbukkit.world.SpawnParticleRequest) returns (google.protobuf.Empty);
rpc GetWorlds(patchbukkit.common.EmptyRequest) returns (patchbukkit.world.GetWorldsResponse);
rpc GetWorldBorder(patchbukkit.world.GetWorldBorderRequest) returns (patchbukkit.world.WorldBorderData);
rpc SetWorldBorder(patchbukkit.world.SetWorldBorderRequest) returns (google.protobuf.Empty);
rpc RegisterEvent(patchbukkit.events.RegisterEventRequest) returns (google.protobuf.Empty);
rpc CallEvent(patchbukkit.events.CallEventRequest) returns (patchbukkit.events.CallEventResponse);

View File

@ -39,3 +39,20 @@ message SetEntityPoseRequest {
string pose = 2;
}
message EntityVelocityResponse {
double x = 1;
double y = 2;
double z = 3;
}
message GetGamemodeResponse {
int32 gamemode = 1;
}
message SetGamemodeRequest {
patchbukkit.common.UUID uuid = 1;
int32 gamemode = 2;
}

View File

@ -44,3 +44,26 @@ message GetWorldsResponse {
repeated patchbukkit.common.UUID world_uuids = 1;
}
message WorldBorderData {
double center_x = 1;
double center_z = 2;
double size = 3;
double target_size = 4;
int64 speed = 5;
int32 warning_time = 6;
int32 warning_blocks = 7;
double damage_per_block = 8;
double damage_buffer = 9;
int32 max_center_coordinate = 10;
}
message GetWorldBorderRequest {
patchbukkit.common.UUID world_uuid = 1;
}
message SetWorldBorderRequest {
patchbukkit.common.UUID world_uuid = 1;
WorldBorderData border = 2;
}

22
rust/Cargo.lock generated
View File

@ -2773,7 +2773,7 @@ dependencies = [
[[package]]
name = "pumpkin"
version = "0.1.0-dev+26.2"
source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#a3b66be27b2f70afc8dbe43923ab2cfbc36e94dd"
source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#75994f3302fa76078087b9a113130541e4d3fc37"
dependencies = [
"arc-swap",
"base64 0.23.0",
@ -2831,7 +2831,7 @@ dependencies = [
[[package]]
name = "pumpkin-api-macros"
version = "0.1.0-dev+26.2"
source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#a3b66be27b2f70afc8dbe43923ab2cfbc36e94dd"
source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#75994f3302fa76078087b9a113130541e4d3fc37"
dependencies = [
"proc-macro-error2",
"proc-macro2",
@ -2842,7 +2842,7 @@ dependencies = [
[[package]]
name = "pumpkin-codecs"
version = "0.1.0-dev+26.2"
source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#a3b66be27b2f70afc8dbe43923ab2cfbc36e94dd"
source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#75994f3302fa76078087b9a113130541e4d3fc37"
dependencies = [
"serde_json",
"tracing",
@ -2851,7 +2851,7 @@ dependencies = [
[[package]]
name = "pumpkin-config"
version = "0.1.0-dev+26.2"
source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#a3b66be27b2f70afc8dbe43923ab2cfbc36e94dd"
source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#75994f3302fa76078087b9a113130541e4d3fc37"
dependencies = [
"pumpkin-util",
"serde",
@ -2863,7 +2863,7 @@ dependencies = [
[[package]]
name = "pumpkin-data"
version = "0.1.0-dev+26.2"
source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#a3b66be27b2f70afc8dbe43923ab2cfbc36e94dd"
source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#75994f3302fa76078087b9a113130541e4d3fc37"
dependencies = [
"crc-fast",
"phf",
@ -2876,7 +2876,7 @@ dependencies = [
[[package]]
name = "pumpkin-inventory"
version = "0.1.0-dev+26.2"
source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#a3b66be27b2f70afc8dbe43923ab2cfbc36e94dd"
source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#75994f3302fa76078087b9a113130541e4d3fc37"
dependencies = [
"pumpkin-data",
"pumpkin-protocol",
@ -2891,7 +2891,7 @@ dependencies = [
[[package]]
name = "pumpkin-macros"
version = "0.1.0-dev+26.2"
source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#a3b66be27b2f70afc8dbe43923ab2cfbc36e94dd"
source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#75994f3302fa76078087b9a113130541e4d3fc37"
dependencies = [
"heck",
"proc-macro-error2",
@ -2903,7 +2903,7 @@ dependencies = [
[[package]]
name = "pumpkin-nbt"
version = "0.1.0-dev+26.2"
source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#a3b66be27b2f70afc8dbe43923ab2cfbc36e94dd"
source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#75994f3302fa76078087b9a113130541e4d3fc37"
dependencies = [
"bytes",
"cesu8",
@ -2918,7 +2918,7 @@ dependencies = [
[[package]]
name = "pumpkin-protocol"
version = "0.1.0-dev+26.2"
source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#a3b66be27b2f70afc8dbe43923ab2cfbc36e94dd"
source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#75994f3302fa76078087b9a113130541e4d3fc37"
dependencies = [
"aes",
"async-compression",
@ -2943,7 +2943,7 @@ dependencies = [
[[package]]
name = "pumpkin-util"
version = "0.1.0-dev+26.2"
source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#a3b66be27b2f70afc8dbe43923ab2cfbc36e94dd"
source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#75994f3302fa76078087b9a113130541e4d3fc37"
dependencies = [
"base64 0.23.0",
"bytes",
@ -2970,7 +2970,7 @@ dependencies = [
[[package]]
name = "pumpkin-world"
version = "0.1.0-dev+26.2"
source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#a3b66be27b2f70afc8dbe43923ab2cfbc36e94dd"
source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#75994f3302fa76078087b9a113130541e4d3fc37"
dependencies = [
"arc-swap",
"bitflags 2.13.1",

View File

@ -49,6 +49,17 @@ pub fn ffi_native_bridge_damage_entity_impl(request: DamageEntityRequest) -> Opt
})
}
pub fn ffi_native_bridge_get_entity_velocity_impl(request: Uuid) -> Option<crate::proto::patchbukkit::entity::EntityVelocityResponse> {
with_player(Some(&request), |player| {
let vel = player.living_entity.entity.velocity.load();
crate::proto::patchbukkit::entity::EntityVelocityResponse {
x: vel.x,
y: vel.y,
z: vel.z,
}
})
}
pub fn ffi_native_bridge_set_entity_velocity_impl(request: SetEntityVelocityRequest) -> Option<()> {
with_player(request.uuid.as_ref(), |player| {
let velocity = pumpkin_util::math::vector3::Vector3::new(request.x, request.y, request.z);
@ -56,6 +67,36 @@ pub fn ffi_native_bridge_set_entity_velocity_impl(request: SetEntityVelocityRequ
})
}
pub fn ffi_native_bridge_set_entity_pose_impl(
_request: crate::proto::patchbukkit::entity::SetEntityPoseRequest,
) -> Option<()> {
Some(())
}
pub fn ffi_native_bridge_get_gamemode_impl(request: Uuid) -> Option<crate::proto::patchbukkit::entity::GetGamemodeResponse> {
with_player(Some(&request), |player| {
let gamemode = player.gamemode.load();
crate::proto::patchbukkit::entity::GetGamemodeResponse {
gamemode: gamemode as i32,
}
})
}
pub fn ffi_native_bridge_set_gamemode_impl(
request: crate::proto::patchbukkit::entity::SetGamemodeRequest,
) -> Option<()> {
let ctx = CALLBACK_CONTEXT.get()?;
with_player(request.uuid.as_ref(), |player| {
let gamemode_val = request.gamemode as i8;
if let Ok(gamemode) = pumpkin_util::gamemode::GameMode::try_from(gamemode_val) {
let player = player.clone();
ctx.runtime.spawn(async move {
player.set_gamemode(gamemode).await;
});
}
})
}
pub fn ffi_native_bridge_teleport_entity_impl(request: TeleportEntityRequest) -> Option<()> {
let ctx = CALLBACK_CONTEXT.get()?;
let loc = request.location?;

View File

@ -71,3 +71,64 @@ pub fn ffi_native_bridge_get_worlds_impl(
Some(crate::proto::patchbukkit::world::GetWorldsResponse { world_uuids })
}
pub fn ffi_native_bridge_get_world_border_impl(
request: crate::proto::patchbukkit::world::GetWorldBorderRequest,
) -> Option<crate::proto::patchbukkit::world::WorldBorderData> {
let ctx = CALLBACK_CONTEXT.get()?;
let uuid_str = &request.world_uuid.as_ref()?.value;
let world_uuid = uuid::Uuid::parse_str(uuid_str).ok()?;
let worlds = ctx.plugin_context.server.worlds.load_full();
let world = worlds
.iter()
.find(|w| w.uuid == world_uuid)
.cloned()
.or_else(|| worlds.first().cloned())?;
let wb = world.worldborder.blocking_lock();
Some(crate::proto::patchbukkit::world::WorldBorderData {
center_x: wb.center_x,
center_z: wb.center_z,
size: wb.old_diameter,
target_size: wb.new_diameter,
speed: wb.speed,
warning_time: wb.warning_time,
warning_blocks: wb.warning_blocks,
damage_per_block: wb.damage_per_block as f64,
damage_buffer: wb.buffer as f64,
max_center_coordinate: wb.portal_teleport_boundary,
})
}
pub fn ffi_native_bridge_set_world_border_impl(
request: crate::proto::patchbukkit::world::SetWorldBorderRequest,
) -> Option<()> {
let ctx = CALLBACK_CONTEXT.get()?;
let uuid_str = &request.world_uuid.as_ref()?.value;
let world_uuid = uuid::Uuid::parse_str(uuid_str).ok()?;
let border_data = request.border?;
let worlds = ctx.plugin_context.server.worlds.load_full();
let world = worlds
.iter()
.find(|w| w.uuid == world_uuid)
.cloned()
.or_else(|| worlds.first().cloned())?;
let mut wb = world.worldborder.blocking_lock();
wb.center_x = border_data.center_x;
wb.center_z = border_data.center_z;
wb.old_diameter = border_data.size;
wb.new_diameter = border_data.target_size;
wb.speed = border_data.speed;
wb.warning_time = border_data.warning_time;
wb.warning_blocks = border_data.warning_blocks;
wb.damage_per_block = border_data.damage_per_block as f32;
wb.buffer = border_data.damage_buffer as f32;
wb.portal_teleport_boundary = border_data.max_center_coordinate;
Some(())
}