feat(plugin-api): add bossbars
This commit is contained in:
parent
71cddd72bc
commit
452edf8987
66
pumpkin-plugin-wit/v0.1/boss-bar.wit
Normal file
66
pumpkin-plugin-wit/v0.1/boss-bar.wit
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
interface boss-bar {
|
||||||
|
use text.{text-component};
|
||||||
|
use player.{player};
|
||||||
|
|
||||||
|
/// Represents the color of a boss bar.
|
||||||
|
enum boss-bar-color {
|
||||||
|
pink,
|
||||||
|
blue,
|
||||||
|
red,
|
||||||
|
green,
|
||||||
|
yellow,
|
||||||
|
purple,
|
||||||
|
white,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents the division (notches) of a boss bar.
|
||||||
|
enum boss-bar-division {
|
||||||
|
no-division,
|
||||||
|
notches-6,
|
||||||
|
notches-10,
|
||||||
|
notches-12,
|
||||||
|
notches-20,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents a boss bar that can be shown to players.
|
||||||
|
resource boss-bar {
|
||||||
|
/// Creates a new boss bar.
|
||||||
|
constructor(title: text-component, color: boss-bar-color, division: boss-bar-division);
|
||||||
|
|
||||||
|
/// Returns the title of this boss bar.
|
||||||
|
get-title: func() -> text-component;
|
||||||
|
|
||||||
|
/// Sets the title of this boss bar.
|
||||||
|
set-title: func(title: text-component);
|
||||||
|
|
||||||
|
/// Returns the health (0.0 to 1.0) of this boss bar.
|
||||||
|
get-health: func() -> f32;
|
||||||
|
|
||||||
|
/// Sets the health (0.0 to 1.0) of this boss bar.
|
||||||
|
set-health: func(health: f32);
|
||||||
|
|
||||||
|
/// Returns the color of this boss bar.
|
||||||
|
get-color: func() -> boss-bar-color;
|
||||||
|
|
||||||
|
/// Sets the color of this boss bar.
|
||||||
|
set-color: func(color: boss-bar-color);
|
||||||
|
|
||||||
|
/// Returns the division of this boss bar.
|
||||||
|
get-division: func() -> boss-bar-division;
|
||||||
|
|
||||||
|
/// Sets the division of this boss bar.
|
||||||
|
set-division: func(division: boss-bar-division);
|
||||||
|
|
||||||
|
/// Adds a player to this boss bar, making it visible to them.
|
||||||
|
add-player: func(player: player);
|
||||||
|
|
||||||
|
/// Removes a player from this boss bar, hiding it from them.
|
||||||
|
remove-player: func(player: player);
|
||||||
|
|
||||||
|
/// Returns a list of all players currently seeing this boss bar.
|
||||||
|
get-players: func() -> list<player>;
|
||||||
|
|
||||||
|
/// Removes this boss bar from all players and cleans it up.
|
||||||
|
remove-all: func();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -34,5 +34,17 @@ interface gui {
|
|||||||
constructor(%type: gui-type, title: text-component);
|
constructor(%type: gui-type, title: text-component);
|
||||||
set-item: func(slot: u32, item: item-stack);
|
set-item: func(slot: u32, item: item-stack);
|
||||||
get-item: func(slot: u32) -> option<item-stack>;
|
get-item: func(slot: u32) -> option<item-stack>;
|
||||||
|
|
||||||
|
/// Returns the type of this GUI.
|
||||||
|
get-type: func() -> gui-type;
|
||||||
|
|
||||||
|
/// Returns the title of this GUI.
|
||||||
|
get-title: func() -> text-component;
|
||||||
|
|
||||||
|
/// Returns the number of slots in this GUI.
|
||||||
|
get-size: func() -> u32;
|
||||||
|
|
||||||
|
/// Clears all items from the GUI.
|
||||||
|
clear-items: func();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,6 +33,8 @@ world plugin {
|
|||||||
import %world;
|
import %world;
|
||||||
/// Provides entity types and manipulation.
|
/// Provides entity types and manipulation.
|
||||||
import entity;
|
import entity;
|
||||||
|
/// Provides boss bar creation and management.
|
||||||
|
import boss-bar;
|
||||||
|
|
||||||
// --- Plugin-provided exports ---
|
// --- Plugin-provided exports ---
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
interface server {
|
interface server {
|
||||||
use player.{player};
|
use player.{player};
|
||||||
|
use common.{game-mode};
|
||||||
|
use %world.{%world};
|
||||||
|
|
||||||
/// Represents the difficulty setting of a Minecraft server.
|
/// Represents the difficulty setting of a Minecraft server.
|
||||||
enum difficulty {
|
enum difficulty {
|
||||||
@ -37,5 +39,44 @@ interface server {
|
|||||||
|
|
||||||
/// Searches for a player by their UUID string.
|
/// Searches for a player by their UUID string.
|
||||||
get-player-by-uuid: func(id: string) -> option<player>;
|
get-player-by-uuid: func(id: string) -> option<player>;
|
||||||
|
|
||||||
|
/// Returns a list of all worlds on this server.
|
||||||
|
get-all-worlds: func() -> list<%world>;
|
||||||
|
|
||||||
|
/// Gets a world by its dimension name (e.g., "minecraft:overworld").
|
||||||
|
get-world-by-name: func(name: string) -> option<%world>;
|
||||||
|
|
||||||
|
/// Broadcasts a system chat message to all players.
|
||||||
|
broadcast: func(message: string);
|
||||||
|
|
||||||
|
/// Returns the maximum number of players allowed on the server.
|
||||||
|
get-max-players: func() -> u32;
|
||||||
|
|
||||||
|
/// Returns whether the server is in hardcore mode.
|
||||||
|
is-hardcore: func() -> bool;
|
||||||
|
|
||||||
|
/// Returns whether the server is in online mode (authenticates with Mojang).
|
||||||
|
is-online-mode: func() -> bool;
|
||||||
|
|
||||||
|
/// Returns the server's Message of the Day (MOTD).
|
||||||
|
get-motd: func() -> string;
|
||||||
|
|
||||||
|
/// Returns whether the server has a whitelist enabled.
|
||||||
|
has-whitelist: func() -> bool;
|
||||||
|
|
||||||
|
/// Returns whether the server allows the Nether dimension.
|
||||||
|
get-allow-nether: func() -> bool;
|
||||||
|
|
||||||
|
/// Returns whether the server allows the End dimension.
|
||||||
|
get-allow-end: func() -> bool;
|
||||||
|
|
||||||
|
/// Returns the server's maximum view distance.
|
||||||
|
get-view-distance: func() -> u8;
|
||||||
|
|
||||||
|
/// Returns the server's maximum simulation distance.
|
||||||
|
get-simulation-distance: func() -> u8;
|
||||||
|
|
||||||
|
/// Returns the server's default gamemode.
|
||||||
|
get-default-gamemode: func() -> game-mode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,7 +35,6 @@ impl PlayerInteractEvent {
|
|||||||
///
|
///
|
||||||
/// - `player`: A reference-counted pointer to the player who triggered the event.
|
/// - `player`: A reference-counted pointer to the player who triggered the event.
|
||||||
/// - `action`: The type of interaction performed.
|
/// - `action`: The type of interaction performed.
|
||||||
/// - `item`: A reference-counted, mutex-protected item stack used during the interaction.
|
|
||||||
/// - `block`: The block that was interacted with.
|
/// - `block`: The block that was interacted with.
|
||||||
/// - `clicked_pos`: The optional position of the block that was clicked.
|
/// - `clicked_pos`: The optional position of the block that was clicked.
|
||||||
///
|
///
|
||||||
|
|||||||
@ -36,6 +36,9 @@ pub type EntityResource = WasmResource<Arc<dyn EntityBase>>;
|
|||||||
pub type WorldResource = WasmResource<Arc<World>>;
|
pub type WorldResource = WasmResource<Arc<World>>;
|
||||||
pub type ScoreboardResource = WasmResource<Arc<World>>;
|
pub type ScoreboardResource = WasmResource<Arc<World>>;
|
||||||
pub type GuiResource = WasmResource<Arc<Mutex<PluginGui>>>;
|
pub type GuiResource = WasmResource<Arc<Mutex<PluginGui>>>;
|
||||||
|
pub type BossBarResource = WasmResource<
|
||||||
|
Arc<Mutex<crate::plugin::loader::wasm::wasm_host::wit::v0_1::boss_bar::PluginBossBar>>,
|
||||||
|
>;
|
||||||
pub type TextComponentResource = WasmResource<TextComponent>;
|
pub type TextComponentResource = WasmResource<TextComponent>;
|
||||||
pub type CommandResource = WasmResource<CommandTree>;
|
pub type CommandResource = WasmResource<CommandTree>;
|
||||||
pub type CommandSenderResource = WasmResource<CommandSender>;
|
pub type CommandSenderResource = WasmResource<CommandSender>;
|
||||||
@ -125,6 +128,16 @@ impl PluginHostState {
|
|||||||
Ok(wasmtime::component::Resource::new_own(resource.rep()))
|
Ok(wasmtime::component::Resource::new_own(resource.rep()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_boss_bar<T>(
|
||||||
|
&mut self,
|
||||||
|
provider: Arc<
|
||||||
|
Mutex<crate::plugin::loader::wasm::wasm_host::wit::v0_1::boss_bar::PluginBossBar>,
|
||||||
|
>,
|
||||||
|
) -> wasmtime::Result<wasmtime::component::Resource<T>> {
|
||||||
|
let resource = self.resource_table.push(BossBarResource { provider })?;
|
||||||
|
Ok(wasmtime::component::Resource::new_own(resource.rep()))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add_text_component<T>(
|
pub fn add_text_component<T>(
|
||||||
&mut self,
|
&mut self,
|
||||||
provider: TextComponent,
|
provider: TextComponent,
|
||||||
|
|||||||
239
pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1/boss_bar.rs
Normal file
239
pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1/boss_bar.rs
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
use crate::plugin::loader::wasm::wasm_host::{
|
||||||
|
state::{BossBarResource, PlayerResource, PluginHostState},
|
||||||
|
wit::v0_1::pumpkin::plugin::boss_bar::{
|
||||||
|
self, BossBar, BossBarColor as WitColor, BossBarDivision as WitDivision,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use crate::server::Server;
|
||||||
|
use crate::world::bossbar::{Bossbar, BossbarColor, BossbarDivisions};
|
||||||
|
use std::sync::{Arc, Weak};
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
use uuid::Uuid;
|
||||||
|
use wasmtime::component::Resource;
|
||||||
|
|
||||||
|
pub struct PluginBossBar {
|
||||||
|
pub bossbar: Bossbar,
|
||||||
|
pub players: Vec<Uuid>,
|
||||||
|
pub server: Weak<Server>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PluginBossBar {
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(bossbar: Bossbar, server: Weak<Server>) -> Self {
|
||||||
|
Self {
|
||||||
|
bossbar,
|
||||||
|
players: Vec::new(),
|
||||||
|
server,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn player_from_resource(
|
||||||
|
state: &PluginHostState,
|
||||||
|
player: &Resource<
|
||||||
|
crate::plugin::loader::wasm::wasm_host::wit::v0_1::pumpkin::plugin::player::Player,
|
||||||
|
>,
|
||||||
|
) -> wasmtime::Result<std::sync::Arc<crate::entity::player::Player>> {
|
||||||
|
state
|
||||||
|
.resource_table
|
||||||
|
.get::<PlayerResource>(&Resource::new_own(player.rep()))
|
||||||
|
.map_err(wasmtime::Error::from)
|
||||||
|
.map(|resource| resource.provider.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PluginHostState {
|
||||||
|
fn get_bossbar_res(&self, res: &Resource<BossBar>) -> wasmtime::Result<&BossBarResource> {
|
||||||
|
self.resource_table
|
||||||
|
.get::<BossBarResource>(&Resource::new_own(res.rep()))
|
||||||
|
.map_err(wasmtime::Error::from)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl boss_bar::Host for PluginHostState {}
|
||||||
|
|
||||||
|
impl boss_bar::HostBossBar for PluginHostState {
|
||||||
|
async fn new(
|
||||||
|
&mut self,
|
||||||
|
title: Resource<
|
||||||
|
crate::plugin::loader::wasm::wasm_host::wit::v0_1::pumpkin::plugin::text::TextComponent,
|
||||||
|
>,
|
||||||
|
color: WitColor,
|
||||||
|
division: WitDivision,
|
||||||
|
) -> wasmtime::Result<Resource<BossBar>> {
|
||||||
|
let title = self.get_text_provider(&title)?;
|
||||||
|
let mut bossbar = Bossbar::new(title);
|
||||||
|
|
||||||
|
bossbar.color = match color {
|
||||||
|
WitColor::Pink => BossbarColor::Pink,
|
||||||
|
WitColor::Blue => BossbarColor::Blue,
|
||||||
|
WitColor::Red => BossbarColor::Red,
|
||||||
|
WitColor::Green => BossbarColor::Green,
|
||||||
|
WitColor::Yellow => BossbarColor::Yellow,
|
||||||
|
WitColor::Purple => BossbarColor::Purple,
|
||||||
|
WitColor::White => BossbarColor::White,
|
||||||
|
};
|
||||||
|
|
||||||
|
bossbar.division = match division {
|
||||||
|
WitDivision::NoDivision => BossbarDivisions::NoDivision,
|
||||||
|
WitDivision::Notches6 => BossbarDivisions::Notches6,
|
||||||
|
WitDivision::Notches10 => BossbarDivisions::Notches10,
|
||||||
|
WitDivision::Notches12 => BossbarDivisions::Notches12,
|
||||||
|
WitDivision::Notches20 => BossbarDivisions::Notches20,
|
||||||
|
};
|
||||||
|
|
||||||
|
let server = self.server.as_ref().expect("server not available").clone();
|
||||||
|
let plugin_bossbar = Arc::new(Mutex::new(PluginBossBar::new(
|
||||||
|
bossbar,
|
||||||
|
Arc::downgrade(&server),
|
||||||
|
)));
|
||||||
|
self.add_boss_bar(plugin_bossbar)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_title(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<BossBar>,
|
||||||
|
) -> wasmtime::Result<
|
||||||
|
Resource<
|
||||||
|
crate::plugin::loader::wasm::wasm_host::wit::v0_1::pumpkin::plugin::text::TextComponent,
|
||||||
|
>,
|
||||||
|
> {
|
||||||
|
let title = {
|
||||||
|
let bossbar = self.get_bossbar_res(&res)?.provider.lock().await;
|
||||||
|
bossbar.bossbar.title.clone()
|
||||||
|
};
|
||||||
|
self.add_text_component(title)
|
||||||
|
.map_err(|_| wasmtime::Error::msg("Failed to add text component"))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn set_title(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<BossBar>,
|
||||||
|
title: Resource<
|
||||||
|
crate::plugin::loader::wasm::wasm_host::wit::v0_1::pumpkin::plugin::text::TextComponent,
|
||||||
|
>,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
let title = self.get_text_provider(&title)?;
|
||||||
|
let mut pbb = self.get_bossbar_res(&res)?.provider.lock().await;
|
||||||
|
pbb.bossbar.title = title.clone();
|
||||||
|
if let Some(server) = pbb.server.upgrade() {
|
||||||
|
for uuid in &pbb.players {
|
||||||
|
if let Some(player) = server.get_player_by_uuid(*uuid) {
|
||||||
|
player
|
||||||
|
.update_bossbar_title(&pbb.bossbar.uuid, title.clone())
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_health(&mut self, res: Resource<BossBar>) -> wasmtime::Result<f32> {
|
||||||
|
let pbb = self.get_bossbar_res(&res)?.provider.lock().await;
|
||||||
|
Ok(pbb.bossbar.health)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn set_health(&mut self, res: Resource<BossBar>, health: f32) -> wasmtime::Result<()> {
|
||||||
|
let mut pbb = self.get_bossbar_res(&res)?.provider.lock().await;
|
||||||
|
pbb.bossbar.health = health;
|
||||||
|
if let Some(server) = pbb.server.upgrade() {
|
||||||
|
for uuid in &pbb.players {
|
||||||
|
if let Some(player) = server.get_player_by_uuid(*uuid) {
|
||||||
|
player
|
||||||
|
.update_bossbar_health(&pbb.bossbar.uuid, health)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_color(&mut self, _res: Resource<BossBar>) -> wasmtime::Result<WitColor> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
async fn set_color(
|
||||||
|
&mut self,
|
||||||
|
_res: Resource<BossBar>,
|
||||||
|
_color: WitColor,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
async fn get_division(&mut self, _res: Resource<BossBar>) -> wasmtime::Result<WitDivision> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
async fn set_division(
|
||||||
|
&mut self,
|
||||||
|
_res: Resource<BossBar>,
|
||||||
|
_division: WitDivision,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
async fn get_players(
|
||||||
|
&mut self,
|
||||||
|
_res: Resource<BossBar>,
|
||||||
|
) -> wasmtime::Result<
|
||||||
|
Vec<
|
||||||
|
Resource<
|
||||||
|
crate::plugin::loader::wasm::wasm_host::wit::v0_1::pumpkin::plugin::player::Player,
|
||||||
|
>,
|
||||||
|
>,
|
||||||
|
> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn add_player(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<BossBar>,
|
||||||
|
player: Resource<
|
||||||
|
crate::plugin::loader::wasm::wasm_host::wit::v0_1::pumpkin::plugin::player::Player,
|
||||||
|
>,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
let mut pbb = self.get_bossbar_res(&res)?.provider.lock().await;
|
||||||
|
let player = player_from_resource(self, &player)?;
|
||||||
|
let uuid = player.gameprofile.id;
|
||||||
|
|
||||||
|
if !pbb.players.contains(&uuid) {
|
||||||
|
pbb.players.push(uuid);
|
||||||
|
player.send_bossbar(&pbb.bossbar).await;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn remove_player(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<BossBar>,
|
||||||
|
player: Resource<
|
||||||
|
crate::plugin::loader::wasm::wasm_host::wit::v0_1::pumpkin::plugin::player::Player,
|
||||||
|
>,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
let mut pbb = self.get_bossbar_res(&res)?.provider.lock().await;
|
||||||
|
let player = player_from_resource(self, &player)?;
|
||||||
|
let uuid = player.gameprofile.id;
|
||||||
|
|
||||||
|
if let Some(idx) = pbb.players.iter().position(|&x| x == uuid) {
|
||||||
|
pbb.players.remove(idx);
|
||||||
|
player.remove_bossbar(pbb.bossbar.uuid).await;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn remove_all(&mut self, res: Resource<BossBar>) -> wasmtime::Result<()> {
|
||||||
|
let pbb = self.get_bossbar_res(&res)?.provider.lock().await;
|
||||||
|
if let Some(server) = pbb.server.upgrade() {
|
||||||
|
for uuid in &pbb.players {
|
||||||
|
if let Some(player) = server.get_player_by_uuid(*uuid) {
|
||||||
|
player.remove_bossbar(pbb.bossbar.uuid).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn drop(&mut self, res: Resource<BossBar>) -> wasmtime::Result<()> {
|
||||||
|
let rep = res.rep();
|
||||||
|
self.remove_all(res).await?;
|
||||||
|
self.resource_table
|
||||||
|
.delete::<BossBarResource>(Resource::new_own(rep))
|
||||||
|
.map_err(wasmtime::Error::from)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -117,6 +117,66 @@ impl gui::HostGui for PluginHostState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_type(&mut self, res: Resource<Gui>) -> wasmtime::Result<GuiType> {
|
||||||
|
let gui = self.get_gui_res(&res)?.provider.lock().await;
|
||||||
|
Ok(match gui.window_type {
|
||||||
|
pumpkin_data::screen::WindowType::Generic9x1 => GuiType::Generic9x1,
|
||||||
|
pumpkin_data::screen::WindowType::Generic9x2 => GuiType::Generic9x2,
|
||||||
|
pumpkin_data::screen::WindowType::Generic9x3 => GuiType::Generic9x3,
|
||||||
|
pumpkin_data::screen::WindowType::Generic9x4 => GuiType::Generic9x4,
|
||||||
|
pumpkin_data::screen::WindowType::Generic9x5 => GuiType::Generic9x5,
|
||||||
|
pumpkin_data::screen::WindowType::Generic9x6 => GuiType::Generic9x6,
|
||||||
|
pumpkin_data::screen::WindowType::Generic3x3 => GuiType::Generic3x3,
|
||||||
|
pumpkin_data::screen::WindowType::Crafter3x3 => GuiType::Crafter3x3,
|
||||||
|
pumpkin_data::screen::WindowType::Anvil => GuiType::Anvil,
|
||||||
|
pumpkin_data::screen::WindowType::Beacon => GuiType::Beacon,
|
||||||
|
pumpkin_data::screen::WindowType::BlastFurnace => GuiType::BlastFurnace,
|
||||||
|
pumpkin_data::screen::WindowType::BrewingStand => GuiType::BrewingStand,
|
||||||
|
pumpkin_data::screen::WindowType::Crafting => GuiType::Crafting,
|
||||||
|
pumpkin_data::screen::WindowType::Enchantment => GuiType::Enchantment,
|
||||||
|
pumpkin_data::screen::WindowType::Furnace => GuiType::Furnace,
|
||||||
|
pumpkin_data::screen::WindowType::Grindstone => GuiType::Grindstone,
|
||||||
|
pumpkin_data::screen::WindowType::Hopper => GuiType::Hopper,
|
||||||
|
pumpkin_data::screen::WindowType::Lectern => GuiType::Lectern,
|
||||||
|
pumpkin_data::screen::WindowType::Loom => GuiType::Loom,
|
||||||
|
pumpkin_data::screen::WindowType::Merchant => GuiType::Merchant,
|
||||||
|
pumpkin_data::screen::WindowType::ShulkerBox => GuiType::ShulkerBox,
|
||||||
|
pumpkin_data::screen::WindowType::Smithing => GuiType::Smithing,
|
||||||
|
pumpkin_data::screen::WindowType::Smoker => GuiType::Smoker,
|
||||||
|
pumpkin_data::screen::WindowType::CartographyTable => GuiType::CartographyTable,
|
||||||
|
pumpkin_data::screen::WindowType::Stonecutter => GuiType::Stonecutter,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_title(
|
||||||
|
&mut self,
|
||||||
|
res: Resource<Gui>,
|
||||||
|
) -> wasmtime::Result<
|
||||||
|
Resource<
|
||||||
|
crate::plugin::loader::wasm::wasm_host::wit::v0_1::pumpkin::plugin::text::TextComponent,
|
||||||
|
>,
|
||||||
|
> {
|
||||||
|
let title = {
|
||||||
|
let gui = self.get_gui_res(&res)?.provider.lock().await;
|
||||||
|
gui.title.clone()
|
||||||
|
};
|
||||||
|
self.add_text_component(title)
|
||||||
|
.map_err(|_| wasmtime::Error::msg("Failed to add text component resource"))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_size(&mut self, res: Resource<Gui>) -> wasmtime::Result<u32> {
|
||||||
|
use pumpkin_world::inventory::Inventory;
|
||||||
|
let gui = self.get_gui_res(&res)?.provider.lock().await;
|
||||||
|
Ok(gui.inventory.size() as u32)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn clear_items(&mut self, res: Resource<Gui>) -> wasmtime::Result<()> {
|
||||||
|
use pumpkin_world::inventory::Clearable;
|
||||||
|
let gui = self.get_gui_res(&res)?.provider.lock().await;
|
||||||
|
gui.inventory.clear().await;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
async fn drop(&mut self, rep: Resource<Gui>) -> wasmtime::Result<()> {
|
async fn drop(&mut self, rep: Resource<Gui>) -> wasmtime::Result<()> {
|
||||||
self.resource_table
|
self.resource_table
|
||||||
.delete::<GuiResource>(Resource::new_own(rep.rep()))
|
.delete::<GuiResource>(Resource::new_own(rep.rep()))
|
||||||
|
|||||||
@ -7,6 +7,7 @@ use wasmtime::component::{HasSelf, InstancePre, Linker, bindgen};
|
|||||||
use wasmtime::{Engine, Store};
|
use wasmtime::{Engine, Store};
|
||||||
|
|
||||||
pub mod block_entity;
|
pub mod block_entity;
|
||||||
|
pub mod boss_bar;
|
||||||
pub mod commands;
|
pub mod commands;
|
||||||
pub mod common;
|
pub mod common;
|
||||||
pub mod context;
|
pub mod context;
|
||||||
|
|||||||
@ -113,6 +113,160 @@ impl pumpkin::plugin::server::HostServer for PluginHostState {
|
|||||||
.transpose()
|
.transpose()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_all_worlds(
|
||||||
|
&mut self,
|
||||||
|
_rep: Resource<Server>,
|
||||||
|
) -> wasmtime::Result<Vec<Resource<pumpkin::plugin::world::World>>> {
|
||||||
|
let server = self
|
||||||
|
.server
|
||||||
|
.as_ref()
|
||||||
|
.ok_or_else(|| wasmtime::Error::msg("Server not available"))?;
|
||||||
|
|
||||||
|
Ok(server
|
||||||
|
.worlds
|
||||||
|
.load()
|
||||||
|
.iter()
|
||||||
|
.map(|world| {
|
||||||
|
self.add_world(world.clone())
|
||||||
|
.expect("failed to add world resource")
|
||||||
|
})
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_world_by_name(
|
||||||
|
&mut self,
|
||||||
|
_rep: Resource<Server>,
|
||||||
|
name: String,
|
||||||
|
) -> wasmtime::Result<Option<Resource<pumpkin::plugin::world::World>>> {
|
||||||
|
let server = self
|
||||||
|
.server
|
||||||
|
.as_ref()
|
||||||
|
.ok_or_else(|| wasmtime::Error::msg("Server not available"))?;
|
||||||
|
|
||||||
|
Ok(server
|
||||||
|
.worlds
|
||||||
|
.load()
|
||||||
|
.iter()
|
||||||
|
.find(|world| world.dimension.minecraft_name == name)
|
||||||
|
.map(|world| {
|
||||||
|
self.add_world(world.clone())
|
||||||
|
.expect("failed to add world resource")
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn broadcast(&mut self, _rep: Resource<Server>, message: String) -> wasmtime::Result<()> {
|
||||||
|
let server = self
|
||||||
|
.server
|
||||||
|
.as_ref()
|
||||||
|
.ok_or_else(|| wasmtime::Error::msg("Server not available"))?;
|
||||||
|
|
||||||
|
server
|
||||||
|
.broadcast_message(
|
||||||
|
&pumpkin_util::text::TextComponent::text(message),
|
||||||
|
&pumpkin_util::text::TextComponent::text("Server"),
|
||||||
|
0,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_max_players(&mut self, _rep: Resource<Server>) -> wasmtime::Result<u32> {
|
||||||
|
let server = self
|
||||||
|
.server
|
||||||
|
.as_ref()
|
||||||
|
.ok_or_else(|| wasmtime::Error::msg("Server not available"))?;
|
||||||
|
|
||||||
|
Ok(server.basic_config.max_players)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn is_hardcore(&mut self, _rep: Resource<Server>) -> wasmtime::Result<bool> {
|
||||||
|
let server = self
|
||||||
|
.server
|
||||||
|
.as_ref()
|
||||||
|
.ok_or_else(|| wasmtime::Error::msg("Server not available"))?;
|
||||||
|
|
||||||
|
Ok(server.basic_config.hardcore)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn is_online_mode(&mut self, _rep: Resource<Server>) -> wasmtime::Result<bool> {
|
||||||
|
let server = self
|
||||||
|
.server
|
||||||
|
.as_ref()
|
||||||
|
.ok_or_else(|| wasmtime::Error::msg("Server not available"))?;
|
||||||
|
|
||||||
|
Ok(server.advanced_config.networking.authentication.enabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_motd(&mut self, _rep: Resource<Server>) -> wasmtime::Result<String> {
|
||||||
|
let server = self
|
||||||
|
.server
|
||||||
|
.as_ref()
|
||||||
|
.ok_or_else(|| wasmtime::Error::msg("Server not available"))?;
|
||||||
|
|
||||||
|
Ok(server.basic_config.motd.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn has_whitelist(&mut self, _rep: Resource<Server>) -> wasmtime::Result<bool> {
|
||||||
|
let server = self
|
||||||
|
.server
|
||||||
|
.as_ref()
|
||||||
|
.ok_or_else(|| wasmtime::Error::msg("Server not available"))?;
|
||||||
|
|
||||||
|
Ok(server.basic_config.white_list)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_allow_nether(&mut self, _rep: Resource<Server>) -> wasmtime::Result<bool> {
|
||||||
|
let server = self
|
||||||
|
.server
|
||||||
|
.as_ref()
|
||||||
|
.ok_or_else(|| wasmtime::Error::msg("Server not available"))?;
|
||||||
|
|
||||||
|
Ok(server.basic_config.allow_nether)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_allow_end(&mut self, _rep: Resource<Server>) -> wasmtime::Result<bool> {
|
||||||
|
let server = self
|
||||||
|
.server
|
||||||
|
.as_ref()
|
||||||
|
.ok_or_else(|| wasmtime::Error::msg("Server not available"))?;
|
||||||
|
|
||||||
|
Ok(server.basic_config.allow_end)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_view_distance(&mut self, _rep: Resource<Server>) -> wasmtime::Result<u8> {
|
||||||
|
let server = self
|
||||||
|
.server
|
||||||
|
.as_ref()
|
||||||
|
.ok_or_else(|| wasmtime::Error::msg("Server not available"))?;
|
||||||
|
|
||||||
|
Ok(server.basic_config.view_distance.get())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_simulation_distance(&mut self, _rep: Resource<Server>) -> wasmtime::Result<u8> {
|
||||||
|
let server = self
|
||||||
|
.server
|
||||||
|
.as_ref()
|
||||||
|
.ok_or_else(|| wasmtime::Error::msg("Server not available"))?;
|
||||||
|
|
||||||
|
Ok(server.basic_config.simulation_distance.get())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_default_gamemode(
|
||||||
|
&mut self,
|
||||||
|
_rep: Resource<Server>,
|
||||||
|
) -> wasmtime::Result<pumpkin::plugin::common::GameMode> {
|
||||||
|
let server = self
|
||||||
|
.server
|
||||||
|
.as_ref()
|
||||||
|
.ok_or_else(|| wasmtime::Error::msg("Server not available"))?;
|
||||||
|
|
||||||
|
Ok(super::events::to_wasm_game_mode(
|
||||||
|
server.basic_config.default_gamemode,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
async fn drop(&mut self, rep: Resource<Server>) -> wasmtime::Result<()> {
|
async fn drop(&mut self, rep: Resource<Server>) -> wasmtime::Result<()> {
|
||||||
self.resource_table
|
self.resource_table
|
||||||
.delete::<ServerResource>(Resource::new_own(rep.rep()))
|
.delete::<ServerResource>(Resource::new_own(rep.rep()))
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user