mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-12-22 22:45:04 +01:00
Start on custom skulls
Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>
This commit is contained in:
parent
1bdbcab4e8
commit
3f499e3ec0
7 changed files with 96 additions and 54 deletions
|
@ -25,9 +25,13 @@
|
|||
|
||||
package org.geysermc.geyser.skin;
|
||||
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.StringTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.Tag;
|
||||
import com.github.steveice10.mc.auth.data.GameProfile;
|
||||
import com.github.steveice10.mc.auth.data.GameProfile.Texture;
|
||||
import com.github.steveice10.mc.auth.data.GameProfile.TextureModel;
|
||||
import com.github.steveice10.mc.auth.data.GameProfile.TextureType;
|
||||
import com.github.steveice10.mc.auth.exception.property.PropertyException;
|
||||
import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType;
|
||||
import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
|
@ -39,11 +43,13 @@ import org.geysermc.geyser.GeyserImpl;
|
|||
import org.geysermc.geyser.entity.type.LivingEntity;
|
||||
import org.geysermc.geyser.entity.type.player.PlayerEntity;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.skin.SkinManager.GameProfileData;
|
||||
import org.geysermc.geyser.text.GeyserLocale;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
@ -95,38 +101,60 @@ public class FakeHeadProvider {
|
|||
}
|
||||
});
|
||||
|
||||
public static void setHead(GeyserSession session, PlayerEntity entity, Tag skullOwner) {
|
||||
if (skullOwner == null) {
|
||||
public static void setHead(GeyserSession session, PlayerEntity entity, DataComponents components) {
|
||||
GameProfile profile = components.get(DataComponentType.PROFILE);
|
||||
|
||||
if (profile == null) {
|
||||
return;
|
||||
}
|
||||
if (skullOwner instanceof CompoundTag profileTag) {
|
||||
SkinManager.GameProfileData gameProfileData = SkinManager.GameProfileData.from(profileTag);
|
||||
if (gameProfileData == null) {
|
||||
|
||||
Map<TextureType, Texture> textures = null;
|
||||
try {
|
||||
textures = profile.getTextures(false);
|
||||
} catch (PropertyException e) {
|
||||
session.getGeyser().getLogger().debug("Failed to get textures from GameProfile: " + e);
|
||||
}
|
||||
|
||||
if (textures == null || textures.isEmpty()) {
|
||||
loadHead(session, entity, profile.getName());
|
||||
return;
|
||||
}
|
||||
|
||||
Texture skinTexture = textures.get(TextureType.SKIN);
|
||||
|
||||
if (skinTexture == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Texture capeTexture = textures.get(TextureType.CAPE);
|
||||
String capeUrl = capeTexture != null ? capeTexture.getURL() : null;
|
||||
|
||||
boolean isAlex = skinTexture.getModel() == TextureModel.SLIM;
|
||||
|
||||
loadHead(session, entity, new GameProfileData(skinTexture.getURL(), capeUrl, isAlex));
|
||||
}
|
||||
|
||||
public static void loadHead(GeyserSession session, PlayerEntity entity, String owner) {
|
||||
if (owner == null || owner.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
CompletableFuture<String> completableFuture = SkinProvider.requestTexturesFromUsername(owner);
|
||||
completableFuture.whenCompleteAsync((encodedJson, throwable) -> {
|
||||
if (throwable != null) {
|
||||
GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.skin.fail", entity.getUuid()), throwable);
|
||||
return;
|
||||
}
|
||||
loadHead(session, entity, gameProfileData);
|
||||
} else if (skullOwner instanceof StringTag ownerTag) {
|
||||
String owner = ownerTag.getValue();
|
||||
if (owner.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
CompletableFuture<String> completableFuture = SkinProvider.requestTexturesFromUsername(owner);
|
||||
completableFuture.whenCompleteAsync((encodedJson, throwable) -> {
|
||||
if (throwable != null) {
|
||||
GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.skin.fail", entity.getUuid()), throwable);
|
||||
try {
|
||||
SkinManager.GameProfileData gameProfileData = SkinManager.GameProfileData.loadFromJson(encodedJson);
|
||||
if (gameProfileData == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
SkinManager.GameProfileData gameProfileData = SkinManager.GameProfileData.loadFromJson(encodedJson);
|
||||
if (gameProfileData == null) {
|
||||
return;
|
||||
}
|
||||
loadHead(session, entity, gameProfileData);
|
||||
} catch (IOException e) {
|
||||
GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.skin.fail", entity.getUuid(), e.getMessage()));
|
||||
}
|
||||
});
|
||||
}
|
||||
loadHead(session, entity, gameProfileData);
|
||||
} catch (IOException e) {
|
||||
GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.skin.fail", entity.getUuid(), e.getMessage()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void loadHead(GeyserSession session, PlayerEntity entity, SkinManager.GameProfileData gameProfileData) {
|
||||
|
|
|
@ -225,7 +225,7 @@ public abstract class InventoryTranslator {
|
|||
GeyserItemStack javaItem = inventory.getItem(sourceSlot);
|
||||
if (javaItem.asItem() == Items.PLAYER_HEAD
|
||||
&& javaItem.getNbt() != null) {
|
||||
FakeHeadProvider.setHead(session, session.getPlayerEntity(), javaItem.getNbt().get("SkullOwner"));
|
||||
FakeHeadProvider.setHead(session, session.getPlayerEntity(), javaItem.getComponents());
|
||||
}
|
||||
} else if (sourceSlot == 5) {
|
||||
//we are probably removing the head, so restore the original skin
|
||||
|
|
|
@ -100,7 +100,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
|||
if (i == 5 &&
|
||||
item.asItem() == Items.PLAYER_HEAD &&
|
||||
item.getNbt() != null) {
|
||||
FakeHeadProvider.setHead(session, session.getPlayerEntity(), item.getNbt().get("SkullOwner"));
|
||||
FakeHeadProvider.setHead(session, session.getPlayerEntity(), item.getComponents());
|
||||
}
|
||||
}
|
||||
armorContentPacket.setContents(Arrays.asList(contents));
|
||||
|
@ -144,7 +144,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
|||
// Check for custom skull
|
||||
if (javaItem.asItem() == Items.PLAYER_HEAD
|
||||
&& javaItem.getNbt() != null) {
|
||||
FakeHeadProvider.setHead(session, session.getPlayerEntity(), javaItem.getNbt().get("SkullOwner"));
|
||||
FakeHeadProvider.setHead(session, session.getPlayerEntity(), javaItem.getComponents());
|
||||
} else {
|
||||
FakeHeadProvider.restoreOriginalSkin(session, session.getPlayerEntity());
|
||||
}
|
||||
|
|
|
@ -26,6 +26,9 @@
|
|||
package org.geysermc.geyser.translator.item;
|
||||
|
||||
import com.github.steveice10.mc.auth.data.GameProfile;
|
||||
import com.github.steveice10.mc.auth.data.GameProfile.Texture;
|
||||
import com.github.steveice10.mc.auth.data.GameProfile.TextureType;
|
||||
import com.github.steveice10.mc.auth.exception.property.PropertyException;
|
||||
import com.github.steveice10.mc.protocol.data.game.Identifier;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.attribute.ModifierOperation;
|
||||
import com.github.steveice10.mc.protocol.data.game.item.ItemStack;
|
||||
|
@ -553,21 +556,28 @@ public final class ItemTranslator {
|
|||
if (components == null) {
|
||||
return null;
|
||||
}
|
||||
//TODO
|
||||
|
||||
GameProfile profile = components.get(DataComponentType.PROFILE);
|
||||
if (profile != null) {
|
||||
// if (!(nbt.get("SkullOwner") instanceof CompoundTag skullOwner)) {
|
||||
// // It's a username give up d:
|
||||
// return null;
|
||||
// }
|
||||
// SkinManager.GameProfileData data = SkinManager.GameProfileData.from(skullOwner);
|
||||
// if (data == null) {
|
||||
// session.getGeyser().getLogger().debug("Not sure how to handle skull head item display. " + nbt);
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// String skinHash = data.skinUrl().substring(data.skinUrl().lastIndexOf('/') + 1);
|
||||
// return BlockRegistries.CUSTOM_SKULLS.get(skinHash);
|
||||
Map<TextureType, Texture> textures = null;
|
||||
try {
|
||||
textures = profile.getTextures(false);
|
||||
} catch (PropertyException e) {
|
||||
session.getGeyser().getLogger().debug("Failed to get textures from GameProfile: " + e);
|
||||
}
|
||||
|
||||
if (textures == null || textures.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Texture skinTexture = textures.get(TextureType.SKIN);
|
||||
|
||||
if (skinTexture == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String skinHash = skinTexture.getURL().substring(skinTexture.getURL().lastIndexOf('/') + 1);
|
||||
return BlockRegistries.CUSTOM_SKULLS.get(skinHash);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -101,6 +101,7 @@ public class SkullBlockEntityTranslator extends BlockEntityTranslator implements
|
|||
}
|
||||
|
||||
public static @Nullable BlockDefinition translateSkull(GeyserSession session, CompoundTag tag, Vector3i blockPosition, int blockState) {
|
||||
// TODO: The tag layout follows new format (profille, etc...)
|
||||
CompoundTag owner = tag.get("SkullOwner");
|
||||
if (owner == null) {
|
||||
session.getSkullCache().removeSkull(blockPosition);
|
||||
|
|
|
@ -31,7 +31,10 @@ import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.Client
|
|||
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
||||
import org.geysermc.geyser.entity.type.Entity;
|
||||
import org.geysermc.geyser.entity.type.LivingEntity;
|
||||
import org.geysermc.geyser.entity.type.player.PlayerEntity;
|
||||
import org.geysermc.geyser.item.Items;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.skin.FakeHeadProvider;
|
||||
import org.geysermc.geyser.translator.item.ItemTranslator;
|
||||
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
||||
import org.geysermc.geyser.translator.protocol.Translator;
|
||||
|
@ -59,15 +62,14 @@ public class JavaSetEquipmentTranslator extends PacketTranslator<ClientboundSetE
|
|||
switch (equipment.getSlot()) {
|
||||
case HELMET -> {
|
||||
ItemStack javaItem = equipment.getItem();
|
||||
// TODO
|
||||
// if (livingEntity instanceof PlayerEntity
|
||||
// && javaItem != null
|
||||
// && javaItem.getId() == Items.PLAYER_HEAD.javaId()
|
||||
// && javaItem.getNbt() != null) {
|
||||
// FakeHeadProvider.setHead(session, (PlayerEntity) livingEntity, javaItem.getNbt().get("SkullOwner"));
|
||||
// } else {
|
||||
// FakeHeadProvider.restoreOriginalSkin(session, livingEntity);
|
||||
// }
|
||||
if (livingEntity instanceof PlayerEntity
|
||||
&& javaItem != null
|
||||
&& javaItem.getId() == Items.PLAYER_HEAD.javaId()
|
||||
&& javaItem.getDataComponents() != null) {
|
||||
FakeHeadProvider.setHead(session, (PlayerEntity) livingEntity, javaItem.getDataComponents());
|
||||
} else {
|
||||
FakeHeadProvider.restoreOriginalSkin(session, livingEntity);
|
||||
}
|
||||
|
||||
livingEntity.setHelmet(item);
|
||||
armorUpdated = true;
|
||||
|
|
|
@ -425,6 +425,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator<Clientbo
|
|||
bedrockBlockEntities.add(blockEntityTranslator.getBlockEntityTag(session, type, x + chunkBlockX, y, z + chunkBlockZ, tag, blockState));
|
||||
|
||||
// Check for custom skulls
|
||||
// TODO: The tag layout follows new format (profille, etc...)
|
||||
if (session.getPreferencesCache().showCustomSkulls() && type == BlockEntityType.SKULL && tag != null && tag.contains("SkullOwner")) {
|
||||
BlockDefinition blockDefinition = SkullBlockEntityTranslator.translateSkull(session, tag, Vector3i.from(x + chunkBlockX, y, z + chunkBlockZ), blockState);
|
||||
if (blockDefinition != null) {
|
||||
|
|
Loading…
Reference in a new issue