From 9ddb91a0878ef7aa4a721db623a12169caf65f31 Mon Sep 17 00:00:00 2001
From: HungDK <>
Date: Wed, 15 Apr 2026 11:26:47 +0700
Subject: [PATCH] Fix raycast to not hit through ui
---
.../Scripts/Managers/EC_HostInputFilter.cs | 12 ++++
Assets/PerfectWorld/Scripts/UI/pickupItem.cs | 7 ++
Assets/Scripts/CECUIManager.cs | 70 +++++++++++++++++++
3 files changed, 89 insertions(+)
diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_HostInputFilter.cs b/Assets/PerfectWorld/Scripts/Managers/EC_HostInputFilter.cs
index edfce9b093..f8b0964885 100644
--- a/Assets/PerfectWorld/Scripts/Managers/EC_HostInputFilter.cs
+++ b/Assets/PerfectWorld/Scripts/Managers/EC_HostInputFilter.cs
@@ -99,6 +99,18 @@ namespace BrewMonster
/// Optional target ID to use instead of raycast (for second-click behavior) / 可选的目标ID,用于替代射线检测(用于第二次点击行为)
public void OnMsgLBtnClick(int idTargetOverride = 0)
{
+ // Interactive UI (buttons, fields, scrolls) consumes the click. Full-screen raycast panels alone do not.
+ // When a non-HUD dialog is open, block world interaction entirely (terrain/NPC/matter) until it is closed.
+ if (idTargetOverride == 0)
+ {
+ if (CECUIManager.IsPointerOverInteractiveUI())
+ return;
+
+ var uiMan = EC_Game.GetGameRun()?.GetUIManager();
+ if (uiMan != null && uiMan.IsWorldInteractionBlockedByUI())
+ return;
+ }
+
// 停止自动策略 / Stop auto policy
// Note: Auto policy check would go here if implemented
diff --git a/Assets/PerfectWorld/Scripts/UI/pickupItem.cs b/Assets/PerfectWorld/Scripts/UI/pickupItem.cs
index abc7386815..ec541a8752 100644
--- a/Assets/PerfectWorld/Scripts/UI/pickupItem.cs
+++ b/Assets/PerfectWorld/Scripts/UI/pickupItem.cs
@@ -84,6 +84,13 @@ public class pickupItem : MonoBehaviour
// Check for mouse clicks on cubes
if (Input.GetMouseButtonDown(0))
{
+ if (CECUIManager.IsPointerOverInteractiveUI())
+ return;
+
+ var uiMan = EC_Game.GetGameRun()?.GetUIManager();
+ if (uiMan != null && uiMan.IsWorldInteractionBlockedByUI())
+ return;
+
HandleCubeClick();
}
}
diff --git a/Assets/Scripts/CECUIManager.cs b/Assets/Scripts/CECUIManager.cs
index e6bf282408..08ac4c1171 100644
--- a/Assets/Scripts/CECUIManager.cs
+++ b/Assets/Scripts/CECUIManager.cs
@@ -9,6 +9,8 @@ using BrewMonster.Scripts.Managers;
using BrewMonster.Scripts.Task.UI;
using BrewMonster.Scripts.UI;
using UnityEngine;
+using UnityEngine.EventSystems;
+using UnityEngine.UI;
using TMPro;
public class CECUIManager : MonoSingleton
@@ -366,6 +368,74 @@ public class CECUIManager : MonoSingleton
return null;
}
+ ///
+ /// Dialog names on that are normal gameplay HUD and must NOT block world raycasts
+ /// (the stack always has at least Win_Hpmpxp after ).
+ ///
+ private static readonly HashSet HudStackDialogNames = new HashSet(StringComparer.Ordinal)
+ {
+ "Win_Hpmpxp",
+ };
+
+ ///
+ /// Returns true when a modal / non-HUD dialog is open and world clicks should be ignored.
+ ///
+ public bool IsWorldInteractionBlockedByUI()
+ {
+ if (_uiStack == null || _uiStack.Count == 0)
+ return false;
+
+ foreach (var name in _uiStack)
+ {
+ if (string.IsNullOrEmpty(name))
+ continue;
+ if (!HudStackDialogNames.Contains(name))
+ return true;
+ }
+
+ return false;
+ }
+
+ ///
+ /// True when the pointer hits UI that should consume the click (buttons, fields, scroll views).
+ /// Unlike , full-screen Images/Text with raycast
+ /// but no interactive control do not block — so clicks can reach the world for NPC selection.
+ ///
+ public static bool IsPointerOverInteractiveUI()
+ {
+ var es = EventSystem.current;
+ if (es == null)
+ return false;
+
+ Vector2 pos = Input.mousePosition;
+ if (Input.touchCount > 0)
+ pos = Input.GetTouch(0).position;
+
+ var ped = new PointerEventData(es) { position = pos };
+ var results = new List();
+ es.RaycastAll(ped, results);
+ if (results.Count == 0)
+ return false;
+
+ foreach (var r in results)
+ {
+ var go = r.gameObject;
+ if (go == null)
+ continue;
+
+ if (go.GetComponentInParent() != null)
+ return true;
+ if (go.GetComponentInParent() != null)
+ return true;
+ if (go.GetComponentInParent() != null)
+ return true;
+ if (go.GetComponentInParent() != null)
+ return true;
+ }
+
+ return false;
+ }
+
// public CDlgMessageBox ShowMessageBox(MessageBoxData messageBoxData)
// {
// var msgBox = GetInGameUIMan().GetDialog("DlgMessageBox") as CDlgMessageBox;