Don't store GameProfile class of players

This stores repetitive information, and also we don't currently use the signature, so it's wasted memory.
This commit is contained in:
Camotoy 2022-03-30 22:30:49 -04:00
parent 7a5321b78f
commit 2a05dd57ff
No known key found for this signature in database
GPG key ID: 7EEFB66FE798081F
10 changed files with 68 additions and 80 deletions

View file

@ -25,7 +25,6 @@
package org.geysermc.geyser.entity.type.player;
import com.github.steveice10.mc.auth.data.GameProfile;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
@ -61,16 +60,22 @@ import org.geysermc.geyser.translator.text.MessageTranslator;
import javax.annotation.Nullable;
import java.util.Collections;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@Getter @Setter
public class PlayerEntity extends LivingEntity {
public static final float SNEAKING_POSE_HEIGHT = 1.5f;
private GameProfile profile;
private String username;
private boolean playerList = true; // Player is in the player list
/**
* The textures property from the GameProfile.
*/
@Nullable
private String texturesProperty;
private Vector3i bedPosition;
/**
@ -82,11 +87,12 @@ public class PlayerEntity extends LivingEntity {
*/
private ParrotEntity rightParrot;
public PlayerEntity(GeyserSession session, int entityId, long geyserId, GameProfile gameProfile, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
super(session, entityId, geyserId, gameProfile.getId(), EntityDefinitions.PLAYER, position, motion, yaw, pitch, headYaw);
public PlayerEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, Vector3f position,
Vector3f motion, float yaw, float pitch, float headYaw, String username, @Nullable String texturesProperty) {
super(session, entityId, geyserId, uuid, EntityDefinitions.PLAYER, position, motion, yaw, pitch, headYaw);
profile = gameProfile;
username = gameProfile.getName();
this.username = username;
this.texturesProperty = texturesProperty;
}
@Override

View file

@ -25,7 +25,6 @@
package org.geysermc.geyser.entity.type.player;
import com.github.steveice10.mc.auth.data.GameProfile;
import com.github.steveice10.mc.protocol.data.game.entity.attribute.Attribute;
import com.github.steveice10.mc.protocol.data.game.entity.attribute.AttributeType;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
@ -71,7 +70,7 @@ public class SessionPlayerEntity extends PlayerEntity {
private int fakeTradeXp;
public SessionPlayerEntity(GeyserSession session) {
super(session, -1, 1, new GameProfile(UUID.randomUUID(), "unknown"), Vector3f.ZERO, Vector3f.ZERO, 0, 0, 0);
super(session, -1, 1, UUID.randomUUID(), Vector3f.ZERO, Vector3f.ZERO, 0, 0, 0, "unknown", null);
valid = true;
}

View file

@ -25,7 +25,6 @@
package org.geysermc.geyser.entity.type.player;
import com.github.steveice10.mc.auth.data.GameProfile;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.math.vector.Vector3i;
import com.nukkitx.protocol.bedrock.data.PlayerPermission;
@ -36,6 +35,8 @@ import com.nukkitx.protocol.bedrock.packet.AddPlayerPacket;
import lombok.Getter;
import org.geysermc.geyser.session.GeyserSession;
import java.util.UUID;
/**
* A wrapper to handle skulls more effectively - skulls have to be treated as entities since there are no
* custom player skulls in Bedrock.
@ -48,8 +49,8 @@ public class SkullPlayerEntity extends PlayerEntity {
@Getter
private final int blockState;
public SkullPlayerEntity(GeyserSession session, long geyserId, GameProfile gameProfile, Vector3f position, float rotation, int blockState) {
super(session, 0, geyserId, gameProfile, position, Vector3f.ZERO, rotation, 0, rotation);
public SkullPlayerEntity(GeyserSession session, long geyserId, Vector3f position, float rotation, int blockState, String texturesProperty) {
super(session, 0, geyserId, UUID.randomUUID(), position, Vector3f.ZERO, rotation, 0, rotation, "", texturesProperty);
this.blockState = blockState;
setPlayerList(false);
}

View file

@ -25,7 +25,6 @@
package org.geysermc.geyser.skin;
import com.github.steveice10.mc.auth.data.GameProfile;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
@ -106,7 +105,7 @@ public class FakeHeadProvider {
session.getPlayerWithCustomHeads().add(entity.getUuid());
GameProfile.Property texturesProperty = entity.getProfile().getProperty("textures");
String texturesProperty = entity.getTexturesProperty();
SkinProvider.EXECUTOR_SERVICE.execute(() -> {
try {
@ -182,7 +181,7 @@ public class FakeHeadProvider {
@Getter
@Setter
private static class FakeHeadEntry {
private final GameProfile.Property texturesProperty;
private final String texturesProperty;
private final String fakeHeadSkinUrl;
private PlayerEntity entity;
@ -192,18 +191,7 @@ public class FakeHeadProvider {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
FakeHeadEntry that = (FakeHeadEntry) o;
return equals(texturesProperty, that.texturesProperty) && Objects.equals(fakeHeadSkinUrl, that.fakeHeadSkinUrl);
}
private boolean equals(GameProfile.Property a, GameProfile.Property b) {
//TODO actually fix this in MCAuthLib
if (a == b) {
return true;
}
if (a == null || b == null) {
return false;
}
return Objects.equals(a.getName(), b.getName()) && Objects.equals(a.getValue(), b.getValue()) && Objects.equals(a.getSignature(), b.getSignature());
return Objects.equals(texturesProperty, that.texturesProperty) && Objects.equals(fakeHeadSkinUrl, that.fakeHeadSkinUrl);
}
@Override

View file

@ -26,7 +26,6 @@
package org.geysermc.geyser.skin;
import com.fasterxml.jackson.databind.JsonNode;
import com.github.steveice10.mc.auth.data.GameProfile;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.ListTag;
import com.github.steveice10.opennbt.tag.builtin.StringTag;
@ -34,9 +33,9 @@ import com.nukkitx.protocol.bedrock.data.skin.ImageData;
import com.nukkitx.protocol.bedrock.data.skin.SerializedSkin;
import com.nukkitx.protocol.bedrock.packet.PlayerListPacket;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.session.auth.AuthType;
import org.geysermc.geyser.entity.type.player.PlayerEntity;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.auth.AuthType;
import org.geysermc.geyser.session.auth.BedrockClientData;
import org.geysermc.geyser.text.GeyserLocale;
@ -54,7 +53,7 @@ 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());
GameProfileData data = GameProfileData.from(playerEntity);
SkinProvider.Cape cape = SkinProvider.getCachedCape(data.capeUrl());
SkinProvider.SkinGeometry geometry = SkinProvider.SkinGeometry.getLegacy(data.isAlex());
@ -65,8 +64,8 @@ public class SkinManager {
return buildEntryManually(
session,
playerEntity.getProfile().getId(),
playerEntity.getProfile().getName(),
playerEntity.getUuid(),
playerEntity.getUsername(),
playerEntity.getGeyserId(),
skin.getTextureUrl(),
skin.getSkinData(),
@ -227,31 +226,31 @@ public class SkinManager {
}
/**
* Generate the GameProfileData from the given GameProfile
* Generate the GameProfileData from the given player entity
*
* @param profile GameProfile to build the GameProfileData from
* @param entity entity to build the GameProfileData from
* @return The built GameProfileData
*/
public static GameProfileData from(GameProfile profile) {
public static GameProfileData from(PlayerEntity entity) {
try {
GameProfile.Property skinProperty = profile.getProperty("textures");
String texturesProperty = entity.getTexturesProperty();
if (skinProperty == null) {
if (texturesProperty == null) {
// Likely offline mode
return loadBedrockOrOfflineSkin(profile);
return loadBedrockOrOfflineSkin(entity);
}
GameProfileData data = loadFromJson(skinProperty.getValue());
GameProfileData data = loadFromJson(texturesProperty);
if (data != null) {
return data;
} else {
return loadBedrockOrOfflineSkin(profile);
return loadBedrockOrOfflineSkin(entity);
}
} catch (IOException exception) {
GeyserImpl.getInstance().getLogger().debug("Something went wrong while processing skin for " + profile.getName());
GeyserImpl.getInstance().getLogger().debug("Something went wrong while processing skin for " + entity.getUsername());
if (GeyserImpl.getInstance().getConfig().isDebugMode()) {
exception.printStackTrace();
}
return loadBedrockOrOfflineSkin(profile);
return loadBedrockOrOfflineSkin(entity);
}
}
@ -280,14 +279,15 @@ public class SkinManager {
* @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) {
private static GameProfileData loadBedrockOrOfflineSkin(PlayerEntity entity) {
// Fallback to the offline mode of working it out
boolean isAlex = (Math.abs(profile.getId().hashCode() % 2) == 1);
UUID uuid = entity.getUuid();
boolean isAlex = (Math.abs(uuid.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)) && GeyserImpl.getInstance().getConfig().getRemote().getAuthType() != AuthType.ONLINE) {
GeyserSession session = GeyserImpl.getInstance().connectionByUuid(profile.getId());
GeyserSession session = GeyserImpl.getInstance().connectionByUuid(uuid);
if (session != null) {
skinUrl = session.getClientData().getSkinId();

View file

@ -27,7 +27,6 @@ package org.geysermc.geyser.skin;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.steveice10.mc.auth.data.GameProfile;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.IntArrayTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
@ -53,7 +52,6 @@ import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.*;
import java.util.concurrent.*;
import java.util.function.Predicate;
@ -157,7 +155,7 @@ public class SkinProvider {
}
public static CompletableFuture<SkinProvider.SkinData> requestSkinData(PlayerEntity entity) {
SkinManager.GameProfileData data = SkinManager.GameProfileData.from(entity.getProfile());
SkinManager.GameProfileData data = SkinManager.GameProfileData.from(entity);
return requestSkinAndCape(entity.getUuid(), data.skinUrl(), data.capeUrl())
.thenApplyAsync(skinAndCape -> {
@ -546,12 +544,11 @@ public class SkinProvider {
* @param skullOwner the CompoundTag of the skull with no textures
* @return a completable GameProfile with textures included
*/
public static CompletableFuture<GameProfile> requestTexturesFromUsername(CompoundTag skullOwner) {
public static CompletableFuture<String> requestTexturesFromUsername(CompoundTag skullOwner) {
return CompletableFuture.supplyAsync(() -> {
Tag uuidTag = skullOwner.get("Id");
String uuidToString = "";
JsonNode node;
GameProfile gameProfile = new GameProfile(UUID.randomUUID(), "");
boolean retrieveUuidFromInternet = !(uuidTag instanceof IntArrayTag); // also covers null check
if (!retrieveUuidFromInternet) {
@ -577,15 +574,12 @@ public class SkinProvider {
// Get textures from UUID
node = WebUtils.getJson("https://sessionserver.mojang.com/session/minecraft/profile/" + uuidToString);
List<GameProfile.Property> profileProperties = new ArrayList<>();
JsonNode properties = node.get("properties");
if (properties == null) {
GeyserImpl.getInstance().getLogger().debug("No properties found in Mojang response for " + uuidToString);
return null;
}
profileProperties.add(new GameProfile.Property("textures", node.get("properties").get(0).get("value").asText()));
gameProfile.setProperties(profileProperties);
return gameProfile;
return node.get("properties").get(0).get("value").asText();
} catch (Exception e) {
if (GeyserImpl.getInstance().getConfig().isDebugMode()) {
e.printStackTrace();

View file

@ -50,7 +50,7 @@ public class SkullSkinManager extends SkinManager {
public static void requestAndHandleSkin(PlayerEntity entity, GeyserSession session,
Consumer<SkinProvider.Skin> skinConsumer) {
GameProfileData data = GameProfileData.from(entity.getProfile());
GameProfileData data = GameProfileData.from(entity);
SkinProvider.requestSkin(entity.getUuid(), data.skinUrl(), true)
.whenCompleteAsync((skin, throwable) -> {

View file

@ -25,7 +25,6 @@
package org.geysermc.geyser.translator.level.block.entity;
import com.github.steveice10.mc.auth.data.GameProfile;
import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.ListTag;
@ -35,15 +34,12 @@ import com.nukkitx.math.vector.Vector3i;
import com.nukkitx.nbt.NbtMapBuilder;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.type.player.SkullPlayerEntity;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.skin.SkinProvider;
import org.geysermc.geyser.skin.SkullSkinManager;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
@ -62,7 +58,7 @@ public class SkullBlockEntityTranslator extends BlockEntityTranslator implements
builder.put("SkullType", skullVariant);
}
public static CompletableFuture<GameProfile> getProfile(CompoundTag tag) {
private static CompletableFuture<String> getTextures(CompoundTag tag) {
CompoundTag owner = tag.get("SkullOwner");
if (owner != null) {
CompoundTag properties = owner.get("Properties");
@ -73,13 +69,7 @@ public class SkullBlockEntityTranslator extends BlockEntityTranslator implements
ListTag textures = properties.get("textures");
LinkedHashMap<?,?> tag1 = (LinkedHashMap<?,?>) textures.get(0).getValue();
StringTag texture = (StringTag) tag1.get("Value");
List<GameProfile.Property> profileProperties = new ArrayList<>();
GameProfile gameProfile = new GameProfile(UUID.randomUUID(), "");
profileProperties.add(new GameProfile.Property("textures", texture.getValue()));
gameProfile.setProperties(profileProperties);
return CompletableFuture.completedFuture(gameProfile);
return CompletableFuture.completedFuture(texture.getValue());
}
return CompletableFuture.completedFuture(null);
}
@ -108,21 +98,21 @@ public class SkullBlockEntityTranslator extends BlockEntityTranslator implements
Vector3i blockPosition = Vector3i.from(posX, posY, posZ);
Vector3f entityPosition = Vector3f.from(x, y, z);
getProfile(tag).whenComplete((gameProfile, throwable) -> {
if (gameProfile == null) {
getTextures(tag).whenComplete((texturesProperty, throwable) -> {
if (texturesProperty == null) {
session.getGeyser().getLogger().debug("Custom skull with invalid SkullOwner tag: " + blockPosition + " " + tag);
return;
}
if (session.getEventLoop().inEventLoop()) {
spawnPlayer(session, gameProfile, blockPosition, entityPosition, rotation, blockState);
spawnPlayer(session, texturesProperty, blockPosition, entityPosition, rotation, blockState);
} else {
session.executeInEventLoop(() -> spawnPlayer(session, gameProfile, blockPosition, entityPosition, rotation, blockState));
session.executeInEventLoop(() -> spawnPlayer(session, texturesProperty, blockPosition, entityPosition, rotation, blockState));
}
});
}
private static void spawnPlayer(GeyserSession session, GameProfile profile, Vector3i blockPosition,
private static void spawnPlayer(GeyserSession session, String texturesProperty, Vector3i blockPosition,
Vector3f entityPosition, float rotation, int blockState) {
long geyserId = session.getEntityCache().getNextEntityId().incrementAndGet();
@ -132,7 +122,7 @@ public class SkullBlockEntityTranslator extends BlockEntityTranslator implements
existingSkull.despawnEntity(blockPosition);
}
SkullPlayerEntity player = new SkullPlayerEntity(session, geyserId, profile, entityPosition, rotation, blockState);
SkullPlayerEntity player = new SkullPlayerEntity(session, geyserId, entityPosition, rotation, blockState, texturesProperty);
// Cache entity
session.getSkullCache().put(blockPosition, player);

View file

@ -25,6 +25,7 @@
package org.geysermc.geyser.translator.protocol.java.entity.player;
import com.github.steveice10.mc.auth.data.GameProfile;
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.clientbound.ClientboundPlayerInfoPacket;
@ -50,31 +51,38 @@ public class JavaPlayerInfoTranslator extends PacketTranslator<ClientboundPlayer
for (PlayerListEntry entry : packet.getEntries()) {
switch (packet.getAction()) {
case ADD_PLAYER -> {
GameProfile profile = entry.getProfile();
PlayerEntity playerEntity;
boolean self = entry.getProfile().getId().equals(session.getPlayerEntity().getUuid());
boolean self = profile.getId().equals(session.getPlayerEntity().getUuid());
if (self) {
// Entity is ourself
playerEntity = session.getPlayerEntity();
} else {
playerEntity = session.getEntityCache().getPlayerEntity(entry.getProfile().getId());
playerEntity = session.getEntityCache().getPlayerEntity(profile.getId());
}
GameProfile.Property textures = profile.getProperty("textures");
String texturesProperty = textures == null ? null : textures.getValue();
if (playerEntity == null) {
// It's a new player
playerEntity = new PlayerEntity(
session,
-1,
session.getEntityCache().getNextEntityId().incrementAndGet(),
entry.getProfile(),
profile.getId(),
Vector3f.ZERO,
Vector3f.ZERO,
0, 0, 0
0, 0, 0,
profile.getName(),
texturesProperty
);
session.getEntityCache().addPlayerEntity(playerEntity);
} else {
playerEntity.setProfile(entry.getProfile());
playerEntity.setUsername(profile.getName());
playerEntity.setTexturesProperty(texturesProperty);
}
playerEntity.setPlayerList(true);

View file

@ -48,7 +48,9 @@ public class JavaAddPlayerTranslator extends PacketTranslator<ClientboundAddPlay
PlayerEntity entity;
if (packet.getUuid().equals(session.getPlayerEntity().getUuid())) {
// Server is sending a fake version of the current player
entity = new PlayerEntity(session, packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(), session.getPlayerEntity().getProfile(), position, Vector3f.ZERO, yaw, pitch, headYaw);
entity = new PlayerEntity(session, packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(),
session.getPlayerEntity().getUuid(), position, Vector3f.ZERO, yaw, pitch, headYaw, session.getPlayerEntity().getUsername(),
session.getPlayerEntity().getTexturesProperty());
} else {
entity = session.getEntityCache().getPlayerEntity(packet.getUuid());
if (entity == null) {