/* * FILE: CECAssureMove.cs * * DESCRIPTION: AssureMove for the Element Client - Anti-cheat movement validation system * * CONVERTED FROM: EC_AssureMove.h/EC_AssureMove.cpp * CREATED BY: Hedi, 2007/4/23 * * HISTORY: * * Copyright (c) 2007 Archosaur Studio, All Rights Reserved. */ using BrewMonster.Scripts; using CSNetwork.GPDataType; using System; using System.Collections.Generic; using UnityEngine; namespace BrewMonster { /// /// Grid structure for collision detection brushes /// 碰撞检测刷子的网格结构 /// public class BrushGrid { public List listCCDBrushes = new List(); } /// /// Brush trace information for collision detection /// 用于碰撞检测的画刷跟踪信息 /// /*public class BrushTraceInfo { public Vector3 vStart; public Vector3 vDelta; public Vector3 vExtent; public bool bIsRay; public float fFraction; public Vector3 vHitPos; public Vector3 vNormal; public void Init(Vector3 start, Vector3 delta, Vector3 extent, bool isRay) { vStart = start; vDelta = delta; vExtent = extent; bIsRay = isRay; fFraction = 1.0f; vHitPos = Vector3.zero; vNormal = Vector3.zero; } }*/ /// /// Collision detection brush interface /// 碰撞检测刷子接口 /// public interface ICCDBrush { bool Trace(BrushTraceInfo info); Bounds GetAABB(); void Release(); } /// /// AssureMove class - validates player movement to prevent cheating /// AssureMove 类 - 验证玩家移动以防止作弊 /// public class CECAssureMove { // List of model files for stepwise loading / 分步加载的模型文件列表 private List[] m_listFiles = new List[7]; // Collision detection brushes / 碰撞检测刷子 private List m_CDBrushes = new List(); // Grid structure for spatial partitioning / 空间分区的网格结构 private BrushGrid[] m_pBrushGrids; // Map origin and grid parameters / 地图原点和网格参数 private Vector3 m_vecMapOrigin; private float m_fGridSize; private int m_nGridRows; private int m_nGridCols; // Cheat detection flags / 作弊检测标志 private bool m_bHasCheatCD; // Collision detection cheat (wall clipping) / 碰撞检测作弊(穿墙) private bool m_bHasCheatFly; // Flying cheat / 飞行作弊 private Vector3 m_vecCheatCDPos; // Position where CD cheat detected / 检测到碰撞作弊的位置 private Vector3 m_vecCheatFlyPos; // Position where fly cheat detected / 检测到飞行作弊的位置 // Float detection timing / 浮空检测计时 private uint m_dwFloatStart; private int m_nFloatTicks; // Constants / 常量 private const float FLOAT_DIFF = 1.3f; // Minimum height difference to trigger float check / 触发浮空检查的最小高度差 private const int MAX_FLOAT_ALLOWED = 30000; // Maximum allowed float time in milliseconds / 允许的最大浮空时间(毫秒) public CECAssureMove() { for (int i = 0; i < 7; i++) { m_listFiles[i] = new List(); } m_pBrushGrids = null; m_vecMapOrigin = Vector3.zero; m_fGridSize = 32.0f; m_nGridRows = 0; m_nGridCols = 0; m_bHasCheatCD = false; m_bHasCheatFly = false; m_vecCheatCDPos = Vector3.zero; m_vecCheatFlyPos = Vector3.zero; m_dwFloatStart = 0; m_nFloatTicks = 0; } ~CECAssureMove() { ReleaseMap(); } /// /// Load map collision data for movement validation /// 加载地图碰撞数据用于移动验证 /// /// Map file path / 地图文件路径 /// Map origin position / 地图原点位置 /// Map width / 地图宽度 /// Map height / 地图高度 /// Grid cell size / 网格单元大小 /// Success status / 成功状态 public bool LoadMap(string szMap, Vector3 vecMapOrigin, float fMapWidth, float fMapHeight, float fGridSize = 32.0f) { // NOTE: Currently disabled for performance, returns true immediately // 注意:当前为了性能已禁用,立即返回 true return true; #pragma warning disable CS0162 // Unreachable code detected ReleaseMap(); m_vecMapOrigin = vecMapOrigin; m_fGridSize = fGridSize; m_nGridCols = (int)(fMapWidth / fGridSize) + 1; m_nGridRows = (int)(fMapHeight / fGridSize) + 1; m_pBrushGrids = new BrushGrid[m_nGridRows * m_nGridCols]; for (int i = 0; i < m_pBrushGrids.Length; i++) { m_pBrushGrids[i] = new BrushGrid(); } List listFiles = new List(); // TODO: Implement CECSceneCheck to get ornament list // CECSceneCheck check; // check.GetOrnamentList(szMap, listFiles); // check.Release(); int nStepSize; if (listFiles.Count < 100) nStepSize = listFiles.Count; else nStepSize = listFiles.Count / 7 + 1; for (int i = 0; i < listFiles.Count; i++) { // Check if there's a duplicate file before this index // 检查此索引之前是否有重复文件 bool isDuplicate = false; for (int k = 0; k < i; k++) { if (string.Equals(listFiles[k], listFiles[i], StringComparison.OrdinalIgnoreCase)) { isDuplicate = true; break; } } if (isDuplicate) continue; m_listFiles[i / nStepSize].Add(listFiles[i]); } return true; #pragma warning restore CS0162 } /// /// Step-wise map loading for progressive loading screens /// 分步地图加载,用于渐进式加载屏幕 /// /// Loading step (0-6) / 加载步骤(0-6) /// Success status / 成功状态 public bool StepLoadMap(int nStep) { // NOTE: Currently disabled for performance, returns true immediately // 注意:当前为了性能已禁用,立即返回 true return true; #pragma warning disable CS0162 // Unreachable code detected if (nStep < 0 || nStep >= 7) return false; // TODO: Implement file loading and brush creation // This would involve: // 1. Loading ornament model files // 2. Extracting collision hulls // 3. Creating CCDBrush objects // 4. Distributing brushes into grid cells return true; #pragma warning restore CS0162 } /// /// Release all map collision data /// 释放所有地图碰撞数据 /// /// Success status / 成功状态 public bool ReleaseMap() { for (int i = 0; i < 7; i++) { m_listFiles[i].Clear(); } if (m_pBrushGrids != null) { m_pBrushGrids = null; } foreach (var pCDBrush in m_CDBrushes) { pCDBrush?.Release(); } m_CDBrushes.Clear(); m_nGridCols = 0; m_nGridRows = 0; m_bHasCheatCD = false; m_bHasCheatFly = false; return true; } /// /// Validate player movement from start to end position /// 验证玩家从起点到终点的移动 /// /// Start position / 起始位置 /// End position / 结束位置 /// True if movement is valid / 如果移动有效则返回 true public bool AssureMove(Vector3 vecStart, Vector3 vecEnd) { if (m_pBrushGrids == null) return true; // Calculate grid coordinates for start and end positions // 计算起点和终点的网格坐标 int sx, sy, ex, ey; sx = (int)((vecStart.x - m_vecMapOrigin.x) / m_fGridSize); ex = (int)((vecEnd.x - m_vecMapOrigin.x) / m_fGridSize); sy = (int)((m_vecMapOrigin.z - vecStart.z) / m_fGridSize); ey = (int)((m_vecMapOrigin.z - vecEnd.z) / m_fGridSize); // Sort coordinates / 排序坐标 if (sx > ex) { int t = sx; sx = ex; ex = t; } if (sy > ey) { int t = sy; sy = ey; ey = t; } // Check if out of bounds / 检查是否越界 if (sx < 0 || sx >= m_nGridCols || sy < 0 || sy >= m_nGridRows) return true; // Setup trace for horizontal movement / 设置水平移动的追踪 BrushTraceInfo info = new BrushTraceInfo(); info.Init(EC_Utility.ToA3DVECTOR3(vecStart), EC_Utility.ToA3DVECTOR3(vecEnd - vecStart), new A3DVECTOR3(0), true); // Setup trace for vertical support check / 设置垂直支撑检查的追踪 Vector3 vecCenter = (vecStart + vecEnd) * 0.5f; BrushTraceInfo vertInfo = new BrushTraceInfo(); vertInfo.Init(EC_Utility.ToA3DVECTOR3(vecCenter), new A3DVECTOR3(0.0f, -FLOAT_DIFF, 0.0f), new A3DVECTOR3(0.7f, 0.7f, 0.7f), false); bool bNeedCheckFloat = false; bool bHasSupported = false; // Check if player has ground support / 检查玩家是否有地面支撑 if (!TraceWithOthers(vertInfo) && GetTerrainHeight(vecCenter) < vecCenter.y - FLOAT_DIFF && GetWaterHeight(vecCenter) < vecCenter.y) { bNeedCheckFloat = true; } else { bHasSupported = true; } // Check collision with brushes in affected grid cells // 检查受影响网格单元中与刷子的碰撞 for (int x = sx; x <= ex; x++) { for (int y = sy; y <= ey; y++) { BrushGrid grid = m_pBrushGrids[y * m_nGridCols + x]; for (int i = 0; i < grid.listCCDBrushes.Count; i++) { int brushIndex = grid.listCCDBrushes[i]; // Check for wall clipping / 检查穿墙 if (brushIndex < m_CDBrushes.Count && m_CDBrushes[brushIndex].Trace(info)) { m_bHasCheatCD = true; m_vecCheatCDPos = vecCenter; return false; } // Check for ground support / 检查地面支撑 if (bNeedCheckFloat) { if (brushIndex < m_CDBrushes.Count && m_CDBrushes[brushIndex].Trace(vertInfo)) { bHasSupported = true; } } } } } // Check for fly cheat detection / 检查飞行作弊检测 if (!bHasSupported) { m_nFloatTicks++; if (m_dwFloatStart == 0) { m_dwFloatStart = GetMilliSecondNow(); } else if (GetMilliSecondNow() - m_dwFloatStart > MAX_FLOAT_ALLOWED && m_nFloatTicks > MAX_FLOAT_ALLOWED / 500) { m_bHasCheatFly = true; m_vecCheatFlyPos = vecCenter; } } else { m_dwFloatStart = 0; m_nFloatTicks = 0; } return true; } /// /// Reset float detection when player is not moving /// 当玩家不移动时重置浮空检测 /// /// Success status / 成功状态 public bool NoAssureMove() { m_dwFloatStart = 0; m_nFloatTicks = 0; return true; } // Accessors / 访问器 /// /// Check if collision detection cheat (wall clipping) was detected /// 检查是否检测到碰撞检测作弊(穿墙) /// public bool IsCheatCD() { return m_bHasCheatCD; } /// /// Check if fly cheat was detected /// 检查是否检测到飞行作弊 /// public bool IsCheatFly() { return m_bHasCheatFly; } /// /// Get the position where collision cheat was detected /// 获取检测到碰撞作弊的位置 /// public Vector3 GetCheatCDPos() { return m_vecCheatCDPos; } /// /// Get the position where fly cheat was detected /// 获取检测到飞行作弊的位置 /// public Vector3 GetCheatFlyPos() { return m_vecCheatFlyPos; } // Helper methods / 辅助方法 /// /// Trace collision with other objects (NPCs, matters, forest) /// 与其他对象(NPC、物品、森林)进行碰撞追踪 /// private bool TraceWithOthers(BrushTraceInfo pInfo) { // TODO: Implement when these managers are available // 待实现:当这些管理器可用时 // CECMatterMan* pMatterMan = g_pGame->GetGameRun()->GetWorld()->GetMatterMan(); // if (pMatterMan && pMatterMan->TraceWithBrush(&info)) // return true; // CECNPCMan* pNPCMan = g_pGame->GetGameRun()->GetWorld()->GetNPCMan(); // if (pNPCMan && pNPCMan->TraceWithBrush(&info)) // return true; // CELForest* pForest = g_pGame->GetGameRun()->GetWorld()->GetForest(); // if (pForest && pForest->TraceWithBrush(&info)) // return true; return false; } /// /// Get terrain height at specified position /// 获取指定位置的地形高度 /// private float GetTerrainHeight(Vector3 pos) { // TODO: Implement terrain height query // 待实现:地形高度查询 // This should query Unity's terrain system or custom terrain manager // 这应该查询 Unity 的地形系统或自定义地形管理器 if (Terrain.activeTerrain != null) { return Terrain.activeTerrain.SampleHeight(pos); } return 0.0f; } /// /// Get water surface height at specified position /// 获取指定位置的水面高度 /// private float GetWaterHeight(Vector3 pos) { // TODO: Implement water height query // 待实现:水面高度查询 // This should query the water system // 这应该查询水系统 return 0.0f; } /// /// Get current time in milliseconds /// 获取当前时间(毫秒) /// private uint GetMilliSecondNow() { return (uint)(Time.realtimeSinceStartup * 1000.0f); } } }