1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
//! 登录验证数据结构
use serde::{Deserialize, Serialize};

use crate::password::Password;

/**
   账户类型枚举,需要提供一个账户种类方可启动游戏
*/
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
pub enum AuthMethod {
    /// 离线账户登录
    Offline {
        /// 离线玩家的名称
        player_name: String,
        /// 离线玩家的统一标识,如果玩家是从其它启动器迁移到使用本启动模块的启动器的,需要提供这个以确保存档物品信息能够正确读取
        uuid: String,
    },
    /// Mojang (Yggdrasil) 账户登录
    Mojang {
        /// 登录令牌,将会作为启动参数的一部分传入游戏实例
        access_token: Password,
        /// 正版玩家的统一标识
        uuid: String,
        /// 正版玩家的名称
        player_name: String,
        /// 正版玩家的头部皮肤位图信息,格式为 RGBA,大小为 8x8,用于展示头像
        head_skin: Vec<u8>,
        /// 正版玩家的头发皮肤位图信息,格式为 RGBA,大小为 8x8,用于展示头像
        hat_skin: Vec<u8>,
    },
    /// 微软账户
    Microsoft {
        /// 登录令牌,将会作为启动参数的一部分传入游戏实例
        access_token: Password,
        /// 刷新令牌,校验/更新登录令牌时实现携带这个作为参数
        refresh_token: Password,
        /// 正版玩家的统一标识
        uuid: String,
        /// 正版玩家的 XBox 用户 ID,用途不明,但是在新版本的 Minecraft 有发现需要使用这个 XUID 的地方
        xuid: String,
        /// 正版玩家的名称
        player_name: String,
        /// 正版玩家的头部皮肤位图信息,格式为 RGBA,大小为 8x8,用于展示头像
        head_skin: Vec<u8>,
        /// 正版玩家的头发皮肤位图信息,格式为 RGBA,大小为 8x8,用于展示头像
        hat_skin: Vec<u8>,
    },
    /// 外置登录(Authlib-Injector)
    AuthlibInjector {
        /// 第三方登录 API 提供方的 API 链接,登录的请求将通过这个 API 发送
        api_location: String,
        /// 第三方登录 API 提供方的服务器名称,用于 GUI 显示
        server_name: String,
        /// 第三方登录 API 提供方的网页主页,用于 GUI 显示跳转
        server_homepage: String,
        /// 第三方登录 API 提供方的元数据,需要在启动时携带这个作为参数
        server_meta: String,
        /// 第三方登录令牌,将会作为启动参数的一部分传入游戏实例
        access_token: Password,
        /// 第三方正版玩家的统一标识
        uuid: String,
        /// 第三方正版玩家的名称
        player_name: String,
        /// 第三方正版玩家的头部皮肤位图信息,格式为 RGBA,大小为 8x8,用于展示头像
        head_skin: Vec<u8>,
        /// 第三方正版玩家的头发皮肤位图信息,格式为 RGBA,大小为 8x8,用于展示头像
        hat_skin: Vec<u8>,
    },
}

pub(crate) mod mojang {
    use serde::{Deserialize, Serialize};

    use crate::password::Password;

    #[derive(Debug, Deserialize, Serialize, PartialEq, Eq)]
    #[serde(rename_all = "camelCase")]
    pub(crate) struct AuthenticateBody {
        pub agent: AuthenticateAgent,
        pub username: String,
        pub password: Password,
        #[serde(skip_serializing_if = "String::is_empty")]
        pub client_token: String,
        pub request_user: bool,
    }

    impl Default for AuthenticateBody {
        fn default() -> Self {
            Self {
                request_user: true,
                username: "".into(),
                password: "".into(),
                client_token: "".into(),
                agent: Default::default(),
            }
        }
    }

    #[derive(Debug, Deserialize, Serialize, PartialEq, Eq)]
    pub(crate) struct AuthenticateAgent {
        pub name: String,
        pub version: usize,
    }

    impl Default for AuthenticateAgent {
        fn default() -> Self {
            Self {
                name: "Minecraft".into(),
                version: 1,
            }
        }
    }

    #[derive(Debug, Deserialize, PartialEq, Eq)]
    #[serde(rename_all = "camelCase")]
    pub(crate) struct AuthenticateResponse {
        pub access_token: Password,
        pub client_token: String,
        pub available_profiles: Vec<AvaliableProfile>,
        pub selected_profile: Option<AvaliableProfile>,
    }

    #[derive(Debug, Serialize, PartialEq, Eq)]
    #[serde(rename_all = "camelCase")]
    pub(crate) struct ValidateResponse {
        pub access_token: Password,
        pub client_token: String,
    }

    #[derive(Debug, Deserialize, Serialize, PartialEq, Eq)]
    pub(crate) struct AvaliableProfile {
        pub name: String,
        pub id: String,
    }

    /// 来自 Mojang 或第三方正版登录传回的错误响应
    #[derive(Debug, Deserialize, PartialEq, Eq, Clone, Default)]
    #[serde(rename_all = "camelCase")]
    pub struct ErrorResponse {
        /// 错误的字符串 ID
        pub error: String,
        /// 错误的字符串信息,可以展示给用户以确认错误原因
        pub error_message: String,
        /// 错误的形成原因,大多数情况这里是空的
        #[serde(default)]
        pub cause: String,
    }

    #[derive(Debug, Deserialize, PartialEq, Eq, Clone)]
    pub(crate) struct ProfileResponse {
        pub id: String,
        pub name: String,
        pub properties: Vec<ProfilePropertie>,
    }

    #[derive(Debug, Deserialize, PartialEq, Eq, Clone)]
    pub(crate) struct ProfilePropertie {
        pub name: String,
        pub value: String,
    }

    #[derive(Debug, Deserialize, PartialEq, Eq, Clone)]
    #[serde(rename_all = "camelCase")]
    pub(crate) struct ProfileTexture {
        pub timestamp: u64,
        pub profile_id: String,
        pub profile_name: String,
        pub textures: Option<TextureData>,
    }

    #[derive(Debug, Deserialize, PartialEq, Eq, Clone)]
    pub(crate) struct TextureData {
        #[serde(rename = "SKIN")]
        pub skin: Option<SkinData>,
        #[serde(rename = "CAPE")]
        pub cape: Option<SkinData>,
    }

    #[derive(Debug, Deserialize, PartialEq, Eq, Clone)]
    pub(crate) struct SkinData {
        pub url: String,
    }
}