mirror of
https://github.com/Pumpkin-MC/Pumpkin.git
synced 2026-08-30 20:14:23 +00:00
feat(plugin): native bedrock features
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
/* This file is generated. Do not edit manually. */
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum ScoreboardDisplaySlot {
|
||||
List,
|
||||
Sidebar,
|
||||
|
||||
Submodule crates/pumpkin-plugin-wit updated: 160251fb0b...8e006930be
@@ -75,7 +75,7 @@ pub enum Mode {
|
||||
Update,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum RenderType {
|
||||
Integer,
|
||||
Hearts,
|
||||
|
||||
@@ -385,7 +385,7 @@ impl KnownPack<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum NumberFormat {
|
||||
/// Show nothing.
|
||||
Blank,
|
||||
|
||||
@@ -60,15 +60,12 @@ impl CommandExecutor for ObjectivesAddExecutor {
|
||||
return Err(DUPLICATE_OBJECTIVE_ERROR.create_without_context());
|
||||
}
|
||||
|
||||
let obj_name_static = Box::leak(objective_name.to_string().into_boxed_str());
|
||||
let criterion_static = Box::leak(criterion.to_string().into_boxed_str());
|
||||
|
||||
let new_objective = ScoreboardObjective::new(
|
||||
obj_name_static,
|
||||
objective_name,
|
||||
display_name.clone(),
|
||||
RenderType::Integer,
|
||||
None,
|
||||
criterion_static,
|
||||
criterion,
|
||||
);
|
||||
|
||||
scoreboard.add_objective(world, new_objective).await;
|
||||
@@ -128,8 +125,8 @@ impl CommandExecutor for PlayersEnableExecutor {
|
||||
let number_format = current_score.and_then(|s| s.number_format.clone());
|
||||
|
||||
let updated_score = ScoreboardScore {
|
||||
entity_name: Box::leak(player_name.clone().into_boxed_str()),
|
||||
objective_name: Box::leak(objective_name.to_string().into_boxed_str()),
|
||||
entity_name: player_name.clone(),
|
||||
objective_name: objective_name.to_string(),
|
||||
value: VarInt(value),
|
||||
display_name,
|
||||
number_format,
|
||||
|
||||
@@ -122,7 +122,7 @@ impl CommandExecutor for TeamAddExecutor {
|
||||
players: vec![],
|
||||
};
|
||||
|
||||
scoreboard.add_team(world, new_team);
|
||||
scoreboard.add_team(world, new_team).await;
|
||||
|
||||
context
|
||||
.source
|
||||
@@ -158,7 +158,7 @@ impl CommandExecutor for TeamRemoveExecutor {
|
||||
|
||||
let team_display_name = team.display_name.clone();
|
||||
|
||||
scoreboard.remove_team(world, team_name);
|
||||
scoreboard.remove_team(world, team_name).await;
|
||||
|
||||
context
|
||||
.source
|
||||
@@ -200,7 +200,9 @@ impl CommandExecutor for TeamEmptyExecutor {
|
||||
}
|
||||
|
||||
for player in &players_to_remove {
|
||||
scoreboard.remove_player_from_team(world, team_name, player);
|
||||
scoreboard
|
||||
.remove_player_from_team(world, team_name, player)
|
||||
.await;
|
||||
}
|
||||
|
||||
context
|
||||
@@ -262,7 +264,9 @@ impl CommandExecutor for TeamJoinExecutor {
|
||||
|
||||
let count = entity_names.len();
|
||||
for name in &entity_names {
|
||||
scoreboard.add_player_to_team(world, team_name, name.clone());
|
||||
scoreboard
|
||||
.add_player_to_team(world, team_name, name.clone())
|
||||
.await;
|
||||
}
|
||||
|
||||
let msg = if count == 1 {
|
||||
@@ -327,7 +331,9 @@ impl CommandExecutor for TeamLeaveExecutor {
|
||||
}
|
||||
}
|
||||
if let Some(team_name) = found_team {
|
||||
scoreboard.remove_player_from_team(world, &team_name, name);
|
||||
scoreboard
|
||||
.remove_player_from_team(world, &team_name, name)
|
||||
.await;
|
||||
removed_count += 1;
|
||||
}
|
||||
}
|
||||
@@ -474,7 +480,7 @@ impl CommandExecutor for TeamModifyColorResetExecutor {
|
||||
|
||||
team.color = NamedColor::White;
|
||||
let team_display_name = team.display_name.clone();
|
||||
scoreboard.update_team(world, team);
|
||||
scoreboard.update_team(world, team).await;
|
||||
|
||||
context
|
||||
.source
|
||||
@@ -519,7 +525,7 @@ impl CommandExecutor for TeamModifyColorExecutor {
|
||||
|
||||
team.color = new_color;
|
||||
let team_display_name = team.display_name.clone();
|
||||
scoreboard.update_team(world, team);
|
||||
scoreboard.update_team(world, team).await;
|
||||
|
||||
context
|
||||
.source
|
||||
@@ -565,7 +571,7 @@ impl CommandExecutor for TeamModifyDisplayNameExecutor {
|
||||
|
||||
team.display_name = new_display_name.clone();
|
||||
let team_display_name = team.display_name.clone();
|
||||
scoreboard.update_team(world, team);
|
||||
scoreboard.update_team(world, team).await;
|
||||
|
||||
context
|
||||
.source
|
||||
@@ -607,7 +613,7 @@ impl CommandExecutor for TeamModifyPrefixExecutor {
|
||||
let new_prefix = TextComponent::text(new_prefix_str.to_string());
|
||||
team.player_prefix = new_prefix.clone();
|
||||
let team_display_name = team.display_name.clone();
|
||||
scoreboard.update_team(world, team);
|
||||
scoreboard.update_team(world, team).await;
|
||||
|
||||
context
|
||||
.source
|
||||
@@ -649,7 +655,7 @@ impl CommandExecutor for TeamModifySuffixExecutor {
|
||||
let new_suffix = TextComponent::text(new_suffix_str.to_string());
|
||||
team.player_suffix = new_suffix.clone();
|
||||
let team_display_name = team.display_name.clone();
|
||||
scoreboard.update_team(world, team);
|
||||
scoreboard.update_team(world, team).await;
|
||||
|
||||
context
|
||||
.source
|
||||
@@ -703,7 +709,7 @@ impl CommandExecutor for TeamModifyFriendlyFireExecutor {
|
||||
}
|
||||
|
||||
let team_display_name = team.display_name.clone();
|
||||
scoreboard.update_team(world, team);
|
||||
scoreboard.update_team(world, team).await;
|
||||
|
||||
let key = if value {
|
||||
translation::java::COMMANDS_TEAM_OPTION_FRIENDLYFIRE_ENABLED
|
||||
@@ -761,7 +767,7 @@ impl CommandExecutor for TeamModifySeeFriendlyInvisiblesExecutor {
|
||||
}
|
||||
|
||||
let team_display_name = team.display_name.clone();
|
||||
scoreboard.update_team(world, team);
|
||||
scoreboard.update_team(world, team).await;
|
||||
|
||||
let key = if value {
|
||||
translation::java::COMMANDS_TEAM_OPTION_SEEFRIENDLYINVISIBLES_ENABLED
|
||||
@@ -829,7 +835,7 @@ impl CommandExecutor for TeamModifyNametagVisibilityExecutor {
|
||||
};
|
||||
|
||||
let team_display_name = team.display_name.clone();
|
||||
scoreboard.update_team(world, team);
|
||||
scoreboard.update_team(world, team).await;
|
||||
|
||||
context
|
||||
.source
|
||||
@@ -931,7 +937,7 @@ impl CommandExecutor for TeamModifyCollisionRuleExecutor {
|
||||
};
|
||||
|
||||
let team_display_name = team.display_name.clone();
|
||||
scoreboard.update_team(world, team);
|
||||
scoreboard.update_team(world, team).await;
|
||||
|
||||
context
|
||||
.source
|
||||
|
||||
@@ -69,8 +69,8 @@ impl CommandExecutor for SimpleTriggerExecutor {
|
||||
let new_value = current_value + 1;
|
||||
|
||||
let updated_score = ScoreboardScore {
|
||||
entity_name: Box::leak(player_name.clone().into_boxed_str()),
|
||||
objective_name: Box::leak(objective_name.to_string().into_boxed_str()),
|
||||
entity_name: player_name.clone(),
|
||||
objective_name: objective_name.to_string(),
|
||||
value: VarInt(new_value),
|
||||
display_name: None,
|
||||
number_format: None,
|
||||
@@ -139,8 +139,8 @@ impl CommandExecutor for AddTriggerExecutor {
|
||||
let new_value = current_value + value;
|
||||
|
||||
let updated_score = ScoreboardScore {
|
||||
entity_name: Box::leak(player_name.clone().into_boxed_str()),
|
||||
objective_name: Box::leak(objective_name.to_string().into_boxed_str()),
|
||||
entity_name: player_name.clone(),
|
||||
objective_name: objective_name.to_string(),
|
||||
value: VarInt(new_value),
|
||||
display_name: None,
|
||||
number_format: None,
|
||||
@@ -204,8 +204,8 @@ impl CommandExecutor for SetTriggerExecutor {
|
||||
}
|
||||
|
||||
let updated_score = ScoreboardScore {
|
||||
entity_name: Box::leak(player_name.clone().into_boxed_str()),
|
||||
objective_name: Box::leak(objective_name.to_string().into_boxed_str()),
|
||||
entity_name: player_name.clone(),
|
||||
objective_name: objective_name.to_string(),
|
||||
value: VarInt(value),
|
||||
display_name: None,
|
||||
number_format: None,
|
||||
|
||||
@@ -10,6 +10,8 @@ use std::sync::atomic::{AtomicBool, AtomicI8, AtomicI32, AtomicU8, AtomicU32, Or
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use crate::world::scoreboard::{BedrockScoreboard, Scoreboard};
|
||||
use advancement::PlayerAdvancement;
|
||||
use arc_swap::ArcSwap;
|
||||
use crossbeam::atomic::AtomicCell;
|
||||
use crossbeam::channel::Receiver;
|
||||
@@ -37,7 +39,162 @@ use tokio::task::JoinHandle;
|
||||
use tracing::{debug, warn};
|
||||
use uuid::Uuid;
|
||||
|
||||
use advancement::PlayerAdvancement;
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum CustomScoreboard {
|
||||
Java(Scoreboard),
|
||||
Bedrock(BedrockScoreboard),
|
||||
}
|
||||
|
||||
impl From<Scoreboard> for CustomScoreboard {
|
||||
fn from(sb: Scoreboard) -> Self {
|
||||
Self::Java(sb)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BedrockScoreboard> for CustomScoreboard {
|
||||
fn from(sb: BedrockScoreboard) -> Self {
|
||||
Self::Bedrock(sb)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct JavaPlayer<'a>(pub &'a Player);
|
||||
|
||||
impl JavaPlayer<'_> {
|
||||
pub async fn send_packet<C: pumpkin_protocol::ClientPacket + Sync>(&self, packet: &C) {
|
||||
if let ClientPlatform::Java(client) = self.0.client.as_ref() {
|
||||
client.enqueue_packet(packet).await;
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn send_custom_payload(&self, channel: &str, data: &[u8]) {
|
||||
if let ClientPlatform::Java(java) = self.0.client.as_ref() {
|
||||
java.enqueue_packet(&CCustomPayload::new(channel, data))
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn send_stats(&self) {
|
||||
self.0.send_stats().await;
|
||||
}
|
||||
|
||||
pub async fn set_scoreboard(&self, scoreboard: Option<Scoreboard>) {
|
||||
*self.0.custom_scoreboard.lock().await = scoreboard.map(CustomScoreboard::Java);
|
||||
self.0.send_scoreboard().await;
|
||||
}
|
||||
|
||||
pub async fn reset_scoreboard(&self) {
|
||||
self.set_scoreboard(None).await;
|
||||
}
|
||||
|
||||
pub async fn get_scoreboard(&self) -> Option<Scoreboard> {
|
||||
let guard = self.0.custom_scoreboard.lock().await;
|
||||
if let Some(CustomScoreboard::Java(sb)) = guard.as_ref() {
|
||||
Some(sb.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct BedrockPlayer<'a>(pub &'a Player);
|
||||
|
||||
impl BedrockPlayer<'_> {
|
||||
pub async fn send_packet<P: pumpkin_protocol::BClientPacket + Sync>(&self, packet: &P) {
|
||||
if let ClientPlatform::Bedrock(client) = self.0.client.as_ref() {
|
||||
client.send_game_packet(packet).await;
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn set_scoreboard(&self, scoreboard: Option<BedrockScoreboard>) {
|
||||
*self.0.custom_scoreboard.lock().await = scoreboard.map(CustomScoreboard::Bedrock);
|
||||
self.0.send_scoreboard().await;
|
||||
}
|
||||
|
||||
pub async fn reset_scoreboard(&self) {
|
||||
self.set_scoreboard(None).await;
|
||||
}
|
||||
|
||||
pub async fn get_scoreboard(&self) -> Option<BedrockScoreboard> {
|
||||
let guard = self.0.custom_scoreboard.lock().await;
|
||||
if let Some(CustomScoreboard::Bedrock(sb)) = guard.as_ref() {
|
||||
Some(sb.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn client_data(&self) -> Option<Arc<pumpkin_protocol::bedrock::server::login::ClientData>> {
|
||||
if let ClientPlatform::Bedrock(client) = self.0.client.as_ref() {
|
||||
let data = client.client_data.load();
|
||||
(**data).clone()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn device_os(&self) -> Option<i32> {
|
||||
self.client_data().map(|d| d.device_os)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn device_id(&self) -> Option<String> {
|
||||
self.client_data().map(|d| d.device_id.clone())
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn device_model(&self) -> Option<String> {
|
||||
self.client_data().map(|d| d.device_model.clone())
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn game_version(&self) -> Option<String> {
|
||||
self.client_data().map(|d| d.game_version.clone())
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn language_code(&self) -> Option<String> {
|
||||
self.client_data().map(|d| d.language_code.clone())
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn current_input_mode(&self) -> Option<i32> {
|
||||
self.client_data().map(|d| d.current_input_mode)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn default_input_mode(&self) -> Option<i32> {
|
||||
self.client_data().map(|d| d.default_input_mode)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn ui_profile(&self) -> Option<i32> {
|
||||
self.client_data().map(|d| d.ui_profile)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn gui_scale(&self) -> Option<i32> {
|
||||
self.client_data().map(|d| d.gui_scale)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn max_view_distance(&self) -> Option<i32> {
|
||||
self.client_data().map(|d| d.max_view_distance)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn memory_tier(&self) -> Option<i32> {
|
||||
self.client_data().map(|d| d.memory_tier)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn graphics_mode(&self) -> Option<i32> {
|
||||
self.client_data().map(|d| d.graphics_mode)
|
||||
}
|
||||
}
|
||||
use pumpkin_data::attributes::Attributes;
|
||||
use pumpkin_data::block_properties::{BlockProperties, HorizontalFacing};
|
||||
use pumpkin_data::damage::DamageType;
|
||||
@@ -594,6 +751,7 @@ pub struct Player {
|
||||
pub tab_list_listed: AtomicBool,
|
||||
pub per_player_time: AtomicCell<Option<(u64, bool)>>,
|
||||
pub per_player_weather: AtomicCell<Option<PlayerWeather>>,
|
||||
pub custom_scoreboard: Mutex<Option<CustomScoreboard>>,
|
||||
pub compass_target: AtomicCell<Option<pumpkin_util::math::position::BlockPos>>,
|
||||
pub respawn_location: AtomicCell<Option<pumpkin_util::math::position::BlockPos>>,
|
||||
pub hidden_players: Mutex<std::collections::HashSet<uuid::Uuid>>,
|
||||
@@ -853,6 +1011,7 @@ impl Player {
|
||||
tab_list_listed: AtomicBool::new(true),
|
||||
per_player_time: AtomicCell::new(None),
|
||||
per_player_weather: AtomicCell::new(None),
|
||||
custom_scoreboard: Mutex::new(None),
|
||||
compass_target: AtomicCell::new(None),
|
||||
respawn_location: AtomicCell::new(None),
|
||||
hidden_players: Mutex::new(std::collections::HashSet::new()),
|
||||
@@ -2760,14 +2919,16 @@ impl Player {
|
||||
.await;
|
||||
}
|
||||
|
||||
pub async fn set_player_time(&self, world: &World, time: u64, relative: bool) {
|
||||
pub async fn set_player_time(&self, time: u64, relative: bool) {
|
||||
let world = self.world();
|
||||
self.per_player_time.store(Some((time, relative)));
|
||||
self.send_time(world).await;
|
||||
self.send_time(&world).await;
|
||||
}
|
||||
|
||||
pub async fn reset_player_time(&self, world: &World) {
|
||||
pub async fn reset_player_time(&self) {
|
||||
let world = self.world();
|
||||
self.per_player_time.store(None);
|
||||
self.send_time(world).await;
|
||||
self.send_time(&world).await;
|
||||
}
|
||||
|
||||
pub fn get_player_time(&self) -> Option<u64> {
|
||||
@@ -2790,6 +2951,66 @@ impl Player {
|
||||
self.per_player_weather.load()
|
||||
}
|
||||
|
||||
pub async fn send_editioned<
|
||||
J: pumpkin_protocol::ClientPacket + Sync,
|
||||
B: pumpkin_protocol::BClientPacket + Sync,
|
||||
>(
|
||||
&self,
|
||||
je_packet: &J,
|
||||
be_packet: &B,
|
||||
) {
|
||||
match self.client.as_ref() {
|
||||
ClientPlatform::Java(client) => client.enqueue_packet(je_packet).await,
|
||||
ClientPlatform::Bedrock(client) => client.enqueue_packet(be_packet).await,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn send_client_packet<C: pumpkin_protocol::ClientPacket + Sync>(&self, packet: &C) {
|
||||
if let ClientPlatform::Java(client) = self.client.as_ref() {
|
||||
client.enqueue_packet(packet).await;
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn as_java(&self) -> Option<JavaPlayer<'_>> {
|
||||
matches!(self.client.as_ref(), ClientPlatform::Java(_)).then(|| JavaPlayer(self))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn as_bedrock(&self) -> Option<BedrockPlayer<'_>> {
|
||||
matches!(self.client.as_ref(), ClientPlatform::Bedrock(_)).then(|| BedrockPlayer(self))
|
||||
}
|
||||
|
||||
pub async fn reset_scoreboard(&self) {
|
||||
*self.custom_scoreboard.lock().await = None;
|
||||
self.send_scoreboard().await;
|
||||
}
|
||||
|
||||
pub async fn send_scoreboard(&self) {
|
||||
let guard = self.custom_scoreboard.lock().await;
|
||||
match guard.as_ref() {
|
||||
Some(CustomScoreboard::Java(custom))
|
||||
if matches!(self.client.as_ref(), ClientPlatform::Java(_)) =>
|
||||
{
|
||||
custom.send_to_player(self).await;
|
||||
}
|
||||
Some(CustomScoreboard::Bedrock(custom))
|
||||
if matches!(self.client.as_ref(), ClientPlatform::Bedrock(_)) =>
|
||||
{
|
||||
custom.send_to_player(self).await;
|
||||
}
|
||||
_ => {
|
||||
drop(guard);
|
||||
self.world()
|
||||
.scoreboard
|
||||
.lock()
|
||||
.await
|
||||
.send_to_player(self)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn set_compass_target(&self, pos: pumpkin_util::math::position::BlockPos) {
|
||||
use pumpkin_protocol::java::client::play::CPlayerSpawnPosition;
|
||||
self.compass_target.store(Some(pos));
|
||||
@@ -2822,6 +3043,85 @@ impl Player {
|
||||
!self.hidden_players.lock().await.contains(other_id)
|
||||
}
|
||||
|
||||
pub async fn can_see_player(&self, other_id: &uuid::Uuid) -> bool {
|
||||
self.can_see(other_id).await
|
||||
}
|
||||
|
||||
// --- Experience & Leveling API ---
|
||||
pub async fn add_experience(self: &Arc<Self>, points: i32) {
|
||||
self.add_experience_points(points).await;
|
||||
}
|
||||
|
||||
pub async fn add_levels(&self, levels: i32) {
|
||||
self.add_experience_levels(levels).await;
|
||||
}
|
||||
|
||||
pub fn get_experience_level(&self) -> i32 {
|
||||
self.experience_level.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
pub fn get_experience_progress(&self) -> f32 {
|
||||
self.experience_progress.load()
|
||||
}
|
||||
|
||||
pub fn get_total_experience(&self) -> i32 {
|
||||
self.experience_points.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
pub async fn set_experience_progress(&self, progress: f32) {
|
||||
let level = self.get_experience_level();
|
||||
let max_points = experience::points_in_level(level);
|
||||
let points = (progress.clamp(0.0, 1.0) * max_points as f32) as i32;
|
||||
self.set_experience(level, progress, points).await;
|
||||
}
|
||||
|
||||
pub async fn set_total_experience(&self, points: i32) {
|
||||
self.set_experience_points(points).await;
|
||||
}
|
||||
|
||||
// --- Item Cooldown System ---
|
||||
pub async fn set_item_cooldown(&self, item_id: &str, ticks: i32) {
|
||||
self.start_cooldown(item_id.to_string(), ticks).await;
|
||||
}
|
||||
|
||||
pub async fn get_item_cooldown(&self, item_id: &str) -> Option<i32> {
|
||||
let cooldowns = self.item_cooldowns.lock().await;
|
||||
if let Some(cooldown) = cooldowns.get(item_id) {
|
||||
let current_tick = self.tick_counter.load(Ordering::Relaxed);
|
||||
let elapsed = current_tick - cooldown.start_tick;
|
||||
if elapsed < cooldown.duration {
|
||||
return Some(cooldown.duration - elapsed);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub async fn has_item_cooldown(&self, item_id: &str) -> bool {
|
||||
self.is_on_cooldown(item_id).await
|
||||
}
|
||||
|
||||
// --- Tab List & Display Names ---
|
||||
pub fn set_tab_list_ping(&self, latency_ms: i32) {
|
||||
self.set_tab_list_latency(latency_ms);
|
||||
}
|
||||
|
||||
// --- Hunger & Saturation Aliases ---
|
||||
pub fn get_food_saturation(&self) -> f32 {
|
||||
self.get_saturation()
|
||||
}
|
||||
|
||||
pub async fn set_food_saturation(&self, saturation: f32) {
|
||||
self.set_saturation(saturation).await;
|
||||
}
|
||||
|
||||
pub fn get_food_exhaustion(&self) -> f32 {
|
||||
self.get_exhaustion()
|
||||
}
|
||||
|
||||
pub async fn set_food_exhaustion(&self, exhaustion: f32) {
|
||||
self.set_exhaustion(exhaustion).await;
|
||||
}
|
||||
|
||||
pub async fn get_target_block(
|
||||
&self,
|
||||
world: &Arc<World>,
|
||||
@@ -3653,14 +3953,6 @@ impl Player {
|
||||
.await;
|
||||
}
|
||||
|
||||
/// Sends a custom payload packet to this player (Java edition only).
|
||||
pub async fn send_custom_payload(&self, channel: &str, data: &[u8]) {
|
||||
if let ClientPlatform::Java(java) = self.client.as_ref() {
|
||||
java.enqueue_packet(&CCustomPayload::new(channel, data))
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn drop_item(&self, item_stack: ItemStack) {
|
||||
self.increment_stat(
|
||||
statistics::StatisticCategory::Dropped,
|
||||
|
||||
@@ -45,7 +45,15 @@ pub type EntityResource = WasmResource<Arc<dyn EntityBase>>;
|
||||
pub type WorldResource = WasmResource<Arc<World>>;
|
||||
pub type ChunkResource = WasmResource<(Arc<World>, Weak<pumpkin_world::chunk::ChunkData>)>;
|
||||
pub type WorldBorderResource = WasmResource<Arc<World>>;
|
||||
pub type ScoreboardResource = WasmResource<Arc<World>>;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum ScoreboardProvider {
|
||||
World(Arc<World>),
|
||||
Player(Arc<Player>),
|
||||
}
|
||||
|
||||
pub type ScoreboardResource = WasmResource<ScoreboardProvider>;
|
||||
pub type BedrockScoreboardResource = WasmResource<Arc<Player>>;
|
||||
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>>,
|
||||
@@ -176,12 +184,22 @@ impl PluginHostState {
|
||||
|
||||
pub fn add_scoreboard<T>(
|
||||
&mut self,
|
||||
provider: Arc<World>,
|
||||
provider: ScoreboardProvider,
|
||||
) -> wasmtime::Result<wasmtime::component::Resource<T>> {
|
||||
let resource = self.resource_table.push(ScoreboardResource { provider })?;
|
||||
Ok(wasmtime::component::Resource::new_own(resource.rep()))
|
||||
}
|
||||
|
||||
pub fn add_bedrock_scoreboard<T>(
|
||||
&mut self,
|
||||
provider: Arc<Player>,
|
||||
) -> wasmtime::Result<wasmtime::component::Resource<T>> {
|
||||
let resource = self
|
||||
.resource_table
|
||||
.push(BedrockScoreboardResource { provider })?;
|
||||
Ok(wasmtime::component::Resource::new_own(resource.rep()))
|
||||
}
|
||||
|
||||
pub fn add_gui<T>(
|
||||
&mut self,
|
||||
provider: Arc<Mutex<PluginGui>>,
|
||||
|
||||
@@ -1059,21 +1059,13 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
||||
relative: bool,
|
||||
) -> wasmtime::Result<()> {
|
||||
let player = player_from_resource(self, &player)?;
|
||||
player
|
||||
.set_player_time(
|
||||
&player.living_entity.entity.world.load_full(),
|
||||
time,
|
||||
relative,
|
||||
)
|
||||
.await;
|
||||
player.set_player_time(time, relative).await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn reset_player_time(&mut self, player: Resource<Player>) -> wasmtime::Result<()> {
|
||||
let player = player_from_resource(self, &player)?;
|
||||
player
|
||||
.reset_player_time(&player.living_entity.entity.world.load_full())
|
||||
.await;
|
||||
player.reset_player_time().await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1222,6 +1214,55 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
||||
Ok(player.can_see(&other.gameprofile.id).await)
|
||||
}
|
||||
|
||||
async fn can_see_player(
|
||||
&mut self,
|
||||
player: Resource<Player>,
|
||||
other: Resource<Player>,
|
||||
) -> wasmtime::Result<bool> {
|
||||
let player = player_from_resource(self, &player)?;
|
||||
let other = player_from_resource(self, &other)?;
|
||||
Ok(player.can_see(&other.gameprofile.id).await)
|
||||
}
|
||||
|
||||
async fn set_tab_list_ping(
|
||||
&mut self,
|
||||
player: Resource<Player>,
|
||||
latency_ms: i32,
|
||||
) -> wasmtime::Result<()> {
|
||||
let player = player_from_resource(self, &player)?;
|
||||
player.set_tab_list_ping(latency_ms);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn set_item_cooldown(
|
||||
&mut self,
|
||||
player: Resource<Player>,
|
||||
item_id: String,
|
||||
ticks: i32,
|
||||
) -> wasmtime::Result<()> {
|
||||
let player = player_from_resource(self, &player)?;
|
||||
player.set_item_cooldown(&item_id, ticks).await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_item_cooldown(
|
||||
&mut self,
|
||||
player: Resource<Player>,
|
||||
item_id: String,
|
||||
) -> wasmtime::Result<Option<i32>> {
|
||||
let player = player_from_resource(self, &player)?;
|
||||
Ok(player.get_item_cooldown(&item_id).await)
|
||||
}
|
||||
|
||||
async fn has_item_cooldown(
|
||||
&mut self,
|
||||
player: Resource<Player>,
|
||||
item_id: String,
|
||||
) -> wasmtime::Result<bool> {
|
||||
let player = player_from_resource(self, &player)?;
|
||||
Ok(player.has_item_cooldown(&item_id).await)
|
||||
}
|
||||
|
||||
async fn get_target_block(
|
||||
&mut self,
|
||||
player: Resource<Player>,
|
||||
@@ -2198,6 +2239,39 @@ impl pumpkin::plugin::player::HostJavaPlayer for PluginHostState {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_scoreboard(
|
||||
&mut self,
|
||||
player_res: Resource<pumpkin::plugin::player::JavaPlayer>,
|
||||
) -> wasmtime::Result<Resource<pumpkin::plugin::scoreboard::Scoreboard>> {
|
||||
let player = self
|
||||
.resource_table
|
||||
.get::<crate::plugin::loader::wasm::wasm_host::state::JavaPlayerResource>(
|
||||
&Resource::new_own(player_res.rep()),
|
||||
)
|
||||
.map_err(|_| wasmtime::Error::msg("invalid java-player resource handle"))?
|
||||
.provider
|
||||
.clone();
|
||||
self.add_scoreboard(
|
||||
crate::plugin::loader::wasm::wasm_host::state::ScoreboardProvider::Player(player),
|
||||
)
|
||||
}
|
||||
|
||||
async fn reset_scoreboard(
|
||||
&mut self,
|
||||
player_res: Resource<pumpkin::plugin::player::JavaPlayer>,
|
||||
) -> wasmtime::Result<()> {
|
||||
let player = self
|
||||
.resource_table
|
||||
.get::<crate::plugin::loader::wasm::wasm_host::state::JavaPlayerResource>(
|
||||
&Resource::new_own(player_res.rep()),
|
||||
)
|
||||
.map_err(|_| wasmtime::Error::msg("invalid java-player resource handle"))?
|
||||
.provider
|
||||
.clone();
|
||||
player.reset_scoreboard().await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn drop(
|
||||
&mut self,
|
||||
rep: Resource<pumpkin::plugin::player::JavaPlayer>,
|
||||
@@ -2543,6 +2617,37 @@ impl pumpkin::plugin::player::HostBedrockPlayer for PluginHostState {
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_scoreboard(
|
||||
&mut self,
|
||||
player_res: Resource<pumpkin::plugin::player::BedrockPlayer>,
|
||||
) -> wasmtime::Result<Resource<pumpkin::plugin::scoreboard::BedrockScoreboard>> {
|
||||
let player = self
|
||||
.resource_table
|
||||
.get::<crate::plugin::loader::wasm::wasm_host::state::BedrockPlayerResource>(
|
||||
&Resource::new_own(player_res.rep()),
|
||||
)
|
||||
.map_err(|_| wasmtime::Error::msg("invalid bedrock-player resource handle"))?
|
||||
.provider
|
||||
.clone();
|
||||
self.add_bedrock_scoreboard(player)
|
||||
}
|
||||
|
||||
async fn reset_scoreboard(
|
||||
&mut self,
|
||||
player_res: Resource<pumpkin::plugin::player::BedrockPlayer>,
|
||||
) -> wasmtime::Result<()> {
|
||||
let player = self
|
||||
.resource_table
|
||||
.get::<crate::plugin::loader::wasm::wasm_host::state::BedrockPlayerResource>(
|
||||
&Resource::new_own(player_res.rep()),
|
||||
)
|
||||
.map_err(|_| wasmtime::Error::msg("invalid bedrock-player resource handle"))?
|
||||
.provider
|
||||
.clone();
|
||||
player.reset_scoreboard().await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn drop(
|
||||
&mut self,
|
||||
rep: Resource<pumpkin::plugin::player::BedrockPlayer>,
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
use wasmtime::component::Resource;
|
||||
|
||||
use crate::plugin::loader::wasm::wasm_host::{
|
||||
state::{PluginHostState, ScoreboardResource},
|
||||
state::{BedrockScoreboardResource, PluginHostState, ScoreboardProvider, ScoreboardResource},
|
||||
wit::v0_1::pumpkin::{
|
||||
self,
|
||||
plugin::scoreboard::{
|
||||
self, CollisionRule, DisplaySlot, NametagVisibility, RenderType, TeamSettings,
|
||||
self, CollisionRule, DisplaySlot, HostBedrockScoreboard, NametagVisibility, RenderType,
|
||||
TeamSettings,
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -21,6 +22,15 @@ impl PluginHostState {
|
||||
.get::<ScoreboardResource>(&Resource::new_own(res.rep()))
|
||||
.map_err(wasmtime::Error::from)
|
||||
}
|
||||
|
||||
fn get_bedrock_scoreboard_res(
|
||||
&self,
|
||||
res: &Resource<scoreboard::BedrockScoreboard>,
|
||||
) -> wasmtime::Result<&BedrockScoreboardResource> {
|
||||
self.resource_table
|
||||
.get::<BedrockScoreboardResource>(&Resource::new_own(res.rep()))
|
||||
.map_err(wasmtime::Error::from)
|
||||
}
|
||||
}
|
||||
|
||||
impl scoreboard::Host for PluginHostState {}
|
||||
@@ -33,7 +43,7 @@ impl scoreboard::HostScoreboard for PluginHostState {
|
||||
display_name: Resource<pumpkin::plugin::text::TextComponent>,
|
||||
render_type: RenderType,
|
||||
) -> wasmtime::Result<()> {
|
||||
let world = self.get_scoreboard_res(&res)?.provider.clone();
|
||||
let provider = self.get_scoreboard_res(&res)?.provider.clone();
|
||||
let display_name = self.get_text_provider(&display_name)?;
|
||||
|
||||
let rt = match render_type {
|
||||
@@ -41,19 +51,80 @@ impl scoreboard::HostScoreboard for PluginHostState {
|
||||
RenderType::Hearts => pumpkin_protocol::java::client::play::RenderType::Hearts,
|
||||
};
|
||||
|
||||
let objective = ScoreboardObjective::new(
|
||||
Box::leak(name.into_boxed_str()),
|
||||
display_name,
|
||||
rt,
|
||||
None,
|
||||
"dummy",
|
||||
);
|
||||
world
|
||||
.scoreboard
|
||||
.lock()
|
||||
.await
|
||||
.add_objective(&world, objective)
|
||||
.await;
|
||||
let objective = ScoreboardObjective::new(name, display_name, rt, None, "dummy");
|
||||
|
||||
match provider {
|
||||
ScoreboardProvider::World(world) => {
|
||||
world
|
||||
.scoreboard
|
||||
.lock()
|
||||
.await
|
||||
.add_objective(world.as_ref(), objective)
|
||||
.await;
|
||||
}
|
||||
ScoreboardProvider::Player(player) => {
|
||||
let mut custom_guard = player.custom_scoreboard.lock().await;
|
||||
if !matches!(
|
||||
*custom_guard,
|
||||
Some(crate::entity::player::CustomScoreboard::Java(_))
|
||||
) {
|
||||
*custom_guard = Some(crate::entity::player::CustomScoreboard::Java(
|
||||
crate::world::scoreboard::Scoreboard::default(),
|
||||
));
|
||||
}
|
||||
if let Some(crate::entity::player::CustomScoreboard::Java(sb)) =
|
||||
custom_guard.as_mut()
|
||||
{
|
||||
sb.add_objective(player.as_ref(), objective).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn update_objective(
|
||||
&mut self,
|
||||
res: Resource<scoreboard::Scoreboard>,
|
||||
name: String,
|
||||
display_name: Resource<pumpkin::plugin::text::TextComponent>,
|
||||
render_type: RenderType,
|
||||
) -> wasmtime::Result<()> {
|
||||
let provider = self.get_scoreboard_res(&res)?.provider.clone();
|
||||
let display_name = self.get_text_provider(&display_name)?;
|
||||
|
||||
let rt = match render_type {
|
||||
RenderType::Integer => pumpkin_protocol::java::client::play::RenderType::Integer,
|
||||
RenderType::Hearts => pumpkin_protocol::java::client::play::RenderType::Hearts,
|
||||
};
|
||||
|
||||
let objective = ScoreboardObjective::new(name, display_name, rt, None, "dummy");
|
||||
|
||||
match provider {
|
||||
ScoreboardProvider::World(world) => {
|
||||
world
|
||||
.scoreboard
|
||||
.lock()
|
||||
.await
|
||||
.update_objective(world.as_ref(), objective)
|
||||
.await;
|
||||
}
|
||||
ScoreboardProvider::Player(player) => {
|
||||
let mut custom_guard = player.custom_scoreboard.lock().await;
|
||||
if !matches!(
|
||||
*custom_guard,
|
||||
Some(crate::entity::player::CustomScoreboard::Java(_))
|
||||
) {
|
||||
*custom_guard = Some(crate::entity::player::CustomScoreboard::Java(
|
||||
crate::world::scoreboard::Scoreboard::default(),
|
||||
));
|
||||
}
|
||||
if let Some(crate::entity::player::CustomScoreboard::Java(sb)) =
|
||||
custom_guard.as_mut()
|
||||
{
|
||||
sb.update_objective(player.as_ref(), objective).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -62,13 +133,25 @@ impl scoreboard::HostScoreboard for PluginHostState {
|
||||
res: Resource<scoreboard::Scoreboard>,
|
||||
name: String,
|
||||
) -> wasmtime::Result<()> {
|
||||
let world = self.get_scoreboard_res(&res)?.provider.clone();
|
||||
world
|
||||
.scoreboard
|
||||
.lock()
|
||||
.await
|
||||
.remove_objective(&world, &name)
|
||||
.await;
|
||||
let provider = self.get_scoreboard_res(&res)?.provider.clone();
|
||||
match provider {
|
||||
ScoreboardProvider::World(world) => {
|
||||
world
|
||||
.scoreboard
|
||||
.lock()
|
||||
.await
|
||||
.remove_objective(world.as_ref(), &name)
|
||||
.await;
|
||||
}
|
||||
ScoreboardProvider::Player(player) => {
|
||||
let mut custom_guard = player.custom_scoreboard.lock().await;
|
||||
if let Some(crate::entity::player::CustomScoreboard::Java(sb)) =
|
||||
custom_guard.as_mut()
|
||||
{
|
||||
sb.remove_objective(player.as_ref(), &name).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -78,65 +161,65 @@ impl scoreboard::HostScoreboard for PluginHostState {
|
||||
slot: DisplaySlot,
|
||||
objective_name: String,
|
||||
) -> wasmtime::Result<()> {
|
||||
let world = self.get_scoreboard_res(&res)?.provider.clone();
|
||||
let slot = match slot {
|
||||
DisplaySlot::PlayerList => pumpkin_data::scoreboard::ScoreboardDisplaySlot::List,
|
||||
DisplaySlot::Sidebar => pumpkin_data::scoreboard::ScoreboardDisplaySlot::Sidebar,
|
||||
DisplaySlot::BelowName => pumpkin_data::scoreboard::ScoreboardDisplaySlot::BelowName,
|
||||
DisplaySlot::SidebarTeamBlack => {
|
||||
pumpkin_data::scoreboard::ScoreboardDisplaySlot::TeamBlack
|
||||
}
|
||||
DisplaySlot::SidebarTeamDarkBlue => {
|
||||
pumpkin_data::scoreboard::ScoreboardDisplaySlot::TeamDarkBlue
|
||||
}
|
||||
DisplaySlot::SidebarTeamDarkGreen => {
|
||||
pumpkin_data::scoreboard::ScoreboardDisplaySlot::TeamDarkGreen
|
||||
}
|
||||
DisplaySlot::SidebarTeamDarkAqua => {
|
||||
pumpkin_data::scoreboard::ScoreboardDisplaySlot::TeamDarkAqua
|
||||
}
|
||||
DisplaySlot::SidebarTeamDarkRed => {
|
||||
pumpkin_data::scoreboard::ScoreboardDisplaySlot::TeamDarkRed
|
||||
}
|
||||
DisplaySlot::SidebarTeamDarkPurple => {
|
||||
pumpkin_data::scoreboard::ScoreboardDisplaySlot::TeamDarkPurple
|
||||
}
|
||||
DisplaySlot::SidebarTeamGold => {
|
||||
pumpkin_data::scoreboard::ScoreboardDisplaySlot::TeamGold
|
||||
}
|
||||
DisplaySlot::SidebarTeamGray => {
|
||||
pumpkin_data::scoreboard::ScoreboardDisplaySlot::TeamGray
|
||||
}
|
||||
DisplaySlot::SidebarTeamDarkGray => {
|
||||
pumpkin_data::scoreboard::ScoreboardDisplaySlot::TeamDarkGray
|
||||
}
|
||||
DisplaySlot::SidebarTeamBlue => {
|
||||
pumpkin_data::scoreboard::ScoreboardDisplaySlot::TeamBlue
|
||||
}
|
||||
DisplaySlot::SidebarTeamGreen => {
|
||||
pumpkin_data::scoreboard::ScoreboardDisplaySlot::TeamGreen
|
||||
}
|
||||
DisplaySlot::SidebarTeamAqua => {
|
||||
pumpkin_data::scoreboard::ScoreboardDisplaySlot::TeamAqua
|
||||
}
|
||||
DisplaySlot::SidebarTeamRed => pumpkin_data::scoreboard::ScoreboardDisplaySlot::TeamRed,
|
||||
DisplaySlot::SidebarTeamLightPurple => {
|
||||
pumpkin_data::scoreboard::ScoreboardDisplaySlot::TeamLightPurple
|
||||
}
|
||||
DisplaySlot::SidebarTeamYellow => {
|
||||
pumpkin_data::scoreboard::ScoreboardDisplaySlot::TeamYellow
|
||||
}
|
||||
DisplaySlot::SidebarTeamWhite => {
|
||||
pumpkin_data::scoreboard::ScoreboardDisplaySlot::TeamWhite
|
||||
}
|
||||
};
|
||||
let provider = self.get_scoreboard_res(&res)?.provider.clone();
|
||||
let slot = map_display_slot(slot);
|
||||
|
||||
world
|
||||
.scoreboard
|
||||
.lock()
|
||||
.await
|
||||
.set_display_objective(&world, slot, &objective_name)
|
||||
.await;
|
||||
match provider {
|
||||
ScoreboardProvider::World(world) => {
|
||||
world
|
||||
.scoreboard
|
||||
.lock()
|
||||
.await
|
||||
.set_display_objective(world.as_ref(), slot, Some(&objective_name))
|
||||
.await;
|
||||
}
|
||||
ScoreboardProvider::Player(player) => {
|
||||
let mut custom_guard = player.custom_scoreboard.lock().await;
|
||||
if !matches!(
|
||||
*custom_guard,
|
||||
Some(crate::entity::player::CustomScoreboard::Java(_))
|
||||
) {
|
||||
*custom_guard = Some(crate::entity::player::CustomScoreboard::Java(
|
||||
crate::world::scoreboard::Scoreboard::default(),
|
||||
));
|
||||
}
|
||||
if let Some(crate::entity::player::CustomScoreboard::Java(sb)) =
|
||||
custom_guard.as_mut()
|
||||
{
|
||||
sb.set_display_objective(player.as_ref(), slot, Some(&objective_name))
|
||||
.await;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn clear_display_slot(
|
||||
&mut self,
|
||||
res: Resource<scoreboard::Scoreboard>,
|
||||
slot: DisplaySlot,
|
||||
) -> wasmtime::Result<()> {
|
||||
let provider = self.get_scoreboard_res(&res)?.provider.clone();
|
||||
let slot = map_display_slot(slot);
|
||||
|
||||
match provider {
|
||||
ScoreboardProvider::World(world) => {
|
||||
world
|
||||
.scoreboard
|
||||
.lock()
|
||||
.await
|
||||
.clear_display_objective(world.as_ref(), slot)
|
||||
.await;
|
||||
}
|
||||
ScoreboardProvider::Player(player) => {
|
||||
let mut custom_guard = player.custom_scoreboard.lock().await;
|
||||
if let Some(crate::entity::player::CustomScoreboard::Java(sb)) =
|
||||
custom_guard.as_mut()
|
||||
{
|
||||
sb.clear_display_objective(player.as_ref(), slot).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -147,36 +230,129 @@ impl scoreboard::HostScoreboard for PluginHostState {
|
||||
objective_name: String,
|
||||
value: i32,
|
||||
) -> wasmtime::Result<()> {
|
||||
let world = self.get_scoreboard_res(&res)?.provider.clone();
|
||||
let score = ScoreboardScore::new(
|
||||
Box::leak(entity_name.into_boxed_str()),
|
||||
Box::leak(objective_name.into_boxed_str()),
|
||||
VarInt(value),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
world
|
||||
.scoreboard
|
||||
.lock()
|
||||
.await
|
||||
.update_score(&world, score)
|
||||
.await;
|
||||
let provider = self.get_scoreboard_res(&res)?.provider.clone();
|
||||
let score = ScoreboardScore::new(entity_name, objective_name, VarInt(value), None, None);
|
||||
match provider {
|
||||
ScoreboardProvider::World(world) => {
|
||||
world
|
||||
.scoreboard
|
||||
.lock()
|
||||
.await
|
||||
.update_score(world.as_ref(), score)
|
||||
.await;
|
||||
}
|
||||
ScoreboardProvider::Player(player) => {
|
||||
let mut custom_guard = player.custom_scoreboard.lock().await;
|
||||
if !matches!(
|
||||
*custom_guard,
|
||||
Some(crate::entity::player::CustomScoreboard::Java(_))
|
||||
) {
|
||||
*custom_guard = Some(crate::entity::player::CustomScoreboard::Java(
|
||||
crate::world::scoreboard::Scoreboard::default(),
|
||||
));
|
||||
}
|
||||
if let Some(crate::entity::player::CustomScoreboard::Java(sb)) =
|
||||
custom_guard.as_mut()
|
||||
{
|
||||
sb.update_score(player.as_ref(), score).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn add_score(
|
||||
&mut self,
|
||||
res: Resource<scoreboard::Scoreboard>,
|
||||
entity_name: String,
|
||||
objective_name: String,
|
||||
delta: i32,
|
||||
) -> wasmtime::Result<i32> {
|
||||
let provider = self.get_scoreboard_res(&res)?.provider.clone();
|
||||
let new_val = match provider {
|
||||
ScoreboardProvider::World(world) => {
|
||||
world
|
||||
.scoreboard
|
||||
.lock()
|
||||
.await
|
||||
.add_score(world.as_ref(), entity_name, objective_name, delta)
|
||||
.await
|
||||
}
|
||||
ScoreboardProvider::Player(player) => {
|
||||
let mut custom_guard = player.custom_scoreboard.lock().await;
|
||||
if !matches!(
|
||||
*custom_guard,
|
||||
Some(crate::entity::player::CustomScoreboard::Java(_))
|
||||
) {
|
||||
*custom_guard = Some(crate::entity::player::CustomScoreboard::Java(
|
||||
crate::world::scoreboard::Scoreboard::default(),
|
||||
));
|
||||
}
|
||||
let Some(crate::entity::player::CustomScoreboard::Java(sb)) = custom_guard.as_mut()
|
||||
else {
|
||||
return Err(wasmtime::Error::msg("Invalid scoreboard state"));
|
||||
};
|
||||
sb.add_score(player.as_ref(), entity_name, objective_name, delta)
|
||||
.await
|
||||
}
|
||||
};
|
||||
Ok(new_val)
|
||||
}
|
||||
|
||||
async fn remove_score(
|
||||
&mut self,
|
||||
res: Resource<scoreboard::Scoreboard>,
|
||||
entity_name: String,
|
||||
objective_name: String,
|
||||
) -> wasmtime::Result<()> {
|
||||
let world = self.get_scoreboard_res(&res)?.provider.clone();
|
||||
world
|
||||
.scoreboard
|
||||
.lock()
|
||||
.await
|
||||
.remove_score(&world, &entity_name, &objective_name)
|
||||
.await;
|
||||
let provider = self.get_scoreboard_res(&res)?.provider.clone();
|
||||
match provider {
|
||||
ScoreboardProvider::World(world) => {
|
||||
world
|
||||
.scoreboard
|
||||
.lock()
|
||||
.await
|
||||
.remove_score(world.as_ref(), &entity_name, &objective_name)
|
||||
.await;
|
||||
}
|
||||
ScoreboardProvider::Player(player) => {
|
||||
let mut custom_guard = player.custom_scoreboard.lock().await;
|
||||
if let Some(crate::entity::player::CustomScoreboard::Java(sb)) =
|
||||
custom_guard.as_mut()
|
||||
{
|
||||
sb.remove_score(player.as_ref(), &entity_name, &objective_name)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn reset_entity_scores(
|
||||
&mut self,
|
||||
res: Resource<scoreboard::Scoreboard>,
|
||||
entity_name: String,
|
||||
) -> wasmtime::Result<()> {
|
||||
let provider = self.get_scoreboard_res(&res)?.provider.clone();
|
||||
match provider {
|
||||
ScoreboardProvider::World(world) => {
|
||||
world
|
||||
.scoreboard
|
||||
.lock()
|
||||
.await
|
||||
.reset_scores_for_entity(world.as_ref(), &entity_name)
|
||||
.await;
|
||||
}
|
||||
ScoreboardProvider::Player(player) => {
|
||||
let mut custom_guard = player.custom_scoreboard.lock().await;
|
||||
if let Some(crate::entity::player::CustomScoreboard::Java(sb)) =
|
||||
custom_guard.as_mut()
|
||||
{
|
||||
sb.reset_scores_for_entity(player.as_ref(), &entity_name)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -186,9 +362,34 @@ impl scoreboard::HostScoreboard for PluginHostState {
|
||||
name: String,
|
||||
settings: TeamSettings,
|
||||
) -> wasmtime::Result<()> {
|
||||
let world = self.get_scoreboard_res(&res)?.provider.clone();
|
||||
let provider = self.get_scoreboard_res(&res)?.provider.clone();
|
||||
let team = map_team_settings(name, &settings, self)?;
|
||||
world.scoreboard.lock().await.add_team(&world, team);
|
||||
match provider {
|
||||
ScoreboardProvider::World(world) => {
|
||||
world
|
||||
.scoreboard
|
||||
.lock()
|
||||
.await
|
||||
.add_team(world.as_ref(), team)
|
||||
.await;
|
||||
}
|
||||
ScoreboardProvider::Player(player) => {
|
||||
let mut custom_guard = player.custom_scoreboard.lock().await;
|
||||
if !matches!(
|
||||
*custom_guard,
|
||||
Some(crate::entity::player::CustomScoreboard::Java(_))
|
||||
) {
|
||||
*custom_guard = Some(crate::entity::player::CustomScoreboard::Java(
|
||||
crate::world::scoreboard::Scoreboard::default(),
|
||||
));
|
||||
}
|
||||
if let Some(crate::entity::player::CustomScoreboard::Java(sb)) =
|
||||
custom_guard.as_mut()
|
||||
{
|
||||
sb.add_team(player.as_ref(), team).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -197,8 +398,25 @@ impl scoreboard::HostScoreboard for PluginHostState {
|
||||
res: Resource<scoreboard::Scoreboard>,
|
||||
name: String,
|
||||
) -> wasmtime::Result<()> {
|
||||
let world = self.get_scoreboard_res(&res)?.provider.clone();
|
||||
world.scoreboard.lock().await.remove_team(&world, &name);
|
||||
let provider = self.get_scoreboard_res(&res)?.provider.clone();
|
||||
match provider {
|
||||
ScoreboardProvider::World(world) => {
|
||||
world
|
||||
.scoreboard
|
||||
.lock()
|
||||
.await
|
||||
.remove_team(world.as_ref(), &name)
|
||||
.await;
|
||||
}
|
||||
ScoreboardProvider::Player(player) => {
|
||||
let mut custom_guard = player.custom_scoreboard.lock().await;
|
||||
if let Some(crate::entity::player::CustomScoreboard::Java(sb)) =
|
||||
custom_guard.as_mut()
|
||||
{
|
||||
sb.remove_team(player.as_ref(), &name).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -208,9 +426,26 @@ impl scoreboard::HostScoreboard for PluginHostState {
|
||||
name: String,
|
||||
settings: TeamSettings,
|
||||
) -> wasmtime::Result<()> {
|
||||
let world = self.get_scoreboard_res(&res)?.provider.clone();
|
||||
let provider = self.get_scoreboard_res(&res)?.provider.clone();
|
||||
let team = map_team_settings(name, &settings, self)?;
|
||||
world.scoreboard.lock().await.update_team(&world, team);
|
||||
match provider {
|
||||
ScoreboardProvider::World(world) => {
|
||||
world
|
||||
.scoreboard
|
||||
.lock()
|
||||
.await
|
||||
.update_team(world.as_ref(), team)
|
||||
.await;
|
||||
}
|
||||
ScoreboardProvider::Player(player) => {
|
||||
let mut custom_guard = player.custom_scoreboard.lock().await;
|
||||
if let Some(crate::entity::player::CustomScoreboard::Java(sb)) =
|
||||
custom_guard.as_mut()
|
||||
{
|
||||
sb.update_team(player.as_ref(), team).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -220,12 +455,26 @@ impl scoreboard::HostScoreboard for PluginHostState {
|
||||
team_name: String,
|
||||
player_name: String,
|
||||
) -> wasmtime::Result<()> {
|
||||
let world = self.get_scoreboard_res(&res)?.provider.clone();
|
||||
world
|
||||
.scoreboard
|
||||
.lock()
|
||||
.await
|
||||
.add_player_to_team(&world, &team_name, player_name);
|
||||
let provider = self.get_scoreboard_res(&res)?.provider.clone();
|
||||
match provider {
|
||||
ScoreboardProvider::World(world) => {
|
||||
world
|
||||
.scoreboard
|
||||
.lock()
|
||||
.await
|
||||
.add_player_to_team(world.as_ref(), &team_name, player_name)
|
||||
.await;
|
||||
}
|
||||
ScoreboardProvider::Player(player) => {
|
||||
let mut custom_guard = player.custom_scoreboard.lock().await;
|
||||
if let Some(crate::entity::player::CustomScoreboard::Java(sb)) =
|
||||
custom_guard.as_mut()
|
||||
{
|
||||
sb.add_player_to_team(player.as_ref(), &team_name, player_name)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -235,12 +484,53 @@ impl scoreboard::HostScoreboard for PluginHostState {
|
||||
team_name: String,
|
||||
player_name: String,
|
||||
) -> wasmtime::Result<()> {
|
||||
let world = self.get_scoreboard_res(&res)?.provider.clone();
|
||||
world
|
||||
.scoreboard
|
||||
.lock()
|
||||
.await
|
||||
.remove_player_from_team(&world, &team_name, &player_name);
|
||||
let provider = self.get_scoreboard_res(&res)?.provider.clone();
|
||||
match provider {
|
||||
ScoreboardProvider::World(world) => {
|
||||
world
|
||||
.scoreboard
|
||||
.lock()
|
||||
.await
|
||||
.remove_player_from_team(world.as_ref(), &team_name, &player_name)
|
||||
.await;
|
||||
}
|
||||
ScoreboardProvider::Player(player) => {
|
||||
let mut custom_guard = player.custom_scoreboard.lock().await;
|
||||
if let Some(crate::entity::player::CustomScoreboard::Java(sb)) =
|
||||
custom_guard.as_mut()
|
||||
{
|
||||
sb.remove_player_from_team(player.as_ref(), &team_name, &player_name)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn clear_team_players(
|
||||
&mut self,
|
||||
res: Resource<scoreboard::Scoreboard>,
|
||||
team_name: String,
|
||||
) -> wasmtime::Result<()> {
|
||||
let provider = self.get_scoreboard_res(&res)?.provider.clone();
|
||||
match provider {
|
||||
ScoreboardProvider::World(world) => {
|
||||
world
|
||||
.scoreboard
|
||||
.lock()
|
||||
.await
|
||||
.clear_team_players(world.as_ref(), &team_name)
|
||||
.await;
|
||||
}
|
||||
ScoreboardProvider::Player(player) => {
|
||||
let mut custom_guard = player.custom_scoreboard.lock().await;
|
||||
if let Some(crate::entity::player::CustomScoreboard::Java(sb)) =
|
||||
custom_guard.as_mut()
|
||||
{
|
||||
sb.clear_team_players(player.as_ref(), &team_name).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -252,6 +542,46 @@ impl scoreboard::HostScoreboard for PluginHostState {
|
||||
}
|
||||
}
|
||||
|
||||
const fn map_display_slot(slot: DisplaySlot) -> pumpkin_data::scoreboard::ScoreboardDisplaySlot {
|
||||
match slot {
|
||||
DisplaySlot::PlayerList => pumpkin_data::scoreboard::ScoreboardDisplaySlot::List,
|
||||
DisplaySlot::Sidebar => pumpkin_data::scoreboard::ScoreboardDisplaySlot::Sidebar,
|
||||
DisplaySlot::BelowName => pumpkin_data::scoreboard::ScoreboardDisplaySlot::BelowName,
|
||||
DisplaySlot::SidebarTeamBlack => pumpkin_data::scoreboard::ScoreboardDisplaySlot::TeamBlack,
|
||||
DisplaySlot::SidebarTeamDarkBlue => {
|
||||
pumpkin_data::scoreboard::ScoreboardDisplaySlot::TeamDarkBlue
|
||||
}
|
||||
DisplaySlot::SidebarTeamDarkGreen => {
|
||||
pumpkin_data::scoreboard::ScoreboardDisplaySlot::TeamDarkGreen
|
||||
}
|
||||
DisplaySlot::SidebarTeamDarkAqua => {
|
||||
pumpkin_data::scoreboard::ScoreboardDisplaySlot::TeamDarkAqua
|
||||
}
|
||||
DisplaySlot::SidebarTeamDarkRed => {
|
||||
pumpkin_data::scoreboard::ScoreboardDisplaySlot::TeamDarkRed
|
||||
}
|
||||
DisplaySlot::SidebarTeamDarkPurple => {
|
||||
pumpkin_data::scoreboard::ScoreboardDisplaySlot::TeamDarkPurple
|
||||
}
|
||||
DisplaySlot::SidebarTeamGold => pumpkin_data::scoreboard::ScoreboardDisplaySlot::TeamGold,
|
||||
DisplaySlot::SidebarTeamGray => pumpkin_data::scoreboard::ScoreboardDisplaySlot::TeamGray,
|
||||
DisplaySlot::SidebarTeamDarkGray => {
|
||||
pumpkin_data::scoreboard::ScoreboardDisplaySlot::TeamDarkGray
|
||||
}
|
||||
DisplaySlot::SidebarTeamBlue => pumpkin_data::scoreboard::ScoreboardDisplaySlot::TeamBlue,
|
||||
DisplaySlot::SidebarTeamGreen => pumpkin_data::scoreboard::ScoreboardDisplaySlot::TeamGreen,
|
||||
DisplaySlot::SidebarTeamAqua => pumpkin_data::scoreboard::ScoreboardDisplaySlot::TeamAqua,
|
||||
DisplaySlot::SidebarTeamRed => pumpkin_data::scoreboard::ScoreboardDisplaySlot::TeamRed,
|
||||
DisplaySlot::SidebarTeamLightPurple => {
|
||||
pumpkin_data::scoreboard::ScoreboardDisplaySlot::TeamLightPurple
|
||||
}
|
||||
DisplaySlot::SidebarTeamYellow => {
|
||||
pumpkin_data::scoreboard::ScoreboardDisplaySlot::TeamYellow
|
||||
}
|
||||
DisplaySlot::SidebarTeamWhite => pumpkin_data::scoreboard::ScoreboardDisplaySlot::TeamWhite,
|
||||
}
|
||||
}
|
||||
|
||||
fn map_team_settings(
|
||||
name: String,
|
||||
settings: &TeamSettings,
|
||||
@@ -336,3 +666,247 @@ const fn map_named_color(
|
||||
pumpkin::plugin::common::NamedColor::White => pumpkin_util::text::color::NamedColor::White,
|
||||
}
|
||||
}
|
||||
|
||||
impl HostBedrockScoreboard for PluginHostState {
|
||||
async fn add_objective(
|
||||
&mut self,
|
||||
res: Resource<scoreboard::BedrockScoreboard>,
|
||||
name: String,
|
||||
display_name: String,
|
||||
sort_order: scoreboard::BedrockSortOrder,
|
||||
) -> wasmtime::Result<()> {
|
||||
let player = self.get_bedrock_scoreboard_res(&res)?.provider.clone();
|
||||
let mut custom_guard = player.custom_scoreboard.lock().await;
|
||||
if !matches!(
|
||||
*custom_guard,
|
||||
Some(crate::entity::player::CustomScoreboard::Bedrock(_))
|
||||
) {
|
||||
*custom_guard = Some(crate::entity::player::CustomScoreboard::Bedrock(
|
||||
crate::world::scoreboard::BedrockScoreboard::default(),
|
||||
));
|
||||
}
|
||||
let Some(crate::entity::player::CustomScoreboard::Bedrock(sb)) = custom_guard.as_mut()
|
||||
else {
|
||||
return Err(wasmtime::Error::msg("Invalid scoreboard state"));
|
||||
};
|
||||
sb.add_objective(
|
||||
player.as_ref(),
|
||||
crate::world::scoreboard::BedrockObjective {
|
||||
name,
|
||||
display_name,
|
||||
sort_order: match sort_order {
|
||||
scoreboard::BedrockSortOrder::Ascending => {
|
||||
crate::world::scoreboard::BedrockSortOrder::Ascending
|
||||
}
|
||||
scoreboard::BedrockSortOrder::Descending => {
|
||||
crate::world::scoreboard::BedrockSortOrder::Descending
|
||||
}
|
||||
},
|
||||
},
|
||||
)
|
||||
.await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn update_objective(
|
||||
&mut self,
|
||||
res: Resource<scoreboard::BedrockScoreboard>,
|
||||
name: String,
|
||||
display_name: String,
|
||||
sort_order: scoreboard::BedrockSortOrder,
|
||||
) -> wasmtime::Result<()> {
|
||||
let player = self.get_bedrock_scoreboard_res(&res)?.provider.clone();
|
||||
let mut custom_guard = player.custom_scoreboard.lock().await;
|
||||
if !matches!(
|
||||
*custom_guard,
|
||||
Some(crate::entity::player::CustomScoreboard::Bedrock(_))
|
||||
) {
|
||||
*custom_guard = Some(crate::entity::player::CustomScoreboard::Bedrock(
|
||||
crate::world::scoreboard::BedrockScoreboard::default(),
|
||||
));
|
||||
}
|
||||
let Some(crate::entity::player::CustomScoreboard::Bedrock(sb)) = custom_guard.as_mut()
|
||||
else {
|
||||
return Err(wasmtime::Error::msg("Invalid scoreboard state"));
|
||||
};
|
||||
sb.update_objective(
|
||||
player.as_ref(),
|
||||
crate::world::scoreboard::BedrockObjective {
|
||||
name,
|
||||
display_name,
|
||||
sort_order: match sort_order {
|
||||
scoreboard::BedrockSortOrder::Ascending => {
|
||||
crate::world::scoreboard::BedrockSortOrder::Ascending
|
||||
}
|
||||
scoreboard::BedrockSortOrder::Descending => {
|
||||
crate::world::scoreboard::BedrockSortOrder::Descending
|
||||
}
|
||||
},
|
||||
},
|
||||
)
|
||||
.await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn remove_objective(
|
||||
&mut self,
|
||||
res: Resource<scoreboard::BedrockScoreboard>,
|
||||
name: String,
|
||||
) -> wasmtime::Result<()> {
|
||||
let player = self.get_bedrock_scoreboard_res(&res)?.provider.clone();
|
||||
let mut custom_guard = player.custom_scoreboard.lock().await;
|
||||
if let Some(crate::entity::player::CustomScoreboard::Bedrock(sb)) = custom_guard.as_mut() {
|
||||
sb.remove_objective(player.as_ref(), &name).await;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn set_display_slot(
|
||||
&mut self,
|
||||
res: Resource<scoreboard::BedrockScoreboard>,
|
||||
slot: scoreboard::BedrockDisplaySlot,
|
||||
objective_name: String,
|
||||
) -> wasmtime::Result<()> {
|
||||
let player = self.get_bedrock_scoreboard_res(&res)?.provider.clone();
|
||||
let mut custom_guard = player.custom_scoreboard.lock().await;
|
||||
if !matches!(
|
||||
*custom_guard,
|
||||
Some(crate::entity::player::CustomScoreboard::Bedrock(_))
|
||||
) {
|
||||
*custom_guard = Some(crate::entity::player::CustomScoreboard::Bedrock(
|
||||
crate::world::scoreboard::BedrockScoreboard::default(),
|
||||
));
|
||||
}
|
||||
let Some(crate::entity::player::CustomScoreboard::Bedrock(sb)) = custom_guard.as_mut()
|
||||
else {
|
||||
return Err(wasmtime::Error::msg("Invalid scoreboard state"));
|
||||
};
|
||||
let b_slot = match slot {
|
||||
scoreboard::BedrockDisplaySlot::PlayerList => {
|
||||
crate::world::scoreboard::BedrockDisplaySlot::PlayerList
|
||||
}
|
||||
scoreboard::BedrockDisplaySlot::Sidebar => {
|
||||
crate::world::scoreboard::BedrockDisplaySlot::Sidebar
|
||||
}
|
||||
scoreboard::BedrockDisplaySlot::BelowName => {
|
||||
crate::world::scoreboard::BedrockDisplaySlot::BelowName
|
||||
}
|
||||
};
|
||||
sb.set_display_objective(player.as_ref(), b_slot, Some(&objective_name))
|
||||
.await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn clear_display_slot(
|
||||
&mut self,
|
||||
res: Resource<scoreboard::BedrockScoreboard>,
|
||||
slot: scoreboard::BedrockDisplaySlot,
|
||||
) -> wasmtime::Result<()> {
|
||||
let player = self.get_bedrock_scoreboard_res(&res)?.provider.clone();
|
||||
let mut custom_guard = player.custom_scoreboard.lock().await;
|
||||
if let Some(crate::entity::player::CustomScoreboard::Bedrock(sb)) = custom_guard.as_mut() {
|
||||
let b_slot = match slot {
|
||||
scoreboard::BedrockDisplaySlot::PlayerList => {
|
||||
crate::world::scoreboard::BedrockDisplaySlot::PlayerList
|
||||
}
|
||||
scoreboard::BedrockDisplaySlot::Sidebar => {
|
||||
crate::world::scoreboard::BedrockDisplaySlot::Sidebar
|
||||
}
|
||||
scoreboard::BedrockDisplaySlot::BelowName => {
|
||||
crate::world::scoreboard::BedrockDisplaySlot::BelowName
|
||||
}
|
||||
};
|
||||
sb.clear_display_objective(player.as_ref(), b_slot).await;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn update_score(
|
||||
&mut self,
|
||||
res: Resource<scoreboard::BedrockScoreboard>,
|
||||
entity_name: String,
|
||||
objective_name: String,
|
||||
value: i32,
|
||||
) -> wasmtime::Result<()> {
|
||||
let player = self.get_bedrock_scoreboard_res(&res)?.provider.clone();
|
||||
let mut custom_guard = player.custom_scoreboard.lock().await;
|
||||
if !matches!(
|
||||
*custom_guard,
|
||||
Some(crate::entity::player::CustomScoreboard::Bedrock(_))
|
||||
) {
|
||||
*custom_guard = Some(crate::entity::player::CustomScoreboard::Bedrock(
|
||||
crate::world::scoreboard::BedrockScoreboard::default(),
|
||||
));
|
||||
}
|
||||
let Some(crate::entity::player::CustomScoreboard::Bedrock(sb)) = custom_guard.as_mut()
|
||||
else {
|
||||
return Err(wasmtime::Error::msg("Invalid scoreboard state"));
|
||||
};
|
||||
sb.update_score(player.as_ref(), &entity_name, &objective_name, value)
|
||||
.await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn add_score(
|
||||
&mut self,
|
||||
res: Resource<scoreboard::BedrockScoreboard>,
|
||||
entity_name: String,
|
||||
objective_name: String,
|
||||
delta: i32,
|
||||
) -> wasmtime::Result<i32> {
|
||||
let player = self.get_bedrock_scoreboard_res(&res)?.provider.clone();
|
||||
let mut custom_guard = player.custom_scoreboard.lock().await;
|
||||
if !matches!(
|
||||
*custom_guard,
|
||||
Some(crate::entity::player::CustomScoreboard::Bedrock(_))
|
||||
) {
|
||||
*custom_guard = Some(crate::entity::player::CustomScoreboard::Bedrock(
|
||||
crate::world::scoreboard::BedrockScoreboard::default(),
|
||||
));
|
||||
}
|
||||
let Some(crate::entity::player::CustomScoreboard::Bedrock(sb)) = custom_guard.as_mut()
|
||||
else {
|
||||
return Err(wasmtime::Error::msg("Invalid scoreboard state"));
|
||||
};
|
||||
let new_val = sb
|
||||
.add_score(player.as_ref(), entity_name, objective_name, delta)
|
||||
.await;
|
||||
Ok(new_val)
|
||||
}
|
||||
|
||||
async fn remove_score(
|
||||
&mut self,
|
||||
res: Resource<scoreboard::BedrockScoreboard>,
|
||||
entity_name: String,
|
||||
objective_name: String,
|
||||
) -> wasmtime::Result<()> {
|
||||
let player = self.get_bedrock_scoreboard_res(&res)?.provider.clone();
|
||||
let mut custom_guard = player.custom_scoreboard.lock().await;
|
||||
if let Some(crate::entity::player::CustomScoreboard::Bedrock(sb)) = custom_guard.as_mut() {
|
||||
sb.remove_score(player.as_ref(), &entity_name, &objective_name)
|
||||
.await;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn reset_entity_scores(
|
||||
&mut self,
|
||||
res: Resource<scoreboard::BedrockScoreboard>,
|
||||
entity_name: String,
|
||||
) -> wasmtime::Result<()> {
|
||||
let player = self.get_bedrock_scoreboard_res(&res)?.provider.clone();
|
||||
let mut custom_guard = player.custom_scoreboard.lock().await;
|
||||
if let Some(crate::entity::player::CustomScoreboard::Bedrock(sb)) = custom_guard.as_mut() {
|
||||
sb.reset_scores_for_entity(player.as_ref(), &entity_name)
|
||||
.await;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn drop(
|
||||
&mut self,
|
||||
_res: Resource<scoreboard::BedrockScoreboard>,
|
||||
) -> wasmtime::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -495,7 +495,11 @@ impl pumpkin::plugin::world::HostWorld for PluginHostState {
|
||||
world: Resource<World>,
|
||||
) -> wasmtime::Result<Resource<pumpkin::plugin::scoreboard::Scoreboard>> {
|
||||
let world_provider = self.get_world_res(&world)?.provider.clone();
|
||||
self.add_scoreboard(world_provider)
|
||||
self.add_scoreboard(
|
||||
crate::plugin::loader::wasm::wasm_host::state::ScoreboardProvider::World(
|
||||
world_provider,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
async fn play_sound(
|
||||
|
||||
@@ -3407,6 +3407,9 @@ impl World {
|
||||
// Sends initial time
|
||||
player.send_time(self).await;
|
||||
|
||||
// Sends initial scoreboard state
|
||||
player.send_scoreboard().await;
|
||||
|
||||
let (spawn_block_pos, yaw, pitch) = {
|
||||
let level_info_lock = self.level_info.load();
|
||||
(
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,6 +14,7 @@ pub fn build() -> TokenStream {
|
||||
let variants = array_to_tokenstream(&sound_categories);
|
||||
|
||||
quote! {
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum ScoreboardDisplaySlot {
|
||||
#variants
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user