Newer
Older
KeeperJerry_Launcher / Launcher / source / client / PlayerProfile.java
@KeeperJerry KeeperJerry on 27 Jun 2020 3 KB Рефактор кода
package launcher.client;

import launcher.LauncherAPI;
import launcher.helper.IOHelper;
import launcher.helper.SecurityHelper;
import launcher.helper.SecurityHelper.DigestAlgorithm;
import launcher.helper.VerifyHelper;
import launcher.serialize.HInput;
import launcher.serialize.HOutput;
import launcher.serialize.stream.StreamObject;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Objects;
import java.util.UUID;

public final class PlayerProfile extends StreamObject
{
    @LauncherAPI
    public final UUID uuid;
    @LauncherAPI
    public final String username;
    @LauncherAPI
    public final Texture skin, cloak;

    @LauncherAPI
    public PlayerProfile(HInput input) throws IOException
    {
        uuid = input.readUUID();
        username = VerifyHelper.verifyUsername(input.readString(64));
        skin = input.readBoolean() ? new Texture(input) : null;
        cloak = input.readBoolean() ? new Texture(input) : null;
    }

    @LauncherAPI
    public PlayerProfile(UUID uuid, String username, Texture skin, Texture cloak)
    {
        this.uuid = Objects.requireNonNull(uuid, "uuid");
        this.username = VerifyHelper.verifyUsername(username);
        this.skin = skin;
        this.cloak = cloak;
    }

    @LauncherAPI
    public static PlayerProfile newOfflineProfile(String username)
    {
        return new PlayerProfile(offlineUUID(username), username, null, null);
    }

    @LauncherAPI
    public static UUID offlineUUID(String username)
    {
        return UUID.nameUUIDFromBytes(IOHelper.encodeASCII("OfflinePlayer:" + username));
    }

    @Override
    public void write(HOutput output) throws IOException
    {
        output.writeUUID(uuid);
        output.writeString(username, 64);

        // Write textures
        output.writeBoolean(skin != null);
        if (skin != null)
        {
            skin.write(output);
        }
        output.writeBoolean(cloak != null);
        if (cloak != null)
        {
            cloak.write(output);
        }
    }

    public static final class Texture extends StreamObject
    {
        private static final DigestAlgorithm DIGEST_ALGO = DigestAlgorithm.SHA256;

        // Instance
        @LauncherAPI
        public final String url;
        @LauncherAPI
        public final byte[] digest;

        @LauncherAPI
        public Texture(String url, byte[] digest)
        {
            this.url = IOHelper.verifyURL(url);
            this.digest = Objects.requireNonNull(digest, "digest");
        }

        @LauncherAPI
        public Texture(String url, boolean cloak) throws IOException
        {
            this.url = IOHelper.verifyURL(url);

            // Fetch texture
            byte[] texture;
            try (InputStream input = IOHelper.newInput(new URL(url)))
            {
                texture = IOHelper.read(input);
            }
            try (ByteArrayInputStream input = new ByteArrayInputStream(texture))
            {
                IOHelper.readTexture(input, cloak); // Verify texture
            }

            // Get digest of texture
            digest = SecurityHelper.digest(DIGEST_ALGO, new URL(url));
        }

        @LauncherAPI
        public Texture(HInput input) throws IOException
        {
            url = IOHelper.verifyURL(input.readASCII(2048));
            digest = input.readByteArray(-DIGEST_ALGO.bytes);
        }

        @Override
        public void write(HOutput output) throws IOException
        {
            output.writeASCII(url, 2048);
            output.writeByteArray(digest, -DIGEST_ALGO.bytes);
        }
    }
}