Merge branch 'develop' into feature/hp_swim

# Conflicts:
#	Assets/Scenes/a61.unity
This commit is contained in:
TungDV
2026-01-06 22:35:23 +07:00
37 changed files with 2098 additions and 385 deletions
+19 -1
View File
@@ -5,7 +5,6 @@ using BrewMonster.Scripts.World;
using BrewMonster.UI;
using CSNetwork;
using CSNetwork.GPDataType;
using CSNetwork.GPDataType;
using CSNetwork.Protocols.RPCData;
using System.Collections.Generic;
using System.Data;
@@ -144,6 +143,25 @@ public partial class CECGameRun
BMLogger.LogError("null _playerPrefab");
return;
}
// 同步世界/地图ID给任务系统(GetPos 返回的 worldId
// English: Sync map ID to task system (worldId returned by GetPos).
// We don't receive mapId in cmd_self_info_1, so use selected RoleInfo.worldtag as current map id.
var roleInfo = UnityGameSession.Instance != null ? UnityGameSession.Instance.GetRoleInfo() : null;
if (roleInfo != null)
{
int idInst = roleInfo.worldtag;
if (idInst > 0)
{
// Ensure instance exists in table (minimal stub instance is fine for now)
if (!m_InstTab.ContainsKey(idInst))
m_InstTab.Add(idInst, new CECInstance());
// Update global world instance id used by task checks
CECWorld.Instance?.SetInstanceID(idInst);
}
}
CECPlayer.InitStaticRes();
hostPlayer = ObjectSpawner.Instance.InstantiateObject(_playerPrefab, setThisAsParent: true).AddComponent<CECHostPlayer>();
hostPlayer.InitCharacter(info);
+364 -13
View File
@@ -19,6 +19,7 @@ using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using UnityEngine;
using UnityEngine.PlayerLoop;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using static System.Net.Mime.MediaTypeNames;
@@ -101,6 +102,8 @@ namespace BrewMonster
public ON_AIR_CDR_INFO m_AirCDRInfo;
public ushort m_wMoveStamp = 0;
private CECCounter m_GatherCnt; // Gather counter
Dictionary<int, COOLTIME> m_skillCoolTime = new();
COOLTIME[] m_aCoolTimes = new COOLTIME[(int)CoolTimeIndex.GP_CT_MAX]; // Cool times
// Host config data version
const int HOSTCFG_VERSION = 11;
@@ -223,7 +226,11 @@ namespace BrewMonster
ccSkin = controller.skinWidth;
}
m_TaskCounter.SetCounter(3000f);
// 任务状态检查节流(毫秒) // Throttle task status check (milliseconds)
// NOTE: CECCounter uses "Period" as threshold; SetCounter only sets current value.
// We want task checking roughly every 3 seconds, not every frame.
m_TaskCounter.SetPeriod(3000f);
m_TaskCounter.Reset(true); // trigger first check immediately
m_bTitleDataReady = false;
playerTransform = transform;
m_GatherCnt ??= new CECCounter();
@@ -320,6 +327,8 @@ namespace BrewMonster
// track status of Task
TickTask();
// Update timers
UpdateTimers(Time.deltaTime);
m_pWorkMan?.Tick(Time.deltaTime);
@@ -329,7 +338,7 @@ namespace BrewMonster
//m_dwMoveRelDir = 0;
m_fVertSpeed = 0.0f;
UpdateTimers(Time.deltaTime);
// Auto team / Automatic party grouping
// m_pAutoTeam.Tick(Time.deltaTime);
}
@@ -488,6 +497,8 @@ namespace BrewMonster
case int value when value == EC_MsgDef.MSG_PM_PLAYERDOEMOTE: OnMsgPlayerDoEmote(Msg); break;
case int value when value == EC_MsgDef.MSG_HST_TARGETISFAR: OnMsgHstTargetIsFar(Msg); break;
case int value when value == EC_MsgDef.MSG_PM_PLAYERGATHER: OnMsgPlayerGather(Msg); break;
case int value when value == EC_MsgDef.MSG_HST_COOLTIMEDATA: OnMsgHstCoolTimeData(Msg); break;
}
@@ -511,6 +522,80 @@ namespace BrewMonster
}*/
}
private void OnMsgHstCoolTimeData(ECMSG Msg)
{
cmd_cooltime_data pCmd = default;
var data = (byte[])Msg.dwParam1;
pCmd.count = GPDataTypeHelper.FromBytes<ushort>(data, 0);
long offset = Marshal.SizeOf(typeof(ushort));
pCmd.list = new item_t[pCmd.count];
for (int i = 0; i < pCmd.count; i++)
{
pCmd.list[i] = GPDataTypeHelper.FromBytes<item_t>(data, ref offset);
}
m_skillCoolTime.Clear();
for (int i = 0; i < pCmd.count; i++)
{
item_t item = pCmd.list[i];
if (item.idx > (int)CoolTimeIndex.GP_CT_SKILL_START)
{
// Is skill cool time
int idSkill = item.idx - (int)CoolTimeIndex.GP_CT_SKILL_START;
COOLTIME ct = m_skillCoolTime[idSkill];
ct.iCurTime = item.cooldown;
ct.iMaxTime = item.max_cooltime;
Mathf.Clamp(ct.iCurTime, 0, ct.iMaxTime);
CECSkill pSkill = GetNormalSkill(idSkill);
if (pSkill != null)
{
pSkill.StartCooling(item.max_cooltime, item.cooldown);
}
/* else if (pSkill = CECComboSkillState::Instance().GetInherentSkillByID(idSkill))
{
pSkill.StartCooling(item.max_cooltime, item.cooldown);
}*/
else if (GetEquipSkillByID(idSkill) == null)
{
// Add to goblin skill list
pSkill = new CECSkill(idSkill, 1);
pSkill.StartCooling(item.max_cooltime, item.cooldown);
m_aGoblinSkills.Add(pSkill);
}
m_skillCoolTime[idSkill] = ct;
}
else if (item.idx >= 0 && item.idx < (int)CoolTimeIndex.GP_CT_MAX)
{
// Other cool time
COOLTIME ct = m_aCoolTimes[item.idx];
ct.iCurTime = item.cooldown;
ct.iMaxTime = item.max_cooltime;
Mathf.Clamp(ct.iCurTime, 0, ct.iMaxTime);
if (item.idx >= (int)CoolTimeIndex.GP_CT_SKILLCOMMONCOOLDOWN0 && item.idx <= (int)CoolTimeIndex.GP_CT_SKILLCOMMONCOOLDOWN4)
{
// other player skills should be set public cool down too.
uint mask = (uint)(1 << (item.idx - (int)CoolTimeIndex.GP_CT_SKILLCOMMONCOOLDOWN0));
for (int y = 0; y < GetPositiveSkillNum(); y++)
{
CECSkill pSkill = GetPositiveSkillByIndex(y);
if (pSkill != null && ((pSkill.GetCommonCoolDown() & mask) != 0))
pSkill.StartCooling(item.max_cooltime, item.cooldown);
}
}
}
else
{
BMLogger.LogError("item.idx >= 0: " + (item.idx >= 0));
}
}
UpdateEquipSkillCoolDown();
}
private void OnMsgEnchantResult(ECMSG msg)
{
// 从消息中获取cmd_enchant_result结构 // Get cmd_enchant_result structure from message
@@ -1101,7 +1186,7 @@ namespace BrewMonster
public bool HostIsReady()
{
return m_bEnterGame;
return m_bEnterGame;
}
private void OnMsgHstDied(in ECMSG msg)
@@ -2737,6 +2822,7 @@ namespace BrewMonster
float fMaxCut = 1.0f)
{
float fDist = A3d_Magnitude(vTargetPos - vHostPos);
BMLogger.LogError($"CanTouchTarget iReason={iReason} , m_pPrepSkill={m_pPrepSkill}");
switch (iReason)
{
case 1: // melee
@@ -2764,8 +2850,11 @@ namespace BrewMonster
{
if (m_pPrepSkill != null)
{
//TODO : Check this function GetCastRange
float fRange = m_pPrepSkill.GetCastRange(m_ExtProps.ak.AttackRange, GetPrayDistancePlus());
BMLogger.LogError($"HoangDev: CanTouchTarget fDist= {fDist}, fRange={fRange}, fDist - fTargetRad={fDist - fTargetRad}, m_ExtProps.ak.AttackRange ={m_ExtProps.ak.AttackRange}, GetPrayDistancePlus()={GetPrayDistancePlus()}");
if (fRange > 0.0f)
{
if (fDist - fTargetRad <= fRange)
@@ -2795,7 +2884,84 @@ namespace BrewMonster
return false;
}
public bool GetSkillCoolTime(int idSkill, out COOLTIME ct)
{
// 获取技能的非公共冷却时间
bool bFound = false;
ct = new COOLTIME();
if (m_skillCoolTime.TryGetValue(idSkill, out ct))
{
bFound = true;
}
return bFound;
}
// Update equipment skill cool down
// 更新装备技能冷却
public void UpdateEquipSkillCoolDown(int cooldown_index = -1)
{
if (cooldown_index < 0)
{
// 更新所有装备技能
// Update all equipment skills
for (int i = 0; i < GetEquipSkillNum(); ++i)
{
CECSkill pSkill = GetEquipSkillByIndex(i);
// 检查技能冷却
// Check skill cooldown
COOLTIME temp;
if (GetSkillCoolTime(pSkill.GetSkillID(), out temp))
{
pSkill.StartCooling(temp.iMaxTime, temp.iCurTime);
continue;
}
// 检查公共冷却
// Check common cooldown
int ccd = pSkill.GetCommonCoolDown();
if (ccd == 0) continue;
for (int j = 0; j < 5; ++j)
{
if ((ccd & (1 << j)) != 0)
{
COOLTIME ct = m_aCoolTimes[(int)CoolTimeIndex.GP_CT_SKILLCOMMONCOOLDOWN0 + j];
pSkill.StartCooling(ct.iMaxTime, ct.iCurTime);
break;
}
}
}
}
else
{
// 更新指定技能
// Update specified skill
if (cooldown_index > (int)CoolTimeIndex.GP_CT_SKILL_START)
{
int idSkill = cooldown_index - (int)CoolTimeIndex.GP_CT_SKILL_START;
CECSkill pSkill = GetEquipSkillByID(idSkill);
COOLTIME temp;
if (pSkill != null && GetSkillCoolTime(idSkill, out temp))
pSkill.StartCooling(temp.iMaxTime, temp.iCurTime);
}
else if (cooldown_index >= (int)CoolTimeIndex.GP_CT_SKILLCOMMONCOOLDOWN0 && cooldown_index <= (int)CoolTimeIndex.GP_CT_SKILLCOMMONCOOLDOWN4)
{
int index = cooldown_index - (int)CoolTimeIndex.GP_CT_SKILLCOMMONCOOLDOWN0;
COOLTIME ct = m_aCoolTimes[(int)CoolTimeIndex.GP_CT_SKILLCOMMONCOOLDOWN0 + index];
uint mask = (uint)(1 << index);
for (int i = 0; i < GetEquipSkillNum(); ++i)
{
CECSkill pSkill = GetEquipSkillByIndex(i);
int ccd = pSkill.GetCommonCoolDown();
if ((ccd & mask) != 0)
pSkill.StartCooling(ct.iMaxTime, ct.iCurTime);
}
}
}
}
public void RemoveObjectFromTabSels(CECObject pObject)
{
for (int i = 0; i < m_aTabSels.Count; i++)
@@ -3675,6 +3841,8 @@ namespace BrewMonster
return (fDist <= fTestDist);
}
public int GetPositiveSkillNum() { return m_aPtSkills.Count; }
public CECSkill GetPositiveSkillByIndex(int n) { return m_aPtSkills[n]; }
public bool UpdateEquipSkins()
{
@@ -4292,8 +4460,8 @@ namespace BrewMonster
{
if (IsDead())
{
/* CECGameUIMan pGameUI = g_pGame->GetGameRun()->GetUIManager()->GetInGameUIMan();
pGameUI->PopupReviveDialog(true);*/
/* CECGameUIMan pGameUI = g_pGame->GetGameRun()->GetUIManager()->GetInGameUIMan();
pGameUI->PopupReviveDialog(true);*/
PopupManager.Instance.OnPlayerDied();
}
m_bEnterGame = true;
@@ -5073,15 +5241,13 @@ namespace BrewMonster
}
// Is gathering resources
bool IsGathering()
public bool IsGathering()
{
if(m_pWorkMan == null) return false;
CECHPWork pWork = m_pWorkMan.GetRunningWork(Host_work_ID.WORK_PICKUP);
if (pWork != null)
return ((EC_HPWorkPick)pWork).IsGather();
return false;
// TODO: fix later
//CECHPWork pWork = m_pWorkMan.GetRunningWork(Host_work_ID.WORK_PICKUP);
//if (pWork != null)
// return (pWork as CECHPWorkPick).IsGather();
//else
// return false;
}
// Is using item ?
@@ -5652,6 +5818,19 @@ namespace BrewMonster
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)
{
@@ -5666,5 +5845,177 @@ namespace BrewMonster
}
}
}
public CECCounter GetGatherCnt() { return m_GatherCnt; }
public void UpdateTimers(float dwDeltaTime)
{
// Get real time tick of this frame
// Update flysword time
/*if (IsFlying() && GetRushFlyFlag())
{
CECIvtrItem pItem = m_pEquipPack.GetItem(EQUIPIVTR_FLYSWORD);
Debug.Assert(pItem != null);
if (pItem.GetClassID() == CECIvtrItem.ICID_FLYSWORD)
{
CECIvtrFlySword pFlySword = (CECIvtrFlySword)pItem;
pFlySword.TimePass(dwDeltaTime);
}
}*/
int i;
// Update skills
for (i = 0; i < m_aPtSkills.Count; i++)
m_aPtSkills[i].Tick(dwDeltaTime);
for (i = 0; i < m_aPsSkills.Count; i++)
m_aPsSkills[i].Tick(dwDeltaTime);
for (i = 0; i < m_aGoblinSkills.Count; i++)
m_aGoblinSkills[i].Tick(dwDeltaTime);
for (i = 0; i < m_aEquipSkills.Count; i++)
m_aEquipSkills[i].Tick(dwDeltaTime);
if (m_pTargetItemSkill != null)
m_pTargetItemSkill.Tick(dwDeltaTime);
//CECComboSkillState.Instance().Tick();
// Update cool times
for (i = 0; i < (int)CoolTimeIndex.GP_CT_MAX; i++)
m_aCoolTimes[i].Update(dwDeltaTime);
foreach (var kvp in m_skillCoolTime)
{
kvp.Value.Update(dwDeltaTime);
}
// Gather time counter
if (m_GatherCnt.IncCounter(dwDeltaTime))
m_GatherCnt.Reset(true);
// Incant time counter
if (m_IncantCnt.IncCounter(dwDeltaTime))
m_IncantCnt.Reset(true);
// Bind command cool counter
/* if (m_BindCmdCoolCnt.IncCounter(dwDeltaTime))
m_BindCmdCoolCnt.Reset(true);
// Auto fashion time counter
if (m_bAutoFashion && GetBoothState() != 2 && !IsShapeChanged())
{
if (m_AutoFashionCnt.IncCounter(dwDeltaTime))
{
if (!CheckAutoFashionCondition())
{
while (!EquipFashionBySuitID((m_iCurFashionSuitID + 1) % GetMaxFashionSuitNum()))
m_iCurFashionSuitID++;
m_AutoFashionCnt.Reset();
}
}
}
// Auto convert Yinpiao
if (m_AutoYinpiao.open)
{
if (m_AutoYinpiao.cnt.IncCounter(dwDeltaTime))
{
ExchangeYinpiao();
m_AutoYinpiao.cnt.Reset();
}
}
// Control the dialog of the target item
m_TargetItemDlgCtrl.Update(dwDeltaTime);
// For some reasons on server, sometimes friend list couldn't be got
// successfully. Try to get it again every 20s if this case really happen
if (m_pFriendMan != null && !m_pFriendMan.CheckInit())
{
m_iGetFriendCnt -= dwDeltaTime;
if (m_iGetFriendCnt < 0)
{
EC_Game.GetGameSession().friend_GetList();
m_iGetFriendCnt = 60000;
}
}
// Duel stopping time counter
if (m_pvp.iDuelState == DUEL_ST_PREPARE)
{
m_pvp.iDuelTimeCnt -= dwDeltaTime;
if (m_pvp.iDuelTimeCnt < 0)
m_pvp.iDuelTimeCnt = 0;
}
else if (m_pvp.iDuelState == DUEL_ST_INDUEL)
{
m_pvp.iDuelTimeCnt += dwDeltaTime;
}
else if (m_pvp.iDuelState == DUEL_ST_STOPPING)
{
m_pvp.iDuelTimeCnt -= dwDeltaTime;
if (m_pvp.iDuelTimeCnt < 0)
{
m_pvp.iDuelTimeCnt = 0;
m_pvp.iDuelState = DUEL_ST_NONE;
m_pvp.idDuelOpp = 0;
}
}
// Update pariah time counter
if (m_dwPariahTime > 0)
{
if (m_dwPariahTime > (uint)dwDeltaTime)
m_dwPariahTime -= (uint)dwDeltaTime;
else
m_dwPariahTime = 0;
}
// Update pet operation time counter
m_PetOptCnt.IncCounter(dwDeltaTime);
// Update battle result time counter
if (IsInBattle() && !IsInFortress() && m_BattleInfo.iResult != 0 && m_BattleInfo.iResultCnt != 0)
{
if ((m_BattleInfo.iResultCnt -= dwDeltaTime) < 0)
m_BattleInfo.iResultCnt = 0;
}
// Update pet corral
if (m_pPetCorral != null)
m_pPetCorral.Tick((uint)dwDeltaTime);
// Update the related people
var keysToRemove = new List<int>();
foreach (var kvp in m_RelatedPlayer)
{
m_RelatedPlayer[kvp.Key] -= dwDeltaTime;
if (m_RelatedPlayer[kvp.Key] <= 0)
keysToRemove.Add(kvp.Key);
}
foreach (var key in keysToRemove)
{
m_RelatedPlayer.Remove(key);
}*/
}
public struct COOLTIME
{
public int iCurTime;
public int iMaxTime;
public void Update(float dwDeltaTime)
{
if (iCurTime > 0)
{
iCurTime -= (int)(dwDeltaTime * 1000);
Mathf.Clamp(iCurTime, 0, float.MaxValue);
}
}
}
}
}
}
+2
View File
@@ -39,6 +39,8 @@ public class CECUIManager : MonoSingleton<CECUIManager>
{
btnSecondClick.onClick.AddListener(OnSecondClickButtonClicked);
}
ShowUI("Win_Hpmpxp");
}
private void OnDestroy()