using CommonAI.RTS; using CommonAI.Zone; using CommonAI.Zone.Helper; using CommonAI.Zone.Instance; using CommonLang; using CommonLang.Log; using CommonLang.Vector; using System; using System.Collections.Generic; using System.Linq; using System.Text; using XmdsCommonServer.Message; using XmdsCommonServer.Plugin.Units; namespace XmdsServerNode.CheatingDeath { public class MoveSpeedChecker { private static Logger _log; private static Logger log { get { if (_log == null) _log = LoggerFactory.GetLogger("GapChecker"); return _log; } } private readonly XmdsInstancePlayer mActor; private Vector2 mLastPos = new Vector2(); private long mLastCheckTime = CUtils.CurrentTimeMS; private bool mCheckFlag = false; public MoveSpeedChecker(InstancePlayer player) { this.mActor = player as XmdsInstancePlayer; this.mActor.OnUpdate += MActor_OnUpdate; this.mActor.OnObjectSendingEvent += MActor_OnObjectSendingEvent; this.mActor.OnHandleAction += MActor_OnHandleAction; this.mActor.OnRemoved += MActor_OnRemoved; this.mActor.OnRegionTransport += MActor_OnRegionTransport; this.mLastPos.SetX(mActor.X); this.mLastPos.SetY(mActor.Y); } private void MActor_OnRemoved(InstanceUnit unit) { this.mActor.OnUpdate -= MActor_OnUpdate; this.mActor.OnObjectSendingEvent -= MActor_OnObjectSendingEvent; this.mActor.OnHandleAction -= MActor_OnHandleAction; } private void MActor_OnRegionTransport() { this.mLastPos.SetX(mActor.X); this.mLastPos.SetY(mActor.Y); } private void MActor_OnHandleAction(InstanceUnit unit, ObjectAction act) { if (act is UnitUpdatePosAction) { var sync = act as UnitUpdatePosAction; mCheckFlag = true; } } public void setFrameNotCheckFlag() { mCheckFlag = false; } private void MActor_OnObjectSendingEvent(InstanceZoneObject obj, ref CommonAI.Zone.ObjectEvent evt) { if (evt is UnitForceSyncPosEvent) { this.mLastPos.SetX(mActor.X); this.mLastPos.SetY(mActor.Y); //Console.WriteLine("UnitForceSyncPosEvent : " + mActor.X + ", " + mActor.Y); } } private void MActor_OnUpdate(InstanceUnit unit) { if (!mActor.IsLock) { if (mCheckFlag) { mCheckFlag = false; var curtime = CUtils.CurrentTimeMS; var intervalMS = (int)(curtime - mLastCheckTime); this.mLastCheckTime = curtime; //以每次上传坐标的时间间隔来检测,避免客户端包积压,一次发N个包导致的瞬移// if (CheckCheating(intervalMS)) { mActor.Lock(CheatingDeathConfig.CHEATER_LOCK_TIME_MS); CheatingDeathManager.SendPlayerException(mActor, "speed too faster"); } } } else { mActor.transport(mLastPos.X, mLastPos.Y); } this.mLastPos.SetX(mActor.X); this.mLastPos.SetY(mActor.Y); } //移动偏差累加// private float over_move_distance = 0; //移动错误累加// private float over_move_tick = 0; protected virtual bool CheckCheating(int intervalMS) { if (mActor.CurrentActionStatus == UnitActionStatus.Move) { var expectDistance = MoveHelper.GetDistance(intervalMS, mActor.MoveSpeedSEC); var moveDistance = MathVector.getDistance(mLastPos.X, mLastPos.Y, mActor.X, mActor.Y); var delta = moveDistance - expectDistance; //计算预期移动距离和实际移动距离偏差// over_move_distance += delta; if (over_move_distance < 0) { over_move_distance = 0; } else if (over_move_distance > CheatingDeathConfig.TOTAL_EXCEPTION_MOVE_DISTANCE_LIMIT) { //位移偏差累加到阀值,错误增加1// //PrintSpeed(delta, moveDistance, expectDistance); over_move_distance = 0; over_move_tick++; mActor.transport(mLastPos.X, mLastPos.Y); if (over_move_tick > CheatingDeathConfig.TOTAL_EXCEPTION_COUNT) { //累计N次错误,则判定为作弊// over_move_tick = 0; return true; } } return false; } else { var expectDistance = MoveHelper.GetDistance(intervalMS, mActor.MoveSpeedSEC); over_move_distance -= expectDistance; if (over_move_distance < 0) { over_move_tick = 0; over_move_distance = 0; } return false; } } protected void PrintSpeed(float delta, float moveDistance, float expectDistance) { //Console.WriteLine(string.Format("Check move : total={0} delta={1} move_distance={2} expect_distance={3}", // over_move_distance, // delta, // moveDistance, // expectDistance // )); } } }