chore: use translations for ags

This commit is contained in:
Alexander Medvedev 2026-08-05 21:10:50 +02:00
parent 4eaa6ace31
commit 5d10c0d8a8
14 changed files with 401 additions and 188 deletions

22
Cargo.lock generated
View File

@ -2612,7 +2612,7 @@ dependencies = [
[[package]] [[package]]
name = "pumpkin" name = "pumpkin"
version = "0.1.0-dev+26.2" version = "0.1.0-dev+26.2-26.40"
dependencies = [ dependencies = [
"arc-swap", "arc-swap",
"base64 0.23.1", "base64 0.23.1",
@ -2675,7 +2675,7 @@ dependencies = [
[[package]] [[package]]
name = "pumpkin-api-macros" name = "pumpkin-api-macros"
version = "0.1.0-dev+26.2" version = "0.1.0-dev+26.2-26.40"
dependencies = [ dependencies = [
"proc-macro-error2", "proc-macro-error2",
"proc-macro2", "proc-macro2",
@ -2685,7 +2685,7 @@ dependencies = [
[[package]] [[package]]
name = "pumpkin-codecs" name = "pumpkin-codecs"
version = "0.1.0-dev+26.2" version = "0.1.0-dev+26.2-26.40"
dependencies = [ dependencies = [
"serde_json", "serde_json",
"tracing", "tracing",
@ -2693,7 +2693,7 @@ dependencies = [
[[package]] [[package]]
name = "pumpkin-config" name = "pumpkin-config"
version = "0.1.0-dev+26.2" version = "0.1.0-dev+26.2-26.40"
dependencies = [ dependencies = [
"pumpkin-util", "pumpkin-util",
"serde", "serde",
@ -2704,7 +2704,7 @@ dependencies = [
[[package]] [[package]]
name = "pumpkin-data" name = "pumpkin-data"
version = "0.1.0-dev+26.2" version = "0.1.0-dev+26.2-26.40"
dependencies = [ dependencies = [
"crc-fast", "crc-fast",
"criterion", "criterion",
@ -2717,7 +2717,7 @@ dependencies = [
[[package]] [[package]]
name = "pumpkin-inventory" name = "pumpkin-inventory"
version = "0.1.0-dev+26.2" version = "0.1.0-dev+26.2-26.40"
dependencies = [ dependencies = [
"pumpkin-data", "pumpkin-data",
"pumpkin-protocol", "pumpkin-protocol",
@ -2731,7 +2731,7 @@ dependencies = [
[[package]] [[package]]
name = "pumpkin-macros" name = "pumpkin-macros"
version = "0.1.0-dev+26.2" version = "0.1.0-dev+26.2-26.40"
dependencies = [ dependencies = [
"heck", "heck",
"proc-macro-error2", "proc-macro-error2",
@ -2742,7 +2742,7 @@ dependencies = [
[[package]] [[package]]
name = "pumpkin-nbt" name = "pumpkin-nbt"
version = "0.1.0-dev+26.2" version = "0.1.0-dev+26.2-26.40"
dependencies = [ dependencies = [
"bytes", "bytes",
"cesu8", "cesu8",
@ -2768,7 +2768,7 @@ dependencies = [
[[package]] [[package]]
name = "pumpkin-protocol" name = "pumpkin-protocol"
version = "0.1.0-dev+26.2" version = "0.1.0-dev+26.2-26.40"
dependencies = [ dependencies = [
"aes", "aes",
"async-compression", "async-compression",
@ -2792,7 +2792,7 @@ dependencies = [
[[package]] [[package]]
name = "pumpkin-util" name = "pumpkin-util"
version = "0.1.0-dev+26.2" version = "0.1.0-dev+26.2-26.40"
dependencies = [ dependencies = [
"base64 0.23.1", "base64 0.23.1",
"bytes", "bytes",
@ -2820,7 +2820,7 @@ dependencies = [
[[package]] [[package]]
name = "pumpkin-world" name = "pumpkin-world"
version = "0.1.0-dev+26.2" version = "0.1.0-dev+26.2-26.40"
dependencies = [ dependencies = [
"arc-swap", "arc-swap",
"bitflags", "bitflags",

View File

@ -77,7 +77,7 @@ module_name_repetitions = "allow"
struct_excessive_bools = "allow" struct_excessive_bools = "allow"
[workspace.package] [workspace.package]
version = "0.1.0-dev+26.2" version = "0.1.0-dev+26.2-26.40"
edition = "2024" edition = "2024"
rust-version = "1.95" rust-version = "1.95"
license = "GPL-3.0" license = "GPL-3.0"

View File

@ -97,6 +97,7 @@ pub struct TextComponentBase {
impl TextComponentBase { impl TextComponentBase {
/// Converts this component to an NBT compound tag. /// Converts this component to an NBT compound tag.
#[expect(clippy::too_many_lines)]
#[must_use] #[must_use]
pub fn to_nbt_compound(&self) -> pumpkin_nbt::NbtCompound { pub fn to_nbt_compound(&self) -> pumpkin_nbt::NbtCompound {
let mut compound = pumpkin_nbt::NbtCompound::new(); let mut compound = pumpkin_nbt::NbtCompound::new();
@ -189,6 +190,83 @@ impl TextComponentBase {
compound.put_byte("obfuscated", i8::from(obfuscated)); compound.put_byte("obfuscated", i8::from(obfuscated));
} }
if let Some(ref click) = self.style.click_event {
let mut click_tag = pumpkin_nbt::NbtCompound::new();
match click {
ClickEvent::OpenUrl { url } => {
click_tag.put_string("action", "open_url".to_string());
click_tag.put_string("url", url.to_string());
}
ClickEvent::OpenFile { path } => {
click_tag.put_string("action", "open_file".to_string());
click_tag.put_string("path", path.to_string());
}
ClickEvent::RunCommand { command } => {
click_tag.put_string("action", "run_command".to_string());
click_tag.put_string("command", command.to_string());
}
ClickEvent::SuggestCommand { command } => {
click_tag.put_string("action", "suggest_command".to_string());
click_tag.put_string("command", command.to_string());
}
ClickEvent::ChangePage { page } => {
click_tag.put_string("action", "change_page".to_string());
click_tag.put_int("page", *page as i32);
}
ClickEvent::CopyToClipboard { value } => {
click_tag.put_string("action", "copy_to_clipboard".to_string());
click_tag.put_string("value", value.to_string());
}
}
compound.put_compound("click_event", click_tag);
}
if let Some(ref hover) = self.style.hover_event {
let mut hover_tag = pumpkin_nbt::NbtCompound::new();
match hover {
HoverEvent::ShowText { value } => {
hover_tag.put_string("action", "show_text".to_string());
if value.len() == 1 {
hover_tag.put_compound("value", value[0].to_nbt_compound());
} else {
let list = value
.iter()
.map(|e| pumpkin_nbt::tag::NbtTag::Compound(e.to_nbt_compound()))
.collect();
hover_tag.put_list("value", list);
}
}
HoverEvent::ShowItem { id, count } => {
hover_tag.put_string("action", "show_item".to_string());
let mut item_tag = pumpkin_nbt::NbtCompound::new();
item_tag.put_string("id", id.to_string());
if let Some(cnt) = count {
item_tag.put_int("count", *cnt);
}
hover_tag.put_compound("item", item_tag);
}
HoverEvent::ShowEntity { id, uuid, name } => {
hover_tag.put_string("action", "show_entity".to_string());
let mut entity_tag = pumpkin_nbt::NbtCompound::new();
entity_tag.put_string("id", id.to_string());
entity_tag.put_string("uuid", uuid.to_string());
if let Some(n) = name {
if n.len() == 1 {
entity_tag.put_compound("name", n[0].to_nbt_compound());
} else {
let list = n
.iter()
.map(|e| pumpkin_nbt::tag::NbtTag::Compound(e.to_nbt_compound()))
.collect();
entity_tag.put_list("name", list);
}
}
hover_tag.put_compound("entity", entity_tag);
}
}
compound.put_compound("hover_event", hover_tag);
}
if !self.extra.is_empty() { if !self.extra.is_empty() {
let list = self let list = self
.extra .extra
@ -893,6 +971,8 @@ impl TextComponent {
self.0.content = Box::new(TextContent::Text { text: "".into() }); self.0.content = Box::new(TextContent::Text { text: "".into() });
self.0.extra = colored_extra; self.0.extra = colored_extra;
self.0.style.click_event = None;
self.0.style.hover_event = None;
self self
} }

View File

@ -271,8 +271,8 @@ impl std::fmt::Display for JavaMinecraftVersion {
pub enum BedrockMinecraftVersion { pub enum BedrockMinecraftVersion {
/// 1.21: Tricky Trials. /// 1.21: Tricky Trials.
V_1_21, V_1_21,
/// 1.26.30 /// 1.26.40
V_1_26_30, V_1_26_40,
/// Fallback for unrecognized protocol versions. /// Fallback for unrecognized protocol versions.
Unknown, Unknown,
} }
@ -285,7 +285,7 @@ impl BedrockMinecraftVersion {
pub const fn protocol_version(&self) -> i32 { pub const fn protocol_version(&self) -> i32 {
match self { match self {
Self::V_1_21 => 671, Self::V_1_21 => 671,
Self::V_1_26_30 => 1001, Self::V_1_26_40 => 2168,
Self::Unknown => -1, Self::Unknown => -1,
} }
} }
@ -297,7 +297,7 @@ impl BedrockMinecraftVersion {
pub const fn from_protocol(protocol: u32) -> Self { pub const fn from_protocol(protocol: u32) -> Self {
match protocol { match protocol {
671 => Self::V_1_21, 671 => Self::V_1_21,
1001 => Self::V_1_26_30, 2168 => Self::V_1_26_40,
_ => Self::Unknown, _ => Self::Unknown,
} }
} }
@ -307,7 +307,7 @@ impl std::fmt::Display for BedrockMinecraftVersion {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
Self::V_1_21 => write!(f, "1.21"), Self::V_1_21 => write!(f, "1.21"),
Self::V_1_26_30 => write!(f, "1.26.30"), Self::V_1_26_40 => write!(f, "1.26.40"),
Self::Unknown => write!(f, "unknown"), Self::Unknown => write!(f, "unknown"),
} }
} }

View File

@ -13,7 +13,9 @@ use super::{
}, },
chunk_noise_router::ChunkNoiseFunctionComponent, chunk_noise_router::ChunkNoiseFunctionComponent,
density_function::{NoiseFunctionComponentRange, PassThrough}, density_function::{NoiseFunctionComponentRange, PassThrough},
proto_noise_router::{ProtoMultiNoiseRouter, ProtoNoiseFunctionComponent}, proto_noise_router::{
BEARDIFIER_ZERO_CONSTANT, ProtoMultiNoiseRouter, ProtoNoiseFunctionComponent,
},
}; };
pub struct MultiNoiseSamplerBuilderOptions { pub struct MultiNoiseSamplerBuilderOptions {
@ -136,13 +138,9 @@ impl<'a> MultiNoiseSampler<'a> {
ProtoNoiseFunctionComponent::PassThrough(pass_through) => { ProtoNoiseFunctionComponent::PassThrough(pass_through) => {
ChunkNoiseFunctionComponent::PassThrough(pass_through.clone()) ChunkNoiseFunctionComponent::PassThrough(pass_through.clone())
} }
ProtoNoiseFunctionComponent::Beardifier(_) => ChunkNoiseFunctionComponent::Independent( ProtoNoiseFunctionComponent::Beardifier(_) => {
Box::leak(Box::new( ChunkNoiseFunctionComponent::Independent(&BEARDIFIER_ZERO_CONSTANT)
crate::generation::noise::router::proto_noise_router::IndependentProtoNoiseFunctionComponent::Constant( }
crate::generation::noise::router::density_function::math::Constant::new(0.0),
),
)),
),
ProtoNoiseFunctionComponent::Wrapper(wrapper) => { ProtoNoiseFunctionComponent::Wrapper(wrapper) => {
//NOTE: Due to our previous invariant with the proto-function, it is guaranteed //NOTE: Due to our previous invariant with the proto-function, it is guaranteed
// that the wrapped function is already on the stack // that the wrapped function is already on the stack

View File

@ -29,6 +29,9 @@ use super::{
}; };
use pumpkin_util::math::vector3::Vector3; use pumpkin_util::math::vector3::Vector3;
pub static BEARDIFIER_ZERO_CONSTANT: IndependentProtoNoiseFunctionComponent =
IndependentProtoNoiseFunctionComponent::Constant(Constant::new(0.0));
pub enum IndependentProtoNoiseFunctionComponent { pub enum IndependentProtoNoiseFunctionComponent {
Constant(Constant), Constant(Constant),
EndIsland(EndIsland), EndIsland(EndIsland),

View File

@ -11,7 +11,9 @@ use super::{
}, },
chunk_noise_router::ChunkNoiseFunctionComponent, chunk_noise_router::ChunkNoiseFunctionComponent,
density_function::{NoiseFunctionComponentRange, PassThrough}, density_function::{NoiseFunctionComponentRange, PassThrough},
proto_noise_router::{ProtoNoiseFunctionComponent, ProtoSurfaceEstimator}, proto_noise_router::{
BEARDIFIER_ZERO_CONSTANT, ProtoNoiseFunctionComponent, ProtoSurfaceEstimator,
},
}; };
pub struct SurfaceHeightSamplerBuilderOptions { pub struct SurfaceHeightSamplerBuilderOptions {
@ -140,13 +142,9 @@ impl<'a> SurfaceHeightEstimateSampler<'a> {
ProtoNoiseFunctionComponent::PassThrough(pass_through) => { ProtoNoiseFunctionComponent::PassThrough(pass_through) => {
ChunkNoiseFunctionComponent::PassThrough(pass_through.clone()) ChunkNoiseFunctionComponent::PassThrough(pass_through.clone())
} }
ProtoNoiseFunctionComponent::Beardifier(_) => ChunkNoiseFunctionComponent::Independent( ProtoNoiseFunctionComponent::Beardifier(_) => {
Box::leak(Box::new( ChunkNoiseFunctionComponent::Independent(&BEARDIFIER_ZERO_CONSTANT)
crate::generation::noise::router::proto_noise_router::IndependentProtoNoiseFunctionComponent::Constant( }
crate::generation::noise::router::density_function::math::Constant::new(0.0),
),
)),
),
ProtoNoiseFunctionComponent::Wrapper(wrapper) => { ProtoNoiseFunctionComponent::Wrapper(wrapper) => {
//NOTE: Due to our previous invariant with the proto-function, it is guaranteed //NOTE: Due to our previous invariant with the proto-function, it is guaranteed
// that the wrapped function is already on the stack // that the wrapped function is already on the stack

View File

@ -22,8 +22,8 @@ pub mod world;
pub mod world_info; pub mod world_info;
pub const CURRENT_MC_VERSION: &str = "26.2"; pub const CURRENT_MC_VERSION: &str = "26.2";
pub const CURRENT_BEDROCK_MC_VERSION: &str = "1.26.30"; pub const CURRENT_BEDROCK_MC_VERSION: &str = "1.26.40";
pub const CURRENT_BEDROCK_MC_PROTOCOL: u32 = 1001; pub const CURRENT_BEDROCK_MC_PROTOCOL: u32 = 2168;
#[macro_export] #[macro_export]
macro_rules! global_path { macro_rules! global_path {

View File

@ -87,18 +87,54 @@ pub enum NotInBounds {
impl From<NotInBounds> for CommandError { impl From<NotInBounds> for CommandError {
fn from(value: NotInBounds) -> Self { fn from(value: NotInBounds) -> Self {
match value { match value {
NotInBounds::LowerBound(val, min) => Self::CommandFailed(TextComponent::text(format!( NotInBounds::LowerBound(val, min) => {
"{} must not be less than {}, found {}", let (key, min_text, val_text) = match val {
val.qualifier(), Number::F64(_) | Number::F32(_) => (
min, pumpkin_data::translation::java::ARGUMENT_DOUBLE_LOW,
val min.to_string(),
))), val.to_string(),
NotInBounds::UpperBound(val, max) => Self::CommandFailed(TextComponent::text(format!( ),
"{} must not be more than {}, found {}", Number::I32(_) => (
val.qualifier(), pumpkin_data::translation::java::ARGUMENT_INTEGER_LOW,
max, min.to_string(),
val val.to_string(),
))), ),
Number::I64(_) => (
pumpkin_data::translation::java::ARGUMENT_LONG_LOW,
min.to_string(),
val.to_string(),
),
};
Self::CommandFailed(TextComponent::translate_cross(
key,
key,
[TextComponent::text(min_text), TextComponent::text(val_text)],
))
}
NotInBounds::UpperBound(val, max) => {
let (key, max_text, val_text) = match val {
Number::F64(_) | Number::F32(_) => (
pumpkin_data::translation::java::ARGUMENT_DOUBLE_BIG,
max.to_string(),
val.to_string(),
),
Number::I32(_) => (
pumpkin_data::translation::java::ARGUMENT_INTEGER_BIG,
max.to_string(),
val.to_string(),
),
Number::I64(_) => (
pumpkin_data::translation::java::ARGUMENT_LONG_BIG,
max.to_string(),
val.to_string(),
),
};
Self::CommandFailed(TextComponent::translate_cross(
key,
key,
[TextComponent::text(max_text), TextComponent::text(val_text)],
))
}
} }
} }
} }
@ -124,8 +160,8 @@ impl Number {
impl Display for Number { impl Display for Number {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self { match self {
Self::F64(v) => write!(f, "{v:.2}"), Self::F64(v) => write!(f, "{v}"),
Self::F32(v) => write!(f, "{v:.2}"), Self::F32(v) => write!(f, "{v}"),
Self::I32(v) => write!(f, "{v}"), Self::I32(v) => write!(f, "{v}"),
Self::I64(v) => write!(f, "{v}"), Self::I64(v) => write!(f, "{v}"),
} }

View File

@ -54,9 +54,11 @@ impl<'a> FindArg<'a> for SoundArgumentConsumer {
Some(Arg::Block(name)) => { Some(Arg::Block(name)) => {
Sound::from_name(name.strip_prefix("minecraft:").unwrap_or(name)).map_or_else( Sound::from_name(name.strip_prefix("minecraft:").unwrap_or(name)).map_or_else(
|| { || {
Err(CommandError::CommandFailed(TextComponent::text(format!( Err(CommandError::CommandFailed(TextComponent::translate_cross(
"Sound {name} does not exist." pumpkin_data::translation::java::ARGUMENT_ID_INVALID,
)))) pumpkin_data::translation::java::ARGUMENT_ID_INVALID,
[],
)))
}, },
Result::Ok, Result::Ok,
) )

View File

@ -54,8 +54,10 @@ impl<'a> FindArg<'a> for SummonableEntitiesArgumentConsumer {
Some(Arg::Block(name)) => { Some(Arg::Block(name)) => {
EntityType::from_name(name.strip_prefix("minecraft:").unwrap_or(name)).map_or_else( EntityType::from_name(name.strip_prefix("minecraft:").unwrap_or(name)).map_or_else(
|| { || {
Err(CommandError::CommandFailed(TextComponent::text( Err(CommandError::CommandFailed(TextComponent::translate_cross(
"Can't find Entity", pumpkin_data::translation::java::ARGUMENT_ENTITY_INVALID,
pumpkin_data::translation::java::ARGUMENT_ENTITY_INVALID,
[],
))) )))
}, },
Result::Ok, Result::Ok,

View File

@ -66,6 +66,113 @@ fn extract_next_url(header: &str) -> Option<String> {
}) })
} }
#[derive(Deserialize)]
struct Donator {
name: String,
tier: String,
tier_slug: String,
}
#[derive(Deserialize)]
struct DonatorResponse {
current: Vec<Donator>,
#[allow(dead_code)]
past: Vec<Donator>,
}
fn tier_priority(tier_slug: &str, tier_name: &str) -> u32 {
let s = format!("{tier_slug} {tier_name}").to_lowercase();
if s.contains("corporate platinum") || s.contains("corp platinum") {
1
} else if s.contains("corporate gold") || s.contains("corp gold") {
2
} else if s.contains("corporate silver") || s.contains("corp silver") {
3
} else if s.contains("corporate bronze") || s.contains("corp bronze") {
4
} else if s.contains("diamond") {
5
} else if s.contains("titanium") {
6
} else if s.contains("platinum") {
7
} else if s.contains("gold") {
8
} else if s.contains("silver") {
9
} else if s.contains("bronze") {
10
} else {
11
}
}
fn tier_color(tier_slug: &str, tier_name: &str) -> NamedColor {
let s = format!("{tier_slug} {tier_name}").to_lowercase();
if s.contains("diamond") {
NamedColor::Aqua
} else if s.contains("titanium") {
NamedColor::DarkAqua
} else if s.contains("platinum") {
NamedColor::LightPurple
} else if s.contains("gold") {
NamedColor::Gold
} else if s.contains("silver") {
NamedColor::Gray
} else if s.contains("bronze") {
NamedColor::DarkRed
} else {
NamedColor::White
}
}
fn fetch_donators_hover() -> TextComponent {
let url = "https://market.pumpkinmc.org/api/v1/rest/donators";
let response = ureq::get(url).header("User-Agent", "Pumpkin-MC").call();
let mut donators_text = TextComponent::text("Click to open Donate\n\nDonators:\n");
if let Ok(mut res) = response
&& let Ok(data) = res.body_mut().read_json::<DonatorResponse>()
{
let mut current = data.current;
current.sort_by(|a, b| {
let prio_a = tier_priority(&a.tier_slug, &a.tier);
let prio_b = tier_priority(&b.tier_slug, &b.tier);
prio_a
.cmp(&prio_b)
.then_with(|| a.tier.cmp(&b.tier))
.then_with(|| a.name.cmp(&b.name))
});
if current.is_empty() {
donators_text = donators_text.add_child(TextComponent::text("No active donators"));
} else {
let mut current_tier = String::new();
for donator in current {
if donator.tier != current_tier {
current_tier.clone_from(&donator.tier);
let color = tier_color(&donator.tier_slug, &donator.tier);
donators_text = donators_text.add_child(
TextComponent::text(format!("\n{current_tier}:\n"))
.color_named(color)
.bold(),
);
}
let color = tier_color(&donator.tier_slug, &donator.tier);
donators_text = donators_text.add_child(
TextComponent::text(format!(" • {}\n", donator.name)).color_named(color),
);
}
}
return donators_text;
}
donators_text.add_child(TextComponent::text("Unable to load donators"))
}
#[expect(clippy::too_many_lines)] #[expect(clippy::too_many_lines)]
impl CommandExecutor for Executor { impl CommandExecutor for Executor {
fn execute<'a>( fn execute<'a>(
@ -94,14 +201,15 @@ impl CommandExecutor for Executor {
profile, profile,
contributors.len() contributors.len()
); );
sender let mut msg = TextComponent::text("");
.send_message(
TextComponent::custom( let version_translation = get_translation_text(
"pumpkin", "pumpkin:commands.pumpkin.version",
"commands.pumpkin.version", locale,
locale, vec![TextComponent::text(version_string.clone()).0],
vec![TextComponent::text(version_string.clone())], );
) msg = msg.add_child(
TextComponent::text(version_translation.clone())
.hover_event(HoverEvent::show_text( .hover_event(HoverEvent::show_text(
TextComponent::text(format!("Commit: {GIT_HASH_FULL}\n\nContributors:\n")) TextComponent::text(format!("Commit: {GIT_HASH_FULL}\n\nContributors:\n"))
.add_child( .add_child(
@ -111,131 +219,101 @@ impl CommandExecutor for Executor {
), ),
)) ))
.click_event(ClickEvent::CopyToClipboard { .click_event(ClickEvent::CopyToClipboard {
value: Cow::from( value: Cow::from(version_translation.replace('\n', "")),
get_translation_text(
"pumpkin:commands.pumpkin.version",
locale,
vec![TextComponent::text(version_string).0],
)
.replace('\n', ""),
),
}) })
.color_named(NamedColor::Green) .color_named(NamedColor::Green),
.add_child( );
TextComponent::custom(
"pumpkin", let desc_translation =
"commands.pumpkin.description", get_translation_text("pumpkin:commands.pumpkin.description", locale, vec![]);
locale, let desc_hover_translation =
vec![], get_translation_text("pumpkin:commands.pumpkin.description.hover", locale, vec![]);
) msg = msg.add_child(
.click_event(ClickEvent::CopyToClipboard { TextComponent::text(desc_translation.clone())
value: Cow::from( .click_event(ClickEvent::CopyToClipboard {
get_translation_text( value: Cow::from(desc_translation.replace('\n', "")),
"pumpkin:commands.pumpkin.description", })
locale, .hover_event(HoverEvent::show_text(TextComponent::text(
vec![], desc_hover_translation,
) )))
.replace('\n', ""), .color_named(NamedColor::White),
), );
})
.hover_event(HoverEvent::show_text(TextComponent::custom( let mc_version_translation = get_translation_text(
"pumpkin", "pumpkin:commands.pumpkin.minecraft_version",
"commands.pumpkin.description.hover", locale,
locale, vec![
vec![], TextComponent::text(CURRENT_MC_VERSION.to_string()).0,
))) TextComponent::text(CURRENT_MC_VERSION.protocol_version().to_string()).0,
.color_named(NamedColor::White), ],
) );
.add_child( let mc_version_hover_translation = get_translation_text(
TextComponent::custom( "pumpkin:commands.pumpkin.minecraft_version.hover",
"pumpkin", locale,
"commands.pumpkin.minecraft_version", vec![],
locale, );
vec![ msg = msg.add_child(
TextComponent::text(CURRENT_MC_VERSION.to_string()), TextComponent::text(mc_version_translation.clone())
TextComponent::text( .click_event(ClickEvent::CopyToClipboard {
CURRENT_MC_VERSION.protocol_version().to_string(), value: Cow::from(mc_version_translation.replace('\n', "")),
), })
], .hover_event(HoverEvent::show_text(TextComponent::text(
) mc_version_hover_translation,
.click_event(ClickEvent::CopyToClipboard { )))
value: Cow::from( .color_named(NamedColor::Gold),
get_translation_text( );
"pumpkin:commands.pumpkin.minecraft_version",
locale, let github_translation =
vec![ get_translation_text("pumpkin:commands.pumpkin.github", locale, vec![]);
TextComponent::text(CURRENT_MC_VERSION.to_string()).0, let github_hover_translation =
TextComponent::text( get_translation_text("pumpkin:commands.pumpkin.github.hover", locale, vec![]);
CURRENT_MC_VERSION.protocol_version().to_string(), msg = msg.add_child(
) TextComponent::text(github_translation)
.0, .click_event(ClickEvent::OpenUrl {
], url: Cow::from("https://github.com/Pumpkin-MC/Pumpkin"),
) })
.replace('\n', ""), .hover_event(HoverEvent::show_text(TextComponent::text(
), github_hover_translation,
}) )))
.hover_event(HoverEvent::show_text(TextComponent::custom( .color_named(NamedColor::Blue)
"pumpkin", .bold()
"commands.pumpkin.minecraft_version.hover", .underlined(),
locale, );
vec![],
))) msg = msg.add_child(TextComponent::text(" "));
.color_named(NamedColor::Gold),
) let donators_hover = fetch_donators_hover();
// https://pumpkinmc.org/ msg = msg.add_child(
.add_child( TextComponent::text("[Donate]")
TextComponent::custom("pumpkin", "commands.pumpkin.github", locale, vec![]) .click_event(ClickEvent::OpenUrl {
.click_event(ClickEvent::OpenUrl { url: Cow::from("https://pumpkinmc.org/donate/"),
url: Cow::from("https://github.com/Pumpkin-MC/Pumpkin"), })
}) .hover_event(HoverEvent::show_text(donators_hover))
.hover_event(HoverEvent::show_text(TextComponent::custom( .rainbow()
"pumpkin", .bold()
"commands.pumpkin.github.hover", .underlined(),
locale, );
vec![],
))) msg = msg.add_child(TextComponent::text(" "));
.color_named(NamedColor::Blue)
.bold() let website_translation =
.underlined(), get_translation_text("pumpkin:commands.pumpkin.website", locale, vec![]);
) let website_hover_translation =
// Spacing get_translation_text("pumpkin:commands.pumpkin.website.hover", locale, vec![]);
.add_child(TextComponent::text(" ")) msg = msg.add_child(
.add_child( TextComponent::text(website_translation)
TextComponent::text("[Donate]") .click_event(ClickEvent::OpenUrl {
.click_event(ClickEvent::OpenUrl { url: Cow::from("https://pumpkinmc.org/"),
url: Cow::from("https://pumpkinmc.org/donate/"), })
}) .hover_event(HoverEvent::show_text(TextComponent::text(
.hover_event(HoverEvent::show_text(TextComponent::text( website_hover_translation,
"Click to open Donate", )))
))) .color_named(NamedColor::Blue)
.rainbow() .bold()
.bold() .underlined(),
.underlined(), );
)
// Spacing sender.send_message(msg).await;
.add_child(TextComponent::text(" "))
.add_child(
TextComponent::custom(
"pumpkin",
"commands.pumpkin.website",
locale,
vec![],
)
.click_event(ClickEvent::OpenUrl {
url: Cow::from("https://pumpkinmc.org/"),
})
.hover_event(HoverEvent::show_text(TextComponent::custom(
"pumpkin",
"commands.pumpkin.website.hover",
locale,
vec![],
)))
.color_named(NamedColor::Blue)
.bold()
.underlined(),
),
)
.await;
// It makes total sense to return the number of // It makes total sense to return the number of
// contributors as the i32 result for this command. // contributors as the i32 result for this command.

View File

@ -5,6 +5,7 @@
compile_error!("Compiling for WASI targets is not supported!"); compile_error!("Compiling for WASI targets is not supported!");
use pumpkin_data::packet::CURRENT_MC_VERSION; use pumpkin_data::packet::CURRENT_MC_VERSION;
use pumpkin_world::{CURRENT_BEDROCK_MC_PROTOCOL, CURRENT_BEDROCK_MC_VERSION};
use std::{ use std::{
backtrace::{Backtrace, BacktraceStatus}, backtrace::{Backtrace, BacktraceStatus},
io::{self}, io::{self},
@ -66,7 +67,7 @@ async fn main() {
info!( info!(
"{}", "{}",
TextComponent::text(format!( TextComponent::text(format!(
"Starting {} {} Minecraft (Protocol {})", "Starting {} {} Java Minecraft (Protocol {}) | {} Bedrock (Protocol {})",
TextComponent::text("Pumpkin") TextComponent::text("Pumpkin")
.color_named(NamedColor::Gold) .color_named(NamedColor::Gold)
.to_pretty_console(), .to_pretty_console(),
@ -74,6 +75,12 @@ async fn main() {
.color_named(NamedColor::Green) .color_named(NamedColor::Green)
.to_pretty_console(), .to_pretty_console(),
TextComponent::text(CURRENT_MC_VERSION.protocol_version().to_string()) TextComponent::text(CURRENT_MC_VERSION.protocol_version().to_string())
.color_named(NamedColor::DarkBlue)
.to_pretty_console(),
TextComponent::text(CURRENT_BEDROCK_MC_VERSION)
.color_named(NamedColor::Gold)
.to_pretty_console(),
TextComponent::text(CURRENT_BEDROCK_MC_PROTOCOL.to_string())
.color_named(NamedColor::DarkBlue) .color_named(NamedColor::DarkBlue)
.to_pretty_console() .to_pretty_console()
)) ))
@ -184,6 +191,15 @@ fn print_support_links_and_warning() {
.color_named(NamedColor::Aqua) .color_named(NamedColor::Aqua)
.to_pretty_console() .to_pretty_console()
); );
info!(
"Consider {} to {}",
TextComponent::text("Donating")
.color_named(NamedColor::DarkPurple)
.to_pretty_console(),
TextComponent::text("https://pumpkinmc.org/donate/")
.color_named(NamedColor::Gold)
.to_pretty_console()
);
} }
fn handle_interrupt() { fn handle_interrupt() {

View File

@ -111,7 +111,7 @@ const fn to_wasm_bedrock_version(
) -> pumpkin::plugin::player::BedrockMinecraftVersion { ) -> pumpkin::plugin::player::BedrockMinecraftVersion {
match version { match version {
BedrockMinecraftVersion::V_1_21 => pumpkin::plugin::player::BedrockMinecraftVersion::V121, BedrockMinecraftVersion::V_1_21 => pumpkin::plugin::player::BedrockMinecraftVersion::V121,
BedrockMinecraftVersion::V_1_26_30 => { BedrockMinecraftVersion::V_1_26_40 => {
pumpkin::plugin::player::BedrockMinecraftVersion::V12630 pumpkin::plugin::player::BedrockMinecraftVersion::V12630
} }
BedrockMinecraftVersion::Unknown => { BedrockMinecraftVersion::Unknown => {