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 40000551c..a2eb60053 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
@@ -128,8 +128,8 @@ public class EntityCache {
         return playerEntities.get(uuid);
     }
 
-    public void removePlayerEntity(UUID uuid) {
-        playerEntities.remove(uuid);
+    public PlayerEntity removePlayerEntity(UUID uuid) {
+        return playerEntities.remove(uuid);
     }
 
     public void addBossBar(UUID uuid, BossBar bossBar) {
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerListEntryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerListEntryTranslator.java
index cd627c645..b8a7972c8 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerListEntryTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerListEntryTranslator.java
@@ -25,6 +25,11 @@
 
 package org.geysermc.connector.network.translators.java.entity.player;
 
+import com.github.steveice10.mc.protocol.data.game.PlayerListEntry;
+import com.github.steveice10.mc.protocol.data.game.PlayerListEntryAction;
+import com.github.steveice10.mc.protocol.packet.ingame.server.ServerPlayerListEntryPacket;
+import com.nukkitx.math.vector.Vector3f;
+import com.nukkitx.protocol.bedrock.packet.PlayerListPacket;
 import org.geysermc.connector.GeyserConnector;
 import org.geysermc.connector.entity.player.PlayerEntity;
 import org.geysermc.connector.network.session.GeyserSession;
@@ -32,12 +37,6 @@ import org.geysermc.connector.network.translators.PacketTranslator;
 import org.geysermc.connector.network.translators.Translator;
 import org.geysermc.connector.skin.SkinManager;
 
-import com.github.steveice10.mc.protocol.data.game.PlayerListEntry;
-import com.github.steveice10.mc.protocol.data.game.PlayerListEntryAction;
-import com.github.steveice10.mc.protocol.packet.ingame.server.ServerPlayerListEntryPacket;
-import com.nukkitx.math.vector.Vector3f;
-import com.nukkitx.protocol.bedrock.packet.PlayerListPacket;
-
 @Translator(packet = ServerPlayerListEntryPacket.class)
 public class JavaPlayerListEntryTranslator extends PacketTranslator<ServerPlayerListEntryPacket> {
     @Override
@@ -57,9 +56,6 @@ public class JavaPlayerListEntryTranslator extends PacketTranslator<ServerPlayer
                     if (self) {
                         // Entity is ourself
                         playerEntity = session.getPlayerEntity();
-                        //TODO: playerEntity.setProfile(entry.getProfile()); seems to help with online mode skins but needs more testing to ensure Floodgate skins aren't overwritten
-                        SkinManager.requestAndHandleSkinAndCape(playerEntity, session, skinAndCape ->
-                                GeyserConnector.getInstance().getLogger().debug("Loaded Local Bedrock Java Skin Data"));
                     } else {
                         playerEntity = session.getEntityCache().getPlayerEntity(entry.getProfile().getId());
                     }
@@ -74,27 +70,35 @@ public class JavaPlayerListEntryTranslator extends PacketTranslator<ServerPlayer
                                 Vector3f.ZERO,
                                 Vector3f.ZERO
                         );
+
+                        session.getEntityCache().addPlayerEntity(playerEntity);
+                    } else {
+                        playerEntity.setProfile(entry.getProfile());
                     }
 
-                    session.getEntityCache().addPlayerEntity(playerEntity);
-
-                    playerEntity.setProfile(entry.getProfile());
                     playerEntity.setPlayerList(true);
-                    playerEntity.setValid(true);
 
-                    PlayerListPacket.Entry playerListEntry = SkinManager.buildCachedEntry(session, playerEntity);
+                    // We'll send our own PlayerListEntry in requestAndHandleSkinAndCape
+                    // But we need to send other player's entries so they show up in the player list
+                    // without processing their skin information - that'll be processed when they spawn in
+                    if (self) {
+                        SkinManager.requestAndHandleSkinAndCape(playerEntity, session, skinAndCape ->
+                                GeyserConnector.getInstance().getLogger().debug("Loaded Local Bedrock Java Skin Data for " + session.getClientData().getUsername()));
+                    } else {
+                        playerEntity.setValid(true);
+                        PlayerListPacket.Entry playerListEntry = SkinManager.buildCachedEntry(session, playerEntity);
 
-                    translate.getEntries().add(playerListEntry);
+                        translate.getEntries().add(playerListEntry);
+                    }
                     break;
                 case REMOVE_PLAYER:
-                    PlayerEntity entity = session.getEntityCache().getPlayerEntity(entry.getProfile().getId());
+                    // As the player entity is no longer present, we can remove the entry
+                    PlayerEntity entity = session.getEntityCache().removePlayerEntity(entry.getProfile().getId());
                     if (entity != null) {
                         // Just remove the entity's player list status
                         // Don't despawn the entity - the Java server will also take care of that.
                         entity.setPlayerList(false);
                     }
-                    // As the player entity is no longer present, we can remove the entry
-                    session.getEntityCache().removePlayerEntity(entry.getProfile().getId());
                     if (entity == session.getPlayerEntity()) {
                         // If removing ourself we use our AuthData UUID
                         translate.getEntries().add(new PlayerListPacket.Entry(session.getAuthData().getUUID()));
@@ -105,7 +109,7 @@ public class JavaPlayerListEntryTranslator extends PacketTranslator<ServerPlayer
             }
         }
 
