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

View File

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

View File

@ -97,6 +97,7 @@ pub struct TextComponentBase {
impl TextComponentBase {
/// Converts this component to an NBT compound tag.
#[expect(clippy::too_many_lines)]
#[must_use]
pub fn to_nbt_compound(&self) -> pumpkin_nbt::NbtCompound {
let mut compound = pumpkin_nbt::NbtCompound::new();
@ -189,6 +190,83 @@ impl TextComponentBase {
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() {
let list = self
.extra
@ -893,6 +971,8 @@ impl TextComponent {
self.0.content = Box::new(TextContent::Text { text: "".into() });
self.0.extra = colored_extra;
self.0.style.click_event = None;
self.0.style.hover_event = None;
self
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -87,18 +87,54 @@ pub enum NotInBounds {
impl From<NotInBounds> for CommandError {
fn from(value: NotInBounds) -> Self {
match value {
NotInBounds::LowerBound(val, min) => Self::CommandFailed(TextComponent::text(format!(
"{} must not be less than {}, found {}",
val.qualifier(),
min,
val
))),
NotInBounds::UpperBound(val, max) => Self::CommandFailed(TextComponent::text(format!(
"{} must not be more than {}, found {}",
val.qualifier(),
max,
val
))),
NotInBounds::LowerBound(val, min) => {
let (key, min_text, val_text) = match val {
Number::F64(_) | Number::F32(_) => (
pumpkin_data::translation::java::ARGUMENT_DOUBLE_LOW,
min.to_string(),
val.to_string(),
),
Number::I32(_) => (
pumpkin_data::translation::java::ARGUMENT_INTEGER_LOW,
min.to_string(),
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 {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::F64(v) => write!(f, "{v:.2}"),
Self::F32(v) => write!(f, "{v:.2}"),
Self::F64(v) => write!(f, "{v}"),
Self::F32(v) => write!(f, "{v}"),
Self::I32(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)) => {
Sound::from_name(name.strip_prefix("minecraft:").unwrap_or(name)).map_or_else(
|| {
Err(CommandError::CommandFailed(TextComponent::text(format!(
"Sound {name} does not exist."
))))
Err(CommandError::CommandFailed(TextComponent::translate_cross(
pumpkin_data::translation::java::ARGUMENT_ID_INVALID,
pumpkin_data::translation::java::ARGUMENT_ID_INVALID,
[],
)))
},
Result::Ok,
)

View File

@ -54,8 +54,10 @@ impl<'a> FindArg<'a> for SummonableEntitiesArgumentConsumer {
Some(Arg::Block(name)) => {
EntityType::from_name(name.strip_prefix("minecraft:").unwrap_or(name)).map_or_else(
|| {
Err(CommandError::CommandFailed(TextComponent::text(
"Can't find Entity",
Err(CommandError::CommandFailed(TextComponent::translate_cross(
pumpkin_data::translation::java::ARGUMENT_ENTITY_INVALID,
pumpkin_data::translation::java::ARGUMENT_ENTITY_INVALID,
[],
)))
},
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)]
impl CommandExecutor for Executor {
fn execute<'a>(
@ -94,14 +201,15 @@ impl CommandExecutor for Executor {
profile,
contributors.len()
);
sender
.send_message(
TextComponent::custom(
"pumpkin",
"commands.pumpkin.version",
locale,
vec![TextComponent::text(version_string.clone())],
)
let mut msg = TextComponent::text("");
let version_translation = get_translation_text(
"pumpkin:commands.pumpkin.version",
locale,
vec![TextComponent::text(version_string.clone()).0],
);
msg = msg.add_child(
TextComponent::text(version_translation.clone())
.hover_event(HoverEvent::show_text(
TextComponent::text(format!("Commit: {GIT_HASH_FULL}\n\nContributors:\n"))
.add_child(
@ -111,131 +219,101 @@ impl CommandExecutor for Executor {
),
))
.click_event(ClickEvent::CopyToClipboard {
value: Cow::from(
get_translation_text(
"pumpkin:commands.pumpkin.version",
locale,
vec![TextComponent::text(version_string).0],
)
.replace('\n', ""),
),
value: Cow::from(version_translation.replace('\n', "")),
})
.color_named(NamedColor::Green)
.add_child(
TextComponent::custom(
"pumpkin",
"commands.pumpkin.description",
locale,
vec![],
)
.click_event(ClickEvent::CopyToClipboard {
value: Cow::from(
get_translation_text(
"pumpkin:commands.pumpkin.description",
locale,
vec![],
)
.replace('\n', ""),
),
})
.hover_event(HoverEvent::show_text(TextComponent::custom(
"pumpkin",
"commands.pumpkin.description.hover",
locale,
vec![],
)))
.color_named(NamedColor::White),
)
.add_child(
TextComponent::custom(
"pumpkin",
"commands.pumpkin.minecraft_version",
locale,
vec![
TextComponent::text(CURRENT_MC_VERSION.to_string()),
TextComponent::text(
CURRENT_MC_VERSION.protocol_version().to_string(),
),
],
)
.click_event(ClickEvent::CopyToClipboard {
value: Cow::from(
get_translation_text(
"pumpkin:commands.pumpkin.minecraft_version",
locale,
vec![
TextComponent::text(CURRENT_MC_VERSION.to_string()).0,
TextComponent::text(
CURRENT_MC_VERSION.protocol_version().to_string(),
)
.0,
],
)
.replace('\n', ""),
),
})
.hover_event(HoverEvent::show_text(TextComponent::custom(
"pumpkin",
"commands.pumpkin.minecraft_version.hover",
locale,
vec![],
)))
.color_named(NamedColor::Gold),
)
// https://pumpkinmc.org/
.add_child(
TextComponent::custom("pumpkin", "commands.pumpkin.github", locale, vec![])
.click_event(ClickEvent::OpenUrl {
url: Cow::from("https://github.com/Pumpkin-MC/Pumpkin"),
})
.hover_event(HoverEvent::show_text(TextComponent::custom(
"pumpkin",
"commands.pumpkin.github.hover",
locale,
vec![],
)))
.color_named(NamedColor::Blue)
.bold()
.underlined(),
)
// Spacing
.add_child(TextComponent::text(" "))
.add_child(
TextComponent::text("[Donate]")
.click_event(ClickEvent::OpenUrl {
url: Cow::from("https://pumpkinmc.org/donate/"),
})
.hover_event(HoverEvent::show_text(TextComponent::text(
"Click to open Donate",
)))
.rainbow()
.bold()
.underlined(),
)
// Spacing
.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;
.color_named(NamedColor::Green),
);
let desc_translation =
get_translation_text("pumpkin:commands.pumpkin.description", locale, vec![]);
let desc_hover_translation =
get_translation_text("pumpkin:commands.pumpkin.description.hover", locale, vec![]);
msg = msg.add_child(
TextComponent::text(desc_translation.clone())
.click_event(ClickEvent::CopyToClipboard {
value: Cow::from(desc_translation.replace('\n', "")),
})
.hover_event(HoverEvent::show_text(TextComponent::text(
desc_hover_translation,
)))
.color_named(NamedColor::White),
);
let mc_version_translation = get_translation_text(
"pumpkin:commands.pumpkin.minecraft_version",
locale,
vec![
TextComponent::text(CURRENT_MC_VERSION.to_string()).0,
TextComponent::text(CURRENT_MC_VERSION.protocol_version().to_string()).0,
],
);
let mc_version_hover_translation = get_translation_text(
"pumpkin:commands.pumpkin.minecraft_version.hover",
locale,
vec![],
);
msg = msg.add_child(
TextComponent::text(mc_version_translation.clone())
.click_event(ClickEvent::CopyToClipboard {
value: Cow::from(mc_version_translation.replace('\n', "")),
})
.hover_event(HoverEvent::show_text(TextComponent::text(
mc_version_hover_translation,
)))
.color_named(NamedColor::Gold),
);
let github_translation =
get_translation_text("pumpkin:commands.pumpkin.github", locale, vec![]);
let github_hover_translation =
get_translation_text("pumpkin:commands.pumpkin.github.hover", locale, vec![]);
msg = msg.add_child(
TextComponent::text(github_translation)
.click_event(ClickEvent::OpenUrl {
url: Cow::from("https://github.com/Pumpkin-MC/Pumpkin"),
})
.hover_event(HoverEvent::show_text(TextComponent::text(
github_hover_translation,
)))
.color_named(NamedColor::Blue)
.bold()
.underlined(),
);
msg = msg.add_child(TextComponent::text(" "));
let donators_hover = fetch_donators_hover();
msg = msg.add_child(
TextComponent::text("[Donate]")
.click_event(ClickEvent::OpenUrl {
url: Cow::from("https://pumpkinmc.org/donate/"),
})
.hover_event(HoverEvent::show_text(donators_hover))
.rainbow()
.bold()
.underlined(),
);
msg = msg.add_child(TextComponent::text(" "));
let website_translation =
get_translation_text("pumpkin:commands.pumpkin.website", locale, vec![]);
let website_hover_translation =
get_translation_text("pumpkin:commands.pumpkin.website.hover", locale, vec![]);
msg = msg.add_child(
TextComponent::text(website_translation)
.click_event(ClickEvent::OpenUrl {
url: Cow::from("https://pumpkinmc.org/"),
})
.hover_event(HoverEvent::show_text(TextComponent::text(
website_hover_translation,
)))
.color_named(NamedColor::Blue)
.bold()
.underlined(),
);
sender.send_message(msg).await;
// It makes total sense to return the number of
// contributors as the i32 result for this command.

View File

@ -5,6 +5,7 @@
compile_error!("Compiling for WASI targets is not supported!");
use pumpkin_data::packet::CURRENT_MC_VERSION;
use pumpkin_world::{CURRENT_BEDROCK_MC_PROTOCOL, CURRENT_BEDROCK_MC_VERSION};
use std::{
backtrace::{Backtrace, BacktraceStatus},
io::{self},
@ -66,7 +67,7 @@ async fn main() {
info!(
"{}",
TextComponent::text(format!(
"Starting {} {} Minecraft (Protocol {})",
"Starting {} {} Java Minecraft (Protocol {}) | {} Bedrock (Protocol {})",
TextComponent::text("Pumpkin")
.color_named(NamedColor::Gold)
.to_pretty_console(),
@ -74,6 +75,12 @@ async fn main() {
.color_named(NamedColor::Green)
.to_pretty_console(),
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)
.to_pretty_console()
))
@ -184,6 +191,15 @@ fn print_support_links_and_warning() {
.color_named(NamedColor::Aqua)
.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() {

View File

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