feat(plugin-api): expand item stack
This commit is contained in:
parent
0c56e47f43
commit
cfeb5d80fc
@ -2,7 +2,8 @@ interface command {
|
|||||||
use %world.{%world, entity};
|
use %world.{%world, entity};
|
||||||
use player.{player};
|
use player.{player};
|
||||||
use block-entity.{command-block-entity};
|
use block-entity.{command-block-entity};
|
||||||
use common.{position, block-position, locale, item-stack, game-mode};
|
use common.{position, block-position, locale, game-mode};
|
||||||
|
use item-stack.{item-stack};
|
||||||
use server.{server, difficulty};
|
use server.{server, difficulty};
|
||||||
use text.{text-component};
|
use text.{text-component};
|
||||||
|
|
||||||
|
|||||||
@ -59,34 +59,6 @@ interface common {
|
|||||||
b: u8,
|
b: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
use data-components.{data-component};
|
|
||||||
use enchantments.{enchantment};
|
|
||||||
|
|
||||||
/// Represents an enchantment and its level.
|
|
||||||
record enchantment-value {
|
|
||||||
enchantment: enchantment,
|
|
||||||
level: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Represents a data component and its serialized value.
|
|
||||||
record data-component-value {
|
|
||||||
component: data-component,
|
|
||||||
/// The serialized value of the component.
|
|
||||||
value: list<u8>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Represents a stack of items with its type and count.
|
|
||||||
record item-stack {
|
|
||||||
/// The unique registry key (e.g., "minecraft:diamond").
|
|
||||||
registry-key: string,
|
|
||||||
/// The number of items in the stack.
|
|
||||||
count: u8,
|
|
||||||
/// The data components associated with this item stack.
|
|
||||||
components: list<data-component-value>,
|
|
||||||
/// The enchantments associated with this item stack.
|
|
||||||
enchantments: list<enchantment-value>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Represents the type of click interaction in a GUI.
|
/// Represents the type of click interaction in a GUI.
|
||||||
enum click-type {
|
enum click-type {
|
||||||
left,
|
left,
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
interface event {
|
interface event {
|
||||||
use common.{block-position, game-mode, hand, item-stack, position, click-type};
|
use common.{block-position, game-mode, hand, position, click-type};
|
||||||
|
use item-stack.{item-stack};
|
||||||
use player.{player};
|
use player.{player};
|
||||||
use text.{text-component};
|
use text.{text-component};
|
||||||
use %world.{%world};
|
use %world.{%world};
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
interface gui {
|
interface gui {
|
||||||
use text.{text-component};
|
use text.{text-component};
|
||||||
use common.{item-stack, click-type};
|
use common.{click-type};
|
||||||
|
use item-stack.{item-stack};
|
||||||
|
|
||||||
enum gui-type {
|
enum gui-type {
|
||||||
generic-9x1,
|
generic-9x1,
|
||||||
|
|||||||
59
pumpkin-plugin-wit/v0.1/item-stack.wit
Normal file
59
pumpkin-plugin-wit/v0.1/item-stack.wit
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
interface item-stack {
|
||||||
|
use data-components.{data-component};
|
||||||
|
use enchantments.{enchantment};
|
||||||
|
use text.{text-component};
|
||||||
|
|
||||||
|
/// Represents an enchantment and its level.
|
||||||
|
record enchantment-value {
|
||||||
|
enchantment: enchantment,
|
||||||
|
level: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents a data component and its serialized value.
|
||||||
|
record data-component-value {
|
||||||
|
component: data-component,
|
||||||
|
/// The serialized value of the component.
|
||||||
|
value: list<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
resource item-stack {
|
||||||
|
constructor(registry-key: string, count: u8);
|
||||||
|
|
||||||
|
/// Returns the unique registry key of the item (e.g., "minecraft:diamond").
|
||||||
|
get-registry-key: func() -> string;
|
||||||
|
|
||||||
|
/// Returns the number of items in the stack.
|
||||||
|
get-count: func() -> u8;
|
||||||
|
/// Sets the number of items in the stack.
|
||||||
|
set-count: func(count: u8);
|
||||||
|
|
||||||
|
/// Returns the maximum number of items that can be in this stack.
|
||||||
|
get-max-count: func() -> u8;
|
||||||
|
|
||||||
|
/// Returns all enchantments on this item stack.
|
||||||
|
get-enchantments: func() -> list<enchantment-value>;
|
||||||
|
/// Adds an enchantment to this item stack.
|
||||||
|
add-enchantment: func(enchantment: enchantment, level: u32);
|
||||||
|
/// Removes an enchantment from this item stack.
|
||||||
|
remove-enchantment: func(enchantment: enchantment);
|
||||||
|
|
||||||
|
/// Returns the lore of this item stack.
|
||||||
|
get-lore: func() -> list<text-component>;
|
||||||
|
/// Sets the lore of this item stack.
|
||||||
|
set-lore: func(lore: list<text-component>);
|
||||||
|
/// Adds a line to the lore of this item stack.
|
||||||
|
add-lore: func(line: text-component);
|
||||||
|
|
||||||
|
/// Returns the custom name of this item stack, if set.
|
||||||
|
get-custom-name: func() -> option<text-component>;
|
||||||
|
/// Sets the custom name of this item stack.
|
||||||
|
set-custom-name: func(name: option<text-component>);
|
||||||
|
|
||||||
|
/// Returns all data components on this item stack.
|
||||||
|
get-components: func() -> list<data-component-value>;
|
||||||
|
/// Sets a data component on this item stack.
|
||||||
|
set-component: func(component: data-component, value: list<u8>);
|
||||||
|
/// Removes a data component from this item stack.
|
||||||
|
remove-component: func(component: data-component);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,7 +3,7 @@
|
|||||||
/// and interactive inputs (checkboxes, text fields, sliders).
|
/// and interactive inputs (checkboxes, text fields, sliders).
|
||||||
interface java-dialogs {
|
interface java-dialogs {
|
||||||
use text.{text-component};
|
use text.{text-component};
|
||||||
use common.{item-stack};
|
use item-stack.{item-stack};
|
||||||
|
|
||||||
/// Represents the layout and button configuration of a dialog.
|
/// Represents the layout and button configuration of a dialog.
|
||||||
enum dialog-type {
|
enum dialog-type {
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
/// Represents a player connected to the Minecraft server.
|
/// Represents a player connected to the Minecraft server.
|
||||||
interface player {
|
interface player {
|
||||||
use common.{hand, item-stack, position, game-mode};
|
use common.{hand, position, game-mode};
|
||||||
|
use item-stack.{item-stack};
|
||||||
use %world.{%world, entity};
|
use %world.{%world, entity};
|
||||||
use permission.{permission-level};
|
use permission.{permission-level};
|
||||||
use text.{text-component};
|
use text.{text-component};
|
||||||
|
|||||||
@ -246,6 +246,18 @@ interface %world {
|
|||||||
/// Returns the minimum Y coordinate (bottom of the world).
|
/// Returns the minimum Y coordinate (bottom of the world).
|
||||||
get-min-y: func() -> s32;
|
get-min-y: func() -> s32;
|
||||||
|
|
||||||
|
/// Returns the sky light level at the specified position.
|
||||||
|
get-sky-light: func(pos: block-pos) -> u8;
|
||||||
|
|
||||||
|
/// Sets the sky light level at the specified position.
|
||||||
|
set-sky-light: func(pos: block-pos, level: u8);
|
||||||
|
|
||||||
|
/// Returns the block light level at the specified position.
|
||||||
|
get-block-light: func(pos: block-pos) -> u8;
|
||||||
|
|
||||||
|
/// Sets the block light level at the specified position.
|
||||||
|
set-block-light: func(pos: block-pos, level: u8);
|
||||||
|
|
||||||
/// Returns a list of all entities in this world.
|
/// Returns a list of all entities in this world.
|
||||||
get-entities: func() -> list<entity>;
|
get-entities: func() -> list<entity>;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -53,6 +53,7 @@ pub type CommandResource = WasmResource<CommandTree>;
|
|||||||
pub type CommandSenderResource = WasmResource<CommandSender>;
|
pub type CommandSenderResource = WasmResource<CommandSender>;
|
||||||
pub type ConsumedArgsResource = WasmResource<OwnedConsumedArgs>;
|
pub type ConsumedArgsResource = WasmResource<OwnedConsumedArgs>;
|
||||||
pub type CommandNodeResource = WasmResource<NonLeafNodeBuilder>;
|
pub type CommandNodeResource = WasmResource<NonLeafNodeBuilder>;
|
||||||
|
pub type ItemStackResource = WasmResource<Arc<Mutex<pumpkin_data::item_stack::ItemStack>>>;
|
||||||
|
|
||||||
pub type OwnedConsumedArgs = HashMap<String, OwnedArg>;
|
pub type OwnedConsumedArgs = HashMap<String, OwnedArg>;
|
||||||
|
|
||||||
@ -220,6 +221,14 @@ impl PluginHostState {
|
|||||||
let resource = self.resource_table.push(CommandNodeResource { provider })?;
|
let resource = self.resource_table.push(CommandNodeResource { provider })?;
|
||||||
Ok(wasmtime::component::Resource::new_own(resource.rep()))
|
Ok(wasmtime::component::Resource::new_own(resource.rep()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_item_stack<T>(
|
||||||
|
&mut self,
|
||||||
|
provider: Arc<Mutex<pumpkin_data::item_stack::ItemStack>>,
|
||||||
|
) -> wasmtime::Result<wasmtime::component::Resource<T>> {
|
||||||
|
let resource = self.resource_table.push(ItemStackResource { provider })?;
|
||||||
|
Ok(wasmtime::component::Resource::new_own(resource.rep()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PluginHttpHooks {
|
pub struct PluginHttpHooks {
|
||||||
|
|||||||
@ -10,7 +10,6 @@ use crate::plugin::{
|
|||||||
to_wasm_click_type, to_wasm_entity_interaction_action, to_wasm_entity_type,
|
to_wasm_click_type, to_wasm_entity_interaction_action, to_wasm_entity_type,
|
||||||
to_wasm_game_mode, to_wasm_hand, to_wasm_position,
|
to_wasm_game_mode, to_wasm_hand, to_wasm_position,
|
||||||
},
|
},
|
||||||
player::to_wit_item_stack,
|
|
||||||
pumpkin::plugin::event::{
|
pumpkin::plugin::event::{
|
||||||
BedrockFormResponseEventData, CustomClickActionEventData, Event,
|
BedrockFormResponseEventData, CustomClickActionEventData, Event,
|
||||||
InteractAction as WasmInteractAction, InventoryClickEventData,
|
InteractAction as WasmInteractAction, InventoryClickEventData,
|
||||||
@ -105,6 +104,9 @@ impl ToFromWasmEvent for InventoryCloseEvent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
impl ToFromWasmEvent for InventoryClickEvent {
|
impl ToFromWasmEvent for InventoryClickEvent {
|
||||||
fn to_wasm_event(&self, state: &mut PluginHostState) -> Event {
|
fn to_wasm_event(&self, state: &mut PluginHostState) -> Event {
|
||||||
let player = state
|
let player = state
|
||||||
@ -117,8 +119,16 @@ impl ToFromWasmEvent for InventoryClickEvent {
|
|||||||
click_type: to_wasm_click_type(self.click_type),
|
click_type: to_wasm_click_type(self.click_type),
|
||||||
slot: self.slot,
|
slot: self.slot,
|
||||||
raw_slot: self.raw_slot,
|
raw_slot: self.raw_slot,
|
||||||
clicked_item: self.clicked_item.as_ref().and_then(to_wit_item_stack),
|
clicked_item: self.clicked_item.as_ref().map(|stack| {
|
||||||
cursor: self.cursor.as_ref().and_then(to_wit_item_stack),
|
state
|
||||||
|
.add_item_stack(Arc::new(Mutex::new(stack.clone())))
|
||||||
|
.expect("failed to add item stack resource")
|
||||||
|
}),
|
||||||
|
cursor: self.cursor.as_ref().map(|stack| {
|
||||||
|
state
|
||||||
|
.add_item_stack(Arc::new(Mutex::new(stack.clone())))
|
||||||
|
.expect("failed to add item stack resource")
|
||||||
|
}),
|
||||||
hotbar_button: self.hotbar_button,
|
hotbar_button: self.hotbar_button,
|
||||||
cancelled: self.cancelled,
|
cancelled: self.cancelled,
|
||||||
})
|
})
|
||||||
|
|||||||
@ -2,13 +2,12 @@ use std::sync::Arc;
|
|||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
use wasmtime::component::Resource;
|
use wasmtime::component::Resource;
|
||||||
|
|
||||||
use super::player::{from_wit_item_stack, to_wit_item_stack};
|
|
||||||
use crate::plugin::api::gui::{PluginGui, PluginInventory};
|
use crate::plugin::api::gui::{PluginGui, PluginInventory};
|
||||||
use crate::plugin::loader::wasm::wasm_host::{
|
use crate::plugin::loader::wasm::wasm_host::{
|
||||||
state::{GuiResource, PluginHostState},
|
state::{GuiResource, PluginHostState},
|
||||||
wit::v0_1::pumpkin::plugin::{
|
wit::v0_1::pumpkin::plugin::{
|
||||||
common::ItemStack as WitItemStack,
|
|
||||||
gui::{self, Gui, GuiType},
|
gui::{self, Gui, GuiType},
|
||||||
|
item_stack::ItemStack as WitHostItemStack,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -85,11 +84,12 @@ impl gui::HostGui for PluginHostState {
|
|||||||
&mut self,
|
&mut self,
|
||||||
res: Resource<Gui>,
|
res: Resource<Gui>,
|
||||||
slot: u32,
|
slot: u32,
|
||||||
item: WitItemStack,
|
item: Resource<WitHostItemStack>,
|
||||||
) -> wasmtime::Result<()> {
|
) -> wasmtime::Result<()> {
|
||||||
let gui = self.get_gui_res(&res)?.provider.lock().await;
|
let gui = self.get_gui_res(&res)?.provider.lock().await;
|
||||||
if (slot as usize) < gui.inventory.slots.len() {
|
if (slot as usize) < gui.inventory.slots.len() {
|
||||||
let item_stack = from_wit_item_stack(item);
|
let item_stack = self.get_item_stack(&item)?;
|
||||||
|
let item_stack = item_stack.lock().await.clone();
|
||||||
*gui.inventory.slots[slot as usize].lock().await = item_stack;
|
*gui.inventory.slots[slot as usize].lock().await = item_stack;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -99,11 +99,23 @@ impl gui::HostGui for PluginHostState {
|
|||||||
&mut self,
|
&mut self,
|
||||||
res: Resource<Gui>,
|
res: Resource<Gui>,
|
||||||
slot: u32,
|
slot: u32,
|
||||||
) -> wasmtime::Result<Option<WitItemStack>> {
|
) -> wasmtime::Result<Option<Resource<WitHostItemStack>>> {
|
||||||
let gui = self.get_gui_res(&res)?.provider.lock().await;
|
let stack = {
|
||||||
if (slot as usize) < gui.inventory.slots.len() {
|
let gui = self.get_gui_res(&res)?.provider.lock().await;
|
||||||
let stack = gui.inventory.slots[slot as usize].lock().await;
|
if (slot as usize) < gui.inventory.slots.len() {
|
||||||
Ok(to_wit_item_stack(&stack))
|
let stack = gui.inventory.slots[slot as usize].lock().await;
|
||||||
|
if stack.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(stack.clone())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(stack) = stack {
|
||||||
|
Ok(Some(self.add_item_stack(Arc::new(Mutex::new(stack)))?))
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|||||||
352
pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1/item_stack.rs
Normal file
352
pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1/item_stack.rs
Normal file
@ -0,0 +1,352 @@
|
|||||||
|
use crate::plugin::loader::wasm::wasm_host::state::{ItemStackResource, PluginHostState};
|
||||||
|
use crate::plugin::loader::wasm::wasm_host::wit::v0_1::pumpkin::plugin::data_components::DataComponent as WitDataComponent;
|
||||||
|
use crate::plugin::loader::wasm::wasm_host::wit::v0_1::pumpkin::plugin::enchantments::Enchantment as WitEnchantment;
|
||||||
|
use crate::plugin::loader::wasm::wasm_host::wit::v0_1::pumpkin::plugin::item_stack::{
|
||||||
|
DataComponentValue as WitDataComponentValue, EnchantmentValue as WitEnchantmentValue,
|
||||||
|
Host as ItemStackInterfaceHost, HostItemStack, ItemStack as ItemStackHandle,
|
||||||
|
};
|
||||||
|
use crate::plugin::loader::wasm::wasm_host::wit::v0_1::pumpkin::plugin::text::TextComponent as WitTextComponent;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
use wasmtime::component::Resource;
|
||||||
|
|
||||||
|
use crate::plugin::loader::wasm::wasm_host::wit::v0_1::player::{
|
||||||
|
WitSeqAccess, text_component_from_resource,
|
||||||
|
};
|
||||||
|
use pumpkin_data::Enchantment;
|
||||||
|
use pumpkin_data::data_component::DataComponent;
|
||||||
|
use pumpkin_data::data_component_impl::{CustomNameImpl, EnchantmentsImpl};
|
||||||
|
use pumpkin_protocol::codec::data_component::{deserialize, serialize};
|
||||||
|
use pumpkin_protocol::ser::deserializer::Deserializer;
|
||||||
|
use pumpkin_protocol::ser::serializer::Serializer;
|
||||||
|
use serde::ser::SerializeStruct;
|
||||||
|
use serde::ser::Serializer as _;
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
pub(crate) fn to_wit_data_component(id: DataComponent) -> WitDataComponent {
|
||||||
|
// Safety: WIT enum is generated in the same order as the internal enum
|
||||||
|
unsafe { std::mem::transmute(id as u8) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn from_wit_data_component(id: WitDataComponent) -> DataComponent {
|
||||||
|
// Safety: WIT enum is generated in the same order as the internal enum
|
||||||
|
unsafe { std::mem::transmute(id as u8) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn to_wit_enchantment(id: &Enchantment) -> WitEnchantment {
|
||||||
|
// Safety: WIT enum is generated in the same order as the internal enum
|
||||||
|
unsafe { std::mem::transmute(id.id) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn from_wit_enchantment(id: WitEnchantment) -> &'static Enchantment {
|
||||||
|
// Safety: WIT enum is generated in the same order as the internal enum
|
||||||
|
Enchantment::from_id(id as u8).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PluginHostState {
|
||||||
|
pub fn get_item_stack(
|
||||||
|
&self,
|
||||||
|
res: &Resource<ItemStackHandle>,
|
||||||
|
) -> wasmtime::Result<Arc<Mutex<pumpkin_data::item_stack::ItemStack>>> {
|
||||||
|
self.resource_table
|
||||||
|
.get::<ItemStackResource>(&Resource::new_own(res.rep()))
|
||||||
|
.map(|r| r.provider.clone())
|
||||||
|
.map_err(wasmtime::Error::from)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ItemStackInterfaceHost for PluginHostState {}
|
||||||
|
|
||||||
|
impl HostItemStack for PluginHostState {
|
||||||
|
async fn new(
|
||||||
|
&mut self,
|
||||||
|
registry_key: String,
|
||||||
|
count: u8,
|
||||||
|
) -> wasmtime::Result<Resource<ItemStackHandle>> {
|
||||||
|
let item = pumpkin_data::item::Item::from_registry_key(
|
||||||
|
registry_key
|
||||||
|
.strip_prefix("minecraft:")
|
||||||
|
.unwrap_or(®istry_key),
|
||||||
|
)
|
||||||
|
.unwrap_or(&pumpkin_data::item::Item::AIR);
|
||||||
|
let stack = pumpkin_data::item_stack::ItemStack::new(count, item);
|
||||||
|
self.add_item_stack(Arc::new(Mutex::new(stack)))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_registry_key(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<ItemStackHandle>,
|
||||||
|
) -> wasmtime::Result<String> {
|
||||||
|
let stack = self.get_item_stack(&res)?;
|
||||||
|
let stack = stack.lock().await;
|
||||||
|
Ok(stack.item.registry_key.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_count(&mut self, res: Resource<ItemStackHandle>) -> wasmtime::Result<u8> {
|
||||||
|
let stack = self.get_item_stack(&res)?;
|
||||||
|
let stack = stack.lock().await;
|
||||||
|
Ok(stack.item_count)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn set_count(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<ItemStackHandle>,
|
||||||
|
count: u8,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
let stack = self.get_item_stack(&res)?;
|
||||||
|
let mut stack = stack.lock().await;
|
||||||
|
stack.item_count = count;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_max_count(&mut self, res: Resource<ItemStackHandle>) -> wasmtime::Result<u8> {
|
||||||
|
let stack = self.get_item_stack(&res)?;
|
||||||
|
let stack = stack.lock().await;
|
||||||
|
// Search in components for MaxStackSize
|
||||||
|
if let Some((_, data)) = stack
|
||||||
|
.item
|
||||||
|
.components
|
||||||
|
.iter()
|
||||||
|
.find(|(id, _)| *id == DataComponent::MaxStackSize)
|
||||||
|
&& let Some(max_size) = data
|
||||||
|
.as_any()
|
||||||
|
.downcast_ref::<pumpkin_data::data_component_impl::MaxStackSizeImpl>()
|
||||||
|
{
|
||||||
|
return Ok(max_size.size);
|
||||||
|
}
|
||||||
|
Ok(64) // Default
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_enchantments(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<ItemStackHandle>,
|
||||||
|
) -> wasmtime::Result<Vec<WitEnchantmentValue>> {
|
||||||
|
let stack = self.get_item_stack(&res)?;
|
||||||
|
let stack = stack.lock().await;
|
||||||
|
let mut enchantments = Vec::new();
|
||||||
|
if let Some((_, Some(data))) = stack
|
||||||
|
.patch
|
||||||
|
.iter()
|
||||||
|
.find(|(id, _)| *id == DataComponent::Enchantments)
|
||||||
|
&& let Some(enc_impl) = data.as_any().downcast_ref::<EnchantmentsImpl>()
|
||||||
|
{
|
||||||
|
for (enc, level) in enc_impl.enchantment.iter() {
|
||||||
|
enchantments.push(WitEnchantmentValue {
|
||||||
|
enchantment: to_wit_enchantment(enc),
|
||||||
|
level: *level as u32,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(enchantments)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn add_enchantment(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<ItemStackHandle>,
|
||||||
|
enchantment: WitEnchantment,
|
||||||
|
level: u32,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
let stack = self.get_item_stack(&res)?;
|
||||||
|
let mut stack = stack.lock().await;
|
||||||
|
let enc = from_wit_enchantment(enchantment);
|
||||||
|
|
||||||
|
let mut current_encs = if let Some((_, Some(data))) = stack
|
||||||
|
.patch
|
||||||
|
.iter()
|
||||||
|
.find(|(id, _)| *id == DataComponent::Enchantments)
|
||||||
|
{
|
||||||
|
data.as_any()
|
||||||
|
.downcast_ref::<EnchantmentsImpl>()
|
||||||
|
.map(|e| e.enchantment.clone().into_owned())
|
||||||
|
.unwrap_or_default()
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
};
|
||||||
|
|
||||||
|
current_encs.retain(|(e, _)| e.id != enc.id);
|
||||||
|
current_encs.push((enc, level as i32));
|
||||||
|
|
||||||
|
if let Some((_, data)) = stack
|
||||||
|
.patch
|
||||||
|
.iter_mut()
|
||||||
|
.find(|(id, _)| *id == DataComponent::Enchantments)
|
||||||
|
{
|
||||||
|
*data = Some(Box::new(EnchantmentsImpl {
|
||||||
|
enchantment: Cow::from(current_encs),
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
stack.patch.push((
|
||||||
|
DataComponent::Enchantments,
|
||||||
|
Some(Box::new(EnchantmentsImpl {
|
||||||
|
enchantment: Cow::from(current_encs),
|
||||||
|
})),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn remove_enchantment(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<ItemStackHandle>,
|
||||||
|
enchantment: WitEnchantment,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
let stack = self.get_item_stack(&res)?;
|
||||||
|
let mut stack = stack.lock().await;
|
||||||
|
let enc = from_wit_enchantment(enchantment);
|
||||||
|
|
||||||
|
if let Some((_, Some(data))) = stack
|
||||||
|
.patch
|
||||||
|
.iter_mut()
|
||||||
|
.find(|(id, _)| *id == DataComponent::Enchantments)
|
||||||
|
&& let Some(enc_impl) = data.as_mut_any().downcast_mut::<EnchantmentsImpl>()
|
||||||
|
{
|
||||||
|
let mut encs = enc_impl.enchantment.clone().into_owned();
|
||||||
|
encs.retain(|(e, _)| e.id != enc.id);
|
||||||
|
enc_impl.enchantment = Cow::from(encs);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_lore(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<ItemStackHandle>,
|
||||||
|
) -> wasmtime::Result<Vec<Resource<WitTextComponent>>> {
|
||||||
|
let _stack = self.get_item_stack(&res)?;
|
||||||
|
// LoreImpl is currently not fully implemented with data.
|
||||||
|
Ok(Vec::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn set_lore(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<ItemStackHandle>,
|
||||||
|
_lore: Vec<Resource<WitTextComponent>>,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
let _stack = self.get_item_stack(&res)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn add_lore(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<ItemStackHandle>,
|
||||||
|
_line: Resource<WitTextComponent>,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
let _stack = self.get_item_stack(&res)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_custom_name(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<ItemStackHandle>,
|
||||||
|
) -> wasmtime::Result<Option<Resource<WitTextComponent>>> {
|
||||||
|
let stack = self.get_item_stack(&res)?;
|
||||||
|
let stack = stack.lock().await;
|
||||||
|
if let Some((_, Some(data))) = stack
|
||||||
|
.patch
|
||||||
|
.iter()
|
||||||
|
.find(|(id, _)| *id == DataComponent::CustomName)
|
||||||
|
&& let Some(name_impl) = data.as_any().downcast_ref::<CustomNameImpl>()
|
||||||
|
{
|
||||||
|
let text = pumpkin_util::text::TextComponent::text(name_impl.name.clone());
|
||||||
|
return Ok(Some(self.add_text_component(text)?));
|
||||||
|
}
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn set_custom_name(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<ItemStackHandle>,
|
||||||
|
name: Option<Resource<WitTextComponent>>,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
let stack = self.get_item_stack(&res)?;
|
||||||
|
let mut stack = stack.lock().await;
|
||||||
|
if let Some(name_res) = name {
|
||||||
|
let text = text_component_from_resource(self, &name_res);
|
||||||
|
// This is a hack to get some string representation.
|
||||||
|
let name_str = format!("{:?}", text.0.content);
|
||||||
|
if let Some((_, data)) = stack
|
||||||
|
.patch
|
||||||
|
.iter_mut()
|
||||||
|
.find(|(id, _)| *id == DataComponent::CustomName)
|
||||||
|
{
|
||||||
|
*data = Some(Box::new(CustomNameImpl { name: name_str }));
|
||||||
|
} else {
|
||||||
|
stack.patch.push((
|
||||||
|
DataComponent::CustomName,
|
||||||
|
Some(Box::new(CustomNameImpl { name: name_str })),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
stack
|
||||||
|
.patch
|
||||||
|
.retain(|(id, _)| *id != DataComponent::CustomName);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_components(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<ItemStackHandle>,
|
||||||
|
) -> wasmtime::Result<Vec<WitDataComponentValue>> {
|
||||||
|
let stack = self.get_item_stack(&res)?;
|
||||||
|
let stack = stack.lock().await;
|
||||||
|
let mut components = Vec::new();
|
||||||
|
for (id, data) in &stack.patch {
|
||||||
|
if let Some(data) = data {
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
let mut serializer = Serializer::new(&mut buf);
|
||||||
|
let mut struct_ser = serializer.serialize_struct("", 0).unwrap();
|
||||||
|
serialize(*id, data.as_ref(), &mut struct_ser).unwrap();
|
||||||
|
struct_ser.end().unwrap();
|
||||||
|
|
||||||
|
components.push(WitDataComponentValue {
|
||||||
|
component: to_wit_data_component(*id),
|
||||||
|
value: buf,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(components)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn set_component(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<ItemStackHandle>,
|
||||||
|
component: WitDataComponent,
|
||||||
|
value: Vec<u8>,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
let stack = self.get_item_stack(&res)?;
|
||||||
|
let mut stack = stack.lock().await;
|
||||||
|
let id = from_wit_data_component(component);
|
||||||
|
let mut deserializer = Deserializer::new(value.as_slice());
|
||||||
|
let mut seq = WitSeqAccess {
|
||||||
|
deserializer: &mut deserializer,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Ok(component_impl) = deserialize(id, &mut seq) {
|
||||||
|
if let Some((_, data)) = stack.patch.iter_mut().find(|(pid, _)| *pid == id) {
|
||||||
|
*data = Some(component_impl);
|
||||||
|
} else {
|
||||||
|
stack.patch.push((id, Some(component_impl)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn remove_component(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<ItemStackHandle>,
|
||||||
|
component: WitDataComponent,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
let stack = self.get_item_stack(&res)?;
|
||||||
|
let mut stack = stack.lock().await;
|
||||||
|
let id = from_wit_data_component(component);
|
||||||
|
stack.patch.retain(|(pid, _)| *pid != id);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn drop(&mut self, rep: Resource<ItemStackHandle>) -> wasmtime::Result<()> {
|
||||||
|
self.resource_table
|
||||||
|
.delete::<ItemStackResource>(Resource::new_own(rep.rep()))
|
||||||
|
.map_err(wasmtime::Error::from)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -17,6 +17,7 @@ pub mod forms;
|
|||||||
pub mod generated_packets;
|
pub mod generated_packets;
|
||||||
pub mod gui;
|
pub mod gui;
|
||||||
pub mod i18n;
|
pub mod i18n;
|
||||||
|
pub mod item_stack;
|
||||||
pub mod java_dialogs;
|
pub mod java_dialogs;
|
||||||
pub mod logging;
|
pub mod logging;
|
||||||
pub mod permission;
|
pub mod permission;
|
||||||
|
|||||||
@ -47,8 +47,12 @@ use pumpkin_protocol::bedrock::client::set_actor_data::{
|
|||||||
use pumpkin_protocol::codec::var_ulong::VarULong;
|
use pumpkin_protocol::codec::var_ulong::VarULong;
|
||||||
use pumpkin_util::version::{BedrockMinecraftVersion, JavaMinecraftVersion};
|
use pumpkin_util::version::{BedrockMinecraftVersion, JavaMinecraftVersion};
|
||||||
|
|
||||||
struct WitSeqAccess<'a> {
|
use pumpkin_protocol::ser::ReadingError;
|
||||||
deserializer: &'a mut Deserializer<&'a [u8]>,
|
use pumpkin_protocol::ser::deserializer::Deserializer;
|
||||||
|
use serde::de::SeqAccess;
|
||||||
|
|
||||||
|
pub(crate) struct WitSeqAccess<'a> {
|
||||||
|
pub(crate) deserializer: &'a mut Deserializer<&'a [u8]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de> SeqAccess<'de> for WitSeqAccess<'_> {
|
impl<'de> SeqAccess<'de> for WitSeqAccess<'_> {
|
||||||
@ -494,132 +498,6 @@ fn world_from_resource(
|
|||||||
.clone()
|
.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::plugin::loader::wasm::wasm_host::wit::v0_1::pumpkin::plugin::common::DataComponentValue as WitDataComponentValue;
|
|
||||||
use crate::plugin::loader::wasm::wasm_host::wit::v0_1::pumpkin::plugin::common::EnchantmentValue as WitEnchantmentValue;
|
|
||||||
use crate::plugin::loader::wasm::wasm_host::wit::v0_1::pumpkin::plugin::data_components::DataComponent as WitDataComponent;
|
|
||||||
use crate::plugin::loader::wasm::wasm_host::wit::v0_1::pumpkin::plugin::enchantments::Enchantment as WitEnchantment;
|
|
||||||
use pumpkin_data::Enchantment;
|
|
||||||
use pumpkin_data::data_component::DataComponent;
|
|
||||||
use pumpkin_data::data_component_impl::{DataComponentImpl, EnchantmentsImpl};
|
|
||||||
use pumpkin_protocol::codec::data_component::{deserialize, serialize};
|
|
||||||
use pumpkin_protocol::ser::ReadingError;
|
|
||||||
use pumpkin_protocol::ser::deserializer::Deserializer;
|
|
||||||
use pumpkin_protocol::ser::serializer::Serializer;
|
|
||||||
use serde::de::SeqAccess;
|
|
||||||
use serde::ser::SerializeStruct;
|
|
||||||
use serde::ser::Serializer as _;
|
|
||||||
use std::borrow::Cow;
|
|
||||||
|
|
||||||
pub(super) fn to_wit_data_component(id: DataComponent) -> WitDataComponent {
|
|
||||||
// Safety: WIT enum is generated in the same order as the internal enum
|
|
||||||
unsafe { std::mem::transmute(id as u8) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn from_wit_data_component(id: WitDataComponent) -> DataComponent {
|
|
||||||
// Safety: WIT enum is generated in the same order as the internal enum
|
|
||||||
unsafe { std::mem::transmute(id as u8) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn to_wit_enchantment(id: &Enchantment) -> WitEnchantment {
|
|
||||||
// Safety: WIT enum is generated in the same order as the internal enum
|
|
||||||
unsafe { std::mem::transmute(id.id) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn from_wit_enchantment(id: WitEnchantment) -> &'static Enchantment {
|
|
||||||
// Safety: WIT enum is generated in the same order as the internal enum
|
|
||||||
Enchantment::from_id(id as u8).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn to_wit_item_stack(
|
|
||||||
stack: &pumpkin_data::item_stack::ItemStack,
|
|
||||||
) -> Option<pumpkin::plugin::common::ItemStack> {
|
|
||||||
if stack.is_empty() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut components = Vec::new();
|
|
||||||
let mut enchantments = Vec::new();
|
|
||||||
for (id, data) in &stack.patch {
|
|
||||||
if let Some(data) = data {
|
|
||||||
if *id == DataComponent::Enchantments {
|
|
||||||
if let Some(enc_impl) = data.as_any().downcast_ref::<EnchantmentsImpl>() {
|
|
||||||
for (enc, level) in enc_impl.enchantment.iter() {
|
|
||||||
enchantments.push(WitEnchantmentValue {
|
|
||||||
enchantment: to_wit_enchantment(enc),
|
|
||||||
level: *level as u32,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut buf = Vec::new();
|
|
||||||
let mut serializer = Serializer::new(&mut buf);
|
|
||||||
let mut struct_ser = serializer.serialize_struct("", 0).unwrap();
|
|
||||||
serialize(*id, data.as_ref(), &mut struct_ser).unwrap();
|
|
||||||
struct_ser.end().unwrap();
|
|
||||||
|
|
||||||
components.push(WitDataComponentValue {
|
|
||||||
component: to_wit_data_component(*id),
|
|
||||||
value: buf,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(pumpkin::plugin::common::ItemStack {
|
|
||||||
registry_key: stack.item.registry_key.to_string(),
|
|
||||||
count: stack.item_count,
|
|
||||||
components,
|
|
||||||
enchantments,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn from_wit_item_stack(
|
|
||||||
stack: pumpkin::plugin::common::ItemStack,
|
|
||||||
) -> pumpkin_data::item_stack::ItemStack {
|
|
||||||
let mut patch: Vec<(DataComponent, Option<Box<dyn DataComponentImpl>>)> = Vec::new();
|
|
||||||
for component_value in stack.components {
|
|
||||||
let id = from_wit_data_component(component_value.component);
|
|
||||||
let mut deserializer = Deserializer::new(component_value.value.as_slice());
|
|
||||||
|
|
||||||
let mut seq = WitSeqAccess {
|
|
||||||
deserializer: &mut deserializer,
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Ok(component_impl) = deserialize(id, &mut seq) {
|
|
||||||
patch.push((id, Some(component_impl)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !stack.enchantments.is_empty() {
|
|
||||||
let mut encs = Vec::new();
|
|
||||||
for enc_val in stack.enchantments {
|
|
||||||
encs.push((
|
|
||||||
from_wit_enchantment(enc_val.enchantment),
|
|
||||||
enc_val.level as i32,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
patch.push((
|
|
||||||
DataComponent::Enchantments,
|
|
||||||
Some(Box::new(EnchantmentsImpl {
|
|
||||||
enchantment: Cow::from(encs),
|
|
||||||
})),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
pumpkin_data::item_stack::ItemStack::new_with_component(
|
|
||||||
stack.count,
|
|
||||||
pumpkin_data::item::Item::from_registry_key(
|
|
||||||
stack
|
|
||||||
.registry_key
|
|
||||||
.strip_prefix("minecraft:")
|
|
||||||
.unwrap_or(&stack.registry_key),
|
|
||||||
)
|
|
||||||
.unwrap_or(&pumpkin_data::item::Item::AIR),
|
|
||||||
patch,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const fn to_wit_permission_level(
|
const fn to_wit_permission_level(
|
||||||
level: PermissionLvl,
|
level: PermissionLvl,
|
||||||
) -> pumpkin::plugin::permission::PermissionLevel {
|
) -> pumpkin::plugin::permission::PermissionLevel {
|
||||||
@ -705,18 +583,21 @@ use pumpkin_protocol::codec::item_stack_seralizer::ItemStackSerializer;
|
|||||||
use pumpkin_protocol::java::client::play::CSetContainerSlot;
|
use pumpkin_protocol::java::client::play::CSetContainerSlot;
|
||||||
use pumpkin_world::inventory::Inventory;
|
use pumpkin_world::inventory::Inventory;
|
||||||
|
|
||||||
|
use crate::plugin::loader::wasm::wasm_host::wit::v0_1::pumpkin::plugin::item_stack::ItemStack as WitHostItemStack;
|
||||||
|
|
||||||
impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
||||||
async fn set_item_in_hand(
|
async fn set_item_in_hand(
|
||||||
&mut self,
|
&mut self,
|
||||||
player: Resource<Player>,
|
player: Resource<Player>,
|
||||||
hand: pumpkin::plugin::common::Hand,
|
hand: pumpkin::plugin::common::Hand,
|
||||||
stack: Option<pumpkin::plugin::common::ItemStack>,
|
stack: Option<Resource<WitHostItemStack>>,
|
||||||
) -> wasmtime::Result<()> {
|
) -> wasmtime::Result<()> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
let stack = stack.map_or_else(
|
let stack = if let Some(stack_res) = stack {
|
||||||
|| pumpkin_data::item_stack::ItemStack::EMPTY.clone(),
|
self.get_item_stack(&stack_res)?.lock().await.clone()
|
||||||
from_wit_item_stack,
|
} else {
|
||||||
);
|
pumpkin_data::item_stack::ItemStack::EMPTY.clone()
|
||||||
|
};
|
||||||
|
|
||||||
let hand = from_wasm_hand(hand);
|
let hand = from_wasm_hand(hand);
|
||||||
let slot = match hand {
|
let slot = match hand {
|
||||||
@ -738,13 +619,14 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
|||||||
&mut self,
|
&mut self,
|
||||||
player: Resource<Player>,
|
player: Resource<Player>,
|
||||||
slot: u8,
|
slot: u8,
|
||||||
stack: Option<pumpkin::plugin::common::ItemStack>,
|
stack: Option<Resource<WitHostItemStack>>,
|
||||||
) -> wasmtime::Result<()> {
|
) -> wasmtime::Result<()> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
let stack = stack.map_or_else(
|
let stack = if let Some(stack_res) = stack {
|
||||||
|| pumpkin_data::item_stack::ItemStack::EMPTY.clone(),
|
self.get_item_stack(&stack_res)?.lock().await.clone()
|
||||||
from_wit_item_stack,
|
} else {
|
||||||
);
|
pumpkin_data::item_stack::ItemStack::EMPTY.clone()
|
||||||
|
};
|
||||||
|
|
||||||
player
|
player
|
||||||
.inventory()
|
.inventory()
|
||||||
@ -759,6 +641,35 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_inventory_item(
|
||||||
|
&mut self,
|
||||||
|
player: Resource<Player>,
|
||||||
|
slot: u8,
|
||||||
|
) -> wasmtime::Result<Option<Resource<WitHostItemStack>>> {
|
||||||
|
let player = player_from_resource(self, &player)?;
|
||||||
|
let stack = player.inventory().get_stack(slot as usize).await;
|
||||||
|
if stack.lock().await.is_empty() {
|
||||||
|
Ok(None)
|
||||||
|
} else {
|
||||||
|
Ok(Some(self.add_item_stack(stack)?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_item_in_hand(
|
||||||
|
&mut self,
|
||||||
|
player: Resource<Player>,
|
||||||
|
hand: pumpkin::plugin::common::Hand,
|
||||||
|
) -> wasmtime::Result<Option<Resource<WitHostItemStack>>> {
|
||||||
|
let player = player_from_resource(self, &player)?;
|
||||||
|
let hand = from_wasm_hand(hand);
|
||||||
|
let stack = player.inventory().get_stack_in_hand(hand).await;
|
||||||
|
if stack.lock().await.is_empty() {
|
||||||
|
Ok(None)
|
||||||
|
} else {
|
||||||
|
Ok(Some(self.add_item_stack(stack)?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async fn as_entity(
|
async fn as_entity(
|
||||||
&mut self,
|
&mut self,
|
||||||
player: Resource<Player>,
|
player: Resource<Player>,
|
||||||
@ -1188,35 +1099,6 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
|||||||
Ok(player.inventory.get_selected_slot())
|
Ok(player.inventory.get_selected_slot())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_item_in_hand(
|
|
||||||
&mut self,
|
|
||||||
player: Resource<Player>,
|
|
||||||
hand: pumpkin::plugin::common::Hand,
|
|
||||||
) -> wasmtime::Result<Option<pumpkin::plugin::common::ItemStack>> {
|
|
||||||
let player = player_from_resource(self, &player)?;
|
|
||||||
let inventory = player.inventory();
|
|
||||||
let item_stack = match hand {
|
|
||||||
pumpkin::plugin::common::Hand::Left => inventory.off_hand_item().await,
|
|
||||||
pumpkin::plugin::common::Hand::Right => inventory.held_item(),
|
|
||||||
};
|
|
||||||
let item_stack = item_stack.lock().await.clone();
|
|
||||||
Ok(to_wit_item_stack(&item_stack))
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_inventory_item(
|
|
||||||
&mut self,
|
|
||||||
player: Resource<Player>,
|
|
||||||
slot: u8,
|
|
||||||
) -> wasmtime::Result<Option<pumpkin::plugin::common::ItemStack>> {
|
|
||||||
let player = player_from_resource(self, &player)?;
|
|
||||||
let slot = slot as usize;
|
|
||||||
if slot >= PlayerInventory::MAIN_SIZE {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
let item_stack = player.inventory.main_inventory[slot].lock().await.clone();
|
|
||||||
Ok(to_wit_item_stack(&item_stack))
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_health(&mut self, player: Resource<Player>) -> wasmtime::Result<f32> {
|
async fn get_health(&mut self, player: Resource<Player>) -> wasmtime::Result<f32> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
Ok(player.living_entity.health.load())
|
Ok(player.living_entity.health.load())
|
||||||
|
|||||||
@ -354,6 +354,55 @@ impl pumpkin::plugin::world::HostWorld for PluginHostState {
|
|||||||
Ok(self.get_world_res(&world)?.provider.min_y)
|
Ok(self.get_world_res(&world)?.provider.min_y)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_sky_light(
|
||||||
|
&mut self,
|
||||||
|
world: Resource<World>,
|
||||||
|
pos: WitBlockPos,
|
||||||
|
) -> wasmtime::Result<u8> {
|
||||||
|
let world_ref = self.get_world_res(&world)?;
|
||||||
|
let internal_pos = BlockPos::new(pos.x, pos.y, pos.z);
|
||||||
|
Ok(world_ref.provider.get_sky_light_level(&internal_pos))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn set_sky_light(
|
||||||
|
&mut self,
|
||||||
|
world: Resource<World>,
|
||||||
|
pos: WitBlockPos,
|
||||||
|
level: u8,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
let world_ref = self.get_world_res(&world)?;
|
||||||
|
let internal_pos = BlockPos::new(pos.x, pos.y, pos.z);
|
||||||
|
world_ref.provider.set_sky_light_level(&internal_pos, level);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_block_light(
|
||||||
|
&mut self,
|
||||||
|
world: Resource<World>,
|
||||||
|
pos: WitBlockPos,
|
||||||
|
) -> wasmtime::Result<u8> {
|
||||||
|
let world_ref = self.get_world_res(&world)?;
|
||||||
|
let internal_pos = BlockPos::new(pos.x, pos.y, pos.z);
|
||||||
|
Ok(world_ref
|
||||||
|
.provider
|
||||||
|
.get_block_light_level(&internal_pos)
|
||||||
|
.unwrap_or(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn set_block_light(
|
||||||
|
&mut self,
|
||||||
|
world: Resource<World>,
|
||||||
|
pos: WitBlockPos,
|
||||||
|
level: u8,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
let world_ref = self.get_world_res(&world)?;
|
||||||
|
let internal_pos = BlockPos::new(pos.x, pos.y, pos.z);
|
||||||
|
world_ref
|
||||||
|
.provider
|
||||||
|
.set_block_light_level(&internal_pos, level);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
async fn get_entities(
|
async fn get_entities(
|
||||||
&mut self,
|
&mut self,
|
||||||
world: Resource<World>,
|
world: Resource<World>,
|
||||||
|
|||||||
@ -3428,6 +3428,20 @@ impl World {
|
|||||||
.get_sky_light_level(&self.level, position)
|
.get_sky_light_level(&self.level, position)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_block_light_level(&self, position: &BlockPos, light_level: u8) {
|
||||||
|
let _ = self
|
||||||
|
.level
|
||||||
|
.light_engine
|
||||||
|
.set_block_light_level(&self.level, position, light_level);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_sky_light_level(&self, position: &BlockPos, light_level: u8) {
|
||||||
|
let _ = self
|
||||||
|
.level
|
||||||
|
.light_engine
|
||||||
|
.set_sky_light_level(&self.level, position, light_level);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn schedule_block_tick(
|
pub fn schedule_block_tick(
|
||||||
&self,
|
&self,
|
||||||
block: &Block,
|
block: &Block,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user