Merge branch 'develop' into feature/update-ui

This commit is contained in:
HungDK
2026-04-08 14:10:51 +07:00
14 changed files with 125 additions and 80 deletions
@@ -26,13 +26,13 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3218176555537563708}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalRotation: {x: 0, y: 0.7071068, z: 0, w: 0.7071068}
m_LocalPosition: {x: 0.235, y: 0.001, z: 0.015}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0}
--- !u!33 &4570469791566163120
MeshFilter:
m_ObjectHideFlags: 0
@@ -26,13 +26,13 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4720678646282004868}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalRotation: {x: 0, y: 0.7071068, z: 0, w: 0.7071068}
m_LocalPosition: {x: 0.564, y: -0.061, z: -0.005}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0}
--- !u!33 &2558500868448674905
MeshFilter:
m_ObjectHideFlags: 0
@@ -26,13 +26,13 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2916308637203925776}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalRotation: {x: 0, y: 0.7071068, z: 0, w: 0.7071068}
m_LocalPosition: {x: 0.564, y: -0.061, z: -0.005}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0}
--- !u!33 &2359515785900208490
MeshFilter:
m_ObjectHideFlags: 0
@@ -26,13 +26,13 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4858308094309864508}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalRotation: {x: 0, y: 0.7071068, z: 0, w: 0.7071068}
m_LocalPosition: {x: 0.84, y: -0.064, z: -0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0}
--- !u!33 &5945091725935784906
MeshFilter:
m_ObjectHideFlags: 0
@@ -26,13 +26,13 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7515438785474843149}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalRotation: {x: 0, y: 0.7071068, z: 0, w: 0.7071068}
m_LocalPosition: {x: 0.564, y: -0.013, z: -0.005}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0}
--- !u!33 &4684279536110930119
MeshFilter:
m_ObjectHideFlags: 0
@@ -26,13 +26,13 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6015463627169791726}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalRotation: {x: 0, y: 0.7071068, z: 0, w: 0.7071068}
m_LocalPosition: {x: 0.564, y: -0.013, z: -0.005}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0}
--- !u!33 &5659237752439739352
MeshFilter:
m_ObjectHideFlags: 0
@@ -26,13 +26,13 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1197563511380039097}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalRotation: {x: 0, y: 0.7071068, z: 0, w: 0.7071068}
m_LocalPosition: {x: 0.564, y: -0.013, z: -0.005}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0}
--- !u!33 &133678441249318870
MeshFilter:
m_ObjectHideFlags: 0
@@ -26,13 +26,13 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6982793425996143688}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalRotation: {x: 0, y: 0.7071068, z: 0, w: 0.7071068}
m_LocalPosition: {x: 0.564, y: -0.013, z: -0.005}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0}
--- !u!33 &1783189990820706467
MeshFilter:
m_ObjectHideFlags: 0
@@ -707,43 +707,40 @@ namespace BrewMonster.Scripts.Task
return false;
}
// 可接任务列表 // Available tasks list
// 可接任务列表(全量一次扫完;分帧接口见 ProcessAvailableTasksChunk
// Available tasks list (full scan in one call; time-sliced API: ProcessAvailableTasksChunk)
public void GetAvailableTasks(TaskInterface pPlayer, List<ATaskTempl> lst)
{
if (lst == null) return;
if (lst.Capacity < 256) lst.Capacity = 256; // 预留容量 // reserve capacity
string log = "";
int count = m_TasksCanSeekOut.Count;
for (int i = 0; i < count; i++)
lst.Clear();
int cursor = 0;
bool completed;
do
{
ATaskTempl pTempl = m_TasksCanSeekOut[i];
ProcessAvailableTasksChunk(pPlayer, lst, ref cursor, int.MaxValue, out completed);
} while (!completed);
}
/// <summary>
/// Process up to maxSteps templates from m_TasksCanSeekOut; cursor is next index (0 = start of list).
/// 每次最多处理 maxSteps 个 m_TasksCanSeekOut 项;cursor 为下一待处理下标。
/// </summary>
public void ProcessAvailableTasksChunk(TaskInterface pPlayer, List<ATaskTempl> lst, ref int cursor, int maxSteps, out bool completed)
{
int count = m_TasksCanSeekOut.Count;
int processed = 0;
while (cursor < count && processed < maxSteps)
{
ATaskTempl pTempl = m_TasksCanSeekOut[cursor];
cursor++;
processed++;
if (pTempl == null) continue;
// 如果等级条件不满足则跳过 // Skip if level requirements are not met
if (!pTempl.CheckReachLevel(pPlayer)) continue;
// 玩家可接此任务则加入列表 // If player can accept this task, add to list
var failCode = pPlayer.CanDeliverTask(pTempl.m_FixedData.m_ID);
if (failCode == 0)
{
if (pPlayer.CanDeliverTask(pTempl.m_FixedData.m_ID) == 0)
lst.Add(pTempl);
}
else
{
log += $"Task ID {pTempl.m_FixedData.m_ID} Fail : {failCode} \n";
}
// if (i % 1000 == 0)
// {
// Debug.Log($"--- {i % 1000} Find Available Task --- \n {log}");
// log = "";
// }
}
completed = cursor >= count;
}
public uint GetTaskStorageId(uint id)
+23 -9
View File
@@ -384,6 +384,8 @@ namespace BrewMonster.Scripts.Task.UI
public void OnCommand_showtrace(string szCommand,bool state) {
m_bShowTrace = state;
Debug.Log($"[DlgTask] OnCommand_showtrace: state={m_bShowTrace}");
if (state)
RebuildAcceptableQuestCache();
ShowTraceDialog();
}
public void TraceTask(uint idTask)
@@ -607,8 +609,6 @@ namespace BrewMonster.Scripts.Task.UI
public void OnEventLButtonDown_Tv_Quest(uint itemData)
{
// UpdateTask((int)itemData);
// POINT ptPos = pObj->GetPos();
// A3DVIEWPORTPARAM *p = m_pA3DEngine->GetActiveViewport()->GetParam();
// int x = GET_X_LPARAM(lParam) - ptPos.x - p->X;
@@ -635,7 +635,7 @@ namespace BrewMonster.Scripts.Task.UI
// if(pTree->GetHitArea(x,y) == AUITREEVIEW_RECT_FRAME)
// CDlgWikiShortcut::PopQuestWiki(GetGameUIMan(),idTask);
// }
m_idSelTask = idTask;
}
// void OnEventMouseMove_Txt_QuestItem(WPARAM wParam, LPARAM lParam, AUIObject *pObj);
@@ -917,9 +917,8 @@ namespace BrewMonster.Scripts.Task.UI
}
else if(showType2 == ShowType2.ST_NOT_RECIEVED)
{
// Re-run GetAvailableTasks every trace refresh; m_vecTasksCanGet was only filled on quest UI events and stayed stale.
// 每次追踪刷新重新计算可接任务;原先仅在任务界面事件里更新列表,游戏中会一直停留在开局数据
RefreshVecTasksCanGet(pTask);
// Can-get list is refreshed only on level-up, quest state change (UpdateQuestView), trace toggle on, or minimion "可接" tab — not every tick.
// 可接列表仅在升级、任务变更、打开追踪、小窗切到可接时刷新,避免每帧扫全表拖垮 FPS
tasks.Capacity = m_vecTasksCanGet.Count;
tasks.AddRange(m_vecTasksCanGet);
}
@@ -1298,8 +1297,8 @@ namespace BrewMonster.Scripts.Task.UI
}
}
// Search view already rebuilt m_vecTasksCanGet inside SearchForTask(-1).
// 搜索页SearchForTask 内已更新 m_vecTasksCanGet。
// Have-quest tab: rebuild can-get cache for trace minimion. Search tab: SearchForTask(-1) already filled m_vecTasksCanGet.
// 已接任务页:重建可接缓存。搜索页SearchForTask 已写 m_vecTasksCanGet,勿二次全表扫描
if (m_iType == 0)
RefreshVecTasksCanGet();
@@ -1413,9 +1412,24 @@ namespace BrewMonster.Scripts.Task.UI
/// 用 GetAvailableTasks 重建可接任务 ID 列表,与可接任务搜索树数据源一致。
/// </summary>
private void RefreshVecTasksCanGet(CECTaskInterface pTaskIfKnown = null)
{
RebuildAcceptableQuestCache(pTaskIfKnown);
}
/// <summary>
/// Rebuilds the cached list of quests the host may accept (trace minimion "可接", etc.).
/// Safe without a DlgTask instance — call from UI manager on level-up and similar.
/// 重建玩家当前可接任务 ID 缓存;可无对话框实例,由 UI 管理器在升级等时机调用。
/// </summary>
public static void RebuildAcceptableQuestCache(CECTaskInterface pTaskIfKnown = null)
{
m_vecTasksCanGet.Clear();
CECTaskInterface pTask = pTaskIfKnown ?? GetHostPlayer()?.GetTaskInterface();
CECTaskInterface pTask = pTaskIfKnown;
if (pTask == null)
{
var run = EC_Game.GetGameRun();
pTask = run?.GetHostPlayer()?.GetTaskInterface();
}
if (pTask == null) return;
ATaskTemplMan pMan = EC_Game.GetTaskTemplateMan();
if (pMan == null) return;
@@ -134,6 +134,7 @@ namespace BrewMonster.Scripts.Task.UI
if(value)
{
m_nLastShowType2 = ShowType2.ST_NOT_RECIEVED;
DlgTask.RebuildAcceptableQuestCache();
}
}
public void OnShowDialog()
@@ -357,6 +357,12 @@ namespace BrewMonster.UI
return false;
}
/// <summary>Quest main dialog (Win_Quest), created in Init. / 任务主界面,Init 时创建。</summary>
public DlgTask GetDlgTask()
{
return m_pDlgTask;
}
public override void Init()
{
base.Init();
+5
View File
@@ -3067,6 +3067,8 @@ namespace BrewMonster
// m_pLevelUpGFX.Start(true);
PlayGfx(EC_Resource.res_GFXFile((int)GfxResourceType.RES_GFX_LEVELUP), null, 1f, 1); //PLAYERMODEL_TYPEALL
EventBus.Publish(new HostPlayerLevelUpUIEvent());
// // Popup notify bubble text
// BubbleText(BUBBLE_LEVELUP, 0);
//
@@ -3622,6 +3624,9 @@ namespace BrewMonster
/// <summary>Fired when selected target HUD should be hidden (deselect or switch).</summary>
public struct TargetHUDClearEvent { }
/// <summary>Host leveled up — UI layer may refresh quest-offer lists, popups, etc. 玩家升级,UI 可刷新可接任务等。</summary>
public struct HostPlayerLevelUpUIEvent { }
public struct GNDINFO
{
public float fGndHei; // Ground height
+41 -19
View File
@@ -6,6 +6,8 @@ using System.Collections.Generic;
using BrewMonster.PerfectWorld.Scripts.Utility.ChatFilter;
using BrewMonster.Scripts.Chat.EmotionData;
using BrewMonster.Scripts.Managers;
using BrewMonster.Scripts.Task.UI;
using BrewMonster.Scripts.UI;
using UnityEngine;
using TMPro;
@@ -55,6 +57,7 @@ public class CECUIManager : MonoSingleton<CECUIManager>
EventBus.Subscribe<CECHostPlayer.NPCINFO>(ShowUINPC);
EventBus.Subscribe<CECHostPlayer.TargetHUDClearEvent>(OnTargetHUDClear);
EventBus.Subscribe<CECHostPlayer.HostPlayerLevelUpUIEvent>(OnHostPlayerLevelUpUI);
EventBus.Subscribe<NPCDiedEvent>(TryHideUINPC);
EventBus.Subscribe<MessageBoxEvent>(OnMessageBox);
@@ -85,22 +88,26 @@ public class CECUIManager : MonoSingleton<CECUIManager>
m_pDlgQuickBar1.UpdateShortcuts();
}
// Periodically update task UI (DlgTask and DlgTaskTrace) / 定期更新任务UIDlgTask和DlgTaskTrace
if (Time.unscaledTime >= _nextTaskUpdateTime)
{
_nextTaskUpdateTime = Time.unscaledTime + TASK_UPDATE_INTERVAL;
//if hostplayer is null, return
var hostPlayer = EC_Game.GetGameRun()?.GetHostPlayer();
if(hostPlayer == null)
{
return;
}
UpdateTaskUI();
// Task UI must run from this Update(): TickInvoker often never calls CECUIManager.Tick in practice
// (registration order, DDOL instance, or no TickInvoker in scene), so logs/body there never ran.
// 任务 UI 必须在此 Update 驱动:TickInvoker 在部分场景下根本不会调到本类 Tick。
if (Time.unscaledTime < _nextTaskUpdateTime)
return;
_nextTaskUpdateTime = Time.unscaledTime + TASK_UPDATE_INTERVAL;
// Hiển thị thông tin đăng nhập khi người chơi đã vào game an toàn / Show login info when host player is ready
// Hàm này bên trong đã có cờ m_bAccountLoginInfoShown để tránh bị gọi nhiều lần, nên đặt ở Update là an toàn.
UpdateTaskUI();
if (EC_Game.GetGameRun()?.GetHostPlayer() != null)
EC_Game.GetGameRun()?.ShowAccountLoginInfo();
}
}
/// <summary>
/// Rebuild acceptable-quest cache after host levels up (heavy scan; not on player code path).
/// 升级后重建可接任务缓存(全表扫描放在 UI 层)。
/// </summary>
private void OnHostPlayerLevelUpUI(CECHostPlayer.HostPlayerLevelUpUIEvent _)
{
DlgTask.RebuildAcceptableQuestCache();
}
/// <summary>
@@ -113,13 +120,27 @@ public class CECUIManager : MonoSingleton<CECUIManager>
var inGameUIMan = GetInGameUIMan();
if (inGameUIMan == null) return;
var dlgTaskDialog = inGameUIMan.GetDialog("Win_Quest");
var bShowTrace = inGameUIMan.IsDialogShow("Win_QuestMinion");
if (dlgTaskDialog != null && dlgTaskDialog is BrewMonster.Scripts.Task.UI.DlgTask dlgTask)
// Prefer cached DlgTask from Init (Win_Quest). Do not rely on `is DlgTask` on AUIDialog:
// prefab may register as AUIDialog while DlgTask is the concrete component on the same GO.
// 优先使用 Init 里缓存的 DlgTask;字典里可能是 AUIDialog 引用,`is DlgTask` 会为 false。
DlgTask dlgTask = null;
if (inGameUIMan is CECGameUIMan gameUi && gameUi.GetDlgTask() != null)
dlgTask = gameUi.GetDlgTask();
if (dlgTask == null)
{
dlgTask.RefreshTaskTrace(bShowTrace);
dlgTask.Tick();
var dlg = inGameUIMan.GetDialog(CECUIHelper.DlgTaskName);
dlgTask = dlg != null ? dlg.GetComponent<DlgTask>() : null;
}
if (dlgTask == null)
return;
if (EC_Game.GetGameRun()?.GetHostPlayer() == null)
return;
var bShowTrace = inGameUIMan.IsDialogShow("Win_QuestMinion");
dlgTask.RefreshTaskTrace(bShowTrace);
dlgTask.Tick();
}
catch (System.Exception)
{
@@ -132,6 +153,7 @@ public class CECUIManager : MonoSingleton<CECUIManager>
{
EventBus.Unsubscribe<CECHostPlayer.NPCINFO>(ShowUINPC);
EventBus.Unsubscribe<CECHostPlayer.TargetHUDClearEvent>(OnTargetHUDClear);
EventBus.Unsubscribe<CECHostPlayer.HostPlayerLevelUpUIEvent>(OnHostPlayerLevelUpUI);
EventBus.Unsubscribe<NPCDiedEvent>(TryHideUINPC);
EventBus.Unsubscribe<MessageBoxEvent>(OnMessageBox);
}