chore(plugin-api): extend entity api
This commit is contained in:
parent
7467195821
commit
4a4b72c83c
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -2988,7 +2988,6 @@ dependencies = [
|
|||||||
"pumpkin-util",
|
"pumpkin-util",
|
||||||
"pumpkin-world",
|
"pumpkin-world",
|
||||||
"serde",
|
"serde",
|
||||||
"take_mut",
|
|
||||||
"thiserror 2.0.18",
|
"thiserror 2.0.18",
|
||||||
"tokio",
|
"tokio",
|
||||||
"uuid",
|
"uuid",
|
||||||
@ -3760,12 +3759,6 @@ dependencies = [
|
|||||||
"winx",
|
"winx",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "take_mut"
|
|
||||||
version = "0.2.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "target-lexicon"
|
name = "target-lexicon"
|
||||||
version = "0.13.5"
|
version = "0.13.5"
|
||||||
|
|||||||
@ -169,7 +169,6 @@ tracing-subscriber = { version = "0.3.23", features = [
|
|||||||
"time",
|
"time",
|
||||||
] }
|
] }
|
||||||
slotmap = "1.1"
|
slotmap = "1.1"
|
||||||
take_mut = "0.2.2"
|
|
||||||
temp-dir = "0.2.0"
|
temp-dir = "0.2.0"
|
||||||
thread_local = "1.1.9"
|
thread_local = "1.1.9"
|
||||||
time = "0.3"
|
time = "0.3"
|
||||||
|
|||||||
@ -1,22 +1,12 @@
|
|||||||
interface block-entity {
|
interface block-entity {
|
||||||
use common.{block-position};
|
use common.{block-pos};
|
||||||
|
|
||||||
resource block-entity {
|
resource block-entity {
|
||||||
resource-location: func() -> string;
|
resource-location: func() -> string;
|
||||||
get-position: func() -> block-position;
|
get-position: func() -> block-pos;
|
||||||
get-id: func() -> u32;
|
get-id: func() -> u32;
|
||||||
// write-nbt: func(nbt: nbt-compound);
|
|
||||||
// from-nbt: func(nbt: nbt-compound, position: block-position) -> entity;
|
|
||||||
// tick: func(world: simple-world);
|
|
||||||
// write-internal: func(nbt: nbt-compound);
|
|
||||||
// chunk-data-nbt: func() -> option<nbt-compound;
|
|
||||||
// get-inventory: func() -> option<inventory>;
|
|
||||||
// set-block-state: func(block-state: block-state-id);
|
|
||||||
// on-block-replaced: func(world: simple-world, position: block-position);
|
|
||||||
is-dirty: func() -> bool;
|
is-dirty: func() -> bool;
|
||||||
clear-dirty: func();
|
clear-dirty: func();
|
||||||
// to-property-delegate: func() -> option<property-delegate>;
|
|
||||||
// to-experience-container: func() -> option<experience-container>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resource command-block-entity {
|
resource command-block-entity {
|
||||||
@ -30,7 +20,65 @@ interface block-entity {
|
|||||||
powered: func() -> bool;
|
powered: func() -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum dye-color {
|
||||||
|
white,
|
||||||
|
orange,
|
||||||
|
magenta,
|
||||||
|
light-blue,
|
||||||
|
yellow,
|
||||||
|
lime,
|
||||||
|
pink,
|
||||||
|
gray,
|
||||||
|
light-gray,
|
||||||
|
cyan,
|
||||||
|
purple,
|
||||||
|
blue,
|
||||||
|
brown,
|
||||||
|
green,
|
||||||
|
red,
|
||||||
|
black,
|
||||||
|
}
|
||||||
|
|
||||||
|
record sign-text {
|
||||||
|
messages: list<string>,
|
||||||
|
color: dye-color,
|
||||||
|
has-glowing-text: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
resource sign-block-entity {
|
||||||
|
get-block-entity: func() -> block-entity;
|
||||||
|
get-front-text: func() -> sign-text;
|
||||||
|
set-front-text: func(text: sign-text);
|
||||||
|
get-back-text: func() -> sign-text;
|
||||||
|
set-back-text: func(text: sign-text);
|
||||||
|
is-waxed: func() -> bool;
|
||||||
|
set-waxed: func(waxed: bool);
|
||||||
|
}
|
||||||
|
|
||||||
|
resource jukebox-block-entity {
|
||||||
|
get-block-entity: func() -> block-entity;
|
||||||
|
is-playing: func() -> bool;
|
||||||
|
stop-playing: func();
|
||||||
|
start-playing: func(length-in-ticks: u64);
|
||||||
|
}
|
||||||
|
|
||||||
|
resource chest-block-entity {
|
||||||
|
get-block-entity: func() -> block-entity;
|
||||||
|
viewer-count: func() -> u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
resource mob-spawner-block-entity {
|
||||||
|
get-block-entity: func() -> block-entity;
|
||||||
|
get-spawn-count: func() -> s32;
|
||||||
|
get-spawn-range: func() -> s32;
|
||||||
|
get-delay: func() -> s32;
|
||||||
|
}
|
||||||
|
|
||||||
variant block-entity-type {
|
variant block-entity-type {
|
||||||
command-block-entity(command-block-entity),
|
command-block-entity(command-block-entity),
|
||||||
|
sign-block-entity(sign-block-entity),
|
||||||
|
jukebox-block-entity(jukebox-block-entity),
|
||||||
|
chest-block-entity(chest-block-entity),
|
||||||
|
mob-spawner-block-entity(mob-spawner-block-entity),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,7 @@ 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, game-mode};
|
use common.{position, block-pos, locale, game-mode};
|
||||||
use item-stack.{item-stack};
|
use item-stack.{item-stack};
|
||||||
use server.{server, difficulty};
|
use server.{server, difficulty};
|
||||||
use text.{text-component};
|
use text.{text-component};
|
||||||
@ -145,7 +145,7 @@ interface command {
|
|||||||
block-predicate(string),
|
block-predicate(string),
|
||||||
time(s32),
|
time(s32),
|
||||||
num(result<number, not-in-bounds>),
|
num(result<number, not-in-bounds>),
|
||||||
block-pos(tuple<s32, s32, s32>),
|
block-pos(block-pos),
|
||||||
pos3d(tuple<f64, f64, f64>),
|
pos3d(tuple<f64, f64, f64>),
|
||||||
pos2d(tuple<f64, f64>),
|
pos2d(tuple<f64, f64>),
|
||||||
rotation(tuple<f32, bool, f32, bool>),
|
rotation(tuple<f32, bool, f32, bool>),
|
||||||
|
|||||||
@ -5,7 +5,11 @@ interface common {
|
|||||||
type raw-text-component = list<u8>;
|
type raw-text-component = list<u8>;
|
||||||
|
|
||||||
/// A position in the world grid (integers).
|
/// A position in the world grid (integers).
|
||||||
type block-position = tuple<s32, s32, s32>;
|
record block-pos {
|
||||||
|
x: s32,
|
||||||
|
y: s32,
|
||||||
|
z: s32,
|
||||||
|
}
|
||||||
|
|
||||||
/// A precise coordinate in the world (floats).
|
/// A precise coordinate in the world (floats).
|
||||||
type position = tuple<f64, f64, f64>;
|
type position = tuple<f64, f64, f64>;
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
interface event {
|
interface event {
|
||||||
use common.{block-position, game-mode, hand, position, click-type};
|
use common.{block-pos, game-mode, hand, position, click-type};
|
||||||
use item-stack.{item-stack};
|
use item-stack.{item-stack};
|
||||||
use player.{player};
|
use player.{player};
|
||||||
use text.{text-component};
|
use text.{text-component};
|
||||||
@ -163,7 +163,7 @@ interface event {
|
|||||||
record player-interact-event-data {
|
record player-interact-event-data {
|
||||||
player: player,
|
player: player,
|
||||||
action: interact-action,
|
action: interact-action,
|
||||||
clicked-pos: option<block-position>,
|
clicked-pos: option<block-pos>,
|
||||||
block: string,
|
block: string,
|
||||||
cancelled: bool
|
cancelled: bool
|
||||||
}
|
}
|
||||||
@ -213,7 +213,7 @@ interface event {
|
|||||||
record block-redstone-event-data {
|
record block-redstone-event-data {
|
||||||
target-world: %world,
|
target-world: %world,
|
||||||
state-id: u16,
|
state-id: u16,
|
||||||
block-position: block-position,
|
block-pos: block-pos,
|
||||||
old-current: s32,
|
old-current: s32,
|
||||||
new-current: s32,
|
new-current: s32,
|
||||||
cancelled: bool
|
cancelled: bool
|
||||||
@ -222,7 +222,7 @@ interface event {
|
|||||||
record block-break-event-data {
|
record block-break-event-data {
|
||||||
player: option<player>,
|
player: option<player>,
|
||||||
block: string,
|
block: string,
|
||||||
block-position: block-position,
|
block-pos: block-pos,
|
||||||
exp: u32,
|
exp: u32,
|
||||||
should-drop: bool,
|
should-drop: bool,
|
||||||
cancelled: bool
|
cancelled: bool
|
||||||
@ -248,7 +248,7 @@ interface event {
|
|||||||
old-state-id: u16,
|
old-state-id: u16,
|
||||||
new-block: string,
|
new-block: string,
|
||||||
new-state-id: u16,
|
new-state-id: u16,
|
||||||
block-position: block-position,
|
block-pos: block-pos,
|
||||||
cancelled: bool
|
cancelled: bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -256,7 +256,7 @@ interface event {
|
|||||||
player: player,
|
player: player,
|
||||||
block-placed: string,
|
block-placed: string,
|
||||||
block-placed-against: string,
|
block-placed-against: string,
|
||||||
block-position: block-position,
|
block-pos: block-pos,
|
||||||
can-build: bool,
|
can-build: bool,
|
||||||
cancelled: bool
|
cancelled: bool
|
||||||
}
|
}
|
||||||
@ -280,10 +280,10 @@ interface event {
|
|||||||
|
|
||||||
record spawn-change-event-data {
|
record spawn-change-event-data {
|
||||||
target-world: %world,
|
target-world: %world,
|
||||||
previous-position: block-position,
|
previous-position: block-pos,
|
||||||
previous-yaw: f32,
|
previous-yaw: f32,
|
||||||
previous-pitch: f32,
|
previous-pitch: f32,
|
||||||
new-position: block-position,
|
new-position: block-pos,
|
||||||
new-yaw: f32,
|
new-yaw: f32,
|
||||||
new-pitch: f32
|
new-pitch: f32
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
interface %world {
|
interface %world {
|
||||||
use common.{position, entity-pose};
|
use common.{position, entity-pose, block-pos};
|
||||||
|
use block-entity.{block-entity, command-block-entity, block-entity-type};
|
||||||
use text.{text-component};
|
use text.{text-component};
|
||||||
use scoreboard.{scoreboard};
|
use scoreboard.{scoreboard};
|
||||||
use particles.{particle};
|
use particles.{particle};
|
||||||
@ -99,13 +100,6 @@ interface %world {
|
|||||||
id: u16,
|
id: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A position in the world grid.
|
|
||||||
record block-pos {
|
|
||||||
x: s32,
|
|
||||||
y: s32,
|
|
||||||
z: s32,
|
|
||||||
}
|
|
||||||
|
|
||||||
resource entity {
|
resource entity {
|
||||||
get-id: func() -> u32;
|
get-id: func() -> u32;
|
||||||
get-uuid: func() -> uuid;
|
get-uuid: func() -> uuid;
|
||||||
@ -118,29 +112,6 @@ interface %world {
|
|||||||
get-pitch: func() -> f32;
|
get-pitch: func() -> f32;
|
||||||
get-head-yaw: func() -> f32;
|
get-head-yaw: func() -> f32;
|
||||||
|
|
||||||
is-on-ground: func() -> bool;
|
|
||||||
|
|
||||||
is-sneaking: func() -> bool;
|
|
||||||
set-sneaking: func(sneaking: bool);
|
|
||||||
|
|
||||||
is-sprinting: func() -> bool;
|
|
||||||
set-sprinting: func(sprinting: bool);
|
|
||||||
|
|
||||||
is-swimming: func() -> bool;
|
|
||||||
set-swimming: func(swimming: bool);
|
|
||||||
|
|
||||||
is-invisible: func() -> bool;
|
|
||||||
set-invisible: func(invisible: bool);
|
|
||||||
|
|
||||||
is-glowing: func() -> bool;
|
|
||||||
set-glowing: func(glowing: bool);
|
|
||||||
|
|
||||||
is-fall-flying: func() -> bool;
|
|
||||||
set-fall-flying: func(fall-flying: bool);
|
|
||||||
|
|
||||||
is-on-fire: func() -> bool;
|
|
||||||
set-on-fire: func(on-fire: bool);
|
|
||||||
|
|
||||||
teleport: func(pos: position, world-ref: %world);
|
teleport: func(pos: position, world-ref: %world);
|
||||||
set-velocity: func(velocity: position);
|
set-velocity: func(velocity: position);
|
||||||
get-velocity: func() -> position;
|
get-velocity: func() -> position;
|
||||||
@ -158,6 +129,73 @@ interface %world {
|
|||||||
get-fire-ticks: func() -> s32;
|
get-fire-ticks: func() -> s32;
|
||||||
set-fire-ticks: func(ticks: s32);
|
set-fire-ticks: func(ticks: s32);
|
||||||
|
|
||||||
|
get-health: func() -> f32;
|
||||||
|
set-health: func(health: f32);
|
||||||
|
get-max-health: func() -> f32;
|
||||||
|
damage: func(amount: f32);
|
||||||
|
is-dead: func() -> bool;
|
||||||
|
|
||||||
|
get-absorption: func() -> f32;
|
||||||
|
set-absorption: func(amount: f32);
|
||||||
|
|
||||||
|
get-age: func() -> s32;
|
||||||
|
set-age: func(age: s32);
|
||||||
|
|
||||||
|
get-fall-distance: func() -> f32;
|
||||||
|
set-fall-distance: func(distance: f32);
|
||||||
|
|
||||||
|
get-ticks-lived: func() -> s32;
|
||||||
|
set-ticks-lived: func(ticks: s32);
|
||||||
|
|
||||||
|
is-sneaking: func() -> bool;
|
||||||
|
set-sneaking: func(sneaking: bool);
|
||||||
|
is-sprinting: func() -> bool;
|
||||||
|
set-sprinting: func(sprinting: bool);
|
||||||
|
is-swimming: func() -> bool;
|
||||||
|
set-swimming: func(swimming: bool);
|
||||||
|
is-invisible: func() -> bool;
|
||||||
|
set-invisible: func(invisible: bool);
|
||||||
|
is-glowing: func() -> bool;
|
||||||
|
set-glowing: func(glowing: bool);
|
||||||
|
is-fall-flying: func() -> bool;
|
||||||
|
set-fall-flying: func(fall-flying: bool);
|
||||||
|
|
||||||
|
get-width: func() -> f32;
|
||||||
|
get-height: func() -> f32;
|
||||||
|
|
||||||
|
set-rotation: func(yaw: f32, pitch: f32);
|
||||||
|
|
||||||
|
is-on-ground: func() -> bool;
|
||||||
|
is-on-fire: func() -> bool;
|
||||||
|
set-on-fire: func(on-fire: bool);
|
||||||
|
has-visual-fire: func() -> bool;
|
||||||
|
set-visual-fire: func(visual-fire: bool);
|
||||||
|
|
||||||
|
get-portal-cooldown: func() -> u32;
|
||||||
|
set-portal-cooldown: func(cooldown: u32);
|
||||||
|
|
||||||
|
get-remaining-air: func() -> s32;
|
||||||
|
set-remaining-air: func(air: s32);
|
||||||
|
get-max-air: func() -> s32;
|
||||||
|
|
||||||
|
send-system-message: func(message: text-component);
|
||||||
|
|
||||||
|
get-eye-height: func() -> f32;
|
||||||
|
get-eye-position: func() -> position;
|
||||||
|
|
||||||
|
get-nearby-entities: func(x: f64, y: f64, z: f64) -> list<entity>;
|
||||||
|
|
||||||
|
get-vehicle: func() -> option<entity>;
|
||||||
|
get-passengers: func() -> list<entity>;
|
||||||
|
add-passenger: func(passenger: entity);
|
||||||
|
remove-passenger: func(passenger: entity);
|
||||||
|
eject-passengers: func();
|
||||||
|
|
||||||
|
get-bounding-box: func() -> bounding-box;
|
||||||
|
|
||||||
|
is-in-water: func() -> bool;
|
||||||
|
is-in-lava: func() -> bool;
|
||||||
|
|
||||||
remove: func();
|
remove: func();
|
||||||
|
|
||||||
/// Performs a raycast from the entity's eye position in its looking direction.
|
/// Performs a raycast from the entity's eye position in its looking direction.
|
||||||
@ -172,6 +210,12 @@ interface %world {
|
|||||||
face: block-direction,
|
face: block-direction,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents an axis-aligned bounding box.
|
||||||
|
record bounding-box {
|
||||||
|
min: position,
|
||||||
|
max: position,
|
||||||
|
}
|
||||||
|
|
||||||
/// Represents a cardinal direction or block face.
|
/// Represents a cardinal direction or block face.
|
||||||
enum block-direction {
|
enum block-direction {
|
||||||
down,
|
down,
|
||||||
@ -267,5 +311,8 @@ interface %world {
|
|||||||
|
|
||||||
/// 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>;
|
||||||
|
|
||||||
|
/// Returns the block entity at the specified position, if any.
|
||||||
|
get-block-entity: func(pos: block-pos) -> option<block-entity-type>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,7 +33,6 @@ hybrid-array = "0.4"
|
|||||||
async-compression = { workspace = true, features = ["tokio", "zlib", "deflate"] }
|
async-compression = { workspace = true, features = ["tokio", "zlib", "deflate"] }
|
||||||
flate2.workspace = true
|
flate2.workspace = true
|
||||||
|
|
||||||
take_mut.workspace = true
|
|
||||||
bitflags.workspace = true
|
bitflags.workspace = true
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|||||||
@ -82,11 +82,6 @@ impl UDPNetworkDecoder {
|
|||||||
&mut self,
|
&mut self,
|
||||||
_key: &[u8; 16],
|
_key: &[u8; 16],
|
||||||
) -> Result<(), EncryptionAlreadyEnabledError> {
|
) -> Result<(), EncryptionAlreadyEnabledError> {
|
||||||
// if matches!(self.reader, DecryptionReader::Decrypt(_)) {
|
|
||||||
// return Err(EncryptionAlreadyEnabledError);
|
|
||||||
// }
|
|
||||||
// let cipher = Aes128Cfb8Dec::new_from_slices(key, key).map_err(|_| ());
|
|
||||||
// take_mut::take(&mut self.reader, |decoder| decoder.upgrade(cipher));
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -107,11 +107,6 @@ impl UDPNetworkEncoder {
|
|||||||
&mut self,
|
&mut self,
|
||||||
_key: &[u8; 16],
|
_key: &[u8; 16],
|
||||||
) -> Result<(), crate::bedrock::packet_decoder::EncryptionAlreadyEnabledError> {
|
) -> Result<(), crate::bedrock::packet_decoder::EncryptionAlreadyEnabledError> {
|
||||||
// if matches!(self.writer, EncryptionWriter::Encrypt(_)) {
|
|
||||||
// return Err(crate::bedrock::packet_decoder::EncryptionAlreadyEnabledError);
|
|
||||||
// }
|
|
||||||
// let cipher = Aes128Cfb8Enc::new_from_slices(key, key).map_err(|_| ());
|
|
||||||
// take_mut::take(&mut self.writer, |encoder| encoder.upgrade(cipher));
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -74,7 +74,7 @@ impl<R: AsyncRead + Unpin> AsyncRead for DecryptionReader<R> {
|
|||||||
/// Supports `ZLib` decoding/decompression
|
/// Supports `ZLib` decoding/decompression
|
||||||
/// Supports Aes128 Encryption
|
/// Supports Aes128 Encryption
|
||||||
pub struct TCPNetworkDecoder<R: AsyncRead + Unpin> {
|
pub struct TCPNetworkDecoder<R: AsyncRead + Unpin> {
|
||||||
reader: DecryptionReader<R>,
|
reader: Option<DecryptionReader<R>>,
|
||||||
compression: Option<CompressionThreshold>,
|
compression: Option<CompressionThreshold>,
|
||||||
payload_scratch: BytesMut,
|
payload_scratch: BytesMut,
|
||||||
}
|
}
|
||||||
@ -82,7 +82,7 @@ pub struct TCPNetworkDecoder<R: AsyncRead + Unpin> {
|
|||||||
impl<R: AsyncRead + Unpin> TCPNetworkDecoder<R> {
|
impl<R: AsyncRead + Unpin> TCPNetworkDecoder<R> {
|
||||||
pub fn new(reader: R) -> Self {
|
pub fn new(reader: R) -> Self {
|
||||||
Self {
|
Self {
|
||||||
reader: DecryptionReader::None(reader),
|
reader: Some(DecryptionReader::None(reader)),
|
||||||
compression: None,
|
compression: None,
|
||||||
payload_scratch: BytesMut::new(),
|
payload_scratch: BytesMut::new(),
|
||||||
}
|
}
|
||||||
@ -94,19 +94,27 @@ impl<R: AsyncRead + Unpin> TCPNetworkDecoder<R> {
|
|||||||
|
|
||||||
/// NOTE: Encryption can only be set; a minecraft stream cannot go back to being unencrypted
|
/// NOTE: Encryption can only be set; a minecraft stream cannot go back to being unencrypted
|
||||||
pub fn set_encryption(&mut self, key: &[u8; 16]) -> Result<(), PacketDecodeError> {
|
pub fn set_encryption(&mut self, key: &[u8; 16]) -> Result<(), PacketDecodeError> {
|
||||||
if matches!(self.reader, DecryptionReader::Decrypt(_)) {
|
if matches!(self.reader, Some(DecryptionReader::Decrypt(_))) {
|
||||||
return Err(PacketDecodeError::Message(
|
return Err(PacketDecodeError::Message(
|
||||||
"Encryption already enabled".into(),
|
"Encryption already enabled".into(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
let cipher = Aes128Cfb8Dec::new_from_slices(key, key)
|
let cipher = Aes128Cfb8Dec::new_from_slices(key, key)
|
||||||
.map_err(|_| PacketDecodeError::Message("Invalid key".into()))?;
|
.map_err(|_| PacketDecodeError::Message("Invalid key".into()))?;
|
||||||
take_mut::take(&mut self.reader, |decoder| decoder.upgrade(cipher));
|
|
||||||
|
if let Some(reader) = self.reader.take() {
|
||||||
|
self.reader = Some(reader.upgrade(cipher));
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_raw_packet(&mut self) -> Result<RawPacket, PacketDecodeError> {
|
pub async fn get_raw_packet(&mut self) -> Result<RawPacket, PacketDecodeError> {
|
||||||
let packet_len = VarInt::decode_async(&mut self.reader)
|
let reader = self
|
||||||
|
.reader
|
||||||
|
.as_mut()
|
||||||
|
.ok_or_else(|| PacketDecodeError::Message("Reader missing".into()))?;
|
||||||
|
|
||||||
|
let packet_len = VarInt::decode_async(reader)
|
||||||
.await
|
.await
|
||||||
.map_err(|err| match err {
|
.map_err(|err| match err {
|
||||||
ReadingError::CleanEOF(_) => PacketDecodeError::ConnectionClosed,
|
ReadingError::CleanEOF(_) => PacketDecodeError::ConnectionClosed,
|
||||||
@ -119,7 +127,7 @@ impl<R: AsyncRead + Unpin> TCPNetworkDecoder<R> {
|
|||||||
Err(PacketDecodeError::OutOfBounds)?;
|
Err(PacketDecodeError::OutOfBounds)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut bounded_reader = (&mut self.reader).take(packet_len);
|
let mut bounded_reader = reader.take(packet_len);
|
||||||
let mut expected_packet_data_len = packet_len as usize;
|
let mut expected_packet_data_len = packet_len as usize;
|
||||||
let mut expected_uncompressed_packet_data_len = None;
|
let mut expected_uncompressed_packet_data_len = None;
|
||||||
|
|
||||||
|
|||||||
@ -81,7 +81,7 @@ impl<W: AsyncWrite + Unpin> AsyncWrite for EncryptionWriter<W> {
|
|||||||
/// Supports `ZLib` endecoding/compression
|
/// Supports `ZLib` endecoding/compression
|
||||||
/// Supports Aes128 Encryption
|
/// Supports Aes128 Encryption
|
||||||
pub struct TCPNetworkEncoder<W: AsyncWrite + Unpin> {
|
pub struct TCPNetworkEncoder<W: AsyncWrite + Unpin> {
|
||||||
writer: EncryptionWriter<W>,
|
writer: Option<EncryptionWriter<W>>,
|
||||||
// compression and compression threshold
|
// compression and compression threshold
|
||||||
compression: Option<(CompressionThreshold, CompressionLevel)>,
|
compression: Option<(CompressionThreshold, CompressionLevel)>,
|
||||||
// Reused compressor to avoid constructing zlib state per packet.
|
// Reused compressor to avoid constructing zlib state per packet.
|
||||||
@ -93,7 +93,7 @@ pub struct TCPNetworkEncoder<W: AsyncWrite + Unpin> {
|
|||||||
impl<W: AsyncWrite + Unpin> TCPNetworkEncoder<W> {
|
impl<W: AsyncWrite + Unpin> TCPNetworkEncoder<W> {
|
||||||
pub const fn new(writer: W) -> Self {
|
pub const fn new(writer: W) -> Self {
|
||||||
Self {
|
Self {
|
||||||
writer: EncryptionWriter::None(writer),
|
writer: Some(EncryptionWriter::None(writer)),
|
||||||
compression: None,
|
compression: None,
|
||||||
compressor: None,
|
compressor: None,
|
||||||
compression_scratch: Vec::new(),
|
compression_scratch: Vec::new(),
|
||||||
@ -109,14 +109,17 @@ impl<W: AsyncWrite + Unpin> TCPNetworkEncoder<W> {
|
|||||||
|
|
||||||
/// NOTE: Encryption can only be set; a minecraft stream cannot go back to being unencrypted
|
/// NOTE: Encryption can only be set; a minecraft stream cannot go back to being unencrypted
|
||||||
pub fn set_encryption(&mut self, key: &[u8; 16]) -> Result<(), PacketEncodeError> {
|
pub fn set_encryption(&mut self, key: &[u8; 16]) -> Result<(), PacketEncodeError> {
|
||||||
if matches!(self.writer, EncryptionWriter::Encrypt(_)) {
|
if matches!(self.writer, Some(EncryptionWriter::Encrypt(_))) {
|
||||||
return Err(PacketEncodeError::Message(
|
return Err(PacketEncodeError::Message(
|
||||||
"Encryption already enabled".into(),
|
"Encryption already enabled".into(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
let cipher = Aes128Cfb8Enc::new_from_slices(key, key)
|
let cipher = Aes128Cfb8Enc::new_from_slices(key, key)
|
||||||
.map_err(|_| PacketEncodeError::Message("Invalid key".into()))?;
|
.map_err(|_| PacketEncodeError::Message("Invalid key".into()))?;
|
||||||
take_mut::take(&mut self.writer, |encoder| encoder.upgrade(cipher));
|
|
||||||
|
if let Some(writer) = self.writer.take() {
|
||||||
|
self.writer = Some(writer.upgrade(cipher));
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,14 +245,16 @@ impl<W: AsyncWrite + Unpin> TCPNetworkEncoder<W> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
full_packet_len_var_int
|
full_packet_len_var_int
|
||||||
.encode_async(&mut self.writer)
|
.encode_async(self.writer.as_mut().unwrap())
|
||||||
.await
|
.await
|
||||||
.map_err(|err| PacketEncodeError::Message(err.to_string()))?;
|
.map_err(|err| PacketEncodeError::Message(err.to_string()))?;
|
||||||
data_len_var_int
|
data_len_var_int
|
||||||
.encode_async(&mut self.writer)
|
.encode_async(self.writer.as_mut().unwrap())
|
||||||
.await
|
.await
|
||||||
.map_err(|err| PacketEncodeError::Message(err.to_string()))?;
|
.map_err(|err| PacketEncodeError::Message(err.to_string()))?;
|
||||||
self.writer
|
self.writer
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
.write_all(&self.compression_scratch)
|
.write_all(&self.compression_scratch)
|
||||||
.await
|
.await
|
||||||
.map_err(|err| PacketEncodeError::Message(err.to_string()))?;
|
.map_err(|err| PacketEncodeError::Message(err.to_string()))?;
|
||||||
@ -274,14 +279,16 @@ impl<W: AsyncWrite + Unpin> TCPNetworkEncoder<W> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
full_packet_len_var_int
|
full_packet_len_var_int
|
||||||
.encode_async(&mut self.writer)
|
.encode_async(self.writer.as_mut().unwrap())
|
||||||
.await
|
.await
|
||||||
.map_err(|err| PacketEncodeError::Message(err.to_string()))?;
|
.map_err(|err| PacketEncodeError::Message(err.to_string()))?;
|
||||||
data_len_var_int
|
data_len_var_int
|
||||||
.encode_async(&mut self.writer)
|
.encode_async(self.writer.as_mut().unwrap())
|
||||||
.await
|
.await
|
||||||
.map_err(|err| PacketEncodeError::Message(err.to_string()))?;
|
.map_err(|err| PacketEncodeError::Message(err.to_string()))?;
|
||||||
self.writer
|
self.writer
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
.write_all(&packet_data)
|
.write_all(&packet_data)
|
||||||
.await
|
.await
|
||||||
.map_err(|err| PacketEncodeError::Message(err.to_string()))?;
|
.map_err(|err| PacketEncodeError::Message(err.to_string()))?;
|
||||||
@ -299,10 +306,12 @@ impl<W: AsyncWrite + Unpin> TCPNetworkEncoder<W> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
full_packet_len_var_int
|
full_packet_len_var_int
|
||||||
.encode_async(&mut self.writer)
|
.encode_async(self.writer.as_mut().unwrap())
|
||||||
.await
|
.await
|
||||||
.map_err(|err| PacketEncodeError::Message(err.to_string()))?;
|
.map_err(|err| PacketEncodeError::Message(err.to_string()))?;
|
||||||
self.writer
|
self.writer
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
.write_all(&packet_data)
|
.write_all(&packet_data)
|
||||||
.await
|
.await
|
||||||
.map_err(|err| PacketEncodeError::Message(err.to_string()))?;
|
.map_err(|err| PacketEncodeError::Message(err.to_string()))?;
|
||||||
@ -313,6 +322,8 @@ impl<W: AsyncWrite + Unpin> TCPNetworkEncoder<W> {
|
|||||||
|
|
||||||
pub async fn flush(&mut self) -> Result<(), PacketEncodeError> {
|
pub async fn flush(&mut self) -> Result<(), PacketEncodeError> {
|
||||||
self.writer
|
self.writer
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
.flush()
|
.flush()
|
||||||
.await
|
.await
|
||||||
.map_err(|err| PacketEncodeError::Message(err.to_string()))
|
.map_err(|err| PacketEncodeError::Message(err.to_string()))
|
||||||
|
|||||||
@ -11,7 +11,7 @@ use pumpkin_nbt::{compound::NbtCompound, tag::NbtTag};
|
|||||||
use pumpkin_util::math::position::BlockPos;
|
use pumpkin_util::math::position::BlockPos;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Copy, Default, Debug, PartialEq, Eq)]
|
||||||
#[repr(i8)]
|
#[repr(i8)]
|
||||||
pub enum DyeColor {
|
pub enum DyeColor {
|
||||||
White = 0,
|
White = 0,
|
||||||
|
|||||||
@ -1936,6 +1936,7 @@ impl JavaClient {
|
|||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_lines)]
|
||||||
pub async fn handle_use_item_on(
|
pub async fn handle_use_item_on(
|
||||||
&self,
|
&self,
|
||||||
player: &Arc<Player>,
|
player: &Arc<Player>,
|
||||||
@ -1985,6 +1986,26 @@ impl JavaClient {
|
|||||||
let world = entity.world.load_full();
|
let world = entity.world.load_full();
|
||||||
let block = world.get_block(&position);
|
let block = world.get_block(&position);
|
||||||
|
|
||||||
|
let event = PlayerInteractEvent::new(
|
||||||
|
player,
|
||||||
|
InteractAction::RightClickBlock,
|
||||||
|
block,
|
||||||
|
Some(position),
|
||||||
|
);
|
||||||
|
|
||||||
|
send_cancellable! {{
|
||||||
|
server;
|
||||||
|
event;
|
||||||
|
'cancelled: {
|
||||||
|
self.enqueue_packet(&CBlockUpdate::new(
|
||||||
|
position,
|
||||||
|
VarInt(block.id as i32),
|
||||||
|
))
|
||||||
|
.await;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
let sneaking = player.living_entity.entity.sneaking.load(Ordering::Relaxed);
|
let sneaking = player.living_entity.entity.sneaking.load(Ordering::Relaxed);
|
||||||
|
|
||||||
// Code based on the java class ServerPlayerInteractionManager
|
// Code based on the java class ServerPlayerInteractionManager
|
||||||
|
|||||||
@ -60,10 +60,10 @@ impl PlayerInteractEvent {
|
|||||||
/// Enum representing possible player interaction actions.
|
/// Enum representing possible player interaction actions.
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
pub enum InteractAction {
|
pub enum InteractAction {
|
||||||
/// Left-clicking the air
|
/// Left-clicking a block
|
||||||
LeftClickBlock,
|
LeftClickBlock,
|
||||||
|
|
||||||
/// Left-clicking a block
|
/// Left-clicking the air
|
||||||
LeftClickAir,
|
LeftClickAir,
|
||||||
|
|
||||||
/// Right-clicking the air
|
/// Right-clicking the air
|
||||||
|
|||||||
@ -55,6 +55,7 @@ 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 ItemStackResource = WasmResource<Arc<Mutex<pumpkin_data::item_stack::ItemStack>>>;
|
||||||
pub type RecipeManagerResource = WasmResource<Arc<RecipeManager>>;
|
pub type RecipeManagerResource = WasmResource<Arc<RecipeManager>>;
|
||||||
|
pub type BlockEntityResource = WasmResource<Arc<dyn crate::block::entities::BlockEntity>>;
|
||||||
|
|
||||||
pub type OwnedConsumedArgs = HashMap<String, OwnedArg>;
|
pub type OwnedConsumedArgs = HashMap<String, OwnedArg>;
|
||||||
|
|
||||||
@ -240,6 +241,14 @@ impl PluginHostState {
|
|||||||
.push(RecipeManagerResource { provider })?;
|
.push(RecipeManagerResource { provider })?;
|
||||||
Ok(wasmtime::component::Resource::new_own(resource.rep()))
|
Ok(wasmtime::component::Resource::new_own(resource.rep()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_block_entity<T>(
|
||||||
|
&mut self,
|
||||||
|
provider: Arc<dyn crate::block::entities::BlockEntity>,
|
||||||
|
) -> wasmtime::Result<wasmtime::component::Resource<T>> {
|
||||||
|
let resource = self.resource_table.push(BlockEntityResource { provider })?;
|
||||||
|
Ok(wasmtime::component::Resource::new_own(resource.rep()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PluginHttpHooks {
|
pub struct PluginHttpHooks {
|
||||||
|
|||||||
@ -1,90 +1,539 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
use wasmtime::component::Resource;
|
use wasmtime::component::Resource;
|
||||||
|
|
||||||
|
use crate::block::entities::BlockEntity as InternalBlockEntity;
|
||||||
|
use crate::block::entities::chest::ChestBlockEntity as InternalChestBlockEntity;
|
||||||
|
use crate::block::entities::command_block::CommandBlockEntity as InternalCommandBlockEntity;
|
||||||
|
use crate::block::entities::jukebox::JukeboxBlockEntity as InternalJukeboxBlockEntity;
|
||||||
|
use crate::block::entities::mob_spawner::MobSpawnerBlockEntity as InternalMobSpawnerBlockEntity;
|
||||||
|
use crate::block::entities::sign::{
|
||||||
|
DyeColor as InternalDyeColor, SignBlockEntity as InternalSignBlockEntity, Text as InternalText,
|
||||||
|
};
|
||||||
use crate::plugin::loader::wasm::wasm_host::{
|
use crate::plugin::loader::wasm::wasm_host::{
|
||||||
state::PluginHostState,
|
state::{BlockEntityResource, PluginHostState},
|
||||||
wit::v0_1::pumpkin::{
|
wit::v0_1::pumpkin::{
|
||||||
self,
|
self,
|
||||||
plugin::{
|
plugin::{
|
||||||
block_entity::{BlockEntity, CommandBlockEntity},
|
block_entity::{
|
||||||
common::BlockPosition,
|
BlockEntity, ChestBlockEntity, CommandBlockEntity, DyeColor, HostBlockEntity,
|
||||||
|
HostChestBlockEntity, HostCommandBlockEntity, HostJukeboxBlockEntity,
|
||||||
|
HostMobSpawnerBlockEntity, HostSignBlockEntity, JukeboxBlockEntity,
|
||||||
|
MobSpawnerBlockEntity, SignBlockEntity, SignText,
|
||||||
|
},
|
||||||
|
common::BlockPos as WitBlockPos,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
impl pumpkin::plugin::block_entity::Host for PluginHostState {}
|
impl pumpkin::plugin::block_entity::Host for PluginHostState {}
|
||||||
|
|
||||||
impl pumpkin::plugin::block_entity::HostBlockEntity for PluginHostState {
|
fn block_entity_from_resource(
|
||||||
async fn resource_location(&mut self, _res: Resource<BlockEntity>) -> wasmtime::Result<String> {
|
state: &PluginHostState,
|
||||||
todo!("Implement resource_location lookup")
|
entity: &Resource<BlockEntity>,
|
||||||
|
) -> wasmtime::Result<Arc<dyn InternalBlockEntity>> {
|
||||||
|
state
|
||||||
|
.resource_table
|
||||||
|
.get::<BlockEntityResource>(&Resource::new_own(entity.rep()))
|
||||||
|
.map_err(|_| wasmtime::Error::msg("invalid block entity resource handle"))
|
||||||
|
.map(|resource| resource.provider.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_position(
|
const fn from_wasm_dye_color(color: DyeColor) -> InternalDyeColor {
|
||||||
&mut self,
|
match color {
|
||||||
_res: Resource<BlockEntity>,
|
DyeColor::White => InternalDyeColor::White,
|
||||||
) -> wasmtime::Result<BlockPosition> {
|
DyeColor::Orange => InternalDyeColor::Orange,
|
||||||
todo!("Implement get_position lookup")
|
DyeColor::Magenta => InternalDyeColor::Magenta,
|
||||||
}
|
DyeColor::LightBlue => InternalDyeColor::LightBlue,
|
||||||
|
DyeColor::Yellow => InternalDyeColor::Yellow,
|
||||||
async fn get_id(&mut self, _res: Resource<BlockEntity>) -> wasmtime::Result<u32> {
|
DyeColor::Lime => InternalDyeColor::Lime,
|
||||||
todo!("Implement get_id lookup")
|
DyeColor::Pink => InternalDyeColor::Pink,
|
||||||
}
|
DyeColor::Gray => InternalDyeColor::Gray,
|
||||||
|
DyeColor::LightGray => InternalDyeColor::LightGray,
|
||||||
async fn is_dirty(&mut self, _res: Resource<BlockEntity>) -> wasmtime::Result<bool> {
|
DyeColor::Cyan => InternalDyeColor::Cyan,
|
||||||
todo!("Implement is_dirty lookup")
|
DyeColor::Purple => InternalDyeColor::Purple,
|
||||||
}
|
DyeColor::Blue => InternalDyeColor::Blue,
|
||||||
|
DyeColor::Brown => InternalDyeColor::Brown,
|
||||||
async fn clear_dirty(&mut self, _res: Resource<BlockEntity>) -> wasmtime::Result<()> {
|
DyeColor::Green => InternalDyeColor::Green,
|
||||||
todo!("Implement clear_dirty logic")
|
DyeColor::Red => InternalDyeColor::Red,
|
||||||
}
|
DyeColor::Black => InternalDyeColor::Black,
|
||||||
|
|
||||||
async fn drop(&mut self, _rep: Resource<BlockEntity>) -> wasmtime::Result<()> {
|
|
||||||
todo!();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl pumpkin::plugin::block_entity::HostCommandBlockEntity for PluginHostState {
|
const fn to_wasm_dye_color(color: InternalDyeColor) -> DyeColor {
|
||||||
|
match color {
|
||||||
|
InternalDyeColor::White => DyeColor::White,
|
||||||
|
InternalDyeColor::Orange => DyeColor::Orange,
|
||||||
|
InternalDyeColor::Magenta => DyeColor::Magenta,
|
||||||
|
InternalDyeColor::LightBlue => DyeColor::LightBlue,
|
||||||
|
InternalDyeColor::Yellow => DyeColor::Yellow,
|
||||||
|
InternalDyeColor::Lime => DyeColor::Lime,
|
||||||
|
InternalDyeColor::Pink => DyeColor::Pink,
|
||||||
|
InternalDyeColor::Gray => DyeColor::Gray,
|
||||||
|
InternalDyeColor::LightGray => DyeColor::LightGray,
|
||||||
|
InternalDyeColor::Cyan => DyeColor::Cyan,
|
||||||
|
InternalDyeColor::Purple => DyeColor::Purple,
|
||||||
|
InternalDyeColor::Blue => DyeColor::Blue,
|
||||||
|
InternalDyeColor::Brown => DyeColor::Brown,
|
||||||
|
InternalDyeColor::Green => DyeColor::Green,
|
||||||
|
InternalDyeColor::Red => DyeColor::Red,
|
||||||
|
InternalDyeColor::Black => DyeColor::Black,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_wasm_sign_text(text: &InternalText) -> SignText {
|
||||||
|
SignText {
|
||||||
|
messages: text.messages.lock().unwrap().to_vec(),
|
||||||
|
color: to_wasm_dye_color(text.get_color()),
|
||||||
|
has_glowing_text: text
|
||||||
|
.has_glowing_text
|
||||||
|
.load(std::sync::atomic::Ordering::Relaxed),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_wasm_sign_text(text: SignText) -> InternalText {
|
||||||
|
let mut messages = [String::new(), String::new(), String::new(), String::new()];
|
||||||
|
for (i, msg) in text.messages.into_iter().take(4).enumerate() {
|
||||||
|
messages[i] = msg;
|
||||||
|
}
|
||||||
|
InternalText::from(pumpkin_nbt::tag::NbtTag::Compound({
|
||||||
|
let mut nbt = pumpkin_nbt::compound::NbtCompound::new();
|
||||||
|
nbt.put_bool("has_glowing_text", text.has_glowing_text);
|
||||||
|
nbt.put_string(
|
||||||
|
"color",
|
||||||
|
InternalDyeColor::from(from_wasm_dye_color(text.color) as i8).into(),
|
||||||
|
);
|
||||||
|
nbt.put_list(
|
||||||
|
"messages",
|
||||||
|
messages
|
||||||
|
.iter()
|
||||||
|
.map(|s| pumpkin_nbt::tag::NbtTag::String(s.clone().into()))
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
nbt
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HostBlockEntity for PluginHostState {
|
||||||
|
async fn resource_location(&mut self, res: Resource<BlockEntity>) -> wasmtime::Result<String> {
|
||||||
|
let entity = block_entity_from_resource(self, &res)?;
|
||||||
|
Ok(entity.resource_location().to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_position(&mut self, res: Resource<BlockEntity>) -> wasmtime::Result<WitBlockPos> {
|
||||||
|
let entity = block_entity_from_resource(self, &res)?;
|
||||||
|
let pos = entity.get_position();
|
||||||
|
Ok(WitBlockPos {
|
||||||
|
x: pos.0.x,
|
||||||
|
y: pos.0.y,
|
||||||
|
z: pos.0.z,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_id(&mut self, res: Resource<BlockEntity>) -> wasmtime::Result<u32> {
|
||||||
|
let entity = block_entity_from_resource(self, &res)?;
|
||||||
|
Ok(entity.get_id())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn is_dirty(&mut self, res: Resource<BlockEntity>) -> wasmtime::Result<bool> {
|
||||||
|
let entity = block_entity_from_resource(self, &res)?;
|
||||||
|
Ok(entity.is_dirty())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn clear_dirty(&mut self, res: Resource<BlockEntity>) -> wasmtime::Result<()> {
|
||||||
|
let entity = block_entity_from_resource(self, &res)?;
|
||||||
|
entity.clear_dirty();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn drop(&mut self, rep: Resource<BlockEntity>) -> wasmtime::Result<()> {
|
||||||
|
let _ = self
|
||||||
|
.resource_table
|
||||||
|
.delete::<BlockEntityResource>(Resource::new_own(rep.rep()));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HostCommandBlockEntity for PluginHostState {
|
||||||
async fn get_block_entity(
|
async fn get_block_entity(
|
||||||
&mut self,
|
&mut self,
|
||||||
_res: Resource<CommandBlockEntity>,
|
res: Resource<CommandBlockEntity>,
|
||||||
) -> wasmtime::Result<Resource<BlockEntity>> {
|
) -> wasmtime::Result<Resource<BlockEntity>> {
|
||||||
todo!("Implement upcasting/mapping to BlockEntity")
|
let entity = self
|
||||||
|
.resource_table
|
||||||
|
.get::<BlockEntityResource>(&Resource::new_own(res.rep()))
|
||||||
|
.map_err(|_| wasmtime::Error::msg("invalid command block entity resource handle"))?;
|
||||||
|
let provider = entity.provider.clone();
|
||||||
|
self.add_block_entity(provider)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn last_output(
|
async fn last_output(&mut self, res: Resource<CommandBlockEntity>) -> wasmtime::Result<String> {
|
||||||
|
let entity = block_entity_from_resource(self, &Resource::new_own(res.rep()))?;
|
||||||
|
if let Some(cmd) = entity.as_any().downcast_ref::<InternalCommandBlockEntity>() {
|
||||||
|
Ok(cmd.last_output.lock().await.clone())
|
||||||
|
} else {
|
||||||
|
Err(wasmtime::Error::msg("Not a command block entity"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn track_output(&mut self, res: Resource<CommandBlockEntity>) -> wasmtime::Result<bool> {
|
||||||
|
let entity = block_entity_from_resource(self, &Resource::new_own(res.rep()))?;
|
||||||
|
entity
|
||||||
|
.as_any()
|
||||||
|
.downcast_ref::<InternalCommandBlockEntity>()
|
||||||
|
.map_or_else(
|
||||||
|
|| Err(wasmtime::Error::msg("Not a command block entity")),
|
||||||
|
|cmd| Ok(cmd.track_output.load(std::sync::atomic::Ordering::Relaxed)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn success_count(&mut self, res: Resource<CommandBlockEntity>) -> wasmtime::Result<u32> {
|
||||||
|
let entity = block_entity_from_resource(self, &Resource::new_own(res.rep()))?;
|
||||||
|
entity
|
||||||
|
.as_any()
|
||||||
|
.downcast_ref::<InternalCommandBlockEntity>()
|
||||||
|
.map_or_else(
|
||||||
|
|| Err(wasmtime::Error::msg("Not a command block entity")),
|
||||||
|
|cmd| Ok(cmd.success_count.load(std::sync::atomic::Ordering::Relaxed)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn command(&mut self, res: Resource<CommandBlockEntity>) -> wasmtime::Result<String> {
|
||||||
|
let entity = block_entity_from_resource(self, &Resource::new_own(res.rep()))?;
|
||||||
|
if let Some(cmd) = entity.as_any().downcast_ref::<InternalCommandBlockEntity>() {
|
||||||
|
Ok(cmd.command.lock().await.clone())
|
||||||
|
} else {
|
||||||
|
Err(wasmtime::Error::msg("Not a command block entity"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn auto(&mut self, res: Resource<CommandBlockEntity>) -> wasmtime::Result<bool> {
|
||||||
|
let entity = block_entity_from_resource(self, &Resource::new_own(res.rep()))?;
|
||||||
|
entity
|
||||||
|
.as_any()
|
||||||
|
.downcast_ref::<InternalCommandBlockEntity>()
|
||||||
|
.map_or_else(
|
||||||
|
|| Err(wasmtime::Error::msg("Not a command block entity")),
|
||||||
|
|cmd| Ok(cmd.auto.load(std::sync::atomic::Ordering::Relaxed)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn condition_met(&mut self, res: Resource<CommandBlockEntity>) -> wasmtime::Result<bool> {
|
||||||
|
let entity = block_entity_from_resource(self, &Resource::new_own(res.rep()))?;
|
||||||
|
entity
|
||||||
|
.as_any()
|
||||||
|
.downcast_ref::<InternalCommandBlockEntity>()
|
||||||
|
.map_or_else(
|
||||||
|
|| Err(wasmtime::Error::msg("Not a command block entity")),
|
||||||
|
|cmd| Ok(cmd.condition_met.load(std::sync::atomic::Ordering::Relaxed)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn powered(&mut self, res: Resource<CommandBlockEntity>) -> wasmtime::Result<bool> {
|
||||||
|
let entity = block_entity_from_resource(self, &Resource::new_own(res.rep()))?;
|
||||||
|
entity
|
||||||
|
.as_any()
|
||||||
|
.downcast_ref::<InternalCommandBlockEntity>()
|
||||||
|
.map_or_else(
|
||||||
|
|| Err(wasmtime::Error::msg("Not a command block entity")),
|
||||||
|
|cmd| Ok(cmd.powered.load(std::sync::atomic::Ordering::Relaxed)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn drop(&mut self, rep: Resource<CommandBlockEntity>) -> wasmtime::Result<()> {
|
||||||
|
let _ = self
|
||||||
|
.resource_table
|
||||||
|
.delete::<BlockEntityResource>(Resource::new_own(rep.rep()));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HostSignBlockEntity for PluginHostState {
|
||||||
|
async fn get_block_entity(
|
||||||
&mut self,
|
&mut self,
|
||||||
_res: Resource<CommandBlockEntity>,
|
res: Resource<SignBlockEntity>,
|
||||||
) -> wasmtime::Result<String> {
|
) -> wasmtime::Result<Resource<BlockEntity>> {
|
||||||
todo!("Implement last_output lookup")
|
let entity = self
|
||||||
|
.resource_table
|
||||||
|
.get::<BlockEntityResource>(&Resource::new_own(res.rep()))
|
||||||
|
.map_err(|_| wasmtime::Error::msg("invalid sign block entity resource handle"))?;
|
||||||
|
let provider = entity.provider.clone();
|
||||||
|
self.add_block_entity(provider)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn track_output(&mut self, _res: Resource<CommandBlockEntity>) -> wasmtime::Result<bool> {
|
async fn get_front_text(
|
||||||
todo!("Implement track_output lookup")
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn success_count(&mut self, _res: Resource<CommandBlockEntity>) -> wasmtime::Result<u32> {
|
|
||||||
todo!("Implement success_count lookup")
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn command(&mut self, _res: Resource<CommandBlockEntity>) -> wasmtime::Result<String> {
|
|
||||||
todo!("Implement command lookup")
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn auto(&mut self, _res: Resource<CommandBlockEntity>) -> wasmtime::Result<bool> {
|
|
||||||
todo!("Implement auto lookup")
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn condition_met(
|
|
||||||
&mut self,
|
&mut self,
|
||||||
_res: Resource<CommandBlockEntity>,
|
res: Resource<SignBlockEntity>,
|
||||||
) -> wasmtime::Result<bool> {
|
) -> wasmtime::Result<SignText> {
|
||||||
todo!("Implement condition_met lookup")
|
let entity = block_entity_from_resource(self, &Resource::new_own(res.rep()))?;
|
||||||
|
entity
|
||||||
|
.as_any()
|
||||||
|
.downcast_ref::<InternalSignBlockEntity>()
|
||||||
|
.map_or_else(
|
||||||
|
|| Err(wasmtime::Error::msg("Not a sign block entity")),
|
||||||
|
|sign| Ok(to_wasm_sign_text(&sign.front_text)),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn powered(&mut self, _res: Resource<CommandBlockEntity>) -> wasmtime::Result<bool> {
|
async fn set_front_text(
|
||||||
todo!("Implement powered lookup")
|
&mut self,
|
||||||
|
res: Resource<SignBlockEntity>,
|
||||||
|
text: SignText,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
let entity = block_entity_from_resource(self, &Resource::new_own(res.rep()))?;
|
||||||
|
entity
|
||||||
|
.as_any()
|
||||||
|
.downcast_ref::<InternalSignBlockEntity>()
|
||||||
|
.map_or_else(
|
||||||
|
|| Err(wasmtime::Error::msg("Not a sign block entity")),
|
||||||
|
|sign| {
|
||||||
|
let new_text = from_wasm_sign_text(text);
|
||||||
|
sign.front_text.has_glowing_text.store(
|
||||||
|
new_text
|
||||||
|
.has_glowing_text
|
||||||
|
.load(std::sync::atomic::Ordering::Relaxed),
|
||||||
|
std::sync::atomic::Ordering::Relaxed,
|
||||||
|
);
|
||||||
|
sign.front_text.set_color(new_text.get_color());
|
||||||
|
(*sign.front_text.messages.lock().unwrap())
|
||||||
|
.clone_from(&new_text.messages.lock().unwrap());
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn drop(&mut self, _rep: Resource<CommandBlockEntity>) -> wasmtime::Result<()> {
|
async fn get_back_text(
|
||||||
todo!();
|
&mut self,
|
||||||
|
res: Resource<SignBlockEntity>,
|
||||||
|
) -> wasmtime::Result<SignText> {
|
||||||
|
let entity = block_entity_from_resource(self, &Resource::new_own(res.rep()))?;
|
||||||
|
entity
|
||||||
|
.as_any()
|
||||||
|
.downcast_ref::<InternalSignBlockEntity>()
|
||||||
|
.map_or_else(
|
||||||
|
|| Err(wasmtime::Error::msg("Not a sign block entity")),
|
||||||
|
|sign| Ok(to_wasm_sign_text(&sign.back_text)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn set_back_text(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<SignBlockEntity>,
|
||||||
|
text: SignText,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
let entity = block_entity_from_resource(self, &Resource::new_own(res.rep()))?;
|
||||||
|
entity
|
||||||
|
.as_any()
|
||||||
|
.downcast_ref::<InternalSignBlockEntity>()
|
||||||
|
.map_or_else(
|
||||||
|
|| Err(wasmtime::Error::msg("Not a sign block entity")),
|
||||||
|
|sign| {
|
||||||
|
let new_text = from_wasm_sign_text(text);
|
||||||
|
sign.back_text.has_glowing_text.store(
|
||||||
|
new_text
|
||||||
|
.has_glowing_text
|
||||||
|
.load(std::sync::atomic::Ordering::Relaxed),
|
||||||
|
std::sync::atomic::Ordering::Relaxed,
|
||||||
|
);
|
||||||
|
sign.back_text.set_color(new_text.get_color());
|
||||||
|
(*sign.back_text.messages.lock().unwrap())
|
||||||
|
.clone_from(&new_text.messages.lock().unwrap());
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn is_waxed(&mut self, res: Resource<SignBlockEntity>) -> wasmtime::Result<bool> {
|
||||||
|
let entity = block_entity_from_resource(self, &Resource::new_own(res.rep()))?;
|
||||||
|
entity
|
||||||
|
.as_any()
|
||||||
|
.downcast_ref::<InternalSignBlockEntity>()
|
||||||
|
.map_or_else(
|
||||||
|
|| Err(wasmtime::Error::msg("Not a sign block entity")),
|
||||||
|
|sign| Ok(sign.is_waxed.load(std::sync::atomic::Ordering::Relaxed)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn set_waxed(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<SignBlockEntity>,
|
||||||
|
waxed: bool,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
let entity = block_entity_from_resource(self, &Resource::new_own(res.rep()))?;
|
||||||
|
entity
|
||||||
|
.as_any()
|
||||||
|
.downcast_ref::<InternalSignBlockEntity>()
|
||||||
|
.map_or_else(
|
||||||
|
|| Err(wasmtime::Error::msg("Not a sign block entity")),
|
||||||
|
|sign| {
|
||||||
|
sign.is_waxed
|
||||||
|
.store(waxed, std::sync::atomic::Ordering::Relaxed);
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn drop(&mut self, rep: Resource<SignBlockEntity>) -> wasmtime::Result<()> {
|
||||||
|
let _ = self
|
||||||
|
.resource_table
|
||||||
|
.delete::<BlockEntityResource>(Resource::new_own(rep.rep()));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HostJukeboxBlockEntity for PluginHostState {
|
||||||
|
async fn get_block_entity(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<JukeboxBlockEntity>,
|
||||||
|
) -> wasmtime::Result<Resource<BlockEntity>> {
|
||||||
|
let entity = self
|
||||||
|
.resource_table
|
||||||
|
.get::<BlockEntityResource>(&Resource::new_own(res.rep()))
|
||||||
|
.map_err(|_| wasmtime::Error::msg("invalid jukebox block entity resource handle"))?;
|
||||||
|
let provider = entity.provider.clone();
|
||||||
|
self.add_block_entity(provider)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn is_playing(&mut self, res: Resource<JukeboxBlockEntity>) -> wasmtime::Result<bool> {
|
||||||
|
let entity = block_entity_from_resource(self, &Resource::new_own(res.rep()))?;
|
||||||
|
entity
|
||||||
|
.as_any()
|
||||||
|
.downcast_ref::<InternalJukeboxBlockEntity>()
|
||||||
|
.map_or_else(
|
||||||
|
|| Err(wasmtime::Error::msg("Not a jukebox block entity")),
|
||||||
|
|jukebox| Ok(jukebox.is_playing()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn stop_playing(&mut self, res: Resource<JukeboxBlockEntity>) -> wasmtime::Result<()> {
|
||||||
|
let entity = block_entity_from_resource(self, &Resource::new_own(res.rep()))?;
|
||||||
|
entity
|
||||||
|
.as_any()
|
||||||
|
.downcast_ref::<InternalJukeboxBlockEntity>()
|
||||||
|
.map_or_else(
|
||||||
|
|| Err(wasmtime::Error::msg("Not a jukebox block entity")),
|
||||||
|
|jukebox| {
|
||||||
|
jukebox.stop_playing();
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn start_playing(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<JukeboxBlockEntity>,
|
||||||
|
length_in_ticks: u64,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
let entity = block_entity_from_resource(self, &Resource::new_own(res.rep()))?;
|
||||||
|
entity
|
||||||
|
.as_any()
|
||||||
|
.downcast_ref::<InternalJukeboxBlockEntity>()
|
||||||
|
.map_or_else(
|
||||||
|
|| Err(wasmtime::Error::msg("Not a jukebox block entity")),
|
||||||
|
|jukebox| {
|
||||||
|
jukebox.start_playing(length_in_ticks);
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn drop(&mut self, rep: Resource<JukeboxBlockEntity>) -> wasmtime::Result<()> {
|
||||||
|
let _ = self
|
||||||
|
.resource_table
|
||||||
|
.delete::<BlockEntityResource>(Resource::new_own(rep.rep()));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HostChestBlockEntity for PluginHostState {
|
||||||
|
async fn get_block_entity(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<ChestBlockEntity>,
|
||||||
|
) -> wasmtime::Result<Resource<BlockEntity>> {
|
||||||
|
let entity = self
|
||||||
|
.resource_table
|
||||||
|
.get::<BlockEntityResource>(&Resource::new_own(res.rep()))
|
||||||
|
.map_err(|_| wasmtime::Error::msg("invalid chest block entity resource handle"))?;
|
||||||
|
let provider = entity.provider.clone();
|
||||||
|
self.add_block_entity(provider)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn viewer_count(&mut self, res: Resource<ChestBlockEntity>) -> wasmtime::Result<u32> {
|
||||||
|
let entity = block_entity_from_resource(self, &Resource::new_own(res.rep()))?;
|
||||||
|
entity
|
||||||
|
.as_any()
|
||||||
|
.downcast_ref::<InternalChestBlockEntity>()
|
||||||
|
.map_or_else(
|
||||||
|
|| Err(wasmtime::Error::msg("Not a chest block entity")),
|
||||||
|
|chest| Ok(chest.get_viewer_count() as u32),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn drop(&mut self, rep: Resource<ChestBlockEntity>) -> wasmtime::Result<()> {
|
||||||
|
let _ = self
|
||||||
|
.resource_table
|
||||||
|
.delete::<BlockEntityResource>(Resource::new_own(rep.rep()));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HostMobSpawnerBlockEntity for PluginHostState {
|
||||||
|
async fn get_block_entity(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<MobSpawnerBlockEntity>,
|
||||||
|
) -> wasmtime::Result<Resource<BlockEntity>> {
|
||||||
|
let entity = self
|
||||||
|
.resource_table
|
||||||
|
.get::<BlockEntityResource>(&Resource::new_own(res.rep()))
|
||||||
|
.map_err(|_| {
|
||||||
|
wasmtime::Error::msg("invalid mob spawner block entity resource handle")
|
||||||
|
})?;
|
||||||
|
let provider = entity.provider.clone();
|
||||||
|
self.add_block_entity(provider)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_spawn_count(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<MobSpawnerBlockEntity>,
|
||||||
|
) -> wasmtime::Result<i32> {
|
||||||
|
let entity = block_entity_from_resource(self, &Resource::new_own(res.rep()))?;
|
||||||
|
entity
|
||||||
|
.as_any()
|
||||||
|
.downcast_ref::<InternalMobSpawnerBlockEntity>()
|
||||||
|
.map_or_else(
|
||||||
|
|| Err(wasmtime::Error::msg("Not a mob spawner block entity")),
|
||||||
|
|spawner| Ok(spawner.spawn_count),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_spawn_range(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<MobSpawnerBlockEntity>,
|
||||||
|
) -> wasmtime::Result<i32> {
|
||||||
|
let entity = block_entity_from_resource(self, &Resource::new_own(res.rep()))?;
|
||||||
|
entity
|
||||||
|
.as_any()
|
||||||
|
.downcast_ref::<InternalMobSpawnerBlockEntity>()
|
||||||
|
.map_or_else(
|
||||||
|
|| Err(wasmtime::Error::msg("Not a mob spawner block entity")),
|
||||||
|
|spawner| Ok(spawner.spawn_range),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_delay(&mut self, res: Resource<MobSpawnerBlockEntity>) -> wasmtime::Result<i32> {
|
||||||
|
let entity = block_entity_from_resource(self, &Resource::new_own(res.rep()))?;
|
||||||
|
entity
|
||||||
|
.as_any()
|
||||||
|
.downcast_ref::<InternalMobSpawnerBlockEntity>()
|
||||||
|
.map_or_else(
|
||||||
|
|| Err(wasmtime::Error::msg("Not a mob spawner block entity")),
|
||||||
|
|spawner| Ok(spawner.delay.load(std::sync::atomic::Ordering::Relaxed)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn drop(&mut self, rep: Resource<MobSpawnerBlockEntity>) -> wasmtime::Result<()> {
|
||||||
|
let _ = self
|
||||||
|
.resource_table
|
||||||
|
.delete::<BlockEntityResource>(Resource::new_own(rep.rep()));
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,7 +43,7 @@ use crate::{
|
|||||||
Arg, ArgumentType, Command, CommandNode, CommandSender, CommandSenderType,
|
Arg, ArgumentType, Command, CommandNode, CommandSender, CommandSenderType,
|
||||||
ConsumedArgs, PermissionLevel, StringType,
|
ConsumedArgs, PermissionLevel, StringType,
|
||||||
},
|
},
|
||||||
common::{Locale, Position},
|
common::{BlockPos as WitBlockPos, Locale, Position},
|
||||||
player::Player,
|
player::Player,
|
||||||
server::Server,
|
server::Server,
|
||||||
text::TextComponent,
|
text::TextComponent,
|
||||||
@ -149,7 +149,11 @@ impl pumpkin::plugin::command::HostConsumedArgs for PluginHostState {
|
|||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
OwnedArg::BlockPos(p) => Arg::BlockPos((p.0.x, p.0.y, p.0.z)),
|
OwnedArg::BlockPos(p) => Arg::BlockPos(WitBlockPos {
|
||||||
|
x: p.0.x,
|
||||||
|
y: p.0.y,
|
||||||
|
z: p.0.z,
|
||||||
|
}),
|
||||||
OwnedArg::Pos3D(v) => Arg::Pos3d((v.x, v.y, v.z)),
|
OwnedArg::Pos3D(v) => Arg::Pos3d((v.x, v.y, v.z)),
|
||||||
OwnedArg::Pos2D(v) => Arg::Pos2d((v.x, v.y)),
|
OwnedArg::Pos2D(v) => Arg::Pos2d((v.x, v.y)),
|
||||||
OwnedArg::Rotation(a, b, c, d) => Arg::Rotation((a, b, c, d)),
|
OwnedArg::Rotation(a, b, c, d) => Arg::Rotation((a, b, c, d)),
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use wasmtime::component::Resource;
|
use wasmtime::component::Resource;
|
||||||
|
|
||||||
|
use pumpkin_util::math::vector3::Vector3;
|
||||||
|
|
||||||
use crate::plugin::loader::wasm::wasm_host::{
|
use crate::plugin::loader::wasm::wasm_host::{
|
||||||
state::{EntityResource, PluginHostState},
|
state::{EntityResource, PluginHostState},
|
||||||
wit::v0_1::events::to_wasm_position,
|
wit::v0_1::events::to_wasm_position,
|
||||||
@ -11,7 +13,8 @@ use crate::plugin::loader::wasm::wasm_host::{
|
|||||||
text::TextComponent,
|
text::TextComponent,
|
||||||
uuid::Uuid,
|
uuid::Uuid,
|
||||||
world::{
|
world::{
|
||||||
BlockPos as WitBlockPos, Entity, HostEntity, RaycastResult as WitRaycastResult, World,
|
BlockPos as WitBlockPos, BoundingBox as WitBoundingBox, Entity, HostEntity,
|
||||||
|
RaycastResult as WitRaycastResult, World,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wit::v0_1::uuid::UuidExt,
|
wit::v0_1::uuid::UuidExt,
|
||||||
@ -283,8 +286,9 @@ impl HostEntity for PluginHostState {
|
|||||||
let entity = entity_from_resource(self, &entity)?;
|
let entity = entity_from_resource(self, &entity)?;
|
||||||
Ok(entity
|
Ok(entity
|
||||||
.get_entity()
|
.get_entity()
|
||||||
.has_visual_fire
|
.fire_ticks
|
||||||
.load(std::sync::atomic::Ordering::Relaxed))
|
.load(std::sync::atomic::Ordering::Relaxed)
|
||||||
|
> 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn set_on_fire(
|
async fn set_on_fire(
|
||||||
@ -410,6 +414,370 @@ impl HostEntity for PluginHostState {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_health(&mut self, entity: Resource<Entity>) -> wasmtime::Result<f32> {
|
||||||
|
let entity = entity_from_resource(self, &entity)?;
|
||||||
|
Ok(entity
|
||||||
|
.get_living_entity()
|
||||||
|
.map_or(0.0, |living| living.health.load()))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn set_health(&mut self, entity: Resource<Entity>, health: f32) -> wasmtime::Result<()> {
|
||||||
|
let entity = entity_from_resource(self, &entity)?;
|
||||||
|
if let Some(living) = entity.get_living_entity() {
|
||||||
|
living.health.store(health);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_max_health(&mut self, entity: Resource<Entity>) -> wasmtime::Result<f32> {
|
||||||
|
let entity = entity_from_resource(self, &entity)?;
|
||||||
|
Ok(entity
|
||||||
|
.get_living_entity()
|
||||||
|
.map_or(0.0, crate::entity::living::LivingEntity::get_max_health))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn damage(&mut self, entity: Resource<Entity>, amount: f32) -> wasmtime::Result<()> {
|
||||||
|
let entity = entity_from_resource(self, &entity)?;
|
||||||
|
entity
|
||||||
|
.damage(&*entity, amount, pumpkin_data::damage::DamageType::GENERIC)
|
||||||
|
.await;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn is_dead(&mut self, entity: Resource<Entity>) -> wasmtime::Result<bool> {
|
||||||
|
let entity = entity_from_resource(self, &entity)?;
|
||||||
|
Ok(entity.get_living_entity().map_or_else(
|
||||||
|
|| entity.get_entity().removal_reason.load().is_some(),
|
||||||
|
|living| living.dead.load(std::sync::atomic::Ordering::Relaxed),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_absorption(&mut self, entity: Resource<Entity>) -> wasmtime::Result<f32> {
|
||||||
|
let entity = entity_from_resource(self, &entity)?;
|
||||||
|
Ok(entity
|
||||||
|
.get_living_entity()
|
||||||
|
.map_or(0.0, |living| living.absorption.load()))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn set_absorption(
|
||||||
|
&mut self,
|
||||||
|
entity: Resource<Entity>,
|
||||||
|
amount: f32,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
let entity = entity_from_resource(self, &entity)?;
|
||||||
|
if let Some(living) = entity.get_living_entity() {
|
||||||
|
living.absorption.store(amount);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_age(&mut self, entity: Resource<Entity>) -> wasmtime::Result<i32> {
|
||||||
|
let entity = entity_from_resource(self, &entity)?;
|
||||||
|
Ok(entity
|
||||||
|
.get_entity()
|
||||||
|
.age
|
||||||
|
.load(std::sync::atomic::Ordering::Relaxed))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn set_age(&mut self, entity: Resource<Entity>, age: i32) -> wasmtime::Result<()> {
|
||||||
|
let entity = entity_from_resource(self, &entity)?;
|
||||||
|
entity
|
||||||
|
.get_entity()
|
||||||
|
.age
|
||||||
|
.store(age, std::sync::atomic::Ordering::Relaxed);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_fall_distance(&mut self, entity: Resource<Entity>) -> wasmtime::Result<f32> {
|
||||||
|
let entity = entity_from_resource(self, &entity)?;
|
||||||
|
Ok(entity
|
||||||
|
.get_living_entity()
|
||||||
|
.map_or(0.0, |living| living.fall_distance.load()))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn set_fall_distance(
|
||||||
|
&mut self,
|
||||||
|
entity: Resource<Entity>,
|
||||||
|
distance: f32,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
let entity = entity_from_resource(self, &entity)?;
|
||||||
|
if let Some(living) = entity.get_living_entity() {
|
||||||
|
living.fall_distance.store(distance);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_eye_height(&mut self, entity: Resource<Entity>) -> wasmtime::Result<f32> {
|
||||||
|
let entity = entity_from_resource(self, &entity)?;
|
||||||
|
Ok(entity.get_entity().entity_dimension.load().eye_height)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_eye_position(&mut self, entity: Resource<Entity>) -> wasmtime::Result<Position> {
|
||||||
|
let entity = entity_from_resource(self, &entity)?;
|
||||||
|
Ok(to_wasm_position(entity.get_eye_pos()))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_nearby_entities(
|
||||||
|
&mut self,
|
||||||
|
entity: Resource<Entity>,
|
||||||
|
x: f64,
|
||||||
|
y: f64,
|
||||||
|
z: f64,
|
||||||
|
) -> wasmtime::Result<Vec<Resource<Entity>>> {
|
||||||
|
let entity = entity_from_resource(self, &entity)?;
|
||||||
|
let pos = entity.get_entity().pos.load();
|
||||||
|
let box_range = pumpkin_util::math::boundingbox::BoundingBox::new(
|
||||||
|
Vector3::new(pos.x - x, pos.y - y, pos.z - z),
|
||||||
|
Vector3::new(pos.x + x, pos.y + y, pos.z + z),
|
||||||
|
);
|
||||||
|
let world = entity.get_entity().world.load_full();
|
||||||
|
let entities = world.get_entities_at_box(&box_range);
|
||||||
|
|
||||||
|
let mut result = Vec::new();
|
||||||
|
for e in entities {
|
||||||
|
// Don't include the entity itself
|
||||||
|
if e.get_entity().entity_id != entity.get_entity().entity_id {
|
||||||
|
result.push(
|
||||||
|
self.add_entity(e)
|
||||||
|
.map_err(|_| wasmtime::Error::msg("failed to add entity resource"))?,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_vehicle(
|
||||||
|
&mut self,
|
||||||
|
entity: Resource<Entity>,
|
||||||
|
) -> wasmtime::Result<Option<Resource<Entity>>> {
|
||||||
|
let entity = entity_from_resource(self, &entity)?;
|
||||||
|
let vehicle = entity.get_entity().vehicle.lock().await;
|
||||||
|
if let Some(v) = vehicle.as_ref() {
|
||||||
|
Ok(Some(self.add_entity(Arc::clone(v)).map_err(|_| {
|
||||||
|
wasmtime::Error::msg("failed to add entity resource")
|
||||||
|
})?))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_passengers(
|
||||||
|
&mut self,
|
||||||
|
entity: Resource<Entity>,
|
||||||
|
) -> wasmtime::Result<Vec<Resource<Entity>>> {
|
||||||
|
let entity = entity_from_resource(self, &entity)?;
|
||||||
|
let passengers = entity.get_entity().passengers.lock().await;
|
||||||
|
let mut result = Vec::new();
|
||||||
|
for p in passengers.iter() {
|
||||||
|
result.push(
|
||||||
|
self.add_entity(Arc::clone(p))
|
||||||
|
.map_err(|_| wasmtime::Error::msg("failed to add entity resource"))?,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn add_passenger(
|
||||||
|
&mut self,
|
||||||
|
entity: Resource<Entity>,
|
||||||
|
passenger: Resource<Entity>,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
let entity = entity_from_resource(self, &entity)?;
|
||||||
|
let passenger = entity_from_resource(self, &passenger)?;
|
||||||
|
entity
|
||||||
|
.get_entity()
|
||||||
|
.add_passenger(Arc::clone(&entity), passenger)
|
||||||
|
.await;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn remove_passenger(
|
||||||
|
&mut self,
|
||||||
|
entity: Resource<Entity>,
|
||||||
|
passenger: Resource<Entity>,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
let entity = entity_from_resource(self, &entity)?;
|
||||||
|
let passenger = entity_from_resource(self, &passenger)?;
|
||||||
|
entity
|
||||||
|
.get_entity()
|
||||||
|
.remove_passenger(passenger.get_entity().entity_id)
|
||||||
|
.await;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn eject_passengers(&mut self, entity: Resource<Entity>) -> wasmtime::Result<()> {
|
||||||
|
let entity = entity_from_resource(self, &entity)?;
|
||||||
|
let ids: Vec<i32> = entity
|
||||||
|
.get_entity()
|
||||||
|
.passengers
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.iter()
|
||||||
|
.map(|p| p.get_entity().entity_id)
|
||||||
|
.collect();
|
||||||
|
for id in ids {
|
||||||
|
entity.get_entity().remove_passenger(id).await;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_bounding_box(
|
||||||
|
&mut self,
|
||||||
|
entity: Resource<Entity>,
|
||||||
|
) -> wasmtime::Result<WitBoundingBox> {
|
||||||
|
let entity = entity_from_resource(self, &entity)?;
|
||||||
|
let bb = entity.get_entity().bounding_box.load();
|
||||||
|
Ok(WitBoundingBox {
|
||||||
|
min: to_wasm_position(bb.min),
|
||||||
|
max: to_wasm_position(bb.max),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn is_in_water(&mut self, entity: Resource<Entity>) -> wasmtime::Result<bool> {
|
||||||
|
let entity = entity_from_resource(self, &entity)?;
|
||||||
|
Ok(entity
|
||||||
|
.get_entity()
|
||||||
|
.touching_water
|
||||||
|
.load(std::sync::atomic::Ordering::Relaxed))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn is_in_lava(&mut self, entity: Resource<Entity>) -> wasmtime::Result<bool> {
|
||||||
|
let entity = entity_from_resource(self, &entity)?;
|
||||||
|
Ok(entity
|
||||||
|
.get_entity()
|
||||||
|
.touching_lava
|
||||||
|
.load(std::sync::atomic::Ordering::Relaxed))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_ticks_lived(&mut self, entity: Resource<Entity>) -> wasmtime::Result<i32> {
|
||||||
|
let entity = entity_from_resource(self, &entity)?;
|
||||||
|
Ok(entity
|
||||||
|
.get_entity()
|
||||||
|
.age
|
||||||
|
.load(std::sync::atomic::Ordering::Relaxed))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn set_ticks_lived(
|
||||||
|
&mut self,
|
||||||
|
entity: Resource<Entity>,
|
||||||
|
ticks: i32,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
let entity = entity_from_resource(self, &entity)?;
|
||||||
|
entity
|
||||||
|
.get_entity()
|
||||||
|
.age
|
||||||
|
.store(ticks, std::sync::atomic::Ordering::Relaxed);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_width(&mut self, entity: Resource<Entity>) -> wasmtime::Result<f32> {
|
||||||
|
let entity = entity_from_resource(self, &entity)?;
|
||||||
|
Ok(entity.get_entity().entity_dimension.load().width)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_height(&mut self, entity: Resource<Entity>) -> wasmtime::Result<f32> {
|
||||||
|
let entity = entity_from_resource(self, &entity)?;
|
||||||
|
Ok(entity.get_entity().entity_dimension.load().height)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn set_rotation(
|
||||||
|
&mut self,
|
||||||
|
entity: Resource<Entity>,
|
||||||
|
yaw: f32,
|
||||||
|
pitch: f32,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
let entity = entity_from_resource(self, &entity)?;
|
||||||
|
entity.get_entity().set_rotation(yaw, pitch);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn has_visual_fire(&mut self, entity: Resource<Entity>) -> wasmtime::Result<bool> {
|
||||||
|
let entity = entity_from_resource(self, &entity)?;
|
||||||
|
Ok(entity
|
||||||
|
.get_entity()
|
||||||
|
.has_visual_fire
|
||||||
|
.load(std::sync::atomic::Ordering::Relaxed))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn set_visual_fire(
|
||||||
|
&mut self,
|
||||||
|
entity: Resource<Entity>,
|
||||||
|
visual_fire: bool,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
let entity = entity_from_resource(self, &entity)?;
|
||||||
|
entity.get_entity().set_on_fire(visual_fire).await;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_portal_cooldown(&mut self, entity: Resource<Entity>) -> wasmtime::Result<u32> {
|
||||||
|
let entity = entity_from_resource(self, &entity)?;
|
||||||
|
Ok(entity
|
||||||
|
.get_entity()
|
||||||
|
.portal_cooldown
|
||||||
|
.load(std::sync::atomic::Ordering::Relaxed))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn set_portal_cooldown(
|
||||||
|
&mut self,
|
||||||
|
entity: Resource<Entity>,
|
||||||
|
cooldown: u32,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
let entity = entity_from_resource(self, &entity)?;
|
||||||
|
entity
|
||||||
|
.get_entity()
|
||||||
|
.portal_cooldown
|
||||||
|
.store(cooldown, std::sync::atomic::Ordering::Relaxed);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_remaining_air(&mut self, entity: Resource<Entity>) -> wasmtime::Result<i32> {
|
||||||
|
let entity = entity_from_resource(self, &entity)?;
|
||||||
|
Ok(entity.get_player().map_or(0, |player| {
|
||||||
|
player
|
||||||
|
.breath_manager
|
||||||
|
.air_supply
|
||||||
|
.load(std::sync::atomic::Ordering::Relaxed)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn set_remaining_air(
|
||||||
|
&mut self,
|
||||||
|
entity: Resource<Entity>,
|
||||||
|
air: i32,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
let entity = entity_from_resource(self, &entity)?;
|
||||||
|
if let Some(player) = entity.get_player() {
|
||||||
|
player
|
||||||
|
.breath_manager
|
||||||
|
.air_supply
|
||||||
|
.store(air, std::sync::atomic::Ordering::Relaxed);
|
||||||
|
player.breath_manager.send_air_supply(player);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_max_air(&mut self, _entity: Resource<Entity>) -> wasmtime::Result<i32> {
|
||||||
|
Ok(crate::entity::breath::MAX_AIR)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn send_system_message(
|
||||||
|
&mut self,
|
||||||
|
entity: Resource<Entity>,
|
||||||
|
message: Resource<TextComponent>,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
let entity = entity_from_resource(self, &entity)?;
|
||||||
|
if let Some(player) = entity.get_player() {
|
||||||
|
let text_res = self
|
||||||
|
.resource_table
|
||||||
|
.get::<crate::plugin::loader::wasm::wasm_host::state::TextComponentResource>(
|
||||||
|
&Resource::new_own(message.rep()),
|
||||||
|
)
|
||||||
|
.map_err(|_| wasmtime::Error::msg("invalid text component resource handle"))?;
|
||||||
|
player.send_system_message(&text_res.provider).await;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
async fn remove(&mut self, entity: Resource<Entity>) -> wasmtime::Result<()> {
|
async fn remove(&mut self, entity: Resource<Entity>) -> wasmtime::Result<()> {
|
||||||
let entity = entity_from_resource(self, &entity)?;
|
let entity = entity_from_resource(self, &entity)?;
|
||||||
entity.get_entity().remove().await;
|
entity.get_entity().remove().await;
|
||||||
|
|||||||
@ -28,7 +28,7 @@ impl ToFromWasmEvent for BlockRedstoneEvent {
|
|||||||
Event::BlockRedstoneEvent(BlockRedstoneEventData {
|
Event::BlockRedstoneEvent(BlockRedstoneEventData {
|
||||||
target_world,
|
target_world,
|
||||||
state_id: self.block_state_id,
|
state_id: self.block_state_id,
|
||||||
block_position: to_wasm_block_position(self.block_pos),
|
block_pos: to_wasm_block_position(self.block_pos),
|
||||||
old_current: self.old_current,
|
old_current: self.old_current,
|
||||||
new_current: self.new_current,
|
new_current: self.new_current,
|
||||||
cancelled: self.cancelled,
|
cancelled: self.cancelled,
|
||||||
@ -40,7 +40,7 @@ impl ToFromWasmEvent for BlockRedstoneEvent {
|
|||||||
Event::BlockRedstoneEvent(data) => Self {
|
Event::BlockRedstoneEvent(data) => Self {
|
||||||
world: consume_world(state, &data.target_world),
|
world: consume_world(state, &data.target_world),
|
||||||
block_state_id: data.state_id,
|
block_state_id: data.state_id,
|
||||||
block_pos: from_wasm_block_position(data.block_position),
|
block_pos: from_wasm_block_position(data.block_pos),
|
||||||
old_current: data.old_current,
|
old_current: data.old_current,
|
||||||
new_current: data.new_current,
|
new_current: data.new_current,
|
||||||
cancelled: data.cancelled,
|
cancelled: data.cancelled,
|
||||||
@ -61,7 +61,7 @@ impl ToFromWasmEvent for BlockBreakEvent {
|
|||||||
Event::BlockBreakEvent(BlockBreakEventData {
|
Event::BlockBreakEvent(BlockBreakEventData {
|
||||||
player,
|
player,
|
||||||
block: to_wasm_block_name(self.block),
|
block: to_wasm_block_name(self.block),
|
||||||
block_position: to_wasm_block_position(self.block_position),
|
block_pos: to_wasm_block_position(self.block_position),
|
||||||
exp: self.exp,
|
exp: self.exp,
|
||||||
should_drop: self.drop,
|
should_drop: self.drop,
|
||||||
cancelled: self.cancelled,
|
cancelled: self.cancelled,
|
||||||
@ -73,7 +73,7 @@ impl ToFromWasmEvent for BlockBreakEvent {
|
|||||||
Event::BlockBreakEvent(data) => Self {
|
Event::BlockBreakEvent(data) => Self {
|
||||||
player: data.player.map(|player| consume_player(state, &player)),
|
player: data.player.map(|player| consume_player(state, &player)),
|
||||||
block: from_wasm_block_name(&data.block),
|
block: from_wasm_block_name(&data.block),
|
||||||
block_position: from_wasm_block_position(data.block_position),
|
block_position: from_wasm_block_position(data.block_pos),
|
||||||
exp: data.exp,
|
exp: data.exp,
|
||||||
drop: data.should_drop,
|
drop: data.should_drop,
|
||||||
cancelled: data.cancelled,
|
cancelled: data.cancelled,
|
||||||
@ -145,7 +145,7 @@ impl ToFromWasmEvent for BlockGrowEvent {
|
|||||||
old_state_id: self.old_state_id,
|
old_state_id: self.old_state_id,
|
||||||
new_block: to_wasm_block_name(self.new_block),
|
new_block: to_wasm_block_name(self.new_block),
|
||||||
new_state_id: self.new_state_id,
|
new_state_id: self.new_state_id,
|
||||||
block_position: to_wasm_block_position(self.block_pos),
|
block_pos: to_wasm_block_position(self.block_pos),
|
||||||
cancelled: self.cancelled,
|
cancelled: self.cancelled,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -158,7 +158,7 @@ impl ToFromWasmEvent for BlockGrowEvent {
|
|||||||
old_state_id: data.old_state_id,
|
old_state_id: data.old_state_id,
|
||||||
new_block: from_wasm_block_name(&data.new_block),
|
new_block: from_wasm_block_name(&data.new_block),
|
||||||
new_state_id: data.new_state_id,
|
new_state_id: data.new_state_id,
|
||||||
block_pos: from_wasm_block_position(data.block_position),
|
block_pos: from_wasm_block_position(data.block_pos),
|
||||||
cancelled: data.cancelled,
|
cancelled: data.cancelled,
|
||||||
},
|
},
|
||||||
_ => panic!("unexpected event type"),
|
_ => panic!("unexpected event type"),
|
||||||
@ -176,7 +176,7 @@ impl ToFromWasmEvent for BlockPlaceEvent {
|
|||||||
player,
|
player,
|
||||||
block_placed: to_wasm_block_name(self.block_placed),
|
block_placed: to_wasm_block_name(self.block_placed),
|
||||||
block_placed_against: to_wasm_block_name(self.block_placed_against),
|
block_placed_against: to_wasm_block_name(self.block_placed_against),
|
||||||
block_position: to_wasm_block_position(self.block_position),
|
block_pos: to_wasm_block_position(self.block_position),
|
||||||
can_build: self.can_build,
|
can_build: self.can_build,
|
||||||
cancelled: self.cancelled,
|
cancelled: self.cancelled,
|
||||||
})
|
})
|
||||||
@ -188,7 +188,7 @@ impl ToFromWasmEvent for BlockPlaceEvent {
|
|||||||
player: consume_player(state, &data.player),
|
player: consume_player(state, &data.player),
|
||||||
block_placed: from_wasm_block_name(&data.block_placed),
|
block_placed: from_wasm_block_name(&data.block_placed),
|
||||||
block_placed_against: from_wasm_block_name(&data.block_placed_against),
|
block_placed_against: from_wasm_block_name(&data.block_placed_against),
|
||||||
block_position: from_wasm_block_position(data.block_position),
|
block_position: from_wasm_block_position(data.block_pos),
|
||||||
can_build: data.can_build,
|
can_build: data.can_build,
|
||||||
cancelled: data.cancelled,
|
cancelled: data.cancelled,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -59,14 +59,18 @@ pub(super) const fn from_wasm_position(
|
|||||||
|
|
||||||
pub(super) const fn to_wasm_block_position(
|
pub(super) const fn to_wasm_block_position(
|
||||||
position: BlockPos,
|
position: BlockPos,
|
||||||
) -> pumpkin::plugin::common::BlockPosition {
|
) -> pumpkin::plugin::common::BlockPos {
|
||||||
(position.0.x, position.0.y, position.0.z)
|
pumpkin::plugin::common::BlockPos {
|
||||||
|
x: position.0.x,
|
||||||
|
y: position.0.y,
|
||||||
|
z: position.0.z,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) const fn from_wasm_block_position(
|
pub(super) const fn from_wasm_block_position(
|
||||||
position: pumpkin::plugin::common::BlockPosition,
|
position: pumpkin::plugin::common::BlockPos,
|
||||||
) -> BlockPos {
|
) -> BlockPos {
|
||||||
BlockPos::new(position.0, position.1, position.2)
|
BlockPos::new(position.x, position.y, position.z)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn to_wasm_block_name(block: &'static Block) -> String {
|
pub(super) fn to_wasm_block_name(block: &'static Block) -> String {
|
||||||
|
|||||||
@ -5,10 +5,11 @@ use crate::plugin::{
|
|||||||
wit::v0_1::{
|
wit::v0_1::{
|
||||||
events::{
|
events::{
|
||||||
ToFromWasmEvent, consume_player, consume_text_component, consume_world,
|
ToFromWasmEvent, consume_player, consume_text_component, consume_world,
|
||||||
from_wasm_click_type, from_wasm_entity_interaction_action, from_wasm_entity_type,
|
from_wasm_block_name, from_wasm_block_position, from_wasm_click_type,
|
||||||
from_wasm_game_mode, from_wasm_hand, from_wasm_position, to_wasm_block_position,
|
from_wasm_entity_interaction_action, from_wasm_entity_type, from_wasm_game_mode,
|
||||||
to_wasm_click_type, to_wasm_entity_interaction_action, to_wasm_entity_type,
|
from_wasm_hand, from_wasm_position, to_wasm_block_position, to_wasm_click_type,
|
||||||
to_wasm_game_mode, to_wasm_hand, to_wasm_position,
|
to_wasm_entity_interaction_action, to_wasm_entity_type, to_wasm_game_mode,
|
||||||
|
to_wasm_hand, to_wasm_position,
|
||||||
},
|
},
|
||||||
pumpkin::plugin::event::{
|
pumpkin::plugin::event::{
|
||||||
BedrockFormResponseEventData, CustomClickActionEventData, Event,
|
BedrockFormResponseEventData, CustomClickActionEventData, Event,
|
||||||
@ -647,6 +648,15 @@ const fn to_wasm_interact_action(action: &InteractAction) -> WasmInteractAction
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fn from_wasm_interact_action(action: WasmInteractAction) -> InteractAction {
|
||||||
|
match action {
|
||||||
|
WasmInteractAction::LeftClickBlock => InteractAction::LeftClickBlock,
|
||||||
|
WasmInteractAction::LeftClickAir => InteractAction::LeftClickAir,
|
||||||
|
WasmInteractAction::RightClickAir => InteractAction::RightClickAir,
|
||||||
|
WasmInteractAction::RightClickBlock => InteractAction::RightClickBlock,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ToFromWasmEvent for PlayerInteractEvent {
|
impl ToFromWasmEvent for PlayerInteractEvent {
|
||||||
fn to_wasm_event(&self, state: &mut PluginHostState) -> Event {
|
fn to_wasm_event(&self, state: &mut PluginHostState) -> Event {
|
||||||
let player = state
|
let player = state
|
||||||
@ -662,11 +672,15 @@ impl ToFromWasmEvent for PlayerInteractEvent {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_wasm_event(event: Event, _state: &mut PluginHostState) -> Self {
|
fn from_wasm_event(event: Event, state: &mut PluginHostState) -> Self {
|
||||||
match event {
|
match event {
|
||||||
Event::PlayerInteractEvent(_data) => {
|
Event::PlayerInteractEvent(data) => Self {
|
||||||
panic!("from_wasm_event for PlayerInteractEvent is not supported")
|
player: consume_player(state, &data.player),
|
||||||
}
|
action: from_wasm_interact_action(data.action),
|
||||||
|
clicked_pos: data.clicked_pos.map(from_wasm_block_position),
|
||||||
|
block: from_wasm_block_name(&data.block),
|
||||||
|
cancelled: data.cancelled,
|
||||||
|
},
|
||||||
_ => panic!("unexpected event type"),
|
_ => panic!("unexpected event type"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,9 +6,14 @@ use pumpkin_world::world::BlockFlags;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use wasmtime::component::Resource;
|
use wasmtime::component::Resource;
|
||||||
|
|
||||||
|
use crate::block::entities::chest::ChestBlockEntity as InternalChestBlockEntity;
|
||||||
|
use crate::block::entities::command_block::CommandBlockEntity as InternalCommandBlockEntity;
|
||||||
|
use crate::block::entities::jukebox::JukeboxBlockEntity as InternalJukeboxBlockEntity;
|
||||||
|
use crate::block::entities::mob_spawner::MobSpawnerBlockEntity as InternalMobSpawnerBlockEntity;
|
||||||
|
use crate::block::entities::sign::SignBlockEntity as InternalSignBlockEntity;
|
||||||
use crate::plugin::loader::wasm::wasm_host::wit::v0_1::pumpkin::plugin::world::{
|
use crate::plugin::loader::wasm::wasm_host::wit::v0_1::pumpkin::plugin::world::{
|
||||||
BlockDirection as WitBlockDirection, BlockFlags as WitBlockFlags, BlockPos as WitBlockPos,
|
BlockDirection as WitBlockDirection, BlockEntity, BlockEntityType, BlockFlags as WitBlockFlags,
|
||||||
BlockState as WitBlockState, PistonBehavior as WitPistonBehavior,
|
BlockPos as WitBlockPos, BlockState as WitBlockState, PistonBehavior as WitPistonBehavior,
|
||||||
};
|
};
|
||||||
use crate::plugin::loader::wasm::wasm_host::{
|
use crate::plugin::loader::wasm::wasm_host::{
|
||||||
state::{PluginHostState, TextComponentResource, WorldResource},
|
state::{PluginHostState, TextComponentResource, WorldResource},
|
||||||
@ -486,6 +491,69 @@ impl pumpkin::plugin::world::HostWorld for PluginHostState {
|
|||||||
Ok(entities)
|
Ok(entities)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_block_entity(
|
||||||
|
&mut self,
|
||||||
|
world: Resource<World>,
|
||||||
|
pos: WitBlockPos,
|
||||||
|
) -> wasmtime::Result<Option<BlockEntityType>> {
|
||||||
|
let world_provider = self.get_world_res(&world)?.provider.clone();
|
||||||
|
let internal_pos = BlockPos::new(pos.x, pos.y, pos.z);
|
||||||
|
let block_entity = world_provider.get_block_entity(&internal_pos);
|
||||||
|
|
||||||
|
if let Some(be) = block_entity {
|
||||||
|
if be
|
||||||
|
.as_any()
|
||||||
|
.downcast_ref::<InternalCommandBlockEntity>()
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
|
let res: Resource<BlockEntity> = self.add_block_entity(be)?;
|
||||||
|
Ok(Some(BlockEntityType::CommandBlockEntity(
|
||||||
|
Resource::new_own(res.rep()),
|
||||||
|
)))
|
||||||
|
} else if be
|
||||||
|
.as_any()
|
||||||
|
.downcast_ref::<InternalSignBlockEntity>()
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
|
let res: Resource<BlockEntity> = self.add_block_entity(be)?;
|
||||||
|
Ok(Some(BlockEntityType::SignBlockEntity(Resource::new_own(
|
||||||
|
res.rep(),
|
||||||
|
))))
|
||||||
|
} else if be
|
||||||
|
.as_any()
|
||||||
|
.downcast_ref::<InternalJukeboxBlockEntity>()
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
|
let res: Resource<BlockEntity> = self.add_block_entity(be)?;
|
||||||
|
Ok(Some(BlockEntityType::JukeboxBlockEntity(
|
||||||
|
Resource::new_own(res.rep()),
|
||||||
|
)))
|
||||||
|
} else if be
|
||||||
|
.as_any()
|
||||||
|
.downcast_ref::<InternalChestBlockEntity>()
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
|
let res: Resource<BlockEntity> = self.add_block_entity(be)?;
|
||||||
|
Ok(Some(BlockEntityType::ChestBlockEntity(Resource::new_own(
|
||||||
|
res.rep(),
|
||||||
|
))))
|
||||||
|
} else if be
|
||||||
|
.as_any()
|
||||||
|
.downcast_ref::<InternalMobSpawnerBlockEntity>()
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
|
let res: Resource<BlockEntity> = self.add_block_entity(be)?;
|
||||||
|
Ok(Some(BlockEntityType::MobSpawnerBlockEntity(
|
||||||
|
Resource::new_own(res.rep()),
|
||||||
|
)))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async fn drop(&mut self, rep: Resource<World>) -> wasmtime::Result<()> {
|
async fn drop(&mut self, rep: Resource<World>) -> wasmtime::Result<()> {
|
||||||
self.resource_table
|
self.resource_table
|
||||||
.delete::<WorldResource>(Resource::new_own(rep.rep()))
|
.delete::<WorldResource>(Resource::new_own(rep.rep()))
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user