rework: rewrite the checking logic
* Fix a duplicate in diff place * Add cache on HttpTexture
This commit is contained in:
parent
06277bacb0
commit
a39c7a9402
@ -10,7 +10,10 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
public class SkinTypeFix implements ClientModInitializer {
|
||||
public static final Logger LOGGER = LoggerFactory.getLogger("SkinTypeFix");
|
||||
public static final String ID = "skintypefix";
|
||||
public static final String NAME = "SkinTypeFix";
|
||||
|
||||
public static final Logger LOGGER = LoggerFactory.getLogger(NAME);
|
||||
public static final Config CONFIG = ConfigLoader.get();
|
||||
|
||||
@Override
|
||||
|
@ -1,9 +1,11 @@
|
||||
package icu.puqns67.skintypefix.accessor;
|
||||
|
||||
import com.mojang.blaze3d.platform.NativeImage;
|
||||
import net.minecraft.client.resources.PlayerSkin;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface HttpTextureAccessor {
|
||||
void skinTypeFix$joinFuture();
|
||||
|
||||
NativeImage skinTypeFix$getImage();
|
||||
@Nullable
|
||||
PlayerSkin.Model skinTypeFix$getType();
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.minecraft.client.renderer.texture.HttpTexture;
|
||||
import net.minecraft.client.renderer.texture.SimpleTexture;
|
||||
import net.minecraft.client.resources.PlayerSkin;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
@ -14,6 +15,8 @@ import org.spongepowered.asm.mixin.*;
|
||||
import java.io.InputStream;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import static icu.puqns67.skintypefix.util.Utils.checkSkinModelType;
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@Mixin(HttpTexture.class)
|
||||
public abstract class HttpTextureMixin extends SimpleTexture implements HttpTextureAccessor {
|
||||
@ -29,6 +32,9 @@ public abstract class HttpTextureMixin extends SimpleTexture implements HttpText
|
||||
@Shadow
|
||||
@Final
|
||||
private boolean processLegacySkin;
|
||||
@Unique
|
||||
@Nullable
|
||||
private PlayerSkin.Model skinTypeFix$type = null;
|
||||
|
||||
public HttpTextureMixin(ResourceLocation location) {
|
||||
super(location);
|
||||
@ -45,10 +51,25 @@ public abstract class HttpTextureMixin extends SimpleTexture implements HttpText
|
||||
}
|
||||
}
|
||||
|
||||
@Unique
|
||||
private void setSkinTypeFix$closeImage() {
|
||||
if (this.skinTypeFix$image != null) {
|
||||
this.skinTypeFix$image.close();
|
||||
this.skinTypeFix$image = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Unique
|
||||
@Nullable
|
||||
public NativeImage skinTypeFix$getImage() {
|
||||
return this.skinTypeFix$image;
|
||||
public PlayerSkin.Model skinTypeFix$getType() {
|
||||
if (this.skinTypeFix$type == null) {
|
||||
if (this.skinTypeFix$image == null) {
|
||||
return null;
|
||||
}
|
||||
this.skinTypeFix$type = checkSkinModelType(this.skinTypeFix$image);
|
||||
this.setSkinTypeFix$closeImage();
|
||||
}
|
||||
return this.skinTypeFix$type;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -61,11 +82,16 @@ public abstract class HttpTextureMixin extends SimpleTexture implements HttpText
|
||||
try {
|
||||
var result = NativeImage.read(stream);
|
||||
if (this.processLegacySkin) {
|
||||
// If this.processLegacySkin is true, the image is the player's skin, so a backup needs to be created for check
|
||||
this.skinTypeFix$image = new NativeImage(64, 64, true);
|
||||
this.skinTypeFix$image.copyFrom(result);
|
||||
|
||||
result = this.processLegacySkin(result);
|
||||
|
||||
if (result != null) {
|
||||
this.setSkinTypeFix$closeImage();
|
||||
|
||||
// If this.processLegacySkin is true, the image is the player's skin,
|
||||
// so a backup needs to be created for check.
|
||||
this.skinTypeFix$image = new NativeImage(64, 64, true);
|
||||
this.skinTypeFix$image.copyFrom(result);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
|
@ -8,7 +8,6 @@ import com.mojang.authlib.minecraft.MinecraftSessionService;
|
||||
import icu.puqns67.skintypefix.SkinTypeFix;
|
||||
import icu.puqns67.skintypefix.accessor.HttpTextureAccessor;
|
||||
import icu.puqns67.skintypefix.util.Utils;
|
||||
import icu.puqns67.skintypefix.util.image.Places;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.minecraft.client.renderer.texture.TextureManager;
|
||||
@ -35,11 +34,11 @@ public class SkinManagerMixin {
|
||||
@Mutable
|
||||
@Final
|
||||
@Unique
|
||||
private TextureManager textureManager;
|
||||
private TextureManager skinTypeFix$textureManager;
|
||||
|
||||
@Inject(method = "<init>", at = @At("TAIL"))
|
||||
public void onInit(TextureManager textureManager, Path path, MinecraftSessionService minecraftSessionService, Executor executor, CallbackInfo ci) {
|
||||
this.textureManager = textureManager;
|
||||
this.skinTypeFix$textureManager = textureManager;
|
||||
}
|
||||
|
||||
@Inject(method = "registerTextures", at = @At("TAIL"), cancellable = true)
|
||||
@ -67,31 +66,24 @@ public class SkinManagerMixin {
|
||||
|
||||
CompletableFuture<PlayerSkin.Model> modelFuture = skinFuture.thenApply(v -> {
|
||||
// Get texture from TextureManager
|
||||
var skinTexture = (HttpTextureAccessor) textureManager.getTexture(skinFuture.join());
|
||||
var skinTexture = (HttpTextureAccessor) this.skinTypeFix$textureManager.getTexture(skinFuture.join());
|
||||
|
||||
// Wait skin loading if it needed fetch from web
|
||||
skinTexture.skinTypeFix$joinFuture();
|
||||
|
||||
// Get image from PlayerSkinTexture
|
||||
var skinImage = skinTexture.skinTypeFix$getImage();
|
||||
if (skinImage == null) {
|
||||
SkinTypeFix.LOGGER.warn("[SkinTypeFix] [{}] Unable to get image!", uuid);
|
||||
var skinModelChecked = skinTexture.skinTypeFix$getType();
|
||||
|
||||
if (skinModelChecked == null) {
|
||||
SkinTypeFix.LOGGER.warn("[SkinTypeFix] [{}] Unable to get skin type, using original skin type!", uuid);
|
||||
return skinModelOrigin;
|
||||
}
|
||||
|
||||
// Check skin type
|
||||
var needFix = switch (skinModelOrigin) {
|
||||
case SLIM -> !Places.DIFF_PLAYER_SKIN.hasTransparent(skinImage);
|
||||
case WIDE -> Places.DIFF_PLAYER_SKIN.hasTransparent(skinImage);
|
||||
};
|
||||
|
||||
if (needFix) {
|
||||
var skinModelFixed = Utils.reverseModelType(skinModelOrigin);
|
||||
SkinTypeFix.LOGGER.info("[SkinTypeFix] [{}] Fixed skin type: {} -> {}", uuid, skinModelOrigin, skinModelFixed);
|
||||
return skinModelFixed;
|
||||
if (skinModelOrigin != skinModelChecked) {
|
||||
SkinTypeFix.LOGGER.info("[SkinTypeFix] [{}] Fixed skin type: {} -> {}", uuid, skinModelOrigin, skinModelChecked);
|
||||
}
|
||||
|
||||
return skinModelOrigin;
|
||||
return skinModelChecked;
|
||||
});
|
||||
|
||||
// Return
|
||||
|
@ -1,19 +1,47 @@
|
||||
package icu.puqns67.skintypefix.util;
|
||||
|
||||
import com.mojang.blaze3d.platform.NativeImage;
|
||||
import icu.puqns67.skintypefix.SkinTypeFix;
|
||||
import icu.puqns67.skintypefix.util.image.Places;
|
||||
import icu.puqns67.skintypefix.util.image.Point;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.client.resources.PlayerSkin;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.UUID;
|
||||
|
||||
public class Utils {
|
||||
public static PlayerSkin.Model reverseModelType(PlayerSkin.Model type) {
|
||||
return switch (type) {
|
||||
case SLIM -> PlayerSkin.Model.WIDE;
|
||||
case WIDE -> PlayerSkin.Model.SLIM;
|
||||
};
|
||||
}
|
||||
private static final ArrayList<Point> PLAYER_SKIN_SLIM = Places.PLAYER_SKIN_SLIM.points();
|
||||
private static final ArrayList<Point> PLAYER_SKIN_DIFF_SLIM_TO_WILD = Places.PLAYER_SKIN_DIFF_SLIM_TO_WILD.points();
|
||||
|
||||
public static boolean isInvalidUUID(UUID uuid) {
|
||||
return Util.NIL_UUID.equals(uuid);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PlayerSkin.Model checkSkinModelType(NativeImage image) {
|
||||
SkinTypeFix.LOGGER.debug("Checking: {}", image);
|
||||
|
||||
var timesForDiff = new HashMap<Integer, Integer>();
|
||||
var timesForSlim = new HashMap<Integer, Integer>();
|
||||
PlayerSkin.Model result = null;
|
||||
|
||||
// The result of NativeImage.getPixelRGBA() is ARGB, not RGBA, like 0xAARRGGBB
|
||||
PLAYER_SKIN_DIFF_SLIM_TO_WILD.forEach(p -> timesForDiff.merge(image.getPixelRGBA(p.x(), p.y()), 1, Integer::sum));
|
||||
PLAYER_SKIN_SLIM.forEach(p -> timesForSlim.merge(image.getPixelRGBA(p.x(), p.y()), 1, Integer::sum));
|
||||
|
||||
var blackTimesForDiff = timesForDiff.getOrDefault(0xff000000, 0);
|
||||
var blackTimesForSlim = timesForSlim.getOrDefault(0xff000000, 0);
|
||||
|
||||
// Rules for check skin module type
|
||||
if (blackTimesForDiff == 64 && blackTimesForSlim < 256) {
|
||||
result = PlayerSkin.Model.SLIM;
|
||||
} else if (blackTimesForDiff == 0 || timesForDiff.size() >= 4) {
|
||||
result = PlayerSkin.Model.WIDE;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +1,30 @@
|
||||
package icu.puqns67.skintypefix.util.image;
|
||||
|
||||
import com.mojang.blaze3d.platform.NativeImage;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class Places {
|
||||
public static final Places DIFF_PLAYER_SKIN = Places.diffPlayerSkin();
|
||||
public static final Places PLAYER_SKIN_SLIM = Places.slimPlayerSkin();
|
||||
public static final Places PLAYER_SKIN_DIFF_SLIM_TO_WILD = Places.diffPlayerSkinSlimToWild();
|
||||
|
||||
private final ArrayList<Square> squares = new ArrayList<>();
|
||||
|
||||
public Places() {
|
||||
private static Places slimPlayerSkin() {
|
||||
var result = new Places();
|
||||
result.add(8, 0, 23, 7);
|
||||
result.add(0, 8, 31, 15);
|
||||
result.add(4, 16, 11, 19);
|
||||
result.add(20, 16, 35, 19);
|
||||
result.add(44, 16, 51, 19);
|
||||
result.add(0, 20, 55, 31);
|
||||
result.add(20, 48, 27, 51);
|
||||
result.add(36, 48, 43, 51);
|
||||
result.add(16, 52, 47, 63);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Places diffPlayerSkin() {
|
||||
private static Places diffPlayerSkinSlimToWild() {
|
||||
var result = new Places();
|
||||
result.add(50, 16, 51, 19);
|
||||
result.add(50, 16, 51, 19);
|
||||
result.add(54, 20, 55, 31);
|
||||
result.add(42, 48, 43, 51);
|
||||
result.add(46, 52, 47, 63);
|
||||
@ -29,12 +39,9 @@ public class Places {
|
||||
this.add(new Square(x1, y1, x2, y2));
|
||||
}
|
||||
|
||||
public boolean hasTransparent(NativeImage image) {
|
||||
for (var square : this.squares) {
|
||||
if (!square.hasTransparent(image)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
public ArrayList<Point> points() {
|
||||
var result = new ArrayList<Point>();
|
||||
this.squares.forEach(v -> result.addAll(v.points()));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,9 @@
|
||||
package icu.puqns67.skintypefix.util.image;
|
||||
|
||||
import com.mojang.blaze3d.platform.NativeImage;
|
||||
|
||||
public record Point(int x, int y) {
|
||||
public Point {
|
||||
if (x < 0 || y < 0) {
|
||||
throw new IllegalArgumentException(String.format("Invalid position: %d, %d", x, y));
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isTransparent(NativeImage image) {
|
||||
return image.getPixelRGBA(x, y) >>> 24 != 0xff;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
package icu.puqns67.skintypefix.util.image;
|
||||
|
||||
import com.mojang.blaze3d.platform.NativeImage;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public record Square(Point p1, Point p2) {
|
||||
@ -27,13 +25,4 @@ public record Square(Point p1, Point p2) {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean hasTransparent(NativeImage image) {
|
||||
for (var point : this.points()) {
|
||||
if (!point.isTransparent(image)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user