479 lines
16 KiB
C#
479 lines
16 KiB
C#
/*
|
||
* 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
|
||
{
|
||
/// <summary>
|
||
/// Grid structure for collision detection brushes
|
||
/// 碰撞检测刷子的网格结构
|
||
/// </summary>
|
||
public class BrushGrid
|
||
{
|
||
public List<int> listCCDBrushes = new List<int>();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Brush trace information for collision detection
|
||
/// 用于碰撞检测的画刷跟踪信息
|
||
/// </summary>
|
||
/*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;
|
||
}
|
||
}*/
|
||
|
||
/// <summary>
|
||
/// Collision detection brush interface
|
||
/// 碰撞检测刷子接口
|
||
/// </summary>
|
||
public interface ICCDBrush
|
||
{
|
||
bool Trace(BrushTraceInfo info);
|
||
Bounds GetAABB();
|
||
void Release();
|
||
}
|
||
|
||
/// <summary>
|
||
/// AssureMove class - validates player movement to prevent cheating
|
||
/// AssureMove 类 - 验证玩家移动以防止作弊
|
||
/// </summary>
|
||
public class CECAssureMove
|
||
{
|
||
// List of model files for stepwise loading / 分步加载的模型文件列表
|
||
private List<string>[] m_listFiles = new List<string>[7];
|
||
|
||
// Collision detection brushes / 碰撞检测刷子
|
||
private List<ICCDBrush> m_CDBrushes = new List<ICCDBrush>();
|
||
|
||
// 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<string>();
|
||
}
|
||
|
||
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();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Load map collision data for movement validation
|
||
/// 加载地图碰撞数据用于移动验证
|
||
/// </summary>
|
||
/// <param name="szMap">Map file path / 地图文件路径</param>
|
||
/// <param name="vecMapOrigin">Map origin position / 地图原点位置</param>
|
||
/// <param name="fMapWidth">Map width / 地图宽度</param>
|
||
/// <param name="fMapHeight">Map height / 地图高度</param>
|
||
/// <param name="fGridSize">Grid cell size / 网格单元大小</param>
|
||
/// <returns>Success status / 成功状态</returns>
|
||
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<string> listFiles = new List<string>();
|
||
// 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
|
||
}
|
||
|
||
/// <summary>
|
||
/// Step-wise map loading for progressive loading screens
|
||
/// 分步地图加载,用于渐进式加载屏幕
|
||
/// </summary>
|
||
/// <param name="nStep">Loading step (0-6) / 加载步骤(0-6)</param>
|
||
/// <returns>Success status / 成功状态</returns>
|
||
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
|
||
}
|
||
|
||
/// <summary>
|
||
/// Release all map collision data
|
||
/// 释放所有地图碰撞数据
|
||
/// </summary>
|
||
/// <returns>Success status / 成功状态</returns>
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Validate player movement from start to end position
|
||
/// 验证玩家从起点到终点的移动
|
||
/// </summary>
|
||
/// <param name="vecStart">Start position / 起始位置</param>
|
||
/// <param name="vecEnd">End position / 结束位置</param>
|
||
/// <returns>True if movement is valid / 如果移动有效则返回 true</returns>
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Reset float detection when player is not moving
|
||
/// 当玩家不移动时重置浮空检测
|
||
/// </summary>
|
||
/// <returns>Success status / 成功状态</returns>
|
||
public bool NoAssureMove()
|
||
{
|
||
m_dwFloatStart = 0;
|
||
m_nFloatTicks = 0;
|
||
return true;
|
||
}
|
||
|
||
// Accessors / 访问器
|
||
|
||
/// <summary>
|
||
/// Check if collision detection cheat (wall clipping) was detected
|
||
/// 检查是否检测到碰撞检测作弊(穿墙)
|
||
/// </summary>
|
||
public bool IsCheatCD() { return m_bHasCheatCD; }
|
||
|
||
/// <summary>
|
||
/// Check if fly cheat was detected
|
||
/// 检查是否检测到飞行作弊
|
||
/// </summary>
|
||
public bool IsCheatFly() { return m_bHasCheatFly; }
|
||
|
||
/// <summary>
|
||
/// Get the position where collision cheat was detected
|
||
/// 获取检测到碰撞作弊的位置
|
||
/// </summary>
|
||
public Vector3 GetCheatCDPos() { return m_vecCheatCDPos; }
|
||
|
||
/// <summary>
|
||
/// Get the position where fly cheat was detected
|
||
/// 获取检测到飞行作弊的位置
|
||
/// </summary>
|
||
public Vector3 GetCheatFlyPos() { return m_vecCheatFlyPos; }
|
||
|
||
// Helper methods / 辅助方法
|
||
|
||
/// <summary>
|
||
/// Trace collision with other objects (NPCs, matters, forest)
|
||
/// 与其他对象(NPC、物品、森林)进行碰撞追踪
|
||
/// </summary>
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Get terrain height at specified position
|
||
/// 获取指定位置的地形高度
|
||
/// </summary>
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Get water surface height at specified position
|
||
/// 获取指定位置的水面高度
|
||
/// </summary>
|
||
private float GetWaterHeight(Vector3 pos)
|
||
{
|
||
// TODO: Implement water height query
|
||
// 待实现:水面高度查询
|
||
|
||
// This should query the water system
|
||
// 这应该查询水系统
|
||
|
||
return 0.0f;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Get current time in milliseconds
|
||
/// 获取当前时间(毫秒)
|
||
/// </summary>
|
||
private uint GetMilliSecondNow()
|
||
{
|
||
return (uint)(Time.realtimeSinceStartup * 1000.0f);
|
||
}
|
||
}
|
||
}
|
||
|