Files
tcg-client/Assets/TcgEngine/Scripts/GameClient/GameClientMatchmaker.cs
xianyi 12a19ba1a9 匹配自动重连
- 修复第一次连接时ClientID为0导致匹配失败的问题
- 在GameClientMatchmaker中添加ClientID检测和自动重连逻辑
- 当检测到ClientID为0时,等待0.5秒后自动断开并重新连接
- 优化MatchmakingPanel显示逻辑,根据ClientID状态显示正确的连接状态
2025-10-16 11:43:27 +08:00

310 lines
9.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Netcode;
using UnityEngine.Events;
using TcgEngine.UI;
namespace TcgEngine.Client
{
/// <summary>
/// 匹配器的主客户端脚本
/// 将向服务器发送请求并在匹配成功或失败时接收响应
/// </summary>
public class GameClientMatchmaker : MonoBehaviour
{
public UnityAction<MatchmakingResult> onMatchmaking;
public UnityAction<MatchmakingList> onMatchmakingList;
public UnityAction<MatchList> onMatchList;
private bool matchmaking = false;
private float timer = 0f;
private float match_timer = 0f;
private string matchmaking_group;
private int matchmaking_players;
private UnityAction<bool> connect_callback;
private float clientid_check_timer = 0f;
private bool reconnecting = false;
private static GameClientMatchmaker _instance;
void Awake()
{
_instance = this;
}
private void Start()
{
TcgNetwork.Get().onConnect += OnConnect;
TcgNetwork.Get().onDisconnect += OnDisconnect;
Messaging.ListenMsg("matchmaking", ReceiveMatchmaking);
Messaging.ListenMsg("matchmaking_list", ReceiveMatchmakingList);
Messaging.ListenMsg("match_list", ReceiveMatchList);
}
private void OnDestroy()
{
Disconnect(); //Disconnect when switching scene
if (TcgNetwork.Get() != null)
{
TcgNetwork.Get().onConnect -= OnConnect;
TcgNetwork.Get().onDisconnect -= OnDisconnect;
Messaging.UnListenMsg("matchmaking");
Messaging.UnListenMsg("matchmaking_list");
Messaging.UnListenMsg("match_list");
}
}
void Update()
{
if (matchmaking)
{
timer += Time.deltaTime;
match_timer += Time.deltaTime;
ulong client_id = TcgNetwork.Get().ClientID;
//检测ClientID为0的情况连接未完全建立
if (IsConnected() && client_id == 0 && !reconnecting)
{
clientid_check_timer += Time.deltaTime;
//如果超过3秒ClientID仍为0断开并重连
if (clientid_check_timer > 0.5f)
{
Debug.Log("ClientID is 0 after 3 seconds, reconnecting...");
reconnecting = true;
//保存匹配信息
string saved_group = matchmaking_group;
int saved_players = matchmaking_players;
//断开连接
Disconnect();
//延迟后重新开始匹配
StartCoroutine(ReconnectAfterDelay(saved_group, saved_players));
clientid_check_timer = 0f;
}
}
else if (IsConnected() && client_id != 0)
{
//ClientID正常重置计时器
clientid_check_timer = 0f;
reconnecting = false;
}
//Send periodic request
if (IsConnected() && client_id != 0 && timer > 2f)
{
timer = 0f;
SendMatchRequest(true, matchmaking_group, matchmaking_players);
}
//Disconnected, stop
if (!IsConnected() && !IsConnecting() && timer > 5f)
{
StopMatchmaking();
}
}
}
private IEnumerator ReconnectAfterDelay(string group, int players)
{
yield return new WaitForSeconds(0.5f);
Debug.Log($"Reconnecting with group: {group}, players: {players}");
StartMatchmaking(group, players);
reconnecting = false;
}
public void StartMatchmaking(string group, int nb_players)
{
if (matchmaking)
StopMatchmaking();
Debug.Log("Start Matchmaking!");
matchmaking_group = group;
matchmaking_players = nb_players;
matchmaking = true;
match_timer = 0f;
timer = 0f;
Connect(NetworkData.Get().url, NetworkData.Get().port, (bool success) =>
{
if (success)
{
SendMatchRequest(false, group, nb_players);
}
else
{
StopMatchmaking();
}
});
}
public void StopMatchmaking()
{
if (matchmaking)
{
Debug.Log("Stop Matchmaking!");
onMatchmaking?.Invoke(null);
matchmaking_group = "";
matchmaking_players = 0;
matchmaking = false;
}
}
public void RefreshMatchmakingList()
{
Connect(NetworkData.Get().url, NetworkData.Get().port, (bool success) =>
{
if (success)
SendMatchmakingListRequest();
});
}
public void RefreshMatchList(string username)
{
Connect(NetworkData.Get().url, NetworkData.Get().port, (bool success) =>
{
if (success)
SendMatchListRequest(username);
});
}
public void Connect(string url, ushort port, UnityAction<bool> callback = null)
{
//Must be logged in to API to connect
if (!Authenticator.Get().IsSignedIn())
{
callback?.Invoke(false);
return;
}
//Check if already connected
if (IsConnected() || IsConnecting())
{
callback?.Invoke(IsConnected());
return;
}
connect_callback = callback;
TcgNetwork.Get().StartClient(url, port);
}
public void Disconnect()
{
TcgNetwork.Get()?.Disconnect();
}
private void OnConnect()
{
Debug.Log("Connected to server!");
connect_callback?.Invoke(true);
connect_callback = null;
}
private void OnDisconnect()
{
StopMatchmaking(); //Stop if currently running
connect_callback?.Invoke(false);
connect_callback = null;
matchmaking = false;
}
private void SendMatchRequest(bool refresh, string group, int nb_players)
{
MsgMatchmaking msg_match = new MsgMatchmaking();
UserData udata = Authenticator.Get().GetUserData();
msg_match.user_id = Authenticator.Get().GetUserId();
msg_match.username = Authenticator.Get().GetUsername();
msg_match.group = group;
msg_match.players = nb_players;
msg_match.elo = udata.elo;
msg_match.time = match_timer;
msg_match.refresh = refresh;
Messaging.SendObject("matchmaking", ServerID, msg_match, NetworkDelivery.Reliable);
}
private void SendMatchmakingListRequest()
{
MsgMatchmakingList msg_match = new MsgMatchmakingList();
msg_match.username = ""; //Return all users
Messaging.SendObject("matchmaking_list", ServerID, msg_match, NetworkDelivery.Reliable);
}
private void SendMatchListRequest(string username)
{
MsgMatchmakingList msg_match = new MsgMatchmakingList();
msg_match.username = username;
Messaging.SendObject("match_list", ServerID, msg_match, NetworkDelivery.Reliable);
}
private void ReceiveMatchmaking(ulong client_id, FastBufferReader reader)
{
reader.ReadNetworkSerializable(out MatchmakingResult msg);
if (IsConnected() && matchmaking && matchmaking_group == msg.group)
{
matchmaking = !msg.success; //Stop matchmaking if success
onMatchmaking?.Invoke(msg);
}
}
private void ReceiveMatchmakingList(ulong client_id, FastBufferReader reader)
{
reader.ReadNetworkSerializable(out MatchmakingList list);
onMatchmakingList?.Invoke(list);
}
private void ReceiveMatchList(ulong client_id, FastBufferReader reader)
{
reader.ReadNetworkSerializable(out MatchList list);
onMatchList?.Invoke(list);
}
public bool IsMatchmaking()
{
return matchmaking;
}
public string GetGroup()
{
return matchmaking_group;
}
public int GetNbPlayers()
{
return matchmaking_players;
}
public float GetTimer()
{
return match_timer;
}
public bool IsConnected()
{
return TcgNetwork.Get().IsConnected();
}
public bool IsConnecting()
{
return TcgNetwork.Get().IsConnecting();
}
public ulong ServerID { get { return TcgNetwork.Get().ServerID; } }
public NetworkMessaging Messaging { get { return TcgNetwork.Get().Messaging; } }
public static GameClientMatchmaker Get()
{
return _instance;
}
}
}