SkinManager.java
net.minecraft.client.resources.SkinManager
信息
- 全限定名:net.minecraft.client.resources.SkinManager
- 类型:public class
- 包:net.minecraft.client.resources
- 源码路径:src/main/java/net/minecraft/client/resources/SkinManager.java
- 起始行号:L38
- 职责:
TODO
字段/常量
-
LOGGER- 类型:
Logger - 修饰符:
private static final - 源码定位:
L39 - 说明:
TODO
- 类型:
-
services- 类型:
Services - 修饰符:
private final - 源码定位:
L40 - 说明:
TODO
- 类型:
-
skinTextureDownloader- 类型:
SkinTextureDownloader - 修饰符:
private final - 源码定位:
L41 - 说明:
TODO
- 类型:
-
skinCache- 类型:
LoadingCache<SkinManager.CacheKey,CompletableFuture<Optional<PlayerSkin>>> - 修饰符:
private final - 源码定位:
L42 - 说明:
TODO
- 类型:
-
skinTextures- 类型:
SkinManager.TextureCache - 修饰符:
private final - 源码定位:
L43 - 说明:
TODO
- 类型:
-
capeTextures- 类型:
SkinManager.TextureCache - 修饰符:
private final - 源码定位:
L44 - 说明:
TODO
- 类型:
-
elytraTextures- 类型:
SkinManager.TextureCache - 修饰符:
private final - 源码定位:
L45 - 说明:
TODO
- 类型:
内部类/嵌套类型
-
net.minecraft.client.resources.SkinManager.CacheKey- 类型:
record - 修饰符:
private - 源码定位:
L142 - 说明:
TODO
- 类型:
-
net.minecraft.client.resources.SkinManager.TextureCache- 类型:
class - 修饰符:
private - 源码定位:
L146 - 说明:
TODO
- 类型:
构造器
public SkinManager(Path skinsDirectory, Services services, SkinTextureDownloader skinTextureDownloader, Executor mainThreadExecutor) @ L47
- 构造器名:SkinManager
- 源码定位:L47
- 修饰符:public
参数:
- skinsDirectory: Path
- services: Services
- skinTextureDownloader: SkinTextureDownloader
- mainThreadExecutor: Executor
说明:
TODO
方法
下面的方法块按源码顺序生成。
public Supplier<PlayerSkin> createLookup(GameProfile profile, boolean requireSecure) @ L88
- 方法名:createLookup
- 源码定位:L88
- 返回类型:Supplier
- 修饰符:public
参数:
- profile: GameProfile
- requireSecure: boolean
说明:
TODO
public CompletableFuture<Optional<PlayerSkin>> get(GameProfile profile) @ L104
- 方法名:get
- 源码定位:L104
- 返回类型:CompletableFuture<Optional
> - 修饰符:public
参数:
- profile: GameProfile
说明:
TODO
private CompletableFuture<PlayerSkin> registerTextures(UUID profileId, MinecraftProfileTextures textures) @ L114
- 方法名:registerTextures
- 源码定位:L114
- 返回类型:CompletableFuture
- 修饰符:private
参数:
- profileId: UUID
- textures: MinecraftProfileTextures
说明:
TODO
代码
@OnlyIn(Dist.CLIENT)
public class SkinManager {
private static final Logger LOGGER = LogUtils.getLogger();
private final Services services;
private final SkinTextureDownloader skinTextureDownloader;
private final LoadingCache<SkinManager.CacheKey, CompletableFuture<Optional<PlayerSkin>>> skinCache;
private final SkinManager.TextureCache skinTextures;
private final SkinManager.TextureCache capeTextures;
private final SkinManager.TextureCache elytraTextures;
public SkinManager(Path skinsDirectory, Services services, SkinTextureDownloader skinTextureDownloader, Executor mainThreadExecutor) {
this.services = services;
this.skinTextureDownloader = skinTextureDownloader;
this.skinTextures = new SkinManager.TextureCache(skinsDirectory, Type.SKIN);
this.capeTextures = new SkinManager.TextureCache(skinsDirectory, Type.CAPE);
this.elytraTextures = new SkinManager.TextureCache(skinsDirectory, Type.ELYTRA);
this.skinCache = CacheBuilder.newBuilder()
.expireAfterAccess(Duration.ofSeconds(15L))
.build(
new CacheLoader<SkinManager.CacheKey, CompletableFuture<Optional<PlayerSkin>>>() {
{
Objects.requireNonNull(SkinManager.this);
}
public CompletableFuture<Optional<PlayerSkin>> load(SkinManager.CacheKey key) {
return CompletableFuture.<MinecraftProfileTextures>supplyAsync(() -> {
Property packedTextures = key.packedTextures();
if (packedTextures == null) {
return MinecraftProfileTextures.EMPTY;
} else {
MinecraftProfileTextures textures = services.sessionService().unpackTextures(packedTextures);
if (textures.signatureState() == SignatureState.INVALID) {
SkinManager.LOGGER.warn("Profile contained invalid signature for textures property (profile id: {})", key.profileId());
}
return textures;
}
}, Util.backgroundExecutor().forName("unpackSkinTextures"))
.thenComposeAsync(textures -> SkinManager.this.registerTextures(key.profileId(), textures), mainThreadExecutor)
.handle((playerSkin, throwable) -> {
if (throwable != null) {
SkinManager.LOGGER.warn("Failed to load texture for profile {}", key.profileId, throwable);
}
return Optional.ofNullable(playerSkin);
});
}
}
);
}
public Supplier<PlayerSkin> createLookup(GameProfile profile, boolean requireSecure) {
CompletableFuture<Optional<PlayerSkin>> future = this.get(profile);
PlayerSkin defaultSkin = DefaultPlayerSkin.get(profile);
if (SharedConstants.DEBUG_DEFAULT_SKIN_OVERRIDE) {
return () -> defaultSkin;
} else {
Optional<PlayerSkin> currentValue = future.getNow(null);
if (currentValue != null) {
PlayerSkin playerSkin = currentValue.filter(skin -> !requireSecure || skin.secure()).orElse(defaultSkin);
return () -> playerSkin;
} else {
return () -> future.getNow(Optional.empty()).filter(skin -> !requireSecure || skin.secure()).orElse(defaultSkin);
}
}
}
public CompletableFuture<Optional<PlayerSkin>> get(GameProfile profile) {
if (SharedConstants.DEBUG_DEFAULT_SKIN_OVERRIDE) {
PlayerSkin defaultSkin = DefaultPlayerSkin.get(profile);
return CompletableFuture.completedFuture(Optional.of(defaultSkin));
} else {
Property packedTextures = this.services.sessionService().getPackedTextures(profile);
return this.skinCache.getUnchecked(new SkinManager.CacheKey(profile.id(), packedTextures));
}
}
private CompletableFuture<PlayerSkin> registerTextures(UUID profileId, MinecraftProfileTextures textures) {
MinecraftProfileTexture skinInfo = textures.skin();
CompletableFuture<ClientAsset.Texture> skinTexture;
PlayerModelType model;
if (skinInfo != null) {
skinTexture = this.skinTextures.getOrLoad(skinInfo);
model = PlayerModelType.byLegacyServicesName(skinInfo.getMetadata("model"));
} else {
PlayerSkin defaultSkin = DefaultPlayerSkin.get(profileId);
skinTexture = CompletableFuture.completedFuture(defaultSkin.body());
model = defaultSkin.model();
}
MinecraftProfileTexture capeInfo = textures.cape();
CompletableFuture<ClientAsset.Texture> capeTexture = capeInfo != null ? this.capeTextures.getOrLoad(capeInfo) : CompletableFuture.completedFuture(null);
MinecraftProfileTexture elytraInfo = textures.elytra();
CompletableFuture<ClientAsset.Texture> elytraTexture = elytraInfo != null
? this.elytraTextures.getOrLoad(elytraInfo)
: CompletableFuture.completedFuture(null);
return CompletableFuture.allOf(skinTexture, capeTexture, elytraTexture)
.thenApply(
unused -> new PlayerSkin(
skinTexture.join(), capeTexture.join(), elytraTexture.join(), model, textures.signatureState() == SignatureState.SIGNED
)
);
}
@OnlyIn(Dist.CLIENT)
private record CacheKey(UUID profileId, @Nullable Property packedTextures) {
}
@OnlyIn(Dist.CLIENT)
private class TextureCache {
private final Path root;
private final Type type;
private final Map<String, CompletableFuture<ClientAsset.Texture>> textures;
private TextureCache(Path root, Type type) {
Objects.requireNonNull(SkinManager.this);
super();
this.textures = new Object2ObjectOpenHashMap<>();
this.root = root;
this.type = type;
}
public CompletableFuture<ClientAsset.Texture> getOrLoad(MinecraftProfileTexture texture) {
String hash = texture.getHash();
CompletableFuture<ClientAsset.Texture> future = this.textures.get(hash);
if (future == null) {
future = this.registerTexture(texture);
this.textures.put(hash, future);
}
return future;
}
private CompletableFuture<ClientAsset.Texture> registerTexture(MinecraftProfileTexture textureInfo) {
String hash = Hashing.sha1().hashUnencodedChars(textureInfo.getHash()).toString();
Identifier textureId = this.getTextureLocation(hash);
Path file = this.root.resolve(hash.length() > 2 ? hash.substring(0, 2) : "xx").resolve(hash);
return SkinManager.this.skinTextureDownloader.downloadAndRegisterSkin(textureId, file, textureInfo.getUrl(), this.type == Type.SKIN);
}
private Identifier getTextureLocation(String textureHash) {
String root = switch (this.type) {
case SKIN -> "skins";
case CAPE -> "capes";
case ELYTRA -> "elytra";
};
return Identifier.withDefaultNamespace(root + "/" + textureHash);
}
}
}引用的其他类
-
- 引用位置:
参数/字段
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
DefaultPlayerSkin.get()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
Identifier.withDefaultNamespace()
- 引用位置:
-
- 引用位置:
参数/字段
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
Util.backgroundExecutor()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
PlayerModelType.byLegacyServicesName()
- 引用位置:
-
- 引用位置:
字段/构造调用/返回值 - 关联成员:
PlayerSkin()
- 引用位置: