using System;
using System.Threading;
using System.Threading.Tasks;
using EventPartnerGather;
using EventPartnerGatherRequests;
using UnityEngine;
using EEventBuildState = EventPartnerGatherRequests.EEventBuildState;
namespace UI.PartnerGather
{
///
/// 自动匹配控制器
/// 负责管理自动匹配的生命周期、轮询和状态处理
///
public class AutoMatchController : IDisposable
{
private const bool EnableTraceLogs = false;
/// Set true to log each poll cycle (state / IsInMatching / partner count). English only.
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));
}
///
/// 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.
///
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}");
}
}
///
/// 开启自动匹配
///
public async Task 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);
}
///
/// 停止自动匹配
///
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;
}
///
/// 轮询匹配结果
///
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();
}
///
/// 处理匹配失败
///
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 CheckStopAutoMatch()
{
Trace($"AutoMatchCheckStop eventId={_manager.EventId}");
if (_manager.ShouldCloseAutoMatch)
{
await StopAutoMatch();
_manager.NotifyAutoMatchStopped();
return true;
}
return false;
}
///
/// 释放资源
///
public void Dispose()
{
Trace($"AutoMatchDispose eventId={_manager.EventId}");
CancelPollMatchResult();
}
#region 日志
private static void PollCycleLog(string message)
{
if (!EnablePollCycleLogs) return;
#if UNITY_EDITOR
Debug.Log($"[AutoMatchController] {message}");
#else
Debug.Log($"[AutoMatchController] {message}");
#endif
}
private static void ELog(string message)
{
#if UNITY_EDITOR
Debug.Log($"[AutoMatchController] {message}");
#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($"[AutoMatchController] {message}");
}
#endregion
}
}