From 15506cf5b495b272f52a2126b2c31ea41dadbe19 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Wed, 9 Oct 2019 20:39:38 +0200 Subject: [PATCH] Edited PlayerInit behavior and updated protocol lib to 2.3.0 --- connector/pom.xml | 2 +- .../org/geysermc/connector/entity/Entity.java | 12 +- .../connector/entity/ExpOrbEntity.java | 2 +- .../connector/entity/PaintingEntity.java | 2 +- .../connector/entity/PlayerEntity.java | 45 ++- .../network/session/GeyserSession.java | 16 +- .../network/session/UpstreamSession.java | 46 +-- .../network/session/cache/EntityCache.java | 14 +- .../network/translators/TranslatorsInit.java | 5 +- .../bedrock/BedrockActionTranslator.java | 2 +- .../bedrock/BedrockInteractTranslator.java | 12 +- .../bedrock/BedrockMovePlayerTranslator.java | 20 +- .../BedrockPlayerInitializedTranslator.java | 14 +- .../inventory/GenericInventoryTranslator.java | 4 +- .../java/JavaBossBarTranslator.java | 2 +- .../entity/JavaEntityHeadLookTranslator.java | 4 +- .../entity/JavaEntityTeleportTranslator.java | 4 +- .../entity/JavaEntityVelocityTranslator.java | 4 +- .../player/JavaPlayerActionAckTranslator.java | 2 +- .../player/JavaPlayerHealthTranslator.java | 4 +- .../JavaPlayerListEntryTranslator.java | 29 +- .../JavaPlayerPositionRotationTranslator.java | 14 +- .../spawn/JavaSpawnExpOrbTranslator.java | 4 +- .../JavaSpawnGlobalEntityTranslator.java | 4 +- .../entity/spawn/JavaSpawnMobTranslator.java | 8 +- .../spawn/JavaSpawnObjectTranslator.java | 8 +- .../spawn/JavaSpawnPaintingTranslator.java | 4 +- .../spawn/JavaSpawnPlayerTranslator.java | 76 +---- .../java/world/JavaBlockChangeTranslator.java | 7 +- .../java/world/JavaChunkDataTranslator.java | 4 +- .../world/JavaMultiBlockChangeTranslator.java | 7 +- .../world/JavaNotifyClientTranslator.java | 6 +- .../world/JavaSpawnPositionTranslator.java | 4 +- .../geysermc/connector/utils/GeyserUtils.java | 285 +----------------- .../connector/utils/SkinProvider.java | 16 +- .../geysermc/connector/utils/SkinUtils.java | 142 +++++++++ 36 files changed, 320 insertions(+), 514 deletions(-) rename connector/src/main/java/org/geysermc/connector/network/translators/java/entity/{spawn => player}/JavaPlayerListEntryTranslator.java (68%) create mode 100644 connector/src/main/java/org/geysermc/connector/utils/SkinUtils.java diff --git a/connector/pom.xml b/connector/pom.xml index c135c245..25d52a00 100644 --- a/connector/pom.xml +++ b/connector/pom.xml @@ -75,7 +75,7 @@ com.nukkitx.protocol bedrock-v361 - 2.2.0 + 2.3.0 compile diff --git a/connector/src/main/java/org/geysermc/connector/entity/Entity.java b/connector/src/main/java/org/geysermc/connector/entity/Entity.java index d70478a0..af8e4e31 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/Entity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/Entity.java @@ -25,8 +25,8 @@ package org.geysermc.connector.entity; -import com.flowpowered.math.vector.Vector3f; import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityPropertiesPacket; +import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.EntityData; import com.nukkitx.protocol.bedrock.data.EntityDataDictionary; import com.nukkitx.protocol.bedrock.data.EntityFlag; @@ -116,17 +116,17 @@ public class Entity { } public void moveRelative(double relX, double relY, double relZ, float yaw, float pitch) { - moveRelative(relX, relY, relZ, new Vector3f(yaw, pitch, yaw)); + moveRelative(relX, relY, relZ, Vector3f.from(yaw, pitch, yaw)); } public void moveRelative(double relX, double relY, double relZ, Vector3f rotation) { setRotation(rotation); - this.position = new Vector3f(position.getX() + relX, position.getY() + relY, position.getZ() + relZ); + this.position = Vector3f.from(position.getX() + relX, position.getY() + relY, position.getZ() + relZ); this.movePending = true; } public void moveAbsolute(Vector3f position, float yaw, float pitch) { - moveAbsolute(position, new Vector3f(yaw, pitch, yaw)); + moveAbsolute(position, Vector3f.from(yaw, pitch, yaw)); } public void moveAbsolute(Vector3f position, Vector3f rotation) { @@ -137,7 +137,7 @@ public class Entity { public EntityDataDictionary getMetadata() { EntityFlags flags = new EntityFlags(); - flags.setFlag(EntityFlag.HAS_GRAVITY, !is(PlayerEntity.class) || as(PlayerEntity.class).isGravity()); + flags.setFlag(EntityFlag.HAS_GRAVITY, true); flags.setFlag(EntityFlag.HAS_COLLISION, true); flags.setFlag(EntityFlag.CAN_SHOW_NAME, true); flags.setFlag(EntityFlag.CAN_CLIMB, true); @@ -199,7 +199,7 @@ public class Entity { * x = Pitch, y = HeadYaw, z = Yaw */ public Vector3f getBedrockRotation() { - return new Vector3f(rotation.getY(), rotation.getZ(), rotation.getX()); + return Vector3f.from(rotation.getY(), rotation.getZ(), rotation.getX()); } @SuppressWarnings("unchecked") diff --git a/connector/src/main/java/org/geysermc/connector/entity/ExpOrbEntity.java b/connector/src/main/java/org/geysermc/connector/entity/ExpOrbEntity.java index 036829e8..89c1532f 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/ExpOrbEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/ExpOrbEntity.java @@ -25,7 +25,7 @@ package org.geysermc.connector.entity; -import com.flowpowered.math.vector.Vector3f; +import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.packet.SpawnExperienceOrbPacket; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; diff --git a/connector/src/main/java/org/geysermc/connector/entity/PaintingEntity.java b/connector/src/main/java/org/geysermc/connector/entity/PaintingEntity.java index 6b1b1c11..f9f6e37f 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/PaintingEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/PaintingEntity.java @@ -1,6 +1,6 @@ package org.geysermc.connector.entity; -import com.flowpowered.math.vector.Vector3f; +import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.packet.AddPaintingPacket; import lombok.Getter; import lombok.Setter; diff --git a/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java b/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java index 0b9f4180..67393114 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java @@ -25,16 +25,18 @@ package org.geysermc.connector.entity; -import com.flowpowered.math.vector.Vector3f; import com.github.steveice10.mc.auth.data.GameProfile; +import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.ItemData; import com.nukkitx.protocol.bedrock.packet.AddPlayerPacket; import com.nukkitx.protocol.bedrock.packet.MobArmorEquipmentPacket; -import com.nukkitx.protocol.bedrock.packet.SetEntityDataPacket; +import com.nukkitx.protocol.bedrock.packet.PlayerListPacket; import lombok.Getter; import lombok.Setter; +import org.geysermc.api.Geyser; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.utils.SkinUtils; import java.util.UUID; @@ -45,7 +47,6 @@ public class PlayerEntity extends Entity { private String username; private long lastSkinUpdate = -1; private boolean playerList = true; - private boolean gravity = false; private ItemData helmet; private ItemData chestplate; @@ -76,17 +77,6 @@ public class PlayerEntity extends Entity { session.getUpstream().sendPacket(armorEquipmentPacket); } - public void enableGravity(GeyserSession session) { - if (!gravity && session.getPlayerEntity().getGeyserId() == getGeyserId()) { - gravity = true; - - SetEntityDataPacket entityDataPacket = new SetEntityDataPacket(); - entityDataPacket.setRuntimeEntityId(geyserId); - entityDataPacket.getMetadata().putAll(getMetadata()); - session.getUpstream().sendPacket(entityDataPacket); - } - } - @Override public boolean despawnEntity(GeyserSession session) { super.despawnEntity(session); @@ -118,4 +108,31 @@ public class PlayerEntity extends Entity { valid = true; session.getUpstream().sendPacket(addPlayerPacket); } + + public void sendPlayer(GeyserSession session) { + if (getLastSkinUpdate() == -1) { + if (playerList) { + PlayerListPacket playerList = new PlayerListPacket(); + playerList.setType(PlayerListPacket.Type.ADD); + playerList.getEntries().add(SkinUtils.buildDefaultEntry(profile, geyserId)); + session.getUpstream().sendPacket(playerList); + } + } + + if (session.getUpstream().isInitialized() && session.getEntityCache().getEntityByGeyserId(geyserId) == null) { + session.getEntityCache().spawnEntity(this); + } else { + spawnEntity(session); + } + + if (!playerList) { + // remove from playerlist if player isn't on playerlist + Geyser.getGeneralThreadPool().execute(() -> { + PlayerListPacket playerList = new PlayerListPacket(); + playerList.setType(PlayerListPacket.Type.REMOVE); + playerList.getEntries().add(new PlayerListPacket.Entry(uuid)); + session.getUpstream().sendPacket(playerList); + }); + } + } } diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index 1d7dfe88..b907187d 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -25,10 +25,6 @@ package org.geysermc.connector.network.session; -import com.flowpowered.math.vector.Vector2f; -import com.flowpowered.math.vector.Vector2i; -import com.flowpowered.math.vector.Vector3f; -import com.flowpowered.math.vector.Vector3i; import com.github.steveice10.mc.auth.data.GameProfile; import com.github.steveice10.mc.auth.exception.request.RequestException; import com.github.steveice10.mc.protocol.MinecraftProtocol; @@ -40,6 +36,10 @@ import com.github.steveice10.packetlib.event.session.PacketReceivedEvent; import com.github.steveice10.packetlib.event.session.SessionAdapter; import com.github.steveice10.packetlib.packet.Packet; import com.github.steveice10.packetlib.tcp.TcpSessionFactory; +import com.nukkitx.math.vector.Vector2f; +import com.nukkitx.math.vector.Vector2i; +import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.math.vector.Vector3i; import com.nukkitx.protocol.bedrock.BedrockServerSession; import com.nukkitx.protocol.bedrock.data.GamePublishSetting; import com.nukkitx.protocol.bedrock.data.GameRule; @@ -257,15 +257,15 @@ public class GeyserSession implements Player { startGamePacket.setUniqueEntityId(playerEntity.getGeyserId()); startGamePacket.setRuntimeEntityId(playerEntity.getGeyserId()); startGamePacket.setPlayerGamemode(0); - startGamePacket.setPlayerPosition(new Vector3f(0, 69, 0)); - startGamePacket.setRotation(new Vector2f(1, 1)); + startGamePacket.setPlayerPosition(Vector3f.from(0, 69, 0)); + startGamePacket.setRotation(Vector2f.from(1, 1)); startGamePacket.setSeed(0); startGamePacket.setDimensionId(playerEntity.getDimension()); startGamePacket.setGeneratorId(1); startGamePacket.setLevelGamemode(0); startGamePacket.setDifficulty(1); - startGamePacket.setDefaultSpawn(new Vector3i(0, 0, 0)); + startGamePacket.setDefaultSpawn(Vector3i.ZERO); startGamePacket.setAcheivementsDisabled(true); startGamePacket.setTime(0); startGamePacket.setEduLevel(false); @@ -304,7 +304,5 @@ public class GeyserSession implements Player { PlayStatusPacket playStatusPacket = new PlayStatusPacket(); playStatusPacket.setStatus(PlayStatusPacket.Status.PLAYER_SPAWN); upstream.sendPacket(playStatusPacket); - - upstream.setFrozen(true); // will freeze until the client decides it is ready } } diff --git a/connector/src/main/java/org/geysermc/connector/network/session/UpstreamSession.java b/connector/src/main/java/org/geysermc/connector/network/session/UpstreamSession.java index af475e5c..f8691bea 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/UpstreamSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/UpstreamSession.java @@ -5,46 +5,24 @@ import com.nukkitx.protocol.bedrock.BedrockServerSession; import lombok.Getter; import lombok.NonNull; import lombok.RequiredArgsConstructor; -import org.geysermc.api.Geyser; +import lombok.Setter; import java.net.InetSocketAddress; -import java.util.Queue; -import java.util.concurrent.ConcurrentLinkedQueue; @RequiredArgsConstructor public class UpstreamSession { @Getter private final BedrockServerSession session; - private Queue packets = new ConcurrentLinkedQueue<>(); - @Getter private boolean frozen = false; - private boolean queueCleared = true; + @Getter @Setter + private boolean initialized = false; public void sendPacket(@NonNull BedrockPacket packet) { - if (frozen || !packets.isEmpty()) { - packets.add(packet); - } else { - session.sendPacket(packet); - } + session.sendPacket(packet); } public void sendPacketImmediately(@NonNull BedrockPacket packet) { session.sendPacketImmediately(packet); } - public void setFrozen(boolean frozen) { - if (this.frozen != frozen) { - this.frozen = frozen; - - if (!frozen) { - Geyser.getGeneralThreadPool().execute(() -> { - BedrockPacket packet; - while ((packet = packets.poll()) != null) { - session.sendPacket(packet); - } - }); - } - } - } - public void disconnect(String reason) { session.disconnect(reason); } @@ -56,20 +34,4 @@ public class UpstreamSession { public InetSocketAddress getAddress() { return session.getAddress(); } - - public boolean hasQueue() { - return !packets.isEmpty(); - } - - /** - * @return true the first time this method is called after the queue is empty.
- * This will enable gravity because now the client is ready to explore - */ - public boolean isQueueCleared() { - if (!hasQueue() && queueCleared) { - queueCleared = false; - return true; - } - return false; - } } diff --git a/connector/src/main/java/org/geysermc/connector/network/session/cache/EntityCache.java b/connector/src/main/java/org/geysermc/connector/network/session/cache/EntityCache.java index 41af7e57..3bb702db 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/cache/EntityCache.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/cache/EntityCache.java @@ -30,9 +30,7 @@ import org.geysermc.connector.entity.Entity; import org.geysermc.connector.entity.PlayerEntity; import org.geysermc.connector.network.session.GeyserSession; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; +import java.util.*; import java.util.concurrent.atomic.AtomicLong; /** @@ -84,6 +82,16 @@ public class EntityCache { return entities.get(entityIdTranslations.get(javaId)); } + public Set getEntitiesByType(Class entityType) { + Set entitiesOfType = new HashSet<>(); + for (Entity entity : (entityType == PlayerEntity.class ? playerEntities : entities).values()) { + if (entity.is(entityType)) { + entitiesOfType.add(entity.as(entityType)); + } + } + return entitiesOfType; + } + public void addPlayerEntity(PlayerEntity entity) { playerEntities.put(entity.getUuid(), entity); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java b/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java index 5f3569dc..534f2286 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java @@ -54,10 +54,7 @@ import org.geysermc.connector.network.translators.inventory.InventoryTranslator; import org.geysermc.connector.network.translators.item.ItemTranslator; import org.geysermc.connector.network.translators.java.*; import org.geysermc.connector.network.translators.java.entity.*; -import org.geysermc.connector.network.translators.java.entity.player.JavaPlayerActionAckTranslator; -import org.geysermc.connector.network.translators.java.entity.player.JavaPlayerHealthTranslator; -import org.geysermc.connector.network.translators.java.entity.player.JavaPlayerPositionRotationTranslator; -import org.geysermc.connector.network.translators.java.entity.player.JavaPlayerSetExperienceTranslator; +import org.geysermc.connector.network.translators.java.entity.player.*; import org.geysermc.connector.network.translators.java.entity.spawn.*; import org.geysermc.connector.network.translators.java.scoreboard.JavaDisplayScoreboardTranslator; import org.geysermc.connector.network.translators.java.scoreboard.JavaScoreboardObjectiveTranslator; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockActionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockActionTranslator.java index fdab51ba..b8382b8c 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockActionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockActionTranslator.java @@ -25,7 +25,6 @@ package org.geysermc.connector.network.translators.bedrock; -import com.flowpowered.math.vector.Vector3i; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction; @@ -34,6 +33,7 @@ import com.github.steveice10.mc.protocol.data.game.world.block.BlockFace; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerActionPacket; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerPlaceBlockPacket; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerStatePacket; +import com.nukkitx.math.vector.Vector3i; import com.nukkitx.protocol.bedrock.packet.PlayerActionPacket; import org.geysermc.connector.entity.Entity; import org.geysermc.connector.network.session.GeyserSession; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInteractTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInteractTranslator.java index 2fad8c21..9b206018 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInteractTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInteractTranslator.java @@ -25,21 +25,11 @@ package org.geysermc.connector.network.translators.bedrock; -import com.flowpowered.math.vector.Vector3f; -import com.flowpowered.math.vector.Vector3i; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.github.steveice10.mc.protocol.data.game.entity.player.InteractAction; -import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction; -import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerState; -import com.github.steveice10.mc.protocol.data.game.world.block.BlockFace; -import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerActionPacket; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerInteractEntityPacket; -import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerPlaceBlockPacket; -import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerStatePacket; +import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.packet.InteractPacket; -import com.nukkitx.protocol.bedrock.packet.PlayerActionPacket; -import org.geysermc.connector.entity.Entity; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMovePlayerTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMovePlayerTranslator.java index ad7645a4..e4ab1b1d 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMovePlayerTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMovePlayerTranslator.java @@ -25,9 +25,10 @@ package org.geysermc.connector.network.translators.bedrock; -import com.flowpowered.math.vector.Vector3f; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerPositionRotationPacket; +import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket; import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket; import com.nukkitx.protocol.bedrock.packet.SetEntityDataPacket; import org.geysermc.connector.entity.Entity; @@ -44,9 +45,15 @@ public class BedrockMovePlayerTranslator extends PacketTranslator { @Override public void translate(SetLocalPlayerAsInitializedPacket packet, GeyserSession session) { if (session.getPlayerEntity().getGeyserId() == packet.getRuntimeEntityId()) { - session.getUpstream().setFrozen(false); + if (!session.getUpstream().isInitialized()) { + session.getUpstream().setInitialized(true); + + 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)); + } + } + } } } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/GenericInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/GenericInventoryTranslator.java index e2f4fa58..862117f9 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/GenericInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/GenericInventoryTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.connector.network.translators.inventory; -import com.flowpowered.math.vector.Vector3i; +import com.nukkitx.math.vector.Vector3i; import com.nukkitx.protocol.bedrock.data.ItemData; import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket; @@ -46,7 +46,7 @@ public class GenericInventoryTranslator extends InventoryTranslator { ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket(); containerOpenPacket.setWindowId((byte) inventory.getId()); containerOpenPacket.setType((byte) 0); - containerOpenPacket.setBlockPosition(new Vector3i(0, 0, 0)); + containerOpenPacket.setBlockPosition(Vector3i.ZERO); session.getUpstream().sendPacket(containerOpenPacket); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaBossBarTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaBossBarTranslator.java index 8b89e3be..3073e469 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaBossBarTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaBossBarTranslator.java @@ -1,7 +1,7 @@ package org.geysermc.connector.network.translators.java; -import com.flowpowered.math.vector.Vector3f; import com.github.steveice10.mc.protocol.packet.ingame.server.ServerBossBarPacket; +import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.EntityData; import com.nukkitx.protocol.bedrock.packet.AddEntityPacket; import com.nukkitx.protocol.bedrock.packet.BossEventPacket; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityHeadLookTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityHeadLookTranslator.java index f583ea91..34addcee 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityHeadLookTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityHeadLookTranslator.java @@ -25,8 +25,8 @@ package org.geysermc.connector.network.translators.java.entity; -import com.flowpowered.math.vector.Vector3f; import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityHeadLookPacket; +import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket; import org.geysermc.connector.entity.Entity; import org.geysermc.connector.network.session.GeyserSession; @@ -43,7 +43,7 @@ public class JavaEntityHeadLookTranslator extends PacketTranslator { @Override @@ -16,16 +15,15 @@ public class JavaPlayerListEntryTranslator extends PacketTranslator { // #slowdownbrother, just don't execute it directly PaintingEntity entity = new PaintingEntity( diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnPlayerTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnPlayerTranslator.java index 968b0b3a..688a00ba 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnPlayerTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnPlayerTranslator.java @@ -25,27 +25,21 @@ package org.geysermc.connector.network.translators.java.entity.spawn; -import com.flowpowered.math.vector.Vector3f; -import com.github.steveice10.mc.auth.data.GameProfile; import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnPlayerPacket; -import com.google.gson.JsonObject; -import com.nukkitx.protocol.bedrock.packet.PlayerListPacket; -import org.apache.commons.codec.Charsets; +import com.nukkitx.math.vector.Vector3f; import org.geysermc.api.Geyser; import org.geysermc.connector.entity.PlayerEntity; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; -import org.geysermc.connector.utils.SkinProvider; - -import java.util.Base64; +import org.geysermc.connector.utils.SkinUtils; public class JavaSpawnPlayerTranslator extends PacketTranslator { @Override public void translate(ServerSpawnPlayerPacket packet, GeyserSession session) { - Vector3f position = new Vector3f(packet.getX(), packet.getY() - EntityType.PLAYER.getOffset(), packet.getZ()); - Vector3f rotation = new Vector3f(packet.getYaw(), packet.getPitch(), packet.getYaw()); + Vector3f position = Vector3f.from(packet.getX(), packet.getY() - EntityType.PLAYER.getOffset(), packet.getZ()); + Vector3f rotation = Vector3f.from(packet.getYaw(), packet.getPitch(), packet.getYaw()); PlayerEntity entity = session.getEntityCache().getPlayerEntity(packet.getUUID()); if (entity == null) { @@ -57,64 +51,8 @@ public class JavaSpawnPlayerTranslator extends PacketTranslator { - GameProfile.Property skinProperty = entity.getProfile().getProperty("textures"); - - JsonObject skinObject = SkinProvider.GSON.fromJson(new String(Base64.getDecoder().decode(skinProperty.getValue()), Charsets.UTF_8), JsonObject.class); - JsonObject textures = skinObject.getAsJsonObject("textures"); - - JsonObject skinTexture = textures.getAsJsonObject("SKIN"); - String skinUrl = skinTexture.get("url").getAsString(); - - boolean isAlex = skinTexture.has("metadata"); - - String capeUrl = null; - if (textures.has("CAPE")) { - JsonObject capeTexture = textures.getAsJsonObject("CAPE"); - capeUrl = capeTexture.get("url").getAsString(); - } - - SkinProvider.requestAndHandleSkinAndCape(entity.getUuid(), skinUrl, capeUrl) - .whenCompleteAsync((skinAndCape, throwable) -> { - SkinProvider.Skin skin = skinAndCape.getSkin(); - SkinProvider.Cape cape = skinAndCape.getCape(); - - if (cape.isFailed() && SkinProvider.ALLOW_THIRD_PARTY_CAPES) { - cape = SkinProvider.getOrDefault(SkinProvider.requestAndHandleUnofficialCape( - cape, entity.getUuid(), - entity.getUsername(), false - ), SkinProvider.EMPTY_CAPE, SkinProvider.UnofficalCape.VALUES.length * 3); - } - - if (entity.getLastSkinUpdate() < skin.getRequestedOn()) { - entity.setLastSkinUpdate(skin.getRequestedOn()); - - PlayerListPacket.Entry updatedEntry = new PlayerListPacket.Entry(skin.getSkinOwner()); - updatedEntry.setName(entity.getUsername()); - updatedEntry.setEntityId(entity.getGeyserId()); - updatedEntry.setSkinId(entity.getUuid().toString()); - updatedEntry.setSkinData(skin.getSkinData()); - updatedEntry.setCapeData(cape.getCapeData()); - updatedEntry.setGeometryName("geometry.humanoid.custom" + (isAlex ? "Slim" : "")); - updatedEntry.setGeometryData(""); - updatedEntry.setXuid(""); - updatedEntry.setPlatformChatId(""); - - PlayerListPacket playerRemovePacket = new PlayerListPacket(); - playerRemovePacket.setType(PlayerListPacket.Type.REMOVE); - playerRemovePacket.getEntries().add(updatedEntry); - session.getUpstream().sendPacket(playerRemovePacket); - - PlayerListPacket playerAddPacket = new PlayerListPacket(); - playerAddPacket.setType(PlayerListPacket.Type.ADD); - playerAddPacket.getEntries().add(updatedEntry); - session.getUpstream().sendPacket(playerAddPacket); - } - }).isCompletedExceptionally(); - }); + entity.sendPlayer(session); + // async skin loading + SkinUtils.requestAndHandleSkinAndCape(entity, session, skinAndCape -> entity.sendPlayer(session)); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaBlockChangeTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaBlockChangeTranslator.java index 63d1b927..6ce67533 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaBlockChangeTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaBlockChangeTranslator.java @@ -1,8 +1,8 @@ package org.geysermc.connector.network.translators.java.world; -import com.flowpowered.math.vector.Vector3i; import com.github.steveice10.mc.protocol.data.game.world.block.BlockChangeRecord; import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerBlockChangePacket; +import com.nukkitx.math.vector.Vector3i; import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; @@ -16,10 +16,11 @@ public class JavaBlockChangeTranslator extends PacketTranslator> 38), (int) (l & 0xFFF), (int) ((l << 26) >> 38) ); } @@ -70,7 +55,7 @@ public class GeyserUtils { } public static Vector3d readLegacyPositionI(ByteBuf from) { - return new Vector3d(from.readInt(), from.readInt(), from.readInt()); + return Vector3d.from(from.readInt(), from.readInt(), from.readInt()); } public static void writePosition(ByteBuf to, Vector3i position) { @@ -106,11 +91,11 @@ public class GeyserUtils { } public static Vector2i readIntChunkCoord(ByteBuf from) { - return new Vector2i(from.readInt(), from.readInt()); + return Vector2i.from(from.readInt(), from.readInt()); } public static Vector2i readVarIntChunkCoord(ByteBuf from) { - return new Vector2i(readVarInt(from), readVarInt(from)); + return Vector2i.from(readVarInt(from), readVarInt(from)); } public static void writeIntChunkCoord(ByteBuf to, Vector2i chunk) { @@ -119,7 +104,7 @@ public class GeyserUtils { } public static Vector2i readPEChunkCoord(ByteBuf from) { - return new Vector2i(readSVarInt(from), readSVarInt(from)); + return Vector2i.from(readSVarInt(from), readSVarInt(from)); } public static void writePEChunkCoord(ByteBuf to, Vector2i chunk) { @@ -140,513 +125,269 @@ public class GeyserUtils { writeVarInt(to, chunk.getY()); } - - - public static final int MAX_LENGTH = 5; - - + public static final int MAX_VARINT_LENGTH = 5; public static void writeFixedSizeVarInt(ByteBuf to, int i) { - int writerIndex = to.writerIndex(); - while ((i & 0xFFFFFF80) != 0x0) { - to.writeByte(i | 0x80); - i >>>= 7; } - - int paddingBytes = MAX_LENGTH - (to.writerIndex() - writerIndex) - 1; + int paddingBytes = MAX_VARINT_LENGTH - (to.writerIndex() - writerIndex) - 1; if (paddingBytes == 0) { - to.writeByte(i); - } else { - to.writeByte(i | 0x80); - while (--paddingBytes > 0) { - to.writeByte(0x80); - } - to.writeByte(0); - } - } - - public static int readVarInt(ByteBuf from) { - int value = 0; - int length = 0; byte part; - do { - part = from.readByte(); - value |= (part & 0x7F) << (length++ * 7); - - if (length > MAX_LENGTH) { - + if (length > MAX_VARINT_LENGTH) { throw new DecoderException("VarInt too big"); - } - } while (part < 0); - return value; - } - - public static void writeVarInt(ByteBuf to, int i) { - while ((i & 0xFFFFFF80) != 0x0) { - to.writeByte(i | 0x80); - i >>>= 7; - } - to.writeByte(i); - } - - public static int readSVarInt(ByteBuf from) { - int varint = readVarInt(from); - return (varint >> 1) ^ -(varint & 1); - } - public static void writeSVarInt(ByteBuf to, int varint) { - writeVarInt(to, (varint << 1) ^ (varint >> 31)); - } - - public static long readVarLong(ByteBuf from) { - long varlong = 0L; - int length = 0; byte part; - do { - part = from.readByte(); - varlong |= (part & 0x7F) << (length++ * 7); if (length > 10) { - throw new RuntimeException("VarLong too big"); - } - } while ((part & 0x80) == 0x80); - return varlong; - } - - public static void writeVarLong(ByteBuf to, long varlong) { - while ((varlong & 0xFFFFFFFFFFFFFF80L) != 0x0L) { - to.writeByte((int) (varlong & 0x7FL) | 0x80); - varlong >>>= 7; - } - to.writeByte((int) varlong); - } - - public static long readSVarLong(ByteBuf from) { - long varlong = readVarLong(from); - return (varlong >> 1) ^ -(varlong & 1); - } - public static void writeSVarLong(ByteBuf to, long varlong) { - writeVarLong(to, (varlong << 1) ^ (varlong >> 63)); } - public static ByteBuf readShortByteArraySlice(ByteBuf from, int limit) { - int length = from.readShort(); - checkLimit(length, limit); - return from.readSlice(length); } - - @SuppressWarnings("unchecked") - public static T[] readShortTArray(ByteBuf from, Class tclass, Function elementReader) { - T[] array = (T[]) Array.newInstance(tclass, from.readShort()); - for (int i = 0; i < array.length; i++) { - array[i] = elementReader.apply(from); - } - return array; - } - - - - public static byte[] readVarIntByteArray(ByteBuf from) { - return readBytes(from, readVarInt(from)); - } - - public static ByteBuf readVarIntByteArraySlice(ByteBuf from, int limit) { - int length = readVarInt(from); - checkLimit(length, limit); - return from.readSlice(length); - } - - public static ByteBuf readVarIntByteArraySlice(ByteBuf from) { - return from.readSlice(readVarInt(from)); - } - - @SuppressWarnings("unchecked") - public static T[] readVarIntTArray(ByteBuf from, Class tclass, Function elementReader) { - T[] array = (T[]) Array.newInstance(tclass, readVarInt(from)); - for (int i = 0; i < array.length; i++) { - array[i] = elementReader.apply(from); - } - return array; - } - - public static int[] readVarIntVarIntArray(ByteBuf from) { - int[] array = new int[readVarInt(from)]; - for (int i = 0; i < array.length; i++) { - array[i] = readVarInt(from); - } - return array; - } - - - - public static void writeShortByteArray(ByteBuf to, ByteBuf data) { - to.writeShort(data.readableBytes()); - to.writeBytes(data); - } - - public static void writeShortByteArray(ByteBuf to, byte[] data) { - to.writeShort(data.length); - to.writeBytes(data); - } - - public static void writeShortByteArray(ByteBuf to, Consumer dataWriter) { - - writeLengthPrefixedBytes(to, (lTo, length) -> lTo.writeShort(length), dataWriter); - + writeLengthPrefixedBytes(to, ByteBuf::writeShort, dataWriter); } - public static void writeShortTArray(ByteBuf to, T[] array, BiConsumer elementWriter) { - to.writeShort(array.length); - for (T element : array) { - elementWriter.accept(to, element); - } - } - - - - public static void writeVarIntByteArray(ByteBuf to, ByteBuf data) { - writeVarInt(to, data.readableBytes()); - to.writeBytes(data); - } - public static void writeVarIntByteArray(ByteBuf to, byte[] data) { - writeVarInt(to, data.length); - to.writeBytes(data); - } - - public static void writeVarIntByteArray(ByteBuf to, Consumer dataWriter) { - writeLengthPrefixedBytes(to, GeyserUtils::writeFixedSizeVarInt, dataWriter); - } - - public static void writeVarIntTArray(ByteBuf to, ToIntFunction arrayWriter) { - writeSizePrefixedData(to, GeyserUtils::writeFixedSizeVarInt, arrayWriter); - } - - public static void writeVarIntTArray(ByteBuf to, T[] array, BiConsumer elementWriter) { - writeVarInt(to, array.length); - for (T element : array) { - elementWriter.accept(to, element); - } - } - - public static void writeVarIntTArray(ByteBuf to, List array, BiConsumer elementWriter) { - writeVarInt(to, array.size()); - for (T element : array) { - elementWriter.accept(to, element); - } - } - public static void writeVarIntEnum(ByteBuf to, Enum e) { - writeVarInt(to, e.ordinal()); - } - - public static void writeByteEnum(ByteBuf to, Enum e) { - to.writeByte(e.ordinal()); - } - - public static UUID readUUID(ByteBuf from) { - return new UUID(from.readLong(), from.readLong()); - } - - public static void writeUUID(ByteBuf to, UUID uuid) { - to.writeLong(uuid.getMostSignificantBits()); - to.writeLong(uuid.getLeastSignificantBits()); - } - - public static void writePEUUID(ByteBuf to, UUID uuid) { - to.writeLongLE(uuid.getMostSignificantBits()); - to.writeLongLE(uuid.getLeastSignificantBits()); - } - - public static byte[] readAllBytes(ByteBuf buf) { - return readBytes(buf, buf.readableBytes()); - } - - public static ByteBuf readAllBytesSlice(ByteBuf from) { - return from.readSlice(from.readableBytes()); - } - - public static ByteBuf readAllBytesSlice(ByteBuf buf, int limit) { - checkLimit(buf.readableBytes(), limit); - return readAllBytesSlice(buf); - } - - public static byte[] readBytes(ByteBuf buf, int length) { - byte[] result = new byte[length]; - buf.readBytes(result); - return result; - } - - protected static void checkLimit(int length, int limit) { - if (length > limit) { - throw new DecoderException(MessageFormat.format("Size {0} is bigger than allowed {1}", length, limit)); - } - } - - public static void writeLengthPrefixedBytes(ByteBuf to, ObjIntConsumer lengthWriter, Consumer dataWriter) { - int lengthWriterIndex = to.writerIndex(); - lengthWriter.accept(to, 0); - int writerIndexDataStart = to.writerIndex(); - dataWriter.accept(to); - int writerIndexDataEnd = to.writerIndex(); - to.writerIndex(lengthWriterIndex); - lengthWriter.accept(to, writerIndexDataEnd - writerIndexDataStart); - to.writerIndex(writerIndexDataEnd); - } - - public static void writeSizePrefixedData(ByteBuf to, ObjIntConsumer sizeWriter, ToIntFunction dataWriter) { - int sizeWriterIndex = to.writerIndex(); - sizeWriter.accept(to, 0); - int size = dataWriter.applyAsInt(to); - int writerIndexDataEnd = to.writerIndex(); - to.writerIndex(sizeWriterIndex); - sizeWriter.accept(to, size); - to.writerIndex(writerIndexDataEnd); - } private static int getAnvilIndex(int x, int y, int z) { - return (y << 8) + (z << 4) + x; - } public static boolean instanceOf(Class clazz, Object o) { @@ -657,6 +398,4 @@ public class GeyserUtils { return false; } } - - } diff --git a/connector/src/main/java/org/geysermc/connector/utils/SkinProvider.java b/connector/src/main/java/org/geysermc/connector/utils/SkinProvider.java index 298661c0..3483a927 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/SkinProvider.java +++ b/connector/src/main/java/org/geysermc/connector/utils/SkinProvider.java @@ -49,13 +49,13 @@ public class SkinProvider { return cachedCapes.get(capeUrl); } - public static CompletableFuture requestAndHandleSkinAndCape(UUID playerId, String skinUrl, String capeUrl) { + public static CompletableFuture requestSkinAndCape(UUID playerId, String skinUrl, String capeUrl) { return CompletableFuture.supplyAsync(() -> { long time = System.currentTimeMillis(); SkinAndCape skinAndCape = new SkinAndCape( - getOrDefault(requestAndHandleSkin(playerId, skinUrl, false), EMPTY_SKIN, 5), - getOrDefault(requestAndHandleCape(capeUrl, false), EMPTY_CAPE, 5) + getOrDefault(requestSkin(playerId, skinUrl, false), EMPTY_SKIN, 5), + getOrDefault(requestCape(capeUrl, false), EMPTY_CAPE, 5) ); Geyser.getLogger().debug("Took " + (System.currentTimeMillis() - time) + "ms for " + playerId); @@ -63,7 +63,7 @@ public class SkinProvider { }, EXECUTOR_SERVICE); } - public static CompletableFuture requestAndHandleSkin(UUID playerId, String textureUrl, boolean newThread) { + public static CompletableFuture requestSkin(UUID playerId, String textureUrl, boolean newThread) { if (textureUrl == null || textureUrl.isEmpty()) return CompletableFuture.completedFuture(EMPTY_SKIN); if (requestedSkins.containsKey(playerId)) return requestedSkins.get(playerId); // already requested @@ -91,7 +91,7 @@ public class SkinProvider { return future; } - public static CompletableFuture requestAndHandleCape(String capeUrl, boolean newThread) { + public static CompletableFuture requestCape(String capeUrl, boolean newThread) { if (capeUrl == null || capeUrl.isEmpty()) return CompletableFuture.completedFuture(EMPTY_CAPE); if (requestedCapes.containsKey(capeUrl)) return requestedCapes.get(capeUrl); // already requested @@ -119,12 +119,12 @@ public class SkinProvider { return future; } - public static CompletableFuture requestAndHandleUnofficialCape(Cape officialCape, UUID playerId, - String username, boolean newThread) { + public static CompletableFuture requestUnofficialCape(Cape officialCape, UUID playerId, + String username, boolean newThread) { if (officialCape.isFailed() && ALLOW_THIRD_PARTY_CAPES) { for (UnofficalCape cape : UnofficalCape.VALUES) { Cape cape1 = getOrDefault( - requestAndHandleCape(cape.getUrlFor(playerId, username), newThread), + requestCape(cape.getUrlFor(playerId, username), newThread), EMPTY_CAPE, 4 ); if (!cape1.isFailed()) { diff --git a/connector/src/main/java/org/geysermc/connector/utils/SkinUtils.java b/connector/src/main/java/org/geysermc/connector/utils/SkinUtils.java new file mode 100644 index 00000000..7254637a --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/utils/SkinUtils.java @@ -0,0 +1,142 @@ +package org.geysermc.connector.utils; + +import com.github.steveice10.mc.auth.data.GameProfile; +import com.google.gson.JsonObject; +import com.nukkitx.protocol.bedrock.packet.PlayerListPacket; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.apache.commons.codec.Charsets; +import org.geysermc.api.Geyser; +import org.geysermc.connector.entity.PlayerEntity; +import org.geysermc.connector.network.session.GeyserSession; + +import java.util.Base64; +import java.util.UUID; +import java.util.function.Consumer; + +public class SkinUtils { + public static PlayerListPacket.Entry buildCachedEntry(GameProfile profile, long geyserId) { + GameProfileData data = GameProfileData.from(profile); + + return buildEntryManually( + profile.getId(), + profile.getName(), + geyserId, + profile.getIdAsString(), + SkinProvider.getCachedSkin(profile.getId()).getSkinData(), + SkinProvider.getCachedCape(data.getCapeUrl()).getCapeData(), + "geometry.humanoid.custom" + (data.isAlex() ? "Slim" : ""), + "" + ); + } + + public static PlayerListPacket.Entry buildDefaultEntry(GameProfile profile, long geyserId) { + return buildEntryManually( + profile.getId(), + profile.getName(), + geyserId, + profile.getIdAsString(), + SkinProvider.STEVE_SKIN, + SkinProvider.EMPTY_CAPE.getCapeData(), + "geometry.humanoid", + "" + ); + } + + public static PlayerListPacket.Entry buildEntryManually(UUID uuid, String username, long geyserId, + String skinId, byte[] skinData, byte[] capeData, + String geometryName, String geometryData) { + PlayerListPacket.Entry entry = new PlayerListPacket.Entry(uuid); + entry.setName(username); + entry.setEntityId(geyserId); + entry.setSkinId(skinId); + entry.setSkinData(skinData != null ? skinData : SkinProvider.STEVE_SKIN); + entry.setCapeData(capeData); + entry.setGeometryName(geometryName); + entry.setGeometryData(geometryData); + entry.setXuid(""); + entry.setPlatformChatId(""); + return entry; + } + + @AllArgsConstructor + @Getter + public static class GameProfileData { + private String skinUrl; + private String capeUrl; + private boolean alex; + + public static GameProfileData from(GameProfile profile) { + GameProfile.Property skinProperty = profile.getProperty("textures"); + + JsonObject skinObject = SkinProvider.GSON.fromJson(new String(Base64.getDecoder().decode(skinProperty.getValue()), Charsets.UTF_8), JsonObject.class); + JsonObject textures = skinObject.getAsJsonObject("textures"); + + JsonObject skinTexture = textures.getAsJsonObject("SKIN"); + String skinUrl = skinTexture.get("url").getAsString(); + + boolean isAlex = skinTexture.has("metadata"); + + String capeUrl = null; + if (textures.has("CAPE")) { + JsonObject capeTexture = textures.getAsJsonObject("CAPE"); + capeUrl = capeTexture.get("url").getAsString(); + } + + return new GameProfileData(skinUrl, capeUrl, isAlex); + } + } + + public static void requestAndHandleSkinAndCape(PlayerEntity entity, GeyserSession session, + Consumer skinAndCapeConsumer) { + Geyser.getGeneralThreadPool().execute(() -> { + SkinUtils.GameProfileData data = SkinUtils.GameProfileData.from(entity.getProfile()); + + SkinProvider.requestSkinAndCape(entity.getUuid(), data.getSkinUrl(), data.getCapeUrl()) + .whenCompleteAsync((skinAndCape, throwable) -> { + try { + SkinProvider.Skin skin = skinAndCape.getSkin(); + SkinProvider.Cape cape = skinAndCape.getCape(); + + if (cape.isFailed() && SkinProvider.ALLOW_THIRD_PARTY_CAPES) { + cape = SkinProvider.getOrDefault(SkinProvider.requestUnofficialCape( + cape, entity.getUuid(), + entity.getUsername(), false + ), SkinProvider.EMPTY_CAPE, SkinProvider.UnofficalCape.VALUES.length * 3); + } + + if (entity.getLastSkinUpdate() < skin.getRequestedOn()) { + entity.setLastSkinUpdate(skin.getRequestedOn()); + + if (session.getUpstream().isInitialized()) { + PlayerListPacket.Entry updatedEntry = SkinUtils.buildEntryManually( + entity.getUuid(), + entity.getUsername(), + entity.getGeyserId(), + entity.getUuid().toString(), + skin.getSkinData(), + cape.getCapeData(), + "geometry.humanoid.custom" + (data.isAlex() ? "Slim" : ""), + "" + ); + + PlayerListPacket playerRemovePacket = new PlayerListPacket(); + playerRemovePacket.setType(PlayerListPacket.Type.REMOVE); + playerRemovePacket.getEntries().add(updatedEntry); + session.getUpstream().sendPacket(playerRemovePacket); + + PlayerListPacket playerAddPacket = new PlayerListPacket(); + playerAddPacket.setType(PlayerListPacket.Type.ADD); + playerAddPacket.getEntries().add(updatedEntry); + session.getUpstream().sendPacket(playerAddPacket); + } + } + } catch (Exception e) { + Geyser.getLogger().error("Failed getting skin for " + entity.getUuid(), e); + } + + if (skinAndCapeConsumer != null) skinAndCapeConsumer.accept(skinAndCape); + }); + }); + } +}