374 lines
10 KiB
C#
374 lines
10 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using asap.core;
|
|
using UnityEngine;
|
|
|
|
namespace Activity
|
|
{
|
|
/// <summary>
|
|
/// <see cref="Services.IEventTokenService"/> 入账/扣账成功后由 <see cref="Services.EventTokenService"/> 发布,
|
|
/// 供各活动自行判断是否刷新入口合并红点等(避免订阅者与具体玩法耦合)。
|
|
/// </summary>
|
|
public readonly struct ActivityEventTokenBalanceChanged
|
|
{
|
|
public int EventId { get; }
|
|
|
|
public ActivityEventTokenBalanceChanged(int eventId)
|
|
{
|
|
EventId = eventId;
|
|
}
|
|
}
|
|
}
|
|
|
|
namespace Activity.Services
|
|
{
|
|
/// <summary>
|
|
/// 活动代币服务实现
|
|
/// 负责管理所有活动的代币数据,提供统一的存储接口
|
|
/// </summary>
|
|
public class EventTokenService : IEventTokenService
|
|
{
|
|
#region 常量与字段
|
|
|
|
private const string TransitionDataKey = "TransitionData";
|
|
|
|
private readonly Dictionary<int, int> _tokenData = new Dictionary<int, int>();
|
|
private readonly object _lock = new object();
|
|
private bool _isInitialized = false;
|
|
#endregion
|
|
|
|
#region 初始化
|
|
|
|
/// <summary>
|
|
/// 初始化服务,从 PlayFab 加载代币数据
|
|
/// </summary>
|
|
public void Initialize()
|
|
{
|
|
if (_isInitialized) return;
|
|
|
|
lock (_lock)
|
|
{
|
|
if (_isInitialized) return;
|
|
|
|
try
|
|
{
|
|
// 从 PlayFab 加载数据
|
|
LoadFromPlayFab();
|
|
|
|
_isInitialized = true;
|
|
|
|
#if UNITY_EDITOR
|
|
Debug.Log($"[EventTokenService] Initialized successfully. Token count: {_tokenData.Count}");
|
|
#endif
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.LogError($"[EventTokenService] Initialization failed: {e.Message}\n{e.StackTrace}");
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 从 PlayFab 加载代币数据
|
|
/// </summary>
|
|
private void LoadFromPlayFab()
|
|
{
|
|
try
|
|
{
|
|
var dataStr = PlayFabMgr.Instance?.GetLocalData(TransitionDataKey);
|
|
if (!string.IsNullOrEmpty(dataStr))
|
|
{
|
|
_tokenData.Clear();
|
|
var data = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<int, int>>(dataStr);
|
|
if (data != null)
|
|
{
|
|
foreach (var kvp in data)
|
|
{
|
|
_tokenData[kvp.Key] = kvp.Value;
|
|
}
|
|
}
|
|
}
|
|
#if UNITY_EDITOR
|
|
Debug.Log($"[EventTokenService] Loaded {_tokenData.Count} token entries from PlayFab");
|
|
#endif
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.LogError($"[EventTokenService] Failed to load from PlayFab: {e.Message}");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 保存数据到 PlayFab
|
|
/// </summary>
|
|
private void SaveToPlayFab()
|
|
{
|
|
try
|
|
{
|
|
var json = Newtonsoft.Json.JsonConvert.SerializeObject(_tokenData);
|
|
PlayFabMgr.Instance?.UpdateUserDataValue(TransitionDataKey, json);
|
|
#if UNITY_EDITOR
|
|
Debug.Log($"[EventTokenService] Saved {_tokenData.Count} token entries to PlayFab");
|
|
#endif
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.LogError($"[EventTokenService] Failed to save to PlayFab: {e.Message}");
|
|
throw;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 基础操作
|
|
|
|
public void AddToken(int eventId, int count)
|
|
{
|
|
if (eventId <= 0)
|
|
{
|
|
Debug.LogWarning($"[EventTokenService] Invalid eventId: {eventId}");
|
|
return;
|
|
}
|
|
|
|
if (count == 0)
|
|
return;
|
|
|
|
lock (_lock)
|
|
{
|
|
try
|
|
{
|
|
EnsureInitialized();
|
|
var currentCount = GetTokenCount(eventId);
|
|
_tokenData[eventId] = currentCount + count;
|
|
SaveToPlayFab();
|
|
|
|
#if UNITY_EDITOR
|
|
Debug.Log($"[EventTokenService] Added {count} tokens to event {eventId}, new total: {_tokenData[eventId]}");
|
|
#endif
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.LogError($"[EventTokenService] AddToken failed for event {eventId}: {e.Message}");
|
|
throw;
|
|
}
|
|
}
|
|
|
|
PublishActivityEventTokenBalanceChanged(eventId);
|
|
}
|
|
|
|
public int RemoveToken(int eventId, int count)
|
|
{
|
|
if (eventId <= 0)
|
|
{
|
|
Debug.LogWarning($"[EventTokenService] Invalid eventId: {eventId}");
|
|
return 0;
|
|
}
|
|
|
|
int actualRemoved = 0;
|
|
lock (_lock)
|
|
{
|
|
try
|
|
{
|
|
EnsureInitialized();
|
|
var currentCount = GetTokenCount(eventId);
|
|
actualRemoved = Mathf.Min(count, currentCount);
|
|
var newCount = currentCount - actualRemoved;
|
|
|
|
if (newCount <= 0)
|
|
{
|
|
_tokenData.Remove(eventId);
|
|
}
|
|
else
|
|
{
|
|
_tokenData[eventId] = newCount;
|
|
}
|
|
|
|
SaveToPlayFab();
|
|
|
|
#if UNITY_EDITOR
|
|
Debug.Log($"[EventTokenService] Removed {actualRemoved} tokens from event {eventId}, remaining: {newCount}");
|
|
#endif
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.LogError($"[EventTokenService] RemoveToken failed for event {eventId}: {e.Message}");
|
|
throw;
|
|
}
|
|
}
|
|
|
|
PublishActivityEventTokenBalanceChanged(eventId);
|
|
|
|
return actualRemoved;
|
|
}
|
|
|
|
public int GetTokenCount(int eventId)
|
|
{
|
|
if (eventId <= 0) return 0;
|
|
|
|
lock (_lock)
|
|
{
|
|
try
|
|
{
|
|
EnsureInitialized();
|
|
return _tokenData.GetValueOrDefault(eventId, 0);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.LogError($"[EventTokenService] GetTokenCount failed for event {eventId}: {e.Message}");
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void SetToken(int eventId, int count)
|
|
{
|
|
if (eventId <= 0)
|
|
{
|
|
Debug.LogWarning($"[EventTokenService] Invalid eventId: {eventId}");
|
|
return;
|
|
}
|
|
|
|
lock (_lock)
|
|
{
|
|
try
|
|
{
|
|
EnsureInitialized();
|
|
_tokenData[eventId] = count;
|
|
SaveToPlayFab();
|
|
|
|
#if UNITY_EDITOR
|
|
Debug.Log($"[EventTokenService] Set event {eventId} token count to {count}");
|
|
#endif
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.LogError($"[EventTokenService] SetToken failed for event {eventId}: {e.Message}");
|
|
throw;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void ClearToken(int eventId)
|
|
{
|
|
if (eventId <= 0) return;
|
|
|
|
lock (_lock)
|
|
{
|
|
try
|
|
{
|
|
EnsureInitialized();
|
|
if (_tokenData.Remove(eventId))
|
|
{
|
|
SaveToPlayFab();
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.LogError($"[EventTokenService] ClearToken failed for event {eventId}: {e.Message}");
|
|
throw;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 批量操作
|
|
|
|
public Dictionary<int, int> GetAllTokens()
|
|
{
|
|
lock (_lock)
|
|
{
|
|
EnsureInitialized();
|
|
return new Dictionary<int, int>(_tokenData);
|
|
}
|
|
}
|
|
|
|
public void SetTokens(Dictionary<int, int> tokens)
|
|
{
|
|
if (tokens == null) return;
|
|
|
|
lock (_lock)
|
|
{
|
|
try
|
|
{
|
|
EnsureInitialized();
|
|
_tokenData.Clear();
|
|
foreach (var kvp in tokens)
|
|
{
|
|
if (kvp.Key > 0)
|
|
{
|
|
_tokenData[kvp.Key] = kvp.Value;
|
|
}
|
|
}
|
|
SaveToPlayFab();
|
|
|
|
#if UNITY_EDITOR
|
|
Debug.Log($"[EventTokenService] Set {tokens.Count} token entries");
|
|
#endif
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.LogError($"[EventTokenService] SetTokens failed: {e.Message}");
|
|
throw;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void ClearTokens(IEnumerable<int> eventIds)
|
|
{
|
|
if (eventIds == null) return;
|
|
|
|
lock (_lock)
|
|
{
|
|
try
|
|
{
|
|
EnsureInitialized();
|
|
bool changed = false;
|
|
foreach (var eventId in eventIds)
|
|
{
|
|
if (_tokenData.Remove(eventId))
|
|
{
|
|
changed = true;
|
|
}
|
|
}
|
|
if (changed)
|
|
{
|
|
SaveToPlayFab();
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.LogError($"[EventTokenService] ClearTokens failed: {e.Message}");
|
|
throw;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 私有辅助方法
|
|
|
|
private void EnsureInitialized()
|
|
{
|
|
if (!_isInitialized)
|
|
{
|
|
Initialize();
|
|
}
|
|
}
|
|
|
|
private static void PublishActivityEventTokenBalanceChanged(int eventId)
|
|
{
|
|
try
|
|
{
|
|
GContext.Publish(new Activity.ActivityEventTokenBalanceChanged(eventId));
|
|
}
|
|
catch
|
|
{
|
|
// GContext 未就绪等
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|