chore: parse translations at compile time

not finished but its much safer and nicer now
This commit is contained in:
Alexander Medvedev
2026-02-08 13:22:36 +01:00
parent abe01f3019
commit e45ab613f4
47 changed files with 339 additions and 193 deletions

79
Cargo.lock generated
View File

@@ -401,7 +401,7 @@ version = "3.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34"
dependencies = [
"windows-sys 0.52.0",
"windows-sys 0.61.2",
]
[[package]]
@@ -501,6 +501,12 @@ dependencies = [
"url",
]
[[package]]
name = "cpubits"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ef0c543070d296ea414df2dd7625d1b24866ce206709d8a4a424f28377f5861"
[[package]]
name = "cpufeatures"
version = "0.2.17"
@@ -651,10 +657,11 @@ dependencies = [
[[package]]
name = "crypto-bigint"
version = "0.7.0-rc.22"
version = "0.7.0-rc.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "053c3561863ce55e3226ecc48b08679f4b66cb1b92b9afb42c2c402dfe8b9b51"
checksum = "cba9eeeb213f7fd29353032f71f7c173e5f6d95d85151cb3a47197b0ea7e8be7"
dependencies = [
"cpubits",
"ctutils",
"num-traits",
"rand_core 0.10.0",
@@ -674,9 +681,9 @@ dependencies = [
[[package]]
name = "crypto-common"
version = "0.2.0-rc.13"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7722afd27468475c9b6063dc03a57ef2ca833816981619f8ebe64d38d207eef"
checksum = "211f05e03c7d03754740fd9e585de910a095d6b99f8bcfffdef8319fa02a8331"
dependencies = [
"hybrid-array",
]
@@ -687,7 +694,7 @@ version = "0.7.0-pre.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "334a79c97c0b7fa536716dc132fd417d0afbf471440a41fc25a5d9f66d8771cd"
dependencies = [
"crypto-bigint 0.7.0-rc.22",
"crypto-bigint 0.7.0-rc.25",
"libm",
"rand_core 0.10.0",
]
@@ -760,13 +767,13 @@ dependencies = [
[[package]]
name = "digest"
version = "0.11.0-rc.9"
version = "0.11.0-rc.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bff8de092798697546237a3a701e4174fe021579faec9b854379af9bf1e31962"
checksum = "02b42f1d9edf5207c137646b568a0168ca0ec25b7f9eaf7f9961da51a3d91cea"
dependencies = [
"block-buffer 0.11.0",
"const-oid 0.10.2",
"crypto-common 0.2.0-rc.13",
"crypto-common 0.2.0",
"subtle",
]
@@ -885,7 +892,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
"windows-sys 0.52.0",
"windows-sys 0.61.2",
]
[[package]]
@@ -1202,11 +1209,11 @@ dependencies = [
[[package]]
name = "hmac"
version = "0.13.0-rc.4"
version = "0.13.0-rc.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9956e202a691c5c86c60303a421f66f93f44b29433407b7c43cf2bebadc750e"
checksum = "ef451d73f36d8a3f93ad32c332ea01146c9650e1ec821a9b0e46c01277d544f8"
dependencies = [
"digest 0.11.0-rc.9",
"digest 0.11.0-rc.11",
]
[[package]]
@@ -1271,9 +1278,9 @@ checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424"
[[package]]
name = "hybrid-array"
version = "0.4.6"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b41fb3dc24fe72c2e3a4685eed55917c2fb228851257f4a8f2d985da9443c3e5"
checksum = "e1b229d73f5803b562cc26e4da0396c8610a4ee209f4fac8fa4f8d709166dc45"
dependencies = [
"typenum",
]
@@ -1718,7 +1725,7 @@ version = "0.50.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
dependencies = [
"windows-sys 0.59.0",
"windows-sys 0.61.2",
]
[[package]]
@@ -2134,7 +2141,7 @@ dependencies = [
"crossbeam",
"flate2",
"futures",
"hmac 0.13.0-rc.4",
"hmac 0.13.0-rc.5",
"libloading",
"log",
"num-bigint",
@@ -2154,7 +2161,7 @@ dependencies = [
"serde",
"serde_json",
"sha1",
"sha2 0.11.0-rc.4",
"sha2 0.11.0-rc.5",
"tempfile",
"thiserror",
"time",
@@ -2319,7 +2326,7 @@ dependencies = [
"serde",
"serde_json",
"serde_json5",
"sha2 0.11.0-rc.4",
"sha2 0.11.0-rc.5",
"slotmap",
"temp-dir",
"thiserror",
@@ -2462,19 +2469,19 @@ dependencies = [
[[package]]
name = "rsa"
version = "0.10.0-rc.14"
version = "0.10.0-rc.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ef381dd6f207f81aff2ee3a8264eddd68ba475bbfcdb44ca445e5906bce381b"
checksum = "1b342b99544549f37509ed7fd42b0cea04bfd9ce07c16ca56094cf0fbeefbbcd"
dependencies = [
"const-oid 0.10.2",
"crypto-bigint 0.7.0-rc.22",
"crypto-bigint 0.7.0-rc.25",
"crypto-primes",
"digest 0.11.0-rc.9",
"digest 0.11.0-rc.11",
"pkcs1",
"pkcs8 0.11.0-rc.10",
"rand_core 0.10.0",
"sha1",
"signature 3.0.0-rc.9",
"signature 3.0.0-rc.10",
"spki 0.8.0-rc.4",
"zeroize",
]
@@ -2495,7 +2502,7 @@ dependencies = [
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.52.0",
"windows-sys 0.61.2",
]
[[package]]
@@ -2680,13 +2687,13 @@ dependencies = [
[[package]]
name = "sha1"
version = "0.11.0-rc.4"
version = "0.11.0-rc.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c777f0a122a53fddb0beb6e706771197000b8eb5c9f42b5b850f450ef48c788"
checksum = "3b167252f3c126be0d8926639c4c4706950f01445900c4b3db0fd7e89fcb750a"
dependencies = [
"cfg-if",
"cpufeatures",
"digest 0.11.0-rc.9",
"digest 0.11.0-rc.11",
]
[[package]]
@@ -2702,13 +2709,13 @@ dependencies = [
[[package]]
name = "sha2"
version = "0.11.0-rc.4"
version = "0.11.0-rc.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7535f94fa3339fe9e5e9be6260a909e62af97f6e14b32345ccf79b92b8b81233"
checksum = "7c5f3b1e2dc8aad28310d8410bd4d7e180eca65fca176c52ab00d364475d0024"
dependencies = [
"cfg-if",
"cpufeatures",
"digest 0.11.0-rc.9",
"digest 0.11.0-rc.11",
]
[[package]]
@@ -2748,11 +2755,11 @@ dependencies = [
[[package]]
name = "signature"
version = "3.0.0-rc.9"
version = "3.0.0-rc.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ad0ce3b3f8efd7406f22e2ca5d02be21cdf3b3d1d53ab141f784de8965c7c7e"
checksum = "7f1880df446116126965eeec169136b2e0251dba37c6223bcc819569550edea3"
dependencies = [
"digest 0.11.0-rc.9",
"digest 0.11.0-rc.11",
"rand_core 0.10.0",
]
@@ -2892,7 +2899,7 @@ dependencies = [
"fastrand",
"once_cell",
"rustix",
"windows-sys 0.52.0",
"windows-sys 0.61.2",
]
[[package]]
@@ -3504,7 +3511,7 @@ version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
dependencies = [
"windows-sys 0.52.0",
"windows-sys 0.61.2",
]
[[package]]

View File

@@ -125,7 +125,7 @@ enum_dispatch = "0.3.13"
env_logger = "0.11.8"
flate2 = "1.1.9"
heck = "0.5"
hmac = "=0.13.0-rc.4"
hmac = "=0.13.0-rc.5"
indexmap = "2.13"
itertools = "0.14.0"
libloading = "0.9"
@@ -150,13 +150,13 @@ pumpkin-util = { path = "pumpkin-util" }
pumpkin-world = { path = "pumpkin-world" }
quote = "1.0"
rand = { git = "https://github.com/rust-random/rand"}
rsa = "=0.10.0-rc.14"
rsa = "=0.10.0-rc.15"
rustc-hash = "2.1.1"
rustyline = "17.0.2"
ruzstd = "0.8.2"
serde_json5 = "0.2.1"
sha1 = "=0.11.0-rc.4"
sha2 = "=0.11.0-rc.4"
sha1 = "=0.11.0-rc.5"
sha2 = "=0.11.0-rc.5"
signature = "2.2.0"
tracing = "0.1.44"
tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt", "time"] }

View File

@@ -51,6 +51,7 @@ mod spawn_egg;
mod structures;
mod tag;
mod tracked_data;
mod translations;
mod world_event;
pub const OUT_DIR: &str = "src/generated";
@@ -72,6 +73,7 @@ pub fn main() {
(game_rules::build, "game_rules.rs"),
(registry::build, "registry.rs"),
(dimension::build, "dimension.rs"),
(translations::build, "translation.rs"),
(jukebox_song::build, "jukebox_song.rs"),
(sound_category::build, "sound_category.rs"),
(entity_pose::build, "entity_pose.rs"),

View File

@@ -0,0 +1,34 @@
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use std::{collections::BTreeMap, fs};
pub(crate) fn build() -> TokenStream {
println!("cargo:rerun-if-changed=../assets/en_us.json");
let en_us: BTreeMap<String, String> = serde_json::from_str(
&fs::read_to_string("../assets/en_us.json").expect("en_us is missing"),
)
.unwrap();
let mut constants = TokenStream::new();
for (name, value) in &en_us {
let clean_name = name.to_uppercase().replace(['.', '-'], "_");
let ident = format_ident!("{}", clean_name);
if !value.is_empty() {
constants.extend(quote! {
#[doc = #value]
pub const #ident: &str = #name;
});
} else {
constants.extend(quote! {
pub const #ident: &str = #name;
});
}
}
quote! {
#constants
}
}

View File

@@ -12,6 +12,10 @@ pub mod packet;
#[path = "generated/jukebox_song.rs"]
pub mod jukebox_song;
#[rustfmt::skip]
#[path = "generated/translation.rs"]
pub mod translation;
#[rustfmt::skip]
#[path = "generated/registry.rs"]
pub mod registry;

View File

@@ -141,7 +141,7 @@ fn is_start_chunk_concentric_rings(
_salt: u32,
) -> bool {
// TODO: Implement proper concentric rings logic
rand::random_bool(1.0 / 100.0)
rand::random_bool(1.0 / 1000.0)
}
#[cfg(test)]

View File

@@ -7,6 +7,7 @@ use crate::block::{
};
use pumpkin_data::block_properties::{BarrelLikeProperties, BlockProperties};
use pumpkin_data::translation;
use pumpkin_inventory::generic_container_screen_handler::create_generic_9x3;
use pumpkin_inventory::player::player_inventory::PlayerInventory;
use pumpkin_inventory::screen_handler::{
@@ -37,7 +38,7 @@ impl ScreenHandlerFactory for BarrelScreenFactory {
}
fn get_display_name(&self) -> TextComponent {
TextComponent::translate("container.barrel", &[])
TextComponent::translate(translation::CONTAINER_BARREL, &[])
}
}

View File

@@ -5,6 +5,7 @@ use pumpkin_data::block_properties::BedPart;
use pumpkin_data::block_properties::BlockProperties;
use pumpkin_data::dimension::Dimension;
use pumpkin_data::entity::EntityType;
use pumpkin_data::translation;
use pumpkin_macros::pumpkin_block_from_tag;
use pumpkin_util::GameMode;
use pumpkin_util::math::position::BlockPos;
@@ -243,7 +244,7 @@ impl BlockBehaviour for BedBlock {
{
args.player
.send_system_message_raw(
&TextComponent::translate("block.minecraft.bed.obstructed", []),
&TextComponent::translate(translation::BLOCK_MINECRAFT_BED_OBSTRUCTED, []),
true,
)
.await;
@@ -256,7 +257,7 @@ impl BlockBehaviour for BedBlock {
args.player
.send_system_message_raw(
&TextComponent::translate("block.minecraft.bed.occupied", []),
&TextComponent::translate(translation::BLOCK_MINECRAFT_BED_OCCUPIED, []),
true,
)
.await;
@@ -275,7 +276,10 @@ impl BlockBehaviour for BedBlock {
{
args.player
.send_system_message_raw(
&TextComponent::translate("block.minecraft.bed.too_far_away", []),
&TextComponent::translate(
translation::BLOCK_MINECRAFT_BED_TOO_FAR_AWAY,
[],
),
true,
)
.await;
@@ -294,7 +298,10 @@ impl BlockBehaviour for BedBlock {
.await
{
args.player
.send_system_message(&TextComponent::translate("block.minecraft.set_spawn", []))
.send_system_message(&TextComponent::translate(
translation::BLOCK_MINECRAFT_SET_SPAWN,
[],
))
.await;
}
@@ -302,7 +309,7 @@ impl BlockBehaviour for BedBlock {
if !can_sleep(args.world).await {
args.player
.send_system_message_raw(
&TextComponent::translate("block.minecraft.bed.no_sleep", []),
&TextComponent::translate(translation::BLOCK_MINECRAFT_BED_NO_SLEEP, []),
true,
)
.await;
@@ -321,7 +328,10 @@ impl BlockBehaviour for BedBlock {
{
args.player
.send_system_message_raw(
&TextComponent::translate("block.minecraft.bed.not_safe", []),
&TextComponent::translate(
translation::BLOCK_MINECRAFT_BED_NOT_SAFE,
[],
),
true,
)
.await;

View File

@@ -3,6 +3,7 @@ use std::sync::Arc;
use pumpkin_data::{
block_properties::{BlockProperties, FurnaceLikeProperties},
screen::WindowType,
translation,
};
use pumpkin_inventory::{
furnace_like::furnace_like_screen_handler::FurnaceLikeScreenHandler,
@@ -74,7 +75,7 @@ impl ScreenHandlerFactory for BlastingFurnaceScreenFactory {
}
fn get_display_name(&self) -> pumpkin_util::text::TextComponent {
TextComponent::translate("container.blast_furnace", &[])
TextComponent::translate(translation::CONTAINER_BLAST_FURNACE, &[])
}
}

View File

@@ -5,7 +5,7 @@ use pumpkin_data::block_properties::{
BlockProperties, ChestLikeProperties, ChestType, HorizontalFacing,
};
use pumpkin_data::entity::EntityPose;
use pumpkin_data::{Block, BlockDirection};
use pumpkin_data::{Block, BlockDirection, translation};
use pumpkin_inventory::double::DoubleInventory;
use pumpkin_inventory::generic_container_screen_handler::{create_generic_9x3, create_generic_9x6};
use pumpkin_inventory::player::player_inventory::PlayerInventory;
@@ -57,9 +57,9 @@ impl ScreenHandlerFactory for ChestScreenFactory {
fn get_display_name(&self) -> TextComponent {
if self.0.size() > 27 {
TextComponent::translate("container.chestDouble", &[])
TextComponent::translate(translation::CONTAINER_CHESTDOUBLE, &[])
} else {
TextComponent::translate("container.chest", &[])
TextComponent::translate(translation::CONTAINER_CHEST, &[])
}
}
}

View File

@@ -1,6 +1,7 @@
use crate::block::registry::BlockActionResult;
use crate::block::{BlockBehaviour, BlockFuture, NormalUseArgs};
use pumpkin_data::translation;
use pumpkin_inventory::crafting::crafting_screen_handler::CraftingTableScreenHandler;
use pumpkin_inventory::player::player_inventory::PlayerInventory;
use pumpkin_inventory::screen_handler::{
@@ -44,6 +45,6 @@ impl ScreenHandlerFactory for CraftingTableScreenFactory {
}
fn get_display_name(&self) -> TextComponent {
TextComponent::translate("container.crafting", &[])
TextComponent::translate(translation::CONTAINER_CRAFTING, &[])
}
}

View File

@@ -6,6 +6,7 @@ use crate::block::{
};
use crate::world::World;
use pumpkin_data::block_properties::{BlockProperties, LadderLikeProperties};
use pumpkin_data::translation;
use pumpkin_inventory::{
generic_container_screen_handler::create_generic_9x3,
player::player_inventory::PlayerInventory,
@@ -37,7 +38,7 @@ impl ScreenHandlerFactory for EnderChestScreenFactory {
}
fn get_display_name(&self) -> TextComponent {
TextComponent::translate("container.enderchest", &[])
TextComponent::translate(translation::CONTAINER_ENDERCHEST, &[])
}
}

View File

@@ -3,6 +3,7 @@ use std::sync::Arc;
use pumpkin_data::{
block_properties::{BlockProperties, FurnaceLikeProperties},
screen::WindowType,
translation,
};
use pumpkin_inventory::{
furnace_like::furnace_like_screen_handler::FurnaceLikeScreenHandler,
@@ -74,7 +75,7 @@ impl ScreenHandlerFactory for FurnaceScreenFactory {
}
fn get_display_name(&self) -> pumpkin_util::text::TextComponent {
TextComponent::translate("container.furnace", &[])
TextComponent::translate(translation::CONTAINER_FURNACE, &[])
}
}

View File

@@ -9,7 +9,7 @@ use crate::block::{
use crate::world::World;
use pumpkin_data::block_properties::{BlockProperties, HopperFacing};
use pumpkin_data::{Block, BlockDirection};
use pumpkin_data::{Block, BlockDirection, translation};
use pumpkin_inventory::generic_container_screen_handler::create_hopper;
use pumpkin_inventory::player::player_inventory::PlayerInventory;
use pumpkin_inventory::screen_handler::{
@@ -43,7 +43,7 @@ impl ScreenHandlerFactory for HopperBlockScreenFactory {
}
fn get_display_name(&self) -> TextComponent {
TextComponent::translate("container.hopper", &[])
TextComponent::translate(translation::CONTAINER_HOPPER, &[])
}
}

View File

@@ -92,7 +92,6 @@ impl BlockBehaviour for CactusBlock {
}
fn on_entity_collision<'a>(&'a self, args: OnEntityCollisionArgs<'a>) -> BlockFuture<'a, ()> {
log::warn!("CactusBlock::on_entity_collision");
Box::pin(async move {
args.entity
.damage(args.entity, 1.0, DamageType::CACTUS)

View File

@@ -7,10 +7,10 @@ use crate::block::{
use crate::entity::Entity;
use crate::entity::item::ItemEntity;
use pumpkin_data::FacingExt;
use pumpkin_data::block_properties::{BlockProperties, Facing};
use pumpkin_data::entity::EntityType;
use pumpkin_data::world::WorldEvent;
use pumpkin_data::{FacingExt, translation};
use pumpkin_inventory::generic_container_screen_handler::create_generic_3x3;
use pumpkin_inventory::player::player_inventory::PlayerInventory;
use pumpkin_inventory::screen_handler::{
@@ -47,7 +47,7 @@ impl ScreenHandlerFactory for DropperScreenFactory {
}
fn get_display_name(&self) -> TextComponent {
TextComponent::translate("container.dropper", &[])
TextComponent::translate(translation::CONTAINER_DROPPER, &[])
}
}

View File

@@ -8,6 +8,7 @@ use crate::block::{
use pumpkin_data::block_properties::BlockProperties;
use pumpkin_data::tag::{self};
use pumpkin_data::translation;
use pumpkin_inventory::generic_container_screen_handler::create_generic_9x3;
use pumpkin_inventory::player::player_inventory::PlayerInventory;
use pumpkin_inventory::screen_handler::{
@@ -37,7 +38,7 @@ impl ScreenHandlerFactory for ShulkerBoxScreenFactory {
}
fn get_display_name(&self) -> TextComponent {
TextComponent::translate("container.shulkerBox", &[])
TextComponent::translate(translation::CONTAINER_SHULKERBOX, &[])
}
}

View File

@@ -3,6 +3,7 @@ use std::sync::Arc;
use pumpkin_data::{
block_properties::{BlockProperties, FurnaceLikeProperties},
screen::WindowType,
translation,
};
use pumpkin_inventory::{
furnace_like::furnace_like_screen_handler::FurnaceLikeScreenHandler,
@@ -73,7 +74,7 @@ impl ScreenHandlerFactory for SmokerScreenFactory {
}
fn get_display_name(&self) -> pumpkin_util::text::TextComponent {
TextComponent::translate("container.smoker", &[])
TextComponent::translate(translation::CONTAINER_SMOKER, &[])
}
}
#[pumpkin_block("minecraft:smoker")]

View File

@@ -1,5 +1,5 @@
use pumpkin_data::Block;
use pumpkin_data::tag::{RegistryKey, get_tag_ids};
use pumpkin_data::{Block, translation};
use pumpkin_protocol::java::client::play::{ArgumentType, SuggestionProviders};
use pumpkin_util::text::TextComponent;
@@ -56,12 +56,12 @@ impl<'a> FindArg<'a> for BlockArgumentConsumer {
|| {
if name.starts_with("minecraft:") {
Err(CommandError::CommandFailed(TextComponent::translate(
"argument.block.id.invalid",
translation::ARGUMENT_BLOCK_ID_INVALID,
[TextComponent::text((*name).to_string())],
)))
} else {
Err(CommandError::CommandFailed(TextComponent::translate(
"argument.block.id.invalid",
translation::ARGUMENT_BLOCK_ID_INVALID,
[TextComponent::text("minecraft:".to_string() + *name)],
)))
}
@@ -122,12 +122,12 @@ impl<'a> FindArg<'a> for BlockPredicateArgumentConsumer {
|| {
if name.starts_with("minecraft:") {
Err(CommandError::CommandFailed(TextComponent::translate(
"argument.block.id.invalid",
translation::ARGUMENT_BLOCK_ID_INVALID,
[TextComponent::text((*name).to_string())],
)))
} else {
Err(CommandError::CommandFailed(TextComponent::translate(
"argument.block.id.invalid",
translation::ARGUMENT_BLOCK_ID_INVALID,
[TextComponent::text("minecraft:".to_string() + *name)],
)))
}
@@ -139,7 +139,7 @@ impl<'a> FindArg<'a> for BlockPredicateArgumentConsumer {
get_tag_ids(RegistryKey::Block, tag).map_or_else(
|| {
Err(CommandError::CommandFailed(TextComponent::translate(
"arguments.block.tag.unknown",
translation::ARGUMENTS_BLOCK_TAG_UNKNOWN,
[TextComponent::text((*tag).to_string())],
)))
},

View File

@@ -13,6 +13,7 @@ use crate::{
net::DisconnectReason,
};
use CommandError::InvalidConsumption;
use pumpkin_data::translation;
use pumpkin_util::text::TextComponent;
const NAMES: [&str; 1] = ["ban"];
@@ -79,7 +80,7 @@ async fn ban_players(
if count == 0 {
Err(CommandError::CommandFailed(TextComponent::translate(
"commands.ban.failed",
translation::COMMANDS_BAN_FAILED,
[],
)))
} else {
@@ -116,7 +117,7 @@ async fn ban_player(
// Send messages
sender
.send_message(TextComponent::translate(
"commands.ban.success",
translation::COMMANDS_BAN_SUCCESS,
[player.get_display_name().await, TextComponent::text(reason)],
))
.await;
@@ -124,7 +125,7 @@ async fn ban_player(
player
.kick(
DisconnectReason::Kicked,
TextComponent::translate("multiplayer.disconnect.banned", []),
TextComponent::translate(translation::MULTIPLAYER_DISCONNECT_BANNED, []),
)
.await;

View File

@@ -11,6 +11,7 @@ use crate::{
server::Server,
};
use CommandError::InvalidConsumption;
use pumpkin_data::translation;
use pumpkin_util::text::TextComponent;
const NAMES: [&str; 1] = ["ban-ip"];
@@ -83,7 +84,7 @@ async fn ban_ip(
let Some(target_ip) = parse_ip(target, server).await else {
return Err(CommandError::CommandFailed(TextComponent::translate(
"commands.banip.invalid",
translation::COMMANDS_BANIP_INVALID,
[],
)));
};
@@ -92,7 +93,7 @@ async fn ban_ip(
if banned_ips.get_entry(&target_ip).is_some() {
return Err(CommandError::CommandFailed(TextComponent::translate(
"commands.banip.failed",
translation::COMMANDS_BANIP_FAILED,
[],
)));
}
@@ -117,7 +118,7 @@ async fn ban_ip(
sender
.send_message(TextComponent::translate(
"commands.banip.success",
translation::COMMANDS_BANIP_SUCCESS,
[
TextComponent::text(target_ip.to_string()),
TextComponent::text(reason),
@@ -127,7 +128,7 @@ async fn ban_ip(
sender
.send_message(TextComponent::translate(
"commands.banip.info",
translation::COMMANDS_BANIP_INFO,
[
TextComponent::text(affected.len().to_string()),
TextComponent::text(names),
@@ -140,7 +141,7 @@ async fn ban_ip(
target
.kick(
DisconnectReason::Kicked,
TextComponent::translate("multiplayer.disconnect.ip_banned", []),
TextComponent::translate(translation::MULTIPLAYER_DISCONNECT_IP_BANNED, []),
)
.await;
}

View File

@@ -4,6 +4,7 @@ use crate::command::{
tree::{CommandTree, builder::argument},
};
use CommandError::InvalidConsumption;
use pumpkin_data::translation;
use pumpkin_util::text::TextComponent;
const NAMES: [&str; 1] = ["banlist"];
@@ -59,7 +60,7 @@ impl CommandExecutor for ListExecutor {
handle_banlist(entries, sender).await
}
_ => Err(CommandError::CommandFailed(TextComponent::translate(
"command.unknown.argument",
translation::COMMAND_UNKNOWN_ARGUMENT,
[],
))),
}
@@ -106,14 +107,14 @@ async fn handle_banlist(
) -> Result<i32, CommandError> {
if list.is_empty() {
return Result::Err(CommandError::CommandFailed(TextComponent::translate(
"commands.banlist.none",
translation::COMMANDS_BANLIST_NONE,
[],
)));
}
sender
.send_message(TextComponent::translate(
"commands.banlist.list",
translation::COMMANDS_BANLIST_LIST,
[TextComponent::text(list.len().to_string())],
))
.await;
@@ -123,7 +124,7 @@ async fn handle_banlist(
for (name, source, reason) in list {
sender
.send_message(TextComponent::translate(
"commands.banlist.entry",
translation::COMMANDS_BANLIST_ENTRY,
[
TextComponent::text(name),
TextComponent::text(source),

View File

@@ -14,6 +14,7 @@ use crate::command::tree::builder::{argument, argument_default_name, literal};
use crate::command::{CommandExecutor, CommandResult, CommandSender};
use crate::world::bossbar::Bossbar;
use crate::world::custom_bossbar::BossbarUpdateError;
use pumpkin_data::translation;
use pumpkin_util::text::TextComponent;
use pumpkin_util::text::hover::HoverEvent;
use std::fmt::Write as _;
@@ -634,9 +635,12 @@ fn bossbar_prefix(title: TextComponent, namespace: String) -> TextComponent {
fn handle_bossbar_error(error: BossbarUpdateError) -> CommandError {
match error {
BossbarUpdateError::InvalidResourceLocation(location) => CommandError::CommandFailed(
TextComponent::translate("commands.bossbar.unknown", [TextComponent::text(location)]),
),
BossbarUpdateError::InvalidResourceLocation(location) => {
CommandError::CommandFailed(TextComponent::translate(
translation::COMMANDS_BOSSBAR_UNKNOWN,
[TextComponent::text(location)],
))
}
BossbarUpdateError::NoChanges(value, variation) => {
let mut key = "commands.bossbar.set.".to_string();
key.push_str(value);

View File

@@ -1,5 +1,6 @@
use std::sync::Arc;
use pumpkin_data::translation;
use pumpkin_util::text::TextComponent;
use pumpkin_world::item::ItemStack;
use tokio::sync::Mutex;
@@ -143,36 +144,36 @@ async fn clear_command_text_output(
) -> Result<TextComponent, TextComponent> {
match (targets, item_count == 0, max_count == 0) {
([target], true, _) => Err(TextComponent::translate(
"clear.failed.single",
translation::CLEAR_FAILED_SINGLE,
[target.get_display_name().await],
)),
(targets, true, _) => Err(TextComponent::translate(
"clear.failed.multiple",
translation::CLEAR_FAILED_MULTIPLE,
[TextComponent::text(targets.len().to_string())],
)),
([target], false, false) => Ok(TextComponent::translate(
"commands.clear.success.single",
translation::COMMANDS_CLEAR_SUCCESS_SINGLE,
[
TextComponent::text(item_count.to_string()),
target.get_display_name().await,
],
)),
(targets, false, false) => Ok(TextComponent::translate(
"commands.clear.success.multiple",
translation::COMMANDS_CLEAR_SUCCESS_MULTIPLE,
[
TextComponent::text(item_count.to_string()),
TextComponent::text(targets.len().to_string()),
],
)),
([target], false, true) => Ok(TextComponent::translate(
"commands.clear.test.single",
translation::COMMANDS_CLEAR_TEST_SINGLE,
[
TextComponent::text(item_count.to_string()),
target.get_display_name().await,
],
)),
(targets, false, true) => Ok(TextComponent::translate(
"commands.clear.test.multiple",
translation::COMMANDS_CLEAR_TEST_MULTIPLE,
[
TextComponent::text(item_count.to_string()),
TextComponent::text(targets.len().to_string()),
@@ -273,7 +274,7 @@ impl CommandExecutor for ItemCountExecutor {
let item = ItemPredicateArgumentConsumer::find_arg(args, ARG_ITEM)?;
let Ok(max) = count_consumer().find_arg_default_name(args)? else {
return Err(CommandError::CommandFailed(TextComponent::translate(
"parsing.int.invalid",
translation::PARSING_INT_INVALID,
[TextComponent::text(i32::MAX.to_string())],
)));
};

View File

@@ -1,4 +1,4 @@
use pumpkin_data::damage::DamageType;
use pumpkin_data::{damage::DamageType, translation};
use pumpkin_util::text::TextComponent;
use crate::command::{
@@ -40,14 +40,14 @@ async fn send_damage_result(
) -> Result<i32, CommandError> {
if !success {
return Err(CommandError::CommandFailed(TextComponent::translate(
"commands.damage.invulnerable",
translation::COMMANDS_DAMAGE_INVULNERABLE,
[],
)));
}
sender
.send_message(TextComponent::translate(
"commands.damage.success",
translation::COMMANDS_DAMAGE_SUCCESS,
[TextComponent::text(amount.to_string()), target_name],
))
.await;

View File

@@ -8,6 +8,7 @@ use crate::command::{
};
use crate::entity::NBTStorage;
use CommandError::InvalidConsumption;
use pumpkin_data::translation;
use pumpkin_nbt::compound::NbtCompound;
use pumpkin_nbt::tag::NbtTag;
use pumpkin_util::text::TextComponent;
@@ -232,7 +233,7 @@ async fn display_data(
.map_err(|string| CommandError::CommandFailed(TextComponent::text(string)))?;
sender
.send_message(TextComponent::translate(
"commands.data.entity.query",
translation::COMMANDS_DATA_ENTITY_QUERY,
[target_name, display],
))
.await;
@@ -243,7 +244,7 @@ async fn display_data(
fn get_i32_result(tag: &NbtTag) -> Result<i32, CommandError> {
match tag {
NbtTag::End => Err(CommandError::CommandFailed(TextComponent::translate(
"commands.data.get.unknown",
translation::COMMANDS_DATA_GET_UNKNOWN,
[],
))),

View File

@@ -1,3 +1,4 @@
use pumpkin_data::translation;
use pumpkin_util::text::TextComponent;
use crate::command::args::bounded_num::{BoundedNumArgumentConsumer, NotInBounds};
@@ -119,12 +120,12 @@ impl CommandExecutor for Executor {
}
}
if success == 0 {
let msg = TextComponent::translate("commands.enchant.failed", []);
let msg = TextComponent::translate(translation::COMMANDS_ENCHANT_FAILED, []);
return Err(CommandError::CommandFailed(msg));
}
if only_one {
let msg = TextComponent::translate(
"commands.enchant.success.single",
translation::COMMANDS_ENCHANT_SUCCESS_SINGLE,
[
enchantment.get_fullname(level),
targets[0].get_display_name().await,
@@ -133,7 +134,7 @@ impl CommandExecutor for Executor {
sender.send_message(msg).await;
} else {
let msg = TextComponent::translate(
"commands.enchant.success.multiple",
translation::COMMANDS_ENCHANT_SUCCESS_MULTIPLE,
[
enchantment.get_fullname(level),
TextComponent::text(targets.len().to_string()),

View File

@@ -1,3 +1,4 @@
use pumpkin_data::translation;
use pumpkin_util::text::TextComponent;
use pumpkin_util::text::color::NamedColor;
@@ -35,7 +36,7 @@ impl CommandExecutor for Executor {
let reason = match args.get(&ARG_REASON) {
Some(Arg::Msg(r)) => TextComponent::text(r.clone()),
_ => TextComponent::translate("multiplayer.disconnect.kicked", []),
_ => TextComponent::translate(translation::MULTIPLAYER_DISCONNECT_KICKED, []),
};
for target in targets {

View File

@@ -1,6 +1,7 @@
use std::sync::Arc;
use pumpkin_data::sound::SoundCategory;
use pumpkin_data::translation;
use pumpkin_util::text::TextComponent;
use rand::{RngExt, rng};
@@ -149,7 +150,7 @@ impl CommandExecutor for Executor {
if players_who_heard == 1 {
sender
.send_message(TextComponent::translate(
"commands.playsound.success.single",
translation::COMMANDS_PLAYSOUND_SUCCESS_SINGLE,
[
TextComponent::text(sound_name),
targets[0].get_display_name().await,
@@ -159,7 +160,7 @@ impl CommandExecutor for Executor {
} else {
sender
.send_message(TextComponent::translate(
"commands.playsound.success.multiple",
translation::COMMANDS_PLAYSOUND_SUCCESS_MULTIPLE,
[
TextComponent::text(sound_name),
TextComponent::text(players_who_heard.to_string()),

View File

@@ -1,3 +1,4 @@
use pumpkin_data::translation;
use pumpkin_util::math::vector3::Vector3;
use pumpkin_util::text::TextComponent;
@@ -89,7 +90,7 @@ async fn send_success_message(sender: &CommandSender, target: &dyn crate::entity
let target_name = target.get_display_name().await;
sender
.send_message(TextComponent::translate(
"commands.rotate.success",
translation::COMMANDS_ROTATE_SUCCESS,
[target_name],
))
.await;

View File

@@ -13,6 +13,7 @@ use crate::command::{
};
use crate::server::Server;
use pumpkin_data::dimension::Dimension;
use pumpkin_data::translation;
use pumpkin_util::{math::position::BlockPos, text::TextComponent};
const NAMES: [&str; 1] = ["setworldspawn"];
@@ -107,7 +108,7 @@ async fn setworldspawn(
};
if world.dimension != Dimension::OVERWORLD && world.dimension != Dimension::OVERWORLD_CAVES {
return Err(CommandError::CommandFailed(TextComponent::translate(
"commands.setworldspawn.failure.not_overworld",
translation::COMMANDS_SETWORLDSPAWN_FAILURE_NOT_OVERWORLD,
[],
)));
}
@@ -126,7 +127,7 @@ async fn setworldspawn(
sender
.send_message(TextComponent::translate(
"commands.setworldspawn.success",
translation::COMMANDS_SETWORLDSPAWN_SUCCESS,
[
TextComponent::text(block_pos.0.x.to_string()),
TextComponent::text(block_pos.0.y.to_string()),

View File

@@ -1,5 +1,6 @@
use std::sync::Arc;
use pumpkin_data::translation;
use pumpkin_util::math::position::BlockPos;
use pumpkin_util::text::TextComponent;
@@ -131,7 +132,7 @@ async fn set_spawnpoint(sender: &CommandSender, target: &Arc<Player>, pos: Block
sender
.send_message(TextComponent::translate(
"commands.spawnpoint.success.single",
translation::COMMANDS_SPAWNPOINT_SUCCESS_SINGLE,
[
TextComponent::text(pos.0.x.to_string()),
TextComponent::text(pos.0.y.to_string()),

View File

@@ -1,3 +1,4 @@
use pumpkin_data::translation;
use pumpkin_util::text::TextComponent;
use pumpkin_util::text::color::NamedColor;
@@ -22,7 +23,7 @@ impl CommandExecutor for Executor {
Box::pin(async move {
sender
.send_message(
TextComponent::translate("commands.stop.stopping", [])
TextComponent::translate(translation::COMMANDS_STOP_STOPPING, [])
.color_named(NamedColor::Red),
)
.await;

View File

@@ -6,6 +6,7 @@ use crate::command::{
},
tree::{CommandTree, builder::argument},
};
use pumpkin_data::translation;
use pumpkin_util::text::TextComponent;
const NAMES: [&str; 1] = ["stopsound"];
@@ -45,23 +46,24 @@ impl CommandExecutor for Executor {
let text = match (category, sound) {
(Ok(c), Ok(s)) => TextComponent::translate(
"commands.stopsound.success.source.sound",
translation::COMMANDS_STOPSOUND_SUCCESS_SOURCE_SOUND,
[
TextComponent::text(s.to_name()),
TextComponent::text(c.to_name()),
],
),
(Ok(c), Err(_)) => TextComponent::translate(
"commands.stopsound.success.source.any",
translation::COMMANDS_STOPSOUND_SUCCESS_SOURCE_ANY,
[TextComponent::text(c.to_name())],
),
(Err(_), Ok(s)) => TextComponent::translate(
"commands.stopsound.success.sourceless.sound",
translation::COMMANDS_STOPSOUND_SUCCESS_SOURCELESS_SOUND,
[TextComponent::text(s.to_name())],
),
(Err(_), Err(_)) => {
TextComponent::translate("commands.stopsound.success.sourceless.any", [])
}
(Err(_), Err(_)) => TextComponent::translate(
translation::COMMANDS_STOPSOUND_SUCCESS_SOURCELESS_ANY,
[],
),
};
sender.send_message(text).await;

View File

@@ -1,3 +1,4 @@
use pumpkin_data::translation;
use pumpkin_util::{math::vector3::Vector3, text::TextComponent};
use uuid::Uuid;
@@ -65,7 +66,10 @@ impl CommandExecutor for Executor {
let name = entity.get_display_name().await;
world.spawn_entity(entity).await;
sender
.send_message(TextComponent::translate("commands.summon.success", [name]))
.send_message(TextComponent::translate(
translation::COMMANDS_SUMMON_SUCCESS,
[name],
))
.await;
Ok(1)

View File

@@ -1,3 +1,4 @@
use pumpkin_data::translation;
use pumpkin_util::text::{
TextComponent,
color::{Color, NamedColor},
@@ -64,13 +65,13 @@ impl TickExecutor {
if manager.is_sprinting() {
sender
.send_message(TextComponent::translate(
"commands.tick.status.sprinting",
translation::COMMANDS_TICK_STATUS_SPRINTING,
[],
))
.await;
sender
.send_message(TextComponent::translate(
"commands.tick.query.rate.sprinting",
translation::COMMANDS_TICK_QUERY_RATE_SPRINTING,
[
TextComponent::text(format!("{tickrate:.1}")),
TextComponent::text(avg_mspt_str),
@@ -83,7 +84,7 @@ impl TickExecutor {
let target_mspt_str = nanos_to_millis_string(manager.nanoseconds_per_tick());
sender
.send_message(TextComponent::translate(
"commands.tick.query.rate.running",
translation::COMMANDS_TICK_QUERY_RATE_RUNNING,
[
TextComponent::text(format!("{tickrate:.1}")),
TextComponent::text(avg_mspt_str),
@@ -103,15 +104,24 @@ impl TickExecutor {
) {
if manager.is_frozen() {
sender
.send_message(TextComponent::translate("commands.tick.status.frozen", []))
.send_message(TextComponent::translate(
translation::COMMANDS_TICK_STATUS_FROZEN,
[],
))
.await;
} else if avg_tick_nanos > manager.nanoseconds_per_tick() {
sender
.send_message(TextComponent::translate("commands.tick.status.lagging", []))
.send_message(TextComponent::translate(
translation::COMMANDS_TICK_STATUS_LAGGING,
[],
))
.await;
} else {
sender
.send_message(TextComponent::translate("commands.tick.status.running", []))
.send_message(TextComponent::translate(
translation::COMMANDS_TICK_STATUS_RUNNING,
[],
))
.await;
}
}
@@ -131,7 +141,7 @@ impl TickExecutor {
sender
.send_message(TextComponent::translate(
"commands.tick.query.percentiles",
translation::COMMANDS_TICK_QUERY_PERCENTILES,
[
TextComponent::text(nanos_to_millis_string(p50_nanos)),
TextComponent::text(nanos_to_millis_string(p95_nanos)),
@@ -151,14 +161,14 @@ impl TickExecutor {
if manager.step_game_if_paused(server, ticks).await {
sender
.send_message(TextComponent::translate(
"commands.tick.step.success",
translation::COMMANDS_TICK_STEP_SUCCESS,
[TextComponent::text(ticks.to_string())],
))
.await;
} else {
sender
.send_message(
TextComponent::translate("commands.tick.step.fail", [])
TextComponent::translate(translation::COMMANDS_TICK_STEP_FAIL, [])
.color_named(NamedColor::Red),
)
.await;
@@ -176,14 +186,14 @@ impl TickExecutor {
{
sender
.send_message(TextComponent::translate(
"commands.tick.sprint.stop.success",
translation::COMMANDS_TICK_SPRINT_STOP_SUCCESS,
[],
))
.await;
}
sender
.send_message(TextComponent::translate(
"commands.tick.status.sprinting",
translation::COMMANDS_TICK_STATUS_SPRINTING,
[],
))
.await;
@@ -198,7 +208,7 @@ impl TickExecutor {
manager.set_tick_rate(server, rate).await;
sender
.send_message(TextComponent::translate(
"commands.tick.rate.success",
translation::COMMANDS_TICK_RATE_SUCCESS,
[TextComponent::text(format!("{rate:.1}"))],
))
.await;
@@ -253,7 +263,7 @@ impl CommandExecutor for TickExecutor {
if manager.stop_stepping(server).await {
sender
.send_message(TextComponent::translate(
"commands.tick.step.stop.success",
translation::COMMANDS_TICK_SPRINT_STOP_SUCCESS,
[],
))
.await;
@@ -262,7 +272,7 @@ impl CommandExecutor for TickExecutor {
// TODO: send feedback as error without Err
sender
.send_message(TextComponent::translate(
"commands.tick.step.stop.fail",
translation::COMMANDS_TICK_SPRINT_STOP_FAIL,
[],
))
.await;
@@ -287,7 +297,7 @@ impl CommandExecutor for TickExecutor {
if manager.stop_sprinting(server).await {
sender
.send_message(TextComponent::translate(
"commands.tick.sprint.stop.success",
translation::COMMANDS_TICK_SPRINT_STOP_SUCCESS,
[],
))
.await;
@@ -296,8 +306,11 @@ impl CommandExecutor for TickExecutor {
// TODO: send feedback as error without Err
sender
.send_message(
TextComponent::translate("commands.tick.sprint.stop.fail", [])
.color(Color::Named(NamedColor::Red)),
TextComponent::translate(
translation::COMMANDS_TICK_SPRINT_STOP_FAIL,
[],
)
.color(Color::Named(NamedColor::Red)),
)
.await;
Ok(0)

View File

@@ -1,3 +1,4 @@
use pumpkin_data::translation;
use pumpkin_util::text::TextComponent;
use crate::command::CommandResult;
@@ -67,7 +68,7 @@ impl CommandExecutor for QueryExecutor {
};
sender
.send_message(TextComponent::translate(
"commands.time.query",
translation::COMMANDS_TIME_QUERY,
[TextComponent::text(curr_time.to_string())],
))
.await;
@@ -112,7 +113,7 @@ impl CommandExecutor for ChangeExecutor {
let curr_time = level_time.query_daytime();
sender
.send_message(TextComponent::translate(
"commands.time.set",
translation::COMMANDS_TIME_SET,
[TextComponent::text(curr_time.to_string())],
))
.await;
@@ -124,7 +125,7 @@ impl CommandExecutor for ChangeExecutor {
level_time.send_time(world).await;
sender
.send_message(TextComponent::translate(
"commands.time.set",
translation::COMMANDS_TIME_SET,
[TextComponent::text(time_count.to_string())],
))
.await;

View File

@@ -1,3 +1,4 @@
use pumpkin_data::translation;
use pumpkin_util::text::TextComponent;
use crate::command::{
@@ -51,7 +52,10 @@ impl CommandExecutor for Executor {
.set_weather_parameters(&world, processed_duration, 0, false, false)
.await;
sender
.send_message(TextComponent::translate("commands.weather.set.clear", []))
.send_message(TextComponent::translate(
translation::COMMANDS_WEATHER_SET_CLEAR,
[],
))
.await;
}
WeatherMode::Rain => {
@@ -62,7 +66,10 @@ impl CommandExecutor for Executor {
.set_weather_parameters(&world, 0, processed_duration, true, false)
.await;
sender
.send_message(TextComponent::translate("commands.weather.set.rain", []))
.send_message(TextComponent::translate(
translation::COMMANDS_WEATHER_SET_RAIN,
[],
))
.await;
}
WeatherMode::Thunder => {
@@ -73,7 +80,10 @@ impl CommandExecutor for Executor {
.set_weather_parameters(&world, 0, processed_duration, true, true)
.await;
sender
.send_message(TextComponent::translate("commands.weather.set.thunder", []))
.send_message(TextComponent::translate(
translation::COMMANDS_WEATHER_SET_THUNDER,
[],
))
.await;
}
}

View File

@@ -1,6 +1,7 @@
use std::sync::atomic::Ordering;
use pumpkin_config::whitelist::WhitelistEntry;
use pumpkin_data::translation;
use pumpkin_util::text::TextComponent;
use crate::command::CommandResult;
@@ -34,7 +35,10 @@ async fn kick_non_whitelisted_players(server: &Server) {
player
.kick(
DisconnectReason::Kicked,
TextComponent::translate("multiplayer.disconnect.not_whitelisted", &[]),
TextComponent::translate(
translation::MULTIPLAYER_DISCONNECT_NOT_WHITELISTED,
&[],
),
)
.await;
}
@@ -54,13 +58,16 @@ impl CommandExecutor for OnExecutor {
let previous = server.white_list.swap(true, Ordering::Relaxed);
if previous {
Err(CommandError::CommandFailed(TextComponent::translate(
"commands.whitelist.alreadyOn",
translation::COMMANDS_WHITELIST_ALREADYON,
&[],
)))
} else {
kick_non_whitelisted_players(server).await;
sender
.send_message(TextComponent::translate("commands.whitelist.enabled", &[]))
.send_message(TextComponent::translate(
translation::COMMANDS_WHITELIST_ENABLED,
&[],
))
.await;
Ok(1)
}
@@ -81,12 +88,15 @@ impl CommandExecutor for OffExecutor {
let previous = server.white_list.swap(false, Ordering::Relaxed);
if previous {
sender
.send_message(TextComponent::translate("commands.whitelist.disabled", &[]))
.send_message(TextComponent::translate(
translation::COMMANDS_WHITELIST_DISABLED,
&[],
))
.await;
Ok(1)
} else {
Err(CommandError::CommandFailed(TextComponent::translate(
"commands.whitelist.alreadyOff",
translation::COMMANDS_WHITELIST_ALREADYOFF,
&[],
)))
}
@@ -107,7 +117,10 @@ impl CommandExecutor for ListExecutor {
let whitelist = &server.data.whitelist_config.read().await.whitelist;
if whitelist.is_empty() {
sender
.send_message(TextComponent::translate("commands.whitelist.none", []))
.send_message(TextComponent::translate(
translation::COMMANDS_WHITELIST_NONE,
[],
))
.await;
return Ok(0);
}
@@ -122,7 +135,7 @@ impl CommandExecutor for ListExecutor {
sender
.send_message(TextComponent::translate(
"commands.whitelist.list",
translation::COMMANDS_WHITELIST_LIST,
[
TextComponent::text(whitelist.len().to_string()),
TextComponent::text(names),
@@ -148,7 +161,10 @@ impl CommandExecutor for ReloadExecutor {
*server.data.whitelist_config.write().await = WhitelistConfig::load();
kick_non_whitelisted_players(server).await;
sender
.send_message(TextComponent::translate("commands.whitelist.reloaded", &[]))
.send_message(TextComponent::translate(
translation::COMMANDS_WHITELIST_RELOADED,
&[],
))
.await;
Ok(1)
})
@@ -181,7 +197,7 @@ impl CommandExecutor for AddExecutor {
.push(WhitelistEntry::new(profile.id, profile.name.clone()));
sender
.send_message(TextComponent::translate(
"commands.whitelist.add.success",
translation::COMMANDS_WHITELIST_ADD_SUCCESS,
[TextComponent::text(profile.name.clone())],
))
.await;
@@ -192,7 +208,7 @@ impl CommandExecutor for AddExecutor {
if successes == 0 {
Err(CommandError::CommandFailed(TextComponent::translate(
"commands.whitelist.add.failed",
translation::COMMANDS_WHITELIST_ADD_FAILED,
&[],
)))
} else {
@@ -228,7 +244,7 @@ impl CommandExecutor for RemoveExecutor {
whitelist.whitelist.remove(i);
sender
.send_message(TextComponent::translate(
"commands.whitelist.remove.success",
translation::COMMANDS_WHITELIST_REMOVE_SUCCESS,
[player.get_display_name().await],
))
.await;
@@ -243,7 +259,7 @@ impl CommandExecutor for RemoveExecutor {
if successes == 0 {
Err(CommandError::CommandFailed(TextComponent::translate(
"commands.whitelist.remove.failed",
translation::COMMANDS_WHITELIST_REMOVE_FAILED,
&[],
)))
} else {

View File

@@ -23,12 +23,12 @@ use crate::entity::{EntityBaseFuture, NbtFuture};
use crate::server::Server;
use crate::world::loot::{LootContextParameters, LootTableExt};
use crossbeam::atomic::AtomicCell;
use pumpkin_data::Block;
use pumpkin_data::damage::DeathMessageType;
use pumpkin_data::data_component_impl::{DeathProtectionImpl, EquipmentSlot, FoodImpl};
use pumpkin_data::effect::StatusEffect;
use pumpkin_data::entity::{EntityPose, EntityStatus, EntityType};
use pumpkin_data::sound::SoundCategory;
use pumpkin_data::{Block, translation};
use pumpkin_data::{damage::DamageType, sound::Sound};
use pumpkin_inventory::entity_equipment::EntityEquipment;
use pumpkin_nbt::compound::NbtCompound;
@@ -888,7 +888,7 @@ impl LivingEntity {
DeathMessageType::FallVariants => {
//TODO
TextComponent::translate(
"death.fell.accident.generic",
translation::DEATH_FELL_ACCIDENT_GENERIC,
[dyn_self.get_display_name().await],
)
}

View File

@@ -38,7 +38,7 @@ use pumpkin_data::entity::{EntityPose, EntityStatus, EntityType};
use pumpkin_data::particle::Particle;
use pumpkin_data::sound::{Sound, SoundCategory};
use pumpkin_data::tag::Taggable;
use pumpkin_data::{Block, BlockState, Enchantment, tag};
use pumpkin_data::{Block, BlockState, Enchantment, tag, translation};
use pumpkin_inventory::player::{
player_inventory::PlayerInventory, player_screen_handler::PlayerScreenHandler,
};
@@ -1378,7 +1378,7 @@ impl Player {
if idle_duration >= Duration::from_secs(idle_timeout_minutes as u64 * 60) {
self.kick(
DisconnectReason::KickedForIdle,
TextComponent::translate("multiplayer.disconnect.idling", []),
TextComponent::translate(translation::MULTIPLAYER_DISCONNECT_IDLING, []),
)
.await;
return;
@@ -1394,7 +1394,7 @@ impl Player {
if self.wait_for_keep_alive.load(Ordering::Relaxed) {
self.kick(
DisconnectReason::Timeout,
TextComponent::translate("disconnect.timeout", []),
TextComponent::translate(translation::DISCONNECT_TIMEOUT, []),
)
.await;
return;

View File

@@ -1,4 +1,4 @@
use pumpkin_data::packet::CURRENT_MC_PROTOCOL;
use pumpkin_data::{packet::CURRENT_MC_PROTOCOL, translation};
use pumpkin_protocol::{ConnectionState, java::server::handshake::SHandShake};
use pumpkin_util::{text::TextComponent, version::MinecraftVersion};
@@ -18,13 +18,13 @@ impl JavaClient {
let protocol = version;
if protocol < LOWEST_SUPPRORTED_PROTOCOL_VERSION {
self.kick(TextComponent::translate(
"multiplayer.disconnect.outdated_client",
translation::MULTIPLAYER_DISCONNECT_OUTDATED_CLIENT,
[TextComponent::text(CURRENT_MC_VERSION.to_string())],
))
.await;
} else if protocol > CURRENT_MC_PROTOCOL {
self.kick(TextComponent::translate(
"multiplayer.disconnect.incompatible",
translation::MULTIPLAYER_DISCONNECT_OUTDATED_SERVER,
[TextComponent::text(CURRENT_MC_VERSION.to_string())],
))
.await;

View File

@@ -1,3 +1,4 @@
use pumpkin_data::translation;
use pumpkin_protocol::{
ConnectionState, KnownPack, Label, Link, LinkType,
java::client::{
@@ -33,7 +34,7 @@ impl JavaClient {
let max_players = server.basic_config.max_players;
if max_players > 0 && server.get_player_count() >= max_players as usize {
self.kick(TextComponent::translate(
"multiplayer.disconnect.server_full",
translation::MULTIPLAYER_DISCONNECT_SERVER_FULL,
[],
))
.await;
@@ -135,11 +136,12 @@ impl JavaClient {
Ok(new_profile) => *profile = new_profile,
Err(error) => {
self.kick(match error {
AuthError::FailedResponse => {
TextComponent::translate("multiplayer.disconnect.authservers_down", [])
}
AuthError::FailedResponse => TextComponent::translate(
translation::MULTIPLAYER_DISCONNECT_AUTHSERVERS_DOWN,
[],
),
AuthError::UnverifiedUsername => TextComponent::translate(
"multiplayer.disconnect.unverified_username",
translation::MULTIPLAYER_DISCONNECT_UNVERIFIED_USERNAME,
[],
),
e => TextComponent::text(e.to_string()),
@@ -159,7 +161,7 @@ impl JavaClient {
&online_player.gameprofile.name
);
self.kick(TextComponent::translate(
"multiplayer.disconnect.duplicate_login",
translation::MULTIPLAYER_DISCONNECT_DUPLICATE_LOGIN,
[],
))
.await;
@@ -176,7 +178,7 @@ impl JavaClient {
&online_player.gameprofile.name
);
self.kick(TextComponent::translate(
"multiplayer.disconnect.duplicate_login",
translation::MULTIPLAYER_DISCONNECT_DUPLICATE_LOGIN,
[],
))
.await;

View File

@@ -30,7 +30,7 @@ use pumpkin_data::block_properties::{
use pumpkin_data::data_component_impl::{ConsumableImpl, EquipmentSlot, EquippableImpl, FoodImpl};
use pumpkin_data::item::Item;
use pumpkin_data::sound::{Sound, SoundCategory};
use pumpkin_data::{Block, BlockDirection, BlockState};
use pumpkin_data::{Block, BlockDirection, BlockState, translation};
use pumpkin_inventory::InventoryError;
use pumpkin_inventory::player::player_inventory::PlayerInventory;
use pumpkin_inventory::screen_handler::{InventoryPlayer, ScreenHandler};
@@ -136,30 +136,47 @@ impl PumpkinError for ChatError {
match self {
Self::OversizedMessage => Some("Chat message too long".into()),
Self::IllegalCharacters => Some(
TextComponent::translate("multiplayer.disconnect.illegal_characters", [])
.get_text(),
TextComponent::translate(
translation::MULTIPLAYER_DISCONNECT_ILLEGAL_CHARACTERS,
[],
)
.get_text(),
),
Self::UnsignedChat => Some(
TextComponent::translate("multiplayer.disconnect.unsigned_chat", []).get_text(),
TextComponent::translate(translation::MULTIPLAYER_DISCONNECT_UNSIGNED_CHAT, [])
.get_text(),
),
Self::TooManyPendingChats => Some(
TextComponent::translate("multiplayer.disconnect.too_many_pending_chats", [])
.get_text(),
TextComponent::translate(
translation::MULTIPLAYER_DISCONNECT_TOO_MANY_PENDING_CHATS,
[],
)
.get_text(),
),
Self::ChatValidationFailed => Some(
TextComponent::translate("multiplayer.disconnect.chat_validation_failed", [])
.get_text(),
TextComponent::translate(
translation::MULTIPLAYER_DISCONNECT_CHAT_VALIDATION_FAILED,
[],
)
.get_text(),
),
Self::OutOfOrderChat => Some(
TextComponent::translate("multiplayer.disconnect.out_of_order_chat", []).get_text(),
TextComponent::translate(translation::MULTIPLAYER_DISCONNECT_OUT_OF_ORDER_CHAT, [])
.get_text(),
),
Self::ExpiredPublicKey => Some(
TextComponent::translate("multiplayer.disconnect.expired_public_key", [])
.get_text(),
TextComponent::translate(
translation::MULTIPLAYER_DISCONNECT_EXPIRED_PUBLIC_KEY,
[],
)
.get_text(),
),
Self::InvalidPublicKey => Some(
TextComponent::translate("multiplayer.disconnect.invalid_public_key_signature", [])
.get_text(),
TextComponent::translate(
translation::MULTIPLAYER_DISCONNECT_INVALID_PUBLIC_KEY_SIGNATURE,
[],
)
.get_text(),
),
}
}
@@ -206,7 +223,7 @@ impl JavaClient {
);
player
.send_system_message(&TextComponent::translate(
"commands.gamemode.success.self",
translation::COMMANDS_GAMEMODE_SUCCESS_SELF,
[TextComponent::translate(gamemode_string, [])],
))
.await;
@@ -274,7 +291,7 @@ impl JavaClient {
let position = packet.position;
if position.x.is_nan() || position.y.is_nan() || position.z.is_nan() {
self.kick(TextComponent::translate(
"multiplayer.disconnect.invalid_player_movement",
translation::MULTIPLAYER_DISCONNECT_INVALID_PLAYER_MOVEMENT,
[],
))
.await;
@@ -387,7 +404,7 @@ impl JavaClient {
|| !packet.pitch.is_finite()
{
self.kick(TextComponent::translate(
"multiplayer.disconnect.invalid_player_movement",
translation::MULTIPLAYER_DISCONNECT_INVALID_PLAYER_MOVEMENT,
[],
))
.await;
@@ -517,7 +534,7 @@ impl JavaClient {
}
if !rotation.yaw.is_finite() || !rotation.pitch.is_finite() {
self.kick(TextComponent::translate(
"multiplayer.disconnect.invalid_player_movement",
translation::MULTIPLAYER_DISCONNECT_INVALID_PLAYER_MOVEMENT,
[],
))
.await;
@@ -1215,7 +1232,7 @@ impl JavaClient {
if entity_id.0 == player.entity_id() {
// This can't be triggered from a non-modded client.
self.kick(TextComponent::translate(
"multiplayer.disconnect.invalid_entity_attacked",
translation::MULTIPLAYER_DISCONNECT_INVALID_ENTITY_ATTACKED,
[],
))
.await;
@@ -1249,7 +1266,7 @@ impl JavaClient {
entity_id.0
);
self.kick(TextComponent::translate(
"multiplayer.disconnect.invalid_entity_attacked",
translation::MULTIPLAYER_DISCONNECT_INVALID_ENTITY_ATTACKED,
[],
))
.await;
@@ -1976,7 +1993,7 @@ impl JavaClient {
player
.send_system_message_raw(
&TextComponent::translate(
"build.tooHigh",
translation::BUILD_TOOHIGH,
vec![TextComponent::text((world.get_top_y()).to_string())],
)
.color_named(NamedColor::Red),

View File

@@ -10,6 +10,7 @@ use crate::{
server::Server,
};
use pumpkin_data::translation;
use pumpkin_protocol::{ClientPacket, Property};
use pumpkin_util::{Hand, ProfileAction, text::TextComponent};
use serde::Deserialize;
@@ -177,12 +178,12 @@ pub async fn can_not_join(
let mut banned_players = server.data.banned_player_list.write().await;
if let Some(entry) = banned_players.get_entry(profile) {
let text = TextComponent::translate(
"multiplayer.disconnect.banned.reason",
translation::MULTIPLAYER_DISCONNECT_BANNED_REASON,
[TextComponent::text(entry.reason.clone())],
);
return Some(match entry.expires {
Some(expires) => text.add_child(TextComponent::translate(
"multiplayer.disconnect.banned.expiration",
translation::MULTIPLAYER_DISCONNECT_BANNED_EXPIRATION,
[TextComponent::text(
expires.format(FORMAT_DESCRIPTION).unwrap(),
)],
@@ -198,7 +199,7 @@ pub async fn can_not_join(
if ops.get_entry(&profile.id).is_none() && !whitelist.is_whitelisted(profile) {
return Some(TextComponent::translate(
"multiplayer.disconnect.not_whitelisted",
translation::MULTIPLAYER_DISCONNECT_NOT_WHITELISTED,
&[],
));
}
@@ -212,12 +213,12 @@ pub async fn can_not_join(
.get_entry(&address.ip())
{
let text = TextComponent::translate(
"multiplayer.disconnect.banned_ip.reason",
translation::MULTIPLAYER_DISCONNECT_BANNED_IP_REASON,
[TextComponent::text(entry.reason.clone())],
);
return Some(match entry.expires {
Some(expires) => text.add_child(TextComponent::translate(
"multiplayer.disconnect.banned_ip.expiration",
translation::MULTIPLAYER_DISCONNECT_BANNED_IP_EXPIRATION,
[TextComponent::text(
expires.format(FORMAT_DESCRIPTION).unwrap(),
)],

View File

@@ -2,6 +2,7 @@ use std::sync::atomic::{AtomicBool, AtomicI32, AtomicI64, Ordering};
use std::time::Instant;
use crossbeam::atomic::AtomicCell;
use pumpkin_data::translation;
use pumpkin_protocol::java::client::play::{CSystemChatMessage, CTickingState, CTickingStep};
use pumpkin_util::text::{TextComponent, color::NamedColor};
@@ -160,7 +161,7 @@ impl ServerTickRateManager {
let mspt = time_spent_ms / total_sprinted_ticks as f64;
TextComponent::translate(
"commands.tick.sprint.report",
translation::COMMANDS_TICK_SPRINT_REPORT,
[
TextComponent::text(format!("{tps:.2}")),
TextComponent::text(format!("{mspt:.2}")),
@@ -168,7 +169,7 @@ impl ServerTickRateManager {
)
} else {
// This is the message for `/tick sprint stop` or a zero-tick sprint.
TextComponent::translate("commands.tick.sprint.stop.success", [])
TextComponent::translate(translation::COMMANDS_TICK_SPRINT_STOP_SUCCESS, [])
};
// Construct the final component with the [Server: ...] wrapper

View File

@@ -52,7 +52,7 @@ use pumpkin_data::{
sound::{Sound, SoundCategory},
world::{RAW, WorldEvent},
};
use pumpkin_data::{BlockDirection, BlockState};
use pumpkin_data::{BlockDirection, BlockState, translation};
use pumpkin_inventory::screen_handler::InventoryPlayer;
use pumpkin_nbt::{compound::NbtCompound, to_bytes_unnamed};
use pumpkin_protocol::bedrock::client::set_actor_data::{
@@ -2475,7 +2475,7 @@ impl World {
let current_players = self.players.load();
player.clone().spawn_task(async move {
let msg_comp = TextComponent::translate(
"multiplayer.player.joined",
translation::MULTIPLAYER_PLAYER_JOINED,
[TextComponent::text(player.gameprofile.name.clone())],
)
.color_named(NamedColor::Yellow);
@@ -2539,7 +2539,7 @@ impl World {
if fire_event {
let msg_comp = TextComponent::translate(
"multiplayer.player.left",
translation::MULTIPLAYER_PLAYER_LEFT,
[TextComponent::text(player.gameprofile.name.clone())],
)
.color_named(NamedColor::Yellow);