Merge branch 'develop' into feature/hp_pet

# Conflicts:
#	Assets/PerfectWorld/Prefab/UIManager.prefab
#	Assets/PerfectWorld/Resources/UI/DialogScriptTableObject.asset
#	Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs
#	Assets/PerfectWorld/Scripts/Network/UnityGameSession.cs
#	Assets/PerfectWorld/Scripts/Players/EC_HostMsg.cs
#	Assets/Scripts/CECHostPlayer.cs
This commit is contained in:
Tungdv
2026-02-26 16:39:23 +07:00
8020 changed files with 5298993 additions and 22099 deletions
+8 -5
View File
@@ -107,15 +107,11 @@ public partial class CECGameRun
private static void Dispose()
{
instance = null;
AddressableManager.Instance.ReleaseAsset(AddressResourceConfig.PlayerPrefab);
AddressableManager.Instance.ReleaseAsset(AddressResourceConfig.MonsterPrefab);
AddressableManager.Instance.ReleaseAsset(AddressResourceConfig.NpcServerPrefab);
//AddressableManager.Instance.ReleaseAsset(AddressResourceConfig.PetServerPrefab);
//AddressableManager.Instance.ReleaseAsset(AddressResourceConfig.PetMountServerPrefab);
}
private void LoadPrefabs()
{
BMLogger.LogError("CECGameRun::LoadPrefabs, Loading prefabs from Resources. Consider using Addressables for better performance and memory management.");
_playerPrefab = Resources.Load<GameObject>(AddressResourceConfig.PlayerPrefab);
_monsterPrefab = Resources.Load<GameObject>(AddressResourceConfig.MonsterPrefab);
_npcServerPrefab = Resources.Load<GameObject>(AddressResourceConfig.NpcServerPrefab);
@@ -209,6 +205,13 @@ public partial class CECGameRun
CECPlayer.InitStaticRes();
hostPlayer = ObjectSpawner.Instance.InstantiateObject(_playerPrefab, setThisAsParent: true).AddComponent<CECHostPlayer>();
hostPlayer.InitCharacter(info);
if (hostPlayer != null)
{
var t = Type.GetType("BrewMonster.UI.SelectedTargetHUDController, Assembly-CSharp");
if (t != null && hostPlayer.GetComponent(t) == null)
hostPlayer.gameObject.AddComponent(t);
}
}
public CECMonster GetMonster()
{
+906
View File
@@ -0,0 +1,906 @@
using BrewMonster.Managers;
using BrewMonster.Network;
using BrewMonster.Scripts;
using BrewMonster.Scripts.World;
using CSNetwork;
using CSNetwork.GPDataType;
using System;
using UnityEngine;
using static BrewMonster.Scripts.CECHPWork;
using static CECPlayerWrapper;
namespace BrewMonster
{
public partial class CECHostPlayer
{
public void OnMsgHstAttackResult(ECMSG Msg)
{
byte[] data = Msg.dwParam1 as byte[];
cmd_host_attack_result pCmd = EC_Utility.ByteArrayToStructure<cmd_host_attack_result>(data);
int iAttackTime = 0;
TurnFaceTo(pCmd.idTarget);
PlayAttackEffect(pCmd.idTarget, 0, 0, pCmd.iDamage, (uint)pCmd.attack_flag, pCmd.attack_speed * 50,
ref iAttackTime);
if (iAttackTime != 0)
{
if (m_pWorkMan.GetRunningWork(CECHPWork.Host_work_ID.WORK_HACKOBJECT) is CECHPWorkMelee pCurWork)
{
pCurWork.SetIdleTime(iAttackTime);
}
}
}
void OnMsgHstAttacked(ECMSG Msg)
{
var m_pPlayerMan = EC_ManMessageMono.Instance.EC_ManPlayer;
cmd_host_attacked pCmd = GPDataTypeHelper.FromBytes<cmd_host_attacked>(Msg.dwParam1 as byte[]);
if (pCmd.iDamage != 0 && (pCmd.cEquipment & 0x7f) != 0x7f)
{
/* char cEquip = (char)(pCmd.cEquipment & 0x7f);
CECIvtrEquip pEquip = (CECIvtrEquip)m_pEquipPack.GetItem(cEquip);
if (pEquip)
pEquip.AddCurEndurance(ARMOR_RUIN_SPEED);*/
}
// The host player is attacked, we should make an effect here
if (GPDataTypeHelper.ISPLAYERID(pCmd.idAttacker))
{
EC_ElsePlayer pAttacker = m_pPlayerMan.GetElsePlayer(pCmd.idAttacker);
if (pAttacker)
{
if (!pAttacker.IsDead())
{
// Face to target
pAttacker.TurnFaceTo(GetPlayerInfo().cid);
}
int useless_attacktime = 0;
pAttacker.PlayAttackEffect(GetCharacterID(), 0, 0, pCmd.iDamage, (uint)pCmd.attack_flag,
pCmd.speed * 50, ref useless_attacktime);
pAttacker.EnterFightState();
}
}
else if (GPDataTypeHelper.ISNPCID(pCmd.idAttacker))
{
CECNPC pAttacker = EC_ManMessageMono.Instance.CECNPCMan.GetNPC(pCmd.idAttacker);
if (pAttacker)
{
pAttacker.OnMsgAttackHostResult(GetCharacterID(), pCmd.iDamage, pCmd.attack_flag, pCmd.speed);
}
}
//CECAutoPolicy::GetInstance().SendEvent_BeHurt(pCmd.idAttacker);
}
private void OnMsgHstHurtResult(ECMSG Msg)
{
//BMLogger.LogError("HoangDev : OnMsgHstHurtResult");
/* int cmd = Convert.ToInt32(Msg.dwParam2);
if (cmd == CommandID.BE_HURT)
{
cmd_be_hurt pCmd = (cmd_be_hurt)Msg.dwParam1;
if (pCmd.damage != 0)
Damaged(pCmd.damage);
}
else if (cmd == CommandID.HURT_RESULT)
{
cmd_hurt_result pCmd = (cmd_hurt_result)Msg.dwParam1;
if (pCmd.target_id == m_PlayerInfo.cid)
return; // Host himself will receive BE_HURT, so ignore this.
if (UnityGameSession.Instance.GameSession.ISPLAYERID(pCmd.target_id))
{
CECElsePlayer pTarget = m_pPlayerMan.GetElsePlayer(pCmd.target_id);
if (pTarget)
pTarget.Damaged(pCmd.damage);
}
else if (UnityGameSession.Instance.GameSession.ISNPCID(pCmd.target_id))
{
CECNPC pTarget = EC_ManMessageMono.Instance._CECNPCMan.GetNPC(pCmd.target_id);
if (pTarget)
pTarget.Damaged(pCmd.damage);
}
}*/
}
private void OnMsgHstStartAttack(in ECMSG Msg)
{
cmd_host_start_attack pCmd = GPDataTypeHelper.FromBytes<cmd_host_start_attack>((byte[])Msg.dwParam1);
// ASSERT(pCmd);
// test code...
// g_pGame.GetRTDebug().OutputNotifyMessage(RTDCOL_WARNING, _AL("start attack !"));
// Check whether target is the one that we have selected
if (m_idSelTarget != pCmd.idTarget)
// g_pGame.RuntimeDebugInfo(RTDCOL_WARNING, _AL("Target has changed !"));
// If target turn to be un-attackable, cancel action
if (AttackableJudge(pCmd.idTarget, true) == 0)
{
UnityGameSession.c2s_CmdCancelAction();
// g_pGame.RuntimeDebugInfo(RTDCOL_WARNING, _AL("Cannel attacking !"));
return;
}
// Synchronize ammo amount
// CECIvtrItem* pItem = m_pEquipPack.GetItem(EQUIPIVTR_PROJECTILE);
// if (pItem)
// {
// if (!pCmd.ammo_remain)
// m_pEquipPack.SetItem(EQUIPIVTR_PROJECTILE, NULL);
// else
// pItem.SetAmount(pCmd.ammo_remain);
// }
CECHPWorkMelee pWork = (CECHPWorkMelee)m_pWorkMan.CreateWork(Host_work_ID.WORK_HACKOBJECT);
m_pWorkMan.StartWork_p1(pWork);
m_bMelee = true;
// AP_ActionEvent(AP_EVENT_STARTMELEE);
}
private void OnMsgHstStopAttack(in ECMSG Msg)
{
// using namespace S2C;
//
m_bMelee = false;
//
// // if there is an attack event currently, we should let it fire now.
ClearComActFlagAllRankNodes(true);
cmd_host_stop_attack pCmd = GPDataTypeHelper.FromBytes<cmd_host_stop_attack>((byte[])Msg.dwParam1);
// ASSERT(pCmd);
/* If attack stopped for target is leave too far, trace it and continue
attacking. Stop reason defined as below:
0x00: attack is canceled or host want to do some other things.
0x01: unable to attack anymore (no ammo, weapon is broken etc.)
0x02: invalid target (target missed or died)
0x04: target is out of range
*/
if ((pCmd.iReason & 0x04) != 0)
{
if (!m_pWorkMan.IsMovingToPosition() &&
!m_pWorkMan.IsTracing())
{
if (CmdNormalAttack(false, false, 0, -1)) //m_pComboSkill != NULL
{
// AP_ActionEvent(AP_EVENT_MELEEOUTOFRANGE, 1);
}
else
{
m_pWorkMan.FinishRunningWork(Host_work_ID.WORK_HACKOBJECT);
// AP_ActionEvent(AP_EVENT_STOPMELEE);
}
}
else
{
// AP_ActionEvent(AP_EVENT_STOPMELEE);
}
}
else
{
m_pWorkMan.FinishRunningWork(Host_work_ID.WORK_HACKOBJECT);
// AP_ActionEvent(AP_EVENT_STOPMELEE);
}
// #ifdef _SHOW_AUTOPOLICY_DEBUG
// a_LogOutput(1, "Stop Attack, Reason = %d", pCmd.iReason);
// #endif
}
private void OnMsgHstSkillResult(ECMSG Msg)
{
cmd_host_skill_attack_result pCmd =
GPDataTypeHelper.FromBytes<cmd_host_skill_attack_result>((byte[])Msg.dwParam1);
int refFake = 0;
PlayAttackEffect(pCmd.idTarget, pCmd.idSkill, 0, pCmd.iDamage, (uint)pCmd.attack_flag,
pCmd.attack_speed * 50, ref refFake, pCmd.section);
}
private void OnMsgPlayerCastSkill(ECMSG Msg)
{
bool bDoOtherThing = false;
int idTarget = 0;
bool bActionStartSkill = false;
int iActionTime = 1000;
CECPlayerWrapper pWrapper = CECAutoPolicy.GetInstance().GetPlayerWrapper();
switch (Convert.ToInt32(Msg.dwParam2))
{
case CommandID.OBJECT_CAST_SKILL:
{
cmd_object_cast_skill pCmd =
GPDataTypeHelper.FromBytes<cmd_object_cast_skill>((byte[])Msg.dwParam1);
if (m_pCurSkill != null)
{
m_pCurSkill.EndCharging();
}
m_pCurSkill = GetPositiveSkillByID(pCmd.skill);
if (m_pCurSkill == null) m_pCurSkill = GetEquipSkillByID(pCmd.skill);
if (m_pCurSkill == null)
m_pCurSkill = CECComboSkillState.Instance.GetInherentSkillByID((uint)pCmd.skill);
if (m_pCurSkill == null)
{
Debug.Assert(m_pCurSkill != null, "Current skill should not be null");
return;
}
if (m_pCurSkill.IsChargeable())
m_pCurSkill.StartCharging(pCmd.time);
int iWaitTime = -1;
if (m_pCurSkill.GetExecuteTime() >= 0)
iWaitTime = pCmd.time + m_pCurSkill.GetExecuteTime();
CECHPWorkSpell pWork = (CECHPWorkSpell)m_pWorkMan.CreateWork(Host_work_ID.WORK_SPELLOBJECT);
pWork.PrepareCast(pCmd.target, m_pCurSkill, iWaitTime);
m_pWorkMan.StartWork_p1(pWork);
// Start time counter for some type skill
// 为某些类型的技能启动时间计数器
if (!m_pCurSkill.IsChargeable())
{
int iTime = pCmd.time;
if (iTime < 10) iTime = 10; // a_ClampFloor
m_IncantCnt.SetPeriod(iTime);
m_IncantCnt.Reset();
}
else
{
// make sure the counter is correct shown
// 确保计数器正确显示
m_IncantCnt.Reset(true);
}
m_bSpellDSkill = false;
TurnFaceTo(pCmd.target);
m_idCurSkillTarget = pCmd.target;
PlaySkillCastAction(m_pCurSkill.GetSkillID());
bActionStartSkill = true;
iActionTime = iWaitTime;
// Special logging for return-to-town skill (167)
// 回城技能(167)的特殊日志
if (m_pCurSkill.GetSkillID() == ID_RETURNTOWN_SKILL)
{
Debug.Log(
$"Return-to-town skill (167) cast - State2 should trigger SetReturntown(1) on server");
}
break;
}
case CommandID.SKILL_PERFORM:
{
// Skill perform
// 技能执行
m_pPrepSkill = null;
if (m_pCurSkill != null && m_pCurSkill.IsDurative())
m_bSpellDSkill = true;
// Special handling for return-to-town skill (167)
// 回城技能(167)的特殊处理
// When skill 167 reaches State2, server calls SetReturntown(1) which should trigger MSG_HST_GOTO
// 当技能167到达State2时,服务器调用SetReturntown(1),这应该触发MSG_HST_GOTO
if (m_pCurSkill != null && m_pCurSkill.GetSkillID() == ID_RETURNTOWN_SKILL)
{
Debug.Log($"Skill 167 (Return to Town) performed - waiting for MSG_HST_GOTO from server");
}
break;
}
case CommandID.HOST_STOP_SKILL:
{
m_pPrepSkill = null;
CECSkill pSkillToMatch = m_pCurSkill;
if (m_pCurSkill != null)
{
ClearComActFlagAllRankNodes(true);
if (((m_pComboSkill != null && !m_pComboSkill.IsStop()) ||
m_pCurSkill.ChangeToMelee()) && !m_pWorkMan.HasDelayedWork())
{
bDoOtherThing = true;
idTarget = m_idCurSkillTarget;
}
m_pCurSkill.EndCharging();
m_pCurSkill = null;
}
AP.AP_ActionEvent((int)AP_EVENT.AP_EVENT_STOPSKILL);
if (pSkillToMatch != null)
{
// m_pWorkMan中的当前任何Work为最高优先级或、或 CECHPWorkSpell 处于最高优先级且队列中有Delay时间
// 此时此处无法准确匹配,而导致的 CECHPWorkSpell 执行时将落后于其它 CECHPWorkSpell 执行期间将无法响应
// 在这种方法执行完成后,我们使用回城机制来
// If the current Work in m_pWorkMan is the highest priority or CECHPWorkSpell is at the highest priority and there is Delay time in the queue
// At this point, it cannot be accurately matched, causing the CECHPWorkSpell execution to lag behind other CECHPWorkSpell execution and cannot respond
// After this method is executed, we use the return to city mechanism
m_pWorkMan.FinishWork(new CECHPWorkSpellMatcher(pSkillToMatch));
}
StopSkillAttackAction();
m_idCurSkillTarget = 0;
break;
}
case CommandID.SELF_SKILL_INTERRUPTED:
{
// Skill interrupted
// 技能被打断
int skill_id = 0;
m_pPrepSkill = null;
CECSkill
pSkillToMatch = m_pCurSkill; // 保存指针值,用在后面函数调用中 | Save pointer value for later function call
if (m_pCurSkill != null)
{
skill_id = m_pCurSkill.GetSkillID();
ClearComActFlagAllRankNodes(false);
if (((m_pComboSkill != null && !m_pComboSkill.IsStop()) ||
m_pCurSkill.ChangeToMelee()) && !m_pWorkMan.HasDelayedWork())
{
bDoOtherThing = true;
idTarget = m_idCurSkillTarget;
}
m_pCurSkill.EndCharging();
m_pCurSkill = null;
}
m_idCurSkillTarget = 0;
if (pSkillToMatch != null)
{
// 逻辑同 HOST_STOP_SKILL 分支处理 | Logic same as HOST_STOP_SKILL branch
m_pWorkMan.FinishWork(new CECHPWorkSpellMatcher(pSkillToMatch));
}
StopSkillCastAction();
// Print a notify message
// 打印提示消息
//EC_Game.GetGameRun().AddFixedMessage(FIXMSG_SKILLINTERRUPT);
AP.AP_ActionEvent((int)AP_EVENT.AP_EVENT_STOPSKILL);
// 通知策略技能被打断 | Notify policy that skill is interrupted
CECAutoPolicy.GetInstance().SendEvent_SkillInterrupt(skill_id);
break;
}
case CommandID.OBJECT_CAST_INSTANT_SKILL:
{
// Cast instant skill
// 施放即时技能
cmd_object_cast_instant_skill pCmd =
GPDataTypeHelper.FromBytes<cmd_object_cast_instant_skill>((byte[])Msg.dwParam1);
Debug.Assert(pCmd.caster == m_PlayerInfo.cid);
CECSkill pSkill = GetPositiveSkillByID(pCmd.skill);
if (pSkill == null) pSkill = GetEquipSkillByID(pCmd.skill);
if (pSkill == null)
{
Debug.Assert(pSkill != null, "Skill should not be null");
return;
}
if (pCmd.target != 0 && pCmd.target != m_PlayerInfo.cid)
TurnFaceTo(pCmd.target);
PlaySkillCastAction(pSkill.GetSkillID());
bActionStartSkill = true;
break;
}
case CommandID.OBJECT_CAST_POS_SKILL:
{
// Cast position skill (target position instead of target object)
// 施放位置技能(目标位置而不是目标对象)
cmd_object_cast_pos_skill pCmd =
GPDataTypeHelper.FromBytes<cmd_object_cast_pos_skill>((byte[])Msg.dwParam1);
Debug.Assert(pCmd.caster == m_PlayerInfo.cid);
CECSkill pSkill = GetNormalSkill(pCmd.skill);
if (pSkill == null) pSkill = GetEquipSkillByID(pCmd.skill);
if (pSkill == null)
{
Debug.Assert(pSkill != null, "Skill should not be null");
break;
}
TurnFaceTo(pCmd.target);
if (pSkill.GetRangeType() != (int)CECSkill.RangeType.RANGE_SLEF &&
pSkill.GetRangeType() != (int)CECSkill.RangeType.RANGE_SELFSPHERE &&
(pSkill.GetSkillID() == 1095 || // 瞬影瞬斩 | Shadow instant slash
pSkill.GetSkillID() == 1278 || // 魔·瞬影瞬斩 | Demon Shadow instant slash
pSkill.GetSkillID() == 1279 || // 妖瞬影瞬斩 | Monster Shadow instant slash
pSkill.GetSkillID() == 2313))
{
A3DVECTOR3 vPos = pCmd.pos;
if (!IsPosCollideFree(vPos))
{
// Add a little height to ensure player's AABB won't embed with building
// 添加一点高度以确保玩家的AABB不会嵌入建筑物
vPos += new A3DVECTOR3(0, 1, 0) * 0.1f;
}
// Ensure we are not under ground
// 确保我们不在地下
A3DVECTOR3 vNormal = new A3DVECTOR3();
float vTerrainHeight = CECWorld.Instance.GetTerrainHeight(vPos, ref vNormal);
if (vPos.y < vTerrainHeight)
vPos.y = vTerrainHeight;
SetPos(EC_Utility.ToVector3(vPos));
m_CDRInfo.vTPNormal = vPos.y <= vTerrainHeight + 0.1f ? vNormal : new A3DVECTOR3(0);
m_CDRInfo.fYVel = 0.0f;
m_CDRInfo.vAbsVelocity = new A3DVECTOR3(0);
ResetJump();
m_MoveCtrl.SetHostLastPos(vPos);
m_MoveCtrl.SetLastSevPos(vPos);
// Update camera
// 更新相机
//UpdateFollowCamera(false, 10);
}
else
{
CECHPWorkFMove pWork =
(CECHPWorkFMove)m_pWorkMan.CreateWork(CECHPWork.Host_work_ID.WORK_FLASHMOVE);
// 检查技能执行时间,防止出现浮点数0,出现错误 | Check skill execute time to prevent float 0 error
int nExecuteTime = pSkill.GetExecuteTime();
if (nExecuteTime < 50) nExecuteTime = 50; // a_ClampFloor
if (pSkill.GetSkillID() == 1145 || // 刺客的瞬移技能,需要增加地面效果1145:百步穿杨瞬斩 | Assassin teleport skill
pSkill.GetSkillID() == 1314 || // 魔·百步穿杨瞬斩 | Demon hundred steps instant slash
pSkill.GetSkillID() == 1315 || // 妖·百步穿杨瞬斩 | Monster hundred steps instant slash
pSkill.GetSkillID() == 1362 || // 影遁回杨 | Shadow escape return
pSkill.GetSkillID() == 1690 || // 影遁魔·回杨 | Shadow escape demon return
pSkill.GetSkillID() == 1691 || // 影遁妖回杨 | Shadow escape monster return
pSkill.GetSkillID() == 1845 || // 星湖之狐·瞬移技能 | Star Lake Fox teleport
pSkill.GetSkillID() == 1844 || // 星湖之狐·瞬移技能 | Star Lake Fox teleport
pSkill.GetSkillID() == 1815 || // 妖精 飞 | Fairy fly
pSkill.GetSkillID() == 2272 || // 一步登天 | One step to heaven
pSkill.GetSkillID() == 2315 || // 百步穿杨瞬斩 | Hundred steps instant slash
pSkill.GetSkillID() == 2285 || // 回杨 | Return
pSkill.GetSkillID() == 2340 || // 突袭 | Raid
pSkill.GetSkillID() == 2341 || // 突袭 | Raid
pSkill.GetSkillID() == 2342 || // 突袭 | Raid
pSkill.GetSkillID() == 2553 || // 飞箭雨 | Arrow rain
pSkill.GetSkillID() == 2740 || // 魔·飞箭雨 | Demon arrow rain
pSkill.GetSkillID() == 2741 || // 妖飞箭雨 | Monster arrow rain
pSkill.GetSkillID() == 2559 || // 闪电 | Lightning
pSkill.GetSkillID() == 2752 || // 魔·闪电 | Demon lightning
pSkill.GetSkillID() == 2753) // 妖闪电 | Monster lightning
{
A3DVECTOR3 vPos = pCmd.pos;
if (!IsPosCollideFree(vPos))
{
// Add a little height to ensure player's AABB won't embed with building
// 添加一点高度以确保玩家的AABB不会嵌入建筑物
vPos += new A3DVECTOR3(0, 1, 0) * 0.1f;
}
// Ensure we are not under ground
// 确保我们不在地下
A3DVECTOR3 vNormal = new A3DVECTOR3();
float vTerrainHeight = CECWorld.Instance.GetTerrainHeight(vPos, ref vNormal);
if (vPos.y < vTerrainHeight)
vPos.y = vTerrainHeight;
m_CDRInfo.vTPNormal = vPos.y <= vTerrainHeight + 0.1f ? vNormal : new A3DVECTOR3(0);
m_CDRInfo.fYVel = 0.0f;
m_CDRInfo.vAbsVelocity = new A3DVECTOR3(0);
ResetJump();
pWork.PrepareMove(pCmd.pos, nExecuteTime * 0.001f, pSkill.GetSkillID());
}
else
{
if (pSkill.GetRangeType() == (int)CECSkill.RangeType.RANGE_SLEF ||
pSkill.GetRangeType() == (int)CECSkill.RangeType.RANGE_SELFSPHERE)
{
m_CDRInfo.vTPNormal = m_MoveCtrl.m_vFlashTPNormal;
}
pWork.PrepareMove(pCmd.pos, nExecuteTime * 0.001f, 0);
}
m_pWorkMan.StartWork_p2(pWork);
iActionTime = nExecuteTime;
}
bActionStartSkill = true;
break;
}
case CommandID.PLAYER_CAST_RUNE_SKILL:
{
// Cast rune skill (item skill)
// 施放符文技能(物品技能)
cmd_player_cast_rune_skill pCmd =
GPDataTypeHelper.FromBytes<cmd_player_cast_rune_skill>((byte[])Msg.dwParam1);
Debug.Assert(pCmd.caster == m_PlayerInfo.cid);
if (m_pTargetItemSkill != null)
{
// Delete old target item skill
m_pTargetItemSkill = null;
}
m_pTargetItemSkill = new CECSkill(pCmd.skill, pCmd.level);
if (m_pTargetItemSkill == null)
{
Debug.Assert(m_pTargetItemSkill != null, "Target item skill should not be null");
return;
}
m_pCurSkill = m_pTargetItemSkill;
if (m_pCurSkill.IsChargeable())
m_pCurSkill.StartCharging(pCmd.time);
int iWaitTime = -1;
if (m_pCurSkill.GetExecuteTime() >= 0)
iWaitTime = pCmd.time + m_pCurSkill.GetExecuteTime();
CECHPWorkSpell pWork =
(CECHPWorkSpell)m_pWorkMan.CreateWork(CECHPWork.Host_work_ID.WORK_SPELLOBJECT);
pWork.PrepareCast(pCmd.target, m_pCurSkill, iWaitTime);
m_pWorkMan.StartWork_p1(pWork);
// Start time counter for some type skill
// 为某些类型的技能启动时间计数器
if (!m_pCurSkill.IsChargeable())
{
int iTime = pCmd.time;
if (iTime < 10) iTime = 10; // a_ClampFloor
m_IncantCnt.SetPeriod(iTime);
m_IncantCnt.Reset();
}
else
{
// make sure the counter is correct shown
// 确保计数器正确显示
m_IncantCnt.Reset(true);
}
m_bSpellDSkill = false;
TurnFaceTo(pCmd.target);
m_idCurSkillTarget = pCmd.target;
PlaySkillCastAction(m_pCurSkill.GetSkillID());
bActionStartSkill = true;
iActionTime = iWaitTime;
Debug.Log($"Cast rune skill({m_pCurSkill.GetSkillID()})");
break;
}
case CommandID.PLAYER_CAST_RUNE_INSTANT_SKILL:
{
// Cast instant rune skill
// 施放即时符文技能
cmd_player_cast_rune_instant_skill pCmd =
GPDataTypeHelper.FromBytes<cmd_player_cast_rune_instant_skill>((byte[])Msg.dwParam1);
Debug.Assert(pCmd.caster == m_PlayerInfo.cid);
if (m_pTargetItemSkill != null)
{
// Delete old target item skill
m_pTargetItemSkill = null;
}
m_pTargetItemSkill = new CECSkill(pCmd.skill, pCmd.level);
if (m_pTargetItemSkill == null)
{
Debug.Assert(m_pTargetItemSkill != null, "Target item skill should not be null");
return;
}
if (pCmd.target != 0 && pCmd.target != m_PlayerInfo.cid)
TurnFaceTo(pCmd.target);
PlaySkillCastAction(m_pTargetItemSkill.GetSkillID());
bActionStartSkill = true;
break;
}
case CommandID.ERROR_MESSAGE:
bDoOtherThing = true;
break;
default:
Debug.Assert(false, "Unknown message type in OnMsgPlayerCastSkill");
break;
}
if (bActionStartSkill)
AP.AP_ActionEvent((int)AP_EVENT.AP_EVENT_STARTSKILL, iActionTime);
if (bDoOtherThing)
{
if (m_pComboSkill != null && !m_pComboSkill.IsStop())
{
// Continue combo skill
// 继续连击技能
if (CECAutoPolicy.GetInstance().IsAutoPolicyEnabled())
EC_ManMessage.PostMessage(EC_MsgDef.MSG_HST_CONTINUECOMBOSKILL, MANAGER_INDEX.MAN_PLAYER, 0, 0,
m_pComboSkill.GetGroupIndex());
else
m_pComboSkill.Continue(false);
}
else
{
if (idTarget != 0 && idTarget != m_PlayerInfo.cid)
NormalAttackObject(idTarget, true);
}
}
}
void OnMsgHstTargetIsFar(ECMSG Msg)
{
// TO DO: fix later
//if(CmdNormalAttack(true, m_pComboSkill != null, 0, -1) )
// AP_ActionEvent(AP_EVENT_MELEEOUTOFRANGE, 1);
if (CmdNormalAttack(true, false, 0, -1))
{
//AP_ActionEvent(AP_EVENT_MELEEOUTOFRANGE, 1);
}
}
private void OnMsgHstDied(in ECMSG msg)
{
// Mark host player as corpse so CECPlayer.IsDead() returns true
m_dwStates |= (uint)PlayerNPCState.GP_STATE_CORPSE;
EventBus.PublishChannel(GetCharacterID(), new ClearComActFlagAllRankNodesEvent(true));
PlayAction((int)PLAYER_ACTION_TYPE.ACT_GROUNDDIE);
if (PopupManager.Instance != null)
{
PopupManager.Instance.OnPlayerDied();
}
}
private bool NormalAttackObject(int idTarget, bool bForceAttack, bool bMoreClose = false)
{
if (idTarget == 0 || idTarget == m_PlayerInfo.cid)
{
// We should have check target isn't dead
return false;
}
//if (!EC_Game.GetGameRun().GetWorld().GetObject(idTarget, 1))
// return false;
bool bStartNewWork = false;
bool bUseAutoPF = false;
//CECPlayerWrapper* pWrapper = CECAutoPolicy::GetInstance().GetPlayerWrapper();
//if (CECAutoPolicy::GetInstance().IsAutoPolicyEnabled() && pWrapper.GetAttackError() >= 2)
//bUseAutoPF = true;
CECHPWorkTrace pWorkTrace = null;
CECHPWork pWork = null;
if ((pWork = m_pWorkMan.GetWork(CECHPWork.Host_work_ID.WORK_TRACEOBJECT)) != null)
{
pWorkTrace = pWork as CECHPWorkTrace;
}
else if ((pWork = m_pWorkMan.GetWork(CECHPWork.Host_work_ID.WORK_HACKOBJECT)) != null)
{
if ((pWork as CECHPWorkMelee).GetTarget() == idTarget)
return false; // Host is attacking the target
pWorkTrace = (CECHPWorkTrace)m_pWorkMan.CreateWork(CECHPWork.Host_work_ID.WORK_TRACEOBJECT);
bStartNewWork = true;
}
else if (m_pWorkMan.CanStartWork(CECHPWork.Host_work_ID.WORK_TRACEOBJECT))
{
pWorkTrace = (CECHPWorkTrace)m_pWorkMan.CreateWork(CECHPWork.Host_work_ID.WORK_TRACEOBJECT);
bStartNewWork = true;
}
if (pWorkTrace != null)
{
pWorkTrace.SetTraceTarget(
pWorkTrace.CreatTraceTarget(idTarget, CECHPWorkTrace.Trace_reason.TRACE_ATTACK, bForceAttack),
bUseAutoPF);
pWorkTrace.SetMoveCloseFlag(bMoreClose);
if (bStartNewWork)
m_pWorkMan.StartWork_p1(pWorkTrace);
return true;
}
return false;
}
public int AttackableJudge(int idTarget, bool bForceAttack)
{
if (CannotAttack())
return 0;
//if (CDlgAutoHelp::IsAutoHelp())
// return 0;
if (idTarget == 0 || idTarget == m_PlayerInfo.cid)
return -1;
CECObject pObject = EC_ManMessageMono.Instance.GetObject(idTarget, 1);
if (!pObject)
return -1;
// If target is pet, it's attacked possibility depends on it's monster
if (GPDataTypeHelper.ISNPCID(idTarget))
{
CECNPC pNPC = (CECNPC)pObject;
int idMaster = pNPC.GetMasterID();
if (idMaster != 0)
{
// master¿ÉÄÜÊÇhostplayer
if (idMaster == m_PlayerInfo.cid)
return 0;
//// Follow pet cannot be attacked
//if (pNPC.IsPetNPC() && ((CECPet)pNPC).IsFollowPet())
// return 0;
idTarget = idMaster;
pObject = EC_ManMessageMono.Instance.GetObject(idTarget, 1);
if (!pObject)
return -1;
}
}
int iRet = 0;
if (GPDataTypeHelper.ISNPCID(idTarget))
{
CECNPC pNPC = (CECNPC)pObject;
// If this npc is host's pet, cannot be attacked
if (pNPC.GetMasterID() == m_PlayerInfo.cid)
return 0;
// If it's a pet and can not be attacked, pet can be attacked only if it's a fighting pet
//if (pNPC.IsPetNPC() && !((CECPet)pNPC).CanBeAttacked())
// return 0;
if (IsInBattle()) // Host is in battle
{
if (InSameBattleCamp(pNPC))
iRet = 0;
else
{
if (pNPC.IsMonsterNPC())
iRet = 1;
else if (pNPC.IsServerNPC() &&
(IsInFortress() ||
pNPC.GetRoleInBattle() == 8)) // ¶Ô·þÎñÐÍNPCµÄ¹¥»÷£¬°ïÅÉ»ùµØ»ò³Çսʱ¿ÉÓÃ
iRet = 1;
else
iRet = 0;
}
}
else if (pNPC.IsServerNPC())
{
// In sanctuary we cannot attack NPCs
if (!IsPVPOpen() || m_bInSanctuary || !bForceAttack)
iRet = 0;
else
iRet = 1;
}
else // Is monster
{
iRet = 1;
}
if (iRet == 1 && pNPC.GetOwnerFaction() > 0)
{
// Õë¶Ô°ïÅÉ PVP Õ½ÕùÖнûÖ¹²¿·Ö¹¥»÷
if (GetFactionID() == pNPC.GetOwnerFaction() || // ²»¹¥»÷ͬ°ï¹Ö
pNPC.IsFactionPVPMineCar() && !CanAttackFactionPVPMineCar() || // ÎÞ·¨ÔÙ¹¥»÷Ëû°ï¿ó³µÇé¿ö
pNPC.IsFactionPVPMineBase() && !CanAttackFactionPVPMineBase())
{
// ÎÞ·¨ÔÙ¹¥»÷Ëû°ï´æ¿óµãÇé¿ö
iRet = 0;
}
}
}
else if (GPDataTypeHelper.ISPLAYERID(idTarget))
{
// Duel: allow attack only on duel opponent while in duel
if (IsInDuel() && m_pvp.idDuelOpp == idTarget)
return 1;
if (m_pvp.iDuelState == Duel_state.DUEL_ST_STOPPING && m_pvp.idDuelOpp == idTarget)
return 0;
// Other player PVP not implemented here; treat as not attackable
return 0;
}
else
{
return -1;
}
return iRet;
}
public bool CannotAttack()
{
return (m_dwLIES & (uint)Logic_Influence_Extned_states.LIES_DISABLEFIGHT) != 0;
}
public bool glb_GetForceAttackFlag(uint pdwParam)
{
/*bool bForceAttack = false;
CECInputCtrl* pInputCtrl = g_pGame.GetGameRun().GetInputCtrl();
if (pdwParam)
bForceAttack = pInputCtrl.IsCtrlPressed(*pdwParam);
else
bForceAttack = pInputCtrl.KeyIsBeingPressed(VK_CONTROL);
return bForceAttack;*/
return false;
}
// Start normal attacking to selected target
public bool CmdNormalAttack(bool bMoreClose /* false */, bool bCombo /* false */,
int idTarget /* 0 */, int iForceAtk /* -1 */)
{
// StackChecker::ACTrace(2);
// first of all see if we need to cancel sitdown work.
// if (m_pWorkMan.IsSitting())
// {
// g_pGame.GetGameSession().c2s_CmdStandUp();
// return false;
// }
if (!CanDo(ActionCanDo.CANDO_MELEE))
return false;
// if (InSlidingState())
// return false;
// if (!bCombo)
// ClearComboSkill();
if (idTarget <= 0)
idTarget = m_idSelTarget;
bool bForceAttack;
if (iForceAtk < 0)
bForceAttack = glb_GetForceAttackFlag(0);
else
bForceAttack = iForceAtk > 0 ? true : false;
// Duel: server accepts attack on opponent only with PVP/force mask
if (IsInDuel() && idTarget == m_pvp.idDuelOpp)
bForceAttack = true;
if (AttackableJudge(idTarget, bForceAttack) != 1)
return false;
return NormalAttackObject(idTarget, bForceAttack, bMoreClose);
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 9117c7fe23c427b4781d9dd334c1aba7
+265
View File
@@ -0,0 +1,265 @@
using BrewMonster.Managers;
using BrewMonster.Network;
using BrewMonster.Scripts;
using BrewMonster.UI;
using CSNetwork;
using CSNetwork.GPDataType;
using ModelRenderer.Scripts.GameData;
using PerfectWorld.Scripts;
using PerfectWorld.Scripts.Managers;
using System;
using UnityEngine;
using static BrewMonster.Scripts.CECHPWork;
namespace BrewMonster
{
public partial class CECHostPlayer
{
private void OnMsgHstNPCGreeting(ECMSG Msg)
{
cmd_npc_greeting pCmd = GPDataTypeHelper.FromBytes<cmd_npc_greeting>((byte[])Msg.dwParam1);
if (GPDataTypeHelper.ISNPCID(pCmd.idObject))
{
// רŴѧϰܵNPC
//if (CECHostSkillModel::Instance().IsSkillLearnNPC(pCmd.idObject))
//{
// CECGameUIMan* pGameUI = g_pGame.GetGameRun().GetUIManager().GetInGameUIMan();
// //m_idSevNPC = pCmd.idObject;
// //m_bTalkWithNPC = true;
// //pGameUI.GetDialog("Win_SkillAction").Show(true);
// //CDlgSkillAction* dlg = dynamic_cast<CDlgSkillAction*>(pGameUI.GetDialog("Win_SkillAction"));
// //dlg.ForceShowDialog();
// CDlgSkillAction* dlg = dynamic_cast<CDlgSkillAction*>(pGameUI.GetDialog("Win_SkillAction"));
// dlg.SetReceivedNPCGreeting(true);
// return;
//}
CECNPC pNPC = EC_ManMessageMono.Instance.CECNPCMan.GetNPC(pCmd.idObject);
if (!pNPC || !pNPC.IsServerNPC())
{
return;
}
// Check distance again
if (!CanTouchTarget(pNPC.GetPos(), pNPC.GetTouchRadius(), 3))
return;
m_idSevNPC = pCmd.idObject;
m_bTalkWithNPC = true;
// Check way point service on NPC
//TODO: Fix later
//var dwID = (pNPC as CECNPCServer).GetWayPointID();
//if (dwID != null && !HasWayPoint(dwID))
//UnityGameSession.c2s_CmdNPCSevWaypoint();
//g_pGame.GetGameSession().c2s_CmdNPCSevWaypoint();
var pGameUI = EC_Game.GetGameRun().GetUIManager().GetInGameUIMan();
NPC_ESSENCE? result = (pNPC as CECNPCServer).GetDBEssence();
if (result != null)
{
pGameUI.PopupNPCDialog(result.Value);
}
}
//else if (GPDataTypeHelper.ISPLAYERID(pCmd.idObject))
//{
// EC_ElsePlayer pPlayer = m_pPlayerMan.GetElsePlayer(pCmd.idObject);
// // Check distance again
// if (!pPlayer || !CanTouchTarget(pPlayer.GetPos(), 0.0f, 3))
// return;
// m_idSevNPC = pCmd.idObject;
// m_bTalkWithNPC = true;
// m_iBoothState = 3;
// g_pGame.GetGameSession().c2s_CmdNPCSevGetContent(GP_NPCSEV_BOOTHSELL);
// m_pBuyPack.RemoveAllItems();
// m_pSellPack.RemoveAllItems();
// m_pEPBoothBPack.RemoveAllItems();
// m_pEPBoothSPack.RemoveAllItems();
// CECGameUIMan* pGameUI = g_pGame.GetGameRun().GetUIManager().GetInGameUIMan();
// pGameUI.PopupBoothDialog(true, false, pCmd.idObject);
//}
else
{
return;
}
}
private void OnMsgPlayerDoEmote(ECMSG Msg)
{
if (!m_pWorkMan.IsStanding() &&
!m_pWorkMan.IsBeingBound())
return;
int cmd = Convert.ToInt32(Msg.dwParam2);
if (cmd == CommandID.OBJECT_DO_EMOTE)
{
cmd_object_do_emote pCmd = GPDataTypeHelper.FromBytes<cmd_object_do_emote>((byte[])Msg.dwParam1);
DoEmote(pCmd.emotion);
// if( m_iBuddyId )
// {
// CECPlayer pBuddy = m_pPlayerMan.GetPlayer(m_iBuddyId);
// if (pBuddy)
// pBuddy.DoEmote(pCmd.emotion);
// }
GetTaskInterface().SetEmotion(pCmd.emotion);
}
else if (cmd == CommandID.OBJECT_EMOTE_RESTORE)
{
CECHPWork pWork = m_pWorkMan.GetRunningWork((int)WorkID.WORK_STAND);
if (pWork != null)
{
((CECHPWorkStand)pWork).SetPoseAction((int)PLAYER_ACTION_TYPE.ACT_STAND, false);
}
}
}
// Do emote action
private bool DoEmote(int idEmote)
{
if (!m_pWorkMan.IsStanding())
return false;
CECHPWorkStand pWork = m_pWorkMan.GetRunningWork(Host_work_ID.WORK_STAND) as CECHPWorkStand;
if (pWork == null)
{
Debug.LogError("Null CECHPWorkStand");
}
int iAction = (int)PLAYER_ACTION_TYPE.ACT_STAND;
bool bSession = false;
// Select action according to pose
switch (idEmote)
{
case (int)RoleExpression.ROLEEXP_WAVE: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_WAVE; break;
case (int)RoleExpression.ROLEEXP_NOD: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_NOD; break;
case (int)RoleExpression.ROLEEXP_SHAKEHEAD: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_SHAKEHEAD; break;
case (int)RoleExpression.ROLEEXP_SHRUG: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_SHRUG; break;
case (int)RoleExpression.ROLEEXP_LAUGH: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_LAUGH; break;
case (int)RoleExpression.ROLEEXP_ANGRY: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_ANGRY; break;
case (int)RoleExpression.ROLEEXP_STUN: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_STUN; break;
case (int)RoleExpression.ROLEEXP_DEPRESSED: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_DEPRESSED; break;
case (int)RoleExpression.ROLEEXP_KISSHAND: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_KISSHAND; break;
case (int)RoleExpression.ROLEEXP_SHY: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_SHY; break;
case (int)RoleExpression.ROLEEXP_SALUTE: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_SALUTE; break;
case (int)RoleExpression.ROLEEXP_SITDOWN:
iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_SITDOWN;
bSession = true;
break;
case (int)RoleExpression.ROLEEXP_ASSAULT: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_ASSAULT; break;
case (int)RoleExpression.ROLEEXP_THINK: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_THINK; break;
case (int)RoleExpression.ROLEEXP_DEFIANCE: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_DEFIANCE; break;
case (int)RoleExpression.ROLEEXP_VICTORY: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_VICTORY; break;
case (int)RoleExpression.ROLEEXP_GAPE: iAction = (int)PLAYER_ACTION_TYPE.ACT_GAPE; break;
case (int)RoleExpression.ROLEEXP_KISS: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_KISS; break;
case (int)RoleExpression.ROLEEXP_FIGHT: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_FIGHT; break;
case (int)RoleExpression.ROLEEXP_ATTACK1: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_ATTACK1; break;
case (int)RoleExpression.ROLEEXP_ATTACK2: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_ATTACK2; break;
case (int)RoleExpression.ROLEEXP_ATTACK3: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_ATTACK3; break;
case (int)RoleExpression.ROLEEXP_ATTACK4: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_ATTACK4; break;
case (int)RoleExpression.ROLEEXP_DEFENCE: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_DEFENCE; break;
case (int)RoleExpression.ROLEEXP_FALL: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_FALL; break;
case (int)RoleExpression.ROLEEXP_FALLONGROUND:
iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_FALLONGROUND; break;
case (int)RoleExpression.ROLEEXP_LOOKAROUND:
iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_LOOKAROUND; break;
case (int)RoleExpression.ROLEEXP_DANCE: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_DANCE; break;
case (int)RoleExpression.ROLEEXP_FASHIONWEAPON:
iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_FASHIONWEAPON; break;
case (int)RoleExpression.ROLEEXP_TWO_KISS: iAction = (int)PLAYER_ACTION_TYPE.ACT_TWO_KISS; break;
case (int)RoleExpression.ROLEEXP_FIREWORK: iAction = (int)PLAYER_ACTION_TYPE.ACT_ATTACK_TOSS; break;
default:
break;
}
pWork.SetPoseAction(iAction, bSession);
return true;
}
void OnMsgPlayerGather(ECMSG Msg)
{
int cmd = Convert.ToInt32(Msg.dwParam2);
if (cmd == CommandID.PLAYER_GATHER_START)
{
cmd_player_gather_start pCmd = GPDataTypeHelper.FromBytes<cmd_player_gather_start>((byte[])Msg.dwParam1);
EC_ManMatter pMatterMan = EC_ManMessageMono.Instance.GetECManMatter;//g_pGame.GetGameRun().GetWorld().GetMatterMan();
CECMatter pMatter = pMatterMan.GetMatter(pCmd.mid);
// if (pMatter && pMatter.IsMonsterSpiritMine()) {
// CECHPWorkUse* pWork = (CECHPWorkUse*)m_pWorkMan.CreateWork(CECHPWork::WORK_USEITEM);
// if (pWork) {
// pWork.SetParams(pCmd.mid, pCmd.use_time * 1000, pCmd.mid, true);
// m_pWorkMan.StartWork_p1(pWork);
// }
// StartMonsterSpiritConnectGfx(pCmd.mid, pMatter.GetPos());
// } else {
EC_HPWorkPick pWork = (EC_HPWorkPick)m_pWorkMan.CreateWork(Host_work_ID.WORK_PICKUP);
if (pWork != null)
{
pWork.SetGather(true, pMatter ? pMatter.GetTemplateID() : 0);
m_pWorkMan.StartWork_p1(pWork);
}
// }
// Start time counter
m_GatherCnt.SetPeriod(pCmd.use_time * 1000);
m_GatherCnt.Reset();
}
else if (cmd == CommandID.PLAYER_GATHER_STOP)
{
cmd_player_gather_stop pCmd = GPDataTypeHelper.FromBytes<cmd_player_gather_stop>((byte[])Msg.dwParam1);
m_pWorkMan.FinishRunningWork(Host_work_ID.WORK_PICKUP);
m_pWorkMan.FinishRunningWork(Host_work_ID.WORK_USEITEM);
// StopMonsterSpiritConnectGfx();
var pDlg = EC_Game.GetGameRun().GetUIManager().GetInGameUIMan().GetDialog("Win_Prgs2");
if (pDlg == null)
{
BMLogger.LogError("Null Win_Prgs2");
return;
}
if (pDlg is not DlgWinPrgs2 dlgWinPrgs)
{
BMLogger.LogError("Can not cast Win_Prgs2");
return;
}
dlgWinPrgs.SetActiveProgress(false);
}
else if (cmd == CommandID.MINE_GATHERED)
{
cmd_mine_gathered pCmd = GPDataTypeHelper.FromBytes<cmd_mine_gathered>((byte[])Msg.dwParam1);
// ASSERT(pCmd && pCmd.player_id == m_PlayerInfo.cid);
elementdataman pDataMan = EC_Game.GetElementDataMan();
DATA_TYPE DataType = pDataMan.get_data_type((uint)pCmd.item_type, ID_SPACE.ID_SPACE_ESSENCE);
if (DataType == DATA_TYPE.DT_MONSTER_SPIRIT_ESSENCE)
{
// StartMonsterSpiritBallGfx();
// m_CardHolder.gain_times++;
}
}
}
// Is doing session pose ?
private bool DoingSessionPose()
{
var pCurWork = m_pWorkMan.GetRunningWork(Host_work_ID.WORK_STAND);
if (pCurWork != null)
{
if (((CECHPWorkStand)pCurWork).DoingSessionPose())
{
return true;
}
}
return false;
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: e28dd00d9a790bb4eb9e05f52c4e6aba
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 9c5087cf8a535ec4db0686ae8fba0ecf
+69
View File
@@ -0,0 +1,69 @@
using BrewMonster.Managers;
using BrewMonster.Network;
using CSNetwork;
using CSNetwork.GPDataType;
using System.Runtime.InteropServices;
namespace BrewMonster
{
public partial class CECHostPlayer
{
private void OnMsgHstJoinTeam(ECMSG Msg)
{
var data = (byte[])Msg.dwParam1;
if (data == null || data.Length < Marshal.SizeOf<cmd_team_join_team>()) return;
var pCmd = GPDataTypeHelper.FromBytes<cmd_team_join_team>(data);
var pTeamMan = CECGameRun.Instance?.GetTeamMan();
if (pTeamMan == null) return;
var pTeam = pTeamMan.GetTeam(pCmd.idLeader);
if (pTeam == null)
pTeam = pTeamMan.CreateTeam(pCmd.idLeader);
if (pTeam == null) return;
if (pCmd.idLeader == m_PlayerInfo.cid)
pTeam.AddMember(pCmd.idLeader);
pTeam.SetPickupFlag(pCmd.wPickFlag);
SetTeam(pTeam);
NotifyUIUpdateTeam();
}
private void OnMsgHstLeaveTeam(ECMSG Msg)
{
var data = (byte[])Msg.dwParam1;
if (data == null || data.Length < Marshal.SizeOf<cmd_team_leave_party>()) return;
var pCmd = GPDataTypeHelper.FromBytes<cmd_team_leave_party>(data);
if (m_pTeam == null) return;
var pTeamMan = CECGameRun.Instance?.GetTeamMan();
if (pTeamMan != null)
pTeamMan.ReleaseTeam(pCmd.idLeader);
SetTeam(null);
NotifyUIUpdateTeam();
}
private void OnMsgHstNewTeamMem(ECMSG Msg)
{
var data = (byte[])Msg.dwParam1;
if (data == null || data.Length < Marshal.SizeOf<cmd_team_new_member>()) return;
var pCmd = GPDataTypeHelper.FromBytes<cmd_team_new_member>(data);
if (m_pTeam == null) return;
int cid = pCmd.idMember;
m_pTeam.AddMember(cid);
m_pTeam.AddUnknownID(cid);
if (EC_ManMessageMono.Instance?.GetECManPlayer?.GetPlayer(cid, 0) == null && UnityGameSession.Instance != null)
UnityGameSession.c2s_CmdTeamMemberPos(1, new[] { cid });
NotifyUIUpdateTeam();
}
private void OnMsgHstTeamMemberData(ECMSG Msg)
{
var data = (byte[])Msg.dwParam1;
if (data == null) return;
try
{
var (header, members) = GPDataTypeHelper.ParseTeamMemberData(data);
if (m_pTeam == null || header.idLeader != m_pTeam.GetLeaderID()) return;
m_pTeam.UpdateTeamData(header, members);
NotifyUIUpdateTeam();
}
catch { }
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 2c86a928789ee0f47861a6e0948ad971
+170
View File
@@ -0,0 +1,170 @@
using BrewMonster.Network;
using BrewMonster.Scripts;
using BrewMonster.Scripts.Pet;
using BrewMonster.UI;
using CSNetwork;
using CSNetwork.GPDataType;
using System;
using System.Runtime.InteropServices;
using BrewMonster.Assets.PerfectWorld.Scripts.Players;
using UnityEngine;
using static BrewMonster.Scripts.Pet.CECPetData;
namespace BrewMonster
{
public partial class CECHostPlayer
{
private void OnMsgPlayerFly(ECMSG Msg)
{
if (Convert.ToInt32(Msg.dwParam2) == CommandID.OBJECT_TAKEOFF)
{
if ((m_dwStates & PlayerNPCState.GP_STATE_FLY) == 0)
{
m_dwStates |= PlayerNPCState.GP_STATE_FLY;
m_bRushFly = false;
CECHPWorkFly pWork = (CECHPWorkFly)m_pWorkMan.CreateWork(CECHPWork.Host_work_ID.WORK_FLYOFF);
if (m_pWorkMan.IsFreeFalling())
{
pWork.m_bContinueFly = true;
m_pWorkMan.StartWork_p1(pWork);
}
else
{
pWork.m_bContinueFly = false;
m_pWorkMan.StartWork_p2(pWork);
}
}
}
else if (Convert.ToInt32(Msg.dwParam2) == CommandID.OBJECT_LANDING)
{
if ((m_dwStates & PlayerNPCState.GP_STATE_FLY) != 0)
{
m_dwStates &= ~(uint)PlayerNPCState.GP_STATE_FLY;
if (IsDead() || m_bCandHangerOn || IsHangerOn())
ShowWing(false);
else
{
CECHPWorkFall pWork =
(CECHPWorkFall)m_pWorkMan.CreateWork(CECHPWork.Host_work_ID.WORK_FREEFALL);
pWork.SetFallType(CECHPWorkFall.Fall_type.TYPE_FLYFALL);
m_pWorkMan.StartWork_p1(pWork);
}
// Below two lines will fix the "host stand in air" bug.
m_iMoveEnv = Move_environment.MOVEENV_GROUND;
m_CDRInfo.vTPNormal.Clear();
}
}
else // HOST_RUSH_FLY
{
cmd_host_rush_fly pCmd = GPDataTypeHelper.FromBytes<cmd_host_rush_fly>((byte[])Msg.dwParam1);
m_bRushFly = pCmd.is_active != 0 ? true : false;
}
}
/* Is host operating pet ?
return value:
0: host doesn't operating pet.
1: host is summoning pet.
2: host is recalling pet.
3: host is banishing pet.
*/
public int IsOperatingPet()
{
if (m_pWorkMan == null)
{
return 0;
}
CECHPWorkConcentrate pWork = (m_pWorkMan.GetRunningWork(CECHPWork.Host_work_ID.WORK_CONCENTRATE)) as CECHPWorkConcentrate;
if (pWork != null)
{
if (pWork.GetDoWhat() == (int)CECHPWorkConcentrate.eDO_PET.DO_SUMMONPET)
return 1;
else if (pWork.GetDoWhat() == (int)CECHPWorkConcentrate.eDO_PET.DO_RECALLPET)
return 2;
else if (pWork.GetDoWhat() == (int)CECHPWorkConcentrate.eDO_PET.DO_BANISHPET)
return 3;
else if (pWork.GetDoWhat() == (int)CECHPWorkConcentrate.eDO_PET.DO_RESTOREPET)
return 4;
}
return 0;
}
// Summon pet
public bool SummonPet(int iPetIdx)
{
if (m_pActionSwitcher != null)
m_pActionSwitcher.PostMessge((int)EMsgActionSwitcher.MSG_MOUNTPET);
CECGameRun pGameRun = EC_Game.GetGameRun();
CECUIManager pGameUI = pGameRun.GetUIManager();
CECPetData pPet = m_pPetCorral.GetPetData(iPetIdx);
if (pPet == null)
return false;
if (!CanDo(ActionCanDo.CANDO_SUMMONPET))
return false;
// Couldn't summon daed pet
if (pPet.IsDead())
{
//pGameRun.AddFixedMessage(FIXMSG_PET_DEAD);
//Debug.LogError("FIXMSG_PET_DEAD");
pGameUI.ShowMessageBox("MessageBox", "PET_DEAD", MessageBoxType.YesButton);
return false;
}
// If host could't stop naturally, cancel summoning
if (!NaturallyStopMoving())
return false;
// ¼ì²éµ±Ç°ÊÇ·ñ½ûÖ¹ÕÙ»½Æï³è
if (pPet.IsMountPet() && m_playerLimits[(int)PLAYER_LIMIT.PLAYER_LIMIT_NOMOUNT])
return false;
if (m_ReincarnationCount != 0)
{
int iLevelRequired = pPet.GetLevel() - 35 - m_ReincarnationCount * 5;
if (m_BasicProps.iLevel < iLevelRequired)
{
if (pGameUI != null)
{
string strText = "";
strText = string.Format(pGameUI.GetInGameUIMan().GetStringFromTable(10787), iLevelRequired);
pGameUI.ShowMessageBox("MessageBox", strText, MessageBoxType.YesButton);
}
return false;
}
}
UnityGameSession.c2s_CmdPetSummon(iPetIdx);
return true;
}
// Recall pet
public bool RecallPet()
{
if (m_pActionSwitcher != null)
m_pActionSwitcher.PostMessge((int)EMsgActionSwitcher.MSG_MOUNTPET);
// If host could't stop naturally, cancel recalling
if (!NaturallyStopMoving())
return false;
UnityGameSession.c2s_CmdPetRecall();
return true;
}
// Get pet operation time counter
public CECCounter GetPetOptTime() { return m_PetOptCnt; }
public CECPetCorral GetPetCorral()
{
return m_pPetCorral;
}
}
}
+2
View File
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 199b19ff05aa30049aca1caf465398f0
@@ -0,0 +1,79 @@
using CSNetwork;
using CSNetwork.GPDataType;
namespace BrewMonster
{
public partial class CECHostPlayer
{
void OnMsgHstExtProp(ECMSG Msg)
{
cmd_own_ext_prop pCmd = GPDataTypeHelper.FromBytes<cmd_own_ext_prop>((byte[])Msg.dwParam1);
m_ExtProps = pCmd.prop;
m_BasicProps.iStatusPt = (int)pCmd.status_point;
m_BasicProps.iAtkDegree = pCmd.attack_degree;
m_BasicProps.iDefDegree = pCmd.defend_degree;
m_BasicProps.iCritRate = pCmd.crit_rate;
m_BasicProps.iCritDamageBonus = pCmd.crit_damage_bonus;
m_BasicProps.iInvisibleDegree = pCmd.invisible_degree;
m_BasicProps.iAntiInvisibleDegree = pCmd.anti_invisible_degree;
m_BasicProps.iPenetration = pCmd.penetration;
m_BasicProps.iResilience = pCmd.resilience;
m_BasicProps.iVigour = pCmd.vigour;
}
private void OnMsgHstInfo00(in ECMSG Msg)
{
cmd_self_info_00 pCmd = GPDataTypeHelper.FromBytes<cmd_self_info_00>((byte[])Msg.dwParam1);
bool bFirstTime = m_BasicProps.iLevel == 0 ? true : false;
if (!bFirstTime)
{
int iLimit = (int)(pCmd.iMaxHP * 0.3f);
if (pCmd.iHP < m_BasicProps.iCurHP && m_BasicProps.iCurHP >= iLimit && pCmd.iHP < iLimit)
{
/*if (CECUIHelper::GetGameUIMan().IsShowLowHP()) {
// ѪÁ¿µÍÓÚÁÙ½çÖµÔò²¥·ÅÌØÐ§
const int GfxLastTime = 10000; // ³ÖÐøÊ±¼ä10Ãë
CECUIHelper::GetGameUIMan().GetScreenEffectMan().StartEffect(CECScreenEffect::EFFECT_REDSPARK, GfxLastTime);
}*/
}
/*if (pCmd.iHP >= iLimit || pCmd.iHP <= 0) {
// ѪÁ¿¸ßÓÚÁÙ½çÖµ»òËÀÍö£¬ÔòÍ£Ö¹²¥·ÅÌØÐ§
CECUIHelper::GetGameUIMan().GetScreenEffectMan().FinishEffect(CECScreenEffect::EFFECT_REDSPARK);
}*/
/*iLimit = (int)(pCmd.iMaxMP * 0.2f);
if (pCmd.iMP < m_BasicProps.iCurMP && m_BasicProps.iCurMP >= iLimit && pCmd.iMP < iLimit)
BubbleText(BUBBLE_MPWARN, 0);*/
/*if (m_ExtProps.max_ap != pCmd.iMaxAP)
g_pGame.GetGameRun().AddFixedMessage(FIXMSG_ADDMAXAP, pCmd.iMaxAP - m_ExtProps.max_ap);*/
}
m_BasicProps.iLevel = pCmd.sLevel;
SetLevel2(pCmd.Level2, bFirstTime);
m_BasicProps.iExp = pCmd.iExp;
m_BasicProps.iSP = pCmd.iSP;
m_BasicProps.iCurHP = pCmd.iHP;
m_BasicProps.iCurMP = pCmd.iMP;
m_BasicProps.iCurAP = pCmd.iAP;
m_ExtProps.bs.max_hp = pCmd.iMaxHP;
m_ExtProps.bs.max_mp = pCmd.iMaxMP;
m_ExtProps.max_ap = pCmd.iMaxAP;
EventBus.Publish(new EXPToUpLevel(GetLevelUpExp(pCmd.sLevel)));
EventBus.Publish<cmd_self_info_00>(pCmd);
EventBus.PublishChannel<cmd_self_info_00>(GetCharacterID(), pCmd);
// if (pCmd.State != 0 && m_bFight == false) PlayEnterBattleGfx();
m_bFight = pCmd.State != 0 ? true : false;
// UpdateGodEvilSprite();
/*CECGameUIMan* pGameUI = g_pGame.GetGameRun().GetUIManager().GetInGameUIMan();
CDlgAutoHelp *pDlgHelp = dynamic_cast<CDlgAutoHelp *>(pGameUI.GetDialog("Win_WikiPop"));*/
/*if(pDlgHelp && m_bFight)
pDlgHelp.SetAutoHelpState(false);*/
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: a19218082b79eef4687286340cd52157
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: c8ab82b5b1e1aee45a936ba119de3444
+263
View File
@@ -0,0 +1,263 @@
using BrewMonster.Network;
using BrewMonster.Scripts;
using CSNetwork;
using CSNetwork.GPDataType;
using System.Runtime.InteropServices;
using Cysharp.Threading.Tasks;
using UnityEngine;
using static BrewMonster.Scripts.CECHPWork;
namespace BrewMonster
{
public partial class CECHostPlayer
{
public void OnMsgHstCorrectPos(in ECMSG Msg)
{
//Debug.LogError("HoangDev : OnMsgHstCorrectPos");
byte[] buf = (byte[])Msg.dwParam1; // chỗ bạn lưu pDataBuf
GCHandle handle = GCHandle.Alloc(buf, GCHandleType.Pinned);
cmd_host_correct_pos pCmd = (cmd_host_correct_pos)Marshal.PtrToStructure(
handle.AddrOfPinnedObject(), typeof(cmd_host_correct_pos));
handle.Free();
//cmd_host_correct_pos pCmd = GPDataTypeHelper.FromBytes<cmd_host_correct_pos>((byte[])Msg.dwParam1);
Debug.LogError("HoangDev :pCmd.pos " + pCmd.pos);
SetPos(pCmd.pos);
m_vVelocity.Clear();
m_CDRInfo.vAbsVelocity.Clear();
m_MoveCtrl.SetMoveStamp(pCmd.stamp);
}
public void OnMsgHstGoto(in ECMSG Msg)
{
PopupManager.Instance.OnPlayerRevived();
// p1 is a byte[] buffer; parse into cmd_notify_hostpos then set position
// p1 是一个 byte[] 缓冲区;解析为 cmd_notify_hostpos 然后设置位置
byte[] buf = (byte[])Msg.dwParam1;
cmd_notify_hostpos pCmd = GPDataTypeHelper.FromBytes<cmd_notify_hostpos>(buf);
int idInst = pCmd.tag;
Vector3 vPos = new Vector3(pCmd.vPos.x, pCmd.vPos.y, pCmd.vPos.z);
int iLine = pCmd.line;
// Call Goto method to properly handle teleportation
// 调用 Goto 方法来正确处理传送
if (!Goto(idInst, vPos, iLine))
{
BMLogger.LogError($"OnMsgHstGoto: Failed to teleport to instance {idInst}");
return;
}
}
void OnMsgHstWayPoint(ECMSG Msg)
{
//CECGameUIMan pGameUI = EC_Game.GetGameRun().GetUIManager().GetInGameUIMan();
//if (Convert.ToInt32(Msg.dwParam2) == CommandID.ACTIVATE_WAYPOINT)
//{
// cmd_activate_waypoint pCmd = GPDataTypeHelper.FromBytes<cmd_activate_waypoint>((byte[])Msg.dwParam1);
// m_aWayPoints.Add(pCmd.waypoint);
// // add to waypoints array
// pGameUI.GetMapDlgsMgr().UpdateWayPoints(&pCmd.waypoint, 1, false);
// // Print a notify message
// const CECMapDlgsMgr::PointMap& aWayPoints = pGameUI.GetMapDlgsMgr().GetTransPoint();
// CECMapDlgsMgr::PointMap::const_iterator itr = aWayPoints.find(pCmd.waypoint);
// if(itr != aWayPoints.end())
// {
// g_pGame.GetGameRun().AddFixedMessage(FIXMSG_NEWWAYPOINT, (itr.second).strName);
// bool bCanPopUITips = true;
// int count = CECUIConfig::Instance().GetGameUI().GetTaskIDDisableWayPointsUITipsCount();
// // ¼ì²éÉíÉÏÊÇ·ñÓнûÖ¹µ¯³ötipsµÄÈÎÎñ
// for (int i=0;i<count;i++){
// int taskID = CECUIConfig::Instance().GetGameUI().GetTaskIDDisableWayPointsUITips(i);
// if(GetTaskInterface() && GetTaskInterface().HasTask(taskID)){
// bCanPopUITips = false;
// break;
// }
// }
// // µ¯³ötips
// CECScriptMan* pScriptMan = g_pGame.GetGameRun().GetUIManager().GetScriptMan();
// if (pScriptMan && bCanPopUITips)
// {
// pScriptMan.GetContext().GetUI().SetTipDialogTitleAndContent(AC2AS_CP(CP_UTF8, pGameUI.GetStringFromTable(11350)), AC2AS_CP(CP_UTF8, (itr.second).strName));
// pScriptMan.GetContext().GetUI().ShowTip(500, 500, 5000, 300);
// }
// }
// }
// else if (Msg.dwParam2 == WAYPOINT_LIST)
// {
// cmd_waypoint_list* pCmd = (cmd_waypoint_list*)Msg.dwParam1;
// m_aWayPoints.SetSize(pCmd.count, 16);
// for (size_t i = 0; i < pCmd.count; i++)
// m_aWayPoints[i] = pCmd.list[i];
// // update the whole list
// pGameUI.GetMapDlgsMgr().UpdateWayPoints(pCmd.list, pCmd.count, true);
// }
}
private void OnMsgHstPressCancel(ECMSG Msg)
{
CECHPWork pCurWork = null;
pCurWork = m_pWorkMan.GetRunningWork(Host_work_ID.WORK_TRACEOBJECT);
if (pCurWork is CECHPWorkTrace workTrace)
{
workTrace.PressCancel();
return;
}
pCurWork = m_pWorkMan.GetRunningWork(Host_work_ID.WORK_HACKOBJECT);
if (pCurWork != null)
{
UnityGameSession.c2s_CmdCancelAction();
return;
}
pCurWork = m_pWorkMan.GetRunningWork(Host_work_ID.WORK_USEITEM);
if (pCurWork != null)
{
UnityGameSession.c2s_CmdCancelAction();
return;
}
pCurWork = m_pWorkMan.GetRunningWork(Host_work_ID.WORK_SPELLOBJECT);
if (pCurWork != null)
{
int iState = ((CECHPWorkSpell)pCurWork).GetState();
if (iState == CECHPWorkSpell.Spell_magic_state.ST_INCANT)
{
UnityGameSession.c2s_CmdCancelAction();
return;
}
}
pCurWork = m_pWorkMan.GetRunningWork(Host_work_ID.WORK_PICKUP);
if (pCurWork != null)
{
if (((EC_HPWorkPick)pCurWork).IsGather())
{
UnityGameSession.c2s_CmdCancelAction();
return;
}
}
//todo: handle this part
// pCurWork = m_pWorkMan.GetRunningWork(Host_work_ID.WORK_CONCENTRATE);
// if (pCurWork !=null){
// if (IsOperatingPet()){
// UnityGameSession.c2s_CmdCancelAction();
// return;
// }
// }
// pCurWork = m_pWorkMan.GetRunningWork(Host_work_ID.WORK_CONGREGATE);
// if (pCurWork !=null){
// if (IsCongregating()){
// UnityGameSession.c2s_CmdCancelAction();
// return;
// }
// }
if (m_bUsingTrashBox || DoingSessionPose())
{
UnityGameSession.c2s_CmdCancelAction();
return;
}
// Cancel current selection
if (m_idSelTarget > 0)
{
SelectTarget(0);
return;
}
// Some work have lower priority
pCurWork = m_pWorkMan.GetRunningWork(Host_work_ID.WORK_MOVETOPOS);
if (pCurWork != null)
{
((CECHPWorkMove)pCurWork).PressCancel();
return;
}
}
public void StopMovement()
{
m_MoveCtrl.SendStopMoveCmd(playerTransform.position, 5f, (int)GPMoveMode.GP_MOVE_WALK);
}
// Return to a target town through skill
// 通过技能返回目标城镇
// This method implements the Goto logic from the original C++ code
// 此方法实现了原始 C++ 代码中的 Goto 逻辑
private bool Goto(int idInst, Vector3 vPos, int iParallelWorldID)
{
// Jump to instance (change world/instance)
// 跳转到实例(更改世界/实例)
// Note: JumpToInstance is currently a stub in CECGameRun, so we skip the call for now
// 注意:JumpToInstance 目前在 CECGameRun 中是一个存根,所以我们现在跳过调用
// if (CECGameRun.Instance != null && !CECGameRun.Instance.JumpToInstance(idInst, vPos, iParallelWorldID))
// {
// Debug.LogError($"CECHostPlayer::Goto, Failed to jump to instance {idInst}");
// return false;
// }
// Stop all current work and goto specified position
// 停止所有当前工作并转到指定位置
if (m_pWorkMan != null)
{
// Stop auto-moving if active
// 如果正在自动移动则停止
// Note: IsAutoMoving check would go here if available
// 注意:如果可用,IsAutoMoving 检查将放在这里
// Finish all work
// 完成所有工作
m_pWorkMan.FinishAllWork(true);
}
// Add a little height to ensure player's AABB won't embed with building
// 增加一点高度以确保玩家的 AABB 不会嵌入建筑物
vPos.y += 0.1f;
// Ensure we are not under ground (terrain height check would go here)
// 确保我们不会在地下(地形高度检查将放在这里)
// Note: Terrain height check is skipped for now as it requires world access
// 注意:暂时跳过地形高度检查,因为它需要世界访问
// Set position
// 设置位置
SetPos(vPos);
// Reset jump state if available
// 如果可用则重置跳跃状态
// ResetJump(); // Uncomment if ResetJump method exists
// Update camera if available
// 如果可用则更新相机
// UpdateFollowCamera(false, 10); // Uncomment if UpdateFollowCamera method exists
LitModelHolder.Instance.LoadAllObjectsNearTargetPosition(vPos).Forget();
return true;
}
public void SetStatusRun(bool value)
{
if (!isGrounded)
{
Debug.LogError("Player not in ground");
return;
}
isRun = value;
}
public bool IsPlayerMoving()
{
return m_pWorkMan.IsMoving();
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 570900be694cc7c4c9c0fc5c399c9a25
File diff suppressed because it is too large Load Diff
+78 -25
View File
@@ -22,6 +22,7 @@ public class CECUIManager : MonoSingleton<CECUIManager>
[SerializeField] private int currentTargetNPCID;
CECGameUIMan gameUI;
AUIManager aUIManager;
AUIDialog _dlgPlayerOptions;
[SerializeField] private DialogScriptTableObject dialogResouce;
[SerializeField] private Canvas canvasDlg;
@@ -33,11 +34,16 @@ public class CECUIManager : MonoSingleton<CECUIManager>
Sprite[] m_iconlistIvtr;
private CDlgInfoTooltip m_pDlgSkillTooltip;
// Task update timer / 任务更新计时器
private float _nextTaskUpdateTime = 0f;
private const float TASK_UPDATE_INTERVAL = .1f;
protected override void Awake()
{
base.Awake();
EventBus.Subscribe<CECHostPlayer.NPCINFO>(ShowUINPC);
EventBus.Subscribe<CECHostPlayer.TargetHUDClearEvent>(OnTargetHUDClear);
EventBus.Subscribe<NPCDiedEvent>(TryHideUINPC);
EventBus.Subscribe<MessageBoxEvent>(OnMessageBox);
@@ -58,22 +64,69 @@ public class CECUIManager : MonoSingleton<CECUIManager>
// _fpsText.text = $"{Mathf.RoundToInt(1f / Time.deltaTime)}";
if (m_pDlgQuickBar1 != null)
{ m_pDlgQuickBar1.UpdateShortcuts(); }
// Periodically update task UI (DlgTask and DlgTaskTrace) / 定期更新任务UIDlgTask和DlgTaskTrace
if (Time.unscaledTime >= _nextTaskUpdateTime)
{
_nextTaskUpdateTime = Time.unscaledTime + TASK_UPDATE_INTERVAL;
UpdateTaskUI();
}
}
/// <summary>
/// Update task UI from DlgTask and DlgTaskTrace / 从DlgTask和DlgTaskTrace更新任务UI
/// </summary>
private void UpdateTaskUI()
{
try
{
var inGameUIMan = GetInGameUIMan();
if (inGameUIMan == null) return;
var dlgTaskDialog = inGameUIMan.GetDialog("Win_Quest");
var dlgTaskTraceDialog = inGameUIMan.GetDialog("Win_QuestMinion");
if (dlgTaskDialog != null && dlgTaskDialog is BrewMonster.Scripts.Task.UI.DlgTask dlgTaskForTrace)
{
if (dlgTaskTraceDialog != null && dlgTaskTraceDialog.IsShow())
{
dlgTaskForTrace.RefreshTaskTrace();
}
dlgTaskForTrace.Tick();
}
}
catch (System.Exception)
{
// Silently handle errors to avoid spamming logs / 静默处理错误以避免日志刷屏
// Task UI update errors are handled silently / 任务UI更新错误被静默处理
}
}
private void OnDestroy()
{
EventBus.Unsubscribe<CECHostPlayer.NPCINFO>(ShowUINPC);
EventBus.Unsubscribe<CECHostPlayer.TargetHUDClearEvent>(OnTargetHUDClear);
EventBus.Unsubscribe<NPCDiedEvent>(TryHideUINPC);
EventBus.Unsubscribe<MessageBoxEvent>(OnMessageBox);
}
private void ShowUINPC(CECHostPlayer.NPCINFO obj)
{
var host = EC_Game.GetGameRun()?.GetHostPlayer();
if (host != null && host.GetSelectedTarget() != obj.IDNPC)
return;
npsUI.gameObject.SetActive(true);
npsUI.SetText($"{obj.CurrentHealth}/{obj.MaxHealth}", obj.Name, "");
npsUI.SetHealthImage((float)obj.CurrentHealth / (float)obj.MaxHealth);
string hpText = obj.MaxHealth > 0 ? $"{obj.CurrentHealth}/{obj.MaxHealth}" : "-/-";
npsUI.SetText(hpText, obj.Name ?? "", "");
float fill = obj.MaxHealth > 0 ? (float)obj.CurrentHealth / (float)obj.MaxHealth : 1f;
npsUI.SetHealthImage(fill);
currentTargetNPCID = obj.IDNPC;
}
private void OnTargetHUDClear(CECHostPlayer.TargetHUDClearEvent _)
{
npsUI.gameObject.SetActive(false);
}
public CDlgQuickBar GetCDlgQuickBar()
{
return m_pDlgQuickBar1;
@@ -108,17 +161,12 @@ public class CECUIManager : MonoSingleton<CECUIManager>
Debug.LogWarning($"Không tìm thấy UI {componentName} đã spawn trong canvasDlg. Type found: {(type != null ? type.FullName : "null")}");
}
public CDlgMessageBox ShowMessageBox(string title, string message)
public CDlgMessageBox ShowMessageBox(MessageBoxData messageBoxData)
{
var msgBox = GetInGameUIMan().GetDialog("DlgMessageBox") as CDlgMessageBox;
if (msgBox != null)
{
msgBox.ShowMessageBox(new MessageBoxData()
{
Title = title,
Message = message,
MessageBoxType = MessageBoxType.YesButton
});
msgBox.ShowMessageBox(messageBoxData);
return msgBox;
}
else
@@ -261,24 +309,19 @@ public class CECUIManager : MonoSingleton<CECUIManager>
}
}
else if(string.CompareOrdinal("Game_Disenchase",pDlg.GetName())==0 && DialogBoxCommandIDs.IDOK == iRetVal)
{
// PAUIDIALOG pMsgBox;
var clearEmbeddedChipDlg = GetInGameUIMan().GetDialog("Game_Disenchase");
// EC_IvtrItem pIvtr = (EC_IvtrItem)m_pDlgUninstall->m_pItema->GetDataPtr("ptr_CECIvtrItem");
//
// pSession.c2s_CmdNPCSevClearEmbeddedChip(
// (WORD)m_pDlgUninstall->m_pItema->GetData(), pIvtr->GetTemplateID());
//
// m_pDlgUninstall->Show(false);
// pHost->EndNPCService();
else if (pDlg is DlgInstall dlgInstall && dlgInstall.GetInstallMode == DlgInstall.InstallMode.Disenchase && DialogBoxCommandIDs.IDOK == iRetVal)
{
UnityGameSession.c2s_CmdNPCSevClearEmbeddedChip(dlgInstall.FirstSlotIndex, dlgInstall.SelectedEquip.GetTemplateID());
dlgInstall.Show(false);
pHost.EndNPCService();
// m_pCurNPCEssence = NULL;
// m_pDlgInventory->Show(false);
// pHost->GetPack(IVTRTYPE_PACK)->UnfreezeAllItems();
//
// MessageBox("", GetStringFromTable(228), MB_OK,
// A3DCOLORRGBA(255, 255, 255, 160), &pMsgBox);
// pMsgBox->SetLife(3);
pHost.GetPack((int)InventoryType.IVTRTYPE_PACK).UnfreezeAllItems();
ShowMessageBox(new MessageBoxData()
{
Message = pDlg.GetStringFromTable(228)
});
}
}
@@ -418,6 +461,16 @@ public class CECUIManager : MonoSingleton<CECUIManager>
return gameUI;
}
/// <summary>Shows the player options menu for the given character. Requires a prefab with id "DlgPlayerOptions" in DialogScriptTableObject.</summary>
public void ShowPlayerOptionsDialog(int characterId)
{
if (characterId == 0 || canvasDlg == null) return;
var gui = GetInGameUIMan();
if (_dlgPlayerOptions == null)
_dlgPlayerOptions = gui.GetDialog("DlgPlayerOptions");
_dlgPlayerOptions?.ShowForPlayer(characterId);
}
/// <summary>
/// Get the current target NPC ID (same as stored from NPCINFO event)
/// </summary>