feat: bedrock translations

This commit is contained in:
Alexander Medvedev 2026-05-03 21:31:46 +02:00
parent fb5ede696c
commit 9b88ef56e4
101 changed files with 46957 additions and 17951 deletions

View File

@ -101,7 +101,7 @@ pub fn build() -> TokenStream {
let max_level = enchantment.max_level; let max_level = enchantment.max_level;
let slots = enchantment.slots; let slots = enchantment.slots;
let slots = slots.iter().map(AttributeModifierSlot::to_tokens); let slots = slots.iter().map(AttributeModifierSlot::to_tokens);
let Translate { translate, with: _ } = &*enchantment.description.0.content else { let Translate { translate, bedrock_translate: _, with: _ } = &*enchantment.description.0.content else {
panic!() panic!()
}; };
let translate = translate.to_string(); let translate = translate.to_string();

View File

@ -84,6 +84,7 @@ impl ToTokens for ItemComponents {
let TextContent::Translate { let TextContent::Translate {
translate: text, translate: text,
bedrock_translate: _,
with: _, with: _,
} = *self.item_name.clone().0.content } = *self.item_name.clone().0.content
else { else {

View File

@ -1,33 +1,60 @@
use proc_macro2::TokenStream; use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote}; use quote::{format_ident, quote};
use std::{collections::BTreeMap, fs}; use std::{collections::BTreeMap, fs};
/// Generates the `TokenStream` for translation key constants sourced from `en_us.json`.
pub fn build() -> TokenStream { pub fn build() -> TokenStream {
let en_us: BTreeMap<String, String> = serde_json::from_str( let java_json: BTreeMap<String, String> = serde_json::from_str(
&fs::read_to_string("../assets/en_us.json").expect("en_us is missing"), &fs::read_to_string("../assets/en_us_java.json").expect("en_us_java is missing"),
) )
.unwrap(); .unwrap();
let mut constants = TokenStream::new(); let mut java_constants = TokenStream::new();
for (name, value) in &java_json {
let ident = to_valid_ident(name);
java_constants.extend(quote! {
#[doc = #value]
pub const #ident: &str = #name;
});
}
for (name, value) in &en_us { let bedrock_content = fs::read_to_string("../assets/en_us_bedrock.lang").expect("en_us_bedrock is missing");
let clean_name = name.to_uppercase().replace(['.', '-'], "_"); let mut bedrock_constants = TokenStream::new();
let ident = format_ident!("{}", clean_name);
if value.is_empty() { for line in bedrock_content.lines() {
constants.extend(quote! { let line = line.trim();
pub const #ident: &str = #name; if line.is_empty() || line.starts_with('#') || line.starts_with('/') {
}); continue;
} else { }
constants.extend(quote! {
if let Some((name, value)) = line.split_once('=') {
let name = name.trim();
let value = value.trim();
let ident = to_valid_ident(name);
bedrock_constants.extend(quote! {
#[doc = #value] #[doc = #value]
pub const #ident: &str = #name; pub const #ident: &str = #name;
}); });
} }
} }
// --- Final Assembly ---
quote! { quote! {
#constants pub mod java {
#java_constants
}
pub mod bedrock {
#bedrock_constants
}
} }
} }
fn to_valid_ident(name: &str) -> Ident {
let mut clean = name.to_uppercase().replace(['.', ':', '-'], "_");
if clean.chars().next().map_or(false, |c| c.is_ascii_digit()) {
clean.insert(0, '_');
}
format_ident!("{}", clean)
}

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,7 @@ use std::io::{Error, Read, Write};
use pumpkin_macros::packet; use pumpkin_macros::packet;
use crate::{ use crate::{
codec::{var_int::VarInt, var_ulong::VarULong}, codec::var_ulong::VarULong,
serial::{PacketRead, PacketWrite}, serial::{PacketRead, PacketWrite},
}; };
@ -37,10 +37,7 @@ impl PacketRead for AnimateAction {
4 => Ok(Self::MagicCriticalHit), 4 => Ok(Self::MagicCriticalHit),
128 => Ok(Self::RowRight), 128 => Ok(Self::RowRight),
129 => Ok(Self::RowLeft), 129 => Ok(Self::RowLeft),
_ => Err(Error::other(format!( _ => Err(Error::other(format!("Invalid animate action ID: {action}"))),
"Invalid animate action ID: {}",
action
))),
} }
} }
} }

View File

@ -1,7 +1,7 @@
use pumpkin_macros::packet; use pumpkin_macros::packet;
use uuid::Uuid; use uuid::Uuid;
use crate::{codec::var_uint::VarUInt, serial::PacketRead}; use crate::serial::PacketRead;
#[derive(Debug, PacketRead)] #[derive(Debug, PacketRead)]
#[packet(77)] #[packet(77)]

View File

@ -99,7 +99,7 @@ impl TryFrom<i32> for Action {
34 => Ok(Self::StartFlying), 34 => Ok(Self::StartFlying),
35 => Ok(Self::StopFlying), 35 => Ok(Self::StopFlying),
36 => Ok(Self::ClientAckServerData), 36 => Ok(Self::ClientAckServerData),
_ => Err(format!("Invalid action ID: {}", value)), _ => Err(format!("Invalid action ID: {value}")),
} }
} }
} }
@ -108,6 +108,6 @@ impl PacketRead for Action {
fn read<R: Read>(reader: &mut R) -> Result<Self, Error> { fn read<R: Read>(reader: &mut R) -> Result<Self, Error> {
let action = VarInt::read(reader)?; let action = VarInt::read(reader)?;
Action::try_from(action.0).map_err(Error::other) Self::try_from(action.0).map_err(Error::other)
} }
} }

View File

