1
2
Fork 0
mirror of https://github.com/mat-1/azalea.git synced 2025-08-02 14:26:04 +00:00

azalea-chat now checks language files

This commit is contained in:
mat 2022-05-08 18:38:22 -05:00
parent a9a8834b3a
commit 7c742347a7
11 changed files with 5424 additions and 20 deletions

44
Cargo.lock generated
View file

@ -86,6 +86,7 @@ version = "0.1.0"
name = "azalea-chat" name = "azalea-chat"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"azalea-language",
"lazy_static", "lazy_static",
"serde", "serde",
"serde_json", "serde_json",
@ -123,6 +124,15 @@ dependencies = [
"sha-1", "sha-1",
] ]
[[package]]
name = "azalea-language"
version = "0.1.0"
dependencies = [
"lazy_static",
"serde",
"serde_json",
]
[[package]] [[package]]
name = "azalea-nbt" name = "azalea-nbt"
version = "0.1.0" version = "0.1.0"
@ -386,7 +396,7 @@ checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1"
dependencies = [ dependencies = [
"bstr", "bstr",
"csv-core", "csv-core",
"itoa", "itoa 0.4.8",
"ryu", "ryu",
"serde", "serde",
] ]
@ -620,6 +630,12 @@ version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
[[package]]
name = "itoa"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
[[package]] [[package]]
name = "js-sys" name = "js-sys"
version = "0.3.55" version = "0.3.55"
@ -1038,9 +1054,9 @@ dependencies = [
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.5.4" version = "1.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
dependencies = [ dependencies = [
"regex-syntax", "regex-syntax",
] ]
@ -1116,9 +1132,9 @@ checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.130" version = "1.0.137"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
@ -1135,9 +1151,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.130" version = "1.0.137"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -1146,11 +1162,11 @@ dependencies = [
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.72" version = "1.0.81"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0ffa0837f2dfa6fb90868c2b5468cad482e175f7dad97e7421951e663f2b527" checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c"
dependencies = [ dependencies = [
"itoa", "itoa 1.0.1",
"ryu", "ryu",
"serde", "serde",
] ]
@ -1213,9 +1229,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.82" version = "1.0.92"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" checksum = "7ff7c592601f11445996a06f8ad0c27f094a58857c2f89e97974ab9235b92c52"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -1278,9 +1294,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.18.0" version = "1.18.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f48b6d60512a392e34dbf7fd456249fd2de3c83669ab642e021903f4015185b" checksum = "4903bf0427cf68dddd5aa6a93220756f8be0c34fcfa9f5e6191e103e15a31395"
dependencies = [ dependencies = [
"bytes", "bytes",
"libc", "libc",

View file

@ -9,6 +9,7 @@ members = [
"azalea-nbt", "azalea-nbt",
"azalea-brigadier", "azalea-brigadier",
"azalea-crypto", "azalea-crypto",
"azalea-language",
] ]
[profile.release] [profile.release]

View file

@ -6,6 +6,7 @@ version = "0.1.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
azalea-language = {path = "../azalea-language"}
lazy_static = "1.4.0" lazy_static = "1.4.0"
serde = "^1.0.130" serde = "^1.0.130"
serde_json = "^1.0.72" serde_json = "^1.0.72"

View file

@ -63,14 +63,15 @@ impl Component {
for component in self.clone().into_iter() { for component in self.clone().into_iter() {
let component_text = match &component { let component_text = match &component {
Self::Text(c) => &c.text, Self::Text(c) => c.text.to_string(),
Self::Translatable(c) => &c.key, Self::Translatable(c) => c.to_string(),
}; };
let component_style = &component.get_base().style; let component_style = &component.get_base().style;
let ansi_text = running_style.compare_ansi(component_style, default_style); let ansi_text = running_style.compare_ansi(component_style, default_style);
built_string.push_str(&ansi_text); built_string.push_str(&ansi_text);
built_string.push_str(component_text); built_string.push_str(&component_text);
running_style.apply(component_style); running_style.apply(component_style);
} }
@ -123,7 +124,12 @@ impl<'de> Deserialize<'de> for Component {
let text = json.get("text").unwrap().as_str().unwrap_or("").to_string(); let text = json.get("text").unwrap().as_str().unwrap_or("").to_string();
component = Component::Text(TextComponent::new(text)); component = Component::Text(TextComponent::new(text));
} else if json.get("translate").is_some() { } else if json.get("translate").is_some() {
let translate = json.get("translate").unwrap().to_string(); let translate = json
.get("translate")
.unwrap()
.as_str()
.ok_or_else(|| de::Error::custom("\"translate\" must be a string"))?
.into();
if json.get("with").is_some() { if json.get("with").is_some() {
let with = json.get("with").unwrap().as_array().unwrap(); let with = json.get("with").unwrap().as_array().unwrap();
let mut with_array = Vec::with_capacity(with.len()); let mut with_array = Vec::with_capacity(with.len());
@ -136,7 +142,7 @@ impl<'de> Deserialize<'de> for Component {
&& text_component.base.style.is_empty() && text_component.base.style.is_empty()
{ {
with_array.push(StringOrComponent::String(text_component.text)); with_array.push(StringOrComponent::String(text_component.text));
break; continue;
} }
} }
with_array.push(StringOrComponent::Component( with_array.push(StringOrComponent::Component(

View file

@ -1,3 +1,5 @@
use std::fmt::{self, Formatter};
use crate::{base_component::BaseComponent, component::Component}; use crate::{base_component::BaseComponent, component::Component};
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -21,4 +23,157 @@ impl TranslatableComponent {
args, args,
} }
} }
pub fn read(&self) -> Result<String, fmt::Error> {
let template = azalea_language::get(&self.key).unwrap_or_else(|| &self.key);
// decode the % things
let mut result = String::new();
let mut i = 0;
let mut matched = 0;
// this code is ugly but it works
while i < template.len() {
if template.chars().nth(i).unwrap() == '%' {
let char_after = match template.chars().nth(i + 1) {
Some(c) => c,
None => {
result.push(template.chars().nth(i).unwrap());
break;
}
};
i += 1;
match char_after {
'%' => {
result.push('%');
}
's' => {
result.push_str(
&self
.args
.get(matched)
.unwrap_or(&StringOrComponent::String("".to_string()))
.to_string(),
);
matched += 1;
}
_ => {
// check if the char is a number
if let Some(d) = char_after.to_digit(10) {
// make sure the next two chars are $s
if let Some('$') = template.chars().nth(i + 1) {
if let Some('s') = template.chars().nth(i + 2) {
i += 2;
result.push_str(
&self
.args
.get((d - 1) as usize)
.unwrap_or(&StringOrComponent::String("".to_string()))
.to_string(),
);
} else {
return Err(fmt::Error);
}
} else {
return Err(fmt::Error);
}
} else {
i -= 1;
result.push('%');
}
}
}
} else {
result.push(template.chars().nth(i).unwrap());
}
i += 1
}
Ok(result.to_string())
}
}
impl fmt::Display for TranslatableComponent {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
write!(f, "{}", self.read()?)
}
}
impl fmt::Display for StringOrComponent {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
match self {
StringOrComponent::String(s) => write!(f, "{}", s),
StringOrComponent::Component(c) => write!(f, "{}", c.to_ansi(None)),
}
}
}
// tests
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_none() {
let c = TranslatableComponent::new("translation.test.none".to_string(), vec![]);
assert_eq!(c.read(), Ok("Hello, world!".to_string()));
}
#[test]
fn test_complex() {
let c = TranslatableComponent::new(
"translation.test.complex".to_string(),
vec![
StringOrComponent::String("a".to_string()),
StringOrComponent::String("b".to_string()),
StringOrComponent::String("c".to_string()),
StringOrComponent::String("d".to_string()),
],
);
// so true mojang
assert_eq!(
c.read(),
Ok("Prefix, ab again b and a lastly c and also a again!".to_string())
);
}
#[test]
fn test_escape() {
let c = TranslatableComponent::new(
"translation.test.escape".to_string(),
vec![
StringOrComponent::String("a".to_string()),
StringOrComponent::String("b".to_string()),
StringOrComponent::String("c".to_string()),
StringOrComponent::String("d".to_string()),
],
);
assert_eq!(c.read(), Ok("%s %a %%s %%b".to_string()));
}
#[test]
fn test_invalid() {
let c = TranslatableComponent::new(
"translation.test.invalid".to_string(),
vec![
StringOrComponent::String("a".to_string()),
StringOrComponent::String("b".to_string()),
StringOrComponent::String("c".to_string()),
StringOrComponent::String("d".to_string()),
],
);
assert_eq!(c.read(), Ok("hi %".to_string()));
}
#[test]
fn test_invalid2() {
let c = TranslatableComponent::new(
"translation.test.invalid2".to_string(),
vec![
StringOrComponent::String("a".to_string()),
StringOrComponent::String("b".to_string()),
StringOrComponent::String("c".to_string()),
StringOrComponent::String("d".to_string()),
],
);
assert_eq!(c.read(), Ok("hi % s".to_string()));
}
} }

View file

@ -4,6 +4,7 @@ use azalea_protocol::{
connect::{GameConnection, HandshakeConnection}, connect::{GameConnection, HandshakeConnection},
packets::{ packets::{
game::{ game::{
clientbound_chat_packet::ClientboundChatPacket,
serverbound_custom_payload_packet::ServerboundCustomPayloadPacket, serverbound_custom_payload_packet::ServerboundCustomPayloadPacket,
serverbound_keep_alive_packet::ServerboundKeepAlivePacket, GamePacket, serverbound_keep_alive_packet::ServerboundKeepAlivePacket, GamePacket,
}, },
@ -44,6 +45,7 @@ pub struct Client {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Event { pub enum Event {
Login, Login,
Chat(ClientboundChatPacket),
} }
/// Whether we should ignore errors when decoding packets. /// Whether we should ignore errors when decoding packets.
@ -309,6 +311,7 @@ impl Client {
} }
GamePacket::ClientboundChatPacket(p) => { GamePacket::ClientboundChatPacket(p) => {
println!("Got chat packet {:?}", p); println!("Got chat packet {:?}", p);
tx.send(Event::Chat(p.clone())).unwrap();
} }
GamePacket::ClientboundSoundPacket(p) => { GamePacket::ClientboundSoundPacket(p) => {
println!("Got sound packet {:?}", p); println!("Got sound packet {:?}", p);

View file

@ -0,0 +1,12 @@
[package]
edition = "2021"
name = "azalea-language"
version = "0.1.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
lazy_static = "1.4.0"
serde = "1.0.137"
serde_json = "1.0.81"
# tokio = {version = "1.18.2", features = ["fs"]}

View file

@ -0,0 +1,4 @@
# Azalea Assets
Translate Minecraft strings from their id.

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,38 @@
use lazy_static::lazy_static;
use std::collections::HashMap;
// use tokio::fs::File;
// pub struct Language {
// pub storage: HashMap<String, String>,
// }
// impl Language {
// pub async fn load() -> Self {
// // TODO: download from mojang's servers and cache somewhere
// let mut storage = HashMap::new();
// let mut file = File::open("en_us.json").unwrap();
// let mut contents = String::new();
// file.read_to_string(&mut contents).unwrap();
// let en_us: HashMap<String, String> = serde_json::from_str(&contents).unwrap();
// Language { storage: en_us }
// }
// pub fn get(&self, key: &str) -> Option<&str> {
// self.storage.get(key)
// }
// }
// yeah i just decided to do this because otherwise we would have to have a
// Language object that we passed around everywhere which is not convenient
// The code above is kept in case I come up with a better solution
lazy_static! {
pub static ref STORAGE: HashMap<String, String> =
serde_json::from_str(include_str!("en_us.json")).unwrap();
}
pub fn get(key: &str) -> Option<&str> {
STORAGE.get(key).map(|s| s.as_str())
}

View file

@ -5,7 +5,7 @@ async fn main() {
println!("Hello, world!"); println!("Hello, world!");
// let address = "95.111.249.143:10000"; // let address = "95.111.249.143:10000";
let address = "172.23.192.1:53911"; let address = "172.23.192.1:61385";
// let response = azalea_client::ping::ping_server(&address.try_into().unwrap()) // let response = azalea_client::ping::ping_server(&address.try_into().unwrap())
// .await // .await
// .unwrap(); // .unwrap();
@ -18,6 +18,9 @@ async fn main() {
while let Some(e) = client.next().await { while let Some(e) = client.next().await {
match e { match e {
Event::Login => {} Event::Login => {}
Event::Chat(p) => {
println!("{}", p.message.to_ansi(None));
}
} }
} }