Add trace to gather matter and gathering matter

This commit is contained in:
HungDK
2025-12-22 18:06:20 +07:00
parent 1aaec5865d
commit eb8980943c
@@ -5,6 +5,7 @@ using BrewMonster.Scripts;
using CSNetwork.GPDataType;
using System;
using System.Runtime.ConstrainedExecution;
using PerfectWorld.Scripts;
using Unity.VisualScripting;
using UnityEngine;
@@ -132,6 +133,10 @@ namespace BrewMonster
float fMaxCut = m_bMoreClose ? -1.0f : 1.0f;
CECObject pObject = EC_ManMessageMono.Instance.GetObject(m_iObjectId, 0);
if (pObject == null)
{
return false;
}
float fTouchRadius = 0.0f;
if (GPDataTypeHelper.ISPLAYERID(m_iObjectId))
@@ -142,7 +147,13 @@ namespace BrewMonster
}
else
{
CECPlayer pPlayer = pObject.GetComponent<CECHostPlayer>();
// pObject is usually EC_ElsePlayer/CECPlayer, not CECHostPlayer.
// Using GetComponent<CECHostPlayer>() returns null and breaks touch checks.
CECPlayer pPlayer = pObject as CECPlayer;
if (pPlayer == null)
{
return false;
}
fTouchRadius = pPlayer.GetTouchRadius();
}
return m_pHost.CanTouchTarget(vHostPos, vTargetPos, fTouchRadius, iTouchReason, fMaxCut);
@@ -150,13 +161,25 @@ namespace BrewMonster
else if (GPDataTypeHelper.ISNPCID(m_iObjectId))
{
CECNPC pNPC = pObject as CECNPC;
if (pNPC == null)
{
return false;
}
fTouchRadius = pNPC.GetTouchRadius();
return m_pHost.CanTouchTarget(vHostPos, vTargetPos, fTouchRadius, iTouchReason, fMaxCut);
}
else if (GPDataTypeHelper.ISMATTERID(m_iObjectId))
{
//CECMatter pMatter = (pObject) as CECMatter;
//return pMatter.CalcDist(vHostPos, true) < pMatter.GetGatherDist();
CECMatter pMatter = (pObject) as CECMatter;
if (pMatter == null)
{
return false;
}
// For matter, use horizontal distance (ignore Y).
// Unity's touch check uses host position + capsule extent, which would otherwise
// force the player to get much closer than intended.
// C++ behavior expects a stand-off distance (default 3.0).
return pMatter.CalcDist(vHostPos, false) < pMatter.GetGatherDist();
}
break;
}
@@ -207,7 +230,11 @@ namespace BrewMonster
public override A3DVECTOR3 GetTargetPos()
{
return (GetTargetObject() as CECNPC).GetServerPos();
// 使用 Unity transform 的实时位置,而不是服务器缓存位置(可能滞后 / 未及时刷新),
// 否则追踪目的地/触碰判定会偏离导致永远触不到。
// Use live transform position (GetPos) instead of cached server position (GetServerPos),
// otherwise tracing destination and touch checks can be wrong and never trigger.
return (GetTargetObject() as CECNPC).GetPos();
}
public override bool OnTouched()
@@ -231,8 +258,16 @@ namespace BrewMonster
}
else if (m_iReason == CECHPWorkTrace.Trace_reason.TRACE_ATTACK)
{
if (m_iObjectId == m_pHost.m_idSelTarget &&
m_pHost.AttackableJudge(m_iObjectId, m_bForceAttack) == 1)
// 服务器的选中目标同步可能比追踪触碰晚到,导致这里永远不触发攻击。
// 为了保证追踪到目标后能正常攻击,这里在必要时主动选中目标。
// Server select-target ack can arrive later than the trace touch moment, which would
// make this block forever. Ensure we select the traced target before attacking.
if (m_iObjectId != m_pHost.m_idSelTarget)
{
UnityGameSession.c2s_CmdSelectTarget(m_iObjectId);
m_pHost.m_idSelTarget = m_iObjectId;
}
if (m_pHost.AttackableJudge(m_iObjectId, m_bForceAttack) == 1)
{
byte byPVPMask = EC_Utility.glb_BuildPVPMask(m_bForceAttack);
UnityGameSession.c2s_CmdNormalAttack(byPVPMask);
@@ -317,7 +352,9 @@ namespace BrewMonster
}
else
{
return (pObject as EC_ElsePlayer).GetServerPos();
// 同上:用实时位置避免 server pos 滞后导致追踪/触碰失败。
// Same rationale: use live position to avoid stale server pos breaking trace/touch.
return (pObject as EC_ElsePlayer).GetPos();
}
}
@@ -342,8 +379,14 @@ namespace BrewMonster
}
if (m_iReason == CECHPWorkTrace.Trace_reason.TRACE_ATTACK)
{
if (m_iObjectId == m_pHost.m_idSelTarget &&
m_pHost.AttackableJudge(m_iObjectId, m_bForceAttack) == 1)
// 同 NPC:追踪触碰可能早于服务器选中目标同步,需主动选中以避免攻击不触发。
// Same as NPC: trace touch can happen before server selection ack; proactively select.
if (m_iObjectId != m_pHost.m_idSelTarget)
{
UnityGameSession.c2s_CmdSelectTarget(m_iObjectId);
m_pHost.m_idSelTarget = m_iObjectId;
}
if (m_pHost.AttackableJudge(m_iObjectId, m_bForceAttack) == 1)
{
byte byPVPMask = EC_Utility.glb_BuildPVPMask(m_bForceAttack);
UnityGameSession.c2s_CmdNormalAttack(byPVPMask);
@@ -431,70 +474,73 @@ namespace BrewMonster
public override bool OnTouched()
{
bool bActionDone = false;
//if (GPDataTypeHelper.ISMATTERID(m_iObjectId))
//{
// if (m_pHost.GetProfession() == PROF_GHOST && m_pHost.IsInvisible())
// {
// g_pGame.GetGameRun().AddFixedMessage(FIXMSG_CANNOT_USE_WHEN_INVISIBLE);
// return bActionDone;
// }
// CECMatter* pMatter = (CECMatter*)GetTargetObject();
if (GPDataTypeHelper.ISMATTERID(m_iObjectId))
{
// if (m_pHost.GetProfession() == BrewMonster.RoleTypes.PROF_GHOST && m_pHost.IsInvisible())
// {
// EC_Game.GetGameRun().AddFixedMessage(FIXMSG_CANNOT_USE_WHEN_INVISIBLE);
// return bActionDone;
// }
CECMatter pMatter = (CECMatter)GetTargetObject();
// if (m_iReason == CECHPWorkTrace::TRACE_PICKUP)
// {
// // Check whether we have enougth place to hold this item or money
// a_LogOutput(1, "[NormalATK]- CECTracedMatter- OnTouched- TRACE_PICKUP");
// if (m_pHost.CanTakeItem(pMatter.GetTemplateID(), 1))
// {
// // Send pickup asking and wait response command
// g_pGame.GetGameSession().c2s_CmdPickup(m_iObjectId, pMatter.GetTemplateID());
// bActionDone = true;
// }
// else
// {
// // Print a notify message
// g_pGame.GetGameRun().AddFixedMessage(FIXMSG_PACKISFULL);
// }
// }
// else
// { // m_iReason == TRACE_GATHER
// int tidMatter = pMatter.GetTemplateID();
// a_LogOutput(1, "[NormalATK]- CECTracedMatter- OnTouched- TRACE_GATHER");
// // Check mine level requirement
// if (m_pHost.GetBasicProps().iLevel < pMatter.GetLevelReq())
// {
// g_pGame.GetGameRun().AddFixedMessage(FIXMSG_LEVELTOOLOW);
// return bActionDone;
// }
if (m_iReason == CECHPWorkTrace.Trace_reason.TRACE_PICKUP)
{
// Check whether we have enougth place to hold this item or money
if (m_pHost.CanTakeItem(pMatter.GetTemplateID(), 1))
{
// Send pickup asking and wait response command
UnityGameSession.RequestPickupItem(m_iObjectId, pMatter.GetTemplateID());
bActionDone = true;
}
else
{
// Print a notify message
//g_pGame.GetGameRun().AddFixedMessage(FIXMSG_PACKISFULL);
Debug.Log("Khong du cho trong de nhat item");
}
}
else if (m_iReason == CECHPWorkTrace.Trace_reason.TRACE_GATHER)
{ // m_iReason == TRACE_GATHER
int tidMatter = pMatter.GetTemplateID();
// Check mine level requirement
if (m_pHost.GetBasicProps().iLevel < pMatter.GetLevelReq())
{
//g_pGame.GetGameRun().AddFixedMessage(FIXMSG_LEVELTOOLOW);
Debug.Log("Cap do cua ban khong du de khai thac tai nguyen nay");
return bActionDone;
}
// // Check whether we have a mine tool
// int iPack, iIndex, idTool;
// if (m_pHost.FindMineTool(tidMatter, &iPack, &iIndex, &idTool))
// {
// DATA_TYPE DataType;
// const MINE_ESSENCE* pData = (const MINE_ESSENCE*)g_pGame.GetElementDataMan().get_data_ptr(pMatter.GetTemplateID(), ID_SPACE_ESSENCE, DataType);
// if (DataType != DT_MINE_ESSENCE)
// {
// ASSERT(DataType == DT_MINE_ESSENCE);
// return bActionDone;
// }
// Check whether we have a mine tool
int iPack = 0;
int iIndex = 0;
int idTool = 0;
if (m_pHost.FindMineTool(tidMatter, ref iPack, ref iIndex, ref idTool))
{
DATA_TYPE DataType = DATA_TYPE.DT_INVALID;
MINE_ESSENCE pData = (MINE_ESSENCE)ElementDataManProvider.GetElementDataMan().get_data_ptr((uint)pMatter.GetTemplateID(), ID_SPACE.ID_SPACE_ESSENCE, ref DataType);
if (DataType != DATA_TYPE.DT_MINE_ESSENCE)
{
//ASSERT(DataType == DT_MINE_ESSENCE);
return bActionDone;
}
// if (m_pHost.GetCoolTime(GP_CT_PLAYER_GATHER))
// {
// g_pGame.GetGameRun().AddFixedMessage(FIXMSG_CMD_INCOOLTIME);
// }
// else
// {
// // Send gather asking and wait response command
// g_pGame.GetGameSession().c2s_CmdGatherMaterial(m_iObjectId, iPack, iIndex, idTool, pData.task_in);
// }
// }
// else
// {
// g_pGame.GetGameRun().AddFixedMessage(FIXMSG_NEEDTOOL);
// }
// }
//}
// if (m_pHost.GetCoolTime(GP_CT_PLAYER_GATHER))
// {
// g_pGame.GetGameRun().AddFixedMessage(FIXMSG_CMD_INCOOLTIME);
// }
else
{
// Send gather asking and wait response command
UnityGameSession.c2s_CmdGatherMaterial(m_iObjectId, iPack, iIndex, idTool, (int)pData.task_in);
bActionDone = true;
}
}
else
{
//g_pGame.GetGameRun().AddFixedMessage(FIXMSG_NEEDTOOL);
}
}
}
return bActionDone;
}
@@ -531,6 +577,10 @@ namespace BrewMonster
public void SetTraceTarget(CECTracedObject pTraceObj, bool bUseAutoPF = false)
{
ResetUseAutoPF(bUseAutoPF);
if (pTraceObj == null)
{
return; // Invalid trace object / Invalid trace object
}
if (!pTraceObj.GetTargetObject() || pTraceObj.GetObjectID() == m_pHost.GetCharacterID())
{
// This is special case
@@ -568,10 +618,10 @@ namespace BrewMonster
{
return new CECTracedNPC(TraceObjectType.TRACE_NPC, iTraceObjId, m_pHost, iReason, bForceAttack);
}
//else if (GPDataTypeHelper.ISMATTERID(iTraceObjId))
//{
// return new CECTracedMatter(TraceObjectType.TRACE_MATTER, iTraceObjId, m_pHost, iReason);
//}
else if (GPDataTypeHelper.ISMATTERID(iTraceObjId))
{
return new CECTracedMatter(TraceObjectType.TRACE_MATTER, iTraceObjId, m_pHost, iReason);
}
return null;
}
@@ -596,17 +646,20 @@ namespace BrewMonster
return true;
}
if (m_bCheckTouch)
// 重要:不要用 m_bCheckTouch 在这里抑制 Touch 检测。
// 之前的移植里 m_bCheckTouch 会在 GroundMove 后被置为 false,导致下一帧永远不进入 OnTouchTarget。
// Important: do not suppress touch checks with m_bCheckTouch here.
// In this port, m_bCheckTouch can be forced false after GroundMove, making OnTouchTarget never fire.
if (IsGoodTimeToTouch())
{
if (IsGoodTimeToTouch())
// 注意:这里不能加 vExtent.y(胶囊半高),否则会把主角位置抬高导致 3D 距离变大,
// 进而 CanTouchTarget 永远不满足(OnTouchTarget 永远不会触发)。
// Note: Do NOT add vExtent.y (capsule half-height) here; touch uses 3D distance and this
// artificially increases the distance, preventing OnTouchTarget() from ever triggering.
if (m_pTraceObject.CanTouchFrom(m_pHost.GetPos()))
{
//OnTouchTarget();
//return true;
if (m_pTraceObject.CanTouchFrom(m_pHost.GetPos() + new A3DVECTOR3(0f, m_pHost.m_CDRInfo.vExtent.y, 0f)))
{
OnTouchTarget();
return true;
}
OnTouchTarget();
return true;
}
}
m_bCheckTouch = true;
@@ -797,7 +850,7 @@ namespace BrewMonster
// Operations
// On first tick
protected virtual void OnFirstTick()
protected override void OnFirstTick()
{
m_pHost.m_iMoveMode = (int)MoveMode.MOVE_MOVE;
m_bHaveMoved = false;
@@ -851,7 +904,7 @@ namespace BrewMonster
else if (!m_pHost.m_GndInfo.bOnGround)
iMoveMode = (int)GPMoveMode.GP_MOVE_FALL;
RaycastHit lastGroundHit;
//RaycastHit lastGroundHit;
//m_pHost.m_GndInfo.bOnGround = m_pHost.GroundCheck(out lastGroundHit);
if (m_pHost.m_GndInfo.bOnGround)
{
@@ -886,10 +939,9 @@ namespace BrewMonster
// CECIntelligentRoute::Instance().OnPlayerPosChange(vCurPos);
//}
if (cdr.vTPNormal.IsZero())
{
m_bCheckTouch = false;
}
// 不要在这里关闭 touch 检测:Tick() 的 touch 检测发生在移动之前,
// 如果这里把 m_bCheckTouch 置 false,会导致下一帧永远跳过触发逻辑。
// Do not disable touch checking here; touch checking happens before movement in Tick().
//if (!m_vCurDirH.IsZero())
//{
@@ -972,6 +1024,33 @@ namespace BrewMonster
}
public A3DVECTOR3 GetCurMovingDest()
{
// 对于采集/拾取物体:保持一定距离,避免角色模型顶住碰撞体抖动
// For gather/pickup matters: keep a stand-off distance to avoid jittering against colliders.
if (m_pTraceObject != null && m_pTraceObject.GetTraceType() == TraceObjectType.TRACE_MATTER)
{
CECMatter matter = m_pTraceObject.GetTargetObject() as CECMatter;
if (matter != null)
{
float keepDist = matter.GetGatherDist();
if (keepDist > 0.01f)
{
A3DVECTOR3 hostPos = m_pHost.GetPos();
A3DVECTOR3 targetPos = matter.GetPos();
A3DVECTOR3 deltaH = targetPos - hostPos;
deltaH.y = 0.0f;
float distH = deltaH.MagnitudeH();
if (distH > keepDist + 0.05f && distH > 1e-4f)
{
deltaH.Normalize();
A3DVECTOR3 dest = targetPos - deltaH * keepDist;
// keep Y stable; GroundMove will resolve final Y anyway
dest.y = hostPos.y;
return dest;
}
}
}
}
return m_pTraceObject.GetTargetPos();
}
public void UpdateUseAutoPF()