280 lines
12 KiB
Lua
280 lines
12 KiB
Lua
-- Backslash toggles HUD only. Keep pages, dialogs and UI cameras visible.
|
|
local Input = CS.UnityEngine.Input
|
|
local KeyCode = CS.UnityEngine.KeyCode
|
|
local Time = CS.UnityEngine.Time
|
|
local GameObject = CS.UnityEngine.GameObject
|
|
local CanvasGroup = CS.UnityEngine.CanvasGroup
|
|
local Camera = CS.UnityEngine.Camera
|
|
|
|
-- Names observed under UIRoot in this Client, plus the existing battle HUD.
|
|
-- Never target an ancestor shared by HUD and character/reward dialogs.
|
|
local HUD_PATHS = {
|
|
"UIRoot/Page/MazeMainPage(Clone)",
|
|
-- Fallback for clients where the phase's private HudPage field is absent
|
|
-- or does not include every battle overlay.
|
|
"UIRoot/Page/BattleGamePhaseUI(Clone)",
|
|
"UIRoot/BelowPage/AdventureWaypointsPage(Clone)",
|
|
"UIRoot/BelowPage/MazeJumpingText(Clone)",
|
|
"UIRoot/BelowPage/MazeMonsterWarningPage(Clone)",
|
|
-- Character controls observed under AvatarMainPage/Root. Keep RankPanel
|
|
-- and dialogs intact so Eidolon illustrations are not hidden with menus.
|
|
"UIRoot/Page/AvatarMainPage(Clone)/Root/AvatarSubMenuPanel_Vertical",
|
|
"UIRoot/Page/AvatarMainPage(Clone)/Root/AvatarDetailPanel",
|
|
"UIRoot/Page/AvatarMainPage(Clone)/Root/AvatarTopListPanel",
|
|
"UIRoot/Page/AvatarMainPage(Clone)/Root/AvatarListPanel",
|
|
"UIRoot/Page/AvatarMainPage(Clone)/Root/BtnClose",
|
|
"UIRoot/Page/AvatarMainPage(Clone)/Root/TopBarArea",
|
|
}
|
|
|
|
-- The old script did not record CanvasGroup state. Undo its blanket hide once
|
|
-- on live upgrade; a fresh Client session avoids any lost legacy fade state.
|
|
if _G.__HIDE_UI_REGISTERED and (_G.__HIDE_UI_SCHEMA or 0) < 2 and _G.__HIDE_UI_ENABLED then
|
|
pcall(function()
|
|
local cams = Camera.allCameras
|
|
for i = 0, cams.Length - 1 do
|
|
local mask = (_G.__ORIG_CAM_MASKS or {})[cams[i]:GetInstanceID()]
|
|
if mask ~= nil then cams[i].cullingMask = mask end
|
|
end
|
|
local function restore(obj)
|
|
if obj then
|
|
local cg = obj:GetComponent(typeof(CanvasGroup))
|
|
if cg then cg.alpha = 1; cg.blocksRaycasts = true; cg.interactable = true end
|
|
end
|
|
end
|
|
local root = GameObject.Find("UIRoot")
|
|
if root then
|
|
restore(root)
|
|
local t = root.transform
|
|
for i = 0, t.childCount - 1 do
|
|
local c = t:GetChild(i); restore(c.gameObject)
|
|
for j = 0, c.childCount - 1 do restore(c:GetChild(j).gameObject) end
|
|
end
|
|
end
|
|
local canvases = GameObject.FindObjectsOfType(typeof(CS.UnityEngine.Canvas))
|
|
for i = 0, canvases.Length - 1 do restore(canvases[i].gameObject) end
|
|
end)
|
|
end
|
|
_G.__HIDE_UI_ENABLED = _G.__HIDE_UI_ENABLED or false
|
|
_G.__HIDE_UI_TARGETS = _G.__HIDE_UI_TARGETS or {}
|
|
|
|
local function restore_hud()
|
|
for id, state in pairs(_G.__HIDE_UI_TARGETS) do
|
|
pcall(function()
|
|
if state.group then
|
|
if state.added then
|
|
CS.UnityEngine.Object.Destroy(state.group)
|
|
else
|
|
state.group.alpha = state.alpha
|
|
state.group.blocksRaycasts = state.raycast
|
|
state.group.interactable = state.interactable
|
|
end
|
|
end
|
|
end)
|
|
_G.__HIDE_UI_TARGETS[id] = nil
|
|
end
|
|
end
|
|
|
|
local function protected_name(name)
|
|
local n = string.lower(tostring(name))
|
|
return string.find(n, "uid", 1, true) ~= nil and string.find(n, "guide", 1, true) == nil
|
|
or n == "versiontext" or n == "betahintdialog(clone)"
|
|
end
|
|
|
|
local function hide_object(obj)
|
|
if not obj or protected_name(obj.name) then return end
|
|
local id = obj:GetInstanceID()
|
|
local state = _G.__HIDE_UI_TARGETS[id]
|
|
if not state then
|
|
local group = obj:GetComponent(typeof(CanvasGroup))
|
|
local added = not group
|
|
if added then group = obj:AddComponent(typeof(CanvasGroup)) end
|
|
state = {group=group, added=added, alpha=group.alpha,
|
|
raycast=group.blocksRaycasts, interactable=group.interactable}
|
|
_G.__HIDE_UI_TARGETS[id] = state
|
|
end
|
|
state.group.alpha = 0
|
|
state.group.blocksRaycasts = false
|
|
state.group.interactable = false
|
|
end
|
|
|
|
-- Keep UID/branding subtrees visible even if they belong to a HUD container.
|
|
local function hide_hud_tree(obj)
|
|
if not obj then return end
|
|
local protected = {}
|
|
local ts = obj:GetComponentsInChildren(typeof(CS.UnityEngine.Transform), true)
|
|
for i = 0, ts.Length - 1 do
|
|
if protected_name(ts[i].name) then
|
|
local t = ts[i]
|
|
while t do
|
|
protected[t:GetInstanceID()] = true
|
|
if t == obj.transform then break end
|
|
t = t.parent
|
|
end
|
|
end
|
|
end
|
|
local function visit(t)
|
|
if protected_name(t.name) then return end
|
|
if not protected[t:GetInstanceID()] then
|
|
hide_object(t.gameObject)
|
|
-- Battle HUD widgets have their own CanvasGroups and some ignore
|
|
-- their parent's alpha. Hide those groups too, preserving each
|
|
-- original state for restoration when the toggle is disabled.
|
|
local groups = t:GetComponentsInChildren(typeof(CanvasGroup), true)
|
|
for i = 0, groups.Length - 1 do
|
|
hide_object(groups[i].gameObject)
|
|
end
|
|
return
|
|
end
|
|
for i = 0, t.childCount - 1 do visit(t:GetChild(i)) end
|
|
end
|
|
visit(obj.transform)
|
|
end
|
|
|
|
-- EX/Eidolon artwork is an image. Hide interactive controls and labels,
|
|
-- never the page's Canvas/camera or the illustration's parent container.
|
|
local function hide_control_components(root, kind)
|
|
local ok, controls = pcall(function()
|
|
return root:GetComponentsInChildren(kind, true)
|
|
end)
|
|
if not ok or not controls then return end
|
|
for i = 0, controls.Length - 1 do
|
|
local component = controls[i]
|
|
if component and component.gameObject and not protected_name(component.gameObject.name) then
|
|
-- Hiding each control directly avoids rescanning its entire
|
|
-- subtree for every Button/LocalizedText pair on the page.
|
|
hide_object(component.gameObject)
|
|
end
|
|
end
|
|
end
|
|
|
|
local function hide_rank_controls(root)
|
|
if not root or not root.activeInHierarchy then return end
|
|
hide_control_components(root, typeof(CS.RPG.Client.LocalizedText))
|
|
-- Selectable includes buttons, toggles, sliders, dropdowns and scrollbars;
|
|
-- some rank-page controls have no text or Button component of their own.
|
|
hide_control_components(root, typeof(CS.UnityEngine.UI.Selectable))
|
|
-- Skill icons use SkillIcon sprites; illustrations use separate portrait
|
|
-- assets. Do not hide arbitrary images or the illustration container.
|
|
local images = root:GetComponentsInChildren(typeof(CS.UnityEngine.UI.Image), true)
|
|
for i = 0, images.Length - 1 do
|
|
local sprite = images[i].sprite
|
|
if sprite and string.lower(tostring(sprite.name)):find("skillicon",1,true) then
|
|
hide_object(images[i].gameObject)
|
|
end
|
|
end
|
|
end
|
|
|
|
local function hide_hud()
|
|
for _, path in ipairs(HUD_PATHS) do
|
|
pcall(function() hide_hud_tree(GameObject.Find(path)) end)
|
|
end
|
|
local ok, err = pcall(function()
|
|
local flags = CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags), 60)
|
|
_G.__HIDE_UI_PHASE_FIELD = _G.__HIDE_UI_PHASE_FIELD
|
|
or typeof(CS.RPG.Client.GamePhaseManager):GetField("_CurrentPhase", flags)
|
|
_G.__HIDE_UI_BATTLE_HUD_FIELD = _G.__HIDE_UI_BATTLE_HUD_FIELD
|
|
or typeof(CS.RPG.Client.BattleGamePhase):GetField("_HudPage", flags)
|
|
local manager = CS.RPG.Client.GlobalVars.s_GamePhaseManager
|
|
local phase = manager and _G.__HIDE_UI_PHASE_FIELD:GetValue(manager)
|
|
if phase and typeof(CS.RPG.Client.BattleGamePhase):IsInstanceOfType(phase) then
|
|
local hud = _G.__HIDE_UI_BATTLE_HUD_FIELD:GetValue(phase)
|
|
if hud and hud.Trans then hide_hud_tree(hud.Trans.gameObject) end
|
|
if hud and hud.ChildDialogs then
|
|
local dialogs = hud.ChildDialogs
|
|
for i = 0, dialogs.Count - 1 do
|
|
if dialogs[i].Trans then hide_hud_tree(dialogs[i].Trans.gameObject) end
|
|
end
|
|
end
|
|
end
|
|
end)
|
|
if not ok and _G.__HIDE_UI_LAST_ERROR ~= tostring(err) then
|
|
_G.__HIDE_UI_LAST_ERROR = tostring(err)
|
|
CS.UnityEngine.Debug.Log("[GaC HideUI] Battle HUD: " .. tostring(err))
|
|
end
|
|
pcall(function()
|
|
local ui = CS.RPG.Client.GlobalVars.s_UIManager
|
|
local pages = ui:GetAllPageNames()
|
|
for i = 0, pages.Count - 1 do
|
|
local name = tostring(pages[i]); local lower = string.lower(name)
|
|
local page = ui:GetPageByName(name)
|
|
if page and page.ChildDialogs then
|
|
for j = 0, page.ChildDialogs.Count - 1 do
|
|
local dialog = page.ChildDialogs[j]
|
|
local dialogName = string.lower(tostring(dialog.Name))
|
|
if dialog.Trans and (dialogName:find("rank",1,true) or dialogName:find("eidolon",1,true)) then
|
|
hide_rank_controls(dialog.Trans.gameObject)
|
|
end
|
|
end
|
|
end
|
|
if lower:find("battle",1,true) then
|
|
local page = ui:GetPageByName(name)
|
|
if page and page.Trans and page.Trans.gameObject.activeInHierarchy then
|
|
hide_hud_tree(page.Trans.gameObject)
|
|
end
|
|
end
|
|
if lower:find("rank",1,true) or lower:find("eidolon",1,true) then
|
|
local page = ui:GetPageByName(name)
|
|
if page and page.Trans then hide_rank_controls(page.Trans.gameObject) end
|
|
end
|
|
end
|
|
hide_rank_controls(GameObject.Find("UIRoot/Page/AvatarMainPage(Clone)/Root/AvatarRankPanel"))
|
|
end)
|
|
end
|
|
|
|
function _G.__HIDE_UI_TICK()
|
|
pcall(function()
|
|
local frame = Time.frameCount
|
|
if _G.__HIDE_UI_LAST_FRAME == frame then return end
|
|
_G.__HIDE_UI_LAST_FRAME = frame
|
|
local toggled = Input.GetKeyDown(KeyCode.Backslash)
|
|
if toggled then
|
|
_G.__HIDE_UI_ENABLED = not _G.__HIDE_UI_ENABLED
|
|
if not _G.__HIDE_UI_ENABLED then restore_hud() end
|
|
end
|
|
-- The page/child scan walks Unity UI trees, so keep it to once a second.
|
|
-- New pages/dialogs never inherit a hidden UIRoot or UI camera.
|
|
if _G.__HIDE_UI_ENABLED then
|
|
local now = Time.unscaledTime
|
|
if toggled or now >= (_G.__HIDE_UI_NEXT_SCAN or 0) then
|
|
_G.__HIDE_UI_NEXT_SCAN = now + 1.0
|
|
hide_hud()
|
|
end
|
|
end
|
|
end)
|
|
end
|
|
|
|
-- Restore targets from the previous policy (including VersionText) on upgrade.
|
|
if _G.__HIDE_UI_SCHEMA ~= 5 then
|
|
restore_hud()
|
|
_G.__HIDE_UI_SCHEMA = 5
|
|
_G.__HIDE_UI_NEXT_SCAN = 0
|
|
end
|
|
|
|
-- Use one render callback. Registering all camera events plus before-render
|
|
-- made the toggle callback run redundantly several times per frame.
|
|
if not _G.__HIDE_UI_REGISTERED then
|
|
local callback = function() _G.__HIDE_UI_TICK() end
|
|
local ok = pcall(function()
|
|
CS.UnityEngine.Application.onBeforeRender('+', callback)
|
|
end)
|
|
if not ok then
|
|
ok = pcall(function()
|
|
CS.UnityEngine.Application.onBeforeRender = CS.UnityEngine.Application.onBeforeRender + callback
|
|
end)
|
|
end
|
|
if not ok then
|
|
ok = pcall(function()
|
|
Camera.onPostRender('+', callback)
|
|
end)
|
|
if not ok then
|
|
ok = pcall(function() Camera.onPostRender = Camera.onPostRender + callback end)
|
|
end
|
|
end
|
|
_G.__HIDE_UI_REGISTERED = ok
|
|
if ok then
|
|
CS.UnityEngine.Debug.Log("<color=#FF00FF>[UI Toggle Script]</color> HUD-only HideUI loaded! Press 'ฃ' to toggle UI.")
|
|
else
|
|
CS.UnityEngine.Debug.Log("[GaC HideUI] Could not register a render callback.")
|
|
end
|
|
end
|