feat: Alex + Slim skins support in avatar and player model renderer
This commit is contained in:
parent
2a2d992649
commit
784249005e
6 changed files with 102 additions and 111 deletions
BIN
packages/oneclient_app/assets/alex.png
Normal file
BIN
packages/oneclient_app/assets/alex.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 958 B |
|
|
@ -1,4 +0,0 @@
|
|||
<svg width="156" height="32" viewBox="0 0 156 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10.9398 25.6841C9.60192 25.6841 8.3644 25.447 7.22718 24.9728C6.10671 24.4986 5.12003 23.8381 4.26712 22.9913C3.41424 22.1446 2.75365 21.1623 2.28539 20.0446C1.81714 18.9099 1.58301 17.6905 1.58301 16.3865C1.58301 15.0655 1.81714 13.8461 2.28539 12.7284C2.75365 11.6107 3.40587 10.6368 4.24206 9.80701C5.07821 8.96023 6.05654 8.3082 7.17703 7.85093C8.31422 7.37675 9.55174 7.13965 10.8896 7.13965C12.2108 7.13965 13.4316 7.37675 14.5521 7.85093C15.6893 8.3082 16.676 8.96023 17.5122 9.80701C18.365 10.6368 19.0256 11.6191 19.4939 12.7538C19.9621 13.8715 20.1963 15.0909 20.1963 16.4119C20.1963 17.7159 19.9621 18.9353 19.4939 20.07C19.0256 21.1877 18.3734 22.17 17.5372 23.0168C16.7011 23.8466 15.7144 24.4986 14.5772 24.9728C13.4567 25.447 12.2443 25.6841 10.9398 25.6841ZM10.8896 22.0514C11.9432 22.0514 12.863 21.8143 13.649 21.3401C14.4517 20.8659 15.0705 20.2054 15.5053 19.3587C15.9401 18.495 16.1576 17.5042 16.1576 16.3865C16.1576 15.5397 16.0321 14.7776 15.7813 14.1002C15.5304 13.4058 15.1709 12.8131 14.7026 12.3219C14.2344 11.8139 13.6741 11.4328 13.0219 11.1788C12.3864 10.9078 11.6757 10.7723 10.8896 10.7723C9.83606 10.7723 8.90791 11.0094 8.10518 11.4836C7.31917 11.9409 6.70876 12.5929 6.27395 13.4397C5.83913 14.2695 5.62175 15.2518 5.62175 16.3865C5.62175 17.2332 5.74716 18.0038 5.99802 18.6982C6.24886 19.3925 6.60007 19.9937 7.05159 20.5018C7.51986 20.9929 8.08009 21.374 8.73232 21.645C9.38451 21.9159 10.1036 22.0514 10.8896 22.0514ZM24.2015 25.3793V7.4445H26.9609L28.1399 11.0264V25.3793H24.2015ZM36.4181 25.3793L25.9825 11.8393L26.9609 7.4445L37.3963 20.9845L36.4181 25.3793ZM36.4181 25.3793L35.3644 21.7974V7.4445H39.3029V25.3793H36.4181ZM44.2267 25.3793V7.4445H48.1649V25.3793H44.2267ZM47.2368 25.3793V21.9244H56.9448V25.3793H47.2368ZM47.2368 17.8853V14.5574H56.0669V17.8853H47.2368ZM47.2368 10.8739V7.4445H56.8192V10.8739H47.2368Z" fill="currentColor" fill-opacity="0.85"/>
|
||||
<path d="M69.2499 25.6588C67.9287 25.6588 66.6996 25.4302 65.5623 24.9729C64.4419 24.4987 63.4552 23.8382 62.6023 22.9915C61.7663 22.1447 61.1139 21.1624 60.6456 20.0447C60.1774 18.91 59.9434 17.6906 59.9434 16.3866C59.9434 15.0825 60.1774 13.8716 60.6456 12.7539C61.1139 11.6192 61.7663 10.6369 62.6023 9.80712C63.4386 8.97727 64.4168 8.33371 65.5373 7.87644C66.6746 7.40227 67.9037 7.16516 69.2248 7.16516C70.6296 7.16516 71.8756 7.3938 72.9625 7.85104C74.0663 8.30831 75.0279 8.93493 75.8473 9.7309L73.2134 12.4236C72.7452 11.9156 72.1766 11.5176 71.5076 11.2297C70.8555 10.9418 70.0946 10.7979 69.2248 10.7979C68.4556 10.7979 67.7448 10.9333 67.0927 11.2043C66.4572 11.4583 65.9053 11.8309 65.437 12.322C64.9854 12.8132 64.626 13.4059 64.3583 14.1003C64.1074 14.7946 63.9821 15.5567 63.9821 16.3866C63.9821 17.2334 64.1074 18.0039 64.3583 18.6983C64.626 19.3926 64.9854 19.9854 65.437 20.4765C65.9053 20.9676 66.4572 21.3487 67.0927 21.6197C67.7448 21.8907 68.4556 22.0261 69.2248 22.0261C70.1279 22.0261 70.914 21.8822 71.5828 21.5943C72.2518 21.3064 72.8288 20.9084 73.3137 20.4003L75.9729 23.0931C75.12 23.8891 74.1415 24.5156 73.0377 24.9729C71.9508 25.4302 70.6882 25.6588 69.2499 25.6588ZM79.6466 25.3794V7.44461H83.5851V25.3794H79.6466ZM82.6821 25.3794V21.8737H91.4367V25.3794H82.6821ZM95.2131 25.3794V7.44461H99.1515V25.3794H95.2131ZM104.067 25.3794V7.44461H108.006V25.3794H104.067ZM107.078 25.3794V21.9245H116.786V25.3794H107.078ZM107.078 17.8854V14.5575H115.908V17.8854H107.078ZM107.078 10.874V7.44461H116.66V10.874H107.078ZM121.006 25.3794V7.44461H123.765L124.944 11.0265V25.3794H121.006ZM133.222 25.3794L122.787 11.8394L123.765 7.44461L134.201 20.9846L133.222 25.3794ZM133.222 25.3794L132.169 21.7975V7.44461H136.107V25.3794H133.222ZM145.371 25.3794V7.69862H149.309V25.3794H145.371ZM139.827 10.9249V7.44461H154.853V10.9249H139.827Z" fill="currentColor"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 3.8 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 848 B |
|
|
@ -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::<String>);
|
||||
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -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::<String>);
|
||||
|
||||
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),
|
||||
|
|
|
|||
|
|
@ -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::<String>);
|
||||
|
||||
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) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue