feat(plugin-api): use trappable
This commit is contained in:
parent
8b418813f8
commit
45ed583312
@ -98,7 +98,7 @@ interface command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
variant command-sender-type {
|
variant command-sender-type {
|
||||||
rcon(list<string>),
|
rcon,
|
||||||
console,
|
console,
|
||||||
player(player),
|
player(player),
|
||||||
command-block(tuple<command-block-entity, %world>),
|
command-block(tuple<command-block-entity, %world>),
|
||||||
|
|||||||
@ -15,79 +15,79 @@ interface player {
|
|||||||
}
|
}
|
||||||
|
|
||||||
resource player {
|
resource player {
|
||||||
get-id: func () -> result<string, string>;
|
get-id: func () -> string;
|
||||||
get-name: func () -> result<string, string>;
|
get-name: func () -> string;
|
||||||
|
|
||||||
// Basic state
|
// Basic state
|
||||||
get-position: func () -> result<position, string>;
|
get-position: func () -> position;
|
||||||
get-rotation: func () -> result<tuple<f32, f32>, string>;
|
get-rotation: func () -> tuple<f32, f32>;
|
||||||
get-world: func () -> result<%world, string>;
|
get-world: func () -> %world;
|
||||||
get-gamemode: func () -> result<game-mode, string>;
|
get-gamemode: func () -> game-mode;
|
||||||
set-gamemode: func (mode: game-mode) -> result<bool, string>;
|
set-gamemode: func (mode: game-mode) -> bool;
|
||||||
get-locale: func () -> result<string, string>;
|
get-locale: func () -> string;
|
||||||
get-ping: func () -> result<u32, string>;
|
get-ping: func () -> u32;
|
||||||
|
|
||||||
// Permissions & metadata
|
// Permissions & metadata
|
||||||
get-permission-level: func () -> result<permission-level, string>;
|
get-permission-level: func () -> permission-level;
|
||||||
set-permission-level: func (level: permission-level) -> result<_, string>;
|
set-permission-level: func (level: permission-level);
|
||||||
has-permission: func (node: string) -> result<bool, string>;
|
has-permission: func (node: string) -> bool;
|
||||||
get-display-name: func () -> result<text-component, string>;
|
get-display-name: func () -> text-component;
|
||||||
|
|
||||||
// Messaging & titles
|
// Messaging & titles
|
||||||
send-system-message: func (text: text-component, overlay: bool) -> result<_, string>;
|
send-system-message: func (text: text-component, overlay: bool);
|
||||||
show-title: func (text: text-component) -> result<_, string>;
|
show-title: func (text: text-component);
|
||||||
show-subtitle: func (text: text-component) -> result<_, string>;
|
show-subtitle: func (text: text-component);
|
||||||
show-actionbar: func (text: text-component) -> result<_, string>;
|
show-actionbar: func (text: text-component);
|
||||||
send-title-animation: func (fade-in: s32, stay: s32, fade-out: s32) -> result<_, string>;
|
send-title-animation: func (fade-in: s32, stay: s32, fade-out: s32);
|
||||||
|
|
||||||
// Teleport & kick
|
// Teleport & kick
|
||||||
teleport: func (position: position, yaw: f32, pitch: f32) -> result<_, string>;
|
teleport: func (position: position, yaw: f32, pitch: f32);
|
||||||
teleport-world: func (world-ref: %world, position: position, yaw: option<f32>, pitch: option<f32>) -> result<_, string>;
|
teleport-world: func (world-ref: %world, position: position, yaw: option<f32>, pitch: option<f32>);
|
||||||
kick: func (message: text-component) -> result<_, string>;
|
kick: func (message: text-component);
|
||||||
respawn: func () -> result<_, string>;
|
respawn: func ();
|
||||||
|
|
||||||
ban: func (reason: option<text-component>) -> result<_, string>;
|
ban: func (reason: option<text-component>);
|
||||||
ban-ip: func (reason: option<text-component>) -> result<_, string>;
|
ban-ip: func (reason: option<text-component>);
|
||||||
|
|
||||||
// Inventory
|
// Inventory
|
||||||
get-selected-slot: func () -> result<u8, string>;
|
get-selected-slot: func () -> u8;
|
||||||
get-item-in-hand: func (hand: hand) -> result<option<item-stack>, string>;
|
get-item-in-hand: func (hand: hand) -> option<item-stack>;
|
||||||
get-inventory-item: func (slot: u8) -> result<option<item-stack>, string>;
|
get-inventory-item: func (slot: u8) -> option<item-stack>;
|
||||||
|
|
||||||
// Status
|
// Status
|
||||||
get-health: func () -> result<f32, string>;
|
get-health: func () -> f32;
|
||||||
set-health: func (health: f32) -> result<_, string>;
|
set-health: func (health: f32);
|
||||||
get-max-health: func () -> result<f32, string>;
|
get-max-health: func () -> f32;
|
||||||
set-max-health: func (max-health: f32) -> result<_, string>;
|
set-max-health: func (max-health: f32);
|
||||||
get-food-level: func () -> result<u8, string>;
|
get-food-level: func () -> u8;
|
||||||
set-food-level: func (food-level: u8) -> result<_, string>;
|
set-food-level: func (food-level: u8);
|
||||||
get-saturation: func () -> result<f32, string>;
|
get-saturation: func () -> f32;
|
||||||
set-saturation: func (saturation: f32) -> result<_, string>;
|
set-saturation: func (saturation: f32);
|
||||||
get-exhaustion: func () -> result<f32, string>;
|
get-exhaustion: func () -> f32;
|
||||||
set-exhaustion: func (exhaustion: f32) -> result<_, string>;
|
set-exhaustion: func (exhaustion: f32);
|
||||||
get-absorption: func () -> result<f32, string>;
|
get-absorption: func () -> f32;
|
||||||
set-absorption: func (absorption: f32) -> result<_, string>;
|
set-absorption: func (absorption: f32);
|
||||||
|
|
||||||
get-experience-level: func() -> result<s32, string>;
|
get-experience-level: func() -> s32;
|
||||||
get-experience-progress: func() -> result<f32, string>;
|
get-experience-progress: func() -> f32;
|
||||||
get-experience-points: func() -> result<s32, string>;
|
get-experience-points: func() -> s32;
|
||||||
set-experience-level: func(level: s32) -> result<_, string>;
|
set-experience-level: func(level: s32);
|
||||||
set-experience-progress: func(progress: f32) -> result<_, string>;
|
set-experience-progress: func(progress: f32);
|
||||||
set-experience-points: func(points: s32) -> result<_, string>;
|
set-experience-points: func(points: s32);
|
||||||
add-experience-levels: func(levels: s32) -> result<_, string>;
|
add-experience-levels: func(levels: s32);
|
||||||
add-experience-points: func(points: s32) -> result<_, string>;
|
add-experience-points: func(points: s32);
|
||||||
|
|
||||||
is-sneaking: func() -> result<bool, string>;
|
is-sneaking: func() -> bool;
|
||||||
set-sneaking: func(sneaking: bool) -> result<_, string>;
|
set-sneaking: func(sneaking: bool);
|
||||||
is-sprinting: func() -> result<bool, string>;
|
is-sprinting: func() -> bool;
|
||||||
set-sprinting: func(sprinting: bool) -> result<_, string>;
|
set-sprinting: func(sprinting: bool);
|
||||||
is-on-ground: func() -> result<bool, string>;
|
is-on-ground: func() -> bool;
|
||||||
is-flying: func() -> result<bool, string>;
|
is-flying: func() -> bool;
|
||||||
set-flying: func(flying: bool) -> result<_, string>;
|
set-flying: func(flying: bool);
|
||||||
|
|
||||||
get-abilities: func() -> result<player-abilities, string>;
|
get-abilities: func() -> player-abilities;
|
||||||
set-abilities: func(abilities: player-abilities) -> result<_, string>;
|
set-abilities: func(abilities: player-abilities);
|
||||||
|
|
||||||
get-ip: func() -> result<string, string>;
|
get-ip: func() -> string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@ -125,6 +125,21 @@ async fn register_player_event(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PluginHostState {
|
||||||
|
fn get_context(&self, res: &Resource<Context>) -> wasmtime::Result<&ContextResource> {
|
||||||
|
self.resource_table
|
||||||
|
.get::<ContextResource>(&Resource::new_own(res.rep()))
|
||||||
|
.map_err(wasmtime::Error::from)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn take_command(&mut self, res: &Resource<Command>) -> wasmtime::Result<CommandResource> {
|
||||||
|
self.resource_table
|
||||||
|
.delete::<CommandResource>(Resource::new_own(res.rep()))
|
||||||
|
// Convert ResourceTableError -> wasmtime::Error
|
||||||
|
.map_err(wasmtime::Error::from)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async fn register_world_event(
|
async fn register_world_event(
|
||||||
resource: &ContextResource,
|
resource: &ContextResource,
|
||||||
handler: &Arc<WasmPluginV0_1_0EventHandler>,
|
handler: &Arc<WasmPluginV0_1_0EventHandler>,
|
||||||
@ -237,7 +252,8 @@ impl pumpkin::plugin::context::HostContext for PluginHostState {
|
|||||||
event_type: EventType,
|
event_type: EventType,
|
||||||
event_priority: EventPriority,
|
event_priority: EventPriority,
|
||||||
blocking: bool,
|
blocking: bool,
|
||||||
) {
|
) -> wasmtime::Result<()> {
|
||||||
|
// Updated return type
|
||||||
let priority = match event_priority {
|
let priority = match event_priority {
|
||||||
EventPriority::Highest => crate::plugin::EventPriority::Highest,
|
EventPriority::Highest => crate::plugin::EventPriority::Highest,
|
||||||
EventPriority::High => crate::plugin::EventPriority::High,
|
EventPriority::High => crate::plugin::EventPriority::High,
|
||||||
@ -246,14 +262,15 @@ impl pumpkin::plugin::context::HostContext for PluginHostState {
|
|||||||
EventPriority::Lowest => crate::plugin::EventPriority::Lowest,
|
EventPriority::Lowest => crate::plugin::EventPriority::Lowest,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Use ? to trap if the plugin was dropped or the context handle is dead
|
||||||
let plugin = self
|
let plugin = self
|
||||||
.plugin
|
.plugin
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.expect("plugin should always be initialized here")
|
.ok_or_else(|| wasmtime::Error::msg("Plugin state uninitialized"))?
|
||||||
.upgrade()
|
.upgrade()
|
||||||
.expect("plugin has been dropped");
|
.ok_or_else(|| wasmtime::Error::msg("Plugin has been dropped"))?;
|
||||||
|
|
||||||
let resource = context.downcast_ref(self);
|
let resource = self.get_context(&context)?;
|
||||||
let handler = Arc::new(WasmPluginV0_1_0EventHandler { handler_id, plugin });
|
let handler = Arc::new(WasmPluginV0_1_0EventHandler { handler_id, plugin });
|
||||||
|
|
||||||
match event_type {
|
match event_type {
|
||||||
@ -275,6 +292,8 @@ impl pumpkin::plugin::context::HostContext for PluginHostState {
|
|||||||
register_player_event(resource, &handler, priority, blocking, event_type).await;
|
register_player_event(resource, &handler, priority, blocking, event_type).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn register_command(
|
async fn register_command(
|
||||||
@ -282,44 +301,37 @@ impl pumpkin::plugin::context::HostContext for PluginHostState {
|
|||||||
context: Resource<Context>,
|
context: Resource<Context>,
|
||||||
command: Resource<Command>,
|
command: Resource<Command>,
|
||||||
permission: String,
|
permission: String,
|
||||||
) {
|
) -> wasmtime::Result<()> {
|
||||||
let command = self
|
// Updated return type
|
||||||
.resource_table
|
// Use your helpers to safely take/get resources
|
||||||
.delete::<CommandResource>(Resource::new_own(command.rep()))
|
let command_res = self.take_command(&command)?;
|
||||||
.expect("invalid command resource handle")
|
let context_res = self.get_context(&context)?;
|
||||||
.provider;
|
|
||||||
|
|
||||||
let context_resource = self
|
context_res
|
||||||
.resource_table
|
|
||||||
.get_any_mut(context.rep())
|
|
||||||
.expect("invalid context resource handle")
|
|
||||||
.downcast_ref::<ContextResource>()
|
|
||||||
.expect("resource type mismatch");
|
|
||||||
|
|
||||||
context_resource
|
|
||||||
.provider
|
.provider
|
||||||
.register_command(command, permission)
|
.register_command(command_res.provider, permission)
|
||||||
.await;
|
.await;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn register_permission(
|
async fn register_permission(
|
||||||
&mut self,
|
&mut self,
|
||||||
context: Resource<Context>,
|
context: Resource<Context>,
|
||||||
permission: Permission,
|
permission: Permission,
|
||||||
) -> Result<(), String> {
|
) -> wasmtime::Result<Result<(), String>> {
|
||||||
let mut children: HashMap<String, bool> = HashMap::with_capacity(permission.children.len());
|
let mut children = HashMap::with_capacity(permission.children.len());
|
||||||
for child in permission.children {
|
for child in permission.children {
|
||||||
children.insert(child.node, child.value);
|
children.insert(child.node, child.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
let permission = pumpkin_util::permission::Permission {
|
let util_permission = pumpkin_util::permission::Permission {
|
||||||
node: permission.node,
|
node: permission.node,
|
||||||
description: permission.description,
|
description: permission.description,
|
||||||
default: match permission.default {
|
default: match permission.default {
|
||||||
PermissionDefault::Deny => pumpkin_util::permission::PermissionDefault::Deny,
|
PermissionDefault::Deny => pumpkin_util::permission::PermissionDefault::Deny,
|
||||||
PermissionDefault::Allow => pumpkin_util::permission::PermissionDefault::Allow,
|
PermissionDefault::Allow => pumpkin_util::permission::PermissionDefault::Allow,
|
||||||
PermissionDefault::Op(permission_level) => {
|
PermissionDefault::Op(lvl) => {
|
||||||
pumpkin_util::permission::PermissionDefault::Op(match permission_level {
|
pumpkin_util::permission::PermissionDefault::Op(match lvl {
|
||||||
PermissionLevel::Zero => pumpkin_util::permission::PermissionLvl::Zero,
|
PermissionLevel::Zero => pumpkin_util::permission::PermissionLvl::Zero,
|
||||||
PermissionLevel::One => pumpkin_util::permission::PermissionLvl::One,
|
PermissionLevel::One => pumpkin_util::permission::PermissionLvl::One,
|
||||||
PermissionLevel::Two => pumpkin_util::permission::PermissionLvl::Two,
|
PermissionLevel::Two => pumpkin_util::permission::PermissionLvl::Two,
|
||||||
@ -331,26 +343,31 @@ impl pumpkin::plugin::context::HostContext for PluginHostState {
|
|||||||
children,
|
children,
|
||||||
};
|
};
|
||||||
|
|
||||||
context
|
let context_res = self
|
||||||
.downcast_mut(self)
|
.resource_table
|
||||||
|
.get_mut::<ContextResource>(&Resource::new_own(context.rep()))?;
|
||||||
|
Ok(context_res
|
||||||
.provider
|
.provider
|
||||||
.register_permission(permission)
|
.register_permission(util_permission)
|
||||||
.await
|
.await)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_data_folder(&mut self, context: Resource<Context>) -> String {
|
async fn get_data_folder(&mut self, context: Resource<Context>) -> wasmtime::Result<String> {
|
||||||
context
|
Ok(self
|
||||||
.downcast_ref(self)
|
.get_context(&context)?
|
||||||
.provider
|
.provider
|
||||||
.get_data_folder()
|
.get_data_folder()
|
||||||
.to_string_lossy()
|
.to_string_lossy()
|
||||||
.into_owned()
|
.into_owned())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_server(&mut self, context: Resource<Context>) -> Resource<Server> {
|
async fn get_server(
|
||||||
let server_provider = context.downcast_ref(self).provider.server.clone();
|
&mut self,
|
||||||
|
context: Resource<Context>,
|
||||||
|
) -> wasmtime::Result<Resource<Server>> {
|
||||||
|
let server_provider = self.get_context(&context)?.provider.server.clone();
|
||||||
self.add_server(server_provider)
|
self.add_server(server_provider)
|
||||||
.expect("failed to add server resource")
|
.map_err(|_| wasmtime::Error::msg("failed to add server resource"))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn drop(&mut self, rep: Resource<Context>) -> wasmtime::Result<()> {
|
async fn drop(&mut self, rep: Resource<Context>) -> wasmtime::Result<()> {
|
||||||
|
|||||||
@ -14,68 +14,77 @@ use crate::plugin::loader::wasm::wasm_host::{
|
|||||||
impl pumpkin::plugin::entity::Host for PluginHostState {}
|
impl pumpkin::plugin::entity::Host for PluginHostState {}
|
||||||
|
|
||||||
impl pumpkin::plugin::entity::HostBlockEntity for PluginHostState {
|
impl pumpkin::plugin::entity::HostBlockEntity for PluginHostState {
|
||||||
async fn resource_location(&mut self, _block_entity: Resource<BlockEntity>) -> String {
|
async fn resource_location(&mut self, _res: Resource<BlockEntity>) -> wasmtime::Result<String> {
|
||||||
todo!()
|
todo!("Implement resource_location lookup")
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_position(&mut self, _block_entity: Resource<BlockEntity>) -> BlockPosition {
|
async fn get_position(
|
||||||
todo!()
|
&mut self,
|
||||||
|
_res: Resource<BlockEntity>,
|
||||||
|
) -> wasmtime::Result<BlockPosition> {
|
||||||
|
todo!("Implement get_position lookup")
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_id(&mut self, _block_entity: Resource<BlockEntity>) -> u32 {
|
async fn get_id(&mut self, _res: Resource<BlockEntity>) -> wasmtime::Result<u32> {
|
||||||
todo!()
|
todo!("Implement get_id lookup")
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn is_dirty(&mut self, _block_entity: Resource<BlockEntity>) -> bool {
|
async fn is_dirty(&mut self, _res: Resource<BlockEntity>) -> wasmtime::Result<bool> {
|
||||||
todo!()
|
todo!("Implement is_dirty lookup")
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn clear_dirty(&mut self, _block_entity: Resource<BlockEntity>) {
|
async fn clear_dirty(&mut self, _res: Resource<BlockEntity>) -> wasmtime::Result<()> {
|
||||||
todo!()
|
todo!("Implement clear_dirty logic")
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn drop(&mut self, _rep: Resource<BlockEntity>) -> wasmtime::Result<()> {
|
async fn drop(&mut self, _rep: Resource<BlockEntity>) -> wasmtime::Result<()> {
|
||||||
todo!()
|
todo!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl pumpkin::plugin::entity::HostCommandBlockEntity for PluginHostState {
|
impl pumpkin::plugin::entity::HostCommandBlockEntity for PluginHostState {
|
||||||
async fn get_block_entity(
|
async fn get_block_entity(
|
||||||
&mut self,
|
&mut self,
|
||||||
_command_block_entity: Resource<CommandBlockEntity>,
|
_res: Resource<CommandBlockEntity>,
|
||||||
) -> Resource<BlockEntity> {
|
) -> wasmtime::Result<Resource<BlockEntity>> {
|
||||||
todo!()
|
todo!("Implement upcasting/mapping to BlockEntity")
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn last_output(&mut self, _command_block_entity: Resource<CommandBlockEntity>) -> String {
|
async fn last_output(
|
||||||
todo!()
|
&mut self,
|
||||||
|
_res: Resource<CommandBlockEntity>,
|
||||||
|
) -> wasmtime::Result<String> {
|
||||||
|
todo!("Implement last_output lookup")
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn track_output(&mut self, _command_block_entity: Resource<CommandBlockEntity>) -> bool {
|
async fn track_output(&mut self, _res: Resource<CommandBlockEntity>) -> wasmtime::Result<bool> {
|
||||||
todo!()
|
todo!("Implement track_output lookup")
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn success_count(&mut self, _command_block_entity: Resource<CommandBlockEntity>) -> u32 {
|
async fn success_count(&mut self, _res: Resource<CommandBlockEntity>) -> wasmtime::Result<u32> {
|
||||||
todo!()
|
todo!("Implement success_count lookup")
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn command(&mut self, _command_block_entity: Resource<CommandBlockEntity>) -> String {
|
async fn command(&mut self, _res: Resource<CommandBlockEntity>) -> wasmtime::Result<String> {
|
||||||
todo!()
|
todo!("Implement command lookup")
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn auto(&mut self, _command_block_entity: Resource<CommandBlockEntity>) -> bool {
|
async fn auto(&mut self, _res: Resource<CommandBlockEntity>) -> wasmtime::Result<bool> {
|
||||||
todo!()
|
todo!("Implement auto lookup")
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn condition_met(&mut self, _command_block_entity: Resource<CommandBlockEntity>) -> bool {
|
async fn condition_met(
|
||||||
todo!()
|
&mut self,
|
||||||
|
_res: Resource<CommandBlockEntity>,
|
||||||
|
) -> wasmtime::Result<bool> {
|
||||||
|
todo!("Implement condition_met lookup")
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn powered(&mut self, _command_block_entity: Resource<CommandBlockEntity>) -> bool {
|
async fn powered(&mut self, _res: Resource<CommandBlockEntity>) -> wasmtime::Result<bool> {
|
||||||
todo!()
|
todo!("Implement powered lookup")
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn drop(&mut self, _rep: Resource<CommandBlockEntity>) -> wasmtime::Result<()> {
|
async fn drop(&mut self, _rep: Resource<CommandBlockEntity>) -> wasmtime::Result<()> {
|
||||||
todo!()
|
todo!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,27 +6,31 @@ use pumpkin_util::translation::{Locale as UtilLocale, add_translation_file, get_
|
|||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
impl Host for PluginHostState {
|
impl Host for PluginHostState {
|
||||||
async fn translate(&mut self, key: String, locale: WitLocale) -> String {
|
async fn translate(&mut self, key: String, locale: WitLocale) -> wasmtime::Result<String> {
|
||||||
let util_locale = wit_to_util_locale(locale);
|
let util_locale = wit_to_util_locale(locale);
|
||||||
get_translation(&key, util_locale)
|
Ok(get_translation(&key, util_locale))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn load_translations(&mut self, namespace: String, json: String, locale: WitLocale) {
|
async fn load_translations(
|
||||||
|
&mut self,
|
||||||
|
namespace: String,
|
||||||
|
json: String,
|
||||||
|
locale: WitLocale,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
let util_locale = wit_to_util_locale(locale);
|
let util_locale = wit_to_util_locale(locale);
|
||||||
add_translation_file(namespace, json, util_locale);
|
add_translation_file(namespace, json, util_locale);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts a WIT Locale to a pumpkin-util Locale.
|
/// Converts a WIT Locale to a pumpkin-util Locale.
|
||||||
fn wit_to_util_locale(wit: WitLocale) -> UtilLocale {
|
fn wit_to_util_locale(wit: WitLocale) -> UtilLocale {
|
||||||
// WIT names are kebab-case (e.g., AfZa -> af-za in .wit, but in generated Rust it might vary)
|
// WIT variants like EnUs often debug to "EnUs".
|
||||||
// We can use the debug representation or a custom mapping.
|
// We convert to lowercase and handle potential format differences.
|
||||||
// Given the amount of variants, we use a string-based approach if possible.
|
|
||||||
let s = format!("{wit:?}").to_lowercase();
|
let s = format!("{wit:?}").to_lowercase();
|
||||||
// pumpkin-util::Locale::from_str expects "af_za" or similar.
|
|
||||||
// WIT might generate "AfZa" or "af_za" depending on bindgen config.
|
// Most translation systems expect underscores (en_us) rather than nothing or dashes.
|
||||||
// Let's assume standard bindgen which might produce "AfZa".
|
// If the WIT Debug format is "EnUs", lowercase is "enus".
|
||||||
// We'll replace kebab-case if necessary.
|
// We might need a smarter mapping if your util expects specifically "en_us".
|
||||||
let s = s.replace('-', "_");
|
|
||||||
UtilLocale::from_str(&s).unwrap_or(UtilLocale::EnUs)
|
UtilLocale::from_str(&s).unwrap_or(UtilLocale::EnUs)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,11 @@ use crate::plugin::loader::wasm::wasm_host::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
impl pumpkin::plugin::logging::Host for PluginHostState {
|
impl pumpkin::plugin::logging::Host for PluginHostState {
|
||||||
async fn log(&mut self, level: pumpkin::plugin::logging::Level, message: String) {
|
async fn log(
|
||||||
|
&mut self,
|
||||||
|
level: pumpkin::plugin::logging::Level,
|
||||||
|
message: String,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
match level {
|
match level {
|
||||||
pumpkin::plugin::logging::Level::Trace => tracing::trace!("[plugin] {message}"),
|
pumpkin::plugin::logging::Level::Trace => tracing::trace!("[plugin] {message}"),
|
||||||
pumpkin::plugin::logging::Level::Debug => tracing::debug!("[plugin] {message}"),
|
pumpkin::plugin::logging::Level::Debug => tracing::debug!("[plugin] {message}"),
|
||||||
@ -11,9 +15,11 @@ impl pumpkin::plugin::logging::Host for PluginHostState {
|
|||||||
pumpkin::plugin::logging::Level::Warn => tracing::warn!("[plugin] {message}"),
|
pumpkin::plugin::logging::Level::Warn => tracing::warn!("[plugin] {message}"),
|
||||||
pumpkin::plugin::logging::Level::Error => tracing::error!("[plugin] {message}"),
|
pumpkin::plugin::logging::Level::Error => tracing::error!("[plugin] {message}"),
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn log_tracing(&mut self, event: Vec<u8>) {
|
async fn log_tracing(&mut self, event: Vec<u8>) -> wasmtime::Result<()> {
|
||||||
log_tracing(event).await;
|
log_tracing(event).await;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,8 +22,8 @@ pub mod world;
|
|||||||
bindgen!({
|
bindgen!({
|
||||||
path: "../pumpkin-plugin-wit/v0.1.0",
|
path: "../pumpkin-plugin-wit/v0.1.0",
|
||||||
world: "plugin",
|
world: "plugin",
|
||||||
imports: { default: async },
|
imports: { default: async | trappable },
|
||||||
exports: { default: async },
|
exports: { default: async | trappable},
|
||||||
});
|
});
|
||||||
|
|
||||||
struct PluginHostComponent;
|
struct PluginHostComponent;
|
||||||
|
|||||||
@ -21,34 +21,36 @@ use pumpkin_util::permission::PermissionLvl;
|
|||||||
fn player_from_resource(
|
fn player_from_resource(
|
||||||
state: &PluginHostState,
|
state: &PluginHostState,
|
||||||
player: &Resource<Player>,
|
player: &Resource<Player>,
|
||||||
) -> Result<std::sync::Arc<crate::entity::player::Player>, String> {
|
) -> wasmtime::Result<std::sync::Arc<crate::entity::player::Player>> {
|
||||||
state
|
state
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<PlayerResource>(&Resource::new_own(player.rep()))
|
.get::<PlayerResource>(&Resource::new_own(player.rep()))
|
||||||
.map_err(|_| "invalid player resource handle".to_string())
|
.map_err(|_| wasmtime::Error::msg("invalid player resource handle"))
|
||||||
.map(|resource| resource.provider.clone())
|
.map(|resource| resource.provider.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn text_component_from_resource(
|
fn text_component_from_resource(
|
||||||
state: &PluginHostState,
|
state: &PluginHostState,
|
||||||
text: &Resource<pumpkin::plugin::text::TextComponent>,
|
text: &Resource<pumpkin::plugin::text::TextComponent>,
|
||||||
) -> Result<pumpkin_util::text::TextComponent, String> {
|
) -> pumpkin_util::text::TextComponent {
|
||||||
state
|
state
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<TextComponentResource>(&Resource::new_own(text.rep()))
|
.get::<TextComponentResource>(&Resource::new_own(text.rep()))
|
||||||
.map_err(|_| "invalid text-component resource handle".to_string())
|
.expect("invalid text-component resource handle")
|
||||||
.map(|resource| resource.provider.clone())
|
.provider
|
||||||
|
.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn world_from_resource(
|
fn world_from_resource(
|
||||||
state: &PluginHostState,
|
state: &PluginHostState,
|
||||||
world: &Resource<pumpkin::plugin::world::World>,
|
world: &Resource<pumpkin::plugin::world::World>,
|
||||||
) -> Result<std::sync::Arc<crate::world::World>, String> {
|
) -> std::sync::Arc<crate::world::World> {
|
||||||
state
|
state
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<WorldResource>(&Resource::new_own(world.rep()))
|
.get::<WorldResource>(&Resource::new_own(world.rep()))
|
||||||
.map_err(|_| "invalid world resource handle".to_string())
|
.expect("invalid world resource handle")
|
||||||
.map(|resource| resource.provider.clone())
|
.provider
|
||||||
|
.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_wit_item_stack(
|
fn to_wit_item_stack(
|
||||||
@ -124,12 +126,12 @@ impl DowncastResourceExt<PlayerResource> for Resource<Player> {
|
|||||||
|
|
||||||
impl pumpkin::plugin::player::Host for PluginHostState {}
|
impl pumpkin::plugin::player::Host for PluginHostState {}
|
||||||
impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
||||||
async fn get_id(&mut self, player: Resource<Player>) -> Result<String, String> {
|
async fn get_id(&mut self, player: Resource<Player>) -> wasmtime::Result<String> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
Ok(player.gameprofile.id.to_string())
|
Ok(player.gameprofile.id.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_name(&mut self, player: Resource<Player>) -> Result<String, String> {
|
async fn get_name(&mut self, player: Resource<Player>) -> wasmtime::Result<String> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
Ok(player.gameprofile.name.clone())
|
Ok(player.gameprofile.name.clone())
|
||||||
}
|
}
|
||||||
@ -137,13 +139,12 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
|||||||
async fn get_position(
|
async fn get_position(
|
||||||
&mut self,
|
&mut self,
|
||||||
player: Resource<Player>,
|
player: Resource<Player>,
|
||||||
) -> Result<pumpkin::plugin::common::Position, String> {
|
) -> wasmtime::Result<pumpkin::plugin::common::Position> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
let position = player.position();
|
Ok(to_wasm_position(player.position()))
|
||||||
Ok(to_wasm_position(position))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_rotation(&mut self, player: Resource<Player>) -> Result<(f32, f32), String> {
|
async fn get_rotation(&mut self, player: Resource<Player>) -> wasmtime::Result<(f32, f32)> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
Ok(player.rotation())
|
Ok(player.rotation())
|
||||||
}
|
}
|
||||||
@ -151,39 +152,36 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
|||||||
async fn get_world(
|
async fn get_world(
|
||||||
&mut self,
|
&mut self,
|
||||||
player: Resource<Player>,
|
player: Resource<Player>,
|
||||||
) -> Result<wasmtime::component::Resource<pumpkin::plugin::world::World>, String> {
|
) -> wasmtime::Result<wasmtime::component::Resource<pumpkin::plugin::world::World>> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
let world = player.world();
|
let world = player.world();
|
||||||
self.add_world(world)
|
self.add_world(world)
|
||||||
.map_err(|_| "failed to add world resource".to_string())
|
.map_err(|_| wasmtime::Error::msg("failed to add world resource"))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_gamemode(
|
async fn get_gamemode(
|
||||||
&mut self,
|
&mut self,
|
||||||
player: Resource<Player>,
|
player: Resource<Player>,
|
||||||
) -> Result<pumpkin::plugin::common::GameMode, String> {
|
) -> wasmtime::Result<pumpkin::plugin::common::GameMode> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
let gamemode = player.gamemode.load();
|
Ok(to_wasm_game_mode(player.gamemode.load()))
|
||||||
Ok(to_wasm_game_mode(gamemode))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn set_gamemode(
|
async fn set_gamemode(
|
||||||
&mut self,
|
&mut self,
|
||||||
player: Resource<Player>,
|
player: Resource<Player>,
|
||||||
mode: pumpkin::plugin::common::GameMode,
|
mode: pumpkin::plugin::common::GameMode,
|
||||||
) -> Result<bool, String> {
|
) -> wasmtime::Result<bool> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
let mode = from_wasm_game_mode(mode);
|
Ok(player.set_gamemode(from_wasm_game_mode(mode)).await)
|
||||||
Ok(player.set_gamemode(mode).await)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_locale(&mut self, player: Resource<Player>) -> Result<String, String> {
|
async fn get_locale(&mut self, player: Resource<Player>) -> wasmtime::Result<String> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
let config = player.config.load();
|
Ok(player.config.load().locale.clone())
|
||||||
Ok(config.locale.clone())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_ping(&mut self, player: Resource<Player>) -> Result<u32, String> {
|
async fn get_ping(&mut self, player: Resource<Player>) -> wasmtime::Result<u32> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
Ok(player.ping.load(Ordering::Relaxed))
|
Ok(player.ping.load(Ordering::Relaxed))
|
||||||
}
|
}
|
||||||
@ -191,7 +189,7 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
|||||||
async fn get_permission_level(
|
async fn get_permission_level(
|
||||||
&mut self,
|
&mut self,
|
||||||
player: Resource<Player>,
|
player: Resource<Player>,
|
||||||
) -> Result<pumpkin::plugin::permission::PermissionLevel, String> {
|
) -> wasmtime::Result<pumpkin::plugin::permission::PermissionLevel> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
Ok(to_wit_permission_level(player.permission_lvl.load()))
|
Ok(to_wit_permission_level(player.permission_lvl.load()))
|
||||||
}
|
}
|
||||||
@ -200,11 +198,9 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
|||||||
&mut self,
|
&mut self,
|
||||||
player: Resource<Player>,
|
player: Resource<Player>,
|
||||||
level: pumpkin::plugin::permission::PermissionLevel,
|
level: pumpkin::plugin::permission::PermissionLevel,
|
||||||
) -> Result<(), String> {
|
) -> wasmtime::Result<()> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
let Some(server) = self.server.as_ref() else {
|
let server = self.server.as_ref().expect("server not available");
|
||||||
return Err("server not available".to_string());
|
|
||||||
};
|
|
||||||
let level = from_wit_permission_level(level);
|
let level = from_wit_permission_level(level);
|
||||||
let command_dispatcher = server.command_dispatcher.read().await;
|
let command_dispatcher = server.command_dispatcher.read().await;
|
||||||
player
|
player
|
||||||
@ -217,22 +213,20 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
|||||||
&mut self,
|
&mut self,
|
||||||
player: Resource<Player>,
|
player: Resource<Player>,
|
||||||
node: String,
|
node: String,
|
||||||
) -> Result<bool, String> {
|
) -> wasmtime::Result<bool> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
let Some(server) = self.server.as_ref() else {
|
let server = self.server.as_ref().expect("server not available");
|
||||||
return Err("server not available".to_string());
|
|
||||||
};
|
|
||||||
Ok(player.has_permission(server, &node).await)
|
Ok(player.has_permission(server, &node).await)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_display_name(
|
async fn get_display_name(
|
||||||
&mut self,
|
&mut self,
|
||||||
player: Resource<Player>,
|
player: Resource<Player>,
|
||||||
) -> Result<Resource<pumpkin::plugin::text::TextComponent>, String> {
|
) -> wasmtime::Result<Resource<pumpkin::plugin::text::TextComponent>> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
let display_name = player.get_display_name().await;
|
let display_name = player.get_display_name().await;
|
||||||
self.add_text_component(display_name)
|
self.add_text_component(display_name)
|
||||||
.map_err(|_| "failed to add text-component resource".to_string())
|
.map_err(|_| wasmtime::Error::msg("failed to add text-component resource"))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn send_system_message(
|
async fn send_system_message(
|
||||||
@ -240,8 +234,8 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
|||||||
player: Resource<Player>,
|
player: Resource<Player>,
|
||||||
text: wasmtime::component::Resource<pumpkin::plugin::text::TextComponent>,
|
text: wasmtime::component::Resource<pumpkin::plugin::text::TextComponent>,
|
||||||
overlay: bool,
|
overlay: bool,
|
||||||
) -> Result<(), String> {
|
) -> wasmtime::Result<()> {
|
||||||
let component = text_component_from_resource(self, &text)?;
|
let component = text_component_from_resource(self, &text);
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
player.send_system_message_raw(&component, overlay).await;
|
player.send_system_message_raw(&component, overlay).await;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -251,8 +245,8 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
|||||||
&mut self,
|
&mut self,
|
||||||
player: Resource<Player>,
|
player: Resource<Player>,
|
||||||
text: wasmtime::component::Resource<pumpkin::plugin::text::TextComponent>,
|
text: wasmtime::component::Resource<pumpkin::plugin::text::TextComponent>,
|
||||||
) -> Result<(), String> {
|
) -> wasmtime::Result<()> {
|
||||||
let component = text_component_from_resource(self, &text)?;
|
let component = text_component_from_resource(self, &text);
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
player.show_title(&component, &TitleMode::Title).await;
|
player.show_title(&component, &TitleMode::Title).await;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -262,8 +256,8 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
|||||||
&mut self,
|
&mut self,
|
||||||
player: Resource<Player>,
|
player: Resource<Player>,
|
||||||
text: wasmtime::component::Resource<pumpkin::plugin::text::TextComponent>,
|
text: wasmtime::component::Resource<pumpkin::plugin::text::TextComponent>,
|
||||||
) -> Result<(), String> {
|
) -> wasmtime::Result<()> {
|
||||||
let component = text_component_from_resource(self, &text)?;
|
let component = text_component_from_resource(self, &text);
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
player.show_title(&component, &TitleMode::SubTitle).await;
|
player.show_title(&component, &TitleMode::SubTitle).await;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -273,8 +267,8 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
|||||||
&mut self,
|
&mut self,
|
||||||
player: Resource<Player>,
|
player: Resource<Player>,
|
||||||
text: wasmtime::component::Resource<pumpkin::plugin::text::TextComponent>,
|
text: wasmtime::component::Resource<pumpkin::plugin::text::TextComponent>,
|
||||||
) -> Result<(), String> {
|
) -> wasmtime::Result<()> {
|
||||||
let component = text_component_from_resource(self, &text)?;
|
let component = text_component_from_resource(self, &text);
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
player.show_title(&component, &TitleMode::ActionBar).await;
|
player.show_title(&component, &TitleMode::ActionBar).await;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -286,7 +280,7 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
|||||||
fade_in: i32,
|
fade_in: i32,
|
||||||
stay: i32,
|
stay: i32,
|
||||||
fade_out: i32,
|
fade_out: i32,
|
||||||
) -> Result<(), String> {
|
) -> wasmtime::Result<()> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
player.send_title_animation(fade_in, stay, fade_out).await;
|
player.send_title_animation(fade_in, stay, fade_out).await;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -298,10 +292,11 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
|||||||
position: pumpkin::plugin::common::Position,
|
position: pumpkin::plugin::common::Position,
|
||||||
yaw: f32,
|
yaw: f32,
|
||||||
pitch: f32,
|
pitch: f32,
|
||||||
) -> Result<(), String> {
|
) -> wasmtime::Result<()> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
let position = from_wasm_position(position);
|
player
|
||||||
player.request_teleport(position, yaw, pitch).await;
|
.request_teleport(from_wasm_position(position), yaw, pitch)
|
||||||
|
.await;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -312,11 +307,12 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
|||||||
position: pumpkin::plugin::common::Position,
|
position: pumpkin::plugin::common::Position,
|
||||||
yaw: Option<f32>,
|
yaw: Option<f32>,
|
||||||
pitch: Option<f32>,
|
pitch: Option<f32>,
|
||||||
) -> Result<(), String> {
|
) -> wasmtime::Result<()> {
|
||||||
let world = world_from_resource(self, &world)?;
|
let world = world_from_resource(self, &world);
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
let position = from_wasm_position(position);
|
player
|
||||||
player.teleport_world(world, position, yaw, pitch).await;
|
.teleport_world(world, from_wasm_position(position), yaw, pitch)
|
||||||
|
.await;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -324,14 +320,14 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
|||||||
&mut self,
|
&mut self,
|
||||||
player: Resource<Player>,
|
player: Resource<Player>,
|
||||||
message: wasmtime::component::Resource<pumpkin::plugin::text::TextComponent>,
|
message: wasmtime::component::Resource<pumpkin::plugin::text::TextComponent>,
|
||||||
) -> Result<(), String> {
|
) -> wasmtime::Result<()> {
|
||||||
let component = text_component_from_resource(self, &message)?;
|
let component = text_component_from_resource(self, &message);
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
player.kick(DisconnectReason::Kicked, component).await;
|
player.kick(DisconnectReason::Kicked, component).await;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn respawn(&mut self, player: Resource<Player>) -> Result<(), String> {
|
async fn respawn(&mut self, player: Resource<Player>) -> wasmtime::Result<()> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
player.respawn().await;
|
player.respawn().await;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -341,15 +337,10 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
|||||||
&mut self,
|
&mut self,
|
||||||
player: Resource<Player>,
|
player: Resource<Player>,
|
||||||
reason: Option<Resource<pumpkin::plugin::text::TextComponent>>,
|
reason: Option<Resource<pumpkin::plugin::text::TextComponent>>,
|
||||||
) -> Result<(), String> {
|
) -> wasmtime::Result<()> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
let Some(server) = self.server.as_ref() else {
|
let server = self.server.as_ref().expect("server not available");
|
||||||
return Err("server not available".to_string());
|
let reason = reason.map(|r| text_component_from_resource(self, &r));
|
||||||
};
|
|
||||||
let reason = match reason {
|
|
||||||
Some(r) => Some(text_component_from_resource(self, &r)?),
|
|
||||||
None => None,
|
|
||||||
};
|
|
||||||
player.ban(server, reason).await;
|
player.ban(server, reason).await;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -358,20 +349,15 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
|||||||
&mut self,
|
&mut self,
|
||||||
player: Resource<Player>,
|
player: Resource<Player>,
|
||||||
reason: Option<Resource<pumpkin::plugin::text::TextComponent>>,
|
reason: Option<Resource<pumpkin::plugin::text::TextComponent>>,
|
||||||
) -> Result<(), String> {
|
) -> wasmtime::Result<()> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
let Some(server) = self.server.as_ref() else {
|
let server = self.server.as_ref().expect("server not available");
|
||||||
return Err("server not available".to_string());
|
let reason = reason.map(|r| text_component_from_resource(self, &r));
|
||||||
};
|
|
||||||
let reason = match reason {
|
|
||||||
Some(r) => Some(text_component_from_resource(self, &r)?),
|
|
||||||
None => None,
|
|
||||||
};
|
|
||||||
player.ban_ip(server, reason).await;
|
player.ban_ip(server, reason).await;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_selected_slot(&mut self, player: Resource<Player>) -> Result<u8, String> {
|
async fn get_selected_slot(&mut self, player: Resource<Player>) -> wasmtime::Result<u8> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
Ok(player.inventory.get_selected_slot())
|
Ok(player.inventory.get_selected_slot())
|
||||||
}
|
}
|
||||||
@ -380,7 +366,7 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
|||||||
&mut self,
|
&mut self,
|
||||||
player: Resource<Player>,
|
player: Resource<Player>,
|
||||||
hand: pumpkin::plugin::common::Hand,
|
hand: pumpkin::plugin::common::Hand,
|
||||||
) -> Result<Option<pumpkin::plugin::common::ItemStack>, String> {
|
) -> wasmtime::Result<Option<pumpkin::plugin::common::ItemStack>> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
let inventory = player.inventory();
|
let inventory = player.inventory();
|
||||||
let item_stack = match hand {
|
let item_stack = match hand {
|
||||||
@ -395,29 +381,28 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
|||||||
&mut self,
|
&mut self,
|
||||||
player: Resource<Player>,
|
player: Resource<Player>,
|
||||||
slot: u8,
|
slot: u8,
|
||||||
) -> Result<Option<pumpkin::plugin::common::ItemStack>, String> {
|
) -> wasmtime::Result<Option<pumpkin::plugin::common::ItemStack>> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
let slot = slot as usize;
|
let slot = slot as usize;
|
||||||
if slot >= PlayerInventory::MAIN_SIZE {
|
if slot >= PlayerInventory::MAIN_SIZE {
|
||||||
return Err("invalid inventory slot".to_string());
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
let item_stack = player.inventory.main_inventory[slot].lock().await.clone();
|
let item_stack = player.inventory.main_inventory[slot].lock().await.clone();
|
||||||
Ok(to_wit_item_stack(&item_stack))
|
Ok(to_wit_item_stack(&item_stack))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_health(&mut self, player: Resource<Player>) -> Result<f32, String> {
|
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())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn set_health(&mut self, player: Resource<Player>, health: f32) -> Result<(), String> {
|
async fn set_health(&mut self, player: Resource<Player>, health: f32) -> wasmtime::Result<()> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
player.set_health(health).await;
|
player.set_health(health).await;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_max_health(&mut self, player: Resource<Player>) -> Result<f32, String> {
|
async fn get_max_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.get_max_health())
|
Ok(player.living_entity.get_max_health())
|
||||||
}
|
}
|
||||||
@ -426,24 +411,28 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
|||||||
&mut self,
|
&mut self,
|
||||||
player: Resource<Player>,
|
player: Resource<Player>,
|
||||||
max_health: f32,
|
max_health: f32,
|
||||||
) -> Result<(), String> {
|
) -> wasmtime::Result<()> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
player.set_max_health(max_health).await;
|
player.set_max_health(max_health).await;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_food_level(&mut self, player: Resource<Player>) -> Result<u8, String> {
|
async fn get_food_level(&mut self, player: Resource<Player>) -> wasmtime::Result<u8> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
Ok(player.hunger_manager.level.load())
|
Ok(player.hunger_manager.level.load())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn set_food_level(&mut self, player: Resource<Player>, level: u8) -> Result<(), String> {
|
async fn set_food_level(
|
||||||
|
&mut self,
|
||||||
|
player: Resource<Player>,
|
||||||
|
level: u8,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
player.set_food_level(level).await;
|
player.set_food_level(level).await;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_saturation(&mut self, player: Resource<Player>) -> Result<f32, String> {
|
async fn get_saturation(&mut self, player: Resource<Player>) -> wasmtime::Result<f32> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
Ok(player.hunger_manager.saturation.load())
|
Ok(player.hunger_manager.saturation.load())
|
||||||
}
|
}
|
||||||
@ -452,13 +441,13 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
|||||||
&mut self,
|
&mut self,
|
||||||
player: Resource<Player>,
|
player: Resource<Player>,
|
||||||
saturation: f32,
|
saturation: f32,
|
||||||
) -> Result<(), String> {
|
) -> wasmtime::Result<()> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
player.set_saturation(saturation).await;
|
player.set_saturation(saturation).await;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_exhaustion(&mut self, player: Resource<Player>) -> Result<f32, String> {
|
async fn get_exhaustion(&mut self, player: Resource<Player>) -> wasmtime::Result<f32> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
Ok(player.get_exhaustion())
|
Ok(player.get_exhaustion())
|
||||||
}
|
}
|
||||||
@ -467,13 +456,13 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
|||||||
&mut self,
|
&mut self,
|
||||||
player: Resource<Player>,
|
player: Resource<Player>,
|
||||||
exhaustion: f32,
|
exhaustion: f32,
|
||||||
) -> Result<(), String> {
|
) -> wasmtime::Result<()> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
player.set_exhaustion(exhaustion).await;
|
player.set_exhaustion(exhaustion).await;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_absorption(&mut self, player: Resource<Player>) -> Result<f32, String> {
|
async fn get_absorption(&mut self, player: Resource<Player>) -> wasmtime::Result<f32> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
Ok(player.get_absorption())
|
Ok(player.get_absorption())
|
||||||
}
|
}
|
||||||
@ -482,23 +471,23 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
|||||||
&mut self,
|
&mut self,
|
||||||
player: Resource<Player>,
|
player: Resource<Player>,
|
||||||
absorption: f32,
|
absorption: f32,
|
||||||
) -> Result<(), String> {
|
) -> wasmtime::Result<()> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
player.set_absorption(absorption).await;
|
player.set_absorption(absorption).await;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_experience_level(&mut self, player: Resource<Player>) -> Result<i32, String> {
|
async fn get_experience_level(&mut self, player: Resource<Player>) -> wasmtime::Result<i32> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
Ok(player.experience_level.load(Ordering::Relaxed))
|
Ok(player.experience_level.load(Ordering::Relaxed))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_experience_progress(&mut self, player: Resource<Player>) -> Result<f32, String> {
|
async fn get_experience_progress(&mut self, player: Resource<Player>) -> wasmtime::Result<f32> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
Ok(player.experience_progress.load())
|
Ok(player.experience_progress.load())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_experience_points(&mut self, player: Resource<Player>) -> Result<i32, String> {
|
async fn get_experience_points(&mut self, player: Resource<Player>) -> wasmtime::Result<i32> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
Ok(player.experience_points.load(Ordering::Relaxed))
|
Ok(player.experience_points.load(Ordering::Relaxed))
|
||||||
}
|
}
|
||||||
@ -507,7 +496,7 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
|||||||
&mut self,
|
&mut self,
|
||||||
player: Resource<Player>,
|
player: Resource<Player>,
|
||||||
level: i32,
|
level: i32,
|
||||||
) -> Result<(), String> {
|
) -> wasmtime::Result<()> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
player.set_experience_level(level, true).await;
|
player.set_experience_level(level, true).await;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -517,7 +506,7 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
|||||||
&mut self,
|
&mut self,
|
||||||
player: Resource<Player>,
|
player: Resource<Player>,
|
||||||
progress: f32,
|
progress: f32,
|
||||||
) -> Result<(), String> {
|
) -> wasmtime::Result<()> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
player
|
player
|
||||||
.set_experience(
|
.set_experience(
|
||||||
@ -533,7 +522,7 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
|||||||
&mut self,
|
&mut self,
|
||||||
player: Resource<Player>,
|
player: Resource<Player>,
|
||||||
points: i32,
|
points: i32,
|
||||||
) -> Result<(), String> {
|
) -> wasmtime::Result<()> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
player
|
player
|
||||||
.set_experience(
|
.set_experience(
|
||||||
@ -549,7 +538,7 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
|||||||
&mut self,
|
&mut self,
|
||||||
player: Resource<Player>,
|
player: Resource<Player>,
|
||||||
levels: i32,
|
levels: i32,
|
||||||
) -> Result<(), String> {
|
) -> wasmtime::Result<()> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
player.add_experience_levels(levels).await;
|
player.add_experience_levels(levels).await;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -559,13 +548,13 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
|||||||
&mut self,
|
&mut self,
|
||||||
player: Resource<Player>,
|
player: Resource<Player>,
|
||||||
points: i32,
|
points: i32,
|
||||||
) -> Result<(), String> {
|
) -> wasmtime::Result<()> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
player.add_experience_points(points).await;
|
player.add_experience_points(points).await;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn is_sneaking(&mut self, player: Resource<Player>) -> Result<bool, String> {
|
async fn is_sneaking(&mut self, player: Resource<Player>) -> wasmtime::Result<bool> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
Ok(player.get_entity().sneaking.load(Ordering::Relaxed))
|
Ok(player.get_entity().sneaking.load(Ordering::Relaxed))
|
||||||
}
|
}
|
||||||
@ -574,13 +563,13 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
|||||||
&mut self,
|
&mut self,
|
||||||
player: Resource<Player>,
|
player: Resource<Player>,
|
||||||
sneaking: bool,
|
sneaking: bool,
|
||||||
) -> Result<(), String> {
|
) -> wasmtime::Result<()> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
player.get_entity().set_sneaking(sneaking).await;
|
player.get_entity().set_sneaking(sneaking).await;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn is_sprinting(&mut self, player: Resource<Player>) -> Result<bool, String> {
|
async fn is_sprinting(&mut self, player: Resource<Player>) -> wasmtime::Result<bool> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
Ok(player.get_entity().sprinting.load(Ordering::Relaxed))
|
Ok(player.get_entity().sprinting.load(Ordering::Relaxed))
|
||||||
}
|
}
|
||||||
@ -589,23 +578,23 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
|||||||
&mut self,
|
&mut self,
|
||||||
player: Resource<Player>,
|
player: Resource<Player>,
|
||||||
sprinting: bool,
|
sprinting: bool,
|
||||||
) -> Result<(), String> {
|
) -> wasmtime::Result<()> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
player.get_entity().set_sprinting(sprinting).await;
|
player.get_entity().set_sprinting(sprinting).await;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn is_on_ground(&mut self, player: Resource<Player>) -> Result<bool, String> {
|
async fn is_on_ground(&mut self, player: Resource<Player>) -> wasmtime::Result<bool> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
Ok(player.get_entity().on_ground.load(Ordering::Relaxed))
|
Ok(player.get_entity().on_ground.load(Ordering::Relaxed))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn is_flying(&mut self, player: Resource<Player>) -> Result<bool, String> {
|
async fn is_flying(&mut self, player: Resource<Player>) -> wasmtime::Result<bool> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
Ok(player.is_flying().await)
|
Ok(player.is_flying().await)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn set_flying(&mut self, player: Resource<Player>, flying: bool) -> Result<(), String> {
|
async fn set_flying(&mut self, player: Resource<Player>, flying: bool) -> wasmtime::Result<()> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
{
|
{
|
||||||
let mut abilities = player.abilities.lock().await;
|
let mut abilities = player.abilities.lock().await;
|
||||||
@ -618,7 +607,7 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
|||||||
async fn get_abilities(
|
async fn get_abilities(
|
||||||
&mut self,
|
&mut self,
|
||||||
player: Resource<Player>,
|
player: Resource<Player>,
|
||||||
) -> Result<pumpkin::plugin::player::PlayerAbilities, String> {
|
) -> wasmtime::Result<pumpkin::plugin::player::PlayerAbilities> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
let abilities = player.abilities.lock().await;
|
let abilities = player.abilities.lock().await;
|
||||||
Ok(pumpkin::plugin::player::PlayerAbilities {
|
Ok(pumpkin::plugin::player::PlayerAbilities {
|
||||||
@ -636,7 +625,7 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
|||||||
&mut self,
|
&mut self,
|
||||||
player: Resource<Player>,
|
player: Resource<Player>,
|
||||||
abilities: pumpkin::plugin::player::PlayerAbilities,
|
abilities: pumpkin::plugin::player::PlayerAbilities,
|
||||||
) -> Result<(), String> {
|
) -> wasmtime::Result<()> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
{
|
{
|
||||||
let mut a = player.abilities.lock().await;
|
let mut a = player.abilities.lock().await;
|
||||||
@ -652,7 +641,7 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_ip(&mut self, player: Resource<Player>) -> Result<String, String> {
|
async fn get_ip(&mut self, player: Resource<Player>) -> wasmtime::Result<String> {
|
||||||
let player = player_from_resource(self, &player)?;
|
let player = player_from_resource(self, &player)?;
|
||||||
Ok(player.get_ip().await)
|
Ok(player.get_ip().await)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,47 +8,56 @@ use crate::plugin::loader::wasm::wasm_host::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
impl PluginHostState {
|
||||||
|
fn get_server_res(&self, res: &Resource<Server>) -> wasmtime::Result<&ServerResource> {
|
||||||
|
self.resource_table
|
||||||
|
.get::<ServerResource>(&Resource::new_own(res.rep()))
|
||||||
|
.map_err(wasmtime::Error::from)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl pumpkin::plugin::server::Host for PluginHostState {}
|
impl pumpkin::plugin::server::Host for PluginHostState {}
|
||||||
|
|
||||||
impl pumpkin::plugin::server::HostServer for PluginHostState {
|
impl pumpkin::plugin::server::HostServer for PluginHostState {
|
||||||
async fn drop(&mut self, rep: Resource<Server>) -> wasmtime::Result<()> {
|
async fn get_difficulty(&mut self, res: Resource<Server>) -> wasmtime::Result<Difficulty> {
|
||||||
let _ = self
|
let resource = self.get_server_res(&res)?;
|
||||||
.resource_table
|
|
||||||
.delete::<ServerResource>(Resource::new_own(rep.rep()));
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_difficulty(&mut self, server: Resource<Server>) -> Difficulty {
|
Ok(match resource.provider.get_difficulty() {
|
||||||
let resource: &ServerResource = self
|
|
||||||
.resource_table
|
|
||||||
.get_any_mut(server.rep())
|
|
||||||
.expect("invalid server resource handle")
|
|
||||||
.downcast_ref::<ServerResource>()
|
|
||||||
.expect("resource type mismatch");
|
|
||||||
|
|
||||||
match resource.provider.get_difficulty() {
|
|
||||||
pumpkin_util::Difficulty::Peaceful => Difficulty::Peaceful,
|
pumpkin_util::Difficulty::Peaceful => Difficulty::Peaceful,
|
||||||
pumpkin_util::Difficulty::Easy => Difficulty::Easy,
|
pumpkin_util::Difficulty::Easy => Difficulty::Easy,
|
||||||
pumpkin_util::Difficulty::Normal => Difficulty::Normal,
|
pumpkin_util::Difficulty::Normal => Difficulty::Normal,
|
||||||
pumpkin_util::Difficulty::Hard => Difficulty::Hard,
|
pumpkin_util::Difficulty::Hard => Difficulty::Hard,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_player_count(
|
async fn get_player_count(&mut self, _res: Resource<Server>) -> wasmtime::Result<u32> {
|
||||||
&mut self,
|
let server = self
|
||||||
_server: Resource<pumpkin::plugin::server::Server>,
|
.server
|
||||||
) -> u32 {
|
.as_ref()
|
||||||
let server = self.server.as_ref().expect("server not available");
|
.ok_or_else(|| wasmtime::Error::msg("Server not available"))?;
|
||||||
server.get_player_count() as u32
|
Ok(server.get_player_count() as u32)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_mspt(&mut self, _server: Resource<pumpkin::plugin::server::Server>) -> f64 {
|
async fn get_mspt(&mut self, _res: Resource<Server>) -> wasmtime::Result<f64> {
|
||||||
let server = self.server.as_ref().expect("server not available");
|
let server = self
|
||||||
server.get_mspt()
|
.server
|
||||||
|
.as_ref()
|
||||||
|
.ok_or_else(|| wasmtime::Error::msg("Server not available"))?;
|
||||||
|
Ok(server.get_mspt())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_tps(&mut self, _server: Resource<pumpkin::plugin::server::Server>) -> f64 {
|
async fn get_tps(&mut self, _res: Resource<Server>) -> wasmtime::Result<f64> {
|
||||||
let server = self.server.as_ref().expect("server not available");
|
let server = self
|
||||||
server.get_tps()
|
.server
|
||||||
|
.as_ref()
|
||||||
|
.ok_or_else(|| wasmtime::Error::msg("Server not available"))?;
|
||||||
|
Ok(server.get_tps())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn drop(&mut self, rep: Resource<Server>) -> wasmtime::Result<()> {
|
||||||
|
self.resource_table
|
||||||
|
.delete::<ServerResource>(Resource::new_own(rep.rep()))
|
||||||
|
.map_err(wasmtime::Error::from)?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use wasmtime::component::Resource;
|
use wasmtime::component::Resource;
|
||||||
|
|
||||||
use crate::plugin::loader::wasm::wasm_host::{
|
use crate::plugin::loader::wasm::wasm_host::{
|
||||||
@ -12,39 +11,309 @@ use crate::plugin::loader::wasm::wasm_host::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use pumpkin_util::text::{
|
use pumpkin_util::text::{
|
||||||
|
TextComponent as InternalTextComponent,
|
||||||
click::ClickEvent,
|
click::ClickEvent,
|
||||||
color::{self, Color},
|
color::{self, Color},
|
||||||
hover::HoverEvent,
|
hover::HoverEvent,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl pumpkin::plugin::text::Host for PluginHostState {}
|
// --- Trapping Helpers ---
|
||||||
|
impl PluginHostState {
|
||||||
|
fn get_text_ref(
|
||||||
|
&self,
|
||||||
|
res: &Resource<TextComponent>,
|
||||||
|
) -> wasmtime::Result<&TextComponentResource> {
|
||||||
|
self.resource_table
|
||||||
|
.get::<TextComponentResource>(&Resource::new_own(res.rep()))
|
||||||
|
.map_err(wasmtime::Error::from)
|
||||||
|
}
|
||||||
|
|
||||||
// TODO - Change the pumpkin_util::text::TextComponent to use &mut self instead of self for the builder pattern.
|
fn get_text_mut(
|
||||||
// right now we have to do a bunch of cloning due to the fact that the builder pattern doesn't accept &mut self.
|
&mut self,
|
||||||
impl DowncastResourceExt<TextComponentResource> for Resource<TextComponent> {
|
res: &Resource<TextComponent>,
|
||||||
|
) -> wasmtime::Result<&mut TextComponentResource> {
|
||||||
|
self.resource_table
|
||||||
|
.get_mut::<TextComponentResource>(&Resource::new_own(res.rep()))
|
||||||
|
.map_err(wasmtime::Error::from)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn take_text(
|
||||||
|
&mut self,
|
||||||
|
res: &Resource<TextComponent>,
|
||||||
|
) -> wasmtime::Result<TextComponentResource> {
|
||||||
|
self.resource_table
|
||||||
|
.delete::<TextComponentResource>(Resource::new_own(res.rep()))
|
||||||
|
.map_err(wasmtime::Error::from)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DowncastResourceExt<TextComponentResource> for wasmtime::component::Resource<TextComponent> {
|
||||||
fn downcast_ref<'a>(&'a self, state: &'a mut PluginHostState) -> &'a TextComponentResource {
|
fn downcast_ref<'a>(&'a self, state: &'a mut PluginHostState) -> &'a TextComponentResource {
|
||||||
state
|
state
|
||||||
.resource_table
|
.resource_table
|
||||||
.get_any_mut(self.rep())
|
.get_any_mut(self.rep())
|
||||||
.expect("invalid text-component resource handle")
|
.expect("invalid handle")
|
||||||
.downcast_ref::<TextComponentResource>()
|
.downcast_ref()
|
||||||
.expect("resource type mismatch")
|
.expect("type mismatch")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn downcast_mut<'a>(&'a self, state: &'a mut PluginHostState) -> &'a mut TextComponentResource {
|
fn downcast_mut<'a>(&'a self, state: &'a mut PluginHostState) -> &'a mut TextComponentResource {
|
||||||
state
|
state
|
||||||
.resource_table
|
.resource_table
|
||||||
.get_any_mut(self.rep())
|
.get_any_mut(self.rep())
|
||||||
.expect("invalid text-component resource handle")
|
.expect("invalid handle")
|
||||||
.downcast_mut::<TextComponentResource>()
|
.downcast_mut()
|
||||||
.expect("resource type mismatch")
|
.expect("type mismatch")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consume(self, state: &mut PluginHostState) -> TextComponentResource {
|
fn consume(self, state: &mut PluginHostState) -> TextComponentResource {
|
||||||
state
|
state
|
||||||
.resource_table
|
.resource_table
|
||||||
.delete::<TextComponentResource>(Resource::new_own(self.rep()))
|
.delete(wasmtime::component::Resource::new_own(self.rep()))
|
||||||
.expect("invalid text-component resource handle")
|
.expect("invalid handle")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl pumpkin::plugin::text::Host for PluginHostState {}
|
||||||
|
|
||||||
|
impl pumpkin::plugin::text::HostTextComponent for PluginHostState {
|
||||||
|
async fn text(&mut self, plain: String) -> wasmtime::Result<Resource<TextComponent>> {
|
||||||
|
let tc = InternalTextComponent::text(plain);
|
||||||
|
self.add_text_component(tc)
|
||||||
|
.map_err(|_| wasmtime::Error::msg("Failed to add text component"))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn translate(
|
||||||
|
&mut self,
|
||||||
|
key: String,
|
||||||
|
with: Vec<Resource<TextComponent>>,
|
||||||
|
) -> wasmtime::Result<Resource<TextComponent>> {
|
||||||
|
let mut components = Vec::with_capacity(with.len());
|
||||||
|
for r in with {
|
||||||
|
components.push(self.take_text(&r)?.provider);
|
||||||
|
}
|
||||||
|
let tc = InternalTextComponent::translate(key, components);
|
||||||
|
self.add_text_component(tc)
|
||||||
|
.map_err(|_| wasmtime::Error::msg("Failed to add text component"))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn add_child(
|
||||||
|
&mut self,
|
||||||
|
text_component: Resource<TextComponent>,
|
||||||
|
child: Resource<TextComponent>,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
let child_tc = self.take_text(&child)?.provider;
|
||||||
|
let parent = self.get_text_mut(&text_component)?;
|
||||||
|
// Cloning here as noted in your TODO until builder pattern supports &mut self
|
||||||
|
parent.provider = parent.provider.clone().add_child(child_tc);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn add_text(
|
||||||
|
&mut self,
|
||||||
|
text_component: Resource<TextComponent>,
|
||||||
|
text: String,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
let parent = self.get_text_mut(&text_component)?;
|
||||||
|
parent.provider = parent.provider.clone().add_text(text);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_text(
|
||||||
|
&mut self,
|
||||||
|
text_component: Resource<TextComponent>,
|
||||||
|
) -> wasmtime::Result<String> {
|
||||||
|
Ok(self
|
||||||
|
.get_text_ref(&text_component)?
|
||||||
|
.provider
|
||||||
|
.clone()
|
||||||
|
.get_text())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn encode(
|
||||||
|
&mut self,
|
||||||
|
text_component: Resource<TextComponent>,
|
||||||
|
) -> wasmtime::Result<Vec<u8>> {
|
||||||
|
Ok(self
|
||||||
|
.get_text_ref(&text_component)?
|
||||||
|
.provider
|
||||||
|
.encode()
|
||||||
|
.into_vec())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn color_named(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<TextComponent>,
|
||||||
|
color: NamedColor,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
self.get_text_mut(&res)?.provider.0.style.color =
|
||||||
|
Some(Color::Named(map_named_color(color)));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn color_rgb(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<TextComponent>,
|
||||||
|
color: RgbColor,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
self.get_text_mut(&res)?.provider.0.style.color =
|
||||||
|
Some(Color::Rgb(color::RGBColor::new(color.r, color.g, color.b)));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn bold(&mut self, res: Resource<TextComponent>, value: bool) -> wasmtime::Result<()> {
|
||||||
|
self.get_text_mut(&res)?.provider.0.style.bold = Some(value);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn italic(&mut self, res: Resource<TextComponent>, value: bool) -> wasmtime::Result<()> {
|
||||||
|
self.get_text_mut(&res)?.provider.0.style.italic = Some(value);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn underlined(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<TextComponent>,
|
||||||
|
value: bool,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
self.get_text_mut(&res)?.provider.0.style.underlined = Some(value);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn strikethrough(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<TextComponent>,
|
||||||
|
value: bool,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
self.get_text_mut(&res)?.provider.0.style.strikethrough = Some(value);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn obfuscated(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<TextComponent>,
|
||||||
|
value: bool,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
self.get_text_mut(&res)?.provider.0.style.obfuscated = Some(value);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn insertion(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<TextComponent>,
|
||||||
|
text: String,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
self.get_text_mut(&res)?.provider.0.style.insertion = Some(text);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn font(&mut self, res: Resource<TextComponent>, font: String) -> wasmtime::Result<()> {
|
||||||
|
self.get_text_mut(&res)?.provider.0.style.font = Some(font);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn shadow_color(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<TextComponent>,
|
||||||
|
color: ArgbColor,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
self.get_text_mut(&res)?.provider.0.style.shadow_color =
|
||||||
|
Some(color::ARGBColor::new(color.a, color.r, color.g, color.b));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn click_open_url(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<TextComponent>,
|
||||||
|
url: String,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
self.get_text_mut(&res)?.provider.0.style.click_event = Some(ClickEvent::OpenUrl {
|
||||||
|
url: Cow::Owned(url),
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn click_run_command(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<TextComponent>,
|
||||||
|
command: String,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
self.get_text_mut(&res)?.provider.0.style.click_event = Some(ClickEvent::RunCommand {
|
||||||
|
command: Cow::Owned(command),
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn click_suggest_command(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<TextComponent>,
|
||||||
|
command: String,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
self.get_text_mut(&res)?.provider.0.style.click_event = Some(ClickEvent::SuggestCommand {
|
||||||
|
command: Cow::Owned(command),
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn click_copy_to_clipboard(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<TextComponent>,
|
||||||
|
text: String,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
self.get_text_mut(&res)?.provider.0.style.click_event = Some(ClickEvent::CopyToClipboard {
|
||||||
|
value: Cow::Owned(text),
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn hover_show_text(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<TextComponent>,
|
||||||
|
text: Resource<TextComponent>,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
let hover_tc = self.take_text(&text)?.provider;
|
||||||
|
self.get_text_mut(&res)?.provider.0.style.hover_event = Some(HoverEvent::ShowText {
|
||||||
|
value: vec![hover_tc.0],
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn hover_show_item(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<TextComponent>,
|
||||||
|
item: String,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
self.get_text_mut(&res)?.provider.0.style.hover_event = Some(HoverEvent::ShowItem {
|
||||||
|
id: Cow::Owned(item),
|
||||||
|
count: None,
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn hover_show_entity(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<TextComponent>,
|
||||||
|
entity_type: String,
|
||||||
|
id: String,
|
||||||
|
name: Option<Resource<TextComponent>>,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
let name_val = match name {
|
||||||
|
Some(r) => Some(vec![self.take_text(&r)?.provider.0]),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
self.get_text_mut(&res)?.provider.0.style.hover_event = Some(HoverEvent::ShowEntity {
|
||||||
|
id: Cow::Owned(entity_type),
|
||||||
|
uuid: Cow::Owned(id),
|
||||||
|
name: name_val,
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn drop(&mut self, rep: Resource<TextComponent>) -> wasmtime::Result<()> {
|
||||||
|
self.resource_table
|
||||||
|
.delete::<TextComponentResource>(Resource::new_own(rep.rep()))
|
||||||
|
.map_err(wasmtime::Error::from)?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,225 +337,3 @@ const fn map_named_color(color: NamedColor) -> color::NamedColor {
|
|||||||
NamedColor::White => color::NamedColor::White,
|
NamedColor::White => color::NamedColor::White,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl pumpkin::plugin::text::HostTextComponent for PluginHostState {
|
|
||||||
async fn text(&mut self, plain: String) -> Resource<TextComponent> {
|
|
||||||
let tc = pumpkin_util::text::TextComponent::text(plain);
|
|
||||||
self.add_text_component(tc).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn translate(
|
|
||||||
&mut self,
|
|
||||||
key: String,
|
|
||||||
with: Vec<Resource<TextComponent>>,
|
|
||||||
) -> Resource<TextComponent> {
|
|
||||||
let with: Vec<pumpkin_util::text::TextComponent> =
|
|
||||||
with.into_iter().map(|r| r.consume(self).provider).collect();
|
|
||||||
let tc = pumpkin_util::text::TextComponent::translate(key, with);
|
|
||||||
self.add_text_component(tc).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn add_child(
|
|
||||||
&mut self,
|
|
||||||
text_component: Resource<TextComponent>,
|
|
||||||
child: Resource<TextComponent>,
|
|
||||||
) {
|
|
||||||
let child = child.consume(self).provider;
|
|
||||||
let parent = &mut text_component.downcast_mut(self).provider;
|
|
||||||
*parent = parent.clone().add_child(child);
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn add_text(&mut self, text_component: Resource<TextComponent>, text: String) {
|
|
||||||
let parent = &mut text_component.downcast_mut(self).provider;
|
|
||||||
*parent = parent.clone().add_text(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_text(&mut self, text_component: Resource<TextComponent>) -> String {
|
|
||||||
text_component
|
|
||||||
.downcast_ref(self)
|
|
||||||
.provider
|
|
||||||
.clone()
|
|
||||||
.get_text()
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn encode(&mut self, text_component: Resource<TextComponent>) -> Vec<u8> {
|
|
||||||
text_component
|
|
||||||
.downcast_ref(self)
|
|
||||||
.provider
|
|
||||||
.encode()
|
|
||||||
.into_vec()
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn color_named(&mut self, text_component: Resource<TextComponent>, color: NamedColor) {
|
|
||||||
text_component.downcast_mut(self).provider.0.style.color =
|
|
||||||
Some(Color::Named(map_named_color(color)));
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn color_rgb(&mut self, text_component: Resource<TextComponent>, color: RgbColor) {
|
|
||||||
text_component.downcast_mut(self).provider.0.style.color =
|
|
||||||
Some(Color::Rgb(color::RGBColor::new(color.r, color.g, color.b)));
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn bold(&mut self, text_component: Resource<TextComponent>, value: bool) {
|
|
||||||
text_component.downcast_mut(self).provider.0.style.bold = Some(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn italic(&mut self, text_component: Resource<TextComponent>, value: bool) {
|
|
||||||
text_component.downcast_mut(self).provider.0.style.italic = Some(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn underlined(&mut self, text_component: Resource<TextComponent>, value: bool) {
|
|
||||||
text_component
|
|
||||||
.downcast_mut(self)
|
|
||||||
.provider
|
|
||||||
.0
|
|
||||||
.style
|
|
||||||
.underlined = Some(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn strikethrough(&mut self, text_component: Resource<TextComponent>, value: bool) {
|
|
||||||
text_component
|
|
||||||
.downcast_mut(self)
|
|
||||||
.provider
|
|
||||||
.0
|
|
||||||
.style
|
|
||||||
.strikethrough = Some(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn obfuscated(&mut self, text_component: Resource<TextComponent>, value: bool) {
|
|
||||||
text_component
|
|
||||||
.downcast_mut(self)
|
|
||||||
.provider
|
|
||||||
.0
|
|
||||||
.style
|
|
||||||
.obfuscated = Some(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn insertion(&mut self, text_component: Resource<TextComponent>, text: String) {
|
|
||||||
text_component.downcast_mut(self).provider.0.style.insertion = Some(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn font(&mut self, text_component: Resource<TextComponent>, font: String) {
|
|
||||||
text_component.downcast_mut(self).provider.0.style.font = Some(font);
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn shadow_color(&mut self, text_component: Resource<TextComponent>, color: ArgbColor) {
|
|
||||||
text_component
|
|
||||||
.downcast_mut(self)
|
|
||||||
.provider
|
|
||||||
.0
|
|
||||||
.style
|
|
||||||
.shadow_color = Some(color::ARGBColor::new(color.a, color.r, color.g, color.b));
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn click_open_url(&mut self, text_component: Resource<TextComponent>, url: String) {
|
|
||||||
text_component
|
|
||||||
.downcast_mut(self)
|
|
||||||
.provider
|
|
||||||
.0
|
|
||||||
.style
|
|
||||||
.click_event = Some(ClickEvent::OpenUrl {
|
|
||||||
url: Cow::Owned(url),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn click_run_command(
|
|
||||||
&mut self,
|
|
||||||
text_component: Resource<TextComponent>,
|
|
||||||
command: String,
|
|
||||||
) {
|
|
||||||
text_component
|
|
||||||
.downcast_mut(self)
|
|
||||||
.provider
|
|
||||||
.0
|
|
||||||
.style
|
|
||||||
.click_event = Some(ClickEvent::RunCommand {
|
|
||||||
command: Cow::Owned(command),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn click_suggest_command(
|
|
||||||
&mut self,
|
|
||||||
text_component: Resource<TextComponent>,
|
|
||||||
command: String,
|
|
||||||
) {
|
|
||||||
text_component
|
|
||||||
.downcast_mut(self)
|
|
||||||
.provider
|
|
||||||
.0
|
|
||||||
.style
|
|
||||||
.click_event = Some(ClickEvent::SuggestCommand {
|
|
||||||
command: Cow::Owned(command),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn click_copy_to_clipboard(
|
|
||||||
&mut self,
|
|
||||||
text_component: Resource<TextComponent>,
|
|
||||||
text: String,
|
|
||||||
) {
|
|
||||||
text_component
|
|
||||||
.downcast_mut(self)
|
|
||||||
.provider
|
|
||||||
.0
|
|
||||||
.style
|
|
||||||
.click_event = Some(ClickEvent::CopyToClipboard {
|
|
||||||
value: Cow::Owned(text),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn hover_show_text(
|
|
||||||
&mut self,
|
|
||||||
text_component: Resource<TextComponent>,
|
|
||||||
text: Resource<TextComponent>,
|
|
||||||
) {
|
|
||||||
let hover_tc = text.consume(self).provider;
|
|
||||||
text_component
|
|
||||||
.downcast_mut(self)
|
|
||||||
.provider
|
|
||||||
.0
|
|
||||||
.style
|
|
||||||
.hover_event = Some(HoverEvent::ShowText {
|
|
||||||
value: vec![hover_tc.0],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn hover_show_item(&mut self, text_component: Resource<TextComponent>, item: String) {
|
|
||||||
text_component
|
|
||||||
.downcast_mut(self)
|
|
||||||
.provider
|
|
||||||
.0
|
|
||||||
.style
|
|
||||||
.hover_event = Some(HoverEvent::ShowItem {
|
|
||||||
id: Cow::Owned(item),
|
|
||||||
count: None,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn hover_show_entity(
|
|
||||||
&mut self,
|
|
||||||
text_component: Resource<TextComponent>,
|
|
||||||
entity_type: String,
|
|
||||||
id: String,
|
|
||||||
name: Option<Resource<TextComponent>>,
|
|
||||||
) {
|
|
||||||
let name = name.map(|r| vec![r.consume(self).provider.0]);
|
|
||||||
text_component
|
|
||||||
.downcast_mut(self)
|
|
||||||
.provider
|
|
||||||
.0
|
|
||||||
.style
|
|
||||||
.hover_event = Some(HoverEvent::ShowEntity {
|
|
||||||
id: Cow::Owned(entity_type),
|
|
||||||
uuid: Cow::Owned(id),
|
|
||||||
name,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn drop(&mut self, rep: Resource<TextComponent>) -> wasmtime::Result<()> {
|
|
||||||
let _ = self
|
|
||||||
.resource_table
|
|
||||||
.delete::<TextComponentResource>(Resource::new_own(rep.rep()));
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,85 +1,69 @@
|
|||||||
use pumpkin_data::block_state::PistonBehavior;
|
use pumpkin_data::block_state::PistonBehavior;
|
||||||
use pumpkin_util::math::position::BlockPos;
|
use pumpkin_util::math::position::BlockPos;
|
||||||
use pumpkin_world::world::BlockFlags;
|
use pumpkin_world::world::{BlockFlags, SimpleWorld};
|
||||||
use wasmtime::component::Resource;
|
use wasmtime::component::Resource;
|
||||||
|
|
||||||
use pumpkin_world::world::SimpleWorld;
|
|
||||||
|
|
||||||
use crate::plugin::loader::wasm::wasm_host::wit::v0_1_0::pumpkin::plugin::world::{
|
use crate::plugin::loader::wasm::wasm_host::wit::v0_1_0::pumpkin::plugin::world::{
|
||||||
BlockFlags as WitBlockFlags, BlockPos as WitBlockPos, BlockState as WitBlockState,
|
BlockFlags as WitBlockFlags, BlockPos as WitBlockPos, BlockState as WitBlockState,
|
||||||
PistonBehavior as WitPistonBehavior,
|
PistonBehavior as WitPistonBehavior,
|
||||||
};
|
};
|
||||||
use crate::plugin::loader::wasm::wasm_host::{
|
use crate::plugin::loader::wasm::wasm_host::{
|
||||||
DowncastResourceExt,
|
|
||||||
state::{PluginHostState, TextComponentResource, WorldResource},
|
state::{PluginHostState, TextComponentResource, WorldResource},
|
||||||
wit::v0_1_0::pumpkin::{self, plugin::world::World},
|
wit::v0_1_0::pumpkin::{self, plugin::world::World},
|
||||||
};
|
};
|
||||||
|
|
||||||
fn text_component_from_resource(
|
// --- Trapping Helpers ---
|
||||||
state: &PluginHostState,
|
impl PluginHostState {
|
||||||
text: &Resource<pumpkin::plugin::text::TextComponent>,
|
fn get_world_res(&self, res: &Resource<World>) -> wasmtime::Result<&WorldResource> {
|
||||||
) -> Result<pumpkin_util::text::TextComponent, String> {
|
self.resource_table
|
||||||
state
|
.get::<WorldResource>(&Resource::new_own(res.rep()))
|
||||||
.resource_table
|
.map_err(wasmtime::Error::from)
|
||||||
.get::<TextComponentResource>(&Resource::new_own(text.rep()))
|
|
||||||
.map_err(|_| "invalid text-component resource handle".to_string())
|
|
||||||
.map(|resource| resource.provider.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DowncastResourceExt<WorldResource> for Resource<World> {
|
|
||||||
fn downcast_ref<'a>(&'a self, state: &'a mut PluginHostState) -> &'a WorldResource {
|
|
||||||
state
|
|
||||||
.resource_table
|
|
||||||
.get_any_mut(self.rep())
|
|
||||||
.expect("invalid world resource handle")
|
|
||||||
.downcast_ref::<WorldResource>()
|
|
||||||
.expect("resource type mismatch")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn downcast_mut<'a>(&'a self, state: &'a mut PluginHostState) -> &'a mut WorldResource {
|
fn get_text_provider(
|
||||||
state
|
&self,
|
||||||
|
res: &Resource<pumpkin::plugin::text::TextComponent>,
|
||||||
|
) -> wasmtime::Result<pumpkin_util::text::TextComponent> {
|
||||||
|
Ok(self
|
||||||
.resource_table
|
.resource_table
|
||||||
.get_any_mut(self.rep())
|
.get::<TextComponentResource>(&Resource::new_own(res.rep()))
|
||||||
.expect("invalid world resource handle")
|
.map_err(wasmtime::Error::from)?
|
||||||
.downcast_mut::<WorldResource>()
|
.provider
|
||||||
.expect("resource type mismatch")
|
.clone())
|
||||||
}
|
|
||||||
|
|
||||||
fn consume(self, state: &mut PluginHostState) -> WorldResource {
|
|
||||||
state
|
|
||||||
.resource_table
|
|
||||||
.delete::<WorldResource>(Resource::new_own(self.rep()))
|
|
||||||
.expect("invalid world resource handle")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl pumpkin::plugin::world::Host for PluginHostState {}
|
impl pumpkin::plugin::world::Host for PluginHostState {}
|
||||||
|
|
||||||
impl pumpkin::plugin::world::HostWorld for PluginHostState {
|
impl pumpkin::plugin::world::HostWorld for PluginHostState {
|
||||||
async fn get_id(&mut self, world: Resource<World>) -> String {
|
async fn get_id(&mut self, world: Resource<World>) -> wasmtime::Result<String> {
|
||||||
world
|
Ok(self
|
||||||
.downcast_ref(self)
|
.get_world_res(&world)?
|
||||||
.provider
|
.provider
|
||||||
.get_world_name()
|
.get_world_name()
|
||||||
.to_string()
|
.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_block_state_id(&mut self, world: Resource<World>, pos: WitBlockPos) -> u16 {
|
async fn get_block_state_id(
|
||||||
let world_ref = world.downcast_ref(self);
|
&mut self,
|
||||||
|
world: Resource<World>,
|
||||||
|
pos: WitBlockPos,
|
||||||
|
) -> wasmtime::Result<u16> {
|
||||||
|
let world_ref = self.get_world_res(&world)?;
|
||||||
let internal_pos = BlockPos::new(pos.x, pos.y, pos.z);
|
let internal_pos = BlockPos::new(pos.x, pos.y, pos.z);
|
||||||
|
Ok(world_ref.provider.get_block_state_id(&internal_pos).await)
|
||||||
world_ref.provider.get_block_state_id(&internal_pos).await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_block_state(&mut self, world: Resource<World>, pos: WitBlockPos) -> WitBlockState {
|
async fn get_block_state(
|
||||||
let world_ref = world.downcast_ref(self);
|
&mut self,
|
||||||
|
world: Resource<World>,
|
||||||
|
pos: WitBlockPos,
|
||||||
|
) -> wasmtime::Result<WitBlockState> {
|
||||||
|
let world_ref = self.get_world_res(&world)?;
|
||||||
let internal_pos = BlockPos::new(pos.x, pos.y, pos.z);
|
let internal_pos = BlockPos::new(pos.x, pos.y, pos.z);
|
||||||
|
|
||||||
// Fetch the actual BlockState struct from the world
|
|
||||||
// get_block_state typically returns &'static BlockState in Pumpkin
|
|
||||||
let state = world_ref.provider.get_block_state(&internal_pos).await;
|
let state = world_ref.provider.get_block_state(&internal_pos).await;
|
||||||
|
|
||||||
WitBlockState {
|
Ok(WitBlockState {
|
||||||
id: state.id,
|
id: state.id,
|
||||||
luminance: state.luminance,
|
luminance: state.luminance,
|
||||||
opacity: state.opacity,
|
opacity: state.opacity,
|
||||||
@ -96,7 +80,7 @@ impl pumpkin::plugin::world::HostWorld for PluginHostState {
|
|||||||
PistonBehavior::Ignore => WitPistonBehavior::Ignore,
|
PistonBehavior::Ignore => WitPistonBehavior::Ignore,
|
||||||
PistonBehavior::PushOnly => WitPistonBehavior::PushOnly,
|
PistonBehavior::PushOnly => WitPistonBehavior::PushOnly,
|
||||||
},
|
},
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn set_block_state(
|
async fn set_block_state(
|
||||||
@ -105,11 +89,10 @@ impl pumpkin::plugin::world::HostWorld for PluginHostState {
|
|||||||
pos: WitBlockPos,
|
pos: WitBlockPos,
|
||||||
state: u16,
|
state: u16,
|
||||||
update_flags: WitBlockFlags,
|
update_flags: WitBlockFlags,
|
||||||
) {
|
) -> wasmtime::Result<()> {
|
||||||
let world_ref = world.downcast_ref(self);
|
let world_ref = self.get_world_res(&world)?;
|
||||||
let internal_pos = BlockPos::new(pos.x, pos.y, pos.z);
|
let internal_pos = BlockPos::new(pos.x, pos.y, pos.z);
|
||||||
|
|
||||||
// Map WIT flags to your internal bitflags
|
|
||||||
let mut internal_flags = BlockFlags::empty();
|
let mut internal_flags = BlockFlags::empty();
|
||||||
if update_flags.contains(WitBlockFlags::NOTIFY_NEIGHBORS) {
|
if update_flags.contains(WitBlockFlags::NOTIFY_NEIGHBORS) {
|
||||||
internal_flags |= BlockFlags::NOTIFY_NEIGHBORS;
|
internal_flags |= BlockFlags::NOTIFY_NEIGHBORS;
|
||||||
@ -136,65 +119,91 @@ impl pumpkin::plugin::world::HostWorld for PluginHostState {
|
|||||||
internal_flags |= BlockFlags::SKIP_BLOCK_ADDED_CALLBACK;
|
internal_flags |= BlockFlags::SKIP_BLOCK_ADDED_CALLBACK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the world
|
|
||||||
world_ref
|
world_ref
|
||||||
.provider
|
.provider
|
||||||
.clone()
|
.clone()
|
||||||
.set_block_state(&internal_pos, state, internal_flags)
|
.set_block_state(&internal_pos, state, internal_flags)
|
||||||
.await;
|
.await;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_time_of_day(&mut self, world: Resource<World>) -> u64 {
|
async fn get_time_of_day(&mut self, world: Resource<World>) -> wasmtime::Result<u64> {
|
||||||
let world_ref = world.downcast_ref(self);
|
Ok(self.get_world_res(&world)?.provider.get_time_of_day().await as u64)
|
||||||
world_ref.provider.get_time_of_day().await as u64
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn set_time_of_day(&mut self, world: Resource<World>, time: u64) {
|
async fn set_time_of_day(&mut self, world: Resource<World>, time: u64) -> wasmtime::Result<()> {
|
||||||
let world_ref = world.downcast_ref(self);
|
self.get_world_res(&world)?
|
||||||
world_ref.provider.set_time_of_day(time as i64).await;
|
.provider
|
||||||
|
.set_time_of_day(time as i64)
|
||||||
|
.await;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_world_age(&mut self, world: Resource<World>) -> u64 {
|
async fn get_world_age(&mut self, world: Resource<World>) -> wasmtime::Result<u64> {
|
||||||
let world_ref = world.downcast_ref(self);
|
Ok(self.get_world_res(&world)?.provider.get_world_age().await as u64)
|
||||||
world_ref.provider.get_world_age().await as u64
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_dimension(&mut self, world: Resource<World>) -> String {
|
async fn get_dimension(&mut self, world: Resource<World>) -> wasmtime::Result<String> {
|
||||||
let world_ref = world.downcast_ref(self);
|
Ok(self
|
||||||
world_ref.provider.dimension.minecraft_name.to_string()
|
.get_world_res(&world)?
|
||||||
|
.provider
|
||||||
|
.dimension
|
||||||
|
.minecraft_name
|
||||||
|
.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_top_block_y(&mut self, world: Resource<World>, x: i32, z: i32) -> i32 {
|
async fn get_top_block_y(
|
||||||
let world_ref = world.downcast_ref(self);
|
&mut self,
|
||||||
world_ref
|
world: Resource<World>,
|
||||||
|
x: i32,
|
||||||
|
z: i32,
|
||||||
|
) -> wasmtime::Result<i32> {
|
||||||
|
Ok(self
|
||||||
|
.get_world_res(&world)?
|
||||||
.provider
|
.provider
|
||||||
.get_top_block(pumpkin_util::math::vector2::Vector2::new(x, z))
|
.get_top_block(pumpkin_util::math::vector2::Vector2::new(x, z))
|
||||||
.await
|
.await)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_motion_blocking_height(&mut self, world: Resource<World>, x: i32, z: i32) -> i32 {
|
async fn get_motion_blocking_height(
|
||||||
let world_ref = world.downcast_ref(self);
|
&mut self,
|
||||||
world_ref.provider.get_motion_blocking_height(x, z).await
|
world: Resource<World>,
|
||||||
|
x: i32,
|
||||||
|
z: i32,
|
||||||
|
) -> wasmtime::Result<i32> {
|
||||||
|
Ok(self
|
||||||
|
.get_world_res(&world)?
|
||||||
|
.provider
|
||||||
|
.get_motion_blocking_height(x, z)
|
||||||
|
.await)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn is_raining(&mut self, world: Resource<World>) -> bool {
|
async fn is_raining(&mut self, world: Resource<World>) -> wasmtime::Result<bool> {
|
||||||
let world_ref = world.downcast_ref(self);
|
Ok(self.get_world_res(&world)?.provider.is_raining().await)
|
||||||
world_ref.provider.is_raining().await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn set_raining(&mut self, world: Resource<World>, raining: bool) {
|
async fn set_raining(&mut self, world: Resource<World>, raining: bool) -> wasmtime::Result<()> {
|
||||||
let world_ref = world.downcast_ref(self);
|
self.get_world_res(&world)?
|
||||||
world_ref.provider.set_raining(raining).await;
|
.provider
|
||||||
|
.set_raining(raining)
|
||||||
|
.await;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn is_thundering(&mut self, world: Resource<World>) -> bool {
|
async fn is_thundering(&mut self, world: Resource<World>) -> wasmtime::Result<bool> {
|
||||||
let world_ref = world.downcast_ref(self);
|
Ok(self.get_world_res(&world)?.provider.is_thundering().await)
|
||||||
world_ref.provider.is_thundering().await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn set_thundering(&mut self, world: Resource<World>, thundering: bool) {
|
async fn set_thundering(
|
||||||
let world_ref = world.downcast_ref(self);
|
&mut self,
|
||||||
world_ref.provider.set_thundering(thundering).await;
|
world: Resource<World>,
|
||||||
|
thundering: bool,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
self.get_world_res(&world)?
|
||||||
|
.provider
|
||||||
|
.set_thundering(thundering)
|
||||||
|
.await;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn broadcast_system_message(
|
async fn broadcast_system_message(
|
||||||
@ -202,19 +211,19 @@ impl pumpkin::plugin::world::HostWorld for PluginHostState {
|
|||||||
world: Resource<World>,
|
world: Resource<World>,
|
||||||
message: Resource<pumpkin::plugin::text::TextComponent>,
|
message: Resource<pumpkin::plugin::text::TextComponent>,
|
||||||
overlay: bool,
|
overlay: bool,
|
||||||
) {
|
) -> wasmtime::Result<()> {
|
||||||
let message = text_component_from_resource(self, &message).unwrap();
|
let msg = self.get_text_provider(&message)?;
|
||||||
let world_ref = world.downcast_ref(self);
|
self.get_world_res(&world)?
|
||||||
world_ref
|
|
||||||
.provider
|
.provider
|
||||||
.broadcast_system_message(&message, overlay)
|
.broadcast_system_message(&msg, overlay)
|
||||||
.await;
|
.await;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn drop(&mut self, rep: Resource<World>) -> wasmtime::Result<()> {
|
async fn drop(&mut self, rep: Resource<World>) -> wasmtime::Result<()> {
|
||||||
let _ = self
|
self.resource_table
|
||||||
.resource_table
|
.delete::<WorldResource>(Resource::new_own(rep.rep()))
|
||||||
.delete::<WorldResource>(Resource::new_own(rep.rep()));
|
.map_err(wasmtime::Error::from)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user