Keep offline notices out of selectable menu rows

This commit is contained in:
Debugger
2026-09-14 18:37:37 -04:00
parent b7625dfbe1
commit 4dd2ec689c
2 changed files with 50 additions and 3 deletions
+33 -2
View File
@@ -5,6 +5,7 @@ local threads_created = 0
local thread_callbacks = {} local thread_callbacks = {}
local thread_origins = {} local thread_origins = {}
local menu_back_calls = 0 local menu_back_calls = 0
local notices, deleted_notices = {}, {}
local memory_values = {} local memory_values = {}
local last_pointer local last_pointer
local function ref() local function ref()
@@ -33,7 +34,14 @@ menu = {
return ref() return ref()
end, end,
readonly = function() counters.text = counters.text + 1; return ref() end, readonly = function() counters.text = counters.text + 1; return ref() end,
divider = function() return ref() end, divider = function(_, label)
local result = ref()
if label == "Unavailable in Single Player." or label == "Waiting for game..." then
notices[result.id] = label
end
return result
end,
delete = function(value) deleted_notices[value.id] = true end,
get_value = function() return false end, get_value = function() return false end,
set_value = function() end, set_value = function() end,
get_menu_name = function() return "" end, get_menu_name = function() return "" end,
@@ -175,8 +183,26 @@ for i = before_load + 1, #native_calls do
assert(native_calls[i] ~= "B3271D7AB655B441", "Menu materialization wrote a stat") assert(native_calls[i] ~= "B3271D7AB655B441", "Menu materialization wrote a stat")
end end
assert(counters.list >= 60, "Missing tab hierarchy: " .. counters.list) assert(counters.list >= 60, "Missing tab hierarchy: " .. counters.list)
assert(counters.action >= 945, "Missing initial actions: " .. counters.action) if not os.getenv("UM_START_OFFLINE") then
assert(counters.action >= 940, "Missing initial actions: " .. counters.action)
end
assert(#compat.imgui_sections >= 43, "Missing ImGui sections: " .. #compat.imgui_sections) assert(#compat.imgui_sections >= 43, "Missing ImGui sections: " .. #compat.imgui_sections)
if os.getenv("UM_START_OFFLINE") then
local viewport_thread = coroutine.create(thread_callbacks[#thread_callbacks])
local ok, message = coroutine.resume(viewport_thread)
assert(ok, message)
assert(next(notices), "Single Player warning did not appear as a non-selectable row")
for _, label in pairs(notices) do
assert(not label:find("\n", 1, true), "Single Player warning spans multiple menu rows")
end
session_started = true
ok, message = coroutine.resume(viewport_thread)
assert(ok, message)
for id in pairs(notices) do
assert(deleted_notices[id], "Single Player warning remained after joining online")
end
assert(counters.action >= 940, "Online controls did not appear after joining: " .. counters.action)
end
for _, name in ipairs({"Self Menu", "Story Mode", "Recovery Menu", "Online Services Menu", for _, name in ipairs({"Self Menu", "Story Mode", "Recovery Menu", "Online Services Menu",
"Collectibles", "Events Menu", "YimResupplier", "Heists Data Editor Menu", "Kortz Center Heist"}) do "Collectibles", "Events Menu", "YimResupplier", "Heists Data Editor Menu", "Kortz Center Heist"}) do
assert(list_names[name], "Missing original menu section: " .. name) assert(list_names[name], "Missing original menu section: " .. name)
@@ -200,6 +226,11 @@ for i = before + 1, #native_calls do
if native_calls[i] == "B3271D7AB655B441" then stat_writes = stat_writes + 1 end if native_calls[i] == "B3271D7AB655B441" then stat_writes = stat_writes + 1 end
end end
assert(stat_writes == 2, "Rank action did not write both stats: " .. stat_writes) assert(stat_writes == 2, "Rank action did not write both stats: " .. stat_writes)
session_started = false
local story_viewport = coroutine.create(thread_callbacks[#thread_callbacks])
local story_ok, story_error = coroutine.resume(story_viewport)
assert(story_ok, story_error)
session_started = true
local story_cash_action local story_cash_action
for _, action in ipairs(actions) do for _, action in ipairs(actions) do
if action.label == "Add 1 Mil Cash $" then story_cash_action = action.callback; break end if action.label == "Add 1 Mil Cash $" then story_cash_action = action.callback; break end
+17 -1
View File
@@ -158,7 +158,6 @@ end
network = network or {} network = network or {}
function network.is_session_started() function network.is_session_started()
if scan_context then return scan_context ~= "story" end
return invoke("9DE624D2FC4B603F", {}, "bool") return invoke("9DE624D2FC4B603F", {}, "bool")
end end
function network.force_script_host(name) function network.force_script_host(name)
@@ -366,7 +365,12 @@ end
local function replay(section, event) local function replay(section, event)
current_section, current_event = section, event current_section, current_event = section, event
building, widget_index, widget_occurrences, text_occurrences, separator_occurrences, parent_stack = false, 0, {}, {}, {}, {section.parent} building, widget_index, widget_occurrences, text_occurrences, separator_occurrences, parent_stack = false, 0, {}, {}, {}, {section.parent}
section.notice_seen = false
section.callback() section.callback()
if section.notice_ref and not section.notice_seen then
menu.delete(section.notice_ref)
section.notice_ref = nil
end
current_section, current_event, parent_stack = nil, nil, nil current_section, current_event, parent_stack = nil, nil, nil
end end
local function event_for(id, value) local function event_for(id, value)
@@ -482,6 +486,17 @@ function ImGui.Text(value)
end end
return return
end end
local compact = label:gsub("%s+", " "):match("^%s*(.-)%s*$")
if compact == "Unavailable in Single Player." or compact == "Waiting for game..." then
current_section.notice_seen = true
if not current_section.notice_ref then
current_section.notice_ref = menu.divider(current_parent(), compact)
elseif menu.get_menu_name(current_section.notice_ref) ~= compact then
menu.set_menu_name(current_section.notice_ref, compact)
end
return
end
label = compact
local text_id = source_key(text_occurrences, "text:" .. tostring(#current_section.text_refs + 1)) local text_id = source_key(text_occurrences, "text:" .. tostring(#current_section.text_refs + 1))
if not current_section.text_refs[text_id] then if not current_section.text_refs[text_id] then
current_section.text_refs[text_id] = menu.readonly(current_parent(), label, "") current_section.text_refs[text_id] = menu.readonly(current_parent(), label, "")
@@ -568,6 +583,7 @@ function compat.materialize_imgui()
section.text_refs, section.widget_refs, section.separator_refs = {}, {}, {} section.text_refs, section.widget_refs, section.separator_refs = {}, {}, {}
section.containers, section.containers_by_id = {}, {} section.containers, section.containers_by_id = {}, {}
section.tooltip, section.last_ref, section.last_text = false, nil, nil section.tooltip, section.last_ref, section.last_text = false, nil, nil
section.notice_ref, section.notice_seen = nil, false
current_section, current_event = section, nil current_section, current_event = section, nil
building, widget_index, widget_occurrences, text_occurrences, separator_occurrences, parent_stack = true, 0, {}, {}, {}, {section.parent} building, widget_index, widget_occurrences, text_occurrences, separator_occurrences, parent_stack = true, 0, {}, {}, {}, {section.parent}
scan_context = section.path:find("Story Mode", 1, true) and "story" or "online" scan_context = section.path:find("Story Mode", 1, true) and "story" or "online"