Merge remote-tracking branch 'origin/develop' into feature/update-logout-logic

This commit is contained in:
MinhHai
2026-03-06 17:33:37 +07:00
5457 changed files with 1396585 additions and 184588 deletions
+100
View File
@@ -0,0 +1,100 @@
using BrewMonster.Network;
using CSNetwork;
using CSNetwork.GPDataType;
using BrewMonster.Scripts;
using UnityEngine;
using System.Threading.Tasks;
using Cysharp.Threading.Tasks;
namespace BrewMonster
{
public partial class CECHostPlayer
{
public void OnMsgPlayerChgShape(ECMSG Msg)
{
cmd_player_chgshape pCmd = GPDataTypeHelper.FromBytes<cmd_player_chgshape>((byte[])Msg.dwParam1);
//ASSERT(pCmd && pCmd->idPlayer == m_PlayerInfo.cid);
TransformShape(pCmd.shape);
}
public async Task TransformShape(byte iShape, bool bLoadAtOnce = false/* =false */)
{
SetShape(iShape);
//a_LogOutput(1, "CECPlayer::TransformShape(iShape=%d)(iShapeType=%d,iShapeID=%d)", iShape, PLAYERMODEL_GETTYPE(iShape), PLAYERMODEL_GETID(iShape));
if (!GetMajorModel()) return;
if (IsShapeChanged())
{
// change to a dummy model, may cause an asynchronous loading
await QueueLoadDummyModel(m_iShape, bLoadAtOnce);
}
else
{
// back to major model is a synchronous operation
ApplyShapeModelChange(GetMajorModel());
}
}
void SetShape(byte iShape)
{
// The shape id from the server is a 8-bit number
// The meaning of each bit:
// | 7 6 | 5 4 3 2 1 0 |
// |-TYPE-|-----Model ID-----|
int iNewShape = (iShape & 0xff); // only accept 8bit
// ԾɵShapeݽ
FixOldShapeInfo(ref iNewShape);
// ְҵModel IDҪת
if( PLAYERMODEL_GETTYPE(iNewShape) == (int)PLAYERMODEL_TYPE.PLAYERMODEL_PROFESSION )
{
int iRealID = _GetProfessionTransformModelID(
m_iProfession, m_iGender, PLAYERMODEL_GETID(iNewShape));
iNewShape = 0x40 | iRealID;
}
// ְҵModel IDΪEC_Resource.hֵʲ
else
{
}
// store the original data into 8~15 bit
m_iShape = iNewShape | ((iShape & 0xff) << 8);
}
void FixOldShapeInfo(ref int iShape)
{
// ǸʱshapeΪ0ûб0ְҵ
if(iShape != 0 && PLAYERMODEL_GETTYPE(iShape) == 0)
iShape |= 0x40;
}
/// <summary>Origin: notify server of force-attack (PVP) state so it accepts/rejects attacks on players. Call when duel starts (true) or ends (false).</summary>
private void NotifyServerForceAttack(bool bForceAttack)
{
byte refuseBless = EC_Utility.glb_BuildRefuseBLSMask();
UnityGameSession.c2s_SendCmdNotifyForceAttack(glb_BuildPVPMask(bForceAttack), refuseBless);
}
public int _GetProfessionTransformModelID(int nChar, int nGender, int nModelID)
{
int result = 0;
switch (nChar){
case (int)PROFESSION.PROF_HAG: //
result = (2 == nModelID) ? (int)ModelResourceType.RES_MOD_ORC_FOX2 : (int)ModelResourceType.RES_MOD_ORC_FOX;
break;
case (int)PROFESSION.PROF_ORC: //
result = (2 == nModelID) ? (int)ModelResourceType.RES_MOD_ORC_PANDER : (int)ModelResourceType.RES_MOD_ORC_TIGER;
break;
case (int)PROFESSION.PROF_MONK: // ʦ
case (int)PROFESSION.PROF_GHOST: // ̿
result = ((int)Gender.GENDER_MALE == nGender) ? (int)ModelResourceType.RES_MOD_SHADOW_FISH_M : (int)ModelResourceType.RES_MOD_SHADOW_FISH_F;
break;
case (int)PROFESSION.PROF_YEYING: // ҹӰ
result = ((int)Gender.GENDER_MALE == nGender) ? (int)ModelResourceType.RES_MOD_YEYING_RESHAPE_M : (int)ModelResourceType.RES_MOD_YEYING_RESHAPE_F;
break;
case (int)PROFESSION.PROF_YUEXIAN: //
result = ((int)Gender.GENDER_MALE == nGender) ? (int)ModelResourceType.RES_MOD_YUEXIAN_RESHAPE_M : (int)ModelResourceType.RES_MOD_YUEXIAN_RESHAPE_F;
break;
}
return result;
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 0a1a767c85a0348eaa6c6bf78e8798e0
+20
View File
@@ -61,6 +61,26 @@ namespace BrewMonster
var (header, members) = GPDataTypeHelper.ParseTeamMemberData(data);
if (m_pTeam == null || header.idLeader != m_pTeam.GetLeaderID()) return;
m_pTeam.UpdateTeamData(header, members);
var pPlayerMan = EC_ManMessageMono.Instance?.GetECManPlayer;
if (pPlayerMan != null)
{
for (int i = 0; i < m_pTeam.GetMemberNum(); i++)
{
var pMember = m_pTeam.GetMemberByIndex(i);
if (pMember == null || pMember.IsInfoReady())
{
continue;
}
var pPlayer = pPlayerMan.GetPlayer(pMember.GetCharacterID(), 0) as CECPlayer;
if (pPlayer != null)
{
pMember.SetProfession(pPlayer.GetProfession());
pMember.SetGender(pPlayer.GetGender());
pMember.SetInfoReadyFlag(true);
}
}
}
NotifyUIUpdateTeam();
}
catch { }
+38 -20
View File
@@ -528,6 +528,7 @@ namespace BrewMonster
if (pSkill.GetType() == (int)skill_type.TYPE_BLESS ||
pSkill.GetType() == (int)skill_type.TYPE_NEUTRALBLESS)
{
BMLogger.LogError($"ApplySkillShortcut: Skill {pSkill.GetSkillID()} is a bless skill, applying bless skill target rules");
if (iTargetType == 0 || !GPDataTypeHelper.ISPLAYERID(idSelTarget))
idCastTarget = m_PlayerInfo.cid;
@@ -545,8 +546,7 @@ namespace BrewMonster
idCastTarget = m_PlayerInfo.cid;
else
{
EC_ElsePlayer pPlayer =
(EC_ElsePlayer)EC_ManMessageMono.Instance.GetECManPlayer.GetPlayer(idCastTarget);
EC_ElsePlayer pPlayer = (EC_ElsePlayer)EC_ManMessageMono.Instance.GetECManPlayer.GetPlayer(idCastTarget);
if (pPlayer == null)
{
// Ä¿±êÏûʧ
@@ -593,25 +593,43 @@ namespace BrewMonster
}
}
}
/* else if (pSkill.GetType() == CECSkill::TYPE_BLESSPET)
{
CECPet* pPet = g_pGame.GetGameRun().GetWorld().GetNPCMan().GetPetByID(idSelTarget);
if (!pPet || pPet.GetMasterID() == GetCharacterID())
{
// Spell skill on host's pet
CECPetData* pPetData = m_pPetCorral.GetActivePet();
if (!pPetData ||
pPetData.GetClass() != GP_PET_CLASS_COMBAT &&
pPetData.GetClass() != GP_PET_CLASS_SUMMON &&
pPetData.GetClass() != GP_PET_CLASS_EVOLUTION)
return false;
/*else if (pSkill.GetType() == (int)skill_type.TYPE_BLESSPET)
{
// Get pet by target ID
// Note: In C++, this uses GetNPCMan()->GetPetByID()
// For C#, we try to get the object and check if it's the host's active pet
CECObject pPetObject = null;
int activePetNPCID = m_pPetCorral.GetActivePetNPCID();
if (idSelTarget != 0)
{
pPetObject = CECWorld.Instance.GetObject(idSelTarget, 0);
}
// If no pet found or target is host's active pet, cast on host's active pet
if (pPetObject == null || idSelTarget == activePetNPCID)
{
// Spell skill on host's pet
CECPetData pPetData = m_pPetCorral.GetActivePet();
if (pPetData == null ||
(pPetData.GetClass() != (int)GP_PET_TYPE.GP_PET_CLASS_COMBAT &&
pPetData.GetClass() != (int)GP_PET_TYPE.GP_PET_CLASS_SUMMON &&
pPetData.GetClass() != (int)GP_PET_TYPE.GP_PET_CLASS_EVOLUTION))
return false;
idCastTarget = m_pPetCorral.GetActivePetNPCID();
}
// Only fighting pet can be blessed.
if (pPet && !pPet.CanBeAttacked())
return false;
}*/
idCastTarget = activePetNPCID;
}
// Only fighting pet can be blessed
// Check if pet can be attacked (is in combat state)
// Note: CanBeAttacked() check is commented out as it may not be implemented yet
// Server will validate this
if (pPetObject != null)
{
// TODO: Implement CanBeAttacked check when CECPet/CECNPC has this method
// C++ code: if (pPet && !pPet->CanBeAttacked()) return false;
// For now, we'll allow the cast - server will validate
}
}*/
else
{
if (iTargetType != 0 && idCastTarget == 0)
+226 -188
View File
@@ -23,7 +23,9 @@ using System.Runtime.InteropServices;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using static BrewMonster.CECPlayer;
using cmd_select_target = CSNetwork.GPDataType.cmd_select_target;
using cmd_player_chgshape = CSNetwork.GPDataType.cmd_player_chgshape;
using Host_work_ID = BrewMonster.Scripts.CECHPWork.Host_work_ID;
using ObjectCoords = System.Collections.Generic.List<CSNetwork.GPDataType.OBJECT_COORD>;
using Trace_reason = BrewMonster.CECHPWorkTrace.Trace_reason;
@@ -104,6 +106,8 @@ namespace BrewMonster
private int MAX_JUMP_COUNT = 2;
bool m_bUsingTrashBox = false; // Whether being using trash box
private float m_fPrayDistancePlus;
private bool m_bInRebuildPet = false; // Whether rebuilding pet / 是否正在重建宠物
private uint m_dwGMFlags = 0; // GM flags / GM标志
private A3DVECTOR3 g_vOrigin = new A3DVECTOR3(0f);
private float EC_SLOPE_Y = 0.5f;
@@ -532,7 +536,7 @@ namespace BrewMonster
public void ProcessMessage(in ECMSG Msg)
{
var msg = (int)Msg.dwMsg;
//Debug.LogError("HoangDev : ProcessMessageProcessMessageProcessMessage " + msg);
//Debug.LogError("HoangDev : ProcessMessageProcessMessageProcessMessage " + msg);
switch (msg)
{
case EC_MsgDef.MSG_HST_CORRECTPOS: OnMsgHstCorrectPos(Msg); break;
@@ -605,7 +609,12 @@ namespace BrewMonster
case EC_MsgDef.MSG_HST_TEAMINVITE: OnMsgHstTeamInvite(Msg); break;
case EC_MsgDef.MSG_HST_TEAMMEMBERDATA: OnMsgHstTeamMemberData(Msg); break;
case EC_MsgDef.MSG_PM_DUELOPT: OnMsgHstDuelOpt(Msg); break;
case EC_MsgDef.MSG_HST_CLEARTESSERA: OnMsgHstClearTessera(Msg); break;
case EC_MsgDef.MSG_PM_PLAYERCHGSHAPE :
OnMsgPlayerChgShape(Msg); break;
default:
// Uncomment to debug unhandled messages
// Debug.LogWarning($"[CECHostPlayer] ProcessMessage: Unhandled message {msg}");
break;
}
/*if (bActionStartSkill)
@@ -629,13 +638,22 @@ namespace BrewMonster
}
private void NotifyUIUpdateTeam()
{
try
//try
//{
// var ui = EC_Game.GetGameRun()?.GetUIManager()?.GetInGameUIMan();
// if (ui is CECGameUIMan gui)
// gui.UpdateTeam(false);
//}
//catch { }
var uiMan = CECUIManager.Instance?.GetInGameUIMan();
if (uiMan == null)
return;
var dlgTeamMain = uiMan.GetDialog("Win_TeamMain") as DlgTeamMain;
if (dlgTeamMain != null)
{
var ui = EC_Game.GetGameRun()?.GetUIManager()?.GetInGameUIMan();
if (ui is CECGameUIMan gui)
gui.UpdateTeam(false);
dlgTeamMain.UpdateTeamInfo();
}
catch { }
}
/// <summary>Update host duel state from S2C duel commands (MSG_PM_DUELOPT).</summary>
@@ -654,7 +672,7 @@ namespace BrewMonster
{
CECUIManager.Instance?.ShowMessageBox(
title: "",
message: "You have received a duel request. Do you accept?",
message: "Bạn vừa nhận được lời thách đấu. Bạn có chấp nhận không?",
messageBoxType: MessageBoxType.BothYesNoButton,
onClickedYes: () => UnityGameSession.c2s_CmdDuelReply(true, idOpp),
onClickedNo: () => UnityGameSession.c2s_CmdDuelReply(false, idOpp));
@@ -710,7 +728,7 @@ namespace BrewMonster
int seqCapture = team_seq;
CECUIManager.Instance?.ShowMessageBox(
title: "",
message: "You have received a team invite. Do you accept?",
message: "Bạn đã nhận được lời mời tham gia tổ đội. Bạn có chấp nhận không?",
messageBoxType: MessageBoxType.BothYesNoButton,
onClickedYes: () => UnityGameSession.c2s_CmdTeamAgreeInvite(idLeader, seqCapture),
onClickedNo: () => UnityGameSession.c2s_CmdTeamRejectInvite(idLeader));
@@ -738,14 +756,7 @@ namespace BrewMonster
NotifyServerForceAttack(true);
}
}
/// <summary>Origin: notify server of force-attack (PVP) state so it accepts/rejects attacks on players. Call when duel starts (true) or ends (false).</summary>
private void NotifyServerForceAttack(bool bForceAttack)
{
byte refuseBless = EC_Utility.glb_BuildRefuseBLSMask();
UnityGameSession.c2s_SendCmdNotifyForceAttack(glb_BuildPVPMask(bForceAttack), refuseBless);
}
#if UNITY_EDITOR
/// <summary>
/// Cycles through learned skills by removing all shortcuts and adding 2 new skills to slots 0 and 1.
@@ -1983,226 +1994,182 @@ namespace BrewMonster
return pNPC && ( /*!IsSkeletonReady() ||*/ CanSafelySelectWith(pNPC.GetDistToHost()));
}
// Check whether host can do a behavior
bool CanDo(int iThing)
// Check whether host can do a behavior / 检查宿主是否可以执行某个行为
public bool CanDo(int iThing)
{
bool bRet = true;
switch (iThing)
{
case ActionCanDo.CANDO_SITDOWN:
if (IsDead() /*|| IsAboutToDie() */ || IsJumping() /*|| IsTrading() || IsUsingTrashBox()*/ ||
IsRooting() || /*IsReviving() || IsTalkingWithNPC() || IsChangingFace() ||*/
!m_GndInfo
.bOnGround /*|| GetBoothState() != 0 || m_iBuddyId || IsOperatingPet() || IsRebuildingPet() ||
IsUsingItem() || IsRidingOnPet() || GetShapeType() == PLAYERMODEL_DUMMYTYPE2 || IsPassiveMove()*/
)
if (IsDead() || IsAboutToDie() || IsJumping() || IsTrading() || IsUsingTrashBox() ||
IsRooting() || IsReviving() || IsTalkingWithNPC() || IsChangingFace() ||
!m_GndInfo.bOnGround || GetBoothState() != 0 || m_iBuddyId != 0 || IsOperatingPet() != 0 || IsRebuildingPet() ||
IsUsingItem() || IsRidingOnPet() || GetShapeType() == (int)PlayerModelType.PLAYERMODEL_DUMMYTYPE2 || IsPassiveMove())
bRet = false;
break;
case ActionCanDo.CANDO_MOVETO:
{
if (IsDead() /*|| IsSitting() || IsTrading() || IsUsingTrashBox()*/ || IsRooting() /*||
IsReviving() || IsTalkingWithNPC() || IsChangingFace() || IsUsingItem() ||
GetBoothState() != 0 || m_bHangerOn || IsOperatingPet() || IsRebuildingPet() || IsPassiveMove()*/)
bRet = false;
break;
}
case ActionCanDo.CANDO_MELEE:
if (IsDead() /*|| IsSitting() */ || m_idSelTarget == 0 || m_idSelTarget == m_PlayerInfo.cid ||
IsJumping() || GPDataTypeHelper.ISMATTERID(m_idSelTarget) /*|| IsTrading() || IsReviving() ||
IsUsingTrashBox() || IsTalkingWithNPC() || IsChangingFace()*/ || CannotAttack() /*||
GetBoothState() != 0 || m_iBuddyId || IsRidingOnPet() || IsOperatingPet() || IsRebuildingPet() ||
IsUsingItem() || IsPassiveMove()*/)
if (IsDead() || IsSitting() || IsTrading() || IsUsingTrashBox() || IsRooting() ||
IsReviving() || IsTalkingWithNPC() || IsChangingFace() || IsUsingItem() ||
GetBoothState() != 0 || m_bHangerOn || IsOperatingPet() != 0 || IsRebuildingPet() || IsPassiveMove())
bRet = false;
break;
case ActionCanDo.CANDO_MELEE:
if (IsDead() || IsSitting() || m_idSelTarget == 0 || m_idSelTarget == m_PlayerInfo.cid ||
IsJumping() || GPDataTypeHelper.ISMATTERID(m_idSelTarget) || IsTrading() || IsReviving() ||
IsUsingTrashBox() || IsTalkingWithNPC() || IsChangingFace() || CannotAttack() ||
GetBoothState() != 0 || m_iBuddyId != 0 || IsRidingOnPet() || IsOperatingPet() != 0 || IsRebuildingPet() ||
IsUsingItem() || IsPassiveMove())
bRet = false;
break;
case ActionCanDo.CANDO_ASSISTSEL:
if (IsDead() || !GPDataTypeHelper.ISPLAYERID(m_idSelTarget) ||
m_idSelTarget == m_PlayerInfo.cid /*||
!m_pTeam || !m_pTeam.GetMemberByID(m_idSelTarget) || m_iBuddyId || IsPassiveMove()*/ ||
if (IsDead() || !GPDataTypeHelper.ISPLAYERID(m_idSelTarget) || m_idSelTarget == m_PlayerInfo.cid ||
m_pTeam == null || m_pTeam.GetMemberByID(m_idSelTarget) == null || m_iBuddyId != 0 || IsPassiveMove() ||
m_playerLimits[(int)PLAYER_LIMIT.PLAYER_LIMIT_NOCHANGESELECT])
bRet = false;
break;
case ActionCanDo.CANDO_FLY:
if (IsDead() || IsRooting() || IsSitting() || IsTrading() || IsReviving() ||
IsUsingTrashBox() || IsTalkingWithNPC() || IsChangingFace() || GetBoothState() != 0 ||
//IsFlashMoving() ||
m_pWorkMan.HasWorkRunningOnPriority(CECHPWorkMan.Work_priority.PRIORITY_2) ||
m_bHangerOn || /*IsOperatingPet() || IsRebuildingPet() ||*/
IsUsingItem() || /*IsRidingOnPet() || GetShapeType() == PLAYERMODEL_DUMMYTYPE2 ||*/ IsPassiveMove() ||
m_playerLimits[(int)PLAYER_LIMIT.PLAYER_LIMIT_NOFLY]/* || m_BattleInfo.IsChariotWar()*/)
IsUsingTrashBox() || IsTalkingWithNPC() || IsChangingFace() || GetBoothState() != 0 ||
IsFlashMoving() || (m_pWorkMan != null && m_pWorkMan.HasWorkRunningOnPriority(CECHPWorkMan.Work_priority.PRIORITY_2)) ||
m_bHangerOn || IsOperatingPet() != 0 || IsRebuildingPet() ||
IsUsingItem() || IsRidingOnPet() || GetShapeType() == (int)PlayerModelType.PLAYERMODEL_DUMMYTYPE2 || IsPassiveMove() ||
m_playerLimits[(int)PLAYER_LIMIT.PLAYER_LIMIT_NOFLY] /*|| m_BattleInfo.IsChariotWar()*/)
bRet = false;
break;
case ActionCanDo.CANDO_PICKUP:
case ActionCanDo.CANDO_GATHER:
if (IsDead() /*|| IsAboutToDie() || IsSitting() || IsTrading() || IsUsingTrashBox() ||
IsReviving() || IsTalkingWithNPC() || IsChangingFace() || GetBoothState() != 0 ||
GetBuddyState() == 1 || IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || IsPassiveMove()*/)
if (IsDead() || IsAboutToDie() || IsSitting() || IsTrading() || IsUsingTrashBox() ||
IsReviving() || IsTalkingWithNPC() || IsChangingFace() || GetBoothState() != 0 ||
GetBuddyState() == 1 || IsOperatingPet() != 0 || IsRebuildingPet() || IsUsingItem() || IsPassiveMove())
bRet = false;
break;
case ActionCanDo.CANDO_TRADE:
if (IsDead() || IsMeleeing() /*|| IsAboutToDie() || IsSitting() || IsJumping() ||
IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() || IsChangingFace() ||
IsSpellingMagic() || GetBoothState() != 0 || m_iBuddyId || IsOperatingPet() || IsRebuildingPet() ||
IsUsingItem() || IsInvisible() || IsPassiveMove()*/)
if (IsDead() || IsAboutToDie() || IsSitting() || IsJumping() || IsMeleeing() ||
IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() || IsChangingFace() ||
IsSpellingMagic() || GetBoothState() != 0 || m_iBuddyId != 0 || IsOperatingPet() != 0 || IsRebuildingPet() ||
IsUsingItem() || IsInvisible() || IsPassiveMove())
bRet = false;
break;
case ActionCanDo.CANDO_PLAYPOSE:
if (IsDead() || IsMeleeing() || /*|| IsAboutToDie() || IsSitting() || IsJumping() || /* ||
IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() || IsChangingFace() ||
IsSpellingMagic() || IsShapeChanged() || IsReviving() ||*/
m_iMoveEnv != (int)MoveEnvironment.MOVEENV_GROUND /*||
GetBoothState() != 0 || m_iBuddyId || IsOperatingPet() || IsRebuildingPet() || IsUsingItem() ||
IsRidingOnPet() || GetShapeType() == PLAYERMODEL_DUMMYTYPE2 || IsPassiveMove() || m_BattleInfo.IsChariotWar()*/
)
if (IsDead() || IsAboutToDie() || IsSitting() || IsJumping() || IsMeleeing() ||
IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() || IsChangingFace() ||
IsSpellingMagic() || IsShapeChanged() || IsReviving() || m_iMoveEnv != (int)MoveEnvironment.MOVEENV_GROUND ||
GetBoothState() != 0 || m_iBuddyId != 0 || IsOperatingPet() != 0 || IsRebuildingPet() || IsUsingItem() ||
IsRidingOnPet() || GetShapeType() == (int)PlayerModelType.PLAYERMODEL_DUMMYTYPE2 || IsPassiveMove() /*|| m_BattleInfo.IsChariotWar()*/)
bRet = false;
break;
//case ActionCanDo.CANDO_SPELLMAGIC:
// if (IsDead() || ISMATTERID(m_idSelTarget) || IsAboutToDie() || IsSitting() ||
// IsJumping() || IsFlashMoving() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() ||
// IsChangingFace() || CannotAttack() || IsReviving() || GetBoothState() != 0 ||
// m_iBuddyId || IsRidingOnPet() || IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || IsPassiveMove())
// bRet = false;
// break;
case ActionCanDo.CANDO_SPELLMAGIC:
if (IsDead() || GPDataTypeHelper.ISMATTERID(m_idSelTarget) || IsAboutToDie() || IsSitting() ||
IsJumping() || IsFlashMoving() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() ||
IsChangingFace() || CannotAttack() || IsReviving() || GetBoothState() != 0 ||
m_iBuddyId != 0 || IsRidingOnPet() || IsOperatingPet() != 0 || IsRebuildingPet() || IsUsingItem() || IsPassiveMove())
bRet = false;
break;
case ActionCanDo.CANDO_SUMMONPET:
if (IsDead() || GPDataTypeHelper.ISMATTERID(m_idSelTarget) || IsAboutToDie() || IsSitting() ||
IsJumping() || /*IsFlashMoving() ||*/ IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() ||
IsChangingFace() || CannotAttack() || IsReviving() || GetBoothState() != 0 ||
IsInvisible() /*|| IsGMInvisible()*/ || IsOperatingPet() != 0 || /*IsRebuildingPet() ||*/ IsUsingItem() || IsPassiveMove()
/*|| m_BattleInfo.IsChariotWar()*/)
IsJumping() || IsFlashMoving() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() ||
IsChangingFace() || CannotAttack() || IsReviving() || GetBoothState() != 0 ||
IsInvisible() || IsGMInvisible() || IsOperatingPet() != 0 || IsRebuildingPet() || IsUsingItem() || IsPassiveMove()
/*|| m_BattleInfo.IsChariotWar()*/)
bRet = false;
break;
case ActionCanDo.CANDO_REBUILDPET:
if (IsDead() || GPDataTypeHelper.ISMATTERID(m_idSelTarget) /*|| IsAboutToDie() || IsSitting() */ ||
IsJumping() /*|| IsFlashMoving() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() ||
IsChangingFace()*/ || CannotAttack() /*|| IsReviving() || GetBoothState() != 0 ||
m_iBuddyId || IsInvisible() || IsGMInvisible() || IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || IsPassiveMove() ||
IsPlayerMoving() || m_BattleInfo.IsChariotWar()*/)
if (IsDead() || GPDataTypeHelper.ISMATTERID(m_idSelTarget) || IsAboutToDie() || IsSitting() ||
IsJumping() || IsFlashMoving() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() ||
IsChangingFace() || CannotAttack() || IsReviving() || GetBoothState() != 0 ||
m_iBuddyId != 0 || IsInvisible() || IsGMInvisible() || IsOperatingPet() != 0 || IsRebuildingPet() || IsUsingItem() || IsPassiveMove() ||
IsPlayerMoving() /*|| m_BattleInfo.IsChariotWar()*/)
bRet = false;
break;
//case ActionCanDo.CANDO_USEITEM:
// if (IsAboutToDie() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() ||
// IsChangingFace() || GetBoothState() != 0 || IsPassiveMove() || m_BattleInfo.IsChariotWar())
// bRet = false;
// break;
case ActionCanDo.CANDO_USEITEM:
if (IsAboutToDie() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() ||
IsChangingFace() || GetBoothState() != 0 || IsPassiveMove() /*|| m_BattleInfo.IsChariotWar()*/)
bRet = false;
break;
case ActionCanDo.CANDO_JUMP:
{
if (IsDead() ||
m_iJumpCount >= MAX_JUMP_COUNT ||
// cannot jump more than one time if shape mode is type2
//(IsJumping() && (GetShapeType() == PLAYERMODEL_DUMMYTYPE2)) ||
IsJumpInWater() || m_iMoveEnv == Move_environment.MOVEENV_AIR || IsSitting() ||
IsMeleeing() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() ||
IsChangingFace() || IsReviving() || IsSpellingMagic() || IsPicking() ||
IsGathering() || IsRooting() || GetBoothState() != 0 ||
m_bHangerOn || /*(IsJumping() && IsRidingOnPet()) ||*/
/*IsOperatingPet() || IsRebuildingPet() ||*/ IsUsingItem() ||
IsPassiveMove() /*|| m_BattleInfo.IsChariotWar()*/)
bRet = false;
break;
}
//case ActionCanDo.CANDO_FOLLOW:
// {
// if (IsDead() || IsAboutToDie() || IsSitting() || IsMeleeing() || IsReviving() ||
// IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() || IsChangingFace() ||
// IsSpellingMagic() || GetBoothState() != 0 || m_bHangerOn || IsOperatingPet() || IsRebuildingPet() ||
// IsUsingItem() || IsPassiveMove())
// bRet = false;
// break;
// }
//case ActionCanDo.CANDO_BOOTH:
// if (IsDead() || IsAboutToDie() || IsPlayerMoving() || IsSitting() || IsReviving() ||
// IsMeleeing() || IsJumping() || IsTrading() || IsUsingTrashBox() ||
// IsTalkingWithNPC() || IsChangingFace() || IsSpellingMagic() || IsFlying() ||
// IsUnderWater() || m_iBuddyId || IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || IsRidingOnPet() || IsInvisible() ||
// IsPassiveMove())
// bRet = false;
// break;
//case ActionCanDo.CANDO_FLASHMOVE:
// if (IsDead() || IsAboutToDie() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() ||
// IsJumping() || IsFlashMoving() || IsFalling() || IsChangingFace() || GetBoothState() != 0 || IsTakingOff() ||
// m_pWorkMan.HasWorkRunningOnPriority(CECHPWorkMan::PRIORITY_2) ||
// m_iBuddyId || IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || IsPassiveMove())
// bRet = false;
// break;
//case ActionCanDo.CANDO_BINDBUDDY:
// if (IsDead() || IsAboutToDie() || IsJumping() || IsSitting() ||
// IsMeleeing() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() ||
// IsChangingFace() || IsReviving() || IsSpellingMagic() || IsPicking() ||
// IsGathering() || IsRooting() || GetBoothState() != 0 ||
// !m_pWorkMan.IsStanding() || m_iBuddyId ||
// IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || GetShapeType() == PLAYERMODEL_DUMMYTYPE2 || IsPassiveMove() ||
// m_playerLimits.test(PLAYER_LIMIT_NOBIND))
// bRet = false;
// break;
//case ActionCanDo.CANDO_DUEL:
// if (IsDead() || IsAboutToDie() || IsSitting() || IsFighting() || IsTrading() ||
// IsReviving() || IsUsingTrashBox() || IsTalkingWithNPC() || IsChangingFace() ||
// GetBoothState() != 0 || m_iBuddyId || m_pvp.iDuelState != DUEL_ST_NONE ||
// IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || IsPassiveMove())
// bRet = false;
// break;
case ActionCanDo.CANDO_CHANGESELECT:
//if (m_playerLimits.test(PLAYER_LIMIT_NOCHANGESELECT))
// bRet = false;
if (IsDead() ||
m_iJumpCount >= MAX_JUMP_COUNT ||
// cannot jump more than one time if shape mode is type2
(IsJumping() && (GetShapeType() == (int)PlayerModelType.PLAYERMODEL_DUMMYTYPE2)) ||
IsJumpInWater() || m_iMoveEnv == (int)MoveEnvironment.MOVEENV_AIR || IsSitting() ||
IsMeleeing() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() ||
IsChangingFace() || IsReviving() || IsSpellingMagic() || IsPicking() ||
IsGathering() || IsRooting() || GetBoothState() != 0 || m_bHangerOn || (IsJumping() && IsRidingOnPet()) ||
IsOperatingPet() != 0 || IsRebuildingPet() || IsUsingItem() || IsPassiveMove() /*|| m_BattleInfo.IsChariotWar()*/)
bRet = false;
break;
//case ActionCanDo.CANDO_SWITCH_PARALLEL_WORLD:
// if (IsDead() || IsAboutToDie() || IsJumping() || IsFighting() ||
// IsMeleeing() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() ||
// IsChangingFace() || IsReviving() || IsSpellingMagic() || IsPicking() ||
// IsGathering() || IsRooting() || GetBoothState() != 0 ||
// m_iBuddyId || IsOperatingPet() || IsRebuildingPet() || IsUsingItem() ||
// GetShapeType() == PLAYERMODEL_DUMMYTYPE2 || IsPassiveMove())
// bRet = false;
// break;
case ActionCanDo.CANDO_FOLLOW:
if (IsDead() || IsAboutToDie() || IsSitting() || IsMeleeing() || IsReviving() ||
IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() || IsChangingFace() ||
IsSpellingMagic() || GetBoothState() != 0 || m_bHangerOn || IsOperatingPet() != 0 || IsRebuildingPet() ||
IsUsingItem() || IsPassiveMove())
bRet = false;
break;
case ActionCanDo.CANDO_BOOTH:
if (IsDead() || IsAboutToDie() || IsPlayerMoving() || IsSitting() || IsReviving() ||
IsMeleeing() || IsJumping() || IsTrading() || IsUsingTrashBox() ||
IsTalkingWithNPC() || IsChangingFace() || IsSpellingMagic() || IsFlying() ||
IsUnderWater() || m_iBuddyId != 0 || IsOperatingPet() != 0 || IsRebuildingPet() || IsUsingItem() || IsRidingOnPet() || IsInvisible() ||
IsPassiveMove())
bRet = false;
break;
case ActionCanDo.CANDO_FLASHMOVE:
if (IsDead() || IsAboutToDie() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() ||
IsJumping() || IsFlashMoving() || IsFalling() || IsChangingFace() || GetBoothState() != 0 || IsTakingOff() ||
(m_pWorkMan != null && m_pWorkMan.HasWorkRunningOnPriority(CECHPWorkMan.Work_priority.PRIORITY_2)) ||
m_iBuddyId != 0 || IsOperatingPet() != 0 || IsRebuildingPet() || IsUsingItem() || IsPassiveMove())
bRet = false;
break;
case ActionCanDo.CANDO_BINDBUDDY:
if (IsDead() || IsAboutToDie() || IsJumping() || IsSitting() ||
IsMeleeing() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() ||
IsChangingFace() || IsReviving() || IsSpellingMagic() || IsPicking() ||
IsGathering() || IsRooting() || GetBoothState() != 0 ||
(m_pWorkMan != null && !m_pWorkMan.IsStanding()) || m_iBuddyId != 0 ||
IsOperatingPet() != 0 || IsRebuildingPet() || IsUsingItem() || GetShapeType() == (int)PlayerModelType.PLAYERMODEL_DUMMYTYPE2 || IsPassiveMove() ||
m_playerLimits[(int)PLAYER_LIMIT.PLAYER_LIMIT_NOBIND])
bRet = false;
break;
case ActionCanDo.CANDO_DUEL:
if (IsDead() || IsAboutToDie() || IsSitting() || IsFighting() || IsTrading() ||
IsReviving() || IsUsingTrashBox() || IsTalkingWithNPC() || IsChangingFace() ||
GetBoothState() != 0 || m_iBuddyId != 0 || m_pvp.iDuelState != (int)DuelState.DUEL_ST_NONE ||
IsOperatingPet() != 0 || IsRebuildingPet() || IsUsingItem() || IsPassiveMove())
bRet = false;
break;
case ActionCanDo.CANDO_CHANGESELECT:
if (m_playerLimits[(int)PLAYER_LIMIT.PLAYER_LIMIT_NOCHANGESELECT])
bRet = false;
break;
case ActionCanDo.CANDO_SWITCH_PARALLEL_WORLD:
if (IsDead() || IsAboutToDie() || IsJumping() || IsFighting() ||
IsMeleeing() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() ||
IsChangingFace() || IsReviving() || IsSpellingMagic() || IsPicking() ||
IsGathering() || IsRooting() || GetBoothState() != 0 ||
m_iBuddyId != 0 || IsOperatingPet() != 0 || IsRebuildingPet() || IsUsingItem() ||
GetShapeType() == (int)PlayerModelType.PLAYERMODEL_DUMMYTYPE2 || IsPassiveMove())
bRet = false;
break;
}
return bRet;
@@ -2295,6 +2262,73 @@ namespace BrewMonster
return m_pWorkMan.IsPassiveMoving();
}
// Is about to die / 是否即将死亡
bool IsAboutToDie()
{
return m_bAboutToDie;
}
// Is rebuilding pet / 是否正在重建宠物
bool IsRebuildingPet()
{
return m_bInRebuildPet;
}
// Is riding on pet / 是否骑乘宠物
bool IsRidingOnPet()
{
return m_RidingPet.id != 0;
}
// Is flash moving / 是否在闪移
bool IsFlashMoving()
{
if (m_pWorkMan == null) return false;
return m_pWorkMan.IsFlashMoving();
}
// Get buddy state / 获取伙伴状态
// return value: 0 = no buddy, 1 = has buddy, 2 = hanger on
int GetBuddyState()
{
if (m_bHangerOn) return 2;
if (m_iBuddyId != 0) return 1;
return 0;
}
// Is invisible / 是否隐身
bool IsInvisible()
{
return (m_dwStates & (uint)PlayerNPCState.GP_STATE_INVISIBLE) != 0;
}
// Is GM invisible / 是否GM隐身
bool IsGMInvisible()
{
// GMF_INVISIBLE would be a constant, using bit check
// GMF_INVISIBLE 将是一个常量,使用位检查
return (m_dwGMFlags & 0x01) != 0; // Assuming GMF_INVISIBLE = 0x01
}
// Is shape changed / 是否形状已改变
bool IsShapeChanged()
{
return m_iShape != 0;
}
// Is taking off / 是否正在起飞
bool IsTakingOff()
{
if (m_pWorkMan == null) return false;
return m_pWorkMan.IsFlyingOff();
}
// Is flying / 是否在飞行
bool IsFlying()
{
return (m_dwStates & (uint)PlayerNPCState.GP_STATE_FLY) != 0;
}
//public void SetGroundInfoClient()
//{
// isGrounded = GroundCheck(out lastGroundHit);
@@ -3547,7 +3581,11 @@ namespace BrewMonster
// Update battle result time counter
if (IsInBattle() && !IsInFortress() && m_BattleInfo.iResult != 0 && m_BattleInfo.iResultCnt != 0)
{
if ((m_BattleInfo.iResultCnt -= dwDeltaTime) < 0)
// iResultCnt is time counter (likely in milliseconds as int), dwDeltaTime is in seconds (float)
// iResultCnt是时间计数器(可能是毫秒为int),dwDeltaTime是秒数(float
// Convert seconds to milliseconds and subtract / 将秒转换为毫秒并减去
int deltaTimeMs = (int)(dwDeltaTime * 1000f);
if ((m_BattleInfo.iResultCnt -= deltaTimeMs) < 0)
m_BattleInfo.iResultCnt = 0;
}
+31
View File
@@ -378,11 +378,28 @@ namespace BrewMonster
m_wingType = enumWingType.WINGTYPE_WING;
//ChangeWing(pResult, static_cast<const WINGMANWING_ESSENCE*>(pEquip)->file_model);
var pWingData = (WINGMANWING_ESSENCE)equipData;
var pWingPrefab = await AddressableManager.Instance.LoadPrefabAsync(pWingData.FileModel.ToLower().Replace('\\', '/'));
Transform parentWing = FindChildRecursive(_pPlayerModel.transform, "HH_chibang");
if(parentWing != null)
{
var pWingObject = Instantiate(pWingPrefab, parentWing);
pWingObject.gameObject.SetActive(false);
pWingObject.name = _wing;
}
BMLogger.Log($"ShowEquipments():: Wingman Wing Essence: {pWingData.id} {pWingData.Name} -- {pWingData.FileModel}");
break;
case DATA_TYPE.DT_FLYSWORD_ESSENCE:
var pFlySword = (FLYSWORD_ESSENCE)equipData;
m_wingType = FlyMode2WingType(pFlySword.fly_mode);
var pflySwordPrefab = await AddressableManager.Instance.LoadPrefabAsync(pFlySword.FileModel.ToLower().Replace('\\', '/'));
var parentSword = FindChildRecursive(_pPlayerModel.transform, "HH_feijian");
if(parentSword != null)
{
var pflySwordObject = Instantiate(pflySwordPrefab, parentSword);
pflySwordObject.gameObject.SetActive(false);
pflySwordObject.name = _wing;
}
BMLogger.Log($"ShowEquipments():: Flysword Essence: {pFlySword.id} {pFlySword.Name} -- {pFlySword.FileModel}");
break;
default:
@@ -480,6 +497,20 @@ namespace BrewMonster
}
}
Transform FindChildRecursive(Transform parent, string name)
{
foreach (Transform child in parent)
{
if (child.name == name)
return child;
Transform found = FindChildRecursive(child, name);
if (found != null)
return found;
}
return null;
}
#region Helper Methods
private GameObject FindChildObjectRecursive(Transform parent, string name)
{