ErrorNoWatcher/src/lua/client/container.rs

137 lines
4.2 KiB
Rust

use azalea::{
BlockPos,
inventory::{Inventory, Menu, Player, SlotList},
prelude::ContainerClientExt,
protocol::packets::game::ServerboundSetCarriedItem,
};
use log::error;
use mlua::{Lua, Result, UserDataRef, Value};
use super::{Client, Container, ContainerRef, ItemStack, Vec3};
pub fn container(_lua: &Lua, client: &Client) -> Result<Option<ContainerRef>> {
Ok(client.get_open_container().map(ContainerRef))
}
pub fn held_item(_lua: &Lua, client: &Client) -> Result<ItemStack> {
Ok(ItemStack(client.component::<Inventory>().held_item()))
}
pub fn held_slot(_lua: &Lua, client: &Client) -> Result<u8> {
Ok(client.component::<Inventory>().selected_hotbar_slot)
}
#[allow(clippy::too_many_lines)]
pub fn menu(lua: &Lua, client: &Client) -> Result<Value> {
fn from_slot_list<const N: usize>(slot_list: SlotList<N>) -> Vec<ItemStack> {
slot_list
.iter()
.map(|item_stack| ItemStack(item_stack.to_owned()))
.collect::<Vec<_>>()
}
let table = lua.create_table()?;
match client.menu() {
Menu::Player(Player {
craft_result,
craft,
armor,
inventory,
offhand,
}) => {
table.set("type", 0)?;
table.set("craft_result", ItemStack(craft_result))?;
table.set("craft", from_slot_list(craft))?;
table.set("armor", from_slot_list(armor))?;
table.set("inventory", from_slot_list(inventory))?;
table.set("offhand", ItemStack(offhand))?;
}
Menu::Generic9x3 { contents, player } => {
table.set("type", 3)?;
table.set("contents", from_slot_list(contents))?;
table.set("player", from_slot_list(player))?;
}
Menu::Generic9x6 { contents, player } => {
table.set("type", 6)?;
table.set("contents", from_slot_list(contents))?;
table.set("player", from_slot_list(player))?;
}
Menu::Crafting {
result,
grid,
player,
} => {
table.set("type", 13)?;
table.set("result", ItemStack(result))?;
table.set("grid", from_slot_list(grid))?;
table.set("player", from_slot_list(player))?;
}
Menu::Hopper { contents, player } => {
table.set("type", 17)?;
table.set("contents", from_slot_list(contents))?;
table.set("player", from_slot_list(player))?;
}
Menu::Merchant {
payments,
result,
player,
} => {
table.set("type", 20)?;
table.set("payments", from_slot_list(payments))?;
table.set("result", ItemStack(result))?;
table.set("player", from_slot_list(player))?;
}
Menu::ShulkerBox { contents, player } => {
table.set("type", 21)?;
table.set("contents", from_slot_list(contents))?;
table.set("player", from_slot_list(player))?;
}
_ => return Ok(Value::Nil),
}
Ok(Value::Table(table))
}
pub async fn open_container_at(
_lua: Lua,
client: UserDataRef<Client>,
position: Vec3,
) -> Result<Option<Container>> {
#[allow(clippy::cast_possible_truncation)]
Ok(client
.clone()
.open_container_at(BlockPos::new(
position.x as i32,
position.y as i32,
position.z as i32,
))
.await
.map(Container))
}
pub fn open_inventory(_lua: &Lua, client: &Client, _: ()) -> Result<Option<Container>> {
Ok(client.open_inventory().map(Container))
}
pub fn set_held_slot(_lua: &Lua, client: &Client, slot: u8) -> Result<()> {
if slot > 8 {
return Ok(());
}
{
let mut ecs = client.ecs.lock();
let mut inventory = client.query::<&mut Inventory>(&mut ecs);
if inventory.selected_hotbar_slot == slot {
return Ok(());
}
inventory.selected_hotbar_slot = slot;
};
if let Err(error) = client.write_packet(ServerboundSetCarriedItem {
slot: u16::from(slot),
}) {
error!("failed to send SetCarriedItem packet: {error:?}");
}
Ok(())
}