-        if (packet.getAction() == PlayerListEntryAction.REMOVE_PLAYER || session.getUpstream().isInitialized()) {
+        if (!translate.getEntries().isEmpty() && (packet.getAction() == PlayerListEntryAction.REMOVE_PLAYER || session.getUpstream().isInitialized())) {
             session.sendUpstreamPacket(translate);
         }
     }
diff --git a/connector/src/main/java/org/geysermc/connector/skin/SkinManager.java b/connector/src/main/java/org/geysermc/connector/skin/SkinManager.java
index b39e7f352..ae3abc943 100644
--- a/connector/src/main/java/org/geysermc/connector/skin/SkinManager.java
+++ b/connector/src/main/java/org/geysermc/connector/skin/SkinManager.java
@@ -33,7 +33,6 @@ import com.nukkitx.protocol.bedrock.packet.PlayerListPacket;
 import lombok.AllArgsConstructor;
 import lombok.Getter;
 import org.geysermc.connector.GeyserConnector;
-import org.geysermc.connector.common.AuthType;
 import org.geysermc.connector.entity.player.PlayerEntity;
 import org.geysermc.connector.network.session.GeyserSession;
 import org.geysermc.connector.network.session.auth.BedrockClientData;
@@ -47,6 +46,9 @@ import java.util.function.Consumer;
 
 public class SkinManager {
 
+    /**
+     * Builds a Bedrock player list entry from our existing, cached Bedrock skin information
+     */
     public static PlayerListPacket.Entry buildCachedEntry(GeyserSession session, PlayerEntity playerEntity) {
         GameProfileData data = GameProfileData.from(playerEntity.getProfile());
         SkinProvider.Cape cape = SkinProvider.getCachedCape(data.getCapeUrl());
@@ -70,27 +72,31 @@ public class SkinManager {
         );
     }
 
+    /**
+     * With all the information needed, build a Bedrock player entry with translated skin information.
+     */
     public static PlayerListPacket.Entry buildEntryManually(GeyserSession session, UUID uuid, String username, long geyserId,
                                                                  String skinId, byte[] skinData,
                                                                  String capeId, byte[] capeData,
                                                                  SkinProvider.SkinGeometry geometry) {
         SerializedSkin serializedSkin = SerializedSkin.of(
                 skinId, geometry.getGeometryName(), ImageData.of(skinData), Collections.emptyList(),
-                ImageData.of(capeData), geometry.getGeometryData(), "", true, false, !capeId.equals(SkinProvider.EMPTY_CAPE.getCapeId()), capeId, skinId
+                ImageData.of(capeData), geometry.getGeometryData(), "", true, false,
+                !capeId.equals(SkinProvider.EMPTY_CAPE.getCapeId()), capeId, skinId
         );
 
-        // This attempts to find the xuid of the player so profile images show up for xbox accounts
+        // This attempts to find the XUID of the player so profile images show up for Xbox accounts
         String xuid = "";
-        GeyserSession player = GeyserConnector.getInstance().getPlayerByUuid(uuid);
+        GeyserSession playerSession = GeyserConnector.getInstance().getPlayerByUuid(uuid);
 
-        if (player != null) {
-            xuid = player.getAuthData().getXboxUUID();
+        if (playerSession != null) {
+            xuid = playerSession.getAuthData().getXboxUUID();
         }
 
         PlayerListPacket.Entry entry;
 
         // If we are building a PlayerListEntry for our own session we use our AuthData UUID instead of the Java UUID
-        // as bedrock expects to get back its own provided uuid
+        // as Bedrock expects to get back its own provided UUID
         if (session.getPlayerEntity().getUuid().equals(uuid)) {
             entry = new PlayerListPacket.Entry(session.getAuthData().getUUID());
         } else {
@@ -134,12 +140,13 @@ public class SkinManager {
                                 geometry, entity.getUuid()
                         ), geometry, 3);
 
+                        boolean isDeadmau5 = "deadmau5".equals(entity.getUsername());
                         // Not a bedrock player check for ears
-                        if (geometry.isFailed() && SkinProvider.ALLOW_THIRD_PARTY_EARS) {
+                        if (geometry.isFailed() && (SkinProvider.ALLOW_THIRD_PARTY_EARS || isDeadmau5)) {
                             boolean isEars;
 
                             // Its deadmau5, gotta support his skin :)
-                            if (entity.getUuid().toString().equals("1e18d5ff-643d-45c8-b509-43b8461d8614")) {
+                            if (isDeadmau5) {
                                 isEars = true;
                             } else {
                                 // Get the ears texture for the player
@@ -185,7 +192,6 @@ public class SkinManager {
                                 playerRemovePacket.setAction(PlayerListPacket.Action.REMOVE);
                                 playerRemovePacket.getEntries().add(updatedEntry);
                                 session.sendUpstreamPacket(playerRemovePacket);
-
                             }
                         }
                     } catch (Exception e) {
@@ -238,20 +244,20 @@ public class SkinManager {
          * @return The built GameProfileData
          */
         public static GameProfileData from(GameProfile profile) {
-            // Fallback to the offline mode of working it out
-            boolean isAlex = (Math.abs(profile.getId().hashCode() % 2) == 1);
-
             try {
                 GameProfile.Property skinProperty = profile.getProperty("textures");
 
-                // TODO: Remove try/catch here
+                if (skinProperty == null) {
+                    // Likely offline mode
+                    return loadBedrockOrOfflineSkin(profile);
+                }
                 JsonNode skinObject = GeyserConnector.JSON_MAPPER.readTree(new String(Base64.getDecoder().decode(skinProperty.getValue()), StandardCharsets.UTF_8));
                 JsonNode textures = skinObject.get("textures");
 
                 JsonNode skinTexture = textures.get("SKIN");
                 String skinUrl = skinTexture.get("url").asText().replace("http://", "https://");
 
-                isAlex = skinTexture.has("metadata");
+                boolean isAlex = skinTexture.has("metadata");
 
                 String capeUrl = null;
                 if (textures.has("CAPE")) {
@@ -261,20 +267,30 @@ public class SkinManager {
 
                 return new GameProfileData(skinUrl, capeUrl, isAlex);
             } catch (Exception exception) {
-                if (GeyserConnector.getInstance().getAuthType() != AuthType.OFFLINE) {
-                    GeyserConnector.getInstance().getLogger().debug("Got invalid texture data for " + profile.getName() + " " + exception.getMessage());
-                }
-                // return default skin with default cape when texture data is invalid
-                String skinUrl = isAlex ? SkinProvider.EMPTY_SKIN_ALEX.getTextureUrl() : SkinProvider.EMPTY_SKIN.getTextureUrl();
-                if ("steve".equals(skinUrl) || "alex".equals(skinUrl)) {
-                    GeyserSession session = GeyserConnector.getInstance().getPlayerByUuid(profile.getId());
-
-                    if (session != null) {
-                        skinUrl = session.getClientData().getSkinId();
-                    }
-                }
-                return new GameProfileData(skinUrl, SkinProvider.EMPTY_CAPE.getTextureUrl(), isAlex);
+                GeyserConnector.getInstance().getLogger().debug("Something went wrong while processing skin for " + profile.getName() + ": " + exception.getMessage());
+                return loadBedrockOrOfflineSkin(profile);
             }
         }
+
+        /**
+         * @return default skin with default cape when texture data is invalid, or the Bedrock player's skin if this
+         * is a Bedrock player.
+         */
+        private static GameProfileData loadBedrockOrOfflineSkin(GameProfile profile) {
+            // Fallback to the offline mode of working it out
+            boolean isAlex = (Math.abs(profile.getId().hashCode() % 2) == 1);
+
+            String skinUrl = isAlex ? SkinProvider.EMPTY_SKIN_ALEX.getTextureUrl() : SkinProvider.EMPTY_SKIN.getTextureUrl();
+            String capeUrl = SkinProvider.EMPTY_CAPE.getTextureUrl();
+            if ("steve".equals(skinUrl) || "alex".equals(skinUrl)) {
+                GeyserSession session = GeyserConnector.getInstance().getPlayerByUuid(profile.getId());
+
+                if (session != null) {
+                    skinUrl = session.getClientData().getSkinId();
+                    capeUrl = session.getClientData().getCapeId();
+                }
+            }
+            return new GameProfileData(skinUrl, capeUrl, isAlex);
+        }
     }
 }