64x 皮肤解析器(64x Skin Parser)

基本信息

属性 值
效果类型 客户端资源处理(PNG 解析)
实现类 roadhog360.simpleskinbackport.client.ImageBufferDownloadPlayerSkin
替代对象 net.minecraft.client.renderer.ImageBufferDownload
触发来源 玩家皮肤纹理下载流程(SkinManager.func_152789_a)
触发物品 玩家在线状态变更时自动下载的玩家皮肤

功能

替代原版 32x64 皮肤解析器,把老格式(32x64)玩家皮肤升级到 64x64,并把新格式(64x64)皮肤原样保留。解析完成后通过 Metadata.model = "slim" 自动判定 slim 手臂。

与原版 ImageBufferDownload 的差异

行为 原版 本实现
输出尺寸 32x64 64x64
32x64 老皮肤处理 直接拉伸 用 12 次 drawImage 复制源区域到 64x64 的对应位置
64x64 新皮肤处理 不识别 直接拷贝到 64x64 画布
头部/身体/装备区域 alpha 标记 一致 一致(同样的 setAreaOpaque/Transparent)

老格式升级映射

源区域 (legacy 32x64)        →  目标区域 (64x64)        用途
(4,16)-(8,20)                →  (24,48)-(20,52)         左臂顶层
(8,16)-(12,20)               →  (28,48)-(24,52)         左臂顶层(镜像)
(8,20)-(12,32)               →  (20,52)-(16,64)         左臂下半
(4,20)-(8,32)                →  (24,52)-(20,64)         左臂下半(镜像)
(0,20)-(4,32)                →  (28,52)-(24,64)         身体左半(顶层覆盖)
(12,20)-(16,32)              →  (32,52)-(28,64)         身体右半(顶层覆盖)
(44,16)-(48,20)              →  (40,48)-(36,48)         右臂顶层
(48,16)-(52,20)              →  (44,48)-(40,48)         右臂顶层(镜像)
(48,20)-(52,32)              →  (36,52)-(32,64)         右臂下半
(44,20)-(48,32)              →  (40,52)-(36,64)         右臂下半(镜像)
(40,20)-(44,32)              →  (44,52)-(40,64)         身体右半(顶层覆盖)
(52,20)-(56,32)              →  (48,52)-(44,64)         身体右半(顶层覆盖)

触发方式

触发 1:MixinAbstractClientPlayer

@Redirect(method = "getDownloadImageSkin",
    at = @At(value = "NEW", target = "()Lnet/minecraft/client/renderer/ImageBufferDownload;"))
private static ImageBufferDownload use64xSkinParser() {
    return new ImageBufferDownloadPlayerSkin(null, null);
}

每次 AbstractClientPlayer.getDownloadImageSkin() 调用时构造解析器(texture = null, callback = null 是临时 hack —— 注释说明:“Once I figure out how to inject where this is called in SkinManager.class I’ll do that instead.”)。

触发 2:MixinSkinManager

@WrapOperation(method = "func_152789_a",
    at = @At(value = "NEW", target = "()Lnet/minecraft/client/renderer/ImageBufferDownload;"))
private ImageBufferDownload changeDownloadBufferManager(Operation<ImageBufferDownload> original,
    @Local MinecraftProfileTexture p_152789_1_,
    @Local MinecraftProfileTexture.Type p_152789_2_,
    @Local SkinManager.SkinAvailableCallback p_152789_3_) {
    if (Utils.isPlayer(p_152789_2_, p_152789_3_)) {
        return new ImageBufferDownloadPlayerSkin(p_152789_1_, p_152789_3_);  // 这里传 texture 和 callback
    }
    return original.call();
}

正式触发点:SkinManager.func_152789_a 中,MinecraftProfileTexture.Type.SKIN + callback 是 EntityPlayer 时替换。

解析完成后调用:Utils.setSlimFromMetadata

@Inject(method = "func_152789_a", at = @At(value = "TAIL", ...))
private void injectCallbackSkinCheck(MinecraftProfileTexture texture, ..., CallbackInfoReturnable<ResourceLocation> cir) {
    if (Utils.isPlayer(type, callback) && callback instanceof IArmsState playerData) {
        Utils.setSlimFromMetadata(texture, playerData);
    }
}

Utils.setSlimFromMetadata:

public static void setSlimFromMetadata(MinecraftProfileTexture texture, IArmsState data) {
    data.ssb$setSlim(Objects.equals(texture.getMetadata("model"), "slim"));
}

把 textures.SKIN.metadata.model = "slim" 映射为 IArmsState.ssb$setSlim(true)。

数值

数值 值 来源
目标画布尺寸 64x64 imageWidth = imageHeight = 64
BufferedImage 类型 TYPE_INT_ARGB new BufferedImage(64, 64, BufferedImage.TYPE_INT_ARGB)
老格式尺寸判定 buffImg.getHeight() == 32 仅当原图高 32 时升级
drawImage 调用数 12(老格式升级) 循环体 6 行 × 2 镜像
alpha 不透明区域 (0,0)-(32,16)、(0,16)-(64,32)、(16,48)-(48,64) setAreaOpaque 调用
alpha 透明区域 (32,0)-(64,32)、(0,32)-(16,48)、(16,32)-(40,48)、(40,32)-(56,48)、(0,48)-(16,64)、(48,48)-(64,64) setAreaTransparent 调用

第三方 mod 集成

无直接依赖。ImageBufferDownloadPlayerSkin 是 Minecraft Forge net.minecraft.client.renderer.ImageBufferDownload 的纯客户端替代品。

相关条目