From e96dc4d98eee266cb199148274c3f85bbf9a3566 Mon Sep 17 00:00:00 2001 From: Alexander Medvedev Date: Wed, 9 Jul 2025 16:26:16 +0200 Subject: [PATCH] Improve compile time --- Cargo.lock | 720 +++---------------------- Cargo.toml | 1 - pumpkin-api-macros/Cargo.toml | 2 +- pumpkin-world/Cargo.toml | 2 +- pumpkin/Cargo.toml | 4 +- pumpkin/src/data/banlist_serializer.rs | 53 +- pumpkin/src/data/banned_ip_data.rs | 9 +- pumpkin/src/data/banned_player_data.rs | 9 +- pumpkin/src/lib.rs | 4 +- pumpkin/src/net/authentication.rs | 55 +- pumpkin/src/net/java/login.rs | 59 +- pumpkin/src/net/mod.rs | 9 +- pumpkin/src/server/mod.rs | 15 - pumpkin/src/server/seasonal_events.rs | 6 +- 14 files changed, 192 insertions(+), 756 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 14f5b7086..fab1af607 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,21 +43,6 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - [[package]] name = "anes" version = "0.1.6" @@ -147,12 +132,6 @@ dependencies = [ "syn", ] -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - [[package]] name = "autocfg" version = "1.5.0" @@ -266,21 +245,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" -[[package]] -name = "chrono" -version = "0.4.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", - "num-traits", - "serde", - "wasm-bindgen", - "windows-link", -] - [[package]] name = "ciborium" version = "0.2.2" @@ -374,20 +338,33 @@ dependencies = [ ] [[package]] -name = "core-foundation" -version = "0.9.4" +name = "cookie" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" dependencies = [ - "core-foundation-sys", - "libc", + "percent-encoding", + "time", + "version_check", ] [[package]] -name = "core-foundation-sys" -version = "0.8.7" +name = "cookie_store" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +checksum = "2eac901828f88a5241ee0600950ab981148a18f2f756900ffba1b125ca6a3ef9" +dependencies = [ + "cookie", + "document-features", + "idna", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "time", + "url", +] [[package]] name = "cpufeatures" @@ -421,8 +398,6 @@ dependencies = [ "itertools 0.13.0", "num-traits", "oorandom", - "plotters", - "rayon", "regex", "serde", "serde_json", @@ -704,15 +679,6 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" -[[package]] -name = "encoding_rs" -version = "0.8.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" -dependencies = [ - "cfg-if", -] - [[package]] name = "enum_dispatch" version = "0.3.13" @@ -802,21 +768,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - [[package]] name = "form_urlencoded" version = "1.2.1" @@ -954,25 +905,6 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" -[[package]] -name = "h2" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17da50a276f1e01e0ba6c029e47b7100754904ee8a278f886546e98575380785" -dependencies = [ - "atomic-waker", - "bytes", - "fnv", - "futures-core", - "futures-sink", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - [[package]] name = "half" version = "2.6.0" @@ -1032,29 +964,6 @@ dependencies = [ "itoa", ] -[[package]] -name = "http-body" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" -dependencies = [ - "bytes", - "http", -] - -[[package]] -name = "http-body-util" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" -dependencies = [ - "bytes", - "futures-core", - "http", - "http-body", - "pin-project-lite", -] - [[package]] name = "httparse" version = "1.10.1" @@ -1070,108 +979,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "hyper" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "itoa", - "pin-project-lite", - "smallvec", - "tokio", - "want", -] - -[[package]] -name = "hyper-rustls" -version = "0.27.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" -dependencies = [ - "http", - "hyper", - "hyper-util", - "rustls", - "rustls-pki-types", - "tokio", - "tokio-rustls", - "tower-service", -] - -[[package]] -name = "hyper-tls" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" -dependencies = [ - "bytes", - "http-body-util", - "hyper", - "hyper-util", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", -] - -[[package]] -name = "hyper-util" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb" -dependencies = [ - "base64", - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "http", - "http-body", - "hyper", - "ipnet", - "libc", - "percent-encoding", - "pin-project-lite", - "socket2", - "system-configuration", - "tokio", - "tower-service", - "tracing", - "windows-registry", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "log", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - [[package]] name = "icu_collections" version = "2.0.0" @@ -1310,22 +1117,6 @@ dependencies = [ "libc", ] -[[package]] -name = "ipnet" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" - -[[package]] -name = "iri-string" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" -dependencies = [ - "memchr", - "serde", -] - [[package]] name = "is_terminal_polyfill" version = "1.70.1" @@ -1518,12 +1309,6 @@ version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - [[package]] name = "miniz_oxide" version = "0.8.9" @@ -1551,23 +1336,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "native-tls" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - [[package]] name = "num-bigint" version = "0.4.6" @@ -1659,50 +1427,6 @@ version = "11.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" -[[package]] -name = "openssl" -version = "0.10.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" -dependencies = [ - "bitflags", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "openssl-probe" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" - -[[package]] -name = "openssl-sys" -version = "0.9.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "parking_lot" version = "0.12.4" @@ -1887,34 +1611,6 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" -[[package]] -name = "plotters" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" -dependencies = [ - "num-traits", - "plotters-backend", - "plotters-svg", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "plotters-backend" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" - -[[package]] -name = "plotters-svg" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" -dependencies = [ - "plotters-backend", -] - [[package]] name = "portable-atomic" version = "1.11.1" @@ -1993,7 +1689,6 @@ dependencies = [ "base64", "bitflags", "bytes", - "chrono", "crossbeam", "dhat", "flate2", @@ -2013,7 +1708,6 @@ dependencies = [ "pumpkin-world", "rand", "rayon", - "reqwest", "rsa", "rsa-der", "rustc-hash 2.1.1", @@ -2028,6 +1722,7 @@ dependencies = [ "time", "tokio", "tokio-util", + "ureq", "uuid", ] @@ -2309,46 +2004,6 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" -[[package]] -name = "reqwest" -version = "0.12.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbc931937e6ca3a06e3b6c0aa7841849b160a90351d6ab467a8b9b9959767531" -dependencies = [ - "base64", - "bytes", - "encoding_rs", - "futures-core", - "h2", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-rustls", - "hyper-tls", - "hyper-util", - "js-sys", - "log", - "mime", - "native-tls", - "percent-encoding", - "pin-project-lite", - "rustls-pki-types", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "tokio", - "tokio-native-tls", - "tower", - "tower-http", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - [[package]] name = "ring" version = "0.17.14" @@ -2429,13 +2084,24 @@ version = "0.23.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7160e3e10bf4535308537f3c4e1641468cd0e485175d6163087c0393c7d46643" dependencies = [ + "log", "once_cell", + "ring", "rustls-pki-types", "rustls-webpki", "subtle", "zeroize", ] +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "rustls-pki-types" version = "1.12.0" @@ -2492,44 +2158,12 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "schannel" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" -dependencies = [ - "windows-sys 0.59.0", -] - [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "security-framework" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" -dependencies = [ - "bitflags", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "serde" version = "1.0.219" @@ -2582,18 +2216,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - [[package]] name = "serdect" version = "0.3.0" @@ -2774,15 +2396,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "sync_wrapper" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" -dependencies = [ - "futures-core", -] - [[package]] name = "synstructure" version = "0.13.2" @@ -2794,27 +2407,6 @@ dependencies = [ "syn", ] -[[package]] -name = "system-configuration" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" -dependencies = [ - "bitflags", - "core-foundation", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "take_mut" version = "0.2.2" @@ -2834,7 +2426,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" dependencies = [ "fastrand", - "getrandom 0.3.3", "once_cell", "rustix", "windows-sys 0.59.0", @@ -2977,26 +2568,6 @@ dependencies = [ "syn", ] -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - -[[package]] -name = "tokio-rustls" -version = "0.26.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" -dependencies = [ - "rustls", - "tokio", -] - [[package]] name = "tokio-util" version = "0.7.15" @@ -3051,76 +2622,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b679217f2848de74cabd3e8fc5e6d66f40b7da40f8e1954d92054d9010690fd5" -[[package]] -name = "tower" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" -dependencies = [ - "futures-core", - "futures-util", - "pin-project-lite", - "sync_wrapper", - "tokio", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-http" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" -dependencies = [ - "bitflags", - "bytes", - "futures-util", - "http", - "http-body", - "iri-string", - "pin-project-lite", - "tower", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-layer" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" - -[[package]] -name = "tower-service" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" - -[[package]] -name = "tracing" -version = "0.1.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" -dependencies = [ - "pin-project-lite", - "tracing-core", -] - -[[package]] -name = "tracing-core" -version = "0.1.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" -dependencies = [ - "once_cell", -] - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - [[package]] name = "twox-hash" version = "1.6.3" @@ -3167,6 +2668,39 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +[[package]] +name = "ureq" +version = "3.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f0fde9bc91026e381155f8c67cb354bcd35260b2f4a29bcc84639f762760c39" +dependencies = [ + "base64", + "cookie_store", + "flate2", + "log", + "percent-encoding", + "rustls", + "rustls-pemfile", + "rustls-pki-types", + "serde", + "serde_json", + "ureq-proto", + "utf-8", + "webpki-roots 0.26.11", +] + +[[package]] +name = "ureq-proto" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59db78ad1923f2b1be62b6da81fe80b173605ca0d57f85da2e005382adf693f7" +dependencies = [ + "base64", + "http", + "httparse", + "log", +] + [[package]] name = "url" version = "2.5.4" @@ -3178,6 +2712,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + [[package]] name = "utf8_iter" version = "1.0.4" @@ -3203,12 +2743,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - [[package]] name = "version_check" version = "0.9.5" @@ -3225,15 +2759,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" @@ -3275,19 +2800,6 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" -dependencies = [ - "cfg-if", - "js-sys", - "once_cell", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "wasm-bindgen-macro" version = "0.2.100" @@ -3321,13 +2833,21 @@ dependencies = [ ] [[package]] -name = "web-sys" -version = "0.3.77" +name = "webpki-roots" +version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" dependencies = [ - "js-sys", - "wasm-bindgen", + "webpki-roots 1.0.1", +] + +[[package]] +name = "webpki-roots" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8782dd5a41a24eed3a4f40b606249b3e236ca61adf1f25ea4d45c73de122b502" +dependencies = [ + "rustls-pki-types", ] [[package]] @@ -3361,76 +2881,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-core" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-link", - "windows-result", - "windows-strings", -] - -[[package]] -name = "windows-implement" -version = "0.60.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "windows-interface" -version = "0.59.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "windows-link" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" - -[[package]] -name = "windows-registry" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e" -dependencies = [ - "windows-link", - "windows-result", - "windows-strings", -] - -[[package]] -name = "windows-result" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-strings" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" -dependencies = [ - "windows-link", -] - [[package]] name = "windows-sys" version = "0.52.0" diff --git a/Cargo.toml b/Cargo.toml index d39384051..b18fe5cc0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,7 +52,6 @@ rayon = "1.10" crossbeam = "0.8" uuid = { version = "1.17", features = ["serde", "v3", "v4"] } -derive_more = { version = "2.0", features = ["full"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/pumpkin-api-macros/Cargo.toml b/pumpkin-api-macros/Cargo.toml index 85d135b1c..8baff656d 100644 --- a/pumpkin-api-macros/Cargo.toml +++ b/pumpkin-api-macros/Cargo.toml @@ -7,7 +7,7 @@ edition.workspace = true proc-macro = true [dependencies] -syn = { version = "2.0", features = ["full"] } +syn = { version = "2.0", features = ["parsing", "printing", "proc-macro", "derive"] } quote = "1.0" proc-macro2 = "1.0" proc-macro-error2.workspace = true diff --git a/pumpkin-world/Cargo.toml b/pumpkin-world/Cargo.toml index 6ca4f0a52..cb8f8b401 100644 --- a/pumpkin-world/Cargo.toml +++ b/pumpkin-world/Cargo.toml @@ -50,7 +50,7 @@ rand = "0.9.1" num_cpus = "1.17.0" [dev-dependencies] -criterion = { version = "0.6", features = ["html_reports", "async_tokio"] } +criterion = { version = "0.6", default-features = false, features = ["html_reports", "async_tokio"] } temp-dir = "0.1.16" # Print log info inside tests when needed env_logger = "0.11.8" diff --git a/pumpkin/Cargo.toml b/pumpkin/Cargo.toml index a4ce1646f..00cbf2d5f 100644 --- a/pumpkin/Cargo.toml +++ b/pumpkin/Cargo.toml @@ -54,7 +54,7 @@ rsa = { version = "=0.10.0-rc.1", features = ["sha1"] } rsa-der = "0.3" # authentication -reqwest = { version = "0.12", features = [ +ureq = { version = "3.0.12", features = [ "json", ] } @@ -72,8 +72,6 @@ simplelog = { version = "0.12.2", features = ["ansi_term"] } # Remove time in favor of chrono? time = "0.3" -chrono = { version = "0.4", features = ["serde"] } - # plugins libloading = "0.8" bitflags = "2.9.1" diff --git a/pumpkin/src/data/banlist_serializer.rs b/pumpkin/src/data/banlist_serializer.rs index ad4387cde..be9e46c11 100644 --- a/pumpkin/src/data/banlist_serializer.rs +++ b/pumpkin/src/data/banlist_serializer.rs @@ -1,7 +1,7 @@ use std::net::IpAddr; -use chrono::{DateTime, FixedOffset, Local}; use serde::{Deserialize, Serialize}; +use time::OffsetDateTime; use uuid::Uuid; use crate::net::GameProfile; @@ -11,10 +11,10 @@ pub struct BannedPlayerEntry { pub uuid: Uuid, pub name: String, #[serde(with = "format::date")] - pub created: DateTime, + pub created: time::OffsetDateTime, pub source: String, #[serde(with = "format::option_date")] - pub expires: Option>, + pub expires: Option, pub reason: String, } @@ -23,13 +23,13 @@ impl BannedPlayerEntry { pub fn new( profile: &GameProfile, source: String, - expires: Option>, + expires: Option, reason: String, ) -> Self { Self { uuid: profile.id, name: profile.name.clone(), - created: Local::now().fixed_offset(), + created: OffsetDateTime::now_utc(), source, expires, reason, @@ -41,10 +41,10 @@ impl BannedPlayerEntry { pub struct BannedIpEntry { pub ip: IpAddr, #[serde(with = "format::date")] - pub created: DateTime, + pub created: time::OffsetDateTime, pub source: String, #[serde(with = "format::option_date")] - pub expires: Option>, + pub expires: Option, pub reason: String, } @@ -53,12 +53,12 @@ impl BannedIpEntry { pub fn new( ip: IpAddr, source: String, - expires: Option>, + expires: Option, reason: String, ) -> Self { Self { ip, - created: Local::now().fixed_offset(), + created: OffsetDateTime::now_utc(), source, expires, reason, @@ -67,56 +67,55 @@ impl BannedIpEntry { } mod format { - const FORMAT: &str = "%Y-%m-%d %H:%M:%S %z"; + use simplelog::FormatItem; + + const DATE_FORMAT: &[FormatItem<'static>] = time::macros::format_description!( + "[year]-[month]-[day] [hour]:[minute]:[second][offset_hour sign:mandatory]:[offset_minute]" + ); pub mod date { - use chrono::{DateTime, FixedOffset}; use serde::{self, Deserialize, Deserializer, Serializer}; + use time::OffsetDateTime; - use super::FORMAT; + use super::DATE_FORMAT; - pub fn serialize(date: &DateTime, serializer: S) -> Result + pub fn serialize(date: &OffsetDateTime, serializer: S) -> Result where S: Serializer, { - let s = date.format(FORMAT).to_string(); + let s = date.format(DATE_FORMAT).unwrap().to_string(); serializer.serialize_str(&s) } - pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + pub fn deserialize<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, { let s = String::deserialize(deserializer)?; - DateTime::parse_from_str(&s, FORMAT).map_err(serde::de::Error::custom) + OffsetDateTime::parse(&s, DATE_FORMAT).map_err(serde::de::Error::custom) } } pub mod option_date { - use chrono::{DateTime, FixedOffset}; use serde::{self, Deserialize, Deserializer, Serializer}; + use time::OffsetDateTime; - use super::FORMAT; + use crate::data::banlist_serializer::format::DATE_FORMAT; #[allow(clippy::ref_option)] - pub fn serialize( - date: &Option>, - serializer: S, - ) -> Result + pub fn serialize(date: &Option, serializer: S) -> Result where S: Serializer, { if let Some(date) = date { - let s = date.format(FORMAT).to_string(); + let s = date.format(DATE_FORMAT).unwrap().to_string(); serializer.serialize_str(&s) } else { serializer.serialize_str("forever") } } - pub fn deserialize<'de, D>( - deserializer: D, - ) -> Result>, D::Error> + pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, { @@ -124,7 +123,7 @@ mod format { if s == "forever" { Ok(None) } else { - DateTime::parse_from_str(&s, FORMAT) + OffsetDateTime::parse(&s, DATE_FORMAT) .map(Some) .map_err(serde::de::Error::custom) } diff --git a/pumpkin/src/data/banned_ip_data.rs b/pumpkin/src/data/banned_ip_data.rs index 4e7c9acd6..3301a34c2 100644 --- a/pumpkin/src/data/banned_ip_data.rs +++ b/pumpkin/src/data/banned_ip_data.rs @@ -1,7 +1,7 @@ use std::{net::IpAddr, path::Path, sync::LazyLock}; -use chrono::Local; use serde::{Deserialize, Serialize}; +use time::OffsetDateTime; use super::{LoadJSONConfiguration, SaveJSONConfiguration, banlist_serializer::BannedIpEntry}; @@ -24,8 +24,11 @@ impl BannedIpList { fn remove_invalid_entries(&mut self) { let original_len = self.banned_ips.len(); - self.banned_ips - .retain(|entry| entry.expires.is_none_or(|expires| expires >= Local::now())); + self.banned_ips.retain(|entry| { + entry + .expires + .is_none_or(|expires| expires >= OffsetDateTime::now_utc()) + }); if original_len != self.banned_ips.len() { self.save(); diff --git a/pumpkin/src/data/banned_player_data.rs b/pumpkin/src/data/banned_player_data.rs index b847ade58..8a91c24a5 100644 --- a/pumpkin/src/data/banned_player_data.rs +++ b/pumpkin/src/data/banned_player_data.rs @@ -1,7 +1,7 @@ use std::{path::Path, sync::LazyLock}; -use chrono::Local; use serde::{Deserialize, Serialize}; +use time::OffsetDateTime; use crate::net::GameProfile; @@ -28,8 +28,11 @@ impl BannedPlayerList { fn remove_invalid_entries(&mut self) { let original_len = self.banned_players.len(); - self.banned_players - .retain(|entry| entry.expires.is_none_or(|expires| expires >= Local::now())); + self.banned_players.retain(|entry| { + entry + .expires + .is_none_or(|expires| expires >= OffsetDateTime::now_utc()) + }); if original_len != self.banned_players.len() { self.save(); diff --git a/pumpkin/src/lib.rs b/pumpkin/src/lib.rs index 19f938af9..b5b24a902 100644 --- a/pumpkin/src/lib.rs +++ b/pumpkin/src/lib.rs @@ -226,9 +226,7 @@ impl PumpkinServer { } if BASIC_CONFIG.allow_chat_reports { - let mojang_public_keys = fetch_mojang_public_keys(server.auth_client.as_ref().unwrap()) - .await - .unwrap(); + let mojang_public_keys = fetch_mojang_public_keys().unwrap(); *server.mojang_public_keys.lock().await = mojang_public_keys; } diff --git a/pumpkin/src/net/authentication.rs b/pumpkin/src/net/authentication.rs index fa69911cb..36890492f 100644 --- a/pumpkin/src/net/authentication.rs +++ b/pumpkin/src/net/authentication.rs @@ -3,11 +3,11 @@ use std::{collections::HashMap, net::IpAddr}; use base64::{Engine, engine::general_purpose}; use pumpkin_config::{advanced_config, networking::auth::TextureConfig}; use pumpkin_protocol::Property; -use reqwest::{StatusCode, Url}; use rsa::RsaPublicKey; use rsa::pkcs8::DecodePublicKey; use serde::Deserialize; use thiserror::Error; +use ureq::http::{StatusCode, Uri}; use uuid::Uuid; use super::GameProfile; @@ -60,11 +60,10 @@ const MOJANG_SERVICES_URL: &str = "https://api.minecraftservices.com/"; /// 3. Now our server will send a Request to the Session servers and check if the Player has joined the Session Server . /// /// See -pub async fn authenticate( +pub fn authenticate( username: &str, server_hash: &str, ip: &IpAddr, - auth_client: &reqwest::Client, ) -> Result { let address = if advanced_config() .networking @@ -95,17 +94,18 @@ pub async fn authenticate( .replace("{server_hash}", server_hash) }; - let response = auth_client - .get(address) - .send() - .await + let mut response = ureq::get(address) + .call() .map_err(|_| AuthError::FailedResponse)?; match response.status() { StatusCode::OK => {} StatusCode::NO_CONTENT => Err(AuthError::UnverifiedUsername)?, other => Err(AuthError::UnknownStatusCode(other))?, } - let profile: GameProfile = response.json().await.map_err(|_| AuthError::FailedParse)?; + let profile: GameProfile = response + .body_mut() + .read_json() + .map_err(|_| AuthError::FailedParse)?; Ok(profile) } @@ -116,36 +116,37 @@ pub fn validate_textures(property: &Property, config: &TextureConfig) -> Result< let textures: ProfileTextures = serde_json::from_slice(&from64).map_err(|e| TextureError::JSONError(e.to_string()))?; for texture in textures.textures { - let url = - Url::parse(&texture.1.url).map_err(|e| TextureError::InvalidURL(e.to_string()))?; + let url = texture + .1 + .url + .parse() + .map_err(|_| TextureError::InvalidURL)?; is_texture_url_valid(&url, config)?; } Ok(()) } -pub fn is_texture_url_valid(url: &Url, config: &TextureConfig) -> Result<(), TextureError> { - let scheme = url.scheme(); +pub fn is_texture_url_valid(url: &Uri, config: &TextureConfig) -> Result<(), TextureError> { + let scheme = url.scheme().unwrap(); if !config .allowed_url_schemes .iter() - .any(|allowed_scheme| scheme.ends_with(allowed_scheme)) + .any(|allowed_scheme| scheme.as_str().ends_with(allowed_scheme)) { return Err(TextureError::DisallowedUrlScheme(scheme.to_string())); } - let domain = url.domain().unwrap_or(""); + let domain = url.authority().unwrap(); if !config .allowed_url_domains .iter() - .any(|allowed_domain| domain.ends_with(allowed_domain)) + .any(|allowed_domain| domain.as_str().ends_with(allowed_domain)) { return Err(TextureError::DisallowedUrlDomain(domain.to_string())); } Ok(()) } -pub async fn fetch_mojang_public_keys( - auth_client: &reqwest::Client, -) -> Result, AuthError> { +pub fn fetch_mojang_public_keys() -> Result, AuthError> { let services_url = advanced_config() .networking .authentication @@ -155,10 +156,8 @@ pub async fn fetch_mojang_public_keys( let url = format!("{services_url}/publickeys"); - let response = auth_client - .get(url) - .send() - .await + let mut response = ureq::get(url) + .call() .map_err(|_| AuthError::FailedResponse)?; match response.status() { @@ -167,8 +166,10 @@ pub async fn fetch_mojang_public_keys( other => Err(AuthError::UnknownStatusCode(other))?, } - let public_keys: MojangPublicKeys = - response.json().await.map_err(|_| AuthError::FailedParse)?; + let public_keys: MojangPublicKeys = response + .body_mut() + .read_json() + .map_err(|_| AuthError::FailedParse)?; let as_rsa_keys = public_keys .player_certificate_keys @@ -186,8 +187,6 @@ pub async fn fetch_mojang_public_keys( #[derive(Error, Debug)] pub enum AuthError { - #[error("Missing auth client")] - MissingAuthClient, #[error("Authentication servers are down")] FailedResponse, #[error("Failed to verify username")] @@ -206,8 +205,8 @@ pub enum AuthError { #[derive(Error, Debug)] pub enum TextureError { - #[error("Invalid URL {0}")] - InvalidURL(String), + #[error("Invalid URL")] + InvalidURL, #[error("Invalid URL scheme for player texture: {0}")] DisallowedUrlScheme(String), #[error("Invalid URL domain for player texture: {0}")] diff --git a/pumpkin/src/net/java/login.rs b/pumpkin/src/net/java/login.rs index 9c318eb5d..1d1eb30b2 100644 --- a/pumpkin/src/net/java/login.rs +++ b/pumpkin/src/net/java/login.rs @@ -265,47 +265,44 @@ impl JavaClientPlatform { shared_secret: &[u8], username: &str, ) -> Result { - if let Some(auth_client) = &server.auth_client { - let hash = server.digest_secret(shared_secret); - let ip = self.address.lock().await.ip(); - let profile = authentication::authenticate(username, &hash, &ip, auth_client).await?; + let hash = server.digest_secret(shared_secret); + let ip = self.address.lock().await.ip(); + let profile = authentication::authenticate(username, &hash, &ip)?; - // Check if the player should join - if let Some(actions) = &profile.profile_actions { - if advanced_config() + // Check if the player should join + if let Some(actions) = &profile.profile_actions { + if advanced_config() + .networking + .authentication + .player_profile + .allow_banned_players + { + for allowed in &advanced_config() .networking .authentication .player_profile - .allow_banned_players + .allowed_actions { - for allowed in &advanced_config() - .networking - .authentication - .player_profile - .allowed_actions - { - if !actions.contains(allowed) { - return Err(AuthError::DisallowedAction); - } + if !actions.contains(allowed) { + return Err(AuthError::DisallowedAction); } - if !actions.is_empty() { - return Err(AuthError::Banned); - } - } else if !actions.is_empty() { + } + if !actions.is_empty() { return Err(AuthError::Banned); } + } else if !actions.is_empty() { + return Err(AuthError::Banned); } - // Validate textures - for property in &profile.properties { - authentication::validate_textures( - property, - &advanced_config().networking.authentication.textures, - ) - .map_err(AuthError::TextureError)?; - } - return Ok(profile); } - Err(AuthError::MissingAuthClient) + // Validate textures + for property in &profile.properties { + authentication::validate_textures( + property, + &advanced_config().networking.authentication.textures, + ) + .map_err(AuthError::TextureError)?; + } + Ok(profile) } pub fn handle_login_cookie_response(&self, packet: &SLoginCookieResponse) { diff --git a/pumpkin/src/net/mod.rs b/pumpkin/src/net/mod.rs index f4650b469..42e1f4687 100644 --- a/pumpkin/src/net/mod.rs +++ b/pumpkin/src/net/mod.rs @@ -19,6 +19,7 @@ use pumpkin_util::{ProfileAction, text::TextComponent}; use serde::Deserialize; use sha1::Digest; use sha2::Sha256; +use simplelog::FormatItem; use tokio::task::JoinHandle; use thiserror::Error; @@ -173,6 +174,10 @@ pub async fn can_not_join( address: &SocketAddr, server: &Server, ) -> Option { + const FORMAT_DESCRIPTION: &[FormatItem<'_>] = time::macros::format_description!( + "[year]-[month]-[day] at [hour]:[minute]:[second] [offset_hour sign:mandatory]:[offset_minute]" + ); + let mut banned_players = BANNED_PLAYER_LIST.write().await; if let Some(entry) = banned_players.get_entry(profile) { let text = TextComponent::translate( @@ -183,7 +188,7 @@ pub async fn can_not_join( Some(expires) => text.add_child(TextComponent::translate( "multiplayer.disconnect.banned.expiration", [TextComponent::text( - expires.format("%F at %T %Z").to_string(), + expires.format(FORMAT_DESCRIPTION).unwrap().to_string(), )], )), None => text, @@ -213,7 +218,7 @@ pub async fn can_not_join( Some(expires) => text.add_child(TextComponent::translate( "multiplayer.disconnect.banned_ip.expiration", [TextComponent::text( - expires.format("%F at %T %Z").to_string(), + expires.format(FORMAT_DESCRIPTION).unwrap().to_string(), )], )), None => text, diff --git a/pumpkin/src/server/mod.rs b/pumpkin/src/server/mod.rs index 0a6f1a802..45bcde481 100644 --- a/pumpkin/src/server/mod.rs +++ b/pumpkin/src/server/mod.rs @@ -74,8 +74,6 @@ pub struct Server { pub cached_registry: Vec, /// Assigns unique IDs to containers. container_id: AtomicU32, - /// Manages authentication with an authentication server, if enabled. - pub auth_client: Option, /// Mojang's public keys, used for chat session signing /// Pulled from Mojang API on startup pub mojang_public_keys: Mutex>, @@ -111,18 +109,6 @@ impl Server { #[allow(clippy::new_without_default)] #[must_use] pub async fn new() -> Self { - let auth_client = BASIC_CONFIG.online_mode.then(|| { - reqwest::Client::builder() - .connect_timeout(Duration::from_millis(u64::from( - advanced_config().networking.authentication.connect_timeout, - ))) - .read_timeout(Duration::from_millis(u64::from( - advanced_config().networking.authentication.read_timeout, - ))) - .build() - .expect("Failed to to make reqwest client") - }); - // First register the default commands. After that, plugins can put in their own. let command_dispatcher = RwLock::new(default_dispatcher().await); let world_path = BASIC_CONFIG.get_world_path(); @@ -194,7 +180,6 @@ impl Server { command_dispatcher, block_registry, item_registry: super::item::items::default_registry(), - auth_client, key_store: KeyStore::new(), listing: Mutex::new(CachedStatus::new()), branding: CachedBranding::new(), diff --git a/pumpkin/src/server/seasonal_events.rs b/pumpkin/src/server/seasonal_events.rs index dd744c078..8852ac283 100644 --- a/pumpkin/src/server/seasonal_events.rs +++ b/pumpkin/src/server/seasonal_events.rs @@ -1,13 +1,13 @@ -use chrono::{Datelike, Local}; use pumpkin_config::advanced_config; use rand::{rng, seq::SliceRandom}; +use time::{Month, OffsetDateTime}; // In fact Mojang also has some Seasonal Events, so we can use that later to match Vanilla :D #[must_use] pub fn is_april() -> bool { - let data = Local::now(); - data.day() == 1 && data.month() == 4 + let data = OffsetDateTime::now_utc(); + data.day() == 1 && data.month() == Month::April } #[must_use]