修了不少东西

This commit is contained in:
2026-07-16 23:04:59 +08:00
parent 29972d0705
commit 73fe474cc6
134 changed files with 7673 additions and 741 deletions
@@ -201,30 +201,51 @@ namespace GameServer.Client
public async Task<ArenaRoomSnapshot> CreateRoom(string songId, string songName, string difficulty, string password = null)
{
await EnsureConnected();
JObject resp = await SendAction("create_room", new
try
{
song_id = songId,
song_name = songName,
difficulty = difficulty,
password = string.IsNullOrWhiteSpace(password) ? null : password
});
ArenaRoomSnapshot snapshot = NormalizeSnapshotFromActionData("create_room", resp);
SetCurrentRoom(snapshot);
return snapshot;
await EnsureConnected();
JObject resp = await SendAction("create_room", new
{
song_id = songId,
song_name = songName,
difficulty = difficulty,
password = string.IsNullOrWhiteSpace(password) ? null : password
});
ArenaRoomSnapshot snapshot = NormalizeSnapshotFromActionData("create_room", resp);
SetCurrentRoom(snapshot);
return snapshot;
}
catch (Exception ex)
{
NetworkManager.ShowUserFacingNetworkError(ex.Message);
throw;
}
}
public async Task<ArenaRoomSnapshot> JoinRoom(string roomCode, string password = null)
{
await EnsureConnected();
JObject resp = await SendAction("join_room", new
try
{
room_code = roomCode,
password = string.IsNullOrWhiteSpace(password) ? null : password
});
ArenaRoomSnapshot snapshot = NormalizeSnapshotFromActionData("join_room", resp);
SetCurrentRoom(snapshot);
return snapshot;
if (string.IsNullOrWhiteSpace(roomCode))
{
throw new Exception("MISSING_ROOM_CODE: room_code is empty");
}
await EnsureConnected();
JObject resp = await SendAction("join_room", new
{
room_code = roomCode.Trim(),
password = string.IsNullOrWhiteSpace(password) ? null : password
});
ArenaRoomSnapshot snapshot = NormalizeSnapshotFromActionData("join_room", resp);
SetCurrentRoom(snapshot);
return snapshot;
}
catch (Exception ex)
{
NetworkManager.ShowUserFacingNetworkError(ex.Message);
throw;
}
}
public async Task<bool> LeaveRoom()
@@ -385,6 +406,31 @@ namespace GameServer.Client
return snapshot;
}
public async Task<ArenaRoomSnapshot> ChangeRoomSong(string songId, string songName, string difficulty)
{
try
{
await EnsureConnected();
JObject resp = await SendAction("change_room_song", new
{
song_id = songId,
song_name = songName,
difficulty = difficulty
});
ArenaRoomSnapshot snapshot = NormalizeSnapshotFromActionData("change_room_song", resp);
if (snapshot != null)
{
SetCurrentRoom(snapshot);
}
return snapshot;
}
catch (Exception ex)
{
NetworkManager.ShowUserFacingNetworkError(ex.Message);
throw;
}
}
public async Task<ArenaRoomSnapshot> StartGame()
{
await EnsureConnected();
@@ -804,11 +850,11 @@ namespace GameServer.Client
NetworkManager network = NetworkManager.Instance;
if (network == null)
{
throw new Exception("NetworkManager is not initialized");
throw new Exception("NETWORK_NOT_READY: NetworkManager is not initialized");
}
if (string.IsNullOrWhiteSpace(network.SteamId))
{
throw new Exception("steam_id is empty");
throw new Exception("MISSING_STEAM_ID: steam_id is empty");
}
_isConnecting = true;
@@ -864,11 +910,11 @@ namespace GameServer.Client
NetworkManager network = NetworkManager.Instance;
if (network == null)
{
throw new Exception("NetworkManager is not initialized");
throw new Exception("NETWORK_NOT_READY: NetworkManager is not initialized");
}
if (string.IsNullOrWhiteSpace(network.SteamId))
{
throw new Exception("steam_id is empty");
throw new Exception("MISSING_STEAM_ID: steam_id is empty");
}
_isSocialConnecting = true;
@@ -1213,6 +1259,15 @@ namespace GameServer.Client
}
return;
}
case "room_song_changed":
{
ArenaRoomSnapshot snapshot = ReadRoomSnapshot(message);
if (snapshot != null)
{
Enqueue(() => SetCurrentRoom(snapshot));
}
return;
}
case "room_dismissed":
{
string roomCode = ReadString(message, "room_code");
@@ -1734,13 +1789,19 @@ namespace GameServer.Client
{
_shutdownLeaveAttempted = false;
string previousRoomCode = CurrentRoom != null ? CurrentRoom.room_code : null;
string previousSongId = CurrentRoom != null ? CurrentRoom.song_id : null;
string previousDifficulty = CurrentRoom != null ? CurrentRoom.difficulty : null;
if (snapshot == null || !IsRoomStartedState(snapshot.status))
{
_isLaunchingArenaGameplay = false;
}
if (snapshot == null || (!string.IsNullOrWhiteSpace(previousRoomCode)
&& !string.Equals(previousRoomCode, snapshot.room_code, StringComparison.Ordinal)))
&& !string.Equals(previousRoomCode, snapshot.room_code, StringComparison.Ordinal))
|| (snapshot != null
&& string.Equals(previousRoomCode, snapshot.room_code, StringComparison.Ordinal)
&& (!string.Equals(previousSongId, snapshot.song_id, StringComparison.Ordinal)
|| !string.Equals(previousDifficulty, snapshot.difficulty, StringComparison.OrdinalIgnoreCase))))
{
ClearRoomRankingScores();
}
@@ -2353,7 +2414,7 @@ namespace GameServer.Client
{
string finalCode = code ?? "ERROR";
string finalMessage = message ?? "Unknown arena error";
gNotice.error.display($"{finalCode}: {finalMessage}");
gNotice.error.display(NetworkManager.DescribeUserFacingNetworkError($"{finalCode}: {finalMessage}"));
OnErrorReceived?.Invoke(finalCode, finalMessage);
});
}
@@ -3890,4 +3951,3 @@ namespace GameServer.Client
}
}
}
@@ -337,6 +337,7 @@ namespace GameServer.Client
[JsonProperty("receiver_id")] public string receiver_id;
[JsonProperty("uid")] public int uid;
[JsonProperty("display_name")] public string display_name;
[JsonProperty("player_title")] public string player_title;
[JsonProperty("avatar_url")] public string avatar_url;
[JsonProperty("content")] public string content;
[JsonProperty("created_at")] public string created_at;
@@ -21,6 +21,8 @@ public class NetworkManager : MonoBehaviour
public static NetworkManager Instance { get; private set; }
private static string _startupSteamId = string.Empty;
private static string _startupSteamDisplayName = string.Empty;
private static string _lastUserFacingNetworkError = string.Empty;
private static float _lastUserFacingNetworkErrorAt;
private static readonly Dictionary<string, CachedRemoteIdentity> _remoteIdentityCache =
new Dictionary<string, CachedRemoteIdentity>(StringComparer.Ordinal);
private static readonly Dictionary<string, Task<ProfileData>> _remoteProfileTasks =
@@ -99,6 +101,8 @@ public class NetworkManager : MonoBehaviour
Instance = null;
_startupSteamId = string.Empty;
_startupSteamDisplayName = string.Empty;
_lastUserFacingNetworkError = string.Empty;
_lastUserFacingNetworkErrorAt = 0f;
_remoteIdentityCache.Clear();
_remoteProfileTasks.Clear();
}
@@ -627,6 +631,7 @@ public class NetworkManager : MonoBehaviour
{
if (OnlineModeSettings.IsLocalOnlyMode)
{
NotifyNetworkError("LOCAL_ONLY_MODE");
return new ArenaCreateResponse
{
success = false,
@@ -635,6 +640,7 @@ public class NetworkManager : MonoBehaviour
};
}
EnsureSteamIdAvailableForOnlineFeature();
var req = new ArenaCreateRequest
{
steam_id = SteamId,
@@ -643,6 +649,13 @@ public class NetworkManager : MonoBehaviour
password = password
};
ArenaCreateResponse resp = await PostJson<ArenaCreateResponse>(BuildApiUrl("/api/arena/create"), req, CancellationToken.None);
if (resp == null || !resp.success)
{
string error = BuildErrorText(resp?.error_code, resp?.message, "CREATE_ROOM_FAILED");
NotifyNetworkError(error);
throw new Exception(error);
}
OnArenaCreated?.Invoke(resp);
return resp;
}
@@ -651,6 +664,7 @@ public class NetworkManager : MonoBehaviour
{
if (OnlineModeSettings.IsLocalOnlyMode)
{
NotifyNetworkError("LOCAL_ONLY_MODE");
return new ArenaJoinResponse
{
success = false,
@@ -660,6 +674,7 @@ public class NetworkManager : MonoBehaviour
};
}
EnsureSteamIdAvailableForOnlineFeature();
var req = new ArenaJoinRequest
{
steam_id = SteamId,
@@ -667,6 +682,13 @@ public class NetworkManager : MonoBehaviour
password = password
};
ArenaJoinResponse resp = await PostJson<ArenaJoinResponse>(BuildApiUrl("/api/arena/join"), req, CancellationToken.None);
if (resp == null || !resp.success)
{
string error = BuildErrorText(resp?.error_code, resp?.message, "JOIN_ROOM_FAILED");
NotifyNetworkError(error);
throw new Exception(error);
}
OnArenaJoined?.Invoke(resp);
return resp;
}
@@ -1682,6 +1704,15 @@ public class NetworkManager : MonoBehaviour
return new InvalidOperationException(message);
}
private void EnsureSteamIdAvailableForOnlineFeature()
{
RefreshSteamIdentity(true);
if (string.IsNullOrWhiteSpace(SteamId))
{
throw new InvalidOperationException("MISSING_STEAM_ID: steam_id is empty");
}
}
private ProfileData BuildLocalOnlyProfile(string targetSteamId)
{
string normalizedSteamId = string.IsNullOrWhiteSpace(targetSteamId) ? string.Empty : targetSteamId.Trim();
@@ -1850,11 +1881,135 @@ public class NetworkManager : MonoBehaviour
private static void NotifyNetworkError(string message)
{
if (!string.IsNullOrWhiteSpace(message))
ShowUserFacingNetworkError(message);
}
public static void ShowUserFacingNetworkError(string message)
{
string userMessage = DescribeUserFacingNetworkError(message);
if (!string.IsNullOrWhiteSpace(userMessage))
{
gNotice.error.display(message);
float now = Time.realtimeSinceStartup;
if (string.Equals(_lastUserFacingNetworkError, userMessage, StringComparison.Ordinal)
&& now - _lastUserFacingNetworkErrorAt < 0.75f)
{
return;
}
_lastUserFacingNetworkError = userMessage;
_lastUserFacingNetworkErrorAt = now;
gNotice.error.display(userMessage);
}
}
public static string DescribeUserFacingNetworkError(string message)
{
if (string.IsNullOrWhiteSpace(message))
{
return "网络错误,请稍后重试";
}
string raw = message.Trim();
string upper = raw.ToUpperInvariant();
if (upper.Contains("LOCAL_ONLY_MODE") || raw.IndexOf("local-only mode", StringComparison.OrdinalIgnoreCase) >= 0)
{
return "当前为离线模式,无法使用联网功能";
}
if (upper.Contains("MISSING_STEAM_ID")
|| upper.Contains("STEAM_ID IS EMPTY")
|| upper.Contains("TARGETSTEAMID IS EMPTY")
|| upper.Contains("STEAMID IS EMPTY")
|| upper.Contains("STEAM ID IS EMPTY"))
{
return "无法得到 SteamID,请确认已启动 Steam、登录账号并保持在线";
}
if (upper.Contains("NETWORKMANAGER IS NOT INITIALIZED") || upper.Contains("NETWORK_NOT_READY"))
{
return "网络模块尚未初始化,请稍后重试";
}
if (upper.Contains("ROOM_NOT_FOUND")
|| raw.IndexOf("room not found", StringComparison.OrdinalIgnoreCase) >= 0
|| raw.IndexOf("房间不存在", StringComparison.OrdinalIgnoreCase) >= 0)
{
return "房间不存在或已解散";
}
if (upper.Contains("ALREADY_IN_ROOM"))
{
return "你已经在房间中";
}
if (upper.Contains("MISSING_ROOM_CODE") || upper.Contains("ROOM_CODE IS EMPTY"))
{
return "房间号不能为空";
}
if (upper.Contains("ROOM_FULL"))
{
return "房间已满";
}
if (upper.Contains("ROOM_STARTED") || upper.Contains("GAME_STARTED") || upper.Contains("ALREADY_STARTED"))
{
return "房间已开始游戏,无法加入";
}
if (upper.Contains("WRONG_PASSWORD") || upper.Contains("INVALID_PASSWORD") || upper.Contains("PASSWORD"))
{
return "房间密码错误";
}
if (upper.Contains("NOT_IN_ROOM"))
{
return "当前不在房间中";
}
if (upper.Contains("TIMED OUT")
|| upper.Contains("TIMEOUT")
|| upper.Contains("CONNECTFAILURE")
|| upper.Contains("CONNECTIONERROR")
|| upper.Contains("CONNECTION FAILED")
|| upper.Contains("CANNOT CONNECT")
|| upper.Contains("COULD NOT RESOLVE")
|| upper.Contains("RESOLVE DESTINATION HOST")
|| upper.Contains("NAMERESOLUTION")
|| upper.Contains("HOST UNREACHABLE")
|| upper.Contains("CONNECTION REFUSED")
|| upper.Contains("CONNECTION RESET")
|| upper.Contains("SOCKET")
|| raw.IndexOf("unable to connect", StringComparison.OrdinalIgnoreCase) >= 0
|| raw.IndexOf("failed to connect", StringComparison.OrdinalIgnoreCase) >= 0)
{
return "未联网或服务器连接失败,请检查网络后重试";
}
if (upper.Contains("HTTP") && (upper.Contains(" 404") || upper.Contains("404:")))
{
return "请求的服务不存在,请稍后重试";
}
if (upper.Contains("HTTP") && (upper.Contains(" 500") || upper.Contains("500:")))
{
return "服务器暂时无法处理请求,请稍后重试";
}
if (raw.Length > 80)
{
return "网络错误,请稍后重试";
}
return raw;
}
private static string BuildErrorText(string code, string message, string fallbackCode)
{
string safeCode = string.IsNullOrWhiteSpace(code) ? fallbackCode : code.Trim();
string safeMessage = string.IsNullOrWhiteSpace(message) ? safeCode : message.Trim();
return $"{safeCode}: {safeMessage}";
}
}
}