From 8ba89dd95e16c7361f9b6bc4c32a895351e7fa23 Mon Sep 17 00:00:00 2001 From: ManDude <7569514+ManDude@users.noreply.github.com> Date: Sat, 11 Jun 2022 00:04:16 +0100 Subject: [PATCH] fix IOP getting stuck on music load (#1437) * fix IOP getting stuck on music load * fix regression? and clang * fix a decomp * fix another regression * another * fix "all actors" * another regression! --- decompiler/config/all-types.gc | 2 +- game/overlord/iso.cpp | 16 +++++++++--- game/runtime.cpp | 4 +++ game/sce/iop.cpp | 8 ++++++ game/sce/iop.h | 8 +++--- game/system/IOP_Kernel.cpp | 15 +++++++++++ game/system/IOP_Kernel.h | 8 +++--- goal_src/engine/entity/entity.gc | 9 ++++--- goal_src/engine/game/generic-obs.gc | 2 +- goal_src/levels/common/basebutton.gc | 10 ++++++- goal_src/levels/common/blocking-plane.gc | 26 +++++++++---------- goal_src/levels/finalboss/robotboss.gc | 5 ++-- goal_src/levels/racer_common/racer.gc | 2 +- .../levels/village_common/villagep-obs.gc | 8 +++++- scripts/update-goal-src.py | 3 ++- .../sparticle/sparticle-launcher-h_REF.gc | 2 +- .../levels/common/blocking-plane_REF.gc | 26 +++++++++---------- 17 files changed, 98 insertions(+), 56 deletions(-) diff --git a/decompiler/config/all-types.gc b/decompiler/config/all-types.gc index bbbb33e91..c5b057256 100644 --- a/decompiler/config/all-types.gc +++ b/decompiler/config/all-types.gc @@ -27748,7 +27748,7 @@ ;; - Functions -(define-extern blocking-plane-spawn (function curve-control none)) +(define-extern blocking-plane-spawn (function curve-control none :behavior process)) (define-extern racer-effect (function none :behavior racer)) (define-extern blocking-plane-destroy (function none)) diff --git a/game/overlord/iso.cpp b/game/overlord/iso.cpp index 9503d19b9..94fd669a6 100644 --- a/game/overlord/iso.cpp +++ b/game/overlord/iso.cpp @@ -412,11 +412,14 @@ u32 ISOThread() { ReturnMessage(msg_from_mbx); } break; case LOAD_MUSIC: { + // NOTE: this check has been removed. there doesn't seem to be any issues with this, and + // it fixes some other issues. there doesn't appear to be any extra safety from it either + // if there's an in progress vag command, try again. - if (in_progress_vag_command && !in_progress_vag_command->paused) { - SendMbx(iso_mbx, msg_from_mbx); - break; - } + // if (in_progress_vag_command && !in_progress_vag_command->paused) { + // SendMbx(iso_mbx, msg_from_mbx); + // break; + // } auto buff = TryAllocateBuffer(BUFFER_PAGE_SIZE); if (!buff) { @@ -641,6 +644,11 @@ u32 ISOThread() { ProcessMessageData(); if (!read_buffer) { + // HACK!! sometimes when we want to exit, some other threads will wait for stuff to be loaded + // in such cases, we continue running until we're the last thread alive when it's safe to die + if (ThreadWantsExit(GetThreadId()) && OnlyThreadAlive(GetThreadId())) { + return 0; + } // didn't actually start a read, just delay for a bit I guess. DelayThread(100); } else { diff --git a/game/runtime.cpp b/game/runtime.cpp index b504fc26b..659652ed0 100644 --- a/game/runtime.cpp +++ b/game/runtime.cpp @@ -49,6 +49,7 @@ #include "game/overlord/srpc.h" #include "game/overlord/stream.h" #include "game/overlord/sbank.h" +#include "game/overlord/ssound.h" #include "game/graphics/gfx.h" @@ -330,6 +331,9 @@ RuntimeExitStatus exec_runtime(int argc, char** argv) { Gfx::Exit(); } + // hack to make the IOP die quicker if it's loading/unloading music + gMusicFade = 0; + deci_thread.join(); // DECI has been killed, shutdown! diff --git a/game/sce/iop.cpp b/game/sce/iop.cpp index 99e9f0574..525a892b9 100644 --- a/game/sce/iop.cpp +++ b/game/sce/iop.cpp @@ -217,4 +217,12 @@ s32 WakeupThread(s32 thid) { iop->kernel.WakeupThread(thid); return 0; } + +bool ThreadWantsExit(s32 thid) { + return iop->kernel.GetWantExit(thid); +} + +bool OnlyThreadAlive(s32 thid) { + return iop->kernel.OnlyThreadAlive(thid); +} } // namespace iop diff --git a/game/sce/iop.h b/game/sce/iop.h index f09a5ecb1..a5ce58d56 100644 --- a/game/sce/iop.h +++ b/game/sce/iop.h @@ -1,8 +1,5 @@ #pragma once -#ifndef JAK1_IOP_H -#define JAK1_IOP_H - #include "common/common_types.h" #define SMEM_Low (0) @@ -101,6 +98,9 @@ void DelayThread(u32 usec); s32 CreateThread(ThreadParam* param); s32 StartThread(s32 thid, u32 arg); s32 WakeupThread(s32 thid); +// kind of a hack +bool ThreadWantsExit(s32 thid); +bool OnlyThreadAlive(s32 thid); void sceSifInitRpc(int mode); void sceSifInitRpc(unsigned int mode); @@ -143,5 +143,3 @@ void LIBRARY_INIT(); void LIBRARY_register(::IOP* i); void LIBRARY_kill(); } // namespace iop - -#endif // JAK1_IOP_H diff --git a/game/system/IOP_Kernel.cpp b/game/system/IOP_Kernel.cpp index 4e76470c6..a1b16f57e 100644 --- a/game/system/IOP_Kernel.cpp +++ b/game/system/IOP_Kernel.cpp @@ -105,6 +105,21 @@ void IOP_Kernel::WakeupThread(s32 id) { // todo, should we ever switch directly to that thread? } +bool IOP_Kernel::OnlyThreadAlive(s32 thid) { + bool yes = false; + for (u64 i = 0; i < threads.size(); i++) { + if (threads[i].started && !threads[i].done) { + if (i != thid) { + return false; + } + if (i == thid) { + yes = true; + } + } + } + return yes; +} + /*! * Dispatch all IOP threads. */ diff --git a/game/system/IOP_Kernel.h b/game/system/IOP_Kernel.h index f5f093617..692db9d7b 100644 --- a/game/system/IOP_Kernel.h +++ b/game/system/IOP_Kernel.h @@ -123,11 +123,6 @@ class IOP_Kernel { * Returns if it got something. */ s32 PollMbx(void** msg, s32 mbx) { - if (_currentThread != -1 && threads.at(_currentThread).wantExit) { - // total hack - returning this value causes the ISO thread to error out and quit. - return KE_WAIT_DELETE; - } - ASSERT(mbx < (s32)mbxs.size()); s32 gotSomething = mbxs[mbx].empty() ? 0 : 1; if (gotSomething) { @@ -165,6 +160,9 @@ class IOP_Kernel { void* recvBuff, s32 recvSize); + bool GetWantExit(s32 thid) const { return threads.at(thid).wantExit; } + bool OnlyThreadAlive(s32 thid); + private: void setupThread(s32 id); void runThread(s32 id); diff --git a/goal_src/engine/entity/entity.gc b/goal_src/engine/entity/entity.gc index 07ff4918d..7a765d0a1 100644 --- a/goal_src/engine/entity/entity.gc +++ b/goal_src/engine/entity/entity.gc @@ -1720,9 +1720,7 @@ ) ) ) - ((#if PC_PORT - (or (= (-> s4-2 display?) 'actor) (with-pc (-> *pc-settings* force-actors?))) - (= (-> s4-2 display?) 'actor)) + ((= (-> s4-2 display?) 'actor) (let* ((s4-4 (-> s4-2 entity)) (s3-3 (-> s4-4 length)) ) @@ -1785,7 +1783,10 @@ (dotimes (s1-2 s2-4) (set! sv-32 (-> s3-5 data s1-2)) (cond - ((and (is-object-visible? s4-2 (-> sv-32 vis-id)) + ((and (#if PC_PORT + (or (with-pc (-> *pc-settings* force-actors?)) (is-object-visible? s4-2 (-> sv-32 vis-id))) + (is-object-visible? s4-2 (-> sv-32 vis-id)) + ) (zero? (logand (-> sv-32 perm status) (entity-perm-status bit-9 bit-10))) ) (when (not (or (-> sv-32 process) (logtest? (-> sv-32 perm status) (entity-perm-status bit-0 dead)) s0-1)) diff --git a/goal_src/engine/game/generic-obs.gc b/goal_src/engine/game/generic-obs.gc index cad9c8feb..051753c99 100644 --- a/goal_src/engine/game/generic-obs.gc +++ b/goal_src/engine/game/generic-obs.gc @@ -1687,7 +1687,7 @@ (let ((s5-0 (new-stack-matrix0)) (gp-0 (vector-reset! (new 'stack-no-clear 'vector))) ) - (let* ((f0-0 (analog-input (the-as int (+ (-> *cpad-list* cpads 0 rightx) -128)) 0.0 48.0 110.0 -1.0)) + (let* ((f0-0 (analog-input-horizontal-third (the-as int (+ (-> *cpad-list* cpads 0 rightx) -128)) 0.0 48.0 110.0 -1.0)) ;; changed for pc port (f1-1 (* -546.13336 f0-0)) (f0-2 (fmin 546.13336 (fmax -546.13336 f1-1))) ) diff --git a/goal_src/levels/common/basebutton.gc b/goal_src/levels/common/basebutton.gc index 98dbe3a21..f165d349a 100644 --- a/goal_src/levels/common/basebutton.gc +++ b/goal_src/levels/common/basebutton.gc @@ -498,8 +498,16 @@ (set! (-> s4-0 param 2) (the-as uint (target-pos 0))) (send-event-function *target* s4-0) ) + ;; NOTE : added case for "training" here. in the original game, the training level does NOT come + ;; with its own code for warp gates and buttons, and uses the villagep-obs imported from village1 + ;; instead. opengoal loads files different enough that warp from training to anywhere except village1 + ;; crashes the game due to running unlinked code. the original game also crashes, but it is not consistent. + ;; the citadel/lavatube case makes it so we wait until it's safe to unload both levels in the heaps, + ;; since the citadel warp gate is located in both levels at once (visually lavatube, technically citadel) + ;; we add "training" to the list here so that the training warp gate waits until it's safe to + ;; dispose the old code from memory. (case (-> self level) - (('citadel 'lavatube) + (('citadel 'lavatube 'training) (while (and *target* (zero? (logand (-> *target* draw status) (draw-status hidden)))) (suspend) ) diff --git a/goal_src/levels/common/blocking-plane.gc b/goal_src/levels/common/blocking-plane.gc index 94a76998a..6bcda2326 100644 --- a/goal_src/levels/common/blocking-plane.gc +++ b/goal_src/levels/common/blocking-plane.gc @@ -85,25 +85,23 @@ (none) ) -(defun blocking-plane-spawn ((arg0 curve-control)) - (with-pp - (cond - ((or (not arg0) (logtest? (-> arg0 flags) (path-control-flag not-found))) - ) - (else - (let ((s5-0 (the int (the float (+ (-> arg0 curve num-cverts) -1)))) - (s4-0 0) - ) - (while (< s4-0 s5-0) - (process-spawn blocking-plane arg0 s4-0 :to pp) - (+! s4-0 2) +(defbehavior blocking-plane-spawn process ((arg0 curve-control)) + (cond + ((or (not arg0) (logtest? (-> arg0 flags) (path-control-flag not-found))) + ) + (else + (let ((s5-0 (the int (the float (+ (-> arg0 curve num-cverts) -1)))) + (s4-0 0) ) + (while (< s4-0 s5-0) + (process-spawn blocking-plane arg0 s4-0 :to self) + (+! s4-0 2) ) ) ) - 0 - (none) ) + 0 + (none) ) (defun blocking-plane-destroy () diff --git a/goal_src/levels/finalboss/robotboss.gc b/goal_src/levels/finalboss/robotboss.gc index 84b64bc20..e79bc1029 100644 --- a/goal_src/levels/finalboss/robotboss.gc +++ b/goal_src/levels/finalboss/robotboss.gc @@ -215,9 +215,8 @@ ) ) ) - (when (and arg0 *debug-segment* (cpad-pressed? 1 x)) - (logclear! (-> *cpad-list* cpads 1 button0-abs 0) (pad-buttons x)) - (logclear! (-> *cpad-list* cpads 1 button0-rel 0) (pad-buttons x)) + (when (and arg0 *debug-segment* (cpad-pressed? 0 l3)) ;; NOTE : changed from (cpad-pressed? 1 x) + (cpad-clear! 0 l3) (go arg0) ) (none) diff --git a/goal_src/levels/racer_common/racer.gc b/goal_src/levels/racer_common/racer.gc index 652bc7250..72612f810 100644 --- a/goal_src/levels/racer_common/racer.gc +++ b/goal_src/levels/racer_common/racer.gc @@ -6,7 +6,7 @@ ;; dgos: L1, FIC, LAV, MIS, OGR, RACERP, ROL (define-extern blocking-plane-destroy (function none)) -(define-extern blocking-plane-spawn (function curve-control none)) +(define-extern blocking-plane-spawn (function curve-control none :behavior process)) ;; DECOMP BEGINS diff --git a/goal_src/levels/village_common/villagep-obs.gc b/goal_src/levels/village_common/villagep-obs.gc index 588295cbb..a7bdbad8b 100644 --- a/goal_src/levels/village_common/villagep-obs.gc +++ b/goal_src/levels/village_common/villagep-obs.gc @@ -619,8 +619,14 @@ ) ) ) + ;; note: they appear to be calling this on the wrong object. + ;; this doesn't actually cause any problems but corrupts the type of `float` in the symbol + ;; table because they they write to some field of arg0, which is actually #t and not a + ;; basebutton. The corruption is completely harmless but is annoying because it looks like + ;; a more severe memory corruption problem. So we fix it. (the-as int ((the-as (function basebutton symbol none) (find-parent-method warp-gate-switch 31)) - (the-as basebutton arg0) + ;;(the-as basebutton arg0) + obj arg0 ) ) diff --git a/scripts/update-goal-src.py b/scripts/update-goal-src.py index c7acb8885..7d8df4c76 100644 --- a/scripts/update-goal-src.py +++ b/scripts/update-goal-src.py @@ -42,7 +42,8 @@ files_with_modifications = [ "citadel-sages", "racer-part", "collectables-part", - "collectables" + "collectables", + "basebutton" ] for file in files: diff --git a/test/decompiler/reference/engine/sparticle/sparticle-launcher-h_REF.gc b/test/decompiler/reference/engine/sparticle/sparticle-launcher-h_REF.gc index 562fec8e9..b0377e2b5 100644 --- a/test/decompiler/reference/engine/sparticle/sparticle-launcher-h_REF.gc +++ b/test/decompiler/reference/engine/sparticle/sparticle-launcher-h_REF.gc @@ -13,7 +13,7 @@ (random-mult int32 :offset 12) (sym symbol :offset 4) (func symbol :offset 4) - (tex uint32 :offset 4) + (tex texture-id :offset 4) (pntr pointer :offset 4) (sound sound-spec :offset 4) ) diff --git a/test/decompiler/reference/levels/common/blocking-plane_REF.gc b/test/decompiler/reference/levels/common/blocking-plane_REF.gc index 7298059d6..e60e60215 100644 --- a/test/decompiler/reference/levels/common/blocking-plane_REF.gc +++ b/test/decompiler/reference/levels/common/blocking-plane_REF.gc @@ -94,25 +94,23 @@ ;; definition for function blocking-plane-spawn ;; INFO: Return type mismatch int vs none. -(defun blocking-plane-spawn ((arg0 curve-control)) - (with-pp - (cond - ((or (not arg0) (logtest? (-> arg0 flags) (path-control-flag not-found))) - ) - (else - (let ((s5-0 (the int (the float (+ (-> arg0 curve num-cverts) -1)))) - (s4-0 0) - ) - (while (< s4-0 s5-0) - (process-spawn blocking-plane arg0 s4-0 :to pp) - (+! s4-0 2) +(defbehavior blocking-plane-spawn process ((arg0 curve-control)) + (cond + ((or (not arg0) (logtest? (-> arg0 flags) (path-control-flag not-found))) + ) + (else + (let ((s5-0 (the int (the float (+ (-> arg0 curve num-cverts) -1)))) + (s4-0 0) ) + (while (< s4-0 s5-0) + (process-spawn blocking-plane arg0 s4-0 :to self) + (+! s4-0 2) ) ) ) - 0 - (none) ) + 0 + (none) ) ;; definition for function blocking-plane-destroy