fix(inventory): enchanting table offers and lapis validation (#2374)

* fix(inventory): match applied enchantments with table preview

* fix(inventory): require lapis for enchanting purchases
This commit is contained in:
yhypno
2026-07-31 08:38:38 +05:30
committed by GitHub
parent a3b66be27b
commit bd7a1a2126

View File

@@ -8,7 +8,7 @@ use pumpkin_data::item_stack::ItemStack;
use pumpkin_data::screen::WindowType;
use pumpkin_data::statistic::{CustomStatistic, StatisticCategory};
use pumpkin_data::tag::{Enchantment as EnchantmentTag, Taggable};
use pumpkin_util::random::RandomImpl;
use pumpkin_util::random::{RandomImpl, legacy_rand::LegacyRand};
use pumpkin_world::inventory::Inventory;
use crate::{
@@ -17,10 +17,44 @@ use crate::{
InventoryPlayer, ItemStackFuture, ScreenHandler, ScreenHandlerBehaviour,
ScreenHandlerFuture, offer_or_drop_stack,
},
slot::NormalSlot,
slot::{BoxFuture, NormalSlot, Slot},
window_property::{EnchantmentTable, WindowProperty},
};
struct LapisSlot(NormalSlot);
fn is_lapis(stack: &ItemStack) -> bool {
stack.item == &Item::LAPIS_LAZULI
}
impl LapisSlot {
fn new(inventory: Arc<dyn Inventory>) -> Self {
Self(NormalSlot::new(inventory, 1))
}
}
impl Slot for LapisSlot {
fn get_inventory(&self) -> Arc<dyn Inventory> {
self.0.get_inventory()
}
fn get_index(&self) -> usize {
self.0.get_index()
}
fn set_id(&self, id: usize) {
self.0.set_id(id);
}
fn can_insert<'a>(&'a self, stack: &'a ItemStack) -> BoxFuture<'a, bool> {
Box::pin(async move { is_lapis(stack) })
}
fn mark_dirty(&self) -> BoxFuture<'_, ()> {
self.0.mark_dirty()
}
}
pub struct EnchantingTableScreenHandler {
pub inventory: Arc<dyn Inventory>,
behaviour: ScreenHandlerBehaviour,
@@ -51,7 +85,7 @@ impl EnchantingTableScreenHandler {
// Enchanting slots: 0 is item, 1 is lapis
handler.add_slot(Arc::new(NormalSlot::new(inventory.clone(), 0)));
handler.add_slot(Arc::new(NormalSlot::new(inventory.clone(), 1)));
handler.add_slot(Arc::new(LapisSlot::new(inventory.clone())));
let player_inventory: Arc<dyn Inventory> = player_inventory.clone();
handler.add_player_slots(&player_inventory);
@@ -81,9 +115,7 @@ impl EnchantingTableScreenHandler {
self.enchantment_level[i] = -1;
}
} else {
let mut random = pumpkin_util::random::xoroshiro128::Xoroshiro::from_seed(
self.enchantment_seed as u64,
);
let mut random = LegacyRand::from_seed(self.enchantment_seed as u64);
for i in 0..3 {
let level = self.calculate_level_requirement(&mut random, i, enchantability);
@@ -92,18 +124,22 @@ impl EnchantingTableScreenHandler {
for i in 0..3 {
if self.level_requirements[i] > 0 {
let mut random = self.create_enchantment_random(i);
let enchantments = Self::get_enchantment_list(
&mut random,
&item,
i,
self.level_requirements[i],
);
if let Some(first) = enchantments.first() {
self.enchantment_id[i] = first.0.id as i32;
self.enchantment_level[i] = first.1;
} else {
if enchantments.is_empty() {
self.enchantment_id[i] = -1;
self.enchantment_level[i] = -1;
} else {
let clue_index =
random.next_bounded_i32(enchantments.len() as i32) as usize;
let clue = enchantments[clue_index];
self.enchantment_id[i] = clue.0.id as i32;
self.enchantment_level[i] = clue.1;
}
} else {
self.enchantment_id[i] = -1;
@@ -117,7 +153,7 @@ impl EnchantingTableScreenHandler {
fn calculate_level_requirement(
&self,
random: &mut pumpkin_util::random::xoroshiro128::Xoroshiro,
random: &mut LegacyRand,
slot: usize,
_enchantability: i32,
) -> i32 {
@@ -132,8 +168,12 @@ impl EnchantingTableScreenHandler {
}
}
const fn create_enchantment_random(&self, slot: usize) -> LegacyRand {
LegacyRand::from_seed(self.enchantment_seed.wrapping_add(slot as i32) as u64)
}
fn get_enchantment_list(
random: &mut pumpkin_util::random::xoroshiro128::Xoroshiro,
random: &mut LegacyRand,
item: &ItemStack,
_slot: usize,
level: i32,
@@ -314,7 +354,9 @@ impl ScreenHandler for EnchantingTableScreenHandler {
let lapis_cost = (id + 1) as u8;
if !player.is_creative()
&& (lapis_stack.is_empty() || lapis_stack.item_count < lapis_cost)
&& (lapis_stack.is_empty()
|| !is_lapis(&lapis_stack)
|| lapis_stack.item_count < lapis_cost)
{
return false;
}
@@ -327,9 +369,7 @@ impl ScreenHandler for EnchantingTableScreenHandler {
return false;
}
let mut random = pumpkin_util::random::xoroshiro128::Xoroshiro::from_seed(
self.enchantment_seed as u64,
);
let mut random = self.create_enchantment_random(id as usize);
let enchantments =
Self::get_enchantment_list(&mut random, &item_stack, id as usize, level_req);
@@ -444,3 +484,14 @@ impl ScreenHandler for EnchantingTableScreenHandler {
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn lapis_slot_only_accepts_lapis_lazuli() {
assert!(is_lapis(&ItemStack::new(1, &Item::LAPIS_LAZULI)));
assert!(!is_lapis(&ItemStack::new(1, &Item::DIRT)));
}
}