Files
test/Assets/PerfectWorld/Scripts/Utility/CECAssureMove.cs
T
2025-12-04 17:26:42 +07:00

479 lines
16 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.
/*
* 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);
}
}
}