From 2a040f8e91e9cd38c1be4b7ba92cc7dc2d4bea01 Mon Sep 17 00:00:00 2001 From: oiupoyt Date: Sat, 29 Aug 2026 19:21:11 +0530 Subject: [PATCH] perf: eliminate account dropdown micro-delays with global avatar caching and dev optimization --- Cargo.toml | 3 ++ .../src/components/account_switcher.rs | 3 +- .../oneclient_app/src/components/avatar.rs | 41 ++++++++++++------- .../src/hooks/queries/player_profile.rs | 15 ++++++- 4 files changed, 45 insertions(+), 17 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ab0d1c44..58863123 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -140,6 +140,9 @@ freya = {version = "=0.5.0-rc.4", features = ["engine", "winit", "router", "remo freya-skia-safe = "=0.99.1" # required for the SKSL player renderer image = {version = "=0.25.10", default-features = false, features = ["png", "jpeg"]} +[profile.dev.package."*"] +opt-level = 3 + [profile.release] codegen-units = 1 debug = "line-tables-only" diff --git a/packages/oneclient_app/src/components/account_switcher.rs b/packages/oneclient_app/src/components/account_switcher.rs index f9f4da03..11d9c827 100644 --- a/packages/oneclient_app/src/components/account_switcher.rs +++ b/packages/oneclient_app/src/components/account_switcher.rs @@ -90,8 +90,7 @@ impl Component for AccountPanel { .spacing(8.) .opacity(progress) .margin(Gaps::new((1.0 - progress) * -8.0, 0., 0., 0.)) - .background(colors::page_elevated().with_a(220)) - .blur(12.) + .background(colors::page_elevated()) .corner_radius(CornerRadius::new_all(12.)) .border( Border::new() diff --git a/packages/oneclient_app/src/components/avatar.rs b/packages/oneclient_app/src/components/avatar.rs index 4647008b..6d5b712b 100644 --- a/packages/oneclient_app/src/components/avatar.rs +++ b/packages/oneclient_app/src/components/avatar.rs @@ -1,3 +1,6 @@ +use std::collections::HashMap; +use std::sync::{Mutex, OnceLock}; + use bytes::Bytes; use freya::elements::image::{ImageHandle, image}; use freya::engine::prelude::{Paint, SkData, SkImage, raster_n32_premul}; @@ -10,6 +13,8 @@ const FACE: f32 = 8.; const HEAD_FACE: (f32, f32) = (8., 8.); const HEAD_OVERLAY: (f32, f32) = (40., 8.); +static AVATAR_HEAD_CACHE: OnceLock>> = OnceLock::new(); + #[derive(PartialEq, Clone)] pub struct Avatar { uuid: String, @@ -40,20 +45,7 @@ impl Component for Avatar { fn render(&self) -> impl IntoElement { let (skin_bytes, _is_slim) = use_player_skin(self.uuid.clone()); - - let mut cache = use_state(|| None::<(usize, ImageHandle)>); - let src_ptr = skin_bytes.as_ptr() as usize; - let cached = cache.read().clone(); - let head = match cached { - Some((ptr, holder)) if ptr == src_ptr => Some(holder), - _ => { - let holder = compose_head(&skin_bytes); - if let Some(holder) = &holder { - cache.set(Some((src_ptr, holder.clone()))); - } - holder - } - }; + let head = get_or_compose_head(&skin_bytes); rect() .width(Size::px(AVATAR_SIZE)) @@ -71,6 +63,27 @@ impl Component for Avatar { } } +fn get_or_compose_head(skin_bytes: &Bytes) -> Option { + if skin_bytes.is_empty() { + return None; + } + let src_ptr = skin_bytes.as_ptr() as usize; + let cache = AVATAR_HEAD_CACHE.get_or_init(|| Mutex::new(HashMap::new())); + { + if let Ok(guard) = cache.lock() { + if let Some(handle) = guard.get(&src_ptr) { + return Some(handle.clone()); + } + } + } + + let composed = compose_head(skin_bytes)?; + if let Ok(mut guard) = cache.lock() { + guard.insert(src_ptr, composed.clone()); + } + Some(composed) +} + fn compose_head(skin_bytes: &Bytes) -> Option { let data = unsafe { SkData::new_bytes(skin_bytes) }; let skin = SkImage::from_encoded(data)?; diff --git a/packages/oneclient_app/src/hooks/queries/player_profile.rs b/packages/oneclient_app/src/hooks/queries/player_profile.rs index ec19930f..d8693c4f 100644 --- a/packages/oneclient_app/src/hooks/queries/player_profile.rs +++ b/packages/oneclient_app/src/hooks/queries/player_profile.rs @@ -22,8 +22,21 @@ impl QueryCapability for FetchPlayerProfileQuery { type Keys = PlayerProfileQueryKeys; async fn run(&self, keys: &Self::Keys) -> Result { - let access_token = keys.access_token.clone(); + let uuid_str = &keys.uuid; + if uuid_str.is_empty() { + return Ok(PlayerProfileView::default()); + } + if let Ok(u) = uuid::Uuid::parse_str(uuid_str) { + if u.get_version() == Some(uuid::Version::Md5) || u.is_nil() { + return Ok(PlayerProfileView { + uuid: uuid_str.clone(), + ..Default::default() + }); + } + } + + let access_token = keys.access_token.clone(); let state = crate::launcher::state()?; let client = &state.services.requester;