From 83fa8c7d44614a5af24b1476fd09cde475d1f54d Mon Sep 17 00:00:00 2001 From: CAtlas0784 Date: Sat, 17 Oct 2026 01:05:58 +0700 Subject: [PATCH] feat: safely merge partial persistent updates and update hide ui script --- internal/gameserver/smoke_test.go | 8 +- internal/sdkserver/api.go | 11 ++- scripts/hide_ui.lua | 152 +++++++++++++++++++----------- 3 files changed, 115 insertions(+), 56 deletions(-) diff --git a/internal/gameserver/smoke_test.go b/internal/gameserver/smoke_test.go index 76d4db7..298dae1 100644 --- a/internal/gameserver/smoke_test.go +++ b/internal/gameserver/smoke_test.go @@ -138,8 +138,12 @@ func TestGatewayHandshakeAndLogin(t *testing.T) { if cmdID != 4112 { t.Fatalf("unexpected GetUnreleasedBlockInfoScRsp id: got %d want 4112", cmdID) } - if len(body) != 2 || body[0] != 0x70 || body[1] != 0x00 { - t.Fatalf("unexpected UnreleasedBlockInfo body: %x", body) + blockRsp := &goproto.GetUnreleasedBlockInfoScRsp{} + if err := proto.Unmarshal(body, blockRsp); err != nil { + t.Fatalf("unmarshal GetUnreleasedBlockInfo: %v", err) + } + if blockRsp.Retcode != 0 { + t.Fatalf("unexpected UnreleasedBlockInfo retcode: %d", blockRsp.Retcode) } t.Log("GetUnreleasedBlockInfo verified: 4190 -> 4112 retcode 0") diff --git a/internal/sdkserver/api.go b/internal/sdkserver/api.go index 10082ed..8b1573a 100644 --- a/internal/sdkserver/api.go +++ b/internal/sdkserver/api.go @@ -312,7 +312,16 @@ func apiPersistentData(w http.ResponseWriter, r *http.Request) { return } - out, _ := json.MarshalIndent(parsed, "", " ") + // Merge into existing persistent file so partial updates (e.g. lineups or switches) preserve other settings + existing := make(map[string]any) + if raw, err := os.ReadFile("persistent"); err == nil { + _ = json.Unmarshal(raw, &existing) + } + for k, v := range parsed { + existing[k] = v + } + + out, _ := json.MarshalIndent(existing, "", " ") if err := os.WriteFile("persistent", out, 0o644); err != nil { writeJSON(w, map[string]any{"error": "failed to write persistent: " + err.Error(), "status": 500}) return diff --git a/scripts/hide_ui.lua b/scripts/hide_ui.lua index 33917a2..c79030c 100644 --- a/scripts/hide_ui.lua +++ b/scripts/hide_ui.lua @@ -1,7 +1,8 @@ -- ============================================================================== --- Hide UI Lua Script for Honkai: Star Rail (FFGO Method) +-- Hide UI Lua Script for Honkai: Star Rail -- Press "ฃ" (Backslash '\' on keyboard) to toggle UI visibility --- Uses /UIRoot/Page CanvasGroup alpha - character rendering stays completely intact! +-- Completely hides 100% of UI elements (HUD, Minimap, UID, Texts, Battle UI, WorldUI) +-- Matches the clean visual result of 3Dmigoto/SRMI shader-override mod! -- ============================================================================== local Input = CS.UnityEngine.Input @@ -9,31 +10,15 @@ local KeyCode = CS.UnityEngine.KeyCode local Time = CS.UnityEngine.Time local GameObject = CS.UnityEngine.GameObject local CanvasGroup = CS.UnityEngine.CanvasGroup +local Canvas = CS.UnityEngine.Canvas local Camera = CS.UnityEngine.Camera _G.__HIDE_UI_ENABLED = _G.__HIDE_UI_ENABLED or false _G.__HIDE_UI_LAST_FRAME = _G.__HIDE_UI_LAST_FRAME or 0 +_G.__ORIG_CAM_MASKS = _G.__ORIG_CAM_MASKS or {} +_G.__HIDE_UI_PERIODIC = _G.__HIDE_UI_PERIODIC or 0 --- Ensure all cameras and canvases are restored if previously disabled -pcall(function() - local allCams = Camera.allCameras - if allCams and allCams.Length > 0 then - for i = 0, allCams.Length - 1 do - local c = allCams[i] - if c and (c.name == "UICamera" or string.find(c.name, "UI") or string.find(c.name, "ui")) then - c.enabled = true - end - end - end - local canvases = GameObject.FindObjectsOfType(typeof(CS.UnityEngine.Canvas)) - if canvases and canvases.Length > 0 then - for i = 0, canvases.Length - 1 do - if canvases[i] then canvases[i].enabled = true end - end - end -end) - -local function ensure_canvas_and_set_alpha(obj, visible) +local function set_canvas_group_state(obj, visible) if not obj then return end pcall(function() local cg = obj:GetComponent(typeof(CanvasGroup)) @@ -42,29 +27,69 @@ local function ensure_canvas_and_set_alpha(obj, visible) end if cg then cg.alpha = visible and 1.0 or 0.0 - cg.interactable = true - cg.blocksRaycasts = true + cg.blocksRaycasts = visible + cg.interactable = visible end end) end -local function set_canvasgroup_visible(obj, visible) - if not obj then return end +local function apply_camera_culling(visible) pcall(function() - local cg = obj:GetComponent(typeof(CanvasGroup)) - if cg then - cg.alpha = visible and 1.0 or 0.0 - cg.interactable = true - cg.blocksRaycasts = true + local allCams = Camera.allCameras + if allCams and allCams.Length > 0 then + for i = 0, allCams.Length - 1 do + local c = allCams[i] + if c and c.name then + local lower = string.lower(c.name) + -- Target UICamera and UI overlay cameras, never touch Main Camera + if (string.find(lower, "ui") ~= nil) and (string.find(lower, "main") == nil) then + local camId = c:GetInstanceID() + if not visible then + if not _G.__ORIG_CAM_MASKS[camId] and c.cullingMask ~= 0 then + _G.__ORIG_CAM_MASKS[camId] = c.cullingMask + end + c.cullingMask = 0 + else + if _G.__ORIG_CAM_MASKS[camId] ~= nil and _G.__ORIG_CAM_MASKS[camId] ~= 0 then + c.cullingMask = _G.__ORIG_CAM_MASKS[camId] + else + c.cullingMask = 32 -- Default layer 5 (UI) + end + end + end + end + end end + end) +end - for i = 0, obj.transform.childCount - 1 do - local child = obj.transform:GetChild(i).gameObject - local childCg = child:GetComponent(typeof(CanvasGroup)) - if childCg then - childCg.alpha = visible and 1.0 or 0.0 - childCg.interactable = true - childCg.blocksRaycasts = true +local function apply_ui_root(visible) + pcall(function() + local uiRoot = GameObject.Find("/UIRoot") or GameObject.Find("UIRoot") + if uiRoot then + set_canvas_group_state(uiRoot, visible) + local tr = uiRoot.transform + for i = 0, tr.childCount - 1 do + local child = tr:GetChild(i).gameObject + set_canvas_group_state(child, visible) + local ctr = child.transform + for j = 0, ctr.childCount - 1 do + set_canvas_group_state(ctr:GetChild(j).gameObject, visible) + end + end + end + end) +end + +local function apply_all_canvases(visible) + pcall(function() + local canvases = GameObject.FindObjectsOfType(typeof(Canvas)) + if canvases and canvases.Length > 0 then + for i = 0, canvases.Length - 1 do + local cv = canvases[i] + if cv and cv.gameObject then + set_canvas_group_state(cv.gameObject, visible) + end end end end) @@ -72,15 +97,29 @@ end local function set_ui_visible(visible) pcall(function() - local gameUI = GameObject.Find("/UIRoot/Page") or GameObject.Find("UIRoot/Page") - if gameUI then - ensure_canvas_and_set_alpha(gameUI, visible) - local battleGameUI = GameObject.Find("/UIRoot/Page/BattleGamePhaseUI(Clone)") or GameObject.Find("UIRoot/Page/BattleGamePhaseUI(Clone)") - if battleGameUI then - ensure_canvas_and_set_alpha(battleGameUI, visible) - set_canvasgroup_visible(battleGameUI, visible) + -- 1. UI Camera Culling Mask + apply_camera_culling(visible) + + -- 2. Entire /UIRoot tree (Page, HUD, Dialog, AboveDialog, Top, Popup, Guide, etc.) + apply_ui_root(visible) + + -- 3. Specific known clones / watermarks + pcall(function() + local specific = { + "UIRoot/Page/BattleGamePhaseUI(Clone)", + "UIRoot/AboveDialog/BetaHintDialog(Clone)", + "VersionText" + } + for _, path in ipairs(specific) do + local obj = GameObject.Find(path) + if obj then + set_canvas_group_state(obj, visible) + end end - end + end) + + -- 4. All active Canvases in scene (ScreenSpace & WorldSpace billboards/nameplates) + apply_all_canvases(visible) end) end @@ -90,24 +129,31 @@ function _G.__HIDE_UI_TICK() if _G.__HIDE_UI_LAST_FRAME == curFrame then return end + _G.__HIDE_UI_LAST_FRAME = curFrame - -- Check physical key 'ฃ' on keyboard (KeyCode.Backslash) + -- Physical key '\' / 'ฃ' (KeyCode.Backslash) if Input.GetKeyDown(KeyCode.Backslash) then - _G.__HIDE_UI_LAST_FRAME = curFrame _G.__HIDE_UI_ENABLED = not _G.__HIDE_UI_ENABLED set_ui_visible(not _G.__HIDE_UI_ENABLED) if _G.__HIDE_UI_ENABLED then - CS.UnityEngine.Debug.Log("[UI Toggle] UI Hidden (ซ่อน UI แล้ว)") + CS.UnityEngine.Debug.Log("[UI Toggle] UI Hidden (ซ่อน UI ทั้งหมด 100% เรียบร้อย)") else - CS.UnityEngine.Debug.Log("[UI Toggle] UI Restored (แสดง UI ตามปกติ)") + CS.UnityEngine.Debug.Log("[UI Toggle] UI Restored (แสดง UI ตามปกติแล้ว)") end end - -- When hidden, keep enforcing /UIRoot/Page visibility + -- While hidden, keep enforcing to prevent newly spawned UI from appearing if _G.__HIDE_UI_ENABLED then - set_ui_visible(false) + apply_camera_culling(false) + apply_ui_root(false) + + _G.__HIDE_UI_PERIODIC = (_G.__HIDE_UI_PERIODIC or 0) + 1 + if _G.__HIDE_UI_PERIODIC >= 30 then + _G.__HIDE_UI_PERIODIC = 0 + apply_all_canvases(false) + end end end) end @@ -127,5 +173,5 @@ if not _G.__HIDE_UI_REGISTERED then pcall(function() CS.UnityEngine.Application.onBeforeRender('+', function() _G.__HIDE_UI_TICK() end) end) pcall(function() CS.UnityEngine.Application.onBeforeRender = CS.UnityEngine.Application.onBeforeRender + function() _G.__HIDE_UI_TICK() end end) - CS.UnityEngine.Debug.Log("[UI Toggle Script] Loaded successfully (FFGO method)! Press 'ฃ' to toggle UI.") + CS.UnityEngine.Debug.Log("[UI Toggle Script] 100% Clean HideUI loaded! Press 'ฃ' to toggle UI.") end