2025-05-18 01:04:31 +08:00

790 lines
16 KiB
C#

// ***********************************************************************
// Assembly : Game
// Author : Kimch
// Created : 2020-12-01
// Description :
// Last Modified By :
// Last Modified On :
// ***********************************************************************
// <copyright file= "ArchiveProxy" company="Kunpo"></copyright>
// <summary></summary>
// ***********************************************************************
using CodeStage.AntiCheat.ObscuredTypes;
using F;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace G
{
/// <summary>
/// 存档功能
/// </summary>
public class ArchiveProxy : F.GameProxy
{
[System.Serializable]
public class ArchiveInfo
{
/// <summary>
///
/// </summary>
public string deviceId;
/// <summary>
///
/// </summary>
public int timestamp;
/// <summary>
///
/// </summary>
public string playerName;
/// <summary>
/// 角色等级
/// </summary>
public int playerGrade;
/// <summary>
/// 最大通关数
/// </summary>
public int completedLevel;
/// <summary>
///
/// </summary>
public int combatValue;
/// <summary>
///
/// </summary>
public bool compress = true;
/// <summary>
///
/// </summary>
public bool isGuest;
/// <summary>
///
/// </summary>
public string appVersion;
/// <summary>
///
/// </summary>
public int version;
/// <summary>
///
/// </summary>
public bool isCheat;
public override string ToString()
{
return JsonUtility.ToJson(this);
}
public bool FromString(string text)
{
if (string.IsNullOrEmpty(text))
{
return false;
}
try
{
JsonUtility.FromJsonOverwrite(text, this);
return true;
}
catch
{
return false;
}
}
}
[System.Serializable]
public class UserInfo
{
public bool god_rank;
}
#region Field
/// <summary>
///
/// </summary>
private Archive _archive;
/// <summary>
///
/// </summary>
private ArchiveInfo _archiveInfo;
/// <summary>
///
/// </summary>
private UserInfo _userInfo;
private bool _isLoaded;
#endregion
#region Property
public override int priority => int.MaxValue;
public string autoUploadArchiveMessage
{
get;
private set;
}
/// <summary>
/// 有本地存档
/// </summary>
public bool hasLocal
{
get;
private set;
}
/// <summary>
///
/// </summary>
public bool isCheckCloud
{
get;
private set;
}
public string deviceId
{
get
{
var result = PlayerPrefs.GetString("sx_d_id");
if (string.IsNullOrEmpty(result))
{
result = SystemInfo.deviceUniqueIdentifier;
if (result == null || result.Length < 10)
{
result = "sx_did_" + Launch.Timestamp.ToString();
}
PlayerPrefs.SetString("sx_d_id", result);
PlayerPrefs.Save();
}
return result;
}
}
/// <summary>
///
/// </summary>
public UserInfo userInfo
{
get { return _userInfo; }
}
#endregion
#region API
/// <summary>Gets the int.</summary>
public int GetInt(string key, int defaultValue = 0)
{
return _archive != null ? _archive.GetInt(key, defaultValue) : defaultValue;
}
/// <summary>
/// 加密
/// </summary>
/// <param name="key"></param>
/// <param name="defaultValue"></param>
/// <returns></returns>
public int GetInt(int key, int defaultValue = 0)
{
return _archive != null ? _archive.GetInt(key, defaultValue) : defaultValue;
}
/// <summary>
/// 获取列表
/// </summary>
/// <param name="key"></param>
/// <returns>不会为空</returns>
public List<ObscuredInt> GetIntList(string key)
{
return _archive?.GetIntList(key);
}
/// <summary>
/// 获取列表
/// </summary>
/// <param name="key"></param>
/// <returns>不会为空</returns>
public List<ObscuredInt> GetIntList(int key)
{
return _archive?.GetIntList(key);
}
/// <summary>Sets the int.</summary>
public void SetInt(string key, int value)
{
_archive?.SetInt(key, value);
}
public void SetInt(int key, int value)
{
_archive?.SetInt(key, value);
}
/// <summary>
///
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
public void SetIntList(string key, List<ObscuredInt> value)
{
_archive?.SetIntList(key, value);
}
/// <summary>
///
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
public void SetIntList(int key, List<ObscuredInt> value)
{
_archive?.SetIntList(key, value);
}
/// <summary>
///
/// </summary>
/// <param name="key"></param>
public void RemoveIntList(string key)
{
_archive?.RemoveIntList(key);
}
/// <summary>
///
/// </summary>
/// <param name="key"></param>
public void RemoveIntList(int key)
{
_archive?.RemoveIntList(key);
}
public string GetString(string key, string defaultValue = null)
{
return _archive?.GetString(key, defaultValue);
}
public string GetString(int key, string defaultValue = null)
{
return _archive?.GetString(key, defaultValue);
}
public List<string> GetStringList(string key)
{
return _archive?.GetStringList(key);
}
public List<string> GetStringList(int key)
{
return _archive?.GetStringList(key);
}
public void SetString(string key, string value)
{
_archive?.SetString(key, value);
}
public void SetString(int key, string value)
{
_archive?.SetString(key, value);
}
/// <summary>Sets the int.</summary>
public void SetStringList(string key, List<string> value)
{
_archive?.SetStringList(key, value);
}
public void SetStringList(int key, List<string> value)
{
_archive?.SetStringList(key, value);
}
public void RemoveString(string key)
{
_archive?.RemoveString(key);
}
public void RemoveString(int key)
{
_archive?.RemoveString(key);
}
#endregion
#region Method
/// <summary>
///
/// </summary>
/// <param name="openId"></param>
/// <param name="openToken"></param>
/// <param name="loginType">通过游客方式登录 LOGIN_TYPE_VISITOR = 1, 通过OneSdk方式登录 = 100</param>
/// <param name="loginInvokeMode">// 正常登陆 NormalLogin = 1,// 账号绑定 AccountBind = 2,// 切换账号 SwitchAccount = 3,</param>
public void OnSDKLogin(string openId, string openToken, int loginType, int loginInvokeMode)
{
_archiveInfo = new ArchiveInfo();
if (loginType == 1)
{
_archiveInfo.isGuest = true;
_archive = Archive.Create(deviceId, "");
}
else
{
_archiveInfo.isGuest = false;
_archive = Archive.Create(deviceId, openId);
}
this.hasLocal = _archive.Load();
_isLoaded = true;
}
/// <summary>
/// 服务器登录成功 处理存档逻辑
/// </summary>
public void OnServerLogin(int loginMode)
{
//正常登陆
if (loginMode == 1)
{
Debug.Log("正常登陆 CheckAndDownload");
CheckAndDownload(OnLoginAccount);
}
//帐号绑订
else if (loginMode == 2)
{
Debug.Log("帐号绑订 Upload");
Upload(false, OnBindAccount);
}
//帐号切换
else if (loginMode == 3)
{
Debug.Log("帐号切换 Download");
Download(OnSwitchAccount);
}
}
/// <summary>
///
/// </summary>
/// <param name="error"></param>
/// <param name="message"></param>
private void OnLoginAccount(int error, string message)
{
Debug.Log("正常登陆 CheckAndDownload 回调 " + error);
if (error == ErrorCode.SUCCESS)
{
isCheckCloud = true;
_lastUploadTime = 180f;
}
else
{
UI.MessageBox.ShowMessage("同步存档失败", "确定重新同步存档?", () =>
{
CheckAndDownload(OnLoginAccount);
});
}
}
/// <summary>
/// 绑定帐号
/// </summary>
/// <param name="error"></param>
/// <param name="message"></param>
private void OnBindAccount(int error, string message)
{
if (error != ErrorCode.SUCCESS)
{
UI.MessageBox.ShowMessage("上传存档失败", "确定重新上传存档?", () =>
{
Upload(false, OnBindAccount);
});
}
}
/// <summary>
/// 切换帐号
/// </summary>
/// <param name="error"></param>
/// <param name="message"></param>
private void OnSwitchAccount(int error, string message)
{
if (error != ErrorCode.SUCCESS)
{
UI.MessageBox.ShowMessage("下载存档失败", "确定重新下载存档?", () =>
{
Download(OnSwitchAccount);
});
}
else
{
GameWorld.Instance.ReloadGame();
}
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public string GetUploadText()
{
return _archive.ToBase64Text(true);
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public string GetUploadInfo()
{
_archiveInfo.deviceId = deviceId;
_archiveInfo.playerName = PlayerProxy.Instance.nickName;
_archiveInfo.playerGrade = PlayerProxy.Instance.grade;
_archiveInfo.completedLevel = LevelProxy.Instance.currentCompletedLevel;
_archiveInfo.combatValue = PlayerProxy.Instance.combatValue;
_archiveInfo.timestamp = Launch.Timestamp;
_archiveInfo.appVersion = Application.version;
_archiveInfo.version = Archive.VERSION;
_archiveInfo.compress = true;
_archiveInfo.isCheat = _archive.CheckAnti(Archive.VERSION);
if (_archiveInfo.isCheat)
{
PostNotification(GlobalDefine.EVENT_SHOW_TOAST, "使用第三方工具,可能会导致封号");
}
return _archiveInfo.ToString();
}
/// <summary>
/// for gm
/// </summary>
/// <param name="text"></param>
public void LoadServerText(ArchiveInfo archiveInfo, string text)
{
var netArchive = Archive.Create(deviceId);
netArchive.FromBase64Text(text, archiveInfo.compress);
var old = _archive;
_archive = netArchive;
old.Dispose();
hasLocal = true;
GameWorld.Instance.ReloadGame();
}
/// <summary>
///
/// </summary>
/// <param name="archives"></param>
bool GetServerData(object data, out string archiveInfoData, out string archiveData)
{
archiveInfoData = null;
archiveData = null;
if (data is IList<object> archives && archives.Count > 0)
{
for (int i = 0; i < archives.Count; i++)
{
var archive = archives.GetDictionary(i);
if (archive != null)
{
var name = archive.GetString("name");
if (name == "archive_info")
{
archiveInfoData = archive.GetString("data");
}
else if (name == "archive")
{
archiveData = archive.GetString("data");
}
else if (name == "user_info")
{
_userInfo = JsonUtility.FromJson<UserInfo>(archive.GetString("data"));
}
}
}
return true;
}
return false;
}
/// <summary>
///
/// </summary>
/// <param name="callback"></param>
/// <returns></returns>
public bool CheckOnline(Callback3 callback)
{
return AntiCheatProxy.Instance.CheckCheat((error, message) =>
{
if (error == ErrorCode.SUCCESS)
ServerProxy.Instance.DownloadArchive(new string[] { "archive_info" }, callback);
});
}
/// <summary>
/// 检查并下载
/// </summary>
/// <param name="callback"></param>
/// <returns></returns>
public bool CheckAndDownload(Callback2 callback)
{
if (!hasLocal)
{
Download(callback);
}
else
{
Check(callback);
}
return true;
}
/// <summary>
/// 第一次检查
/// </summary>
/// <param name="callback"></param>
/// <returns></returns>
public bool Check(Callback2 callback)
{
ServerProxy.Instance.DownloadArchive(new string[] { "user_info", "archive_info", "archive" },
(error, msg, data) =>
{
if (error == 0)
{
if (GetServerData(data, out string archiveInfoData, out string archiveData))
{
// 是否是新号
if (_archiveInfo.FromString(archiveInfoData))
{
bool diffDevice = _archiveInfo.deviceId != deviceId;
if (diffDevice)
{
_archive.FromBase64Text(archiveData, _archiveInfo.compress);
}
if (!GlobalUtils.IsSmallVersion(_archiveInfo.appVersion, Application.version))
Upload(diffDevice, callback);
else UploadBackup(diffDevice, archiveInfoData, archiveData, callback);
}
else
{
_archive.FromBase64Text("", _archiveInfo.compress);
Upload(true, callback);
}
}
else
{
callback?.Invoke(0, "");
}
}
else
{
callback?.Invoke(error, msg);
}
});
return true;
}
/// <summary>
/// 下载存档
/// </summary>
/// <param name="callback"></param>
/// <returns></returns>
public void Download(Callback2 callback)
{
//本地没有存档
ServerProxy.Instance.DownloadArchive(new string[] { "archive_info", "archive" },
(error, msg, data) =>
{
if (error == 0)
{
GetServerData(data, out string archiveInfoData, out string archiveData);
if (!string.IsNullOrEmpty(archiveInfoData))
_archiveInfo.FromString(archiveInfoData);
_archive.FromBase64Text(archiveData, _archiveInfo.compress);
hasLocal = true;
GetUploadInfo();
}
callback?.Invoke(error, msg);
});
}
/// <summary>
/// 上传存档
/// </summary>
/// <param name="method"> 1 上传正常 0 只上传信息 </param>
/// <param name="callback"></param>
/// <returns></returns>
public void Upload(bool onlyUploadInfo, Callback2 callback)
{
string uploadInfo = GetUploadInfo();
string uploadText = null;
if (!onlyUploadInfo)
{
uploadText = GetUploadText();
}
ServerProxy.Instance.UploadArchive(uploadInfo, uploadText, null, null,
(error, message) =>
{
if (error == ErrorCode.SUCCESS)
{
message = "上次保存时间:\n" + System.DateTime.Now.ToString();
}
callback?.Invoke(error, message);
});
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public void UploadBackup(bool onlyUploadInfo, string archiveInfo2, string archive2, Callback2 callback)
{
string uploadInfo = GetUploadInfo();
string uploadText = null;
if (!onlyUploadInfo)
{
uploadText = GetUploadText();
}
ServerProxy.Instance.UploadArchive(uploadInfo, uploadText, archiveInfo2, archive2, callback);
}
public void UploadImmediate()
{
_lastUploadTime = 0.1f;
}
/// <summary>
/// 保存
/// </summary>
public void Save()
{
if (AntiCheatProxy.Instance.isCheatMemory)
{
PostNotification(GlobalDefine.EVENT_SHOW_TOAST, "修改内存会导致帐号异常");
Debug.LogError("修改内存会导致帐号异常" + $"uid={UserProxy.AccountID}");
return;
}
if (_archive != null)
_archive.Save();
}
/// <summary>
/// 清除帐号
/// </summary>
public void Delete()
{
if (_archive != null)
_archive.Delete();
_archive = null;
}
float _lastUploadTime = -1f;
void AutoUpload()
{
if (_lastUploadTime > 0f)
{
_lastUploadTime -= Time.deltaTime;
if (_lastUploadTime <= 0f)
{
if (!GlobalVar.IsBattling)
{
if (!AntiCheatProxy.Instance.isCheat)
{
Upload(false, OnAutoUpload);
_lastUploadTime = 100f;
}
else if (AntiCheatProxy.Instance.isCheatTime)
{
autoUploadArchiveMessage = "当前时间异常";
_lastUploadTime = 10f;
}
else if (AntiCheatProxy.Instance.isCheatMemory)
{
autoUploadArchiveMessage = "修改内存会导致帐号异常";
_lastUploadTime = float.MaxValue;
}
}
else
{
_lastUploadTime = 1f;
}
}
}
}
/// <summary>
///
/// </summary>
/// <param name="error"></param>
/// <param name="message"></param>
private void OnAutoUpload(int error, string message)
{
if (error == ErrorCode.SUCCESS)
{
autoUploadArchiveMessage = "上次保存时间:\n" + System.DateTime.Now.ToString();
}
else
{
autoUploadArchiveMessage = "自动同步失败";
}
}
float _lastUpdateTime = -1f;
void AutoSave()
{
_lastUpdateTime += Time.deltaTime;
if (_lastUpdateTime > 5f)
{
_lastUpdateTime = 0f;
if (!GlobalVar.IsBattling)
Save();
return;
}
}
#endregion
#region Unity && Proxy
public static ArchiveProxy Instance;
// Use this for initialization
private void Awake()
{
Instance = this;
KPlatform.ApplicationFocusEvent += this.OnApplicationFocusEvent;
}
private void LateUpdate()
{
AutoSave();
AutoUpload();
}
private void OnApplicationFocusEvent(bool focus)
{
if (!focus)
Save();
}
#endregion
}
}