258 lines
8.5 KiB
C#
258 lines
8.5 KiB
C#
using System;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using EventPartnerGather;
|
|
using EventPartnerGatherRequests;
|
|
using UnityEngine;
|
|
using EEventBuildState = EventPartnerGatherRequests.EEventBuildState;
|
|
|
|
|
|
namespace UI.PartnerGather
|
|
{
|
|
/// <summary>
|
|
/// 自动匹配控制器
|
|
/// 负责管理自动匹配的生命周期、轮询和状态处理
|
|
/// </summary>
|
|
public class AutoMatchController : IDisposable
|
|
{
|
|
private const bool EnableTraceLogs = false;
|
|
/// <summary>Set true to log each poll cycle (state / IsInMatching / partner count). English only.</summary>
|
|
private const bool EnablePollCycleLogs = false;
|
|
private readonly IAutoMatchManagerContext _manager;
|
|
private CancellationTokenSource _pollCancellation;
|
|
private bool _isMatching;
|
|
|
|
private const int PollIntervalSeconds = 10;
|
|
|
|
public bool IsMatching => _isMatching;
|
|
|
|
public AutoMatchController(IAutoMatchManagerContext manager)
|
|
{
|
|
_manager = manager ?? throw new ArgumentNullException(nameof(manager));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Panel re-enabled: if local toggle is still on, sync partners from status then (re)start matching + polling.
|
|
/// Do not clear IsAutoMatchEnabled when status says IsInMatching=false — user may have only closed the panel
|
|
/// (polling was cancelled locally) or the API may not reflect queue state; re-call ControlAutoMatch(true) via StartAutoMatch.
|
|
/// </summary>
|
|
public async Task TryResumeAutoMatch()
|
|
{
|
|
try
|
|
{
|
|
if (!_manager.IsAutoMatchEnabled)
|
|
return;
|
|
|
|
if (_manager.ShouldCloseAutoMatch)
|
|
{
|
|
_manager.SetAutoMatchEnabled(false);
|
|
_manager.NotifyAutoMatchStopped();
|
|
return;
|
|
}
|
|
|
|
var response = await _manager.FetchAndProcessAutoMatchStatus(force: true);
|
|
if (response?.IsInMatching == true)
|
|
ELog($"AutoMatchStateRestored eventId={_manager.EventId}");
|
|
|
|
var ok = await StartAutoMatch();
|
|
if (!ok)
|
|
_manager.SetAutoMatchEnabled(false);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
LogError($"TryResumeAutoMatchError eventId={_manager.EventId} error={e.Message}");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 开启自动匹配
|
|
/// </summary>
|
|
public async Task<bool> StartAutoMatch()
|
|
{
|
|
var eventId = _manager.EventId;
|
|
try
|
|
{
|
|
Trace($"AutoMatchStartRequest eventId={eventId}");
|
|
var response = await _manager.ControlAutoMatch(true);
|
|
|
|
if (response.State != EEventBuildState.Success)
|
|
{
|
|
LogError($"AutoMatchStartFailed eventId={eventId} state={response.State} reason={response.Message}");
|
|
return false;
|
|
}
|
|
|
|
_isMatching = true;
|
|
StartPullMatchResult(eventId);
|
|
ELog($"AutoMatchStarted eventId={eventId}");
|
|
return true;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
LogError($"AutoMatchStartException eventId={eventId} error={e.Message}");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private void StartPullMatchResult(int eventId)
|
|
{
|
|
_pollCancellation = new CancellationTokenSource();
|
|
_ = PollMatchResult(eventId, _pollCancellation.Token);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 停止自动匹配
|
|
/// </summary>
|
|
public async Task StopAutoMatch()
|
|
{
|
|
Trace($"AutoMatchStopRequest eventId={_manager.EventId}");
|
|
|
|
if (!_isMatching)
|
|
return;
|
|
try
|
|
{
|
|
ELog($"AutoMatchStopping eventId={_manager.EventId}");
|
|
await _manager.ControlAutoMatch(false);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
LogError($"AutoMatchStopException eventId={_manager.EventId} error={e.Message}");
|
|
}
|
|
finally
|
|
{
|
|
CancelPollMatchResult();
|
|
}
|
|
}
|
|
|
|
public void CancelPollMatchResult()
|
|
{
|
|
Trace($"AutoMatchPollingCancel eventId={_manager.EventId}");
|
|
|
|
_pollCancellation?.Cancel();
|
|
_pollCancellation?.Dispose();
|
|
_pollCancellation = null;
|
|
_isMatching = false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 轮询匹配结果
|
|
/// </summary>
|
|
private async Task PollMatchResult(int eventId, CancellationToken cancellationToken)
|
|
{
|
|
while (!cancellationToken.IsCancellationRequested)
|
|
{
|
|
try
|
|
{
|
|
var bRet = await CheckStopAutoMatch();
|
|
if (bRet)
|
|
{
|
|
break;
|
|
}
|
|
|
|
var response = await _manager.FetchAndProcessAutoMatchStatus(force: true);
|
|
var buildState = response?.State;
|
|
PollCycleLog(
|
|
$"PollTick eventId={eventId} state={buildState} isInMatching={response?.IsInMatching} partnerCount={response?.Partners?.Count ?? 0}");
|
|
switch (buildState)
|
|
{
|
|
case EEventBuildState.Success:
|
|
await OnMatchSuccess(response);
|
|
break;
|
|
case EEventBuildState.Failed:
|
|
OnMatchFailed(response);
|
|
break;
|
|
}
|
|
|
|
if (buildState == EEventBuildState.Failed)
|
|
break;
|
|
|
|
// 等待下次轮询
|
|
await Task.Delay(PollIntervalSeconds * 1000, cancellationToken);
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
Trace($"AutoMatchPollingCancelled eventId={eventId}");
|
|
break;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
LogError($"AutoMatchPollingException eventId={eventId} error={e.Message}");
|
|
await Task.Delay(PollIntervalSeconds * 1000, cancellationToken);
|
|
}
|
|
}
|
|
|
|
_isMatching = false;
|
|
}
|
|
|
|
private async Task OnMatchSuccess(AutoMatchStatusResponse result)
|
|
{
|
|
Trace($"AutoMatchSuccess eventId={_manager.EventId} partnerCount={result?.Partners?.Count ?? 0}");
|
|
await CheckStopAutoMatch();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 处理匹配失败
|
|
/// </summary>
|
|
private void OnMatchFailed(AutoMatchStatusResponse result)
|
|
{
|
|
var message = result?.Message ?? string.Empty;
|
|
ELog($"AutoMatchFailed eventId={_manager.EventId} state={result?.State} reason={message}");
|
|
_manager.NotifyAutoMatchFailed(message);
|
|
_ = StopAutoMatch();
|
|
}
|
|
|
|
|
|
private async Task<bool> CheckStopAutoMatch()
|
|
{
|
|
Trace($"AutoMatchCheckStop eventId={_manager.EventId}");
|
|
if (_manager.ShouldCloseAutoMatch)
|
|
{
|
|
await StopAutoMatch();
|
|
_manager.NotifyAutoMatchStopped();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 释放资源
|
|
/// </summary>
|
|
public void Dispose()
|
|
{
|
|
Trace($"AutoMatchDispose eventId={_manager.EventId}");
|
|
CancelPollMatchResult();
|
|
}
|
|
|
|
#region 日志
|
|
|
|
private static void PollCycleLog(string message)
|
|
{
|
|
if (!EnablePollCycleLogs) return;
|
|
#if UNITY_EDITOR
|
|
Debug.Log($"<color=cyan>[AutoMatchController] {message}</color>");
|
|
#else
|
|
Debug.Log($"[AutoMatchController] {message}");
|
|
#endif
|
|
}
|
|
|
|
private static void ELog(string message)
|
|
{
|
|
#if UNITY_EDITOR
|
|
Debug.Log($"<color=cyan>[AutoMatchController] {message}</color>");
|
|
#endif
|
|
}
|
|
[System.Diagnostics.Conditional("UNITY_EDITOR")]
|
|
private static void Trace(string message)
|
|
{
|
|
if (!EnableTraceLogs) return;
|
|
ELog(message);
|
|
}
|
|
|
|
private static void LogError(string message)
|
|
{
|
|
Debug.LogError($"<color=red>[AutoMatchController] {message}</color>");
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|