Files
MinFt/Client/Assets/Scripts/Core/PlayFabMgr.cs
Liubing\LB 3d8d4d18f3 first commit
先修复一下,错误的场景

删除不必要的钓场资产

修复into场景

update:更新meta文件,修复报错

update:修复资源

修复第一章节建造

修复建造第三章

update:删除多余内容

update:更新README.md

update:还原图标

update:更新README

update:更新配置
2026-04-28 02:17:22 +08:00

297 lines
9.2 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 asap.core;
using PlayFab;
using PlayFab.ClientModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;
public class PlayFabMgr : MonoBehaviour
{
const int USER_DATA_UPDATE_INTERVAL = 40;
const int Buffer_Count = 5;
const string Last_Update_Time_Key_Prefix = "LastUpdateTime";
const string Local_Data_Key_prefix = "LocalData";
private string Last_Update_Time_Key;
private string Local_Data_Key;
private LinkedList<Dictionary<string, string>> dataBuffer;
private Dictionary<string, string> swapData;
private Dictionary<string, long> lastUpdateTime;
private Dictionary<string, string> localData;
private CancellationTokenSource tokenSource;
static PlayFabMgr _instance = null;
public static PlayFabMgr Instance
{
get
{
if (_instance == null)
{
GameDebug.LogError("PlayFabMgr Instance doesn't exist yet!");
}
return _instance;
}
}
public Dictionary<string, string> CompareDatas(Dictionary<string, UserDataRecord> remoteDatas, string userId)
{
Last_Update_Time_Key = $"{Last_Update_Time_Key_Prefix}_{userId}";
Local_Data_Key = $"{Local_Data_Key_prefix}_{userId}";
var lastUpdateTimeStr = PlayerPrefs.GetString(Last_Update_Time_Key, string.Empty);
var now = ZZTimeHelper.UtcNow().Ticks;
localData = new Dictionary<string, string>();
lastUpdateTime = new Dictionary<string, long>();
if (string.IsNullOrEmpty(lastUpdateTimeStr))
{
if (remoteDatas != null && remoteDatas.Count > 0)
{
lastUpdateTime = remoteDatas.ToDictionary(x => x.Key, x => x.Value.LastUpdated.Ticks);
localData = remoteDatas.ToDictionary(x => x.Key, x => x.Value.Value);
}
}
else
{
var tempLastUpdateTime = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, long>>(lastUpdateTimeStr);
var localDataStr = PlayerPrefs.GetString(Local_Data_Key);
var tempLocalData = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, string>>(localDataStr);
var allKeys = tempLocalData.Keys.Concat(remoteDatas.Keys).Distinct();
foreach (var key in allKeys)
{
var localValue = tempLocalData.ContainsKey(key) ? tempLocalData[key] : null;
var remoteValue = remoteDatas.ContainsKey(key) ? remoteDatas[key].Value : null;
var localTime = tempLastUpdateTime.ContainsKey(key) ? tempLastUpdateTime[key] : 0;
var remoteTime = remoteDatas.ContainsKey(key) ? remoteDatas[key].LastUpdated.Ticks : 0;
if (localValue == null)
{
localData[key] = remoteValue;
lastUpdateTime[key] = remoteTime;
continue;
}
if (remoteValue == null)
{
UpdateUserDataValue(key, localValue);
lastUpdateTime[key] = now;
localData[key] = localValue;
continue;
}
var timeDelta = localTime - remoteTime;
if (Math.Abs(timeDelta) > TimeSpan.TicksPerSecond * 60)
{
if (localTime > remoteTime)
{
UpdateUserDataValue(key, localValue);
lastUpdateTime[key] = now;
localData[key] = localValue;
}
else
{
lastUpdateTime[key] = remoteTime;
localData[key] = remoteValue;
}
}
else
{
lastUpdateTime[key] = localTime;
localData[key] = localValue;
}
}
}
PlayerPrefs.SetString(Last_Update_Time_Key, LitJson.JsonMapper.ToJson(lastUpdateTime));
PlayerPrefs.SetString(Local_Data_Key, LitJson.JsonMapper.ToJson(localData));
return localData;
}
void Awake()
{
_instance = this;
InitBuffer();
tokenSource = new CancellationTokenSource();
UpdateUserDataValue(tokenSource.Token);
}
void InitBuffer()
{
dataBuffer = new LinkedList<Dictionary<string, string>>();
for (int i = 0; i < Buffer_Count; i++)
{
dataBuffer.AddLast(new Dictionary<string, string>());
}
swapData = new Dictionary<string, string>();
}
void OnApplicationPause(bool is_pause)
{
if (is_pause)
{
tokenSource.Cancel();
tokenSource = null;
SyncData();
}
else
{
tokenSource = new CancellationTokenSource();
UpdateUserDataValue(tokenSource.Token);
}
}
void OnApplicationQuit()
{
tokenSource.Cancel();
tokenSource = null;
SyncData();
}
void OnDestroy()
{
tokenSource?.Cancel();
tokenSource = null;
SyncData();
}
private async void UpdateUserDataValue(CancellationToken token)
{
try
{
while (!token.IsCancellationRequested)
{
SyncData();
await Task.Delay(USER_DATA_UPDATE_INTERVAL * 1000);
}
}
catch (System.Exception) { }
}
public void UpdateUserDataValue(string key, string data, bool remoteStore = true)
{
if (remoteStore)
{
var cbuff = dataBuffer.First;
while (cbuff != null)
{
var datas = cbuff.Value;
if (!datas.ContainsKey(key) && datas.Count >= 10)
{
cbuff = cbuff.Next;
continue;
}
cbuff.Value[key] = data;
break;
}
}
localData[key] = data;
lastUpdateTime[key] = ZZTimeHelper.UtcNow().Ticks;
//Debug.Log($"[PlayFabMgr]UpdateUserDataValue key:{key} data:{data}");
PlayerPrefs.SetString(Last_Update_Time_Key, LitJson.JsonMapper.ToJson(lastUpdateTime));
PlayerPrefs.SetString(Local_Data_Key, LitJson.JsonMapper.ToJson(localData));
}
/// <summary>
/// 没有数据返回 null 一定一定一定判空!!!
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public string GetLocalData(string key)
{
if (localData.ContainsKey(key))
{
return localData[key];
}
else
{
return null;
}
}
private void SyncData()
{
var buf = dataBuffer.First;
if (buf.Value.Count == 0)
return;
var datas = buf.Value;
swapData.Clear();
buf.Value = swapData;
swapData = datas;
dataBuffer.RemoveFirst();
dataBuffer.AddLast(buf);
var request = new UpdateUserDataRequest()
{
Data = swapData,
Permission = UserDataPermission.Public
};
PlayFabClientAPI.UpdateUserData(request, null, UpdateFaild);
#if UNITY_EDITOR
//IConfig config = GContext.container.Resolve<IConfig>();
//if (config != null && config.Get<string>("DBUG", string.Empty) == "1")
//{
try
{
//写入本地文件记录 key 和时间
string persistentPath = Application.persistentDataPath;
// 拼接文件名这里使用txt文件记录数据
string filePath = System.IO.Path.Combine(persistentPath, "syncData.csv");
string currentTime = ZZTimeHelper.UtcNow().ToString("yyyy-MM-dd HH:mm:ss");
string dataLine = $"{currentTime},{string.Join(',', swapData.Keys)}";
// 使用追加模式写入文件,每次写入一行数据
using (System.IO.StreamWriter writer = System.IO.File.AppendText(filePath))
{
writer.WriteLine(dataLine);
}
}
catch (Exception e)
{
Debug.LogError($"记录数据时出错: {e.Message}");
}
//}
#endif
}
private void UpdateFaild(PlayFabError error)
{
GameDebug.LogError("[PlayFabMgr]UpdateUserData Error: {0}", error.ToString());
}
public async Task<bool> SyncDataImmidiate(string key, string data)
{
foreach (var buff in dataBuffer)
{
if (buff.ContainsKey(key))
{
buff.Remove(key);
}
}
var taskSource = new TaskCompletionSource<bool>();
var request = new UpdateUserDataRequest()
{
Data = new Dictionary<string, string>() { { key, data } },
Permission = UserDataPermission.Public
};
PlayFabClientAPI.UpdateUserData(request,
(r) => { taskSource.SetResult(true); },
(e) =>
{
taskSource.SetResult(false);
UnityEngine.Debug.LogError($"[PlayFabMgr]UpdateUserData Error: {e.ToString()}");
}
);
return await taskSource.Task;
}
}