/*
* 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);
}
}
}