Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
ab9e2f4
Add core player event bridge
yunuservices Feb 4, 2026
a1f66a3
Add server command and broadcast events
yunuservices Feb 4, 2026
6d0b455
Add block and interact event bridge
yunuservices Feb 4, 2026
f63621a
Add native block lookup bridge
yunuservices Feb 4, 2026
b91f9e8
Document GraalVM JVM compatibility
yunuservices Feb 4, 2026
0dc86ce
Enhance interact and entity event bridge
yunuservices Feb 4, 2026
b324772
Add player login/teleport/world/gamemode event bridge
yunuservices Feb 4, 2026
e5982af
Add prelogin, advancement, and animation event bridge
yunuservices Feb 4, 2026
f9499b5
Add armor stand manipulate event bridge
yunuservices Feb 4, 2026
c27f40d
Add bed enter/leave event bridge
yunuservices Feb 4, 2026
80e44eb
Add bucket events bridge
yunuservices Feb 4, 2026
9879203
Add PlayerChangedMainHandEvent
yunuservices Feb 4, 2026
95437f9
Add player channel events
yunuservices Feb 4, 2026
4bfe660
Add command preprocess/send events
yunuservices Feb 4, 2026
7dc20ec
Add PlayerDropItemEvent
yunuservices Feb 4, 2026
1801529
Add PlayerEditBookEvent
yunuservices Feb 4, 2026
7507781
Add PlayerEggThrowEvent
yunuservices Feb 4, 2026
585a412
Add PlayerExpChangeEvent
yunuservices Feb 4, 2026
87e6d23
Add PlayerFishEvent
yunuservices Feb 4, 2026
b2dbd98
Add player entity interaction events
yunuservices Feb 4, 2026
d485ab7
Add PlayerItemHeldEvent bridge
yunuservices Feb 4, 2026
bba9d21
Add player item damage/consume/mend events
yunuservices Feb 4, 2026
a4005b5
Add player kick and level change events
yunuservices Feb 4, 2026
1e73933
Add player toggle and swap hand events
yunuservices Feb 4, 2026
8b12bef
Add resource pack status and respawn events
yunuservices Feb 4, 2026
a56249b
Add portal, velocity, and misc player events
yunuservices Feb 4, 2026
bfdf350
Add player harvest block event
yunuservices Feb 4, 2026
6545c56
Add block can build and burn events
yunuservices Feb 4, 2026
d11b839
Add block ignite event
yunuservices Feb 5, 2026
e59c1e6
Add block spread event
yunuservices Feb 5, 2026
7814906
Add block damage events
yunuservices Feb 5, 2026
b062673
Add BlockDispenseEvent bridge
yunuservices Feb 5, 2026
f49b3e3
Add BlockDropItemEvent bridge
yunuservices Feb 5, 2026
3c4ae91
Add BlockExplodeEvent bridge
yunuservices Feb 5, 2026
c79540d
Add BlockFadeEvent bridge
yunuservices Feb 5, 2026
30c75f9
Add BlockFertilizeEvent bridge
yunuservices Feb 5, 2026
2a19cbb
Add BlockFormEvent bridge
yunuservices Feb 5, 2026
1bf504b
Add BlockFromToEvent bridge
yunuservices Feb 5, 2026
b92b5bd
Add BlockGrowEvent bridge
yunuservices Feb 5, 2026
a619e38
Add piston extend/retract events bridge
yunuservices Feb 5, 2026
a222a6a
Add BlockRedstoneEvent bridge
yunuservices Feb 5, 2026
3f7bfcc
Add BlockMultiPlace and BlockPhysics events bridge
yunuservices Feb 5, 2026
50a126d
Add note/sign/tnt/moisture/sponge/fluid events
yunuservices Feb 5, 2026
0a23ea0
Add SpawnChangeEvent
yunuservices Feb 5, 2026
0b7bf00
Add ServerListPingEvent
yunuservices Feb 5, 2026
3762641
Bridge plugin and service server events
yunuservices Feb 5, 2026
60c3925
Restore rust Cargo.toml to upstream deps
yunuservices Feb 5, 2026
271da00
Fix event compatibility and java bridge helpers
yunuservices Feb 5, 2026
0b95ca1
Align PatchBukkit runtime with current event support
yunuservices Feb 5, 2026
6ee1092
Align bridge with local Pumpkin events and verify server-test
yunuservices Feb 5, 2026
63e874a
Use git-based Pumpkin dependencies on feat/events
yunuservices Feb 5, 2026
258062c
Refresh lockfile after rebasing Pumpkin feat/events
yunuservices Feb 6, 2026
635f40d
Fix critical bridge issues for ignite and world mapping
yunuservices Feb 6, 2026
54da03f
chore(rust): bump Pumpkin dependency lock to ba0410c3
yunuservices Feb 6, 2026
1dd858f
fix(rust): resolve clippy warnings in event bridge handlers
yunuservices Feb 6, 2026
85095a4
fix: address review feedback across bridge and runtime sync
yunuservices Feb 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,27 @@ A plugin for [PumpkinMC](https://pumpkinmc.org/) that adds support for [PaperMC]
4. **Initialize**: Restart PumpkinMC. This creates a new `patchbukkit/` directory in your server root.
5. **Add Plugins**: Drop your .jar plugin files (Paper/Spigot/Bukkit) into the newly created `patchbukkit/patchbukkit-plugins/` folder and restart.

## GraalVM (Ecosystem Compatibility)

PatchBukkit is a **native Rust plugin** that embeds a JVM for Bukkit/Paper/Spigot plugins. For
maximum ecosystem compatibility, the recommended GraalVM usage is **JVM mode**, not native-image.

**Recommended approach**
- Use GraalVM JDK as a drop-in replacement for a standard JDK.
- Keep plugins running on the JVM (dynamic classloading, reflection, JNI/FFM).

**Why not native-image yet**
- Bukkit/Paper plugins rely heavily on dynamic classloading, reflection, and Java agents.
- PatchBukkit embeds a JVM and uses JNI/FFM; native-image would require extensive config
and compatibility work across the plugin ecosystem.

**Suggested JVM flags (starting point)**
- `-XX:+UseG1GC`
- `-XX:+UseStringDeduplication`
- `-Dpolyglot.engine.WarnInterpreterOnly=false`

These are general JVM tuning hints; validate against your workload.

## Development

If you wish to contribute to PatchBukkit, follow the following steps:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1238,10 +1238,7 @@ public void setMotd(@NotNull String motd) {

@Override
public @NotNull WarningState getWarningState() {
// TODO Auto-generated method stub
throw new UnsupportedOperationException(
"Unimplemented method 'getWarningState'"
);
return WarningState.DEFAULT;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package org.patchbukkit.bridge;

import org.bukkit.Location;
import org.patchbukkit.world.PatchBukkitWorld;

import java.util.UUID;

public class BridgeUtils {
Expand All @@ -10,4 +13,60 @@ public static UUID convertUuid(patchbukkit.common.UUID uuid) {
public static patchbukkit.common.UUID convertUuid(UUID uuid) {
return patchbukkit.common.UUID.newBuilder().setValue(uuid.toString()).build();
}

public static Location convertLocation(patchbukkit.common.Location location) {
if (location == null || location.getWorld() == null || location.getWorld().getUuid() == null) {
return null;
}

var world = PatchBukkitWorld.getOrCreate(convertUuid(location.getWorld().getUuid()));
var position = location.getPosition();
if (position == null) {
return null;
}

return new Location(
world,
position.getX(),
position.getY(),
position.getZ(),
location.getYaw(),
location.getPitch()
);
}

public static patchbukkit.common.Location convertLocation(Location location) {
if (location == null || location.getWorld() == null) {
return null;
}

return patchbukkit.common.Location.newBuilder()
.setWorld(patchbukkit.common.World.newBuilder()
.setUuid(convertUuid(location.getWorld().getUID()))
.build())
.setPosition(patchbukkit.common.Vec3.newBuilder()
.setX(location.getX())
.setY(location.getY())
.setZ(location.getZ())
.build())
.setYaw(location.getYaw())
.setPitch(location.getPitch())
.build();
}

public static PatchBukkitWorld convertWorld(patchbukkit.common.World world) {
if (world == null || world.getUuid() == null) {
return null;
}
return PatchBukkitWorld.getOrCreate(convertUuid(world.getUuid()));
}

public static patchbukkit.common.World convertWorld(org.bukkit.World world) {
if (world == null) {
return null;
}
return patchbukkit.common.World.newBuilder()
.setUuid(convertUuid(world.getUID()))
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
package org.patchbukkit.entity;

import java.util.UUID;

import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.block.Block;
import org.bukkit.entity.AbstractArrow;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.List;

public class PatchBukkitAbstractArrow extends PatchBukkitProjectile implements AbstractArrow {
Comment thread
yunuservices marked this conversation as resolved.
private PickupStatus pickupStatus = PickupStatus.ALLOWED;
private double damage = 2.0;
private int knockbackStrength = 0;
private int pierceLevel = 0;
private boolean critical = false;
private boolean inBlock = false;
private boolean shotFromCrossbow = false;
private boolean noPhysics = false;
private int lifetimeTicks = 0;
private ItemStack item = new ItemStack(Material.ARROW, 1);
private ItemStack weapon = null;
private Sound hitSound = Sound.ENTITY_ARROW_HIT;

public PatchBukkitAbstractArrow(UUID uuid, String name) {
super(uuid, name);
warnSnapshotLimitation(
"entity:abstract_arrow_snapshot",
"PatchBukkitAbstractArrow uses fallback local values; Pumpkin does not fully expose arrow/bow runtime state yet."
);
}

public Block getAttachedBlock() {
return null;
}

@Override
public @NotNull List<Block> getAttachedBlocks() {
return Collections.emptyList();
}

public double getDamage() {
return damage;
}

public void setDamage(double damage) {
this.damage = damage;
}

public int getKnockbackStrength() {
return knockbackStrength;
}

public void setKnockbackStrength(int knockbackStrength) {
this.knockbackStrength = knockbackStrength;
}

public PickupStatus getPickupStatus() {
return pickupStatus;
}

public void setPickupStatus(PickupStatus status) {
this.pickupStatus = status;
}

public int getPierceLevel() {
return pierceLevel;
}

public void setPierceLevel(int pierceLevel) {
this.pierceLevel = pierceLevel;
}

public boolean isCritical() {
return critical;
}

public void setCritical(boolean critical) {
this.critical = critical;
}

public boolean isInBlock() {
return inBlock;
}

public boolean isShotFromCrossbow() {
return shotFromCrossbow;
}

public void setShotFromCrossbow(boolean shotFromCrossbow) {
this.shotFromCrossbow = shotFromCrossbow;
}

public ItemStack getItem() {
return item;
}

public void setItem(ItemStack item) {
if (item != null) {
this.item = item;
}
}

@Override
public @NotNull ItemStack getItemStack() {
return getItem();
}

@Override
public void setItemStack(@NotNull ItemStack stack) {
setItem(stack);
}

public ItemStack getWeapon() {
return weapon != null ? weapon : item;
}

public void setWeapon(ItemStack weapon) {
this.weapon = weapon;
}

public Sound getHitSound() {
return hitSound;
}

public void setHitSound(Sound sound) {
if (sound != null) {
this.hitSound = sound;
}
}

public boolean hasNoPhysics() {
return noPhysics;
}

public void setNoPhysics(boolean noPhysics) {
this.noPhysics = noPhysics;
}

public int getLifetimeTicks() {
return lifetimeTicks;
}

public void setLifetimeTicks(int ticks) {
this.lifetimeTicks = ticks;
}

@Override
public void setShooter(org.bukkit.projectiles.ProjectileSource shooter, boolean update) {
setShooter(shooter);
if (update) {
setHasBeenShot(true);
}
}
}
Loading