PatchBukkit/rust/src/java/native_callbacks/itemstack.rs
Alexander Medvedev afb0e82713 many fixes
2026-08-08 20:39:14 +02:00

188 lines
6.7 KiB
Rust

use pumpkin_data::data_component_impl::EquipmentSlot;
use pumpkin_data::item::Item;
use pumpkin_data::item_stack::ItemStack as PumpkinItemStack;
use tokio::task::block_in_place;
use crate::{
java::native_callbacks::{CALLBACK_CONTEXT, utils::with_player},
proto::patchbukkit::{
common::Uuid,
itemstack::{
GetPlayerInventoryResponse, ItemStack as ProtoItemStack, SetPlayerEquipmentRequest,
SetPlayerInventorySlotRequest, SetPlayerSelectedSlotRequest,
},
},
};
fn pumpkin_item_to_proto(stack: &PumpkinItemStack) -> ProtoItemStack {
if stack.is_empty() {
ProtoItemStack {
r#type: "minecraft:air".to_string(),
amount: 0,
}
} else {
let registry_key = stack.item.registry_key;
let r#type = if registry_key.starts_with("minecraft:") {
registry_key.to_string()
} else {
format!("minecraft:{registry_key}")
};
ProtoItemStack {
r#type,
amount: u32::from(stack.item_count),
}
}
}
fn proto_item_to_pumpkin(proto: Option<&ProtoItemStack>) -> PumpkinItemStack {
let Some(proto) = proto else {
return PumpkinItemStack::EMPTY.clone();
};
if proto.amount == 0 || proto.r#type.is_empty() {
return PumpkinItemStack::EMPTY.clone();
}
let key = proto
.r#type
.strip_prefix("minecraft:")
.unwrap_or(&proto.r#type);
if let Some(item) = Item::from_registry_key(key) {
PumpkinItemStack::new(proto.amount as u8, item)
} else {
PumpkinItemStack::EMPTY.clone()
}
}
pub fn ffi_native_bridge_get_player_inventory_impl(
request: Uuid,
) -> Option<GetPlayerInventoryResponse> {
let ctx = CALLBACK_CONTEXT.get()?;
with_player(Some(&request), |player| {
let player = player.clone();
block_in_place(|| {
ctx.runtime.block_on(async {
let selected_slot = u32::from(player.inventory.get_selected_slot());
let main_guard = player.inventory.main_inventory.read().await;
let main_inventory = main_guard.iter().map(pumpkin_item_to_proto).collect();
let eq_guard = player.inventory.entity_equipment.lock().await;
let off_hand = pumpkin_item_to_proto(&eq_guard.get(&EquipmentSlot::OFF_HAND));
let helmet = pumpkin_item_to_proto(&eq_guard.get(&EquipmentSlot::HEAD));
let chestplate = pumpkin_item_to_proto(&eq_guard.get(&EquipmentSlot::CHEST));
let leggings = pumpkin_item_to_proto(&eq_guard.get(&EquipmentSlot::LEGS));
let boots = pumpkin_item_to_proto(&eq_guard.get(&EquipmentSlot::FEET));
GetPlayerInventoryResponse {
main_inventory,
selected_slot,
off_hand: Some(off_hand),
helmet: Some(helmet),
chestplate: Some(chestplate),
leggings: Some(leggings),
boots: Some(boots),
}
})
})
})
}
pub fn ffi_native_bridge_set_player_inventory_slot_impl(
request: SetPlayerInventorySlotRequest,
) -> Option<()> {
let ctx = CALLBACK_CONTEXT.get()?;
let slot = request.slot as usize;
let pumpkin_item = proto_item_to_pumpkin(request.item.as_ref());
with_player(request.uuid.as_ref(), |player| {
let player = player.clone();
ctx.runtime.spawn(async move {
if slot < 36 {
let mut main_guard = player.inventory.main_inventory.write().await;
main_guard[slot] = pumpkin_item;
} else {
let eq_slot = match slot {
36 => Some(EquipmentSlot::FEET),
37 => Some(EquipmentSlot::LEGS),
38 => Some(EquipmentSlot::CHEST),
39 => Some(EquipmentSlot::HEAD),
40 => Some(EquipmentSlot::OFF_HAND),
_ => None,
};
if let Some(eq_slot) = eq_slot {
let mut eq_guard = player.inventory.entity_equipment.lock().await;
eq_guard.put(&eq_slot, pumpkin_item);
}
}
});
})
}
pub fn ffi_native_bridge_set_player_selected_slot_impl(
request: SetPlayerSelectedSlotRequest,
) -> Option<()> {
with_player(request.uuid.as_ref(), |player| {
if request.slot < 9 {
player.inventory.set_selected_slot(request.slot as u8);
}
})
}
pub fn ffi_native_bridge_set_player_equipment_impl(
request: SetPlayerEquipmentRequest,
) -> Option<()> {
let ctx = CALLBACK_CONTEXT.get()?;
let pumpkin_item = proto_item_to_pumpkin(request.item.as_ref());
let slot_type = request.slot_type;
with_player(request.uuid.as_ref(), |player| {
let player = player.clone();
ctx.runtime.spawn(async move {
match slot_type {
0 => {
// Main Hand
player.inventory.set_held_item(pumpkin_item).await;
}
1 => {
// Off Hand
let mut eq = player.inventory.entity_equipment.lock().await;
eq.put(&EquipmentSlot::OFF_HAND, pumpkin_item);
}
2 => {
// Feet
let mut eq = player.inventory.entity_equipment.lock().await;
eq.put(&EquipmentSlot::FEET, pumpkin_item);
}
3 => {
// Legs
let mut eq = player.inventory.entity_equipment.lock().await;
eq.put(&EquipmentSlot::LEGS, pumpkin_item);
}
4 => {
// Chest
let mut eq = player.inventory.entity_equipment.lock().await;
eq.put(&EquipmentSlot::CHEST, pumpkin_item);
}
5 => {
// Head
let mut eq = player.inventory.entity_equipment.lock().await;
eq.put(&EquipmentSlot::HEAD, pumpkin_item);
}
_ => {}
}
});
})
}
pub fn ffi_native_bridge_clear_player_inventory_impl(request: Uuid) -> Option<()> {
let ctx = CALLBACK_CONTEXT.get()?;
with_player(Some(&request), |player| {
let player = player.clone();
ctx.runtime.spawn(async move {
let mut main_guard = player.inventory.main_inventory.write().await;
main_guard.fill_with(|| PumpkinItemStack::EMPTY.clone());
let mut eq_guard = player.inventory.entity_equipment.lock().await;
eq_guard.clear();
});
})
}