From 266b423efa5f66952c179d7655a45a75a263da5d Mon Sep 17 00:00:00 2001 From: water111 <48171810+water111@users.noreply.github.com> Date: Sat, 4 Jan 2025 11:39:28 -0500 Subject: [PATCH] [jak3] Avoid language 255 issue (#3818) In Jak 3, the default PC settings file would have a language of 255 because it runs before the first settings update. This would cause the game to crash the second time it is started. I also added this simple imgui window to see the names of streams in the "SPU" memory, which has been useful for debugging ![image](https://github.com/user-attachments/assets/0a9d6af7-c423-4d8a-a461-faf45e350f33) --------- Co-authored-by: water111 --- game/graphics/opengl_renderer/debug_gui.cpp | 17 +++++ game/graphics/opengl_renderer/debug_gui.h | 3 + game/overlord/jak3/dma.cpp | 74 +++++++++++++++++++++ game/overlord/jak3/dma.h | 16 +++++ goal_src/jak3/pc/pckernel.gc | 8 ++- 5 files changed, 117 insertions(+), 1 deletion(-) diff --git a/game/graphics/opengl_renderer/debug_gui.cpp b/game/graphics/opengl_renderer/debug_gui.cpp index c8acd7f0f88..0462bb01eae 100644 --- a/game/graphics/opengl_renderer/debug_gui.cpp +++ b/game/graphics/opengl_renderer/debug_gui.cpp @@ -6,6 +6,7 @@ #include "game/graphics/display.h" #include "game/graphics/gfx.h" #include "game/graphics/screenshot.h" +#include "game/overlord/jak3/dma.h" #include "game/system/hid/sdl_util.h" #include "fmt/core.h" @@ -104,6 +105,7 @@ void OpenGlDebugGui::draw(const DmaStats& dma_stats) { ImGui::MenuItem("Profiler", nullptr, &m_draw_profiler); ImGui::MenuItem("Small Profiler", nullptr, &small_profiler); ImGui::MenuItem("Loader", nullptr, &m_draw_loader); + ImGui::MenuItem("Overlord", nullptr, &m_draw_overlord); if (ImGui::MenuItem("Reboot In Debug Mode!")) { want_reboot_in_debug = true; } @@ -215,4 +217,19 @@ void OpenGlDebugGui::draw(const DmaStats& dma_stats) { if (m_draw_frame_time) { m_frame_timer.draw_window(dma_stats); } + + if (should_draw_overlord_debug()) { + draw_overlord_debug_menu(); + } +} + +void OpenGlDebugGui::draw_overlord_debug_menu() { + ImGui::Begin("Overlord"); + + for (int stream_idx = 0; stream_idx < 6; stream_idx++) { + auto& stream = jak3::g_overlord_stream_memory.infos[stream_idx]; + + ImGui::Text("%30s [%3d] | %30s [%3d]", stream[0].name.chars, stream[0].idx, + stream[1].name.chars, stream[1].idx); + } } diff --git a/game/graphics/opengl_renderer/debug_gui.h b/game/graphics/opengl_renderer/debug_gui.h index 7ed401b213e..91101bff959 100644 --- a/game/graphics/opengl_renderer/debug_gui.h +++ b/game/graphics/opengl_renderer/debug_gui.h @@ -50,6 +50,7 @@ class OpenGlDebugGui { bool should_draw_subtitle_editor() const { return master_enable && m_subtitle_editor; } bool should_draw_filters_menu() const { return master_enable && m_filters_menu; } bool should_draw_loader_menu() const { return master_enable && m_draw_loader; } + bool should_draw_overlord_debug() const { return master_enable && m_draw_overlord; } bool should_advance_frame() { return m_frame_timer.should_advance_frame(); } bool should_gl_finish() const { return m_frame_timer.do_gl_finish; } @@ -72,11 +73,13 @@ class OpenGlDebugGui { bool master_enable = false; private: + void draw_overlord_debug_menu(); FrameTimeRecorder m_frame_timer; bool m_draw_frame_time = false; bool m_draw_profiler = false; bool m_draw_debug = false; bool m_draw_loader = false; + bool m_draw_overlord = false; bool m_subtitle_editor = false; bool m_filters_menu = false; bool m_want_screenshot = false; diff --git a/game/overlord/jak3/dma.cpp b/game/overlord/jak3/dma.cpp index 5fced6b50c5..30703c30c67 100644 --- a/game/overlord/jak3/dma.cpp +++ b/game/overlord/jak3/dma.cpp @@ -13,6 +13,7 @@ #define VOICE_BIT(voice) (1 << ((voice) >> 1)) namespace jak3 { +OverlordStreamMemory g_overlord_stream_memory; using namespace iop; namespace { @@ -51,6 +52,8 @@ struct DmaInterruptHandlerHack { bool pending = false; } g_DmaInterruptHack; +const char* g_current_stream_name = 0; + } // namespace void jak3_overlord_init_globals_dma() { @@ -139,10 +142,74 @@ int voice_trans_wrapper(s16 chan, u32 mode, const void* iop_addr, u32 spu_addr, } else { g_voiceTransRunning = true; g_voiceTransTime = GetSystemTimeLow(); + + switch (spu_addr) { + case 0x5040: + g_overlord_stream_memory.update_name(g_current_stream_name, 0, 0); + break; + case 0x7040: + g_overlord_stream_memory.update_name(g_current_stream_name, 0, 1); + break; + case 0x9080: + g_overlord_stream_memory.update_name(g_current_stream_name, 1, 0); + break; + case 0xb080: + g_overlord_stream_memory.update_name(g_current_stream_name, 1, 1); + break; + case 0xd0c0: + g_overlord_stream_memory.update_name(g_current_stream_name, 2, 0); + break; + case 0xf0c0: + g_overlord_stream_memory.update_name(g_current_stream_name, 2, 1); + break; + case 0x11100: + g_overlord_stream_memory.update_name(g_current_stream_name, 3, 0); + break; + case 0x13100: + g_overlord_stream_memory.update_name(g_current_stream_name, 3, 1); + break; + case 0x15140: + g_overlord_stream_memory.update_name(g_current_stream_name, 4, 0); + break; + case 0x17140: + g_overlord_stream_memory.update_name(g_current_stream_name, 4, 1); + break; + case 0x19180: + g_overlord_stream_memory.update_name(g_current_stream_name, 5, 0); + break; + case 0x1b180: + g_overlord_stream_memory.update_name(g_current_stream_name, 5, 1); + break; + } return sceSdVoiceTrans(chan, mode, iop_addr, spu_addr, size); } } +OverlordStreamMemory::OverlordStreamMemory() { + for (auto& x : infos) { + for (auto& y : x) { + y.idx = 0; + strcpy(y.name.chars, "Uninitialized"); + } + } +} + +void OverlordStreamMemory::update_name(const char* input, int stream, int side) { + auto& info = infos[stream][side]; + if (!input) { + strcpy(info.name.chars, "???"); + info.idx = 0; + } else { + if (strcmp(input, info.name.chars) == 0) { + info.idx++; + } else { + info.idx = 0; + strncpy(info.name.chars, input, 48); + info.name.chars[47] = 0; + } + } +} + u32 read_rate_calc(u32 pitch) { u64 pitch1 = (pitch >> 3); u64 mult_result = pitch1 * 0x2492'4925ull; @@ -464,6 +531,13 @@ int DMA_SendToSPUAndSync(const u8* iop_mem, ovrld_log(LogCategory::SPU_DMA_STR, "DMA to SPU requested for {}, {} bytes to 0x{:x}, currently busy? {}", cmd ? cmd->name : "NO-CMD", length, spu_addr, g_bSpuDmaBusy); + if (cmd) { + g_current_stream_name = cmd->name; + } else { + const static char* unknown = "unknown"; + g_current_stream_name = unknown; + } + if (g_bSpuDmaBusy == 0) { // not busy, we can actually start dma now. g_nSpuDmaChannel = snd_GetFreeSPUDMA(); diff --git a/game/overlord/jak3/dma.h b/game/overlord/jak3/dma.h index f8e689d6ab4..12cb0485ac8 100644 --- a/game/overlord/jak3/dma.h +++ b/game/overlord/jak3/dma.h @@ -2,6 +2,8 @@ #include "common/common_types.h" +#include "game/overlord/jak3/rpc_interface.h" + namespace jak3 { void jak3_overlord_init_globals_dma(); struct ISO_VAGCommand; @@ -29,4 +31,18 @@ struct DmaQueueEntry { u32 num_isobuffered_chunks = 0; }; void dma_intr_hack(); + +struct OverlordStreamMemory { + struct Info { + SoundStreamName name; + int idx = 0; + }; + Info infos[6][2]; + + OverlordStreamMemory(); + void update_name(const char* input, int stream, int side); +}; + +extern OverlordStreamMemory g_overlord_stream_memory; + } // namespace jak3 \ No newline at end of file diff --git a/goal_src/jak3/pc/pckernel.gc b/goal_src/jak3/pc/pckernel.gc index c684f355b81..56c8a04376a 100644 --- a/goal_src/jak3/pc/pckernel.gc +++ b/goal_src/jak3/pc/pckernel.gc @@ -249,7 +249,13 @@ ) (defmethod get-game-language ((obj pc-settings-jak3)) - (get-current-language) + ;; if the language is unintialized, return the default + (let ((lang (get-current-language))) + (if (= lang 255) + (scf-get-language) + lang + ) + ) )