diff --git a/src/Snap.Hutao/Snap.Hutao/Web/ApiEndpoints.cs b/src/Snap.Hutao/Snap.Hutao/Web/ApiEndpoints.cs
index cb9986a8..c3b863db 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/ApiEndpoints.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/ApiEndpoints.cs
@@ -281,7 +281,10 @@ internal static class ApiEndpoints
///
/// 公告列表
///
- public static string AnnList(string languageCode, string region)
+ /// 语言代码
+ /// 服务器
+ /// 公告列表Url
+ public static string AnnList(string languageCode, in Region region)
{
return $"{Hk4eApiAnnouncementApi}/getAnnList?{AnnouncementQuery(languageCode, region)}";
}
@@ -289,7 +292,10 @@ internal static class ApiEndpoints
///
/// 公告内容
///
- public static string AnnContent(string languageCode, string region)
+ /// 语言代码
+ /// 服务器
+ /// 公告列表Url
+ public static string AnnContent(string languageCode, in Region region)
{
return $"{Hk4eApiAnnouncementApi}/getAnnContent?{AnnouncementQuery(languageCode, region)}";
}
@@ -428,7 +434,7 @@ internal static class ApiEndpoints
///
public const string WebStaticMihoyoReferer = "https://webstatic.mihoyo.com";
- private static string AnnouncementQuery(string languageCode, string region)
+ private static string AnnouncementQuery(string languageCode, in Region region)
{
return $"game=hk4e&game_biz=hk4e_cn&lang={languageCode}&bundle_id=hk4e_cn&platform=pc®ion={region}&level=55&uid=100000000";
}
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/ApiOsEndpoints.cs b/src/Snap.Hutao/Snap.Hutao/Web/ApiOsEndpoints.cs
index d1205ff4..eb17d057 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/ApiOsEndpoints.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/ApiOsEndpoints.cs
@@ -100,7 +100,7 @@ internal static class ApiOsEndpoints
///
/// 地区代号
/// 用户游戏角色字符串
- public static string UserGameRolesByLtoken(string region)
+ public static string UserGameRolesByLtoken(in Region region)
{
return $"{ApiAccountOsBindingApi}/getUserGameRolesByLtoken?game_biz=hk4e_global®ion={region}";
}
@@ -197,7 +197,7 @@ internal static class ApiOsEndpoints
/// 语言代码
/// 服务器
/// 公告列表Url
- public static string AnnList(string languageCode, string region)
+ public static string AnnList(string languageCode, in Region region)
{
return $"{Hk4eApiOsAnnouncementApi}/getAnnList?{AnnouncementQuery(languageCode, region)}";
}
@@ -208,7 +208,7 @@ internal static class ApiOsEndpoints
/// 语言代码
/// 服务器
/// 公告内容Url
- public static string AnnContent(string languageCode, string region)
+ public static string AnnContent(string languageCode, in Region region)
{
return $"{Hk4eApiOsAnnouncementApi}/getAnnContent?{AnnouncementQuery(languageCode, region)}";
}
@@ -360,7 +360,7 @@ internal static class ApiOsEndpoints
///
public const string AppHoyolabReferer = "https://app.hoyolab.com/";
- private static string AnnouncementQuery(string languageCode, string region)
+ private static string AnnouncementQuery(string languageCode, in Region region)
{
return $"game=hk4e&game_biz=hk4e_global&lang={languageCode}&bundle_id=hk4e_global&platform=pc®ion={region}&level=55&uid=100000000";
}
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Event/GachaInfo/GachaLogPage.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Event/GachaInfo/GachaLogPage.cs
index e4a6dc7f..1dd4da2a 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Event/GachaInfo/GachaLogPage.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Event/GachaInfo/GachaLogPage.cs
@@ -41,7 +41,8 @@ internal sealed class GachaLogPage : IJsonOnDeserialized
/// 地区
///
[JsonPropertyName("region")]
- public string Region { get; set; } = default!;
+ [JsonConverter(typeof(RegionConverter))]
+ public Region Region { get; set; } = default!;
public void OnDeserialized()
{
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/PlayerUid.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/PlayerUid.cs
index a788a6cd..c1fa8b94 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/PlayerUid.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/PlayerUid.cs
@@ -17,18 +17,18 @@ internal readonly partial struct PlayerUid
///
/// 地区代码
///
- public readonly string Region;
+ public readonly Region Region;
///
/// 构造一个新的玩家 Uid 结构
///
/// uid
/// 服务器,当提供该参数时会无条件信任
- public PlayerUid(string value, string? region = default)
+ public PlayerUid(string value, in Region? region = default)
{
Must.Argument(HoyolabRegex.UidRegex().IsMatch(value), SH.WebHoyolabInvalidUid);
Value = value;
- Region = region ?? EvaluateRegion(value.AsSpan()[0]);
+ Region = region ?? Region.FromUid(value);
}
public static implicit operator PlayerUid(string source)
@@ -67,12 +67,12 @@ internal readonly partial struct PlayerUid
};
}
- public static TimeSpan GetRegionTimeZoneUtcOffsetForRegion(string region)
+ public static TimeSpan GetRegionTimeZoneUtcOffsetForRegion(in Region region)
{
// 美服 UTC-05
// 欧服 UTC+01
// 其他 UTC+08
- return region switch
+ return region.Value switch
{
"os_usa" => ServerRegionTimeZone.AmericaServerOffset,
"os_euro" => ServerRegionTimeZone.EuropeServerOffset,
@@ -85,21 +85,4 @@ internal readonly partial struct PlayerUid
{
return Value;
}
-
- private static string EvaluateRegion(in char first)
- {
- return first switch
- {
- // CN
- >= '1' and <= '4' => "cn_gf01", // 国服
- '5' => "cn_qd01", // 渠道
-
- // OS
- '6' => "os_usa", // 美服
- '7' => "os_euro", // 欧服
- '8' => "os_asia", // 亚服
- '9' => "os_cht", // 台服
- _ => throw Must.NeverHappen(),
- };
- }
}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/PlayerUidExtension.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/PlayerUidExtension.cs
index 538827a8..411d39e2 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/PlayerUidExtension.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/PlayerUidExtension.cs
@@ -12,7 +12,7 @@ internal static class PlayerUidExtension
{
NameValueCollection collection = [];
collection.Set("role_id", playerUid.Value);
- collection.Set("server", playerUid.Region);
+ collection.Set("server", playerUid.Region.Value);
return collection.ToQueryString();
}
@@ -21,7 +21,7 @@ internal static class PlayerUidExtension
{
NameValueCollection collection = [];
collection.Set("uid", playerUid.Value);
- collection.Set("region", playerUid.Region);
+ collection.Set("region", playerUid.Region.Value);
return collection.ToQueryString();
}
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/RegionConverter.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/RegionConverter.cs
new file mode 100644
index 00000000..209ad3ac
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/RegionConverter.cs
@@ -0,0 +1,22 @@
+// Copyright (c) DGP Studio. All rights reserved.
+// Licensed under the MIT license.
+
+namespace Snap.Hutao.Web.Hoyolab;
+
+internal sealed class RegionConverter : JsonConverter
+{
+ public override Region Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ if (reader.GetString() is { } regionValue)
+ {
+ return Region.FromRegion(regionValue);
+ }
+
+ return default;
+ }
+
+ public override void Write(Utf8JsonWriter writer, Region value, JsonSerializerOptions options)
+ {
+ writer.WriteStringValue(value.ToString());
+ }
+}
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/GenAuthKeyData.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/GenAuthKeyData.cs
index 429049a6..de71b91f 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/GenAuthKeyData.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/GenAuthKeyData.cs
@@ -25,7 +25,7 @@ internal sealed class GenAuthKeyData
AuthAppId = authAppId;
GameBiz = gameBiz;
GameUid = int.Parse(uid.Value, CultureInfo.InvariantCulture);
- Region = uid.Region;
+ Region = uid.Region.Value;
}
///
@@ -50,7 +50,8 @@ internal sealed class GenAuthKeyData
/// 区域
///
[JsonPropertyName("region")]
- public string Region { get; set; } = default!;
+ [JsonConverter(typeof(RegionConverter))]
+ public Region Region { get; set; } = default!;
///
/// 创建为祈愿记录验证密钥提交数据
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/UserGameRole.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/UserGameRole.cs
index 2856598f..2e8ca931 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/UserGameRole.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/UserGameRole.cs
@@ -19,7 +19,8 @@ internal sealed class UserGameRole
/// 服务器
///
[JsonPropertyName("region")]
- public string Region { get; set; } = default!;
+ [JsonConverter(typeof(RegionConverter))]
+ public Region Region { get; set; } = default!;
///
/// 游戏Uid
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Event/BbsSignReward/SignInData.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Event/BbsSignReward/SignInData.cs
index d3f5b4cd..275c7414 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Event/BbsSignReward/SignInData.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Event/BbsSignReward/SignInData.cs
@@ -17,7 +17,7 @@ internal sealed class SignInData
public SignInData(PlayerUid uid, bool isOversea)
{
ActivityId = isOversea ? ApiOsEndpoints.SignInRewardActivityId : ApiEndpoints.LunaActivityId;
- Region = uid.Region;
+ Region = uid.Region.Value;
Uid = uid.Value;
}
@@ -31,7 +31,8 @@ internal sealed class SignInData
/// 地区代码
///
[JsonPropertyName("region")]
- public string Region { get; }
+ [JsonConverter(typeof(RegionConverter))]
+ public Region Region { get; }
///
/// Uid
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Event/Calculate/CalculateClient.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Event/Calculate/CalculateClient.cs
index 8d08d3be..fb1777fc 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Event/Calculate/CalculateClient.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Event/Calculate/CalculateClient.cs
@@ -55,7 +55,7 @@ internal sealed partial class CalculateClient
public async ValueTask> GetAvatarsAsync(UserAndUid userAndUid, CancellationToken token = default)
{
int currentPage = 1;
- SyncAvatarFilter filter = new() { Uid = userAndUid.Uid.Value, Region = userAndUid.Uid.Region };
+ SyncAvatarFilter filter = new() { Uid = userAndUid.Uid.Value, Region = userAndUid.Uid.Region.Value };
List avatars = [];
Response>? resp;
@@ -181,7 +181,8 @@ internal sealed partial class CalculateClient
public string Uid { get; set; } = default!;
[JsonPropertyName("region")]
- public string Region { get; set; } = default!;
+ [JsonConverter(typeof(RegionConverter))]
+ public Region Region { get; set; } = default!;
}
private class IdCount
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/Avatar/CharacterData.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/Avatar/CharacterData.cs
index b60cef12..5bf07d7d 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/Avatar/CharacterData.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/Avatar/CharacterData.cs
@@ -20,7 +20,7 @@ internal sealed class CharacterData
{
CharacterIds = characterIds;
Uid = uid.Value;
- Server = uid.Region;
+ Server = uid.Region.Value;
}
///
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/Avatar/Role.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/Avatar/Role.cs
index 2c28e0a2..4adcbf77 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/Avatar/Role.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/Avatar/Role.cs
@@ -25,7 +25,8 @@ internal sealed class Role
/// 服务器
///
[JsonPropertyName("region")]
- public string Region { get; set; } = default!;
+ [JsonConverter(typeof(RegionConverter))]
+ public Region Region { get; set; } = default!;
///
/// 等级
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/BasicRoleInfo.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/BasicRoleInfo.cs
index 311ee399..75980f1e 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/BasicRoleInfo.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/BasicRoleInfo.cs
@@ -26,7 +26,8 @@ internal sealed class BasicRoleInfo
/// 区域代码
///
[JsonPropertyName("region")]
- public string Region { get; set; } = default!;
+ [JsonConverter(typeof(RegionConverter))]
+ public Region Region { get; set; } = default!;
///
/// 等级