From 784249005e06fe2b4af0facea3e7132747d138b7 Mon Sep 17 00:00:00 2001 From: LynithDev <61880709+LynithDev@users.noreply.github.com> Date: Wed, 8 Jul 2026 17:57:05 +0200 Subject: [PATCH] feat: Alex + Slim skins support in avatar and player model renderer --- packages/oneclient_app/assets/alex.png | Bin 0 -> 958 bytes packages/oneclient_app/assets/oneclient.svg | 4 - packages/oneclient_app/assets/steve.png | Bin 1379 -> 848 bytes .../oneclient_app/src/components/avatar.rs | 31 +---- .../src/components/player_model.rs | 70 +++++------- packages/oneclient_app/src/hooks/mod.rs | 108 ++++++++++++------ 6 files changed, 102 insertions(+), 111 deletions(-) create mode 100644 packages/oneclient_app/assets/alex.png delete mode 100644 packages/oneclient_app/assets/oneclient.svg diff --git a/packages/oneclient_app/assets/alex.png b/packages/oneclient_app/assets/alex.png new file mode 100644 index 0000000000000000000000000000000000000000..99af19334ecf2f9160e4c28b2f5b47ed04df4599 GIT binary patch literal 958 zcmV;v13~8)W)E){ zFoKTR*{Xr#0fECNFbvk(s)A&D1*l*4(OLtn%@3k*T^e!5iy0zJ__++uSXq;-lg?5H zV>ta`&hFoqV{0YuFti|OG6Z!kQ8k#-7&Wjiu9lxSlX+g+JiV6X>yzPH4H`xzKMQ1O zYfO2=^2eSuFlAKW8czA==dv`$)?7EPkpeI>Hj$gEvL-ozhQkUYq!0Kc`W;9#qYnUmoA z3OrGWLlAD(!!kf{ z!azn7l7&E*+ySFl#h7BD@B26*9(!;+_NZ9`Vdu$&NPZ>I;EQJa^EjRnLWEigQ5%R5r|$$3>Qi{^`|OMus%-hR*!q(kl1Hc zQ2g?rgVStv*gB%+pU5K(hhwVD7QqSJS5Px5*ebZMpr#EKM4=nz<314Z>?pz6f^GoQ zgi5?82t1{}AWJX}QCZUki}cwnMOjN!a2?KKBdb z+z=#8hCq+GrC;dvDEuI&0!iKV3!4QJ8t?iAYs?10x?fNr*surdenHXJEE%#s1??BW gtzVFi;JXU`0{B{0H2iXh{r~^~07*qoM6N<$g84wO3IG5A literal 0 HcmV?d00001 diff --git a/packages/oneclient_app/assets/oneclient.svg b/packages/oneclient_app/assets/oneclient.svg deleted file mode 100644 index 3f305562..00000000 --- a/packages/oneclient_app/assets/oneclient.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/packages/oneclient_app/assets/steve.png b/packages/oneclient_app/assets/steve.png index b821a51840d216541a777bdc719abcc8e2cf729c..1607786076eca0c9cff6bf8fba03e1542855a359 100644 GIT binary patch delta 836 zcmV-K1H1g=3eX0S8Gi!+005o0f$RVP0CiAIR7C&)01CXk0L;uL8VV#B2rC{9Gb9l| zDiybbYqNP?Qay?P|Np9TS({@?kXb(fe}4dIXjN5Jlwdw~OEZB}IgegGNhJ_M9SV0s zHEKXGG$j%!C@42KH$Oi=N=iyPF^NGnn?^dN1A2M|h=>H0m45)FqyVq4@V%)S00001 zbW%=J06^y0W&i*JiAh93RCwC$)?I5J=NU!eYmfXPyO>f4BrTNW#Qp!jCq63lE3{yU zOK??bRu6@+;FWq9ypCpISnS!)eZw<=mzL?bfPZ-!2Y}56Rd~K2PHuv3o-e3b1MqwS zYctsM1)DOjZhyAz<~5#QqSao_yv`GO0T5Q&X6HPSy)-p56m4Q@>%SL&VU_I^ZO2r@ zK@OJ$+w7RVzS{BX)i>>!!^p@5u8z}oa$URP=C+QNX=Znq5;*AXb+xOV)%DvrI5WA# zi=n(>?|ia1YAjm1C^*-ft~+n9m*1S7$Ltpkxy-(~(SP;l>(1kWf1iH86Gvi0%uo0hKLQQ`Fb>7OtM5j!9Xo~?HVVKC1_LPC{%|)H=RtEG z83k7E1%Cj@qBfhNgRq|fyMMkHlvz9J3N;AOaI)5dJQR!-%a+k#Sz{DZTjHU>U^a|R z8UrIs7?=PK^MJ8v+878B*n?BZ5DPHQnOKGt3k0|q5J)hnwisz8pwR=tIedDD+H~7u zZeJX_HCIcw2e81p7pQqB5n-m|jytonUfdm4lYgx><}1G@_RJ68hkc;0-F@ZKAbpQp z^B2JT@i+F#mmECKRse8Jo+GFYfDg{_|0j6gF?&)6KWG!p=p()r1AgRkf@}n{VT9so z0t|pNn`C&%3y-jeQT9&&yvIJ=zkb<4Bcp|n&{|+WUrx}>!m_MLpvxT$8`yCShM4Uc zB|RD#2&l^?W;6r{Siofg3JD?b#9cV6ey-|_zyNkR!58<1HB9!{B>fMQEPx|ax^W@^ O0000|q1 delta 1371 zcmV-h1*H1W2IC5l8Gi-<0063Kaozv`00d`2O+f$vv5yPR+4+9XWzTvhkqAlk zs}>TpVZ}U>d1%ezO1g149jHX9CpMg3vq(t-fMBw3?>2gTs>!=TWd(rE*VR;50VI=2 zpHNm70J!({X~1P=4?vp52!P~tm=gd@=EDGVr0U8C02|-Da)HWY_16KIR5k$ExD=0! zlK&b^)m9J$Q-7OkE0x*p$;GsFt*i9fh19UxT?bMtE7d}XSd;+($Dt1Dq7B^VcEk1& zkpcj1SzV=!z~GJz)#}Q^-}~#AP;31%6$c<3gE}bVb|iqHeZ;H-P!GMr?KRi9W2_cE zUEzWFIWj;KFEaFZbeJZdXPo?X`h4>|HEmp?Vi1cu4S!j93WC!n+78=CL}LWhI74|= zmD{Ve?o>cNy}p`0-MvEJ9}TMOm*GJg%Uqz}BN-aIc1#H|h(#ULMILRTP5d3UkBH0^ zaHqinN-m#IPtLZ`*rkKil3J?FBX#T^p&xgyD)Y!A0SaOei#n)_He{P&`-tcOaC*!g zw$=2gqkoY`FYcqK=bIgKhv?g#9{Tkl<9)sTc{)HJ`VP~uv*$+)Vo?Wm(FXUvTm)_V zh)Apfcu)-6p0+f-?K?qlE*N76KOa0?B#)qg9q(CyP75=4Bfuz%pjm0btnk z10XLyoB_x(TRg|Xpv>zAbSa z{|dG znbwG$0K_Ryaf(x%;uNPi#VJm4ihom_;uNPi6`Be@TrKwDXUPH3&j05g067At;{}LP zn*xyskn8&e{NG;Rxq_7ZSGwtaf?N+jqXNKo-+KDXAZ#Z|r34`8e&9)w>3F>C0TlcE zeCy!^i;!5`Syo? z`kUAB_e=rE_x%EWh?@Wu^a8|mr$XN^FrDw)0GOsoWB}xQyl(2@pqHS^5`b?Z6bqdG d3e0o>_y_q1m)BbC*S!D$002ovPDHLkV1i+ri|qga diff --git a/packages/oneclient_app/src/components/avatar.rs b/packages/oneclient_app/src/components/avatar.rs index 9f5bebf0..e1d5c488 100644 --- a/packages/oneclient_app/src/components/avatar.rs +++ b/packages/oneclient_app/src/components/avatar.rs @@ -2,10 +2,8 @@ use bytes::Bytes; use freya::elements::image::{ImageHandle, image}; use freya::engine::prelude::{Paint, SkData, SkImage, raster_n32_premul}; use freya::prelude::*; -use freya::query::QueryStateData; -use crate::AppAssets; -use crate::hooks::{use_cached_image, use_player_profile}; +use crate::hooks::use_player_skin; const AVATAR_SIZE: f32 = 32.; const FACE: f32 = 8.; @@ -37,32 +35,7 @@ impl ContainerSizeExt for Avatar {} impl Component for Avatar { fn render(&self) -> impl IntoElement { - let profile = use_player_profile(self.uuid.clone(), None::); - - let skin_url = match &*profile.read().state() { - QueryStateData::Settled { - res: Ok(profile), .. - } => profile.skin_url.clone(), - _ => None, - }; - - let skin_query = use_cached_image(skin_url.clone(), 256); - - let steve = use_memo(|| AppAssets::get_bytes("steve.png").unwrap_or_default()); - - let skin_bytes = { - let reader = skin_query.read(); - match (&skin_url, &*reader.state()) { - (Some(_), QueryStateData::Settled { res: Ok(bytes), .. }) - | ( - Some(_), - QueryStateData::Loading { - res: Some(Ok(bytes)), - }, - ) => bytes.clone(), - _ => steve.read().clone(), - } - }; + 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; diff --git a/packages/oneclient_app/src/components/player_model.rs b/packages/oneclient_app/src/components/player_model.rs index 91133b98..1f5054ab 100644 --- a/packages/oneclient_app/src/components/player_model.rs +++ b/packages/oneclient_app/src/components/player_model.rs @@ -5,12 +5,10 @@ use freya::engine::prelude::{ Data, Paint, SamplingOptions, Shader, SkData, SkImage, SkRect, TileMode, }; use freya::prelude::*; -use freya::query::QueryStateData; use skia_safe::RuntimeEffect; use skia_safe::runtime_effect::ChildPtr; -use crate::AppAssets; -use crate::hooks::{use_cached_image, use_player_profile}; +use crate::hooks::use_player_skin; const CAM_DIST: f32 = 80.0; const CAM_FOCAL: f32 = 1.85; @@ -81,31 +79,7 @@ impl PlayerModel { impl Component for PlayerModel { fn render(&self) -> impl IntoElement { - let profile = use_player_profile(self.uuid.clone(), None::); - - let skin_url = match &*profile.read().state() { - QueryStateData::Settled { - res: Ok(profile), .. - } => profile.skin_url.clone(), - _ => None, - }; - - let skin_query = use_cached_image(skin_url.clone(), 256); - let steve = use_memo(|| AppAssets::get_bytes("steve.png").unwrap_or_default()); - - let skin_bytes = { - let reader = skin_query.read(); - match (&skin_url, &*reader.state()) { - (Some(_), QueryStateData::Settled { res: Ok(bytes), .. }) - | ( - Some(_), - QueryStateData::Loading { - res: Some(Ok(bytes)), - }, - ) => bytes.clone(), - _ => steve.read().clone(), - } - }; + let (skin_bytes, is_slim) = use_player_skin(self.uuid.clone()); let mut cache = use_state(|| None::<(usize, Shader)>); let src_ptr = skin_bytes.as_ptr() as usize; @@ -151,15 +125,19 @@ impl Component for PlayerModel { let (Some(effect), Some(skin)) = (&effect, &skin_shader) else { return; }; + let (w, h) = (ctx.size.width, ctx.size.height); - if w <= 0.0 || h <= 0.0 { + + if w <= 0.0 || h <= 0.0 { return; } let (cur_yaw, cur_pitch) = (yaw(), pitch()); - let mut uniforms = Vec::with_capacity(24); - for value in [w, h, cur_yaw, cur_pitch, CAM_DIST, CAM_FOCAL] { + let slim = if is_slim { 1.0 } else { 0.0 }; + + let mut uniforms = Vec::with_capacity(28); + for value in [w, h, cur_yaw, cur_pitch, CAM_DIST, CAM_FOCAL, slim] { uniforms.extend_from_slice(&value.to_le_bytes()); } @@ -237,6 +215,7 @@ uniform float uYaw; uniform float uPitch; uniform float uDist; uniform float uFocal; +uniform float uSlim; uniform shader uSkin; void hitBox(float3 ro, float3 rd, float3 cmin, float3 cmax, float3 dims, float3 td, @@ -266,8 +245,8 @@ void hitBox(float3 ro, float3 rd, float3 cmin, float3 cmax, float3 dims, float3 nrm = float3(1.0, 0.0, 0.0); } } else if (tN == tmin.y) { - if (rd.y > 0.0) { // -Y face (bottom) - uv = float2(base.x + d + w + n.x * w, base.y + (1.0 - n.z) * d); + if (rd.y > 0.0) { // -Y face (bottom): 180deg from top, flip both axes + uv = float2(base.x + d + w + (1.0 - n.x) * w, base.y + (1.0 - n.z) * d); nrm = float3(0.0, -1.0, 0.0); } else { // +Y face (top) uv = float2(base.x + d + n.x * w, base.y + n.z * d); @@ -285,9 +264,9 @@ void hitBox(float3 ro, float3 rd, float3 cmin, float3 cmax, float3 dims, float3 half4 s = uSkin.eval(uv); - if (s.a < 0.5) { - return; - } + if (s.a < 0.5) { + return; + } float3 L = normalize(float3(0.4, 0.8, 0.6)); float diff = 0.65 + 0.35 * clamp(dot(nrm, L), 0.0, 1.0); @@ -311,14 +290,17 @@ half4 main(float2 fragCoord) { float best = 1e9; half4 col = half4(0.0); + float aw = uSlim > 0.5 ? 3.0 : 4.0; // arm width: slim = 3px, classic = 4px + float sw = aw + 0.5; // arm overlay (sleeve) width + hitBox(ro, rd, float3(-4.0, 8.0, -4.0), float3(4.0, 16.0, 4.0), float3(8.0, 8.0, 8.0), float3(8.0, 8.0, 8.0), float2(0.0, 0.0), best, col); // head hitBox(ro, rd, float3(-4.0, -4.0, -2.0), float3(4.0, 8.0, 2.0), float3(8.0, 12.0, 4.0), float3(8.0, 12.0, 4.0), float2(16.0, 16.0), best, col); // body - hitBox(ro, rd, float3(-8.0, -4.0, -2.0), float3(-4.0, 8.0, 2.0), - float3(4.0, 12.0, 4.0), float3(4.0, 12.0, 4.0), float2(40.0, 16.0), best, col); // right arm - hitBox(ro, rd, float3(4.0, -4.0, -2.0), float3(8.0, 8.0, 2.0), - float3(4.0, 12.0, 4.0), float3(4.0, 12.0, 4.0), float2(32.0, 48.0), best, col); // left arm + hitBox(ro, rd, float3(-4.0 - aw, -4.0, -2.0), float3(-4.0, 8.0, 2.0), + float3(aw, 12.0, 4.0), float3(aw, 12.0, 4.0), float2(40.0, 16.0), best, col); // right arm + hitBox(ro, rd, float3(4.0, -4.0, -2.0), float3(4.0 + aw, 8.0, 2.0), + float3(aw, 12.0, 4.0), float3(aw, 12.0, 4.0), float2(32.0, 48.0), best, col); // left arm hitBox(ro, rd, float3(-4.0, -16.0, -2.0), float3(0.0, -4.0, 2.0), float3(4.0, 12.0, 4.0), float3(4.0, 12.0, 4.0), float2(0.0, 16.0), best, col); // right leg hitBox(ro, rd, float3(0.0, -16.0, -2.0), float3(4.0, -4.0, 2.0), @@ -328,10 +310,10 @@ half4 main(float2 fragCoord) { float3(9.0, 9.0, 9.0), float3(8.0, 8.0, 8.0), float2(32.0, 0.0), best, col); // hat hitBox(ro, rd, float3(-4.25, -4.25, -2.25), float3(4.25, 8.25, 2.25), float3(8.5, 12.5, 4.5), float3(8.0, 12.0, 4.0), float2(16.0, 32.0), best, col); // jacket - hitBox(ro, rd, float3(-8.25, -4.25, -2.25), float3(-3.75, 8.25, 2.25), - float3(4.5, 12.5, 4.5), float3(4.0, 12.0, 4.0), float2(40.0, 32.0), best, col); // right sleeve - hitBox(ro, rd, float3(3.75, -4.25, -2.25), float3(8.25, 8.25, 2.25), - float3(4.5, 12.5, 4.5), float3(4.0, 12.0, 4.0), float2(48.0, 48.0), best, col); // left sleeve + hitBox(ro, rd, float3(-3.75 - sw, -4.25, -2.25), float3(-3.75, 8.25, 2.25), + float3(sw, 12.5, 4.5), float3(aw, 12.0, 4.0), float2(40.0, 32.0), best, col); // right sleeve + hitBox(ro, rd, float3(3.75, -4.25, -2.25), float3(3.75 + sw, 8.25, 2.25), + float3(sw, 12.5, 4.5), float3(aw, 12.0, 4.0), float2(48.0, 48.0), best, col); // left sleeve hitBox(ro, rd, float3(-4.25, -16.25, -2.25), float3(0.25, -3.75, 2.25), float3(4.5, 12.5, 4.5), float3(4.0, 12.0, 4.0), float2(0.0, 32.0), best, col); // right pant hitBox(ro, rd, float3(-0.25, -16.25, -2.25), float3(4.25, -3.75, 2.25), diff --git a/packages/oneclient_app/src/hooks/mod.rs b/packages/oneclient_app/src/hooks/mod.rs index 3d8e13c8..25d18ef3 100644 --- a/packages/oneclient_app/src/hooks/mod.rs +++ b/packages/oneclient_app/src/hooks/mod.rs @@ -6,52 +6,92 @@ mod view_state; pub use view_state::{PersistedView, use_view_state}; pub use active_cluster::{ - use_active_cluster_id, use_provide_active_cluster, ActiveClusterState, BrowserCompatState, - use_browser_compat, use_provide_browser_compat, LinkConfirmState, use_link_confirm, - use_provide_link_confirm, BrowserUiState, BrowserStateStore, use_browser_state_store, - use_provide_browser_state, OnboardingSelectionState, use_onboarding_selection, + ActiveClusterState, BrowserCompatState, BrowserStateStore, BrowserUiState, LinkConfirmState, + OnboardingSelectionState, use_active_cluster_id, use_browser_compat, use_browser_state_store, + use_link_confirm, use_onboarding_selection, use_provide_active_cluster, + use_provide_browser_compat, use_provide_browser_state, use_provide_link_confirm, use_provide_onboarding_selection, }; pub use dispatch::BridgeDispatch; pub use queries::{ - try_cluster_analytics, try_global_analytics, use_cluster_analytics, use_global_analytics, - ClusterAction, invalidate_cluster_queries, invalidate_profile_queries, use_cluster_mutation, - AddOfflineAccountKeys, RefreshAccountKeys, RemoveAccountKeys, SetDefaultAccountKeys, - UseRefreshAccount, UseRemoveAccount, UseSetDefaultAccount, accounts_have_microsoft, - login_code_already_handled, - mutation_error, mutation_is_pending, pick_version_metadata, try_account, try_accounts, - try_default_account, try_game_profile, use_account, use_accounts, use_add_microsoft_account, - use_add_offline_account, use_begin_microsoft_login, use_bundle_updates, - bundle_overrides_map, bundles_with_status_items, use_bundle_overrides, use_bundles_with_status, - ClusterBundles, OnboardingBundlesQuery, onboarding_bundles_items, use_onboarding_bundles, - use_cached_image, CachedImageQuery, use_changelog, changelog_error, changelog_groups, - changelog_is_loading, use_cluster_content, cluster_content_items, - invalidate_java_queries, java_runtimes, provider_versions, use_java_runtimes, - use_provider_versions, - content_type_for_slug, package_meta_batch, project_detail, search_items, search_pending, - search_total, use_package_meta_batch, use_package_project, use_package_search, - use_package_versions, version_list, versions_total, use_package_categories, category_list, - BROWSE_PAGE_SIZE, VERSIONS_PAGE_SIZE, - use_cluster_profile, use_cluster_settings, + AddOfflineAccountKeys, BROWSE_PAGE_SIZE, CachedImageQuery, ClusterAction, ClusterBundles, + ClusterLogsQuery, LogAction, LogContentQuery, OnboardingBundlesQuery, RefreshAccountKeys, + RemoveAccountKeys, ScreenshotAction, SetDefaultAccountKeys, UploadLogKeys, UploadLogMutation, + UseLogAction, UseRefreshAccount, UseRemoveAccount, UseScreenshotAction, UseSetDefaultAccount, + UseUploadLog, VERSIONS_PAGE_SIZE, accounts_have_microsoft, bundle_overrides_map, + bundles_with_status_items, category_list, changelog_error, changelog_groups, + changelog_is_loading, cluster_content_items, content_type_for_slug, invalidate_cluster_queries, + invalidate_java_queries, invalidate_logs_queries, invalidate_profile_queries, + invalidate_screenshots_queries, java_runtimes, loader_versions, login_code_already_handled, + mutation_error, mutation_is_pending, onboarding_bundles_items, package_meta_batch, + pick_version_metadata, project_detail, provider_versions, search_items, search_pending, + search_total, try_account, try_accounts, try_cluster_analytics, try_cluster_logs, + try_cluster_screenshots, try_default_account, try_game_profile, try_global_analytics, + try_log_content, use_account, use_accounts, use_add_microsoft_account, use_add_offline_account, + use_begin_microsoft_login, use_bundle_overrides, use_bundle_updates, use_bundles_with_status, + use_cached_image, use_changelog, use_cluster_analytics, use_cluster_content, use_cluster_logs, + use_cluster_mutation, use_cluster_profile, use_cluster_screenshots, use_cluster_settings, use_clusters, use_current_account, use_default_account, use_finish_microsoft_login, - use_game_profile, use_named_profiles, use_player_profile, use_refresh_account, - use_refresh_all_accounts, use_remove_account, use_set_default_account, use_version_metadata, - use_versions, use_loader_versions, loader_versions, - ClusterLogsQuery, LogAction, LogContentQuery, UploadLogKeys, UploadLogMutation, - UseLogAction, UseUploadLog, invalidate_logs_queries, - try_cluster_logs, try_log_content, use_cluster_logs, use_log_action, use_log_content, - use_upload_log, - ScreenshotAction, UseScreenshotAction, invalidate_screenshots_queries, - try_cluster_screenshots, use_cluster_screenshots, use_local_image, use_screenshot_action, + use_game_profile, use_global_analytics, use_java_runtimes, use_loader_versions, + use_local_image, use_log_action, use_log_content, use_named_profiles, use_onboarding_bundles, + use_package_categories, use_package_meta_batch, use_package_project, use_package_search, + use_package_versions, use_player_profile, use_provider_versions, use_refresh_account, + use_refresh_all_accounts, use_remove_account, use_screenshot_action, use_set_default_account, + use_upload_log, use_version_metadata, use_versions, version_list, versions_total, }; use crate::notifications::NotificationSnapshot; +use bytes::Bytes; use freya::prelude::*; +use freya::query::QueryStateData; + +use crate::AppAssets; + +pub fn use_player_skin(uuid: String) -> (Bytes, bool) { + let profile = use_player_profile(uuid.clone(), None::); + + let (skin_url, is_slim) = match &*profile.read().state() { + QueryStateData::Settled { + res: Ok(profile), .. + } => (profile.skin_url.clone(), profile.is_slim), + _ => (None, false), + }; + + let skin_query = use_cached_image(skin_url.clone(), 256); + + let steve = use_memo(|| AppAssets::get_bytes("steve.png").unwrap_or_default()); + let alex = use_memo(|| AppAssets::get_bytes("alex.png").unwrap_or_default()); + + // No custom skin: pick alex (slim) or steve (classic) from the UUID. + let default_slim = (java_string_hash(&uuid) & 1) == 1; + + let reader = skin_query.read(); + match (&skin_url, &*reader.state()) { + (Some(_), QueryStateData::Settled { res: Ok(bytes), .. }) + | ( + Some(_), + QueryStateData::Loading { + res: Some(Ok(bytes)), + }, + ) => (bytes.clone(), is_slim), + _ if default_slim => (alex.read().clone(), true), + _ => (steve.read().clone(), false), + } +} + +/// Java `String.hashCode()`: h = h*31 + c over UTF-16 units, wrapping i32. +fn java_string_hash(s: &str) -> i32 { + let mut h: i32 = 0; + for c in s.encode_utf16() { + h = h.wrapping_mul(31).wrapping_add(c as i32); + } + h +} use crate::bridge::{ - use_bridge_snapshot, BridgeSnapshot, ClustersSnapshot, GameSnapshot, JavaSnapshot, LauncherInit, - OneClientBridge, ProfilesSnapshot, SettingsSnapshot, + BridgeSnapshot, ClustersSnapshot, GameSnapshot, JavaSnapshot, LauncherInit, OneClientBridge, + ProfilesSnapshot, SettingsSnapshot, use_bridge_snapshot, }; pub fn use_provide_bridge(bridge: &OneClientBridge) {