1
0
mirror of https://github.com/GeyserMC/Geyser.git synced 2025-12-19 14:59:27 +00:00

Fix: "Invalid skin length" issue, code-of-conduct screen not appearing correctly on server switching, InputMode / UiProfile not being read correctly

Fixes https://github.com/GeyserMC/Geyser/issues/5995, fixes https://github.com/GeyserMC/Geyser/issues/5994
This commit is contained in:
onebeastchris
2025-11-23 21:28:14 +01:00
parent 473a4a58fd
commit e726b91f08
5 changed files with 21 additions and 9 deletions

View File

@@ -747,6 +747,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
private boolean allowVibrantVisuals = true; private boolean allowVibrantVisuals = true;
@Accessors(fluent = true) @Accessors(fluent = true)
@Setter
private boolean hasAcceptedCodeOfConduct = false; private boolean hasAcceptedCodeOfConduct = false;
@Accessors(fluent = true) @Accessors(fluent = true)

View File

@@ -46,6 +46,7 @@ import org.geysermc.floodgate.util.UiProfile;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.UUID; import java.util.UUID;
@Getter @Getter
@@ -62,7 +63,8 @@ public final class BedrockClientData {
@SerializedName(value = "SkinId") @SerializedName(value = "SkinId")
private String skinId; private String skinId;
@SerializedName(value = "SkinData") @SerializedName(value = "SkinData")
private String skinData; @JsonAdapter(value = StringToByteDeserializer.class)
private byte[] skinData;
@SerializedName(value = "SkinImageHeight") @SerializedName(value = "SkinImageHeight")
private int skinImageHeight; private int skinImageHeight;
@SerializedName(value = "SkinImageWidth") @SerializedName(value = "SkinImageWidth")
@@ -79,9 +81,11 @@ public final class BedrockClientData {
@SerializedName(value = "CapeOnClassicSkin") @SerializedName(value = "CapeOnClassicSkin")
private boolean capeOnClassicSkin; private boolean capeOnClassicSkin;
@SerializedName(value = "SkinResourcePatch") @SerializedName(value = "SkinResourcePatch")
private String geometryName; @JsonAdapter(value = StringToByteDeserializer.class)
private byte[] geometryName;
@SerializedName(value = "SkinGeometryData") @SerializedName(value = "SkinGeometryData")
private String geometryData; @JsonAdapter(value = StringToByteDeserializer.class)
private byte[] geometryData;
@SerializedName(value = "PersonaSkin") @SerializedName(value = "PersonaSkin")
private boolean personaSkin; private boolean personaSkin;
@SerializedName(value = "PremiumSkin") @SerializedName(value = "PremiumSkin")
@@ -95,12 +99,15 @@ public final class BedrockClientData {
@JsonAdapter(value = IntToEnumTypeFactory.class) @JsonAdapter(value = IntToEnumTypeFactory.class)
private DeviceOs deviceOs; private DeviceOs deviceOs;
@SerializedName(value = "UIProfile") @SerializedName(value = "UIProfile")
@JsonAdapter(value = IntToEnumTypeFactory.class)
private UiProfile uiProfile; private UiProfile uiProfile;
@SerializedName(value = "GuiScale") @SerializedName(value = "GuiScale")
private int guiScale; private int guiScale;
@SerializedName(value = "CurrentInputMode") @SerializedName(value = "CurrentInputMode")
@JsonAdapter(value = IntToEnumTypeFactory.class)
private InputMode currentInputMode; private InputMode currentInputMode;
@SerializedName(value = "DefaultInputMode") @SerializedName(value = "DefaultInputMode")
@JsonAdapter(value = IntToEnumTypeFactory.class)
private InputMode defaultInputMode; private InputMode defaultInputMode;
@SerializedName("PlatformOnlineId") @SerializedName("PlatformOnlineId")
private String platformOnlineId; private String platformOnlineId;
@@ -144,7 +151,7 @@ public final class BedrockClientData {
private static final class StringToByteDeserializer implements JsonDeserializer<byte[]> { private static final class StringToByteDeserializer implements JsonDeserializer<byte[]> {
@Override @Override
public byte[] deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { public byte[] deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
return json.getAsString().getBytes(StandardCharsets.UTF_8); return Base64.getDecoder().decode(json.getAsString().getBytes(StandardCharsets.UTF_8));
} }
} }

View File

@@ -29,8 +29,6 @@ import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheBuilder;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive; import com.google.gson.JsonPrimitive;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.nbt.NbtType;
@@ -312,11 +310,11 @@ public class SkinManager {
} }
try { try {
byte[] skinBytes = Base64.getDecoder().decode(clientData.getSkinData().getBytes(StandardCharsets.UTF_8)); byte[] skinBytes = clientData.getSkinData();
byte[] capeBytes = clientData.getCapeData(); byte[] capeBytes = clientData.getCapeData();
byte[] geometryNameBytes = Base64.getDecoder().decode(clientData.getGeometryName().getBytes(StandardCharsets.UTF_8)); byte[] geometryNameBytes = clientData.getGeometryName();
byte[] geometryBytes = Base64.getDecoder().decode(clientData.getGeometryData().getBytes(StandardCharsets.UTF_8)); byte[] geometryBytes = clientData.getGeometryData();
if (skinBytes.length <= (128 * 128 * 4) && !clientData.isPersonaSkin()) { if (skinBytes.length <= (128 * 128 * 4) && !clientData.isPersonaSkin()) {
SkinProvider.storeBedrockSkin(playerEntity.getUuid(), clientData.getSkinId(), skinBytes); SkinProvider.storeBedrockSkin(playerEntity.getUuid(), clientData.getSkinId(), skinBytes);

View File

@@ -74,6 +74,9 @@ public class JavaLoginFinishedTranslator extends PacketTranslator<ClientboundLog
session.setToken(null); session.setToken(null);
session.getClientData().setOriginalString(null); session.getClientData().setOriginalString(null);
// Reset code of conduct accepted state, mirrors Java Edition
session.hasAcceptedCodeOfConduct(false);
// configuration phase stuff that the vanilla client replies with after receiving the GameProfilePacket // configuration phase stuff that the vanilla client replies with after receiving the GameProfilePacket
session.sendDownstreamPacket(new ServerboundCustomPayloadPacket(Key.key("brand"), PluginMessageUtils.getGeyserBrandData()), ProtocolState.CONFIGURATION); session.sendDownstreamPacket(new ServerboundCustomPayloadPacket(Key.key("brand"), PluginMessageUtils.getGeyserBrandData()), ProtocolState.CONFIGURATION);
session.sendJavaClientSettings(); session.sendJavaClientSettings();

View File

@@ -44,6 +44,9 @@ public class JavaStartConfigurationTranslator extends PacketTranslator<Clientbou
erosionHandler.close(); erosionHandler.close();
} }
// Reset code of conduct being accepted
session.hasAcceptedCodeOfConduct(false);
ChunkUtils.sendEmptyChunks(session, session.getPlayerEntity().position().toInt(), session.getServerRenderDistance(), false); ChunkUtils.sendEmptyChunks(session, session.getPlayerEntity().position().toInt(), session.getServerRenderDistance(), false);
} }
} }