@ -5,13 +5,8 @@ use pumpkin_util::math::{position::BlockPos, vector2::Vector2, vector3::Vector3}
use crate::{ use crate::{
codec::{ codec::{
bitset::Bitset, bitset::Bitset, var_int::VarInt, var_long::VarLong, var_uint::VarUInt, var_ulong::VarULong,
var_int::VarInt,
var_long::{VarLong, VarLongType},
var_uint::VarUInt,
var_ulong::VarULong,
}, },
packet::{self, Packet},
serial::PacketRead, serial::PacketRead,
}; };
@ -40,6 +35,7 @@ pub struct SPlayerAuthInput {
} }
impl PacketRead for SPlayerAuthInput { impl PacketRead for SPlayerAuthInput {
#[expect(clippy::useless_let_if_seq)]
fn read<R: Read>(reader: &mut R) -> Result<Self, Error> { fn read<R: Read>(reader: &mut R) -> Result<Self, Error> {
let pitch = f32::read(reader)?; let pitch = f32::read(reader)?;
let yaw = f32::read(reader)?; let yaw = f32::read(reader)?;
@ -129,7 +125,7 @@ pub struct PlayerBlockAction {
pub face: VarInt, pub face: VarInt,
} }
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(u32)] #[repr(u32)]
pub enum InputMode { pub enum InputMode {
Mouse = 1, Mouse = 1,
@ -138,7 +134,7 @@ pub enum InputMode {
MotionController = 4, MotionController = 4,
} }
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(u32)] #[repr(u32)]
pub enum PlayMode { pub enum PlayMode {
Normal = 0, Normal = 0,
@ -148,7 +144,7 @@ pub enum PlayMode {
NumModes = 9, NumModes = 9,
} }
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(u32)] #[repr(u32)]
pub enum InteractionModel { pub enum InteractionModel {
Touch = 0, Touch = 0,
@ -156,7 +152,7 @@ pub enum InteractionModel {
Classic = 2, Classic = 2,
} }
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum InputData { pub enum InputData {
Ascend = 0, Ascend = 0,
Descend = 1, Descend = 1,

View File

@ -38,7 +38,7 @@ impl SText {
} }
#[must_use] #[must_use]
pub fn translation(message: String, parameters: Vec<String>) -> Self { pub const fn translation(message: String, parameters: Vec<String>) -> Self {
Self { Self {
needs_translation: true, needs_translation: true,
r#type: TextPacketType::Translation, r#type: TextPacketType::Translation,

View File

@ -168,7 +168,7 @@ impl PacketRead for VarLong {
let decoded = ((val >> 1) as i64) ^ -((val & 1) as i64); let decoded = ((val >> 1) as i64) ^ -((val & 1) as i64);
Ok(VarLong(decoded)) Ok(Self(decoded))
} }
} }

View File

@ -12,6 +12,7 @@ use serde::de::{Error, MapAccess, SeqAccess, Visitor};
use serde::{Deserialize, Deserializer, Serialize}; use serde::{Deserialize, Deserializer, Serialize};
use std::borrow::Cow; use std::borrow::Cow;
use std::fmt::Formatter; use std::fmt::Formatter;
use std::fmt::Write;
use std::sync::LazyLock; use std::sync::LazyLock;
use style::Style; use style::Style;
@ -103,9 +104,11 @@ impl TextComponentBase {
pub fn to_pretty_console(self) -> String { pub fn to_pretty_console(self) -> String {
let mut text = match *self.content { let mut text = match *self.content {
TextContent::Text { text } => text.into_owned(), TextContent::Text { text } => text.into_owned(),
TextContent::Translate { translate, with } => { TextContent::Translate {
translation_to_pretty(format!("minecraft:{translate}"), Locale::EnUs, with) translate,
} bedrock_translate: _,
with,
} => translation_to_pretty(format!("minecraft:{translate}"), Locale::EnUs, with),
TextContent::EntityNames { TextContent::EntityNames {
selector, selector,
separator: _, separator: _,
@ -144,7 +147,7 @@ impl TextComponentBase {
if let Some(color) = &self.style.color { if let Some(color) = &self.style.color {
match color { match color {
Color::Named(named) => { Color::Named(named) => {
text.push_str(&format!("§{}", named.to_legacy_char())); let _ = write!(text, "§{}", named.to_legacy_char());
} }
Color::Rgb(_rgb) => { Color::Rgb(_rgb) => {
// Bedrock doesn't strictly support Java's §x hex format. // Bedrock doesn't strictly support Java's §x hex format.
@ -174,7 +177,11 @@ impl TextComponentBase {
// 2. Resolve Content // 2. Resolve Content
match &*self.content { match &*self.content {
TextContent::Text { text: t } => text.push_str(t), TextContent::Text { text: t } => text.push_str(t),
TextContent::Translate { translate, with } => { TextContent::Translate {
translate,
bedrock_translate: _,
with,
} => {
// TODO // TODO
text.push_str(&get_translation_text( text.push_str(&get_translation_text(
translate.to_string(), translate.to_string(),
@ -211,9 +218,11 @@ impl TextComponentBase {
pub fn get_text(self, locale: Locale) -> String { pub fn get_text(self, locale: Locale) -> String {
let mut text = match *self.content { let mut text = match *self.content {
TextContent::Text { text } => text.into_owned(), TextContent::Text { text } => text.into_owned(),
TextContent::Translate { translate, with } => { TextContent::Translate {
get_translation_text(format!("minecraft:{translate}"), locale, with) translate,
} bedrock_translate: _,
with,
} => get_translation_text(format!("minecraft:{translate}"), locale, with),
TextContent::EntityNames { TextContent::EntityNames {
selector, selector,
separator: _, separator: _,
@ -382,6 +391,37 @@ impl TextComponent {
Self(TextComponentBase { Self(TextComponentBase {
content: Box::new(TextContent::Translate { content: Box::new(TextContent::Translate {
translate: key.into(), translate: key.into(),
bedrock_translate: None,
with: with.into().into_iter().map(|x| x.0).collect(),
}),
style: Box::new(Style::default()),
extra: vec![],
})
}
/// Creates a new text component with a translation key that has a Bedrock-specific fallback.
///
/// # Arguments
/// - `java_key` – The translation key for Java (e.g., "multiplayer.player.joined").
/// - `bedrock_key` – The translation key for Bedrock (e.g., "multiplayer.player.joined").
/// - `with` – The substitution parameters for the translation.
///
/// # Returns
/// A new `TextComponent` that will be translated natively on both clients.
#[must_use]
pub fn translate_cross<
K1: Into<Cow<'static, str>>,
K2: Into<Cow<'static, str>>,
W: Into<Vec<Self>>,
>(
java_key: K1,
bedrock_key: K2,
with: W,
) -> Self {
Self(TextComponentBase {
content: Box::new(TextContent::Translate {
translate: java_key.into(),
bedrock_translate: Some(bedrock_key.into()),
with: with.into().into_iter().map(|x| x.0).collect(), with: with.into().into_iter().map(|x| x.0).collect(),
}), }),
style: Box::new(Style::default()), style: Box::new(Style::default()),
@ -1003,6 +1043,9 @@ pub enum TextContent {
Translate { Translate {
/// The translation key (e.g. "multiplayer.player.joined"). /// The translation key (e.g. "multiplayer.player.joined").
translate: Cow<'static, str>, translate: Cow<'static, str>,
/// Bedrock translation key. If specified, Bedrock clients receive an `SText::translation` packet.
#[serde(skip, default)]
bedrock_translate: Option<Cow<'static, str>>,
/// Substitution parameters for the translation. /// Substitution parameters for the translation.
#[serde(default, skip_serializing_if = "Vec::is_empty")] #[serde(default, skip_serializing_if = "Vec::is_empty")]
with: Vec<TextComponentBase>, with: Vec<TextComponentBase>,

View File

@ -14,10 +14,9 @@ use std::{
/// - Try to optimize code of '`to_translated`' /// - Try to optimize code of '`to_translated`'
use crate::text::{TextComponentBase, TextContent, style::Style}; use crate::text::{TextComponentBase, TextContent, style::Style};
static VANILLA_EN_US_JSON: &str = include_str!("../../assets/en_us.json"); static VANILLA_EN_US_JSON: &str = include_str!("../../assets/en_us_java.json");
static PUMPKIN_BRB_JSON: &str = include_str!("../../assets/translations/brb.json"); static PUMPKIN_BRB_JSON: &str = include_str!("../../assets/translations/brb.json");
static PUMPKIN_DE_DE_JSON: &str = include_str!("../../assets/translations/de_de.json"); static PUMPKIN_DE_DE_JSON: &str = include_str!("../../assets/translations/de_de.json");
static PUMPKIN_EN_US_JSON: &str = include_str!("../../assets/translations/en_us.json");
static PUMPKIN_ES_ES_JSON: &str = include_str!("../../assets/translations/es_es.json"); static PUMPKIN_ES_ES_JSON: &str = include_str!("../../assets/translations/es_es.json");
static PUMPKIN_FR_FR_JSON: &str = include_str!("../../assets/translations/fr_fr.json"); static PUMPKIN_FR_FR_JSON: &str = include_str!("../../assets/translations/fr_fr.json");
static PUMPKING_IT_IT_JSON: &str = include_str!("../../assets/translations/it_it.json"); static PUMPKING_IT_IT_JSON: &str = include_str!("../../assets/translations/it_it.json");
@ -271,13 +270,11 @@ pub static TRANSLATIONS: LazyLock<Mutex<[HashMap<String, String>; Locale::COUNT]
let mut array: [HashMap<String, String>; Locale::COUNT] = let mut array: [HashMap<String, String>; Locale::COUNT] =
std::array::from_fn(|_| HashMap::new()); std::array::from_fn(|_| HashMap::new());
let vanilla_en_us: HashMap<String, String> = let vanilla_en_us: HashMap<String, String> =
serde_json::from_str(VANILLA_EN_US_JSON).expect("Could not parse en_us.json."); serde_json::from_str(VANILLA_EN_US_JSON).expect("Could not parse en_us_java.json.");
let pumpkin_brb: HashMap<String, String> = let pumpkin_brb: HashMap<String, String> =
serde_json::from_str(PUMPKIN_BRB_JSON).expect("Could not parse brb.json."); serde_json::from_str(PUMPKIN_BRB_JSON).expect("Could not parse brb.json.");
let pumpkin_de_de: HashMap<String, String> = let pumpkin_de_de: HashMap<String, String> =
serde_json::from_str(PUMPKIN_DE_DE_JSON).expect("Could not parse de_de.json."); serde_json::from_str(PUMPKIN_DE_DE_JSON).expect("Could not parse de_de.json.");
let pumpkin_en_us: HashMap<String, String> =
serde_json::from_str(PUMPKIN_EN_US_JSON).expect("Could not parse en_us.json.");
let pumpkin_es_es: HashMap<String, String> = let pumpkin_es_es: HashMap<String, String> =
serde_json::from_str(PUMPKIN_ES_ES_JSON).expect("Could not parse es_es.json."); serde_json::from_str(PUMPKIN_ES_ES_JSON).expect("Could not parse es_es.json.");
let pumpkin_fr_fr: HashMap<String, String> = let pumpkin_fr_fr: HashMap<String, String> =
@ -328,9 +325,6 @@ pub static TRANSLATIONS: LazyLock<Mutex<[HashMap<String, String>; Locale::COUNT]
for (key, value) in pumpkin_de_de { for (key, value) in pumpkin_de_de {
array[Locale::DeDe as usize].insert(format!("pumpkin:{key}"), value); array[Locale::DeDe as usize].insert(format!("pumpkin:{key}"), value);
} }
for (key, value) in pumpkin_en_us {
array[Locale::EnUs as usize].insert(format!("pumpkin:{key}"), value);
}
for (key, value) in pumpkin_es_es { for (key, value) in pumpkin_es_es {
array[Locale::EsEs as usize].insert(format!("pumpkin:{key}"), value); array[Locale::EsEs as usize].insert(format!("pumpkin:{key}"), value);
} }

View File

@ -90,6 +90,10 @@ impl ScreenHandlerFactory for AnvilScreenFactory {
} }
fn get_display_name(&self) -> TextComponent { fn get_display_name(&self) -> TextComponent {
TextComponent::translate(translation::CONTAINER_REPAIR, &[]) TextComponent::translate_cross(
translation::java::CONTAINER_REPAIR,
translation::bedrock::CONTAINER_REPAIR,
&[],
)
} }
} }

View File

@ -38,7 +38,11 @@ impl ScreenHandlerFactory for BarrelScreenFactory {
} }
fn get_display_name(&self) -> TextComponent { fn get_display_name(&self) -> TextComponent {
TextComponent::translate(translation::CONTAINER_BARREL, &[]) TextComponent::translate_cross(
translation::java::CONTAINER_BARREL,
translation::bedrock::CONTAINER_BARREL,
&[],
)
} }
} }

View File

@ -259,7 +259,11 @@ impl BlockBehaviour for BedBlock {
{ {
args.player args.player
.send_system_message_raw( .send_system_message_raw(
&TextComponent::translate(translation::BLOCK_MINECRAFT_BED_OBSTRUCTED, []), &TextComponent::translate_cross(
translation::java::BLOCK_MINECRAFT_BED_OBSTRUCTED,
translation::java::BLOCK_MINECRAFT_BED_OBSTRUCTED,
[],
),
true, true,
) )
.await; .await;
@ -272,7 +276,11 @@ impl BlockBehaviour for BedBlock {
args.player args.player
.send_system_message_raw( .send_system_message_raw(
&TextComponent::translate(translation::BLOCK_MINECRAFT_BED_OCCUPIED, []), &TextComponent::translate_cross(
translation::java::BLOCK_MINECRAFT_BED_OCCUPIED,
translation::bedrock::TILE_BED_OCCUPIED,
[],
),
true, true,
) )
.await; .await;
@ -291,8 +299,9 @@ impl BlockBehaviour for BedBlock {
{ {
args.player args.player
.send_system_message_raw( .send_system_message_raw(
&TextComponent::translate( &TextComponent::translate_cross(
translation::BLOCK_MINECRAFT_BED_TOO_FAR_AWAY, translation::java::BLOCK_MINECRAFT_BED_TOO_FAR_AWAY,
translation::java::BLOCK_MINECRAFT_BED_TOO_FAR_AWAY,
[], [],
), ),
true, true,
@ -313,8 +322,9 @@ impl BlockBehaviour for BedBlock {
.await .await
{ {
args.player args.player
.send_system_message(&TextComponent::translate( .send_system_message(&TextComponent::translate_cross(
translation::BLOCK_MINECRAFT_SET_SPAWN, translation::java::BLOCK_MINECRAFT_SET_SPAWN,
translation::bedrock::TILE_BED_RESPAWNSET,
[], [],
)) ))
.await; .await;
@ -324,7 +334,11 @@ impl BlockBehaviour for BedBlock {
if !can_sleep(args.world).await { if !can_sleep(args.world).await {
args.player args.player
.send_system_message_raw( .send_system_message_raw(
&TextComponent::translate(translation::BLOCK_MINECRAFT_BED_NO_SLEEP, []), &TextComponent::translate_cross(
translation::java::BLOCK_MINECRAFT_BED_NO_SLEEP,
translation::java::BLOCK_MINECRAFT_BED_NO_SLEEP,
[],
),
true, true,
) )
.await; .await;
@ -343,8 +357,9 @@ impl BlockBehaviour for BedBlock {
{ {
args.player args.player
.send_system_message_raw( .send_system_message_raw(
&TextComponent::translate( &TextComponent::translate_cross(
translation::BLOCK_MINECRAFT_BED_NOT_SAFE, translation::java::BLOCK_MINECRAFT_BED_NOT_SAFE,
translation::java::BLOCK_MINECRAFT_BED_NOT_SAFE,
[], [],
), ),
true, true,

View File

@ -75,7 +75,11 @@ impl ScreenHandlerFactory for BlastingFurnaceScreenFactory {
} }
fn get_display_name(&self) -> pumpkin_util::text::TextComponent { fn get_display_name(&self) -> pumpkin_util::text::TextComponent {
TextComponent::translate(translation::CONTAINER_BLAST_FURNACE, &[]) TextComponent::translate_cross(
translation::java::CONTAINER_BLAST_FURNACE,
translation::bedrock::TILE_BLAST_FURNACE_NAME,
&[],
)
} }
} }

View File

@ -38,7 +38,11 @@ impl ScreenHandlerFactory for BrewingScreenFactory {
} }
fn get_display_name(&self) -> TextComponent { fn get_display_name(&self) -> TextComponent {
TextComponent::translate(translation::CONTAINER_BREWING, &[]) TextComponent::translate_cross(
translation::java::CONTAINER_BREWING,
translation::bedrock::CONTAINER_BREWING,
&[],
)
} }
} }

View File

@ -57,9 +57,17 @@ impl ScreenHandlerFactory for ChestScreenFactory {
fn get_display_name(&self) -> TextComponent { fn get_display_name(&self) -> TextComponent {
if self.0.size() > 27 { if self.0.size() > 27 {
TextComponent::translate(translation::CONTAINER_CHESTDOUBLE, &[]) TextComponent::translate_cross(
translation::java::CONTAINER_CHESTDOUBLE,
translation::bedrock::CONTAINER_CHESTDOUBLE,
&[],
)
} else { } else {
TextComponent::translate(translation::CONTAINER_CHEST, &[]) TextComponent::translate_cross(
translation::java::CONTAINER_CHEST,
translation::bedrock::CONTAINER_CHEST,
&[],
)
} }
} }
} }

View File

@ -45,6 +45,10 @@ impl ScreenHandlerFactory for CraftingTableScreenFactory {
} }
fn get_display_name(&self) -> TextComponent { fn get_display_name(&self) -> TextComponent {
TextComponent::translate(translation::CONTAINER_CRAFTING, &[]) TextComponent::translate_cross(
translation::java::CONTAINER_CRAFTING,
translation::bedrock::CONTAINER_CRAFTING,
&[],
)
} }
} }

View File

@ -38,7 +38,11 @@ impl ScreenHandlerFactory for EnderChestScreenFactory {
} }
fn get_display_name(&self) -> TextComponent { fn get_display_name(&self) -> TextComponent {
TextComponent::translate(translation::CONTAINER_ENDERCHEST, &[]) TextComponent::translate_cross(
translation::java::CONTAINER_ENDERCHEST,
translation::bedrock::CONTAINER_ENDERCHEST,
&[],
)
} }
} }

View File

@ -75,7 +75,11 @@ impl ScreenHandlerFactory for FurnaceScreenFactory {
} }
fn get_display_name(&self) -> pumpkin_util::text::TextComponent { fn get_display_name(&self) -> pumpkin_util::text::TextComponent {
TextComponent::translate(translation::CONTAINER_FURNACE, &[]) TextComponent::translate_cross(
translation::java::CONTAINER_FURNACE,
translation::bedrock::CONTAINER_FURNACE,
&[],
)
} }
} }

View File

@ -43,7 +43,11 @@ impl ScreenHandlerFactory for HopperBlockScreenFactory {
} }
fn get_display_name(&self) -> TextComponent { fn get_display_name(&self) -> TextComponent {
TextComponent::translate(translation::CONTAINER_HOPPER, &[]) TextComponent::translate_cross(
translation::java::CONTAINER_HOPPER,
translation::bedrock::CONTAINER_HOPPER,
&[],
)
} }
} }

View File

@ -47,7 +47,11 @@ impl ScreenHandlerFactory for DropperScreenFactory {
} }
fn get_display_name(&self) -> TextComponent { fn get_display_name(&self) -> TextComponent {
TextComponent::translate(translation::CONTAINER_DROPPER, &[]) TextComponent::translate_cross(
translation::java::CONTAINER_DROPPER,
translation::bedrock::CONTAINER_DROPPER,
&[],
)
} }
} }

View File

@ -38,7 +38,11 @@ impl ScreenHandlerFactory for ShulkerBoxScreenFactory {
} }
fn get_display_name(&self) -> TextComponent { fn get_display_name(&self) -> TextComponent {
TextComponent::translate(translation::CONTAINER_SHULKERBOX, &[]) TextComponent::translate_cross(
translation::java::CONTAINER_SHULKERBOX,
translation::bedrock::CONTAINER_SHULKERBOX,
&[],
)
} }
} }

View File

@ -74,7 +74,11 @@ impl ScreenHandlerFactory for SmokerScreenFactory {
} }
fn get_display_name(&self) -> pumpkin_util::text::TextComponent { fn get_display_name(&self) -> pumpkin_util::text::TextComponent {
TextComponent::translate(translation::CONTAINER_SMOKER, &[]) TextComponent::translate_cross(
translation::java::CONTAINER_SMOKER,
translation::bedrock::TILE_SMOKER_NAME,
&[],
)
} }
} }
#[pumpkin_block("minecraft:smoker")] #[pumpkin_block("minecraft:smoker")]

View File

@ -55,13 +55,15 @@ impl<'a> FindArg<'a> for BlockArgumentConsumer {
Some(Arg::Block(name)) => Block::from_name(name).map_or_else( Some(Arg::Block(name)) => Block::from_name(name).map_or_else(
|| { || {
if name.starts_with("minecraft:") { if name.starts_with("minecraft:") {
Err(CommandError::CommandFailed(TextComponent::translate( Err(CommandError::CommandFailed(TextComponent::translate_cross(
translation::ARGUMENT_BLOCK_ID_INVALID, translation::java::ARGUMENT_BLOCK_ID_INVALID,
translation::java::ARGUMENT_BLOCK_ID_INVALID,
[TextComponent::text((*name).to_string())], [TextComponent::text((*name).to_string())],
))) )))
} else { } else {
Err(CommandError::CommandFailed(TextComponent::translate( Err(CommandError::CommandFailed(TextComponent::translate_cross(
translation::ARGUMENT_BLOCK_ID_INVALID, translation::java::ARGUMENT_BLOCK_ID_INVALID,
translation::java::ARGUMENT_BLOCK_ID_INVALID,
[TextComponent::text("minecraft:".to_string() + *name)], [TextComponent::text("minecraft:".to_string() + *name)],
))) )))
} }
@ -121,13 +123,15 @@ impl<'a> FindArg<'a> for BlockPredicateArgumentConsumer {
Block::from_name(name).map_or_else( Block::from_name(name).map_or_else(
|| { || {
if name.starts_with("minecraft:") { if name.starts_with("minecraft:") {
Err(CommandError::CommandFailed(TextComponent::translate( Err(CommandError::CommandFailed(TextComponent::translate_cross(
translation::ARGUMENT_BLOCK_ID_INVALID, translation::java::ARGUMENT_BLOCK_ID_INVALID,
translation::java::ARGUMENT_BLOCK_ID_INVALID,
[TextComponent::text((*name).to_string())], [TextComponent::text((*name).to_string())],
))) )))
} else { } else {
Err(CommandError::CommandFailed(TextComponent::translate( Err(CommandError::CommandFailed(TextComponent::translate_cross(
translation::ARGUMENT_BLOCK_ID_INVALID, translation::java::ARGUMENT_BLOCK_ID_INVALID,
translation::java::ARGUMENT_BLOCK_ID_INVALID,
[TextComponent::text("minecraft:".to_string() + *name)], [TextComponent::text("minecraft:".to_string() + *name)],
))) )))
} }
@ -138,8 +142,9 @@ impl<'a> FindArg<'a> for BlockPredicateArgumentConsumer {
|tag| { |tag| {
get_tag_ids(RegistryKey::Block, tag).map_or_else( get_tag_ids(RegistryKey::Block, tag).map_or_else(
|| { || {
Err(CommandError::CommandFailed(TextComponent::translate( Err(CommandError::CommandFailed(TextComponent::translate_cross(
translation::ARGUMENTS_BLOCK_TAG_UNKNOWN, translation::java::ARGUMENTS_BLOCK_TAG_UNKNOWN,
translation::java::ARGUMENTS_BLOCK_TAG_UNKNOWN,
[TextComponent::text((*tag).to_string())], [TextComponent::text((*tag).to_string())],
))) )))
}, },

View File

@ -402,7 +402,11 @@ pub(crate) fn parse_target_selector_with_context(
parse_target_selector(raw_arg.value).map_err(|error| { parse_target_selector(raw_arg.value).map_err(|error| {
syntax_error_for_arg_with_cursor( syntax_error_for_arg_with_cursor(
raw_arg, raw_arg,
TextComponent::translate(translation::ARGUMENT_ENTITY_INVALID, []), TextComponent::translate_cross(
translation::java::ARGUMENT_ENTITY_INVALID,
translation::java::ARGUMENT_ENTITY_INVALID,
[],
),
error.cursor, error.cursor,
) )
}) })
@ -415,7 +419,11 @@ pub(crate) fn ensure_player_only_selector(
if selector.includes_entities() { if selector.includes_entities() {
Err(syntax_error_for_arg_with_cursor( Err(syntax_error_for_arg_with_cursor(
raw_arg, raw_arg,
TextComponent::translate(translation::ARGUMENT_PLAYER_ENTITIES, []), TextComponent::translate_cross(
translation::java::ARGUMENT_PLAYER_ENTITIES,
translation::java::ARGUMENT_PLAYER_ENTITIES,
[],
),
0, 0,
)) ))
} else { } else {
@ -483,7 +491,7 @@ mod test {
pumpkin_util::text::TextContent::Translate { translate, .. } => translate.as_ref(), pumpkin_util::text::TextContent::Translate { translate, .. } => translate.as_ref(),
_ => "", _ => "",
}; };
assert_eq!(translate_key, translation::ARGUMENT_PLAYER_ENTITIES); assert_eq!(translate_key, translation::java::ARGUMENT_PLAYER_ENTITIES);
assert_eq!(error.context.unwrap().cursor, 4); assert_eq!(error.context.unwrap().cursor, 4);
} }
} }

View File

@ -368,7 +368,11 @@ fn selector_suggestions() -> Vec<CommandSuggestion> {
fn syntax_player_unknown(raw_arg: RawArg<'_>) -> CommandSyntaxError { fn syntax_player_unknown(raw_arg: RawArg<'_>) -> CommandSyntaxError {
syntax_error_for_arg_with_cursor( syntax_error_for_arg_with_cursor(
raw_arg, raw_arg,
TextComponent::translate(translation::ARGUMENT_PLAYER_UNKNOWN, []), TextComponent::translate_cross(
translation::java::ARGUMENT_PLAYER_UNKNOWN,
translation::java::ARGUMENT_PLAYER_UNKNOWN,
[],
),
0, 0,
) )
} }
@ -416,7 +420,7 @@ mod test {
TextContent::Translate { translate, .. } => translate.as_ref(), TextContent::Translate { translate, .. } => translate.as_ref(),
_ => "", _ => "",
}; };
assert_eq!(translate_key, translation::ARGUMENT_PLAYER_UNKNOWN); assert_eq!(translate_key, translation::java::ARGUMENT_PLAYER_UNKNOWN);
assert_eq!(error.context.unwrap().cursor, 4); assert_eq!(error.context.unwrap().cursor, 4);
} }
} }

View File

@ -158,14 +158,16 @@ impl BlockPosArgumentConsumer {
let pos = Self::find_arg(args, name)?; let pos = Self::find_arg(args, name)?;
if world.level.try_get_chunk(&pos.chunk_position()).is_none() { if world.level.try_get_chunk(&pos.chunk_position()).is_none() {
return Err(CommandError::CommandFailed(TextComponent::translate( return Err(CommandError::CommandFailed(TextComponent::translate_cross(
"argument.pos.unloaded",
"argument.pos.unloaded", "argument.pos.unloaded",
[], [],
))); )));
} }
if !world.is_in_build_limit(pos) { if !world.is_in_build_limit(pos) {
return Err(CommandError::CommandFailed(TextComponent::translate( return Err(CommandError::CommandFailed(TextComponent::translate_cross(
"argument.pos.outofworld",
"argument.pos.outofworld", "argument.pos.outofworld",
[], [],
))); )));
@ -181,7 +183,8 @@ impl BlockPosArgumentConsumer {
let pos = Self::find_arg(args, name)?; let pos = Self::find_arg(args, name)?;
if !World::is_valid(pos) { if !World::is_valid(pos) {
return Err(CommandError::CommandFailed(TextComponent::translate( return Err(CommandError::CommandFailed(TextComponent::translate_cross(
"argument.pos.outofbounds",
"argument.pos.outofbounds", "argument.pos.outofbounds",
[], [],
))); )));

View File

@ -59,12 +59,14 @@ impl<'a> FindArg<'a> for ItemArgumentConsumer {
Some(Arg::Item(name)) => Item::from_registry_key(name).map_or_else( Some(Arg::Item(name)) => Item::from_registry_key(name).map_or_else(
|| { || {
if name.starts_with("minecraft:") { if name.starts_with("minecraft:") {
Err(CommandError::CommandFailed(TextComponent::translate( Err(CommandError::CommandFailed(TextComponent::translate_cross(
"argument.item.id.invalid",
"argument.item.id.invalid", "argument.item.id.invalid",
[TextComponent::text((*name).to_string())], [TextComponent::text((*name).to_string())],
))) )))
} else { } else {
Err(CommandError::CommandFailed(TextComponent::translate( Err(CommandError::CommandFailed(TextComponent::translate_cross(
"argument.item.id.invalid",
"argument.item.id.invalid", "argument.item.id.invalid",
[TextComponent::text("minecraft:".to_string() + *name)], [TextComponent::text("minecraft:".to_string() + *name)],
))) )))
@ -141,15 +143,21 @@ impl<'a> FindArg<'a> for ItemPredicateArgumentConsumer {
Item::from_registry_key(name).map_or_else( Item::from_registry_key(name).map_or_else(
|| { || {
if name.starts_with("minecraft:") { if name.starts_with("minecraft:") {
Err(CommandError::CommandFailed(TextComponent::translate( Err(CommandError::CommandFailed(
"argument.item.id.invalid", TextComponent::translate_cross(
[TextComponent::text((*name).to_string())], "argument.item.id.invalid",
))) "argument.item.id.invalid",
[TextComponent::text((*name).to_string())],
),
))
} else { } else {
Err(CommandError::CommandFailed(TextComponent::translate( Err(CommandError::CommandFailed(
"argument.item.id.invalid", TextComponent::translate_cross(
[TextComponent::text("minecraft:".to_string() + *name)], "argument.item.id.invalid",
))) "argument.item.id.invalid",
[TextComponent::text("minecraft:".to_string() + *name)],
),
))
} }
}, },
|item| Ok(ItemPredicate::Item(item)), |item| Ok(ItemPredicate::Item(item)),
@ -158,7 +166,8 @@ impl<'a> FindArg<'a> for ItemPredicateArgumentConsumer {
|tag| { |tag| {
get_tag_ids(RegistryKey::Item, tag).map_or_else( get_tag_ids(RegistryKey::Item, tag).map_or_else(
|| { || {
Err(CommandError::CommandFailed(TextComponent::translate( Err(CommandError::CommandFailed(TextComponent::translate_cross(
"arguments.item.tag.unknown",
"arguments.item.tag.unknown", "arguments.item.tag.unknown",
[TextComponent::text((*tag).to_string())], [TextComponent::text((*tag).to_string())],
))) )))

View File

@ -8,12 +8,18 @@ use crate::world::World;
use pumpkin_data::translation; use pumpkin_data::translation;
use pumpkin_util::math::position::BlockPos; use pumpkin_util::math::position::BlockPos;
pub const NOT_LOADED_ERROR_TYPE: CommandErrorType<0> = pub const NOT_LOADED_ERROR_TYPE: CommandErrorType<0> = CommandErrorType::new(
CommandErrorType::new(translation::ARGUMENT_POS_UNLOADED); translation::java::ARGUMENT_POS_UNLOADED,
pub const OUT_OF_WORLD_ERROR_TYPE: CommandErrorType<0> = translation::java::ARGUMENT_POS_UNLOADED,
CommandErrorType::new(translation::ARGUMENT_POS_OUTOFWORLD); );
pub const OUT_OF_BOUNDS_ERROR_TYPE: CommandErrorType<0> = pub const OUT_OF_WORLD_ERROR_TYPE: CommandErrorType<0> = CommandErrorType::new(
CommandErrorType::new(translation::ARGUMENT_POS_OUTOFBOUNDS); translation::java::ARGUMENT_POS_OUTOFWORLD,
translation::java::ARGUMENT_POS_OUTOFWORLD,
);
pub const OUT_OF_BOUNDS_ERROR_TYPE: CommandErrorType<0> = CommandErrorType::new(
translation::java::ARGUMENT_POS_OUTOFBOUNDS,
translation::java::ARGUMENT_POS_OUTOFBOUNDS,
);
/// An argument type for a 3-dimensional vector representing a block position. /// An argument type for a 3-dimensional vector representing a block position.
/// ///

View File

@ -12,8 +12,10 @@ pub mod block_pos;
pub mod rotation; pub mod rotation;
pub mod vec3; pub mod vec3;
pub const MIXED_TYPE_ERROR_TYPE: CommandErrorType<0> = pub const MIXED_TYPE_ERROR_TYPE: CommandErrorType<0> = CommandErrorType::new(
CommandErrorType::new(translation::ARGUMENT_POS_MIXED); translation::java::ARGUMENT_POS_MIXED,
translation::java::ARGUMENT_POS_MIXED,
);
/// Represents a single world coordinate. /// Represents a single world coordinate.
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]

View File

@ -7,8 +7,10 @@ use crate::command::string_reader::StringReader;
use pumpkin_data::translation; use pumpkin_data::translation;
use pumpkin_util::math::vector3::Vector3; use pumpkin_util::math::vector3::Vector3;
pub const NOT_COMPLETE_ERROR_TYPE: CommandErrorType<0> = pub const NOT_COMPLETE_ERROR_TYPE: CommandErrorType<0> = CommandErrorType::new(
CommandErrorType::new(translation::ARGUMENT_ROTATION_INCOMPLETE); translation::java::ARGUMENT_ROTATION_INCOMPLETE,
translation::java::ARGUMENT_ROTATION_INCOMPLETE,
);
pub struct RotationArgumentType; pub struct RotationArgumentType;

View File

@ -7,8 +7,10 @@ use crate::command::string_reader::StringReader;
use pumpkin_data::translation; use pumpkin_data::translation;
use pumpkin_util::math::vector3::Vector3; use pumpkin_util::math::vector3::Vector3;
pub const INCOMPLETE_ERROR_TYPE: CommandErrorType<0> = pub const INCOMPLETE_ERROR_TYPE: CommandErrorType<0> = CommandErrorType::new(
CommandErrorType::new(translation::ARGUMENT_POS3D_INCOMPLETE); translation::java::ARGUMENT_POS3D_INCOMPLETE,
translation::java::ARGUMENT_POS3D_INCOMPLETE,
);
/// An argument type for a 3-dimensional vector. /// An argument type for a 3-dimensional vector.
pub enum Vec3ArgumentType { pub enum Vec3ArgumentType {

View File

@ -11,24 +11,34 @@ use pumpkin_data::translation;
use std::sync::Arc; use std::sync::Arc;
/// A [`CommandErrorType`] to tell that no entities could be found. /// A [`CommandErrorType`] to tell that no entities could be found.
pub const NO_ENTITIES_ERROR_TYPE: CommandErrorType<0> = pub const NO_ENTITIES_ERROR_TYPE: CommandErrorType<0> = CommandErrorType::new(
CommandErrorType::new(translation::ARGUMENT_ENTITY_NOTFOUND_ENTITY); translation::java::ARGUMENT_ENTITY_NOTFOUND_ENTITY,
translation::java::ARGUMENT_ENTITY_NOTFOUND_ENTITY,
);
/// A [`CommandErrorType`] to tell that no players could be found. /// A [`CommandErrorType`] to tell that no players could be found.
pub const NO_PLAYERS_ERROR_TYPE: CommandErrorType<0> = pub const NO_PLAYERS_ERROR_TYPE: CommandErrorType<0> = CommandErrorType::new(
CommandErrorType::new(translation::ARGUMENT_ENTITY_NOTFOUND_PLAYER); translation::java::ARGUMENT_ENTITY_NOTFOUND_PLAYER,
translation::java::ARGUMENT_ENTITY_NOTFOUND_PLAYER,
);
/// A [`CommandErrorType`] to tell that only players are allowed for an entity selector. /// A [`CommandErrorType`] to tell that only players are allowed for an entity selector.
pub const ONLY_PLAYERS_ALLOWED_ERROR_TYPE: CommandErrorType<0> = pub const ONLY_PLAYERS_ALLOWED_ERROR_TYPE: CommandErrorType<0> = CommandErrorType::new(
CommandErrorType::new(translation::ARGUMENT_PLAYER_ENTITIES); translation::java::ARGUMENT_PLAYER_ENTITIES,
translation::java::ARGUMENT_PLAYER_ENTITIES,
);
/// A [`CommandErrorType`] to tell that only 1 entity is allowed for an entity selector. /// A [`CommandErrorType`] to tell that only 1 entity is allowed for an entity selector.
pub const NOT_SINGLE_ENTITY_ERROR_TYPE: CommandErrorType<0> = pub const NOT_SINGLE_ENTITY_ERROR_TYPE: CommandErrorType<0> = CommandErrorType::new(
CommandErrorType::new(translation::ARGUMENT_ENTITY_TOOMANY); translation::java::ARGUMENT_ENTITY_TOOMANY,
translation::java::ARGUMENT_ENTITY_TOOMANY,
);
/// A [`CommandErrorType`] to tell that only 1 player is allowed for an entity selector. /// A [`CommandErrorType`] to tell that only 1 player is allowed for an entity selector.
pub const NOT_SINGLE_PLAYER_ERROR_TYPE: CommandErrorType<0> = pub const NOT_SINGLE_PLAYER_ERROR_TYPE: CommandErrorType<0> = CommandErrorType::new(
CommandErrorType::new(translation::ARGUMENT_PLAYER_TOOMANY); translation::java::ARGUMENT_PLAYER_TOOMANY,
translation::java::ARGUMENT_PLAYER_TOOMANY,
);
pub const ENTITY_SELECTOR_PERMISSION: &str = "minecraft:command.selector"; pub const ENTITY_SELECTOR_PERMISSION: &str = "minecraft:command.selector";

View File

@ -8,8 +8,10 @@ use pumpkin_data::translation;
use pumpkin_util::math::vector3::Vector3; use pumpkin_util::math::vector3::Vector3;
use pumpkin_util::text::TextComponent; use pumpkin_util::text::TextComponent;
pub const INVALID_ERROR_TYPE: CommandErrorType<1> = pub const INVALID_ERROR_TYPE: CommandErrorType<1> = CommandErrorType::new(
CommandErrorType::new(translation::ARGUMENT_ANCHOR_INVALID); translation::java::ARGUMENT_ANCHOR_INVALID,
translation::java::ARGUMENT_ANCHOR_INVALID,
);
pub struct EntityAnchorArgumentType; pub struct EntityAnchorArgumentType;

View File

@ -10,20 +10,34 @@ use pumpkin_util::math::bounds::{DoubleBounds, FloatDegreeBounds, IntBounds};
use pumpkin_util::text::TextComponent; use pumpkin_util::text::TextComponent;
use std::str::FromStr; use std::str::FromStr;
pub const UNKNOWN_OPTION_ERROR_TYPE: CommandErrorType<1> = pub const UNKNOWN_OPTION_ERROR_TYPE: CommandErrorType<1> = CommandErrorType::new(
CommandErrorType::new(translation::ARGUMENT_ENTITY_OPTIONS_UNKNOWN); translation::java::ARGUMENT_ENTITY_OPTIONS_UNKNOWN,
pub const INAPPLICABLE_OPTION_ERROR_TYPE: CommandErrorType<1> = translation::java::ARGUMENT_ENTITY_OPTIONS_UNKNOWN,
CommandErrorType::new(translation::ARGUMENT_ENTITY_OPTIONS_INAPPLICABLE); );
pub const DISTANCE_NEGATIVE_ERROR_TYPE: CommandErrorType<0> = pub const INAPPLICABLE_OPTION_ERROR_TYPE: CommandErrorType<1> = CommandErrorType::new(
CommandErrorType::new(translation::ARGUMENT_ENTITY_OPTIONS_DISTANCE_NEGATIVE); translation::java::ARGUMENT_ENTITY_OPTIONS_INAPPLICABLE,
pub const LEVEL_NEGATIVE_ERROR_TYPE: CommandErrorType<0> = translation::java::ARGUMENT_ENTITY_OPTIONS_INAPPLICABLE,
CommandErrorType::new(translation::ARGUMENT_ENTITY_OPTIONS_LEVEL_NEGATIVE); );
pub const LIMIT_TOO_SMALL_ERROR_TYPE: CommandErrorType<0> = pub const DISTANCE_NEGATIVE_ERROR_TYPE: CommandErrorType<0> = CommandErrorType::new(
CommandErrorType::new(translation::ARGUMENT_ENTITY_OPTIONS_LIMIT_TOOSMALL); translation::java::ARGUMENT_ENTITY_OPTIONS_DISTANCE_NEGATIVE,
pub const SORT_UNKNOWN_ERROR_TYPE: CommandErrorType<1> = translation::java::ARGUMENT_ENTITY_OPTIONS_DISTANCE_NEGATIVE,
CommandErrorType::new(translation::ARGUMENT_ENTITY_OPTIONS_SORT_IRREVERSIBLE); );
pub const GAMEMODE_INVALID_ERROR_TYPE: CommandErrorType<1> = pub const LEVEL_NEGATIVE_ERROR_TYPE: CommandErrorType<0> = CommandErrorType::new(
CommandErrorType::new(translation::ARGUMENT_ENTITY_OPTIONS_MODE_INVALID); translation::java::ARGUMENT_ENTITY_OPTIONS_LEVEL_NEGATIVE,
translation::java::ARGUMENT_ENTITY_OPTIONS_LEVEL_NEGATIVE,
);
pub const LIMIT_TOO_SMALL_ERROR_TYPE: CommandErrorType<0> = CommandErrorType::new(
translation::java::ARGUMENT_ENTITY_OPTIONS_LIMIT_TOOSMALL,
translation::java::ARGUMENT_ENTITY_OPTIONS_LIMIT_TOOSMALL,
);
pub const SORT_UNKNOWN_ERROR_TYPE: CommandErrorType<1> = CommandErrorType::new(
translation::java::ARGUMENT_ENTITY_OPTIONS_SORT_IRREVERSIBLE,
translation::java::ARGUMENT_ENTITY_OPTIONS_SORT_IRREVERSIBLE,
);
pub const GAMEMODE_INVALID_ERROR_TYPE: CommandErrorType<1> = CommandErrorType::new(
translation::java::ARGUMENT_ENTITY_OPTIONS_MODE_INVALID,
translation::java::ARGUMENT_ENTITY_OPTIONS_MODE_INVALID,
);
/// Options to customize an [`EntitySelectorParser`]. /// Options to customize an [`EntitySelectorParser`].
/// ///

View File

@ -17,23 +17,35 @@ use pumpkin_util::math::vector3::Vector3;
use pumpkin_util::text::TextComponent; use pumpkin_util::text::TextComponent;
use uuid::Uuid; use uuid::Uuid;
pub const INVALID_NAME_OR_UUID_ERROR_TYPE: CommandErrorType<0> = pub const INVALID_NAME_OR_UUID_ERROR_TYPE: CommandErrorType<0> = CommandErrorType::new(
CommandErrorType::new(translation::ARGUMENT_ENTITY_INVALID); translation::java::ARGUMENT_ENTITY_INVALID,
translation::java::ARGUMENT_ENTITY_INVALID,
);
pub const UNKNOWN_SELECTOR_TYPE_ERROR_TYPE: CommandErrorType<1> = pub const UNKNOWN_SELECTOR_TYPE_ERROR_TYPE: CommandErrorType<1> = CommandErrorType::new(
CommandErrorType::new(translation::ARGUMENT_ENTITY_SELECTOR_UNKNOWN); translation::java::ARGUMENT_ENTITY_SELECTOR_UNKNOWN,
translation::java::ARGUMENT_ENTITY_SELECTOR_UNKNOWN,
);
pub const SELECTORS_NOT_ALLOWED_ERROR_TYPE: CommandErrorType<0> = pub const SELECTORS_NOT_ALLOWED_ERROR_TYPE: CommandErrorType<0> = CommandErrorType::new(
CommandErrorType::new(translation::ARGUMENT_ENTITY_SELECTOR_NOT_ALLOWED); translation::java::ARGUMENT_ENTITY_SELECTOR_NOT_ALLOWED,
translation::java::ARGUMENT_ENTITY_SELECTOR_NOT_ALLOWED,
);
pub const MISSING_SELECTOR_TYPE_ERROR_TYPE: CommandErrorType<0> = pub const MISSING_SELECTOR_TYPE_ERROR_TYPE: CommandErrorType<0> = CommandErrorType::new(
CommandErrorType::new(translation::ARGUMENT_ENTITY_SELECTOR_MISSING); translation::java::ARGUMENT_ENTITY_SELECTOR_MISSING,
translation::java::ARGUMENT_ENTITY_SELECTOR_MISSING,
);
pub const EXPECTED_END_OF_OPTIONS_ERROR_TYPE: CommandErrorType<0> = pub const EXPECTED_END_OF_OPTIONS_ERROR_TYPE: CommandErrorType<0> = CommandErrorType::new(
CommandErrorType::new(translation::ARGUMENT_ENTITY_OPTIONS_UNTERMINATED); translation::java::ARGUMENT_ENTITY_OPTIONS_UNTERMINATED,
translation::java::ARGUMENT_ENTITY_OPTIONS_UNTERMINATED,
);
pub const EXPECTED_OPTION_VALUE_ERROR_TYPE: CommandErrorType<1> = pub const EXPECTED_OPTION_VALUE_ERROR_TYPE: CommandErrorType<1> = CommandErrorType::new(
CommandErrorType::new(translation::ARGUMENT_ENTITY_OPTIONS_VALUELESS); translation::java::ARGUMENT_ENTITY_OPTIONS_VALUELESS,
translation::java::ARGUMENT_ENTITY_OPTIONS_VALUELESS,
);
bitflags! { bitflags! {
/// A list of bit flags to set entity selector parser properties. /// A list of bit flags to set entity selector parser properties.

View File

@ -11,8 +11,10 @@ use crate::net::GameProfile;
use pumpkin_data::translation; use pumpkin_data::translation;
use uuid::Uuid; use uuid::Uuid;
pub const UNKNOWN_PLAYER_ERROR_TYPE: CommandErrorType<0> = pub const UNKNOWN_PLAYER_ERROR_TYPE: CommandErrorType<0> = CommandErrorType::new(
CommandErrorType::new(translation::ARGUMENT_PLAYER_UNKNOWN); translation::java::ARGUMENT_PLAYER_UNKNOWN,
translation::java::ARGUMENT_PLAYER_UNKNOWN,
);
/// A result from the [`GameProfileArgumentType`], which can be resolved into /// A result from the [`GameProfileArgumentType`], which can be resolved into
/// one or more [`GameProfile`]s, successfully or not. /// one or more [`GameProfile`]s, successfully or not.

View File

@ -64,12 +64,18 @@ macro_rules! impl_copy_get {
}; };
} }
const EMPTY_BOUNDS_ERROR_TYPE: CommandErrorType<0> = const EMPTY_BOUNDS_ERROR_TYPE: CommandErrorType<0> = CommandErrorType::new(
CommandErrorType::new(translation::ARGUMENT_RANGE_EMPTY); translation::java::ARGUMENT_RANGE_EMPTY,
const SWAPPED_BOUNDS_ERROR_TYPE: CommandErrorType<0> = translation::java::ARGUMENT_RANGE_EMPTY,
CommandErrorType::new(translation::ARGUMENT_RANGE_SWAPPED); );
const INVALID_IDENTIFIER_ERROR_TYPE: CommandErrorType<0> = const SWAPPED_BOUNDS_ERROR_TYPE: CommandErrorType<0> = CommandErrorType::new(
CommandErrorType::new(translation::ARGUMENT_ID_INVALID); translation::java::ARGUMENT_RANGE_SWAPPED,
translation::java::ARGUMENT_RANGE_SWAPPED,
);
const INVALID_IDENTIFIER_ERROR_TYPE: CommandErrorType<0> = CommandErrorType::new(
translation::java::ARGUMENT_ID_INVALID,
translation::java::ARGUMENT_ID_INVALID,
);
/// A trait to try getting a value from a [`StringReader`]. /// A trait to try getting a value from a [`StringReader`].
pub trait FromStringReader: Sized { pub trait FromStringReader: Sized {

View File

@ -6,10 +6,14 @@ use crate::command::string_reader::StringReader;
use pumpkin_data::translation; use pumpkin_data::translation;
use pumpkin_util::text::TextComponent; use pumpkin_util::text::TextComponent;
pub const INVALID_UNIT_ERROR_TYPE: CommandErrorType<0> = pub const INVALID_UNIT_ERROR_TYPE: CommandErrorType<0> = CommandErrorType::new(
CommandErrorType::new(translation::ARGUMENT_TIME_INVALID_UNIT); translation::java::ARGUMENT_TIME_INVALID_UNIT,
pub const TICK_COUNT_TOO_LOW_ERROR_TYPE: CommandErrorType<2> = translation::java::ARGUMENT_TIME_INVALID_UNIT,
CommandErrorType::new(translation::ARGUMENT_TIME_TICK_COUNT_TOO_LOW); );
pub const TICK_COUNT_TOO_LOW_ERROR_TYPE: CommandErrorType<2> = CommandErrorType::new(
translation::java::ARGUMENT_TIME_TICK_COUNT_TOO_LOW,
translation::java::ARGUMENT_TIME_TICK_COUNT_TOO_LOW,
);
/// Represents an argument type parsing a time value, which can /// Represents an argument type parsing a time value, which can
/// have one of these suffixes: /// have one of these suffixes:

View File

@ -79,8 +79,9 @@ async fn ban_players(
} }
if count == 0 { if count == 0 {
Err(CommandError::CommandFailed(TextComponent::translate( Err(CommandError::CommandFailed(TextComponent::translate_cross(
translation::COMMANDS_BAN_FAILED, translation::java::COMMANDS_BAN_FAILED,
translation::bedrock::COMMANDS_BAN_FAILED,
[], [],
))) )))
} else { } else {
@ -123,8 +124,9 @@ async fn ban_profile(
// Send messages // Send messages
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation::COMMANDS_BAN_SUCCESS, translation::java::COMMANDS_BAN_SUCCESS,
translation::bedrock::COMMANDS_BAN_SUCCESS,
[ [
TextComponent::text(profile.name.clone()), TextComponent::text(profile.name.clone()),
TextComponent::text(reason), TextComponent::text(reason),
@ -136,7 +138,11 @@ async fn ban_profile(
player player
.kick( .kick(
DisconnectReason::Kicked, DisconnectReason::Kicked,
TextComponent::translate(translation::MULTIPLAYER_DISCONNECT_BANNED, []), TextComponent::translate_cross(
translation::java::MULTIPLAYER_DISCONNECT_BANNED,
translation::bedrock::DISCONNECTIONSCREEN_TITLE_BANNEDBYHOST,
[],
),
) )
.await; .await;
} }

View File

@ -83,8 +83,9 @@ async fn ban_ip(
let reason = reason.unwrap_or_else(|| "Banned by an operator.".to_string()); let reason = reason.unwrap_or_else(|| "Banned by an operator.".to_string());
let Some(target_ip) = parse_ip(target, server).await else { let Some(target_ip) = parse_ip(target, server).await else {
return Err(CommandError::CommandFailed(TextComponent::translate( return Err(CommandError::CommandFailed(TextComponent::translate_cross(
translation::COMMANDS_BANIP_INVALID, translation::java::COMMANDS_BANIP_INVALID,
translation::bedrock::COMMANDS_BANIP_INVALID,
[], [],
))); )));
}; };
@ -92,8 +93,9 @@ async fn ban_ip(
let mut banned_ips = server.data.banned_ip_list.write().await; let mut banned_ips = server.data.banned_ip_list.write().await;
if banned_ips.get_entry(&target_ip).is_some() { if banned_ips.get_entry(&target_ip).is_some() {
return Err(CommandError::CommandFailed(TextComponent::translate( return Err(CommandError::CommandFailed(TextComponent::translate_cross(
translation::COMMANDS_BANIP_FAILED, translation::java::COMMANDS_BANIP_FAILED,
translation::java::COMMANDS_BANIP_FAILED,
[], [],
))); )));
} }
@ -117,8 +119,9 @@ async fn ban_ip(
.join(" "); .join(" ");
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation::COMMANDS_BANIP_SUCCESS, translation::java::COMMANDS_BANIP_SUCCESS,
translation::bedrock::COMMANDS_BANIP_SUCCESS,
[ [
TextComponent::text(target_ip.to_string()), TextComponent::text(target_ip.to_string()),
TextComponent::text(reason), TextComponent::text(reason),
@ -127,8 +130,9 @@ async fn ban_ip(
.await; .await;
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation::COMMANDS_BANIP_INFO, translation::java::COMMANDS_BANIP_INFO,
translation::java::COMMANDS_BANIP_INFO,
[ [
TextComponent::text(affected.len().to_string()), TextComponent::text(affected.len().to_string()),
TextComponent::text(names), TextComponent::text(names),
@ -141,7 +145,11 @@ async fn ban_ip(
target target
.kick( .kick(
DisconnectReason::Kicked, DisconnectReason::Kicked,
TextComponent::translate(translation::MULTIPLAYER_DISCONNECT_IP_BANNED, []), TextComponent::translate_cross(
translation::java::MULTIPLAYER_DISCONNECT_IP_BANNED,
translation::java::MULTIPLAYER_DISCONNECT_IP_BANNED,
[],
),
) )
.await; .await;
} }

View File

@ -57,15 +57,20 @@ impl CommandExecutor for BanListCommandExecutor {
if entries.is_empty() { if entries.is_empty() {
source source
.send_feedback( .send_feedback(
TextComponent::translate(translation::COMMANDS_BANLIST_NONE, []), TextComponent::translate_cross(
translation::java::COMMANDS_BANLIST_NONE,
translation::java::COMMANDS_BANLIST_NONE,
[],
),
false, false,
) )
.await; .await;
} else { } else {
source source
.send_feedback( .send_feedback(
TextComponent::translate( TextComponent::translate_cross(
translation::COMMANDS_BANLIST_LIST, translation::java::COMMANDS_BANLIST_LIST,
translation::java::COMMANDS_BANLIST_LIST,
[TextComponent::text(entries.len().to_string())], [TextComponent::text(entries.len().to_string())],
), ),
false, false,
@ -75,8 +80,9 @@ impl CommandExecutor for BanListCommandExecutor {
for entry in entries { for entry in entries {
source source
.send_feedback( .send_feedback(
TextComponent::translate( TextComponent::translate_cross(
translation::COMMANDS_BANLIST_ENTRY, translation::java::COMMANDS_BANLIST_ENTRY,
translation::java::COMMANDS_BANLIST_ENTRY,
[ [
TextComponent::text(entry.name), TextComponent::text(entry.name),
TextComponent::text(entry.source), TextComponent::text(entry.source),

View File

@ -68,7 +68,8 @@ impl CommandExecutor for AddExecutor {
let text_component = TextComponentArgConsumer::find_arg(args, ARG_NAME)?; let text_component = TextComponentArgConsumer::find_arg(args, ARG_NAME)?;
if server.bossbars.lock().await.has_bossbar(&namespace) { if server.bossbars.lock().await.has_bossbar(&namespace) {
return Result::Err(CommandError::CommandFailed(TextComponent::translate( return Result::Err(CommandError::CommandFailed(TextComponent::translate_cross(
"commands.bossbar.create.failed",
"commands.bossbar.create.failed", "commands.bossbar.create.failed",
[TextComponent::text(namespace.clone())], [TextComponent::text(namespace.clone())],
))); )));
@ -82,7 +83,8 @@ impl CommandExecutor for AddExecutor {
drop(bossbars); drop(bossbars);
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.bossbar.create.success",
"commands.bossbar.create.success", "commands.bossbar.create.success",
[bossbar_prefix(bossbar.title.clone(), namespace.clone())], [bossbar_prefix(bossbar.title.clone(), namespace.clone())],
)) ))
@ -116,7 +118,8 @@ impl CommandExecutor for GetExecutor {
match self.0 { match self.0 {
CommandValueGet::Max => { CommandValueGet::Max => {
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.bossbar.get.max",
"commands.bossbar.get.max", "commands.bossbar.get.max",
[ [
bossbar_prefix( bossbar_prefix(
@ -132,7 +135,8 @@ impl CommandExecutor for GetExecutor {
CommandValueGet::Players => Ok(bossbar.players.len() as i32), CommandValueGet::Players => Ok(bossbar.players.len() as i32),
CommandValueGet::Value => { CommandValueGet::Value => {
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.bossbar.get.value",
"commands.bossbar.get.value", "commands.bossbar.get.value",
[ [
bossbar_prefix( bossbar_prefix(
@ -152,7 +156,8 @@ impl CommandExecutor for GetExecutor {
"commands.bossbar.get.visible.hidden" "commands.bossbar.get.visible.hidden"
}; };
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
state,
state, state,
[bossbar_prefix( [bossbar_prefix(
bossbar.bossbar_data.title.clone(), bossbar.bossbar_data.title.clone(),
@ -181,7 +186,8 @@ impl CommandExecutor for ListExecutor {
if bossbars.is_empty() { if bossbars.is_empty() {
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.bossbar.list.bars.none",
"commands.bossbar.list.bars.none", "commands.bossbar.list.bars.none",
[], [],
)) ))
@ -207,7 +213,8 @@ impl CommandExecutor for ListExecutor {
} }
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.bossbar.list.bars.some",
"commands.bossbar.list.bars.some", "commands.bossbar.list.bars.some",
[ [
TextComponent::text(bossbars.len().to_string()), TextComponent::text(bossbars.len().to_string()),
@ -242,7 +249,8 @@ impl CommandExecutor for RemoveExecutor {
}; };
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.bossbar.remove.success",
"commands.bossbar.remove.success", "commands.bossbar.remove.success",
[bossbar_prefix( [bossbar_prefix(
bossbar.bossbar_data.title.clone(), bossbar.bossbar_data.title.clone(),
@ -306,7 +314,8 @@ impl CommandExecutor for SetExecutor {
} }
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.bossbar.set.color.success",
"commands.bossbar.set.color.success", "commands.bossbar.set.color.success",
[bossbar_prefix( [bossbar_prefix(
bossbar.bossbar_data.title.clone(), bossbar.bossbar_data.title.clone(),
@ -319,7 +328,8 @@ impl CommandExecutor for SetExecutor {
} }
CommandValueSet::Max => { CommandValueSet::Max => {
let Ok(max_value) = max_value_consumer().find_arg_default_name(args)? else { let Ok(max_value) = max_value_consumer().find_arg_default_name(args)? else {
return Err(CommandError::CommandFailed(TextComponent::translate( return Err(CommandError::CommandFailed(TextComponent::translate_cross(
"parsing.int.invalid",
"parsing.int.invalid", "parsing.int.invalid",
[TextComponent::text(i32::MAX.to_string())], [TextComponent::text(i32::MAX.to_string())],
))); )));
@ -339,7 +349,8 @@ impl CommandExecutor for SetExecutor {
} }
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.bossbar.set.max.success",
"commands.bossbar.set.max.success", "commands.bossbar.set.max.success",
[ [
bossbar_prefix( bossbar_prefix(
@ -369,7 +380,8 @@ impl CommandExecutor for SetExecutor {
} }
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.bossbar.set.name.success",
"commands.bossbar.set.name.success", "commands.bossbar.set.name.success",
[bossbar_prefix(text_component, namespace.to_string())], [bossbar_prefix(text_component, namespace.to_string())],
)) ))
@ -392,7 +404,8 @@ impl CommandExecutor for SetExecutor {
} }
} }
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.bossbar.set.players.success.none",
"commands.bossbar.set.players.success.none", "commands.bossbar.set.players.success.none",
[bossbar_prefix( [bossbar_prefix(
bossbar.bossbar_data.title.clone(), bossbar.bossbar_data.title.clone(),
@ -429,7 +442,8 @@ impl CommandExecutor for SetExecutor {
.join(", "); .join(", ");
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.bossbar.set.players.success.some",
"commands.bossbar.set.players.success.some", "commands.bossbar.set.players.success.some",
[ [
bossbar_prefix( bossbar_prefix(
@ -459,7 +473,8 @@ impl CommandExecutor for SetExecutor {
} }
} }
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.bossbar.set.style.success",
"commands.bossbar.set.style.success", "commands.bossbar.set.style.success",
[bossbar_prefix( [bossbar_prefix(
bossbar.bossbar_data.title.clone(), bossbar.bossbar_data.title.clone(),
@ -471,7 +486,8 @@ impl CommandExecutor for SetExecutor {
} }
CommandValueSet::Value => { CommandValueSet::Value => {
let Ok(value) = value_consumer().find_arg_default_name(args)? else { let Ok(value) = value_consumer().find_arg_default_name(args)? else {
return Err(CommandError::CommandFailed(TextComponent::translate( return Err(CommandError::CommandFailed(TextComponent::translate_cross(
"parsing.int.invalid",
"parsing.int.invalid", "parsing.int.invalid",
[TextComponent::text(i32::MAX.to_string())], [TextComponent::text(i32::MAX.to_string())],
))); )));
@ -491,7 +507,8 @@ impl CommandExecutor for SetExecutor {
} }
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.bossbar.set.value.success",
"commands.bossbar.set.value.success", "commands.bossbar.set.value.success",
[ [
bossbar_prefix( bossbar_prefix(
@ -528,7 +545,8 @@ impl CommandExecutor for SetExecutor {
}; };
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
state,
state, state,
[bossbar_prefix( [bossbar_prefix(
bossbar.bossbar_data.title.clone(), bossbar.bossbar_data.title.clone(),
@ -635,8 +653,9 @@ fn bossbar_prefix(title: TextComponent, namespace: String) -> TextComponent {
fn handle_bossbar_error(error: BossbarUpdateError) -> CommandError { fn handle_bossbar_error(error: BossbarUpdateError) -> CommandError {
match error { match error {
BossbarUpdateError::InvalidResourceLocation(location) => { BossbarUpdateError::InvalidResourceLocation(location) => {
CommandError::CommandFailed(TextComponent::translate( CommandError::CommandFailed(TextComponent::translate_cross(
translation::COMMANDS_BOSSBAR_UNKNOWN, translation::java::COMMANDS_BOSSBAR_UNKNOWN,
translation::java::COMMANDS_BOSSBAR_UNKNOWN,
[TextComponent::text(location)], [TextComponent::text(location)],
)) ))
} }
@ -646,7 +665,7 @@ fn handle_bossbar_error(error: BossbarUpdateError) -> CommandError {
|var| format!("commands.bossbar.set.{value}.unchanged.{var}"), |var| format!("commands.bossbar.set.{value}.unchanged.{var}"),
); );
CommandError::CommandFailed(TextComponent::translate(key, [])) CommandError::CommandFailed(TextComponent::translate_cross(key.clone(), key, []))
} }
} }
} }

View File

@ -143,37 +143,43 @@ async fn clear_command_text_output(
targets: &[Arc<Player>], targets: &[Arc<Player>],
) -> Result<TextComponent, TextComponent> { ) -> Result<TextComponent, TextComponent> {
match (targets, item_count == 0, max_count == 0) { match (targets, item_count == 0, max_count == 0) {
([target], true, _) => Err(TextComponent::translate( ([target], true, _) => Err(TextComponent::translate_cross(
translation::CLEAR_FAILED_SINGLE, translation::java::CLEAR_FAILED_SINGLE,
translation::java::CLEAR_FAILED_SINGLE,
[target.get_display_name().await], [target.get_display_name().await],
)), )),
(targets, true, _) => Err(TextComponent::translate( (targets, true, _) => Err(TextComponent::translate_cross(
translation::CLEAR_FAILED_MULTIPLE, translation::java::CLEAR_FAILED_MULTIPLE,
translation::java::CLEAR_FAILED_MULTIPLE,
[TextComponent::text(targets.len().to_string())], [TextComponent::text(targets.len().to_string())],
)), )),
([target], false, false) => Ok(TextComponent::translate( ([target], false, false) => Ok(TextComponent::translate_cross(
translation::COMMANDS_CLEAR_SUCCESS_SINGLE, translation::java::COMMANDS_CLEAR_SUCCESS_SINGLE,
translation::java::COMMANDS_CLEAR_SUCCESS_SINGLE,
[ [
TextComponent::text(item_count.to_string()), TextComponent::text(item_count.to_string()),
target.get_display_name().await, target.get_display_name().await,
], ],
)), )),
(targets, false, false) => Ok(TextComponent::translate( (targets, false, false) => Ok(TextComponent::translate_cross(
translation::COMMANDS_CLEAR_SUCCESS_MULTIPLE, translation::java::COMMANDS_CLEAR_SUCCESS_MULTIPLE,
translation::java::COMMANDS_CLEAR_SUCCESS_MULTIPLE,
[ [
TextComponent::text(item_count.to_string()), TextComponent::text(item_count.to_string()),
TextComponent::text(targets.len().to_string()), TextComponent::text(targets.len().to_string()),
], ],
)), )),
([target], false, true) => Ok(TextComponent::translate( ([target], false, true) => Ok(TextComponent::translate_cross(
translation::COMMANDS_CLEAR_TEST_SINGLE, translation::java::COMMANDS_CLEAR_TEST_SINGLE,
translation::java::COMMANDS_CLEAR_TEST_SINGLE,
[ [
TextComponent::text(item_count.to_string()), TextComponent::text(item_count.to_string()),
target.get_display_name().await, target.get_display_name().await,
], ],
)), )),
(targets, false, true) => Ok(TextComponent::translate( (targets, false, true) => Ok(TextComponent::translate_cross(
translation::COMMANDS_CLEAR_TEST_MULTIPLE, translation::java::COMMANDS_CLEAR_TEST_MULTIPLE,
translation::java::COMMANDS_CLEAR_TEST_MULTIPLE,
[ [
TextComponent::text(item_count.to_string()), TextComponent::text(item_count.to_string()),
TextComponent::text(targets.len().to_string()), TextComponent::text(targets.len().to_string()),
@ -273,8 +279,9 @@ impl CommandExecutor for ItemCountExecutor {
let item = ItemPredicateArgumentConsumer::find_arg(args, ARG_ITEM)?; let item = ItemPredicateArgumentConsumer::find_arg(args, ARG_ITEM)?;
let Ok(max) = count_consumer().find_arg_default_name(args)? else { let Ok(max) = count_consumer().find_arg_default_name(args)? else {
return Err(CommandError::CommandFailed(TextComponent::translate( return Err(CommandError::CommandFailed(TextComponent::translate_cross(
translation::PARSING_INT_INVALID, translation::java::PARSING_INT_INVALID,
translation::java::PARSING_INT_INVALID,
[TextComponent::text(i32::MAX.to_string())], [TextComponent::text(i32::MAX.to_string())],
))); )));
}; };

View File

@ -39,15 +39,17 @@ async fn send_damage_result(
target_name: TextComponent, target_name: TextComponent,
) -> Result<i32, CommandError> { ) -> Result<i32, CommandError> {
if !success { if !success {
return Err(CommandError::CommandFailed(TextComponent::translate( return Err(CommandError::CommandFailed(TextComponent::translate_cross(
translation::COMMANDS_DAMAGE_INVULNERABLE, translation::java::COMMANDS_DAMAGE_INVULNERABLE,
translation::java::COMMANDS_DAMAGE_INVULNERABLE,
[], [],
))); )));
} }
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation::COMMANDS_DAMAGE_SUCCESS, translation::java::COMMANDS_DAMAGE_SUCCESS,
translation::bedrock::COMMANDS_DAMAGE_SUCCESS,
[TextComponent::text(amount.to_string()), target_name], [TextComponent::text(amount.to_string()), target_name],
)) ))
.await; .await;

View File

@ -232,8 +232,9 @@ async fn display_data(
let display = TextComponent::text(format!("PNBT Data ({} bytes)", nbt.data.len())); let display = TextComponent::text(format!("PNBT Data ({} bytes)", nbt.data.len()));
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation::COMMANDS_DATA_ENTITY_QUERY, translation::java::COMMANDS_DATA_ENTITY_QUERY,
translation::java::COMMANDS_DATA_ENTITY_QUERY,
[target_name, display], [target_name, display],
)) ))
.await; .await;
@ -244,8 +245,9 @@ async fn display_data(
#[allow(dead_code)] #[allow(dead_code)]
fn get_i32_result(tag: &NbtTag) -> Result<i32, CommandError> { fn get_i32_result(tag: &NbtTag) -> Result<i32, CommandError> {
match tag { match tag {
NbtTag::End => Err(CommandError::CommandFailed(TextComponent::translate( NbtTag::End => Err(CommandError::CommandFailed(TextComponent::translate_cross(
translation::COMMANDS_DATA_GET_UNKNOWN, translation::java::COMMANDS_DATA_GET_UNKNOWN,
translation::java::COMMANDS_DATA_GET_UNKNOWN,
[], [],
))), ))),

View File

@ -44,9 +44,14 @@ impl CommandExecutor for DefaultGamemodeExecutor {
let gamemode_string = format!("gameMode.{gamemode_string}"); let gamemode_string = format!("gameMode.{gamemode_string}");
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.defaultgamemode.success", "commands.defaultgamemode.success",
[TextComponent::translate(gamemode_string, [])], "commands.defaultgamemode.success",
[TextComponent::translate_cross(
gamemode_string.clone(),
gamemode_string,
[],
)],
)) ))
.await; .await;

View File

@ -51,7 +51,8 @@ impl CommandExecutor for Executor {
.await; .await;
} }
let msg = TextComponent::translate( let msg = TextComponent::translate_cross(
"commands.deop.success",
"commands.deop.success", "commands.deop.success",
[TextComponent::text(profile.name.clone())], [TextComponent::text(profile.name.clone())],
); );
@ -64,7 +65,8 @@ impl CommandExecutor for Executor {
} }
if succeeded_deops == 0 { if succeeded_deops == 0 {
Err(CommandError::CommandFailed(TextComponent::translate( Err(CommandError::CommandFailed(TextComponent::translate_cross(
"commands.deop.failed",
"commands.deop.failed", "commands.deop.failed",
[], [],
))) )))

View File

@ -12,7 +12,7 @@ const DESCRIPTION: &str = "Query or change the difficulty of the world.";
const PERMISSION: &str = "minecraft:command.difficulty"; const PERMISSION: &str = "minecraft:command.difficulty";
const FAILURE_ERROR_TYPE: CommandErrorType<1> = const FAILURE_ERROR_TYPE: CommandErrorType<1> =
CommandErrorType::new("commands.difficulty.failure"); CommandErrorType::new("commands.difficulty.failure", "commands.difficulty.failure");
struct DifficultyQueryExecutor; struct DifficultyQueryExecutor;
@ -24,9 +24,14 @@ impl CommandExecutor for DifficultyQueryExecutor {
context context
.source .source
.send_feedback( .send_feedback(
TextComponent::translate( TextComponent::translate_cross(
"commands.difficulty.query", "commands.difficulty.query",
[TextComponent::translate(difficulty.translation_key(), [])], "commands.difficulty.query",
[TextComponent::translate_cross(
difficulty.translation_key(),
difficulty.translation_key(),
[],
)],
), ),
false, false,
) )
@ -59,9 +64,14 @@ impl CommandExecutor for DifficultySetExecutor {
context context
.source .source
.send_feedback( .send_feedback(
TextComponent::translate( TextComponent::translate_cross(
"commands.difficulty.success", "commands.difficulty.success",
[TextComponent::translate(difficulty.translation_key(), [])], "commands.difficulty.success",
[TextComponent::translate_cross(
difficulty.translation_key(),
difficulty.translation_key(),
[],
)],
), ),
true, true,
) )

View File

@ -113,23 +113,30 @@ impl CommandExecutor for GiveExecutor {
} }
} }
let translation_name = TextComponent::translate(effect.translation_key.to_string(), []); let translation_name = TextComponent::translate_cross(
effect.translation_key.to_string(),
effect.translation_key.to_string(),
[],
);
if successes == 0 { if successes == 0 {
return Err(CommandError::CommandFailed(TextComponent::translate( return Err(CommandError::CommandFailed(TextComponent::translate_cross(
"commands.effect.give.failed",
"commands.effect.give.failed", "commands.effect.give.failed",
[], [],
))); )));
} else if targets.len() == 1 { } else if targets.len() == 1 {
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.effect.give.success.single",
"commands.effect.give.success.single", "commands.effect.give.success.single",
[translation_name, targets[0].get_display_name().await], [translation_name, targets[0].get_display_name().await],
)) ))
.await; .await;
} else { } else {
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.effect.give.success.multiple",
"commands.effect.give.success.multiple", "commands.effect.give.success.multiple",
[ [
translation_name, translation_name,
@ -170,7 +177,8 @@ impl CommandExecutor for ClearExecutor {
//if the player or everyplayer don't have any effect //if the player or everyplayer don't have any effect
if succeeded_clears == 0 { if succeeded_clears == 0 {
return Err(CommandError::CommandFailed(TextComponent::translate( return Err(CommandError::CommandFailed(TextComponent::translate_cross(
"commands.effect.clear.everything.failed",
"commands.effect.clear.everything.failed", "commands.effect.clear.everything.failed",
[], [],
))); )));
@ -178,14 +186,16 @@ impl CommandExecutor for ClearExecutor {
//a player have at least 1 effect //a player have at least 1 effect
else if targets.len() == 1 { else if targets.len() == 1 {
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.effect.clear.everything.success.single",
"commands.effect.clear.everything.success.single", "commands.effect.clear.everything.success.single",
[targets[0].get_display_name().await], [targets[0].get_display_name().await],
)) ))
.await; .await;
} else { } else {
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.effect.clear.everything.success.multiple",
"commands.effect.clear.everything.success.multiple", "commands.effect.clear.everything.success.multiple",
[TextComponent::text(targets.len().to_string())], [TextComponent::text(targets.len().to_string())],
)) ))
@ -208,26 +218,37 @@ impl CommandExecutor for ClearExecutor {
} }
if succeeded_clears == 0 { if succeeded_clears == 0 {
return Err(CommandError::CommandFailed(TextComponent::translate( return Err(CommandError::CommandFailed(TextComponent::translate_cross(
"commands.effect.clear.specific.failed",
"commands.effect.clear.specific.failed", "commands.effect.clear.specific.failed",
[], [],
))); )));
} else if targets.len() == 1 { } else if targets.len() == 1 {
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.effect.clear.specific.success.single",
"commands.effect.clear.specific.success.single", "commands.effect.clear.specific.success.single",
[ [
TextComponent::translate(effect.translation_key, []), TextComponent::translate_cross(
effect.translation_key,
effect.translation_key,
[],
),
targets[0].get_display_name().await, targets[0].get_display_name().await,
], ],
)) ))
.await; .await;
} else { } else {
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.effect.clear.specific.success.multiple",
"commands.effect.clear.specific.success.multiple", "commands.effect.clear.specific.success.multiple",
[ [
TextComponent::translate(effect.translation_key, []), TextComponent::translate_cross(
effect.translation_key,
effect.translation_key,
[],
),
TextComponent::text(targets.len().to_string()), TextComponent::text(targets.len().to_string()),
], ],
)) ))

View File

@ -31,14 +31,16 @@ impl CommandExecutor for Executor {
Ok(Ok(level)) => level, Ok(Ok(level)) => level,
Ok(Err(err)) => { Ok(Err(err)) => {
let err_msg = match err { let err_msg = match err {
NotInBounds::LowerBound(val, min) => TextComponent::translate( NotInBounds::LowerBound(val, min) => TextComponent::translate_cross(
"argument.integer.low",
"argument.integer.low", "argument.integer.low",
&[ &[
TextComponent::text(min.to_string()), TextComponent::text(min.to_string()),
TextComponent::text(val.to_string()), TextComponent::text(val.to_string()),
], ],
), ),
NotInBounds::UpperBound(val, max) => TextComponent::translate( NotInBounds::UpperBound(val, max) => TextComponent::translate_cross(
"argument.integer.big",
"argument.integer.big", "argument.integer.big",
&[ &[
TextComponent::text(max.to_string()), TextComponent::text(max.to_string()),
@ -52,7 +54,8 @@ impl CommandExecutor for Executor {
}; };
if level > enchantment.max_level { if level > enchantment.max_level {
let msg = TextComponent::translate( let msg = TextComponent::translate_cross(
"commands.enchant.failed.level",
"commands.enchant.failed.level", "commands.enchant.failed.level",
[ [
TextComponent::text(level.to_string()), TextComponent::text(level.to_string()),
@ -68,9 +71,7 @@ impl CommandExecutor for Executor {
for target in targets { for target in targets {
// let Some(target) = target.get_living_entity() else { // let Some(target) = target.get_living_entity() else {
// if only_one { // if only_one {
// let msg = TextComponent::translate( // let msg = TextComponent::translate_cross(// "commands.enchant.failed.entity".clone(), // "commands.enchant.failed.entity", // [targets[0].get_display_name().await],
// "commands.enchant.failed.entity",
// [targets[0].get_display_name().await],
// ); // );
// sender.send_message(msg).await; // sender.send_message(msg).await;
// return Ok(()); // return Ok(());
@ -85,7 +86,8 @@ impl CommandExecutor for Executor {
let mut item = lock.lock().await; let mut item = lock.lock().await;
if item.is_empty() { if item.is_empty() {
if only_one { if only_one {
let msg = TextComponent::translate( let msg = TextComponent::translate_cross(
"commands.enchant.failed.itemless",
"commands.enchant.failed.itemless", "commands.enchant.failed.itemless",
[targets[0].get_display_name().await], [targets[0].get_display_name().await],
); );
@ -95,7 +97,8 @@ impl CommandExecutor for Executor {
} }
if !enchantment.can_enchant(item.item) { if !enchantment.can_enchant(item.item) {
if only_one { if only_one {
let msg = TextComponent::translate( let msg = TextComponent::translate_cross(
"commands.enchant.failed.incompatible",
"commands.enchant.failed.incompatible", "commands.enchant.failed.incompatible",
[item.item.translated_name()], [item.item.translated_name()],
); );
@ -108,7 +111,8 @@ impl CommandExecutor for Executor {
item.enchant(enchantment, level); item.enchant(enchantment, level);
success += 1; success += 1;
} else if only_one { } else if only_one {
let msg = TextComponent::translate( let msg = TextComponent::translate_cross(
"commands.enchant.failed.incompatible",
"commands.enchant.failed.incompatible", "commands.enchant.failed.incompatible",
[item.item.translated_name()], [item.item.translated_name()],
); );
@ -120,12 +124,17 @@ impl CommandExecutor for Executor {
} }
} }
if success == 0 { if success == 0 {
let msg = TextComponent::translate(translation::COMMANDS_ENCHANT_FAILED, []); let msg = TextComponent::translate_cross(
translation::java::COMMANDS_ENCHANT_FAILED,
translation::java::COMMANDS_ENCHANT_FAILED,
[],
);
return Err(CommandError::CommandFailed(msg)); return Err(CommandError::CommandFailed(msg));
} }
if only_one { if only_one {
let msg = TextComponent::translate( let msg = TextComponent::translate_cross(
translation::COMMANDS_ENCHANT_SUCCESS_SINGLE, translation::java::COMMANDS_ENCHANT_SUCCESS_SINGLE,
translation::java::COMMANDS_ENCHANT_SUCCESS_SINGLE,
[ [
enchantment.get_fullname(level), enchantment.get_fullname(level),
targets[0].get_display_name().await, targets[0].get_display_name().await,
@ -133,8 +142,9 @@ impl CommandExecutor for Executor {
); );
sender.send_message(msg).await; sender.send_message(msg).await;
} else { } else {
let msg = TextComponent::translate( let msg = TextComponent::translate_cross(
translation::COMMANDS_ENCHANT_SUCCESS_MULTIPLE, translation::java::COMMANDS_ENCHANT_SUCCESS_MULTIPLE,
translation::java::COMMANDS_ENCHANT_SUCCESS_MULTIPLE,
[ [
enchantment.get_fullname(level), enchantment.get_fullname(level),
TextComponent::text(targets.len().to_string()), TextComponent::text(targets.len().to_string()),

View File

@ -58,7 +58,8 @@ impl Executor {
}; };
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation_key,
translation_key, translation_key,
[ [
target.get_display_name().await, target.get_display_name().await,
@ -87,7 +88,8 @@ impl Executor {
}; };
if targets.len() > 1 { if targets.len() > 1 {
TextComponent::translate( TextComponent::translate_cross(
format!("commands.experience.{mode_str}.{type_str}.success.multiple"),
format!("commands.experience.{mode_str}.{type_str}.success.multiple"), format!("commands.experience.{mode_str}.{type_str}.success.multiple"),
[ [
TextComponent::text(amount.to_string()), TextComponent::text(amount.to_string()),
@ -95,7 +97,8 @@ impl Executor {
], ],
) )
} else { } else {
TextComponent::translate( TextComponent::translate_cross(
format!("commands.experience.{mode_str}.{type_str}.success.single"),
format!("commands.experience.{mode_str}.{type_str}.success.single"), format!("commands.experience.{mode_str}.{type_str}.success.single"),
[TextComponent::text(amount.to_string()), first_target_name], [TextComponent::text(amount.to_string()), first_target_name],
) )
@ -140,14 +143,16 @@ impl CommandExecutor for Executor {
if self.mode == Mode::Query { if self.mode == Mode::Query {
let target = targets.first().ok_or_else(|| { let target = targets.first().ok_or_else(|| {
CommandError::CommandFailed(TextComponent::translate( CommandError::CommandFailed(TextComponent::translate_cross(
"argument.player.unknown",
"argument.player.unknown", "argument.player.unknown",
[], [],
)) ))
})?; })?;
if targets.len() > 1 { if targets.len() > 1 {
return Err(CommandError::CommandFailed(TextComponent::translate( return Err(CommandError::CommandFailed(TextComponent::translate_cross(
"argument.player.toomany",
"argument.player.toomany", "argument.player.toomany",
[], [],
))); )));
@ -166,7 +171,8 @@ impl CommandExecutor for Executor {
} }
if successes == 0 { if successes == 0 {
return Err(CommandError::CommandFailed(TextComponent::translate( return Err(CommandError::CommandFailed(TextComponent::translate_cross(
"commands.experience.set.points.invalid",
"commands.experience.set.points.invalid", "commands.experience.set.points.invalid",
[], [],
))); )));

View File

@ -286,8 +286,9 @@ impl CommandExecutor for Executor {
}; };
if !context.world.is_in_build_limit(from) || !context.world.is_in_build_limit(to) { if !context.world.is_in_build_limit(from) || !context.world.is_in_build_limit(to) {
return Err(CommandError::CommandFailed(TextComponent::translate( return Err(CommandError::CommandFailed(TextComponent::translate_cross(
translation::ARGUMENT_POS_OUTOFBOUNDS, translation::java::ARGUMENT_POS_OUTOFBOUNDS,
translation::java::ARGUMENT_POS_OUTOFBOUNDS,
[], [],
))); )));
} }
@ -302,8 +303,9 @@ impl CommandExecutor for Executor {
* (context.end_z - context.start_z + 1) as i64; * (context.end_z - context.start_z + 1) as i64;
if total_blocks > max_block_modifications { if total_blocks > max_block_modifications {
return Err(CommandError::CommandFailed(TextComponent::translate( return Err(CommandError::CommandFailed(TextComponent::translate_cross(
translation::COMMANDS_FILL_TOOBIG, translation::java::COMMANDS_FILL_TOOBIG,
translation::java::COMMANDS_FILL_TOOBIG,
[ [
TextComponent::text(max_block_modifications.to_string()), TextComponent::text(max_block_modifications.to_string()),
TextComponent::text(total_blocks.to_string()), TextComponent::text(total_blocks.to_string()),
@ -325,15 +327,17 @@ impl CommandExecutor for Executor {
} }
if context.placed_blocks == 0 { if context.placed_blocks == 0 {
return Err(CommandError::CommandFailed(TextComponent::translate( return Err(CommandError::CommandFailed(TextComponent::translate_cross(
translation::COMMANDS_FILL_FAILED, translation::java::COMMANDS_FILL_FAILED,
translation::bedrock::COMMANDS_FILL_FAILED,
[], [],
))); )));
} }
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation::COMMANDS_FILL_SUCCESS, translation::java::COMMANDS_FILL_SUCCESS,
translation::bedrock::COMMANDS_FILL_SUCCESS,
[TextComponent::text(context.placed_blocks.to_string())], [TextComponent::text(context.placed_blocks.to_string())],
)) ))
.await; .await;

View File

@ -2,6 +2,7 @@ use crate::command::args::GetCloned;
use crate::command::args::gamemode::GamemodeArgumentConsumer; use crate::command::args::gamemode::GamemodeArgumentConsumer;
use crate::TextComponent; use crate::TextComponent;
use pumpkin_data::translation;
use crate::command::args::players::PlayersArgumentConsumer; use crate::command::args::players::PlayersArgumentConsumer;
@ -54,29 +55,34 @@ impl CommandExecutor for TargetExecutor {
let gamemode_string = format!("{gamemode:?}").to_lowercase(); let gamemode_string = format!("{gamemode:?}").to_lowercase();
let gamemode_string = format!("gameMode.{gamemode_string}"); let gamemode_string = format!("gameMode.{gamemode_string}");
// Checking if the target was the sender of this command. // Checking if the target was the sender of this command.
let gamemode_comp = TextComponent::translate_cross(
gamemode_string.clone(),
gamemode_string.clone(),
[],
);
if sender.as_player().as_ref() == Some(target) { if sender.as_player().as_ref() == Some(target) {
target target
.send_system_message(&TextComponent::translate( .send_system_message(&TextComponent::translate_cross(
"commands.gamemode.success.self", translation::java::COMMANDS_GAMEMODE_SUCCESS_SELF,
[TextComponent::translate(gamemode_string, [])], translation::bedrock::COMMANDS_GAMEMODE_SUCCESS_SELF,
[gamemode_comp],
)) ))
.await; .await;
} else { } else {
if server.level_info.load().game_rules.send_command_feedback { if server.level_info.load().game_rules.send_command_feedback {
target target
.send_system_message(&TextComponent::translate( .send_system_message(&TextComponent::translate_cross(
"gameMode.changed", translation::java::GAMEMODE_CHANGED,
[TextComponent::translate(gamemode_string.clone(), [])], translation::bedrock::GAMEMODE_CHANGED,
[gamemode_comp.clone()],
)) ))
.await; .await;
} }
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.gamemode.success.other", translation::java::COMMANDS_GAMEMODE_SUCCESS_OTHER,
[ translation::bedrock::COMMANDS_GAMEMODE_SUCCESS_OTHER,
target.get_display_name().await, [target.get_display_name().await, gamemode_comp],
TextComponent::translate(gamemode_string, []),
],
)) ))
.await; .await;
} }

View File

@ -40,7 +40,8 @@ impl CommandExecutor for QueryExecutor {
drop(level_info); drop(level_info);
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.gamerule.query",
"commands.gamerule.query", "commands.gamerule.query",
[key, value], [key, value],
)) ))
@ -93,7 +94,8 @@ impl CommandExecutor for SetExecutor {
let value_component = TextComponent::text(output_value); let value_component = TextComponent::text(output_value);
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.gamerule.set",
"commands.gamerule.set", "commands.gamerule.set",
[key, value_component], [key, value_component],
)) ))

View File

@ -81,7 +81,8 @@ impl CommandExecutor for Executor {
} }
let msg = if targets.len() == 1 { let msg = if targets.len() == 1 {
TextComponent::translate( TextComponent::translate_cross(
"commands.give.success.single",
"commands.give.success.single", "commands.give.success.single",
[ [
TextComponent::text(item_count.to_string()), TextComponent::text(item_count.to_string()),
@ -96,7 +97,8 @@ impl CommandExecutor for Executor {
], ],
) )
} else { } else {
TextComponent::translate( TextComponent::translate_cross(
"commands.give.success.multiple",
"commands.give.success.multiple", "commands.give.success.multiple",
[ [
TextComponent::text(item_count.to_string()), TextComponent::text(item_count.to_string()),

View File

@ -17,7 +17,8 @@ use pumpkin_util::text::color::{Color, NamedColor};
const NO_COMMANDS_ERROR_TYPE: LiteralCommandErrorType = const NO_COMMANDS_ERROR_TYPE: LiteralCommandErrorType =
LiteralCommandErrorType::new("No commands are available to show help for"); LiteralCommandErrorType::new("No commands are available to show help for");
const FAILED_ERROR_TYPE: CommandErrorType<0> = CommandErrorType::new("commands.help.failed"); const FAILED_ERROR_TYPE: CommandErrorType<0> =
CommandErrorType::new("commands.help.failed", "commands.help.failed");
const PLUGIN_NOT_FOUND_ERROR_TYPE: LiteralCommandErrorType = const PLUGIN_NOT_FOUND_ERROR_TYPE: LiteralCommandErrorType =
LiteralCommandErrorType::new("Plugin not found or has no commands"); LiteralCommandErrorType::new("Plugin not found or has no commands");

View File

@ -36,7 +36,11 @@ impl CommandExecutor for Executor {
let reason = match args.get(&ARG_REASON) { let reason = match args.get(&ARG_REASON) {
Some(Arg::Msg(r)) => TextComponent::text(r.clone()), Some(Arg::Msg(r)) => TextComponent::text(r.clone()),
_ => TextComponent::translate(translation::MULTIPLAYER_DISCONNECT_KICKED, []), _ => TextComponent::translate_cross(
translation::java::MULTIPLAYER_DISCONNECT_KICKED,
translation::java::MULTIPLAYER_DISCONNECT_KICKED,
[],
),
}; };
for target in targets { for target in targets {

View File

@ -27,13 +27,15 @@ impl CommandExecutor for TargetsExecutor {
} }
let msg = if target_count == 1 { let msg = if target_count == 1 {
TextComponent::translate( TextComponent::translate_cross(
translation::COMMANDS_KILL_SUCCESS_SINGLE, translation::java::COMMANDS_KILL_SUCCESS_SINGLE,
translation::java::COMMANDS_KILL_SUCCESS_SINGLE,
[targets[0].get_display_name().await], [targets[0].get_display_name().await],
) )
} else { } else {
TextComponent::translate( TextComponent::translate_cross(
translation::COMMANDS_KILL_SUCCESS_MULTIPLE, translation::java::COMMANDS_KILL_SUCCESS_MULTIPLE,
translation::java::COMMANDS_KILL_SUCCESS_MULTIPLE,
[TextComponent::text(target_count.to_string())], [TextComponent::text(target_count.to_string())],
) )
}; };
@ -56,8 +58,9 @@ impl CommandExecutor for SelfExecutor {
context context
.source .source
.send_feedback( .send_feedback(
TextComponent::translate( TextComponent::translate_cross(
translation::COMMANDS_KILL_SUCCESS_SINGLE, translation::java::COMMANDS_KILL_SUCCESS_SINGLE,
translation::java::COMMANDS_KILL_SUCCESS_SINGLE,
[target.get_display_name().await], [target.get_display_name().await],
), ),
true, true,

View File

@ -1,6 +1,6 @@
use std::sync::Arc; use std::sync::Arc;
use pumpkin_data::translation::{COMMANDS_LIST_NAMEANDID, COMMANDS_LIST_PLAYERS}; use pumpkin_data::translation::java::{COMMANDS_LIST_NAMEANDID, COMMANDS_LIST_PLAYERS};
use pumpkin_util::{ use pumpkin_util::{
permission::{Permission, PermissionDefault, PermissionRegistry}, permission::{Permission, PermissionDefault, PermissionRegistry},
text::TextComponent, text::TextComponent,
@ -40,7 +40,8 @@ impl CommandExecutor for ListCommandExecutor {
context context
.source .source
.send_feedback( .send_feedback(
TextComponent::translate( TextComponent::translate_cross(
COMMANDS_LIST_PLAYERS,
COMMANDS_LIST_PLAYERS, COMMANDS_LIST_PLAYERS,
[ [
TextComponent::text(players_len.to_string()), TextComponent::text(players_len.to_string()),
@ -70,7 +71,8 @@ fn get_player_names_and_ids(players: &[Arc<Player>]) -> TextComponent {
let names_and_ids = players let names_and_ids = players
.iter() .iter()
.map(|p| { .map(|p| {
TextComponent::translate( TextComponent::translate_cross(
COMMANDS_LIST_NAMEANDID,
COMMANDS_LIST_NAMEANDID, COMMANDS_LIST_NAMEANDID,
&[ &[
p.get_name(), p.get_name(),

View File

@ -64,7 +64,8 @@ impl CommandExecutor for Executor {
} }
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.op.success",
"commands.op.success", "commands.op.success",
[TextComponent::text(profile.name.clone())], [TextComponent::text(profile.name.clone())],
)) ))
@ -78,7 +79,8 @@ impl CommandExecutor for Executor {
} }
if successes == 0 { if successes == 0 {
Err(CommandError::CommandFailed(TextComponent::translate( Err(CommandError::CommandFailed(TextComponent::translate_cross(
"commands.op.failed",
"commands.op.failed", "commands.op.failed",
[], [],
))) )))

View File

@ -43,7 +43,8 @@ impl CommandExecutor for Executor {
if let Some(idx) = idx { if let Some(idx) = idx {
lock.banned_players.remove(idx); lock.banned_players.remove(idx);
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.pardon.success",
"commands.pardon.success", "commands.pardon.success",
[TextComponent::text(target.name.clone())], [TextComponent::text(target.name.clone())],
)) ))
@ -56,7 +57,8 @@ impl CommandExecutor for Executor {
lock.save(); lock.save();
Ok(successes) Ok(successes)
} else { } else {
Err(CommandError::CommandFailed(TextComponent::translate( Err(CommandError::CommandFailed(TextComponent::translate_cross(
"commands.pardon.failed",
"commands.pardon.failed", "commands.pardon.failed",
[], [],
))) )))

View File

@ -31,7 +31,8 @@ impl CommandExecutor for Executor {
}; };
let Ok(ip) = IpAddr::from_str(target) else { let Ok(ip) = IpAddr::from_str(target) else {
return Err(CommandError::CommandFailed(TextComponent::translate( return Err(CommandError::CommandFailed(TextComponent::translate_cross(
"commands.pardonip.invalid",
"commands.pardonip.invalid", "commands.pardonip.invalid",
[], [],
))); )));
@ -43,14 +44,16 @@ impl CommandExecutor for Executor {
{ {
lock.banned_ips.remove(idx); lock.banned_ips.remove(idx);
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.pardonip.success",
"commands.pardonip.success", "commands.pardonip.success",
[TextComponent::text(ip.to_string())], [TextComponent::text(ip.to_string())],
)) ))
.await; .await;
Ok(1) Ok(1)
} else { } else {
Err(CommandError::CommandFailed(TextComponent::translate( Err(CommandError::CommandFailed(TextComponent::translate_cross(
"commands.pardonip.failed",
"commands.pardonip.failed", "commands.pardonip.failed",
[], [],
))) )))

View File

@ -74,7 +74,8 @@ impl CommandExecutor for Executor {
.await; .await;
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.particle.success",
"commands.particle.success", "commands.particle.success",
[TextComponent::text(format!("{particle:?}"))], [TextComponent::text(format!("{particle:?}"))],
)) ))

View File

@ -141,7 +141,8 @@ impl CommandExecutor for Executor {
// Send appropriate message based on results // Send appropriate message based on results
if players_who_heard == 0 { if players_who_heard == 0 {
Err(CommandError::CommandFailed(TextComponent::translate( Err(CommandError::CommandFailed(TextComponent::translate_cross(
"commands.playsound.failed",
"commands.playsound.failed", "commands.playsound.failed",
[], [],
))) )))
@ -149,8 +150,9 @@ impl CommandExecutor for Executor {
let sound_name = sound.to_name(); let sound_name = sound.to_name();
if players_who_heard == 1 { if players_who_heard == 1 {
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation::COMMANDS_PLAYSOUND_SUCCESS_SINGLE, translation::java::COMMANDS_PLAYSOUND_SUCCESS_SINGLE,
translation::java::COMMANDS_PLAYSOUND_SUCCESS_SINGLE,
[ [
TextComponent::text(sound_name), TextComponent::text(sound_name),
targets[0].get_display_name().await, targets[0].get_display_name().await,
@ -159,8 +161,9 @@ impl CommandExecutor for Executor {
.await; .await;
} else { } else {
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation::COMMANDS_PLAYSOUND_SUCCESS_MULTIPLE, translation::java::COMMANDS_PLAYSOUND_SUCCESS_MULTIPLE,
translation::java::COMMANDS_PLAYSOUND_SUCCESS_MULTIPLE,
[ [
TextComponent::text(sound_name), TextComponent::text(sound_name),
TextComponent::text(players_who_heard.to_string()), TextComponent::text(players_who_heard.to_string()),

View File

@ -89,8 +89,9 @@ async fn rotate_entity(
async fn send_success_message(sender: &CommandSender, target: &dyn crate::entity::EntityBase) { async fn send_success_message(sender: &CommandSender, target: &dyn crate::entity::EntityBase) {
let target_name = target.get_display_name().await; let target_name = target.get_display_name().await;
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation::COMMANDS_ROTATE_SUCCESS, translation::java::COMMANDS_ROTATE_SUCCESS,
translation::java::COMMANDS_ROTATE_SUCCESS,
[target_name], [target_name],
)) ))
.await; .await;

View File

@ -2,7 +2,7 @@ use crate::command::argument_builder::{ArgumentBuilder, command};
use crate::command::context::command_context::CommandContext; use crate::command::context::command_context::CommandContext;
use crate::command::node::dispatcher::CommandDispatcher; use crate::command::node::dispatcher::CommandDispatcher;
use crate::command::node::{CommandExecutor, CommandExecutorResult}; use crate::command::node::{CommandExecutor, CommandExecutorResult};
use pumpkin_data::translation::{CHAT_COPY_CLICK, COMMANDS_SEED_SUCCESS}; use pumpkin_data::translation::java::{CHAT_COPY_CLICK, COMMANDS_SEED_SUCCESS};
use pumpkin_util::PermissionLvl; use pumpkin_util::PermissionLvl;
use pumpkin_util::permission::{Permission, PermissionDefault, PermissionRegistry}; use pumpkin_util::permission::{Permission, PermissionDefault, PermissionRegistry};
use pumpkin_util::text::click::ClickEvent; use pumpkin_util::text::click::ClickEvent;
@ -16,11 +16,13 @@ const PERMISSION: &str = "minecraft:command.seed";
struct SeedCommandExecutor; struct SeedCommandExecutor;
fn create_copy_on_click_text(content: String) -> TextComponent { fn create_copy_on_click_text(content: String) -> TextComponent {
TextComponent::translate( TextComponent::translate_cross(
COMMANDS_SEED_SUCCESS,
COMMANDS_SEED_SUCCESS, COMMANDS_SEED_SUCCESS,
[TextComponent::wrap_in_square_brackets( [TextComponent::wrap_in_square_brackets(
TextComponent::text(content.clone()) TextComponent::text(content.clone())
.hover_event(HoverEvent::show_text(TextComponent::translate( .hover_event(HoverEvent::show_text(TextComponent::translate_cross(
CHAT_COPY_CLICK,
CHAT_COPY_CLICK, CHAT_COPY_CLICK,
[], [],
))) )))

View File

@ -111,7 +111,8 @@ impl CommandExecutor for Executor {
if success { if success {
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.setblock.success",
"commands.setblock.success", "commands.setblock.success",
[ [
TextComponent::text(pos.0.x.to_string()), TextComponent::text(pos.0.x.to_string()),
@ -122,7 +123,8 @@ impl CommandExecutor for Executor {
.await; .await;
Ok(1) Ok(1)
} else { } else {
Err(CommandError::CommandFailed(TextComponent::translate( Err(CommandError::CommandFailed(TextComponent::translate_cross(
"commands.setblock.failed",
"commands.setblock.failed", "commands.setblock.failed",
[], [],
))) )))

View File

@ -33,12 +33,17 @@ impl CommandExecutor for SetIdleTimeoutExecutor {
{ {
if minutes == 0 { if minutes == 0 {
context.source.send_feedback( context.source.send_feedback(
TextComponent::translate("commands.setidletimeout.success.disabled", []), TextComponent::translate_cross(
"commands.setidletimeout.success.disabled",
"commands.setidletimeout.success.disabled",
[],
),
true, true,
) )
} else { } else {
context.source.send_feedback( context.source.send_feedback(
TextComponent::translate( TextComponent::translate_cross(
"commands.setidletimeout.success",
"commands.setidletimeout.success", "commands.setidletimeout.success",
[TextComponent::text(minutes.to_string())], [TextComponent::text(minutes.to_string())],
), ),

View File

@ -108,8 +108,9 @@ async fn setworldspawn(
))); )));
}; };
if world.dimension != Dimension::OVERWORLD && world.dimension != Dimension::OVERWORLD_CAVES { if world.dimension != Dimension::OVERWORLD && world.dimension != Dimension::OVERWORLD_CAVES {
return Err(CommandError::CommandFailed(TextComponent::translate( return Err(CommandError::CommandFailed(TextComponent::translate_cross(
translation::COMMANDS_SETWORLDSPAWN_FAILURE_NOT_OVERWORLD, translation::java::COMMANDS_SETWORLDSPAWN_FAILURE_NOT_OVERWORLD,
translation::java::COMMANDS_SETWORLDSPAWN_FAILURE_NOT_OVERWORLD,
[], [],
))); )));
} }
@ -150,8 +151,9 @@ async fn setworldspawn(
server.level_info.store(Arc::new(new_info)); server.level_info.store(Arc::new(new_info));
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation::COMMANDS_SETWORLDSPAWN_SUCCESS_NEW, translation::java::COMMANDS_SETWORLDSPAWN_SUCCESS_NEW,
translation::java::COMMANDS_SETWORLDSPAWN_SUCCESS_NEW,
[ [
TextComponent::text(new_position.0.x.to_string()), TextComponent::text(new_position.0.x.to_string()),
TextComponent::text(new_position.0.y.to_string()), TextComponent::text(new_position.0.y.to_string()),

View File

@ -131,8 +131,9 @@ async fn set_spawnpoint(sender: &CommandSender, target: &Arc<Player>, pos: Block
.await; .await;
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation::COMMANDS_SPAWNPOINT_SUCCESS_SINGLE_NEW, translation::java::COMMANDS_SPAWNPOINT_SUCCESS_SINGLE_NEW,
translation::java::COMMANDS_SPAWNPOINT_SUCCESS_SINGLE_NEW,
[ [
TextComponent::text(pos.0.x.to_string()), TextComponent::text(pos.0.x.to_string()),
TextComponent::text(pos.0.y.to_string()), TextComponent::text(pos.0.y.to_string()),

View File

@ -22,8 +22,12 @@ impl CommandExecutor for StopCommandExecutor {
context context
.source .source
.send_feedback( .send_feedback(
TextComponent::translate(translation::COMMANDS_STOP_STOPPING, []) TextComponent::translate_cross(
.color_named(NamedColor::Red), translation::java::COMMANDS_STOP_STOPPING,
translation::bedrock::COMMANDS_STOP_START,
[],
)
.color_named(NamedColor::Red),
true, true,
) )
.await; .await;

View File

@ -45,23 +45,27 @@ impl CommandExecutor for Executor {
} }
let text = match (category, sound) { let text = match (category, sound) {
(Ok(c), Ok(s)) => TextComponent::translate( (Ok(c), Ok(s)) => TextComponent::translate_cross(
translation::COMMANDS_STOPSOUND_SUCCESS_SOURCE_SOUND, translation::java::COMMANDS_STOPSOUND_SUCCESS_SOURCE_SOUND,
translation::java::COMMANDS_STOPSOUND_SUCCESS_SOURCE_SOUND,
[ [
TextComponent::text(s.to_name()), TextComponent::text(s.to_name()),
TextComponent::text(c.to_name()), TextComponent::text(c.to_name()),
], ],
), ),
(Ok(c), Err(_)) => TextComponent::translate( (Ok(c), Err(_)) => TextComponent::translate_cross(
translation::COMMANDS_STOPSOUND_SUCCESS_SOURCE_ANY, translation::java::COMMANDS_STOPSOUND_SUCCESS_SOURCE_ANY,
translation::java::COMMANDS_STOPSOUND_SUCCESS_SOURCE_ANY,
[TextComponent::text(c.to_name())], [TextComponent::text(c.to_name())],
), ),
(Err(_), Ok(s)) => TextComponent::translate( (Err(_), Ok(s)) => TextComponent::translate_cross(
translation::COMMANDS_STOPSOUND_SUCCESS_SOURCELESS_SOUND, translation::java::COMMANDS_STOPSOUND_SUCCESS_SOURCELESS_SOUND,
translation::java::COMMANDS_STOPSOUND_SUCCESS_SOURCELESS_SOUND,
[TextComponent::text(s.to_name())], [TextComponent::text(s.to_name())],
), ),
(Err(_), Err(_)) => TextComponent::translate( (Err(_), Err(_)) => TextComponent::translate_cross(
translation::COMMANDS_STOPSOUND_SUCCESS_SOURCELESS_ANY, translation::java::COMMANDS_STOPSOUND_SUCCESS_SOURCELESS_ANY,
translation::java::COMMANDS_STOPSOUND_SUCCESS_SOURCELESS_ANY,
[], [],
), ),
}; };

View File

@ -68,8 +68,9 @@ impl CommandExecutor for Executor {
let name = entity.get_display_name().await; let name = entity.get_display_name().await;
world.spawn_entity(entity).await; world.spawn_entity(entity).await;
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation::COMMANDS_SUMMON_SUCCESS, translation::java::COMMANDS_SUMMON_SUCCESS,
translation::bedrock::COMMANDS_SUMMON_SUCCESS,
[name], [name],
)) ))
.await; .await;

View File

@ -81,8 +81,9 @@ impl CommandExecutor for EntitiesToEntityExecutor {
let pitch = destination.pitch.load(); let pitch = destination.pitch.load();
let world = destination.world.load_full(); let world = destination.world.load_full();
if !World::is_valid(BlockPos(pos.floor_to_i32())) { if !World::is_valid(BlockPos(pos.floor_to_i32())) {
return Err(CommandError::CommandFailed(TextComponent::translate( return Err(CommandError::CommandFailed(TextComponent::translate_cross(
translation::COMMANDS_TELEPORT_INVALIDPOSITION, translation::java::COMMANDS_TELEPORT_INVALIDPOSITION,
translation::java::COMMANDS_TELEPORT_INVALIDPOSITION,
[], [],
))); )));
} }
@ -112,8 +113,9 @@ impl CommandExecutor for EntitiesToPosFacingPosExecutor {
let pos = Position3DArgumentConsumer::find_arg(args, ARG_LOCATION)?; let pos = Position3DArgumentConsumer::find_arg(args, ARG_LOCATION)?;
if !World::is_valid(BlockPos(pos.floor_to_i32())) { if !World::is_valid(BlockPos(pos.floor_to_i32())) {
return Err(CommandError::CommandFailed(TextComponent::translate( return Err(CommandError::CommandFailed(TextComponent::translate_cross(
translation::COMMANDS_TELEPORT_INVALIDPOSITION, translation::java::COMMANDS_TELEPORT_INVALIDPOSITION,
translation::java::COMMANDS_TELEPORT_INVALIDPOSITION,
[], [],
))); )));
} }
@ -147,8 +149,9 @@ impl CommandExecutor for EntitiesToPosFacingEntityExecutor {
let pos = Position3DArgumentConsumer::find_arg(args, ARG_LOCATION)?; let pos = Position3DArgumentConsumer::find_arg(args, ARG_LOCATION)?;
if !World::is_valid(BlockPos(pos.floor_to_i32())) { if !World::is_valid(BlockPos(pos.floor_to_i32())) {
return Err(CommandError::CommandFailed(TextComponent::translate( return Err(CommandError::CommandFailed(TextComponent::translate_cross(
translation::COMMANDS_TELEPORT_INVALIDPOSITION, translation::java::COMMANDS_TELEPORT_INVALIDPOSITION,
translation::java::COMMANDS_TELEPORT_INVALIDPOSITION,
[], [],
))); )));
} }
@ -183,8 +186,9 @@ impl CommandExecutor for EntitiesToPosWithRotationExecutor {
let pos = Position3DArgumentConsumer::find_arg(args, ARG_LOCATION)?; let pos = Position3DArgumentConsumer::find_arg(args, ARG_LOCATION)?;
if !World::is_valid(BlockPos(pos.floor_to_i32())) { if !World::is_valid(BlockPos(pos.floor_to_i32())) {
return Err(CommandError::CommandFailed(TextComponent::translate( return Err(CommandError::CommandFailed(TextComponent::translate_cross(
translation::COMMANDS_TELEPORT_INVALIDPOSITION, translation::java::COMMANDS_TELEPORT_INVALIDPOSITION,
translation::java::COMMANDS_TELEPORT_INVALIDPOSITION,
[], [],
))); )));
} }
@ -219,8 +223,9 @@ impl CommandExecutor for EntitiesToPosExecutor {
let pos = Position3DArgumentConsumer::find_arg(args, ARG_LOCATION)?; let pos = Position3DArgumentConsumer::find_arg(args, ARG_LOCATION)?;
if !World::is_valid(BlockPos(pos.floor_to_i32())) { if !World::is_valid(BlockPos(pos.floor_to_i32())) {
return Err(CommandError::CommandFailed(TextComponent::translate( return Err(CommandError::CommandFailed(TextComponent::translate_cross(
translation::COMMANDS_TELEPORT_INVALIDPOSITION, translation::java::COMMANDS_TELEPORT_INVALIDPOSITION,
translation::java::COMMANDS_TELEPORT_INVALIDPOSITION,
[], [],
))); )));
} }
@ -259,8 +264,9 @@ impl CommandExecutor for SelfToEntityExecutor {
match sender { match sender {
CommandSender::Player(player) => { CommandSender::Player(player) => {
if !World::is_valid(BlockPos(pos.floor_to_i32())) { if !World::is_valid(BlockPos(pos.floor_to_i32())) {
return Err(CommandError::CommandFailed(TextComponent::translate( return Err(CommandError::CommandFailed(TextComponent::translate_cross(
translation::COMMANDS_TELEPORT_INVALIDPOSITION, translation::java::COMMANDS_TELEPORT_INVALIDPOSITION,
translation::java::COMMANDS_TELEPORT_INVALIDPOSITION,
[], [],
))); )));
} }
@ -271,8 +277,9 @@ impl CommandExecutor for SelfToEntityExecutor {
Ok(1) Ok(1)
} }
_ => Err(CommandError::CommandFailed(TextComponent::translate( _ => Err(CommandError::CommandFailed(TextComponent::translate_cross(
translation::PERMISSIONS_REQUIRES_PLAYER, translation::java::PERMISSIONS_REQUIRES_PLAYER,
translation::java::PERMISSIONS_REQUIRES_PLAYER,
[], [],
))), ))),
} }
@ -295,8 +302,9 @@ impl CommandExecutor for SelfToPosExecutor {
let yaw = player.living_entity.entity.yaw.load(); let yaw = player.living_entity.entity.yaw.load();
let pitch = player.living_entity.entity.pitch.load(); let pitch = player.living_entity.entity.pitch.load();
if !World::is_valid(BlockPos(pos.floor_to_i32())) { if !World::is_valid(BlockPos(pos.floor_to_i32())) {
return Err(CommandError::CommandFailed(TextComponent::translate( return Err(CommandError::CommandFailed(TextComponent::translate_cross(
translation::COMMANDS_TELEPORT_INVALIDPOSITION, translation::java::COMMANDS_TELEPORT_INVALIDPOSITION,
translation::java::COMMANDS_TELEPORT_INVALIDPOSITION,
[], [],
))); )));
} }
@ -307,8 +315,9 @@ impl CommandExecutor for SelfToPosExecutor {
Ok(1) Ok(1)
} }
_ => Err(CommandError::CommandFailed(TextComponent::translate( _ => Err(CommandError::CommandFailed(TextComponent::translate_cross(
translation::PERMISSIONS_REQUIRES_PLAYER, translation::java::PERMISSIONS_REQUIRES_PLAYER,
translation::java::PERMISSIONS_REQUIRES_PLAYER,
[], [],
))), ))),
} }

View File

@ -64,14 +64,16 @@ impl TickExecutor {
if manager.is_sprinting() { if manager.is_sprinting() {
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation::COMMANDS_TICK_STATUS_SPRINTING, translation::java::COMMANDS_TICK_STATUS_SPRINTING,
translation::java::COMMANDS_TICK_STATUS_SPRINTING,
[], [],
)) ))
.await; .await;
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation::COMMANDS_TICK_QUERY_RATE_SPRINTING, translation::java::COMMANDS_TICK_QUERY_RATE_SPRINTING,
translation::java::COMMANDS_TICK_QUERY_RATE_SPRINTING,
[ [
TextComponent::text(format!("{tickrate:.1}")), TextComponent::text(format!("{tickrate:.1}")),
TextComponent::text(avg_mspt_str), TextComponent::text(avg_mspt_str),
@ -83,8 +85,9 @@ impl TickExecutor {
let target_mspt_str = nanos_to_millis_string(manager.nanoseconds_per_tick()); let target_mspt_str = nanos_to_millis_string(manager.nanoseconds_per_tick());
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation::COMMANDS_TICK_QUERY_RATE_RUNNING, translation::java::COMMANDS_TICK_QUERY_RATE_RUNNING,
translation::java::COMMANDS_TICK_QUERY_RATE_RUNNING,
[ [
TextComponent::text(format!("{tickrate:.1}")), TextComponent::text(format!("{tickrate:.1}")),
TextComponent::text(avg_mspt_str), TextComponent::text(avg_mspt_str),
@ -104,22 +107,25 @@ impl TickExecutor {
) { ) {
if manager.is_frozen() { if manager.is_frozen() {
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation::COMMANDS_TICK_STATUS_FROZEN, translation::java::COMMANDS_TICK_STATUS_FROZEN,
translation::java::COMMANDS_TICK_STATUS_FROZEN,
[], [],
)) ))
.await; .await;
} else if avg_tick_nanos > manager.nanoseconds_per_tick() { } else if avg_tick_nanos > manager.nanoseconds_per_tick() {
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation::COMMANDS_TICK_STATUS_LAGGING, translation::java::COMMANDS_TICK_STATUS_LAGGING,
translation::java::COMMANDS_TICK_STATUS_LAGGING,
[], [],
)) ))
.await; .await;
} else { } else {
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation::COMMANDS_TICK_STATUS_RUNNING, translation::java::COMMANDS_TICK_STATUS_RUNNING,
translation::java::COMMANDS_TICK_STATUS_RUNNING,
[], [],
)) ))
.await; .await;
@ -140,8 +146,9 @@ impl TickExecutor {
let p99_nanos = relevant_ticks[(sample_size as f32 * 0.99).floor() as usize]; let p99_nanos = relevant_ticks[(sample_size as f32 * 0.99).floor() as usize];
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation::COMMANDS_TICK_QUERY_PERCENTILES, translation::java::COMMANDS_TICK_QUERY_PERCENTILES,
translation::java::COMMANDS_TICK_QUERY_PERCENTILES,
[ [
TextComponent::text(nanos_to_millis_string(p50_nanos)), TextComponent::text(nanos_to_millis_string(p50_nanos)),
TextComponent::text(nanos_to_millis_string(p95_nanos)), TextComponent::text(nanos_to_millis_string(p95_nanos)),
@ -160,16 +167,21 @@ impl TickExecutor {
) { ) {
if manager.step_game_if_paused(server, ticks).await { if manager.step_game_if_paused(server, ticks).await {
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation::COMMANDS_TICK_STEP_SUCCESS, translation::java::COMMANDS_TICK_STEP_SUCCESS,
translation::java::COMMANDS_TICK_STEP_SUCCESS,
[TextComponent::text(ticks.to_string())], [TextComponent::text(ticks.to_string())],
)) ))
.await; .await;
} else { } else {
sender sender
.send_message( .send_message(
TextComponent::translate(translation::COMMANDS_TICK_STEP_FAIL, []) TextComponent::translate_cross(
.color_named(NamedColor::Red), translation::java::COMMANDS_TICK_STEP_FAIL,
translation::java::COMMANDS_TICK_STEP_FAIL,
[],
)
.color_named(NamedColor::Red),
) )
.await; .await;
} }
@ -185,15 +197,17 @@ impl TickExecutor {
.await .await
{ {
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation::COMMANDS_TICK_SPRINT_STOP_SUCCESS, translation::java::COMMANDS_TICK_SPRINT_STOP_SUCCESS,
translation::java::COMMANDS_TICK_SPRINT_STOP_SUCCESS,
[], [],
)) ))
.await; .await;
} }
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation::COMMANDS_TICK_STATUS_SPRINTING, translation::java::COMMANDS_TICK_STATUS_SPRINTING,
translation::java::COMMANDS_TICK_STATUS_SPRINTING,
[], [],
)) ))
.await; .await;
@ -207,8 +221,9 @@ impl TickExecutor {
) -> Result<i32, E> { ) -> Result<i32, E> {
manager.set_tick_rate(server, rate).await; manager.set_tick_rate(server, rate).await;
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation::COMMANDS_TICK_RATE_SUCCESS, translation::java::COMMANDS_TICK_RATE_SUCCESS,
translation::java::COMMANDS_TICK_RATE_SUCCESS,
[TextComponent::text(format!("{rate:.1}"))], [TextComponent::text(format!("{rate:.1}"))],
)) ))
.await; .await;
@ -242,7 +257,7 @@ impl CommandExecutor for TickExecutor {
"commands.tick.status.running" "commands.tick.status.running"
}; };
sender sender
.send_message(TextComponent::translate(message_key, [])) .send_message(TextComponent::translate_cross(message_key, message_key, []))
.await; .await;
Ok(freeze as i32) Ok(freeze as i32)
} }
@ -262,8 +277,9 @@ impl CommandExecutor for TickExecutor {
SubCommand::StepStop => { SubCommand::StepStop => {
if manager.stop_stepping(server).await { if manager.stop_stepping(server).await {
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation::COMMANDS_TICK_SPRINT_STOP_SUCCESS, translation::java::COMMANDS_TICK_SPRINT_STOP_SUCCESS,
translation::java::COMMANDS_TICK_SPRINT_STOP_SUCCESS,
[], [],
)) ))
.await; .await;
@ -271,8 +287,9 @@ impl CommandExecutor for TickExecutor {
} else { } else {
// TODO: send feedback as error without Err // TODO: send feedback as error without Err
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation::COMMANDS_TICK_SPRINT_STOP_FAIL, translation::java::COMMANDS_TICK_SPRINT_STOP_FAIL,
translation::java::COMMANDS_TICK_SPRINT_STOP_FAIL,
[], [],
)) ))
.await; .await;
@ -296,8 +313,9 @@ impl CommandExecutor for TickExecutor {
SubCommand::SprintStop => { SubCommand::SprintStop => {
if manager.stop_sprinting(server).await { if manager.stop_sprinting(server).await {
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation::COMMANDS_TICK_SPRINT_STOP_SUCCESS, translation::java::COMMANDS_TICK_SPRINT_STOP_SUCCESS,
translation::java::COMMANDS_TICK_SPRINT_STOP_SUCCESS,
[], [],
)) ))
.await; .await;
@ -306,8 +324,9 @@ impl CommandExecutor for TickExecutor {
// TODO: send feedback as error without Err // TODO: send feedback as error without Err
sender sender
.send_message( .send_message(
TextComponent::translate( TextComponent::translate_cross(
translation::COMMANDS_TICK_SPRINT_STOP_FAIL, translation::java::COMMANDS_TICK_SPRINT_STOP_FAIL,
translation::java::COMMANDS_TICK_SPRINT_STOP_FAIL,
[], [],
) )
.color(Color::Named(NamedColor::Red)), .color(Color::Named(NamedColor::Red)),

View File

@ -67,8 +67,9 @@ impl CommandExecutor for QueryExecutor {
QueryMode::Day => level_time.query_day(), QueryMode::Day => level_time.query_day(),
}; };
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation::COMMANDS_TIME_QUERY, translation::java::COMMANDS_TIME_QUERY,
translation::java::COMMANDS_TIME_QUERY,
[TextComponent::text(curr_time.to_string())], [TextComponent::text(curr_time.to_string())],
)) ))
.await; .await;
@ -112,8 +113,9 @@ impl CommandExecutor for ChangeExecutor {
level_time.send_time(world).await; level_time.send_time(world).await;
let curr_time = level_time.query_daytime(); let curr_time = level_time.query_daytime();
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation::COMMANDS_TIME_SET, translation::java::COMMANDS_TIME_SET,
translation::bedrock::COMMANDS_TIME_SET,
[TextComponent::text(curr_time.to_string())], [TextComponent::text(curr_time.to_string())],
)) ))
.await; .await;
@ -124,8 +126,9 @@ impl CommandExecutor for ChangeExecutor {
level_time.set_time(time_count.into()); level_time.set_time(time_count.into());
level_time.send_time(world).await; level_time.send_time(world).await;
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation::COMMANDS_TIME_SET, translation::java::COMMANDS_TIME_SET,
translation::bedrock::COMMANDS_TIME_SET,
[TextComponent::text(time_count.to_string())], [TextComponent::text(time_count.to_string())],
)) ))
.await; .await;

View File

@ -53,14 +53,22 @@ impl CommandExecutor for ClearOrResetExecutor {
} else { } else {
"commands.title.cleared.single" "commands.title.cleared.single"
}; };
TextComponent::translate(text, [targets[0].get_display_name().await]) TextComponent::translate_cross(
text,
text,
[targets[0].get_display_name().await],
)
} else { } else {
let text = if reset { let text = if reset {
"commands.title.reset.multiple" "commands.title.reset.multiple"
} else { } else {
"commands.title.cleared.multiple" "commands.title.cleared.multiple"
}; };
TextComponent::translate(text, [TextComponent::text(targets.len().to_string())]) TextComponent::translate_cross(
text,
text,
[TextComponent::text(targets.len().to_string())],
)
}) })
.await; .await;
@ -94,12 +102,14 @@ impl CommandExecutor for TitleExecutor {
let mode_name = format!("{mode:?}").to_lowercase(); let mode_name = format!("{mode:?}").to_lowercase();
sender sender
.send_message(if targets.len() == 1 { .send_message(if targets.len() == 1 {
TextComponent::translate( TextComponent::translate_cross(
format!("commands.title.show.{mode_name}.single").clone(),
format!("commands.title.show.{mode_name}.single"), format!("commands.title.show.{mode_name}.single"),
[targets[0].get_display_name().await], [targets[0].get_display_name().await],
) )
} else { } else {
TextComponent::translate( TextComponent::translate_cross(
format!("commands.title.show.{mode_name}.multiple"),
format!("commands.title.show.{mode_name}.multiple"), format!("commands.title.show.{mode_name}.multiple"),
[TextComponent::text(targets.len().to_string())], [TextComponent::text(targets.len().to_string())],
) )
@ -135,12 +145,14 @@ impl CommandExecutor for TimesTitleExecutor {
sender sender
.send_message(if targets.len() == 1 { .send_message(if targets.len() == 1 {
TextComponent::translate( TextComponent::translate_cross(
"commands.title.times.single",
"commands.title.times.single", "commands.title.times.single",
[targets[0].get_display_name().await], [targets[0].get_display_name().await],
) )
} else { } else {
TextComponent::translate( TextComponent::translate_cross(
"commands.title.times.multiple",
"commands.title.times.multiple", "commands.title.times.multiple",
[TextComponent::text(targets.len().to_string())], [TextComponent::text(targets.len().to_string())],
) )

View File

@ -97,7 +97,8 @@ impl CommandExecutor for TargetPlayerExecutor {
}; };
if players.is_empty() { if players.is_empty() {
return Err(CommandError::CommandFailed(TextComponent::translate( return Err(CommandError::CommandFailed(TextComponent::translate_cross(
"commands.transfer.error.no_players",
"commands.transfer.error.no_players", "commands.transfer.error.no_players",
[], [],
))); )));
@ -115,7 +116,8 @@ impl CommandExecutor for TargetPlayerExecutor {
if players.len() == 1 { if players.len() == 1 {
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.transfer.success.single",
"commands.transfer.success.single", "commands.transfer.success.single",
[ [
players[0].get_display_name().await, players[0].get_display_name().await,
@ -126,7 +128,8 @@ impl CommandExecutor for TargetPlayerExecutor {
.await; .await;
} else { } else {
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.transfer.success.multiple",
"commands.transfer.success.multiple", "commands.transfer.success.multiple",
[ [
TextComponent::text(players.len().to_string()), TextComponent::text(players.len().to_string()),

View File

@ -52,8 +52,9 @@ impl CommandExecutor for Executor {
.set_weather_parameters(&world, processed_duration, 0, false, false) .set_weather_parameters(&world, processed_duration, 0, false, false)
.await; .await;
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation::COMMANDS_WEATHER_SET_CLEAR, translation::java::COMMANDS_WEATHER_SET_CLEAR,
translation::java::COMMANDS_WEATHER_SET_CLEAR,
[], [],
)) ))
.await; .await;
@ -66,8 +67,9 @@ impl CommandExecutor for Executor {
.set_weather_parameters(&world, 0, processed_duration, true, false) .set_weather_parameters(&world, 0, processed_duration, true, false)
.await; .await;
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation::COMMANDS_WEATHER_SET_RAIN, translation::java::COMMANDS_WEATHER_SET_RAIN,
translation::java::COMMANDS_WEATHER_SET_RAIN,
[], [],
)) ))
.await; .await;
@ -80,8 +82,9 @@ impl CommandExecutor for Executor {
.set_weather_parameters(&world, 0, processed_duration, true, true) .set_weather_parameters(&world, 0, processed_duration, true, true)
.await; .await;
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation::COMMANDS_WEATHER_SET_THUNDER, translation::java::COMMANDS_WEATHER_SET_THUNDER,
translation::java::COMMANDS_WEATHER_SET_THUNDER,
[], [],
)) ))
.await; .await;

View File

@ -37,8 +37,9 @@ async fn kick_non_whitelisted_players(server: &Server) {
player player
.kick( .kick(
DisconnectReason::Kicked, DisconnectReason::Kicked,
TextComponent::translate( TextComponent::translate_cross(
translation::MULTIPLAYER_DISCONNECT_NOT_WHITELISTED, translation::java::MULTIPLAYER_DISCONNECT_NOT_WHITELISTED,
translation::java::MULTIPLAYER_DISCONNECT_NOT_WHITELISTED,
&[], &[],
), ),
) )
@ -59,15 +60,17 @@ impl CommandExecutor for OnExecutor {
Box::pin(async move { Box::pin(async move {
let previous = server.white_list.swap(true, Ordering::Relaxed); let previous = server.white_list.swap(true, Ordering::Relaxed);
if previous { if previous {
Err(CommandError::CommandFailed(TextComponent::translate( Err(CommandError::CommandFailed(TextComponent::translate_cross(
translation::COMMANDS_WHITELIST_ALREADYON, translation::java::COMMANDS_WHITELIST_ALREADYON,
translation::java::COMMANDS_WHITELIST_ALREADYON,
&[], &[],
))) )))
} else { } else {
kick_non_whitelisted_players(server).await; kick_non_whitelisted_players(server).await;
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation::COMMANDS_WHITELIST_ENABLED, translation::java::COMMANDS_WHITELIST_ENABLED,
translation::java::COMMANDS_WHITELIST_ENABLED,
&[], &[],
)) ))
.await; .await;
@ -90,15 +93,17 @@ impl CommandExecutor for OffExecutor {
let previous = server.white_list.swap(false, Ordering::Relaxed); let previous = server.white_list.swap(false, Ordering::Relaxed);
if previous { if previous {
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation::COMMANDS_WHITELIST_DISABLED, translation::java::COMMANDS_WHITELIST_DISABLED,
translation::java::COMMANDS_WHITELIST_DISABLED,
&[], &[],
)) ))
.await; .await;
Ok(1) Ok(1)
} else { } else {
Err(CommandError::CommandFailed(TextComponent::translate( Err(CommandError::CommandFailed(TextComponent::translate_cross(
translation::COMMANDS_WHITELIST_ALREADYOFF, translation::java::COMMANDS_WHITELIST_ALREADYOFF,
translation::java::COMMANDS_WHITELIST_ALREADYOFF,
&[], &[],
))) )))
} }
@ -119,8 +124,9 @@ impl CommandExecutor for ListExecutor {
let whitelist = &server.data.whitelist_config.read().await.whitelist; let whitelist = &server.data.whitelist_config.read().await.whitelist;
if whitelist.is_empty() { if whitelist.is_empty() {
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation::COMMANDS_WHITELIST_NONE, translation::java::COMMANDS_WHITELIST_NONE,
translation::java::COMMANDS_WHITELIST_NONE,
[], [],
)) ))
.await; .await;
@ -136,8 +142,9 @@ impl CommandExecutor for ListExecutor {
let names_len = names.len() as i32; let names_len = names.len() as i32;
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation::COMMANDS_WHITELIST_LIST, translation::java::COMMANDS_WHITELIST_LIST,
translation::java::COMMANDS_WHITELIST_LIST,
[ [
TextComponent::text(whitelist.len().to_string()), TextComponent::text(whitelist.len().to_string()),
TextComponent::text(names), TextComponent::text(names),
@ -163,8 +170,9 @@ impl CommandExecutor for ReloadExecutor {
*server.data.whitelist_config.write().await = WhitelistConfig::load(); *server.data.whitelist_config.write().await = WhitelistConfig::load();
kick_non_whitelisted_players(server).await; kick_non_whitelisted_players(server).await;
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation::COMMANDS_WHITELIST_RELOADED, translation::java::COMMANDS_WHITELIST_RELOADED,
translation::java::COMMANDS_WHITELIST_RELOADED,
&[], &[],
)) ))
.await; .await;
@ -204,8 +212,9 @@ impl CommandExecutor for AddExecutor {
.whitelist .whitelist
.push(WhitelistEntry::new(profile.id, profile.name.clone())); .push(WhitelistEntry::new(profile.id, profile.name.clone()));
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation::COMMANDS_WHITELIST_ADD_SUCCESS, translation::java::COMMANDS_WHITELIST_ADD_SUCCESS,
translation::java::COMMANDS_WHITELIST_ADD_SUCCESS,
[TextComponent::text(profile.name.clone())], [TextComponent::text(profile.name.clone())],
)) ))
.await; .await;
@ -215,8 +224,9 @@ impl CommandExecutor for AddExecutor {
whitelist.save(); whitelist.save();
if successes == 0 { if successes == 0 {
Err(CommandError::CommandFailed(TextComponent::translate( Err(CommandError::CommandFailed(TextComponent::translate_cross(
translation::COMMANDS_WHITELIST_ADD_FAILED, translation::java::COMMANDS_WHITELIST_ADD_FAILED,
translation::java::COMMANDS_WHITELIST_ADD_FAILED,
&[], &[],
))) )))
} else { } else {
@ -251,8 +261,9 @@ impl CommandExecutor for RemoveExecutor {
if let Some(i) = i { if let Some(i) = i {
whitelist.whitelist.remove(i); whitelist.whitelist.remove(i);
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
translation::COMMANDS_WHITELIST_REMOVE_SUCCESS, translation::java::COMMANDS_WHITELIST_REMOVE_SUCCESS,
translation::java::COMMANDS_WHITELIST_REMOVE_SUCCESS,
[TextComponent::text(player.name.clone())], [TextComponent::text(player.name.clone())],
)) ))
.await; .await;
@ -266,8 +277,9 @@ impl CommandExecutor for RemoveExecutor {
kick_non_whitelisted_players(server).await; kick_non_whitelisted_players(server).await;
if successes == 0 { if successes == 0 {
Err(CommandError::CommandFailed(TextComponent::translate( Err(CommandError::CommandFailed(TextComponent::translate_cross(
translation::COMMANDS_WHITELIST_REMOVE_FAILED, translation::java::COMMANDS_WHITELIST_REMOVE_FAILED,
translation::java::COMMANDS_WHITELIST_REMOVE_FAILED,
&[], &[],
))) )))
} else { } else {

View File

@ -59,7 +59,8 @@ impl CommandExecutor for GetExecutor {
let diameter = border.new_diameter.round() as i32; let diameter = border.new_diameter.round() as i32;
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.worldborder.get",
"commands.worldborder.get", "commands.worldborder.get",
[TextComponent::text(diameter.to_string())], [TextComponent::text(diameter.to_string())],
)) ))
@ -95,14 +96,16 @@ impl CommandExecutor for SetExecutor {
}; };
if (distance - border.new_diameter).abs() < f64::EPSILON { if (distance - border.new_diameter).abs() < f64::EPSILON {
return Err(CommandError::CommandFailed(TextComponent::translate( return Err(CommandError::CommandFailed(TextComponent::translate_cross(
NOTHING_CHANGED_EXCEPTION,
NOTHING_CHANGED_EXCEPTION, NOTHING_CHANGED_EXCEPTION,
[], [],
))); )));
} }
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.worldborder.set.immediate",
"commands.worldborder.set.immediate", "commands.worldborder.set.immediate",
[TextComponent::text(format!("{distance:.1}"))], [TextComponent::text(format!("{distance:.1}"))],
)) ))
@ -148,7 +151,8 @@ impl CommandExecutor for SetTimeExecutor {
match distance.total_cmp(&border.new_diameter) { match distance.total_cmp(&border.new_diameter) {
std::cmp::Ordering::Equal => { std::cmp::Ordering::Equal => {
return Err(CommandError::CommandFailed(TextComponent::translate( return Err(CommandError::CommandFailed(TextComponent::translate_cross(
NOTHING_CHANGED_EXCEPTION,
NOTHING_CHANGED_EXCEPTION, NOTHING_CHANGED_EXCEPTION,
[], [],
))); )));
@ -156,7 +160,8 @@ impl CommandExecutor for SetTimeExecutor {
std::cmp::Ordering::Less => { std::cmp::Ordering::Less => {
let dist = format!("{distance:.1}"); let dist = format!("{distance:.1}");
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.worldborder.set.shrink",
"commands.worldborder.set.shrink", "commands.worldborder.set.shrink",
[ [
TextComponent::text(dist), TextComponent::text(dist),
@ -168,7 +173,8 @@ impl CommandExecutor for SetTimeExecutor {
std::cmp::Ordering::Greater => { std::cmp::Ordering::Greater => {
let dist = format!("{distance:.1}"); let dist = format!("{distance:.1}");
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.worldborder.set.grow",
"commands.worldborder.set.grow", "commands.worldborder.set.grow",
[ [
TextComponent::text(dist), TextComponent::text(dist),
@ -214,7 +220,8 @@ impl CommandExecutor for AddExecutor {
}; };
if distance_add == 0.0 { if distance_add == 0.0 {
return Err(CommandError::CommandFailed(TextComponent::translate( return Err(CommandError::CommandFailed(TextComponent::translate_cross(
NOTHING_CHANGED_EXCEPTION,
NOTHING_CHANGED_EXCEPTION, NOTHING_CHANGED_EXCEPTION,
[], [],
))); )));
@ -224,7 +231,8 @@ impl CommandExecutor for AddExecutor {
let dist = format!("{distance:.1}"); let dist = format!("{distance:.1}");
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.worldborder.set.immediate",
"commands.worldborder.set.immediate", "commands.worldborder.set.immediate",
[TextComponent::text(dist)], [TextComponent::text(dist)],
)) ))
@ -277,7 +285,8 @@ impl CommandExecutor for AddTimeExecutor {
std::cmp::Ordering::Less => { std::cmp::Ordering::Less => {
let dist = format!("{distance:.1}"); let dist = format!("{distance:.1}");
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.worldborder.set.shrink",
"commands.worldborder.set.shrink", "commands.worldborder.set.shrink",
[ [
TextComponent::text(dist), TextComponent::text(dist),
@ -289,7 +298,8 @@ impl CommandExecutor for AddTimeExecutor {
std::cmp::Ordering::Greater => { std::cmp::Ordering::Greater => {
let dist = format!("{distance:.1}"); let dist = format!("{distance:.1}");
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.worldborder.set.grow",
"commands.worldborder.set.grow", "commands.worldborder.set.grow",
[ [
TextComponent::text(dist), TextComponent::text(dist),
@ -329,7 +339,8 @@ impl CommandExecutor for CenterExecutor {
let Vector2 { x, y } = Position2DArgumentConsumer.find_arg_default_name(args)?; let Vector2 { x, y } = Position2DArgumentConsumer.find_arg_default_name(args)?;
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.worldborder.center.success",
"commands.worldborder.center.success", "commands.worldborder.center.success",
[ [
TextComponent::text(format!("{x:.2}")), TextComponent::text(format!("{x:.2}")),
@ -369,7 +380,8 @@ impl CommandExecutor for DamageAmountExecutor {
}; };
if (damage_per_block - border.damage_per_block).abs() < f32::EPSILON { if (damage_per_block - border.damage_per_block).abs() < f32::EPSILON {
return Err(CommandError::CommandFailed(TextComponent::translate( return Err(CommandError::CommandFailed(TextComponent::translate_cross(
"commands.worldborder.damage.amount.failed",
"commands.worldborder.damage.amount.failed", "commands.worldborder.damage.amount.failed",
[], [],
))); )));
@ -377,7 +389,8 @@ impl CommandExecutor for DamageAmountExecutor {
let damage = format!("{damage_per_block:.2}"); let damage = format!("{damage_per_block:.2}");
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.worldborder.damage.amount.success",
"commands.worldborder.damage.amount.success", "commands.worldborder.damage.amount.success",
[TextComponent::text(damage)], [TextComponent::text(damage)],
)) ))
@ -413,7 +426,8 @@ impl CommandExecutor for DamageBufferExecutor {
}; };
if (buffer - border.buffer).abs() < f32::EPSILON { if (buffer - border.buffer).abs() < f32::EPSILON {
return Err(CommandError::CommandFailed(TextComponent::translate( return Err(CommandError::CommandFailed(TextComponent::translate_cross(
"commands.worldborder.damage.amount.failed",
"commands.worldborder.damage.amount.failed", "commands.worldborder.damage.amount.failed",
[], [],
))); )));
@ -421,7 +435,8 @@ impl CommandExecutor for DamageBufferExecutor {
let buf = format!("{buffer:.2}"); let buf = format!("{buffer:.2}");
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.worldborder.damage.buffer.success",
"commands.worldborder.damage.buffer.success", "commands.worldborder.damage.buffer.success",
[TextComponent::text(buf)], [TextComponent::text(buf)],
)) ))
@ -457,14 +472,16 @@ impl CommandExecutor for WarningDistanceExecutor {
}; };
if distance == border.warning_blocks { if distance == border.warning_blocks {
return Err(CommandError::CommandFailed(TextComponent::translate( return Err(CommandError::CommandFailed(TextComponent::translate_cross(
"commands.worldborder.warning.distance.failed",
"commands.worldborder.warning.distance.failed", "commands.worldborder.warning.distance.failed",
[], [],
))); )));
} }
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.worldborder.warning.distance.success",
"commands.worldborder.warning.distance.success", "commands.worldborder.warning.distance.success",
[TextComponent::text(distance.to_string())], [TextComponent::text(distance.to_string())],
)) ))
@ -500,14 +517,16 @@ impl CommandExecutor for WarningTimeExecutor {
}; };
if time == border.warning_time { if time == border.warning_time {
return Err(CommandError::CommandFailed(TextComponent::translate( return Err(CommandError::CommandFailed(TextComponent::translate_cross(
"commands.worldborder.warning.time.failed",
"commands.worldborder.warning.time.failed", "commands.worldborder.warning.time.failed",
[], [],
))); )));
} }
sender sender
.send_message(TextComponent::translate( .send_message(TextComponent::translate_cross(
"commands.worldborder.warning.time.success",
"commands.worldborder.warning.time.success", "commands.worldborder.warning.time.success",
[TextComponent::text(time.to_string())], [TextComponent::text(time.to_string())],
)) ))

View File

@ -15,10 +15,14 @@ use pumpkin_util::text::color::{Color, NamedColor};
use std::pin::Pin; use std::pin::Pin;
use std::sync::Arc; use std::sync::Arc;
pub const REQUIRES_PLAYER: CommandErrorType<0> = pub const REQUIRES_PLAYER: CommandErrorType<0> = CommandErrorType::new(
CommandErrorType::new(translation::PERMISSIONS_REQUIRES_PLAYER); translation::java::PERMISSIONS_REQUIRES_PLAYER,
pub const REQUIRES_ENTITY: CommandErrorType<0> = translation::java::PERMISSIONS_REQUIRES_PLAYER,
CommandErrorType::new(translation::PERMISSIONS_REQUIRES_ENTITY); );
pub const REQUIRES_ENTITY: CommandErrorType<0> = CommandErrorType::new(
translation::java::PERMISSIONS_REQUIRES_ENTITY,
translation::java::PERMISSIONS_REQUIRES_ENTITY,
);
pub trait ReturnValueCallable: Send + Sync { pub trait ReturnValueCallable: Send + Sync {
fn call(&self, value: ReturnValue) -> Pin<Box<dyn Future<Output = ()> + Send + '_>>; fn call(&self, value: ReturnValue) -> Pin<Box<dyn Future<Output = ()> + Send + '_>>;
@ -407,10 +411,13 @@ impl CommandSource {
/// Sends a message to all online operators. /// Sends a message to all online operators.
async fn send_to_ops(&self, message: TextComponent) { async fn send_to_ops(&self, message: TextComponent) {
let text = let text = TextComponent::translate_cross(
TextComponent::translate("chat.type.admin", &[self.display_name.clone(), message]) "chat.type.admin",
.color(Color::Named(NamedColor::Gray)) "chat.type.admin",
.italic(); &[self.display_name.clone(), message],
)
.color(Color::Named(NamedColor::Gray))
.italic();
let Some(server) = &self.server else { let Some(server) = &self.server else {
return; return;
}; };

View File

@ -106,9 +106,13 @@ fn render_syntax_error_messages(syntax_error: CommandSyntaxError) -> Vec<TextCom
} }
context_message = context_message.add_child( context_message = context_message.add_child(
TextComponent::translate(translation::COMMAND_CONTEXT_HERE, []) TextComponent::translate_cross(
.color_named(NamedColor::Red) translation::java::COMMAND_CONTEXT_HERE,
.italic(), translation::java::COMMAND_CONTEXT_HERE,
[],
)
.color_named(NamedColor::Red)
.italic(),
); );
vec![syntax_error.message, context_message] vec![syntax_error.message, context_message]
@ -748,7 +752,7 @@ mod test {
let here_component = &context.extra[3]; let here_component = &context.extra[3];
if let TextContent::Translate { translate, .. } = here_component.content.as_ref() { if let TextContent::Translate { translate, .. } = here_component.content.as_ref() {
assert_eq!(translate, translation::COMMAND_CONTEXT_HERE); assert_eq!(translate, translation::java::COMMAND_CONTEXT_HERE);
} else { } else {
panic!("expected translate component for command.context.here"); panic!("expected translate component for command.context.here");
} }

View File

@ -1,62 +1,117 @@
use pumpkin_data::translation; use pumpkin_data::translation;
// These are akin to the translatable built-in exceptions in Minecraft. // These are akin to the translatable built-in exceptions in Minecraft.
pub const READER_EXPECTED_START_QUOTE: CommandErrorType<0> = pub const READER_EXPECTED_START_QUOTE: CommandErrorType<0> = CommandErrorType::new(
CommandErrorType::new(translation::PARSING_QUOTE_EXPECTED_START); translation::java::PARSING_QUOTE_EXPECTED_START,
pub const READER_EXPECTED_END_QUOTE: CommandErrorType<0> = translation::java::PARSING_QUOTE_EXPECTED_START,
CommandErrorType::new(translation::PARSING_QUOTE_EXPECTED_END); );
pub const READER_INVALID_ESCAPE: CommandErrorType<1> = pub const READER_EXPECTED_END_QUOTE: CommandErrorType<0> = CommandErrorType::new(
CommandErrorType::new(translation::PARSING_QUOTE_ESCAPE); translation::java::PARSING_QUOTE_EXPECTED_END,
pub const READER_INVALID_BOOL: CommandErrorType<1> = translation::java::PARSING_QUOTE_EXPECTED_END,
CommandErrorType::new(translation::PARSING_BOOL_INVALID); );
pub const READER_EXPECTED_BOOL: CommandErrorType<0> = pub const READER_INVALID_ESCAPE: CommandErrorType<1> = CommandErrorType::new(
CommandErrorType::new(translation::PARSING_BOOL_EXPECTED); translation::java::PARSING_QUOTE_ESCAPE,
pub const READER_INVALID_INT: CommandErrorType<1> = translation::java::PARSING_QUOTE_ESCAPE,
CommandErrorType::new(translation::PARSING_INT_INVALID); );
pub const READER_EXPECTED_INT: CommandErrorType<0> = pub const READER_INVALID_BOOL: CommandErrorType<1> = CommandErrorType::new(
CommandErrorType::new(translation::PARSING_INT_EXPECTED); translation::java::PARSING_BOOL_INVALID,
pub const READER_INVALID_LONG: CommandErrorType<1> = translation::java::PARSING_BOOL_INVALID,
CommandErrorType::new(translation::PARSING_LONG_INVALID); );
pub const READER_EXPECTED_LONG: CommandErrorType<0> = pub const READER_EXPECTED_BOOL: CommandErrorType<0> = CommandErrorType::new(
CommandErrorType::new(translation::PARSING_LONG_EXPECTED); translation::java::PARSING_BOOL_EXPECTED,
pub const READER_INVALID_DOUBLE: CommandErrorType<1> = translation::java::PARSING_BOOL_EXPECTED,
CommandErrorType::new(translation::PARSING_DOUBLE_INVALID); );
pub const READER_EXPECTED_DOUBLE: CommandErrorType<0> = pub const READER_INVALID_INT: CommandErrorType<1> = CommandErrorType::new(
CommandErrorType::new(translation::PARSING_DOUBLE_EXPECTED); translation::java::PARSING_INT_INVALID,
pub const READER_INVALID_FLOAT: CommandErrorType<1> = translation::java::PARSING_INT_INVALID,
CommandErrorType::new(translation::PARSING_FLOAT_INVALID); );
pub const READER_EXPECTED_FLOAT: CommandErrorType<0> = pub const READER_EXPECTED_INT: CommandErrorType<0> = CommandErrorType::new(
CommandErrorType::new(translation::PARSING_FLOAT_EXPECTED); translation::java::PARSING_INT_EXPECTED,
pub const READER_EXPECTED_SYMBOL: CommandErrorType<1> = translation::java::PARSING_INT_EXPECTED,
CommandErrorType::new(translation::PARSING_EXPECTED); );
pub const READER_INVALID_LONG: CommandErrorType<1> = CommandErrorType::new(
translation::java::PARSING_LONG_INVALID,
translation::java::PARSING_LONG_INVALID,
);
pub const READER_EXPECTED_LONG: CommandErrorType<0> = CommandErrorType::new(
translation::java::PARSING_LONG_EXPECTED,
translation::java::PARSING_LONG_EXPECTED,
);
pub const READER_INVALID_DOUBLE: CommandErrorType<1> = CommandErrorType::new(
translation::java::PARSING_DOUBLE_INVALID,
translation::java::PARSING_DOUBLE_INVALID,
);
pub const READER_EXPECTED_DOUBLE: CommandErrorType<0> = CommandErrorType::new(
translation::java::PARSING_DOUBLE_EXPECTED,
translation::java::PARSING_DOUBLE_EXPECTED,
);
pub const READER_INVALID_FLOAT: CommandErrorType<1> = CommandErrorType::new(
translation::java::PARSING_FLOAT_INVALID,
translation::java::PARSING_FLOAT_INVALID,
);
pub const READER_EXPECTED_FLOAT: CommandErrorType<0> = CommandErrorType::new(
translation::java::PARSING_FLOAT_EXPECTED,
translation::java::PARSING_FLOAT_EXPECTED,
);
pub const READER_EXPECTED_SYMBOL: CommandErrorType<1> = CommandErrorType::new(
translation::java::PARSING_EXPECTED,
translation::java::PARSING_EXPECTED,
);
pub const LITERAL_INCORRECT: CommandErrorType<1> = pub const LITERAL_INCORRECT: CommandErrorType<1> = CommandErrorType::new(
CommandErrorType::new(translation::ARGUMENT_LITERAL_INCORRECT); translation::java::ARGUMENT_LITERAL_INCORRECT,
translation::java::ARGUMENT_LITERAL_INCORRECT,
);
pub const DOUBLE_TOO_LOW: CommandErrorType<2> = pub const DOUBLE_TOO_LOW: CommandErrorType<2> = CommandErrorType::new(
CommandErrorType::new(translation::ARGUMENT_DOUBLE_LOW); translation::java::ARGUMENT_DOUBLE_LOW,
pub const DOUBLE_TOO_HIGH: CommandErrorType<2> = translation::java::ARGUMENT_DOUBLE_LOW,
CommandErrorType::new(translation::ARGUMENT_DOUBLE_BIG); );
pub const FLOAT_TOO_LOW: CommandErrorType<2> = pub const DOUBLE_TOO_HIGH: CommandErrorType<2> = CommandErrorType::new(
CommandErrorType::new(translation::ARGUMENT_FLOAT_LOW); translation::java::ARGUMENT_DOUBLE_BIG,
pub const FLOAT_TOO_HIGH: CommandErrorType<2> = translation::java::ARGUMENT_DOUBLE_BIG,
CommandErrorType::new(translation::ARGUMENT_FLOAT_BIG); );
pub const INTEGER_TOO_LOW: CommandErrorType<2> = pub const FLOAT_TOO_LOW: CommandErrorType<2> = CommandErrorType::new(
CommandErrorType::new(translation::ARGUMENT_INTEGER_LOW); translation::java::ARGUMENT_FLOAT_LOW,
pub const INTEGER_TOO_HIGH: CommandErrorType<2> = translation::java::ARGUMENT_FLOAT_LOW,
CommandErrorType::new(translation::ARGUMENT_INTEGER_BIG); );
pub const LONG_TOO_LOW: CommandErrorType<2> = CommandErrorType::new(translation::ARGUMENT_LONG_LOW); pub const FLOAT_TOO_HIGH: CommandErrorType<2> = CommandErrorType::new(
pub const LONG_TOO_HIGH: CommandErrorType<2> = translation::java::ARGUMENT_FLOAT_BIG,
CommandErrorType::new(translation::ARGUMENT_LONG_BIG); translation::java::ARGUMENT_FLOAT_BIG,
);
pub const INTEGER_TOO_LOW: CommandErrorType<2> = CommandErrorType::new(
translation::java::ARGUMENT_INTEGER_LOW,
translation::java::ARGUMENT_INTEGER_LOW,
);
pub const INTEGER_TOO_HIGH: CommandErrorType<2> = CommandErrorType::new(
translation::java::ARGUMENT_INTEGER_BIG,
translation::java::ARGUMENT_INTEGER_BIG,
);
pub const LONG_TOO_LOW: CommandErrorType<2> = CommandErrorType::new(
translation::java::ARGUMENT_LONG_LOW,
translation::java::ARGUMENT_LONG_LOW,
);
pub const LONG_TOO_HIGH: CommandErrorType<2> = CommandErrorType::new(
translation::java::ARGUMENT_LONG_BIG,
translation::java::ARGUMENT_LONG_BIG,
);
pub const DISPATCHER_UNKNOWN_COMMAND: CommandErrorType<0> = pub const DISPATCHER_UNKNOWN_COMMAND: CommandErrorType<0> = CommandErrorType::new(
CommandErrorType::new(translation::COMMAND_UNKNOWN_COMMAND); translation::java::COMMAND_UNKNOWN_COMMAND,
pub const DISPATCHER_UNKNOWN_ARGUMENT: CommandErrorType<0> = translation::bedrock::COMMANDS_GENERIC_UNKNOWN,
CommandErrorType::new(translation::COMMAND_UNKNOWN_ARGUMENT); );
pub const DISPATCHER_EXPECTED_ARGUMENT_SEPARATOR: CommandErrorType<0> = pub const DISPATCHER_UNKNOWN_ARGUMENT: CommandErrorType<0> = CommandErrorType::new(
CommandErrorType::new(translation::COMMAND_EXPECTED_SEPARATOR); translation::java::COMMAND_UNKNOWN_ARGUMENT,
pub const DISPATCHER_PARSE_EXCEPTION: CommandErrorType<1> = translation::java::COMMAND_UNKNOWN_ARGUMENT,
CommandErrorType::new(translation::COMMAND_EXCEPTION); );
pub const DISPATCHER_EXPECTED_ARGUMENT_SEPARATOR: CommandErrorType<0> = CommandErrorType::new(
translation::java::COMMAND_EXPECTED_SEPARATOR,
translation::java::COMMAND_EXPECTED_SEPARATOR,
);
pub const DISPATCHER_PARSE_EXCEPTION: CommandErrorType<1> = CommandErrorType::new(
translation::java::COMMAND_EXCEPTION,
translation::bedrock::COMMANDS_GENERIC_SYNTAX,
);
use crate::command::errors::{ use crate::command::errors::{
command_syntax_error::{CommandSyntaxError, ContextProvider}, command_syntax_error::{CommandSyntaxError, ContextProvider},
@ -70,7 +125,7 @@ use pumpkin_util::text::TextComponent;
pub enum TemplateText { pub enum TemplateText {
/// This is first translated, then arguments are substituted (which are not constant) /// This is first translated, then arguments are substituted (which are not constant)
/// when it needs to be displayed. /// when it needs to be displayed.
TranslationKey(&'static str), TranslationKey(&'static str, &'static str),
/// Directly shows up to the user without any translation done. /// Directly shows up to the user without any translation done.
Literal(&'static str), Literal(&'static str),
@ -89,14 +144,21 @@ pub enum TemplateText {
/// - `CommandErrorType<N>` = `DynamicNCommandExceptionType` /// - `CommandErrorType<N>` = `DynamicNCommandExceptionType`
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct CommandErrorType<const N: usize> { pub struct CommandErrorType<const N: usize> {
pub translation_key: &'static str, pub java_translation_key: &'static str,
pub bedrock_translation_key: &'static str,
} }
impl<const N: usize> CommandErrorType<N> { impl<const N: usize> CommandErrorType<N> {
/// Creates an error type from a given translation string. /// Creates an error type from a given translation string.
#[must_use] #[must_use]
pub const fn new(translation_key: &'static str) -> Self { pub const fn new(
Self { translation_key } java_translation_key: &'static str,
bedrock_translation_key: &'static str,
) -> Self {
Self {
java_translation_key,
bedrock_translation_key,
}
} }
/// Creates an error without context from itself and from a slice of `N` arguments. /// Creates an error without context from itself and from a slice of `N` arguments.
@ -107,7 +169,11 @@ impl<const N: usize> CommandErrorType<N> {
) -> CommandSyntaxError { ) -> CommandSyntaxError {
CommandSyntaxError::create_without_context( CommandSyntaxError::create_without_context(
self, self,
TextComponent::translate(self.translation_key, args), TextComponent::translate_cross(
self.java_translation_key,
self.bedrock_translation_key,
args.to_vec(),
),
) )
} }
@ -122,7 +188,11 @@ impl<const N: usize> CommandErrorType<N> {
{ {
CommandSyntaxError::create( CommandSyntaxError::create(
self, self,
TextComponent::translate(self.translation_key, args), TextComponent::translate_cross(
self.java_translation_key,
self.bedrock_translation_key,
args.to_vec(),
),
context_provider, context_provider,
) )
} }
@ -206,7 +276,7 @@ impl<T: AnyCommandErrorType> PartialEq<T> for dyn AnyCommandErrorType {
impl<const N: usize> Sealed for CommandErrorType<N> {} impl<const N: usize> Sealed for CommandErrorType<N> {}
impl<const N: usize> AnyCommandErrorType for CommandErrorType<N> { impl<const N: usize> AnyCommandErrorType for CommandErrorType<N> {
fn text(&self) -> TemplateText { fn text(&self) -> TemplateText {
TemplateText::TranslationKey(self.translation_key) TemplateText::TranslationKey(self.java_translation_key, self.bedrock_translation_key)
} }
fn argument_count(&self) -> usize { fn argument_count(&self) -> usize {
@ -281,7 +351,7 @@ mod test {
const TEST_LITERAL_ERROR_TYPE: LiteralCommandErrorType = const TEST_LITERAL_ERROR_TYPE: LiteralCommandErrorType =
LiteralCommandErrorType::new("Test error"); LiteralCommandErrorType::new("Test error");
const TEST_TRANSLATABLE_ERROR_TYPE: CommandErrorType<1> = const TEST_TRANSLATABLE_ERROR_TYPE: CommandErrorType<1> =
CommandErrorType::new("this.key.is.arbitrary"); CommandErrorType::new("this.key.is.arbitrary", "this.key.is.arbitrary");
#[test] #[test]
fn create_literal_error() { fn create_literal_error() {
@ -322,7 +392,8 @@ mod test {
assert_eq!(error.error_type, &TEST_TRANSLATABLE_ERROR_TYPE); assert_eq!(error.error_type, &TEST_TRANSLATABLE_ERROR_TYPE);
assert_eq!( assert_eq!(
error.message, error.message,
TextComponent::translate( TextComponent::translate_cross(
"this.key.is.arbitrary",
"this.key.is.arbitrary", "this.key.is.arbitrary",
[TextComponent::text("some argument")] [TextComponent::text("some argument")]
) )

View File

@ -16,7 +16,7 @@ use crate::command::string_reader::StringReader;
use crate::command::suggestion::suggestions::{Suggestions, SuggestionsBuilder}; use crate::command::suggestion::suggestions::{Suggestions, SuggestionsBuilder};
use crate::command::tree::Command; use crate::command::tree::Command;
use futures::future; use futures::future;
use pumpkin_data::translation::COMMAND_CONTEXT_HERE; use pumpkin_data::translation::java::COMMAND_CONTEXT_HERE;
use pumpkin_protocol::java::client::play::CommandSuggestion; use pumpkin_protocol::java::client::play::CommandSuggestion;
use pumpkin_util::text::TextComponent; use pumpkin_util::text::TextComponent;
use pumpkin_util::text::click::ClickEvent; use pumpkin_util::text::click::ClickEvent;
@ -440,7 +440,7 @@ impl CommandDispatcher {
} }
error_text = error_text.add_child( error_text = error_text.add_child(
TextComponent::translate(COMMAND_CONTEXT_HERE, &[]) TextComponent::translate_cross(COMMAND_CONTEXT_HERE, COMMAND_CONTEXT_HERE, &[])
.color(Color::Named(NamedColor::Red)) .color(Color::Named(NamedColor::Red))
.italic(), .italic(),
); );

View File

@ -1243,7 +1243,8 @@ impl LivingEntity {
if let Some(cause) = cause if let Some(cause) = cause
&& source.is_some() && source.is_some()
{ {
TextComponent::translate( TextComponent::translate_cross(
format!("death.attack.{}.player", damage_type.message_id),
format!("death.attack.{}.player", damage_type.message_id), format!("death.attack.{}.player", damage_type.message_id),
[ [
dyn_self.get_display_name().await, dyn_self.get_display_name().await,
@ -1251,7 +1252,8 @@ impl LivingEntity {
], ],
) )
} else { } else {
TextComponent::translate( TextComponent::translate_cross(
format!("death.attack.{}", damage_type.message_id),
format!("death.attack.{}", damage_type.message_id), format!("death.attack.{}", damage_type.message_id),
[dyn_self.get_display_name().await], [dyn_self.get_display_name().await],
) )
@ -1259,13 +1261,15 @@ impl LivingEntity {
} }
DeathMessageType::FallVariants => { DeathMessageType::FallVariants => {
//TODO //TODO
TextComponent::translate( TextComponent::translate_cross(
translation::DEATH_FELL_ACCIDENT_GENERIC, translation::java::DEATH_FELL_ACCIDENT_GENERIC,
translation::bedrock::DEATH_FELL_ACCIDENT_GENERIC,
[dyn_self.get_display_name().await], [dyn_self.get_display_name().await],
) )
} }
DeathMessageType::IntentionalGameDesign => TextComponent::text("[") DeathMessageType::IntentionalGameDesign => TextComponent::text("[")
.add_child(TextComponent::translate( .add_child(TextComponent::translate_cross(
format!("death.attack.{}.message", damage_type.message_id),
format!("death.attack.{}.message", damage_type.message_id), format!("death.attack.{}.message", damage_type.message_id),
[dyn_self.get_display_name().await], [dyn_self.get_display_name().await],
)) ))

View File

@ -321,7 +321,8 @@ pub trait EntityBase: Send + Sync + NBTStorage + std::any::Any {
.load() .load()
.as_ref() .as_ref()
.clone() .clone()
.unwrap_or(TextComponent::translate( .unwrap_or(TextComponent::translate_cross(
format!("entity.minecraft.{}", entity.entity_type.resource_name),
format!("entity.minecraft.{}", entity.entity_type.resource_name), format!("entity.minecraft.{}", entity.entity_type.resource_name),
[], [],
)) ))
@ -331,16 +332,13 @@ pub trait EntityBase: Send + Sync + NBTStorage + std::any::Any {
Box::pin(async move { Box::pin(async move {
// TODO: team color // TODO: team color
let entity = self.get_entity(); let entity = self.get_entity();
let mut name = let mut name = entity.custom_name.load().as_ref().clone().unwrap_or(
entity TextComponent::translate_cross(
.custom_name format!("entity.minecraft.{}", entity.entity_type.resource_name),
.load() format!("entity.minecraft.{}", entity.entity_type.resource_name),
.as_ref() [],
.clone() ),
.unwrap_or(TextComponent::translate( );
format!("entity.minecraft.{}", entity.entity_type.resource_name),
[],
));
let name_clone = name.clone(); let name_clone = name.clone();
name = name.hover_event(HoverEvent::show_entity( name = name.hover_event(HoverEvent::show_entity(
entity.entity_uuid.to_string(), entity.entity_uuid.to_string(),
@ -2247,7 +2245,7 @@ impl Entity {
} else { } else {
self.bedrock_flags_two.fetch_and(mask, Ordering::Relaxed); self.bedrock_flags_two.fetch_and(mask, Ordering::Relaxed);
} }
}; }
let world = self.world.load(); let world = self.world.load();
let chunk_pos = self.chunk_pos.load(); let chunk_pos = self.chunk_pos.load();
@ -2983,6 +2981,7 @@ pub enum Flag {
} }
impl Flag { impl Flag {
#[must_use]
pub const fn to_bedrock(&self) -> Option<u32> { pub const fn to_bedrock(&self) -> Option<u32> {
match self { match self {
Self::OnFire => Some(entity_data_flag::ON_FIRE), Self::OnFire => Some(entity_data_flag::ON_FIRE),

View File

@ -1774,7 +1774,11 @@ impl Player {
if idle_duration >= Duration::from_secs(idle_timeout_minutes as u64 * 60) { if idle_duration >= Duration::from_secs(idle_timeout_minutes as u64 * 60) {
self.kick( self.kick(
DisconnectReason::KickedForIdle, DisconnectReason::KickedForIdle,
TextComponent::translate(translation::MULTIPLAYER_DISCONNECT_IDLING, []), TextComponent::translate_cross(
translation::java::MULTIPLAYER_DISCONNECT_IDLING,
translation::java::MULTIPLAYER_DISCONNECT_IDLING,
[],
),
) )
.await; .await;
return; return;
@ -1790,7 +1794,11 @@ impl Player {
if self.wait_for_keep_alive.load(Ordering::Relaxed) { if self.wait_for_keep_alive.load(Ordering::Relaxed) {
self.kick( self.kick(
DisconnectReason::Timeout, DisconnectReason::Timeout,
TextComponent::translate(translation::DISCONNECT_TIMEOUT, []), TextComponent::translate_cross(
translation::java::DISCONNECT_TIMEOUT,
translation::bedrock::DISCONNECT_TIMEOUT,
[],
),
) )
.await; .await;
return; return;
@ -2363,7 +2371,11 @@ impl Player {
drop(banned_players); drop(banned_players);
let kick_reason = reason.unwrap_or_else(|| { let kick_reason = reason.unwrap_or_else(|| {
TextComponent::translate(translation::MULTIPLAYER_DISCONNECT_BANNED, []) TextComponent::translate_cross(
translation::java::MULTIPLAYER_DISCONNECT_BANNED,
translation::bedrock::DISCONNECTIONSCREEN_TITLE_BANNEDBYHOST,
[],
)
}); });
self.kick(DisconnectReason::Kicked, kick_reason).await; self.kick(DisconnectReason::Kicked, kick_reason).await;
@ -2394,7 +2406,11 @@ impl Player {
drop(banned_ips); drop(banned_ips);
let kick_reason = reason.unwrap_or_else(|| { let kick_reason = reason.unwrap_or_else(|| {
TextComponent::translate(translation::MULTIPLAYER_DISCONNECT_IP_BANNED, []) TextComponent::translate_cross(
translation::java::MULTIPLAYER_DISCONNECT_IP_BANNED,
translation::java::MULTIPLAYER_DISCONNECT_IP_BANNED,
[],
)
}); });
let affected = server.get_players_by_ip(target_ip).await; let affected = server.get_players_by_ip(target_ip).await;

View File

@ -155,7 +155,7 @@ impl BedrockClient {
let real_name = player_data.display_name; let real_name = player_data.display_name;
// IMPORTANT: Bedrock allows spaces in names. While we could support this, it would significantly complicate parsing player arguments in commands, so we don't // IMPORTANT: Bedrock allows spaces in names. While we could support this, it would significantly complicate parsing player arguments in commands, so we don't
let under_score_name = real_name.replace(" ", "_"); let under_score_name = real_name.replace(' ', "_");
let profile = GameProfile { let profile = GameProfile {
id: Uuid::parse_str(&player_data.uuid).map_err(|_| LoginError::InvalidUuid)?, id: Uuid::parse_str(&player_data.uuid).map_err(|_| LoginError::InvalidUuid)?,

View File

@ -721,8 +721,7 @@ impl BedrockClient {
.await; .await;
} }
SAnimate::PACKET_ID => { SAnimate::PACKET_ID => {
self.handle_animate(player, server, SAnimate::read(reader)?) self.handle_animate(player, server, &SAnimate::read(reader)?);
.await;
} }
SLoadingScreen::PACKET_ID => { SLoadingScreen::PACKET_ID => {
// Ignore for now // Ignore for now

View File

@ -6,11 +6,7 @@ use std::{
use pumpkin_macros::send_cancellable; use pumpkin_macros::send_cancellable;
use pumpkin_protocol::{ use pumpkin_protocol::{
bedrock::{ bedrock::{
client::{ client::{chunk_radius_update::CChunkRadiusUpdate, container_open::CContainerOpen},
chunk_radius_update::CChunkRadiusUpdate,
container_open::CContainerOpen,
level_event::{CLevelEvent, LevelEvent},
},
server::{ server::{
animate::{AnimateAction, SAnimate}, animate::{AnimateAction, SAnimate},
command_request::SCommandRequest, command_request::SCommandRequest,
@ -23,14 +19,10 @@ use pumpkin_protocol::{
text::SText, text::SText,
}, },
}, },
codec::{var_int::VarInt, var_long::VarLong, var_ulong::VarULong}, codec::{var_int::VarInt, var_long::VarLong},
java::client::play::{Animation, CEntityAnimation, CSetBlockDestroyStage, CSystemChatMessage}, java::client::play::{Animation, CSystemChatMessage},
};
use pumpkin_util::{
GameMode,
math::{position::BlockPos, vector3::Vector3},
text::TextComponent,
}; };
use pumpkin_util::{GameMode, math::position::BlockPos, text::TextComponent};
use pumpkin_world::world::BlockFlags; use pumpkin_world::world::BlockFlags;
@ -197,16 +189,16 @@ impl BedrockClient {
.await; .await;
} }
pub async fn handle_animate(&self, player: &Arc<Player>, _server: &Server, packet: SAnimate) { pub fn handle_animate(&self, player: &Arc<Player>, _server: &Server, packet: &SAnimate) {
if !player.has_client_loaded() { if !player.has_client_loaded() {
return; return;
} }
let entity = &player.living_entity.entity; let entity = &player.living_entity.entity;
let world = entity.world.load(); let _world = entity.world.load();
// Broadcast the animation to other players // Broadcast the animation to other players
let java_animation = match packet.action { let _java_animation = match packet.action {
AnimateAction::SwingArm => Some(Animation::SwingMainArm), AnimateAction::SwingArm => Some(Animation::SwingMainArm),
AnimateAction::WakeUp => Some(Animation::LeaveBed), AnimateAction::WakeUp => Some(Animation::LeaveBed),
AnimateAction::CriticalHit => Some(Animation::CriticalEffect), AnimateAction::CriticalHit => Some(Animation::CriticalEffect),
@ -291,6 +283,7 @@ impl BedrockClient {
}} }}
} }
#[expect(clippy::match_same_arms)]
pub async fn handle_player_action( pub async fn handle_player_action(
&self, &self,
player: &Arc<Player>, player: &Arc<Player>,

View File

@ -19,14 +19,16 @@ impl JavaClient {
if self.connection_state.load() != ConnectionState::Status { if self.connection_state.load() != ConnectionState::Status {
let protocol = version; let protocol = version;
if protocol < LOWEST_SUPPORTED_MC_VERSION.protocol_version() as u32 { if protocol < LOWEST_SUPPORTED_MC_VERSION.protocol_version() as u32 {
self.kick(TextComponent::translate( self.kick(TextComponent::translate_cross(
translation::MULTIPLAYER_DISCONNECT_OUTDATED_CLIENT, translation::java::MULTIPLAYER_DISCONNECT_OUTDATED_CLIENT,
translation::java::MULTIPLAYER_DISCONNECT_OUTDATED_CLIENT,
[TextComponent::text(CURRENT_MC_VERSION.to_string())], [TextComponent::text(CURRENT_MC_VERSION.to_string())],
)) ))
.await; .await;
} else if protocol > CURRENT_MC_VERSION.protocol_version() as u32 { } else if protocol > CURRENT_MC_VERSION.protocol_version() as u32 {
self.kick(TextComponent::translate( self.kick(TextComponent::translate_cross(
translation::MULTIPLAYER_DISCONNECT_OUTDATED_SERVER, translation::java::MULTIPLAYER_DISCONNECT_OUTDATED_SERVER,
translation::java::MULTIPLAYER_DISCONNECT_OUTDATED_SERVER,
[TextComponent::text(CURRENT_MC_VERSION.to_string())], [TextComponent::text(CURRENT_MC_VERSION.to_string())],
)) ))
.await; .await;

View File

@ -34,8 +34,9 @@ impl JavaClient {
// TODO: If client is an operator or has otherwise suitable elevated permissions, allow the client to bypass this requirement. // TODO: If client is an operator or has otherwise suitable elevated permissions, allow the client to bypass this requirement.
let max_players = server.basic_config.max_players; let max_players = server.basic_config.max_players;
if max_players > 0 && server.get_player_count() >= max_players as usize { if max_players > 0 && server.get_player_count() >= max_players as usize {
self.kick(TextComponent::translate( self.kick(TextComponent::translate_cross(
translation::MULTIPLAYER_DISCONNECT_SERVER_FULL, translation::java::MULTIPLAYER_DISCONNECT_SERVER_FULL,
translation::java::MULTIPLAYER_DISCONNECT_SERVER_FULL,
[], [],
)) ))
.await; .await;
@ -137,12 +138,14 @@ impl JavaClient {
Ok(new_profile) => *profile = new_profile, Ok(new_profile) => *profile = new_profile,
Err(error) => { Err(error) => {
self.kick(match error { self.kick(match error {
AuthError::FailedResponse => TextComponent::translate( AuthError::FailedResponse => TextComponent::translate_cross(
translation::MULTIPLAYER_DISCONNECT_AUTHSERVERS_DOWN, translation::java::MULTIPLAYER_DISCONNECT_AUTHSERVERS_DOWN,
translation::java::MULTIPLAYER_DISCONNECT_AUTHSERVERS_DOWN,
[], [],
), ),
AuthError::UnverifiedUsername => TextComponent::translate( AuthError::UnverifiedUsername => TextComponent::translate_cross(
translation::MULTIPLAYER_DISCONNECT_UNVERIFIED_USERNAME, translation::java::MULTIPLAYER_DISCONNECT_UNVERIFIED_USERNAME,
translation::java::MULTIPLAYER_DISCONNECT_UNVERIFIED_USERNAME,
[], [],
), ),
e => TextComponent::text(e.to_string()), e => TextComponent::text(e.to_string()),
@ -161,8 +164,9 @@ impl JavaClient {
&profile.id, &profile.id,
&online_player.gameprofile.name &online_player.gameprofile.name
); );
self.kick(TextComponent::translate( self.kick(TextComponent::translate_cross(
translation::MULTIPLAYER_DISCONNECT_DUPLICATE_LOGIN, translation::java::MULTIPLAYER_DISCONNECT_DUPLICATE_LOGIN,
translation::java::MULTIPLAYER_DISCONNECT_DUPLICATE_LOGIN,
[], [],
)) ))
.await; .await;
@ -178,8 +182,9 @@ impl JavaClient {
&profile.id, &profile.id,
&online_player.gameprofile.name &online_player.gameprofile.name
); );
self.kick(TextComponent::translate( self.kick(TextComponent::translate_cross(
translation::MULTIPLAYER_DISCONNECT_DUPLICATE_LOGIN, translation::java::MULTIPLAYER_DISCONNECT_DUPLICATE_LOGIN,
translation::java::MULTIPLAYER_DISCONNECT_DUPLICATE_LOGIN,
[], [],
)) ))
.await; .await;

View File

@ -152,44 +152,57 @@ impl PumpkinError for ChatError {
match self { match self {
Self::OversizedMessage => Some("Chat message too long".into()), Self::OversizedMessage => Some("Chat message too long".into()),
Self::IllegalCharacters => Some( Self::IllegalCharacters => Some(
TextComponent::translate( TextComponent::translate_cross(
translation::MULTIPLAYER_DISCONNECT_ILLEGAL_CHARACTERS, translation::java::MULTIPLAYER_DISCONNECT_ILLEGAL_CHARACTERS,
translation::java::MULTIPLAYER_DISCONNECT_ILLEGAL_CHARACTERS,
[], [],
) )
.get_text(), .get_text(),
), ),
Self::UnsignedChat => Some( Self::UnsignedChat => Some(
TextComponent::translate(translation::MULTIPLAYER_DISCONNECT_UNSIGNED_CHAT, []) TextComponent::translate_cross(
.get_text(), translation::java::MULTIPLAYER_DISCONNECT_UNSIGNED_CHAT,
translation::java::MULTIPLAYER_DISCONNECT_UNSIGNED_CHAT,
[],
)
.get_text(),
), ),
Self::TooManyPendingChats => Some( Self::TooManyPendingChats => Some(
TextComponent::translate( TextComponent::translate_cross(
translation::MULTIPLAYER_DISCONNECT_TOO_MANY_PENDING_CHATS, translation::java::MULTIPLAYER_DISCONNECT_TOO_MANY_PENDING_CHATS,
translation::java::MULTIPLAYER_DISCONNECT_TOO_MANY_PENDING_CHATS,
[], [],
) )
.get_text(), .get_text(),
), ),
Self::ChatValidationFailed => Some( Self::ChatValidationFailed => Some(
TextComponent::translate( TextComponent::translate_cross(
translation::MULTIPLAYER_DISCONNECT_CHAT_VALIDATION_FAILED, translation::java::MULTIPLAYER_DISCONNECT_CHAT_VALIDATION_FAILED,
translation::java::MULTIPLAYER_DISCONNECT_CHAT_VALIDATION_FAILED,
[], [],
) )
.get_text(), .get_text(),
), ),
Self::OutOfOrderChat => Some( Self::OutOfOrderChat => Some(
TextComponent::translate(translation::MULTIPLAYER_DISCONNECT_OUT_OF_ORDER_CHAT, []) TextComponent::translate_cross(
.get_text(), translation::java::MULTIPLAYER_DISCONNECT_OUT_OF_ORDER_CHAT,
translation::java::MULTIPLAYER_DISCONNECT_OUT_OF_ORDER_CHAT,
[],
)
.get_text(),
), ),
Self::ExpiredPublicKey => Some( Self::ExpiredPublicKey => Some(
TextComponent::translate( TextComponent::translate_cross(
translation::MULTIPLAYER_DISCONNECT_EXPIRED_PUBLIC_KEY, translation::java::MULTIPLAYER_DISCONNECT_EXPIRED_PUBLIC_KEY,
translation::java::MULTIPLAYER_DISCONNECT_EXPIRED_PUBLIC_KEY,
[], [],
) )
.get_text(), .get_text(),
), ),
Self::InvalidPublicKey => Some( Self::InvalidPublicKey => Some(
TextComponent::translate( TextComponent::translate_cross(
translation::MULTIPLAYER_DISCONNECT_INVALID_PUBLIC_KEY_SIGNATURE, translation::java::MULTIPLAYER_DISCONNECT_INVALID_PUBLIC_KEY_SIGNATURE,
translation::java::MULTIPLAYER_DISCONNECT_INVALID_PUBLIC_KEY_SIGNATURE,
[], [],
) )
.get_text(), .get_text(),
@ -240,9 +253,14 @@ impl JavaClient {
change_game_mode.game_mode.to_str().to_lowercase() change_game_mode.game_mode.to_str().to_lowercase()
); );
player player
.send_system_message(&TextComponent::translate( .send_system_message(&TextComponent::translate_cross(
translation::COMMANDS_GAMEMODE_SUCCESS_SELF, translation::java::COMMANDS_GAMEMODE_SUCCESS_SELF,
[TextComponent::translate(gamemode_string, [])], translation::bedrock::COMMANDS_GAMEMODE_SUCCESS_SELF,
[TextComponent::translate_cross(
gamemode_string.clone(),
gamemode_string,
[],
)],
)) ))
.await; .await;
} }
@ -312,8 +330,9 @@ impl JavaClient {
// y = feet Y // y = feet Y
let position = packet.position; let position = packet.position;
if position.x.is_nan() || position.y.is_nan() || position.z.is_nan() { if position.x.is_nan() || position.y.is_nan() || position.z.is_nan() {
self.kick(TextComponent::translate( self.kick(TextComponent::translate_cross(
translation::MULTIPLAYER_DISCONNECT_INVALID_PLAYER_MOVEMENT, translation::java::MULTIPLAYER_DISCONNECT_INVALID_PLAYER_MOVEMENT,
translation::java::MULTIPLAYER_DISCONNECT_INVALID_PLAYER_MOVEMENT,
[], [],
)) ))
.await; .await;
@ -426,8 +445,9 @@ impl JavaClient {
|| !packet.yaw.is_finite() || !packet.yaw.is_finite()
|| !packet.pitch.is_finite() || !packet.pitch.is_finite()
{ {
self.kick(TextComponent::translate( self.kick(TextComponent::translate_cross(
translation::MULTIPLAYER_DISCONNECT_INVALID_PLAYER_MOVEMENT, translation::java::MULTIPLAYER_DISCONNECT_INVALID_PLAYER_MOVEMENT,
translation::java::MULTIPLAYER_DISCONNECT_INVALID_PLAYER_MOVEMENT,
[], [],
)) ))
.await; .await;
@ -556,8 +576,9 @@ impl JavaClient {
return; return;
} }
if !rotation.yaw.is_finite() || !rotation.pitch.is_finite() { if !rotation.yaw.is_finite() || !rotation.pitch.is_finite() {
self.kick(TextComponent::translate( self.kick(TextComponent::translate_cross(
translation::MULTIPLAYER_DISCONNECT_INVALID_PLAYER_MOVEMENT, translation::java::MULTIPLAYER_DISCONNECT_INVALID_PLAYER_MOVEMENT,
translation::java::MULTIPLAYER_DISCONNECT_INVALID_PLAYER_MOVEMENT,
[], [],
)) ))
.await; .await;
@ -1595,8 +1616,9 @@ impl JavaClient {
} }
if entity_id.0 == player.entity_id() { if entity_id.0 == player.entity_id() {
self.kick(TextComponent::translate( self.kick(TextComponent::translate_cross(
translation::MULTIPLAYER_DISCONNECT_INVALID_ENTITY_ATTACKED, translation::java::MULTIPLAYER_DISCONNECT_INVALID_ENTITY_ATTACKED,
translation::java::MULTIPLAYER_DISCONNECT_INVALID_ENTITY_ATTACKED,
[], [],
)) ))
.await; .await;
@ -1609,8 +1631,9 @@ impl JavaClient {
.map(|p| Arc::clone(p) as Arc<dyn EntityBase>) .map(|p| Arc::clone(p) as Arc<dyn EntityBase>)
.or_else(|| world.get_entity_by_id(entity_id.0)); .or_else(|| world.get_entity_by_id(entity_id.0));
let Some(target) = target else { let Some(target) = target else {
self.kick(TextComponent::translate( self.kick(TextComponent::translate_cross(
translation::MULTIPLAYER_DISCONNECT_INVALID_ENTITY_ATTACKED, translation::java::MULTIPLAYER_DISCONNECT_INVALID_ENTITY_ATTACKED,
translation::java::MULTIPLAYER_DISCONNECT_INVALID_ENTITY_ATTACKED,
[], [],
)) ))
.await; .await;
@ -1684,10 +1707,7 @@ impl JavaClient {
} }
if entity_id.0 == player.entity_id() { if entity_id.0 == player.entity_id() {
self.kick(TextComponent::translate( self.kick(TextComponent::translate_cross(translation::java::MULTIPLAYER_DISCONNECT_INVALID_ENTITY_ATTACKED, translation::java::MULTIPLAYER_DISCONNECT_INVALID_ENTITY_ATTACKED, [],))
translation::MULTIPLAYER_DISCONNECT_INVALID_ENTITY_ATTACKED,
[],
))
.await; .await;
return; return;
} }
@ -1737,10 +1757,7 @@ impl JavaClient {
player.entity_id(), player.entity_id(),
event.entity_id event.entity_id
); );
self.kick(TextComponent::translate( self.kick(TextComponent::translate_cross(translation::java::MULTIPLAYER_DISCONNECT_INVALID_ENTITY_ATTACKED, translation::java::MULTIPLAYER_DISCONNECT_INVALID_ENTITY_ATTACKED, [],))
translation::MULTIPLAYER_DISCONNECT_INVALID_ENTITY_ATTACKED,
[],
))
.await; .await;
} }
} }
@ -2619,8 +2636,9 @@ impl JavaClient {
if location.0.y + face.to_offset().y > world.get_top_y() { if location.0.y + face.to_offset().y > world.get_top_y() {
player player
.send_system_message_raw( .send_system_message_raw(
&TextComponent::translate( &TextComponent::translate_cross(
translation::BUILD_TOOHIGH, translation::java::BUILD_TOOHIGH,
translation::bedrock::BUILD_TOOHIGH,
vec![TextComponent::text((world.get_top_y()).to_string())], vec![TextComponent::text((world.get_top_y()).to_string())],
) )
.color_named(NamedColor::Red), .color_named(NamedColor::Red),

View File

@ -177,13 +177,15 @@ pub async fn can_not_join(
let mut banned_players = server.data.banned_player_list.write().await; let mut banned_players = server.data.banned_player_list.write().await;
if let Some(entry) = banned_players.get_entry(profile) { if let Some(entry) = banned_players.get_entry(profile) {
let text = TextComponent::translate( let text = TextComponent::translate_cross(
translation::MULTIPLAYER_DISCONNECT_BANNED_REASON, translation::java::MULTIPLAYER_DISCONNECT_BANNED_REASON,
translation::java::MULTIPLAYER_DISCONNECT_BANNED_REASON,
[TextComponent::text(entry.reason.clone())], [TextComponent::text(entry.reason.clone())],
); );
return Some(match entry.expires { return Some(match entry.expires {
Some(expires) => text.add_child(TextComponent::translate( Some(expires) => text.add_child(TextComponent::translate_cross(
translation::MULTIPLAYER_DISCONNECT_BANNED_EXPIRATION, translation::java::MULTIPLAYER_DISCONNECT_BANNED_EXPIRATION,
translation::java::MULTIPLAYER_DISCONNECT_BANNED_EXPIRATION,
[TextComponent::text( [TextComponent::text(
expires.format(FORMAT_DESCRIPTION).unwrap(), expires.format(FORMAT_DESCRIPTION).unwrap(),
)], )],
@ -198,8 +200,9 @@ pub async fn can_not_join(
let whitelist = server.data.whitelist_config.read().await; let whitelist = server.data.whitelist_config.read().await;
if ops.get_entry(&profile.id).is_none() && !whitelist.is_whitelisted(profile) { if ops.get_entry(&profile.id).is_none() && !whitelist.is_whitelisted(profile) {
return Some(TextComponent::translate( return Some(TextComponent::translate_cross(
translation::MULTIPLAYER_DISCONNECT_NOT_WHITELISTED, translation::java::MULTIPLAYER_DISCONNECT_NOT_WHITELISTED,
translation::java::MULTIPLAYER_DISCONNECT_NOT_WHITELISTED,
&[], &[],
)); ));
} }
@ -212,13 +215,15 @@ pub async fn can_not_join(
.await .await
.get_entry(&address.ip()) .get_entry(&address.ip())
{ {
let text = TextComponent::translate( let text = TextComponent::translate_cross(
translation::MULTIPLAYER_DISCONNECT_BANNED_IP_REASON, translation::java::MULTIPLAYER_DISCONNECT_BANNED_IP_REASON,
translation::java::MULTIPLAYER_DISCONNECT_BANNED_IP_REASON,
[TextComponent::text(entry.reason.clone())], [TextComponent::text(entry.reason.clone())],
); );
return Some(match entry.expires { return Some(match entry.expires {
Some(expires) => text.add_child(TextComponent::translate( Some(expires) => text.add_child(TextComponent::translate_cross(
translation::MULTIPLAYER_DISCONNECT_BANNED_IP_EXPIRATION, translation::java::MULTIPLAYER_DISCONNECT_BANNED_IP_EXPIRATION,
translation::java::MULTIPLAYER_DISCONNECT_BANNED_IP_EXPIRATION,
[TextComponent::text( [TextComponent::text(
expires.format(FORMAT_DESCRIPTION).unwrap(), expires.format(FORMAT_DESCRIPTION).unwrap(),
)], )],

View File

@ -160,8 +160,9 @@ impl ServerTickRateManager {
let tps = (total_sprinted_ticks as f64 * 1000.0) / time_spent_ms; let tps = (total_sprinted_ticks as f64 * 1000.0) / time_spent_ms;
let mspt = time_spent_ms / total_sprinted_ticks as f64; let mspt = time_spent_ms / total_sprinted_ticks as f64;
TextComponent::translate( TextComponent::translate_cross(
translation::COMMANDS_TICK_SPRINT_REPORT, translation::java::COMMANDS_TICK_SPRINT_REPORT,
translation::java::COMMANDS_TICK_SPRINT_REPORT,
[ [
TextComponent::text(format!("{tps:.2}")), TextComponent::text(format!("{tps:.2}")),
TextComponent::text(format!("{mspt:.2}")), TextComponent::text(format!("{mspt:.2}")),
@ -169,7 +170,11 @@ impl ServerTickRateManager {
) )
} else { } else {
// This is the message for `/tick sprint stop` or a zero-tick sprint. // This is the message for `/tick sprint stop` or a zero-tick sprint.
TextComponent::translate(translation::COMMANDS_TICK_SPRINT_STOP_SUCCESS, []) TextComponent::translate_cross(
translation::java::COMMANDS_TICK_SPRINT_STOP_SUCCESS,
translation::java::COMMANDS_TICK_SPRINT_STOP_SUCCESS,
[],
)
}; };
// Construct the final component with the [Server: ...] wrapper // Construct the final component with the [Server: ...] wrapper

View File

@ -622,7 +622,11 @@ impl DragonFight {
fn make_bossbar(&self) -> Bossbar { fn make_bossbar(&self) -> Bossbar {
Bossbar { Bossbar {
uuid: self.bossbar_uuid, uuid: self.bossbar_uuid,
title: TextComponent::translate("entity.minecraft.ender_dragon", []), title: TextComponent::translate_cross(
"entity.minecraft.ender_dragon",
"entity.minecraft.ender_dragon",
[],
),
health: 1.0, health: 1.0,
color: BossbarColor::Pink, color: BossbarColor::Pink,
division: BossbarDivisions::NoDivision, division: BossbarDivisions::NoDivision,

Some files were not shown because too many files have changed in this diff Show More