Files
ft/Client/LocalPackages/YiDunProtector/Runtime/YiDunManager.cs
2026-06-29 21:18:33 +08:00

456 lines
15 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 System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using AOT;
using NetEase;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NTESHTPSec;
using UnityEngine;
using UnityEngine.Android;
using AntiCheatResult = NetEase.AntiCheatResult;
using RequestCmdID = NetEase.RequestCmdID;
// using AntiCheatResult = NTESHTPSec.AntiCheatResult;
namespace YiDun.Protector
{
public abstract class YiDunManager
{
private static YiDunManager _instance;
private static readonly object Lock = new object();
public static YiDunManager Instance
{
get
{
lock (Lock)
{
if (_instance == null)
{
// 创建具体实现类的实例
_instance = CreateConcreteInstance();
if (_instance != null)
{
Debug.Log($"[YiDunManager] : {_instance.GetType().Name}");
}
else
{
Debug.LogError("[YiDunManager] Failed");
}
}
return _instance;
}
}
}
private static YiDunManager CreateConcreteInstance()
{
// 这里可以根据平台或其他条件返回不同的具体实现
#if UNITY_ANDROID && !UNITY_EDITOR
return new YiDunAndroidManager();
#elif UNITY_IOS && !UNITY_EDITOR
return new YiDunIOSManager();
#else
return new DefaultYiDunManager();
#endif
}
//
private string ProductId { get; set; }
private string BusinessId { get; set; }
private string Token { get; set; }
private string Account { get; set; }
/// <summary>
/// 销毁单例实例(主要用于测试)
/// </summary>
public static void DestroyInstance()
{
lock (Lock)
{
if (_instance != null)
{
_instance.Cleanup();
_instance = null;
Debug.Log("[YiDunManager] 单例实例已销毁");
}
}
}
public void Cleanup()
{
}
// 标记
// public static string PlatformFlag = "";
public abstract string PlatformFlag { get; }
//
private HTProtectConfig _config;
public delegate void OutAction<T>(out T result);
public void Init(string productId, YiDunHtpCallback yiDunHtpCallback)
{
Debug.Log($"Init-> {PlatformFlag} {productId}");
ProductId = productId;
#if UNITY_ANDROID && !UNITY_EDITOR
NetSecProtect.init(productId, yiDunHtpCallback, _config);
#elif (UNITY_IOS || UNITY_IPHONE) && !UNITY_EDITOR
// NTESRiskSecProtect.init(productId, (code,message,content ) =>
// {
// Debug.Log($"init callback -> {productId} {code} {message} {content}");
// // yiDunHtpCallback.onReceive(code,message);
// NTESRiskSecProtect.ioctl(NTESHTPSec.RequestCmdID.Cmd_SetConfigData,message);
// });
NTESRiskSecProtect.setServerType(_config.getServerType());
NTESRiskSecProtect.setChannel(_config.getChannel());
NTESRiskSecProtect.InitCallback initCallback = new NTESRiskSecProtect.InitCallback(InitProductIdCallback);
NTESRiskSecProtect.init(productId, initCallback);
#endif
}
[MonoPInvokeCallback(typeof(NTESRiskSecProtect.InitCallback))]
public static void InitProductIdCallback(int code, string message, string content)
{
Debug.Log($"init callback -> {code} {message} {content}");
// code返回200说明初始化成功
NTESRiskSecProtect.ioctl(NTESHTPSec.RequestCmdID.Cmd_SetConfigData,message);
}
//
public YiDunManager InitConfig(OutAction<HTProtectConfig> act)
{
act?.Invoke(out _config);
#if (UNITY_ANDROID) && !UNITY_EDITOR
Debug.Log($"InitConfig() Android");
#elif (UNITY_IOS || UNITY_IPHONE) && !UNITY_EDITOR
Debug.Log($"InitConfig() IOS");
NTESRiskSecProtect.setChannel(_config.getChannel());
#else
Debug.Log($"InitConfig() Default");
#endif
return this;
}
// 获取超时时间 3000秒
private int timeOut = 3000;
private int _tryTimesForGetToken = 0;
private int MaxTimesForGetToken = 3;
private bool IsTokenGetProcessed = false;
private TaskCompletionSource<bool> _taskCompletionForGetToken;
public async Task<bool> StartGetToken()
{
// Log("StartGetToken-> ");
_tryTimesForGetToken = 0;
_taskCompletionForGetToken = new TaskCompletionSource<bool>();
await TryGetToken();
return await _taskCompletionForGetToken.Task;
}
private async Task TryGetToken()
{
// Log("TryGetToken()-> ");
var task = new TaskCompletionSource<bool>();
GetTokenAsync(timeOut,BusinessId, new YiDunGetTokenCallback( (code, message) =>
{
if (code == AntiCheatResult.OK)
{
Debug.Log($"GetToken Succeed In {_tryTimesForGetToken} times");
Token = message;
FinishGetToken();
}
task.TrySetResult(true);
}));
await task.Task;
if (IsTokenGetProcessed)
{
return;
}
if (_tryTimesForGetToken >= MaxTimesForGetToken)
{
return;
}
await TryNextGetToken();
}
private void FinishGetToken()
{
Log("FinishGetToken ");
IsTokenGetProcessed = true;
var bRet = _taskCompletionForGetToken.TrySetResult(true);
if (!bRet)
{
Log("FinishGetToken-> Failed");
}
}
private async Task TryNextGetToken()
{
_tryTimesForGetToken++;
Log($"TryNextGetToken For {_tryTimesForGetToken} times");
await TryGetToken();
}
//
public int SetRoleInfo(string businessId, string roleId, string roleName, string roleAccount, string roleServer,
int serverId, string gameJson)
{
BusinessId = businessId;
Account = roleAccount;
Log($"SetRoleInfo ->{businessId},{roleId} {roleName} {roleAccount} {roleServer} {serverId} {gameJson}");
#if (UNITY_ANDROID ) && !UNITY_EDITOR
return NetSecProtect.setRoleInfo(businessId, roleId, roleName, roleAccount, roleServer, serverId, gameJson);
#elif (UNITY_IOS || UNITY_IPHONE) && !UNITY_EDITOR
return NTESRiskSecProtect.setRoleInfo(businessId, roleId, roleName, roleAccount, roleServer, serverId, gameJson);
#endif
return 0;
}
//
public void LogOut()
{
#if (UNITY_ANDROID ) && !UNITY_EDITOR
NetSecProtect.logOut();
#elif (UNITY_IOS || UNITY_IPHONE) && !UNITY_EDITOR
NTESRiskSecProtect.logOut();
#endif
Debug.Log("LogOut");
}
//
public void GetTokenAsync(int timeOut, string businessId, YiDunGetTokenCallback callback)
{
#if (UNITY_ANDROID ) && !UNITY_EDITOR
NetSecProtect.getTokenAsync(timeOut, businessId, callback);
#elif (UNITY_IOS || UNITY_IPHONE) && !UNITY_EDITOR
// NTESRiskSecProtect.getTokenAsync(timeOut,businessId, (token, code, codeStr, businessId) =>
NTESRiskSecProtect.getTokenAsync(timeOut,businessId,(result) =>
{
callback.onResult(new AntiCheatResult(result.code,result.codeStr,result.token,businessId) );
});
#else
callback.onResult(new AntiCheatResult(200,"token","simulator_token",businessId));
#endif
Log($"GetTokenAsync-> {timeOut} {businessId}");
}
/**
*
* 拼接组装参与计算的params参数示例
* 不同接口校验参数不同详见目录下的demo文件 https://github.com/yidun/irisk-openapi-demo/blob/main/irisk-openapi-csharp-demo
*/
private static Dictionary<string, string> GetParamsMap(RiskRequest riskRequest)
{
var parameters = new Dictionary<String, String>
{
// { "productId", riskRequest.productId },
{ "secretId", riskRequest.secretId },
{ "businessId", riskRequest.businessId },
{ "timestamp", riskRequest.timestamp },
{ "nonce", riskRequest.nonce },
{ "version", riskRequest.version },
{ "token", riskRequest.token },
{ "account", riskRequest.account },
{ "ip", riskRequest.ip },
{ "sceneData", riskRequest.sceneData }
};
return parameters;
}
// 获取签名
public static string GenSignature(String secretKey, Dictionary<String, String> parameters)
{
parameters = parameters.OrderBy(o => o.Key, StringComparer.Ordinal).ToDictionary(o => o.Key, p => p.Value);
var builder = new StringBuilder();
foreach (var kv in parameters)
{
builder.Append(kv.Key).Append(kv.Value);
}
builder.Append(secretKey);
var tmp = builder.ToString();
MD5 md5 = new MD5CryptoServiceProvider();
var result = md5.ComputeHash(Encoding.UTF8.GetBytes(tmp));
builder.Clear();
foreach (var b in result)
{
builder.Append(b.ToString("x2").ToLower());
}
return builder.ToString();
}
public YiDunManager BindTo(GameObject gameObject)
{
#if (UNITY_ANDROID && !UNITY_EDITOR)
if (!gameObject.GetComponent<NetSecProtect>())
{
gameObject.AddComponent<NetSecProtect>();
}
#elif (UNITY_IOS|| UNITY_IPHONE) && !UNITY_EDITOR
if (!gameObject.GetComponent<NTESRiskSecProtect>())
{
gameObject.AddComponent<NTESRiskSecProtect>();
}
#endif
return this;
}
private string CheckURL = "http://ir-open.dun.163.com/v6/risk/check";
// private string ContentType = "Content-Type:application/json";
private string SecretId = "7992abe1b4c13dddf09b6d5e6614f790";
private string SecretKey = "513123689ad874638be2ab02edd9c826";
public class RiskRequest
{
// public string productId;
public string businessId;
public string secretId;
public string timestamp;
//
public readonly string nonce = Guid.NewGuid().ToString("N");
public readonly string version = "603";
public string signature;
public string token;
public string account;
// public string roleId;
// public string nickname;
// public string phone;
// public string email;
// public long registerTime; // 注册事件,可不填
public readonly string ip = "unknown";
public string sceneData;
}
private const int TIME_DELTA = 60 * 2;
private DateTime _riskTime = DateTime.MinValue;
private bool CheckRiskEnable()
{
var timeSpan = DateTime.UtcNow - _riskTime;
// Log($"CheckRiskEnable() -> {timeSpan.TotalSeconds} > {TIME_DELTA} = {timeSpan.TotalSeconds > TIME_DELTA}");
return timeSpan.TotalSeconds > TIME_DELTA;
}
private async void DoRiskCheck(string sceneData)
{
if (!CheckRiskEnable() )
return ;
_riskTime = DateTime.UtcNow;
Log("DoRiskCheck-> ");
using (var client = new HttpClient())
{
try
{
client.Timeout = TimeSpan.FromSeconds(15);
var riskRequest = new RiskRequest()
{
// productId = ProductId,
businessId = BusinessId,
secretId = SecretId,
timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString(),
token = Token,
account = Account,
sceneData = sceneData
};
// var json = JsonConvert.SerializeObject(riskRequest);
riskRequest.signature = GenSignature(SecretKey, GetParamsMap(riskRequest));
var content = JsonConvert.SerializeObject(riskRequest);
var stringContent = new StringContent(content, Encoding.UTF8, "application/json");
var response = await client.PostAsync(CheckURL, stringContent);
var result = await response.Content.ReadAsStringAsync();
if (result != null)
{
var ret = JObject.Parse(result);
var code = ret.GetValue("code")?.ToObject<int>();
var msg = ret.GetValue("msg")?.ToObject<string>();
if (code == 200)
{
Debug.Log($"SUCCESS: code={code}, msg={msg}");
}
else
{
Debug.Log($"ERROR: code={code}, msg={msg}");
}
}
}
catch (Exception ex)
{
// ignored
Debug.LogError(ex.Message + "\n" + ex.StackTrace);
}
finally
{
Token = string.Empty;
}
}
}
// 定时器定时发送RiskCheck
public async void PostRiskCheck(string sceneData = "{ }")
{
Log("PostRiskCheck()-> ");
if (string.IsNullOrEmpty(Token))
{
Log("token is Invalid - trying Get");
await StartGetToken();
if (string.IsNullOrEmpty(Token))
return;
}
DoRiskCheck(sceneData);
}
private static void Log(string message)
{
Debug.Log($"<color=cyan> YiDunManager => {message} </color>");
}
}
public class YiDunIOSManager : YiDunManager
{
public override string PlatformFlag => "iOS";
}
// 方便测试
public class DefaultYiDunManager : YiDunManager
{
public override string PlatformFlag => "defaut";
}
public class YiDunAndroidManager : YiDunManager
{
public override string PlatformFlag => "Android";
}
}