Files
ft/Client/Assets/Scripts/AntiCheat/AntiCheatManager.cs
2026-06-29 21:18:33 +08:00

296 lines
9.1 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 cfg;
using game;
using GameCore;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
public class BanServerConfig
{
public bool AntiCheatOn { get; set; }
public Dictionary<int, List<int>> AntiCheatParam { get; set; }
public List<int> GetParam(int key)
{
if (AntiCheatParam != null && AntiCheatParam.ContainsKey(key))
{
return AntiCheatParam[key];
}
return null;
}
}
public class AntiCheatRequest
{
public string playerID { get; set; }
public int banType { get; set; }
public string deviceId { get; set; }
public bool gm { get; set; }
}
public class AntiCheatResponse
{
public string playerID { get; set; }
public int banTypeCode { get; set; } // 封禁类型编码如101
public bool isBanned { get; set; }
}
public class AntiCheatManager
{
[Inject]
public IUserService userService { get; set; }
[Inject]
public ICustomServerMgr customServerMgr { get; set; }
bool IsAnti = false;
string DeviceId
{
get
{
#if UNITY_IOS
return UnityEngine.iOS.Device.advertisingIdentifier;
#elif UNITY_ANDROID
return SystemInfo.deviceUniqueIdentifier;
#endif
}
}
#region
// 检测登录/钓鱼行为101检查是否已经被封
// 获取服务器表配置
public async Task CheckLoginPhishingBehavior()
{
if (tbServerConfig == null)
{
try
{
var json = await customServerMgr.GetStringAsync("anti-cheat/GetConfigRequest");
if (!string.IsNullOrEmpty(json) && json != "[]")
{
tbServerConfig = Newtonsoft.Json.JsonConvert.DeserializeObject<BanServerConfig>(json);
}
}
catch
{
Debug.LogWarning("[AntiCheat] Failed to fetch server config.");
}
}
if (IsAnti)
{
return;
}
if (tbServerConfig == null)
{
return;
}
bool AntiCheatOn = tbServerConfig.AntiCheatOn;
if (!AntiCheatOn)
{
return;
}
int buildCount = GetDailyBuildCount();
int vip = GContext.container.Resolve<PlayerData>().vip;
int maxLevel = GContext.container.Resolve<Tables>().TbMapData.DataList[^1].LevelRequired;
int level = GContext.container.Resolve<PlayerData>().lv;
if (level > maxLevel)
{
//建造等级超出已解锁地图的最大建造等级-303
TriggerBanEvent(303);
}
else
{
//0付费,vip等级>=5 -101
float payAmount = GContext.container.Resolve<PlayerShopData>().GetBuyData();
var Param = tbServerConfig.GetParam(101);
if (Param != null && Param.Count == 2
&& payAmount <= Param[0]
&& vip >= Param[1])
{
TriggerBanEvent(101);
}
}
}
// 检测道具获取行为201/202/203
public void CheckItemChangeBehavior(int id, int count)
{
if (tbServerConfig == null)
{
return;
}
bool AntiCheatOn = tbServerConfig.AntiCheatOn;
if (!AntiCheatOn)
{
return;
}
float payAmount = GContext.container.Resolve<PlayerShopData>().GetBuyData();
int createRoleDays = (int)((DateTime.UtcNow.Ticks - userService.CreateTime.Ticks) / TimeSpan.TicksPerDay);
//玩家行为 item_change
if (id == 1001)
{
//付费为0,距离创角小于等于7天单次获取5000及以上鱼钩-201
var Param = tbServerConfig.GetParam(201);
if (Param != null && Param.Count == 3
&& payAmount <= Param[0]
&& createRoleDays <= Param[1]
&& count >= Param[2])
{
TriggerBanEvent(201);
return;
}
//付费为0单次获取15000及以上鱼钩-202
Param = tbServerConfig.GetParam(202);
if (Param != null && Param.Count == 2
&& payAmount <= Param[0]
&& count >= Param[1])
{
TriggerBanEvent(202);
}
}
else if (id == 1005)
{
//付费为0,单次获取5000及以上钻石 - 203
var Param = tbServerConfig.GetParam(203);
if (Param != null && Param.Count == 2
&& payAmount <= Param[0]
&& count >= Param[1])
{
TriggerBanEvent(203);
}
}
}
// 检测建造行为301/302/303/304
public void CheckBuildBehavior(int addLevel)
{
if (tbServerConfig == null)
{
return;
}
bool AntiCheatOn = tbServerConfig.AntiCheatOn;
if (!AntiCheatOn)
{
return;
}
float payAmount = GContext.container.Resolve<PlayerShopData>().GetBuyData();
int createRoleDays = (int)((DateTime.UtcNow.Ticks - userService.CreateTime.Ticks) / TimeSpan.TicksPerDay);
int buildCount = GetDailyBuildCount();
int level = GContext.container.Resolve<PlayerData>().lv;
//付费为0,距离创角<10天建造等级达到10000及以上-302
var Param = tbServerConfig.GetParam(302);
if (Param != null && Param.Count == 3
&& payAmount <= Param[0]
&& createRoleDays <= Param[1]
&& level >= Param[2])
{
TriggerBanEvent(302);
return;
}
//付费为0,单日build_upgrade1000次及以上-301
Param = tbServerConfig.GetParam(301);
if (Param != null && Param.Count == 2
&& payAmount <= Param[0]
&& level - buildCount >= Param[1])
{
TriggerBanEvent(301);
return;
}
//前后两次建造building times差值大于1(第二次减第一次大于1)-304
Param = tbServerConfig.GetParam(304);
if (Param != null && Param.Count == 1
&& addLevel > Param[0])
{
TriggerBanEvent(304);
return;
}
}
int GetDailyBuildCount()
{
string key = $"BuildCount_{userService.UserId}";
string dayBuildData = PlayerPrefs.GetString(key, "");
var currentDays = (DateTime.UtcNow.Date - new DateTime(2026, 1, 1)).TotalDays;
if (!string.IsNullOrEmpty(dayBuildData))
{
var parts = dayBuildData.Split('_');
if (parts.Length == 2)
{
double savedDays;
if (double.TryParse(parts[0], out savedDays))
{
int savedLevel;
if (int.TryParse(parts[1], out savedLevel))
{
if (savedDays == currentDays)
{
//同一天,返回保存的建造次数
return savedLevel;
}
}
}
}
}
int level = GContext.container.Resolve<PlayerData>().lv;
PlayerPrefs.SetString(key, $"{currentDays}_{level}");
//获取单日建造次数逻辑
return level;
}
BanServerConfig tbServerConfig = null;
void TriggerBanEvent(int banType)
{
if (IsAnti || banType == 0)
{
return;
}
OnBan("anti-cheat/SendClientBan", banType);
}
public void CheckBan()
{
if (IsAnti)
{
return;
}
OnBan("anti-cheat/CheckBan", 0);
}
async void OnBan(string url, int banType)
{
IConfig config = GContext.container.Resolve<IConfig>();
AntiCheatRequest evt = new AntiCheatRequest
{
playerID = userService.UserId,
banType = banType,
deviceId = DeviceId,
gm = config != null && (config.Get("DEBUG", "0") == "1" || config.Get("GM", "0") == "1")
};
string json = await customServerMgr.CustomServerPost(url, Newtonsoft.Json.JsonConvert.SerializeObject(evt));
if (IsAnti)
{
return;
}
if (!string.IsNullOrEmpty(json) && json != "[]")
{
AntiCheatResponse response = Newtonsoft.Json.JsonConvert.DeserializeObject<AntiCheatResponse>(json);
Debug.Log($"[AntiCheat] PlayerID: {response.playerID} DeviceId: {DeviceId} banned for reason: {response.banTypeCode}");
#if !UNITY_EDITOR
if (response.banTypeCode > 0)
{
#if AGG
using (var e = GEvent.GameEvent("Anti_cheating"))
{
e.AddContent("type", response.banTypeCode)
.AddContent("deviceId", DeviceId)
.AddContent("is_first_ban", !response.isBanned);
}
#endif
IsAnti = true;
await UIManager.Instance.ShowUI(UITypes.AccountAbnormalityPopupPanel);
}
#endif
}
}
#endregion
}