forked from GeyserMC/Geyser
Fixes errors related to skins
This commit is contained in:
parent
51c1792d67
commit
068033aeaa
5 changed files with 30 additions and 27 deletions
|
@ -15,7 +15,6 @@ public class BedrockPlayerInitializedTranslator extends PacketTranslator<SetLoca
|
|||
|
||||
for (PlayerEntity entity : session.getEntityCache().getEntitiesByType(PlayerEntity.class)) {
|
||||
if (!entity.isValid()) {
|
||||
entity.sendPlayer(session);
|
||||
// async skin loading
|
||||
SkinUtils.requestAndHandleSkinAndCape(entity, session, skinAndCape -> entity.sendPlayer(session));
|
||||
}
|
||||
|
|
|
@ -51,8 +51,9 @@ public class JavaSpawnPlayerTranslator extends PacketTranslator<ServerSpawnPlaye
|
|||
entity.setPosition(position);
|
||||
entity.setRotation(rotation);
|
||||
|
||||
entity.sendPlayer(session);
|
||||
// async skin loading
|
||||
SkinUtils.requestAndHandleSkinAndCape(entity, session, skinAndCape -> entity.sendPlayer(session));
|
||||
if (session.getUpstream().isInitialized()) {
|
||||
SkinUtils.requestAndHandleSkinAndCape(entity, session, skinAndCape -> entity.sendPlayer(session));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package org.geysermc.connector.utils;
|
|||
import lombok.Getter;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.Color;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
@ -19,11 +18,11 @@ public class ProvidedSkin {
|
|||
try {
|
||||
for (int y = 0; y < image.getHeight(); y++) {
|
||||
for (int x = 0; x < image.getWidth(); x++) {
|
||||
Color color = new Color(image.getRGB(x, y), true);
|
||||
outputStream.write(color.getRed());
|
||||
outputStream.write(color.getGreen());
|
||||
outputStream.write(color.getBlue());
|
||||
outputStream.write(color.getAlpha());
|
||||
int rgba = image.getRGB(x, y);
|
||||
outputStream.write((rgba >> 16) & 0xFF); // Red
|
||||
outputStream.write((rgba >> 8) & 0xFF); // Green
|
||||
outputStream.write(rgba & 0xFF); // Blue
|
||||
outputStream.write((rgba >> 24) & 0xFF); // Alpha
|
||||
}
|
||||
}
|
||||
image.flush();
|
||||
|
|
|
@ -22,12 +22,12 @@ public class SkinProvider {
|
|||
public static final boolean ALLOW_THIRD_PARTY_CAPES = ((GeyserConnector)Geyser.getConnector()).getConfig().isAllowThirdPartyCapes();
|
||||
private static final ExecutorService EXECUTOR_SERVICE = Executors.newFixedThreadPool(ALLOW_THIRD_PARTY_CAPES ? 21 : 14);
|
||||
|
||||
public static final Skin EMPTY_SKIN = new Skin(-1, "");
|
||||
public static final byte[] STEVE_SKIN = new ProvidedSkin("bedrock/skin/skin_steve.png").getSkin();
|
||||
public static final Skin EMPTY_SKIN = new Skin(-1, "steve", STEVE_SKIN);
|
||||
private static Map<UUID, Skin> cachedSkins = new ConcurrentHashMap<>();
|
||||
private static Map<UUID, CompletableFuture<Skin>> requestedSkins = new ConcurrentHashMap<>();
|
||||
|
||||
public static final Cape EMPTY_CAPE = new Cape("", new byte[0], -1, true);
|
||||
public static final Cape EMPTY_CAPE = new Cape("", "no-cape", new byte[0], -1, true);
|
||||
private static Map<String, Cape> cachedCapes = new ConcurrentHashMap<>();
|
||||
private static Map<String, CompletableFuture<Cape>> requestedCapes = new ConcurrentHashMap<>();
|
||||
|
||||
|
@ -149,8 +149,11 @@ public class SkinProvider {
|
|||
cape = requestImage(capeUrl, true);
|
||||
} catch (Exception ignored) {} // just ignore I guess
|
||||
|
||||
String[] urlSection = capeUrl.split("/"); // A real url is expected at this stage
|
||||
|
||||
return new Cape(
|
||||
capeUrl,
|
||||
urlSection[urlSection.length - 1], // get the texture id and use it as cape id
|
||||
cape.length > 0 ? cape : EMPTY_CAPE.getCapeData(),
|
||||
System.currentTimeMillis(),
|
||||
cape.length == 0
|
||||
|
@ -209,13 +212,14 @@ public class SkinProvider {
|
|||
public static class Skin {
|
||||
private UUID skinOwner;
|
||||
private String textureUrl;
|
||||
private byte[] skinData = STEVE_SKIN;
|
||||
private byte[] skinData;
|
||||
private long requestedOn;
|
||||
private boolean updated;
|
||||
|
||||
private Skin(long requestedOn, String textureUrl) {
|
||||
private Skin(long requestedOn, String textureUrl, byte[] skinData) {
|
||||
this.requestedOn = requestedOn;
|
||||
this.textureUrl = textureUrl;
|
||||
this.skinData = skinData;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -223,6 +227,7 @@ public class SkinProvider {
|
|||
@Getter
|
||||
public static class Cape {
|
||||
private String textureUrl;
|
||||
private String capeId;
|
||||
private byte[] capeData;
|
||||
private long requestedOn;
|
||||
private boolean failed;
|
||||
|
|
|
@ -20,6 +20,7 @@ import java.util.function.Consumer;
|
|||
public class SkinUtils {
|
||||
public static PlayerListPacket.Entry buildCachedEntry(GameProfile profile, long geyserId) {
|
||||
GameProfileData data = GameProfileData.from(profile);
|
||||
SkinProvider.Cape cape = SkinProvider.getCachedCape(data.getCapeUrl());
|
||||
|
||||
return buildEntryManually(
|
||||
profile.getId(),
|
||||
|
@ -27,7 +28,8 @@ public class SkinUtils {
|
|||
geyserId,
|
||||
profile.getIdAsString(),
|
||||
SkinProvider.getCachedSkin(profile.getId()).getSkinData(),
|
||||
SkinProvider.getCachedCape(data.getCapeUrl()).getCapeData(),
|
||||
cape.getCapeId(),
|
||||
cape.getCapeData(),
|
||||
getLegacySkinGeometry("geometry.humanoid.custom" + (data.isAlex() ? "Slim" : "")),
|
||||
""
|
||||
);
|
||||
|
@ -40,6 +42,7 @@ public class SkinUtils {
|
|||
geyserId,
|
||||
profile.getIdAsString(),
|
||||
SkinProvider.STEVE_SKIN,
|
||||
SkinProvider.EMPTY_CAPE.getCapeId(),
|
||||
SkinProvider.EMPTY_CAPE.getCapeData(),
|
||||
getLegacySkinGeometry("geometry.humanoid"),
|
||||
""
|
||||
|
@ -47,18 +50,13 @@ public class SkinUtils {
|
|||
}
|
||||
|
||||
public static PlayerListPacket.Entry buildEntryManually(UUID uuid, String username, long geyserId,
|
||||
String skinId, byte[] skinData, byte[] capeData,
|
||||
String skinId, byte[] skinData,
|
||||
String capeId, byte[] capeData,
|
||||
String geometryName, String geometryData) {
|
||||
if (skinData == null || skinData.length == 0) {
|
||||
skinData = SkinProvider.EMPTY_SKIN.getSkinData();
|
||||
}
|
||||
|
||||
if (capeData == null || capeData.length == 0) {
|
||||
capeData = SkinProvider.EMPTY_CAPE.getCapeData();
|
||||
}
|
||||
|
||||
SerializedSkin serializedSkin = SerializedSkin.of(skinId, geometryName, ImageData.of(64, 64, skinData),
|
||||
Collections.emptyList(), ImageData.of(64, 32, capeData), geometryData, "", true, false, false, "", "");
|
||||
SerializedSkin serializedSkin = SerializedSkin.of(
|
||||
skinId, geometryName, ImageData.of(skinData), Collections.emptyList(),
|
||||
ImageData.of(capeData), geometryData, "", true, false, false, capeId, uuid.toString()
|
||||
);
|
||||
|
||||
PlayerListPacket.Entry entry = new PlayerListPacket.Entry(uuid);
|
||||
entry.setName(username);
|
||||
|
@ -107,7 +105,7 @@ public class SkinUtils {
|
|||
public static void requestAndHandleSkinAndCape(PlayerEntity entity, GeyserSession session,
|
||||
Consumer<SkinProvider.SkinAndCape> skinAndCapeConsumer) {
|
||||
Geyser.getGeneralThreadPool().execute(() -> {
|
||||
SkinUtils.GameProfileData data = SkinUtils.GameProfileData.from(entity.getProfile());
|
||||
GameProfileData data = GameProfileData.from(entity.getProfile());
|
||||
|
||||
SkinProvider.requestSkinAndCape(entity.getUuid(), data.getSkinUrl(), data.getCapeUrl())
|
||||
.whenCompleteAsync((skinAndCape, throwable) -> {
|
||||
|
@ -126,12 +124,13 @@ public class SkinUtils {
|
|||
entity.setLastSkinUpdate(skin.getRequestedOn());
|
||||
|
||||
if (session.getUpstream().isInitialized()) {
|
||||
PlayerListPacket.Entry updatedEntry = SkinUtils.buildEntryManually(
|
||||
PlayerListPacket.Entry updatedEntry = buildEntryManually(
|
||||
entity.getUuid(),
|
||||
entity.getUsername(),
|
||||
entity.getGeyserId(),
|
||||
entity.getUuid().toString(),
|
||||
skin.getSkinData(),
|
||||
cape.getCapeId(),
|
||||
cape.getCapeData(),
|
||||
getLegacySkinGeometry("geometry.humanoid.custom" + (data.isAlex() ? "Slim" : "")),
|
||||
""
|
||||
|
|
Loading…
Reference in a new issue