1
0
mirror of https://github.com/Suiranoil/SkinRestorer.git synced 2026-01-16 04:42:12 +00:00

support custom skins for player head block

This commit is contained in:
2025-07-05 19:15:22 +03:00
parent 1b8a6c2f5d
commit e65501e620
4 changed files with 71 additions and 2 deletions

View File

@@ -0,0 +1,54 @@
package net.lionarius.skinrestorer.mixin;
import com.mojang.authlib.GameProfile;
import net.lionarius.skinrestorer.SkinRestorer;
import net.lionarius.skinrestorer.util.PlayerUtils;
import net.minecraft.server.Services;
import net.minecraft.world.level.block.entity.SkullBlockEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.function.BooleanSupplier;
@Mixin(SkullBlockEntity.class)
public abstract class SkullBlockEntityMixin {
@Inject(method = "fetchProfileByName", at = @At("HEAD"),
cancellable = true)
private static void fetchProfileByName(String name, Services services, CallbackInfoReturnable<CompletableFuture<Optional<GameProfile>>> cir) {
var profileOpt = services.profileCache().get(name);
skinrestorer$replaceSkin(profileOpt, cir);
}
@Inject(method = "fetchProfileById", at = @At("HEAD"),
cancellable = true)
private static void fetchProfileById(UUID id, Services services, BooleanSupplier cacheUninitialized, CallbackInfoReturnable<CompletableFuture<Optional<GameProfile>>> cir) {
var profileOpt = services.profileCache().get(id);
skinrestorer$replaceSkin(profileOpt, cir);
}
@Unique
private static void skinrestorer$replaceSkin(Optional<GameProfile> profileOpt, CallbackInfoReturnable<CompletableFuture<Optional<GameProfile>>> cir) {
if (profileOpt.isEmpty())
return;
var profile = PlayerUtils.cloneGameProfile(profileOpt.get());
if (SkinRestorer.getSkinStorage().hasSavedSkin(profile.getId())) {
cir.setReturnValue(CompletableFuture.supplyAsync(() -> {
var skin = SkinRestorer.getSkinStorage().getSkin(profile.getId(), false);
PlayerUtils.applyRestoredSkin(profile, skin.value());
return Optional.of(profile);
}));
}
}
}

View File

@@ -17,15 +17,22 @@ public class SkinStorage {
return this.skinMap.containsKey(uuid) || this.skinIO.skinExists(uuid); return this.skinMap.containsKey(uuid) || this.skinIO.skinExists(uuid);
} }
public SkinValue getSkin(UUID uuid) { public SkinValue getSkin(UUID uuid, boolean cache) {
if (!skinMap.containsKey(uuid)) { if (!skinMap.containsKey(uuid)) {
var skin = skinIO.loadSkin(uuid); var skin = skinIO.loadSkin(uuid);
if (!cache)
return skin;
setSkin(uuid, skin); setSkin(uuid, skin);
} }
return skinMap.get(uuid); return skinMap.get(uuid);
} }
public SkinValue getSkin(UUID uuid) {
return this.getSkin(uuid, true);
}
public void removeSkin(UUID uuid, boolean save) { public void removeSkin(UUID uuid, boolean save) {
var skin = skinMap.remove(uuid); var skin = skinMap.remove(uuid);
if (skin != null && save) if (skin != null && save)

View File

@@ -96,6 +96,13 @@ public final class PlayerUtils {
} }
} }
public static GameProfile cloneGameProfile(GameProfile profile) {
var newProfile = new GameProfile(profile.getId(), profile.getName());
newProfile.getProperties().putAll(profile.getProperties());
return newProfile;
}
public static Property getPlayerSkin(GameProfile profile) { public static Property getPlayerSkin(GameProfile profile) {
return Iterables.getFirst(profile.getProperties().get(TEXTURES_KEY), null); return Iterables.getFirst(profile.getProperties().get(TEXTURES_KEY), null);
} }

View File

@@ -9,7 +9,8 @@
"ChunkMapAccessor", "ChunkMapAccessor",
"PlayerListMixin", "PlayerListMixin",
"ServerLoginPacketListenerImplMixin", "ServerLoginPacketListenerImplMixin",
"TrackedEntityAccessorInvoker" "TrackedEntityAccessorInvoker",
"SkullBlockEntityMixin"
], ],
"injectors": { "injectors": {
"defaultRequire": 1 "defaultRequire": 1