[jak2] double load dgo workaround (#2331)

fixes #2282
This commit is contained in:
ManDude
2023-03-19 20:30:23 +00:00
committed by GitHub
parent d46f790973
commit d1260a0c0b
6 changed files with 109 additions and 46 deletions
+71 -32
View File
@@ -70,10 +70,14 @@ s32 iso_thread;
s32 dgo_thread;
s32 str_thread;
s32 play_thread;
VagDir gVagDir;
VagDirJak2 gVagDir;
u32 gPlayPos;
static RPC_Dgo_Cmd sRPCBuff[1]; // todo move...
DgoCommand scmd;
// todo move...
static RPC_Dgo_Cmd sRPCBuff[1];
DgoCommand scmd; // renamed to sLoadDGO in Jak 2
// :-)
#define sLoadDGO scmd
static VagCommand vag_cmd;
VagCommand* gVAGCMD = nullptr;
s32 gDialogVolume = 0;
@@ -108,9 +112,8 @@ void iso_init_globals() {
* Initialize the ISO Driver.
* Requires a buffer large enough to hold 3 sector (or 4 if you have DUP files)
*/
static MsgPacket not_on_stack_sync;
void InitDriver(u8* buffer) {
MsgPacket msg_packet;
if (!isofs->init(buffer)) {
// succesful init!
iso_init_flag = 0;
@@ -118,7 +121,10 @@ void InitDriver(u8* buffer) {
// you idiots, you're giving the kernel a pointer to a stack variable!
// (this is fixed in Jak 1 Japan and NTSC Greatest Hits)
SendMbx(sync_mbx, &msg_packet);
// SendMbx(sync_mbx, &msg_packet);
// whoever fixed that bug felt similarly about it
SendMbx(sync_mbx, &not_on_stack_sync);
}
/*!
@@ -161,8 +167,10 @@ u32 InitISOFS(const char* fs_mode, const char* loading_screen) {
// mark us as NOT initialized.
iso_init_flag = 1;
while (!DMA_SendToSPUAndSync(&VAG_SilentLoop, 0x30, gTrapSRAM)) {
DelayThread(1000);
if (g_game_version == GameVersion::Jak1) {
while (!DMA_SendToSPUAndSync(&VAG_SilentLoop, 0x30, gTrapSRAM)) {
DelayThread(1000);
}
}
// INITIALIZE MESSAGE BOXES
@@ -171,6 +179,9 @@ u32 InitISOFS(const char* fs_mode, const char* loading_screen) {
mbx_param.option = 0;
iso_mbx = CreateMbx(&mbx_param);
if (iso_mbx <= 0) {
printf("IOP: ======================================================================\n");
printf("IOP : iso InitISOFS : Cannot create ISO mbx\n");
printf("IOP: ======================================================================\n");
return 1;
}
@@ -178,6 +189,9 @@ u32 InitISOFS(const char* fs_mode, const char* loading_screen) {
mbx_param.option = 0;
dgo_mbx = CreateMbx(&mbx_param);
if (dgo_mbx <= 0) {
printf("IOP: ======================================================================\n");
printf("IOP : iso InitISOFS : Cannot create DGO mbx\n");
printf("IOP: ======================================================================\n");
return 1;
}
@@ -185,6 +199,9 @@ u32 InitISOFS(const char* fs_mode, const char* loading_screen) {
mbx_param.option = 0;
sync_mbx = CreateMbx(&mbx_param);
if (sync_mbx <= 0) {
printf("IOP: ======================================================================\n");
printf("IOP : iso InitISOFS : Cannot create sync mbx\n");
printf("IOP: ======================================================================\n");
return 1;
}
@@ -198,6 +215,9 @@ u32 InitISOFS(const char* fs_mode, const char* loading_screen) {
strcpy(thread_param.name, "ISOThread");
iso_thread = CreateThread(&thread_param);
if (iso_thread <= 0) {
printf("IOP: ======================================================================\n");
printf("IOP : iso InitISOFS : Cannot create ISO thread\n");
printf("IOP: ======================================================================\n");
return 1;
}
@@ -209,6 +229,9 @@ u32 InitISOFS(const char* fs_mode, const char* loading_screen) {
strcpy(thread_param.name, "DGOThread");
dgo_thread = CreateThread(&thread_param);
if (dgo_thread <= 0) {
printf("IOP: ======================================================================\n");
printf("IOP : iso InitISOFS : Cannot create DGO thread\n");
printf("IOP: ======================================================================\n");
return 1;
}
@@ -220,6 +243,9 @@ u32 InitISOFS(const char* fs_mode, const char* loading_screen) {
strcpy(thread_param.name, "STRThread");
str_thread = CreateThread(&thread_param);
if (str_thread <= 0) {
printf("IOP: ======================================================================\n");
printf("IOP : iso InitISOFS : Cannot create STR thread\n");
printf("IOP: ======================================================================\n");
return 1;
}
@@ -231,6 +257,9 @@ u32 InitISOFS(const char* fs_mode, const char* loading_screen) {
strcpy(thread_param.name, "PLAYThread");
play_thread = CreateThread(&thread_param);
if (play_thread <= 0) {
printf("IOP: ======================================================================\n");
printf("IOP : iso InitISOFS : Cannot create PLAY thread\n");
printf("IOP: ======================================================================\n");
return 1;
}
@@ -246,7 +275,12 @@ u32 InitISOFS(const char* fs_mode, const char* loading_screen) {
// LOAD VAGDIR file
FileRecord* vagdir_file = FindISOFile("VAGDIR.AYB");
if (vagdir_file) {
LoadISOFileToIOP(vagdir_file, &gVagDir, sizeof(gVagDir));
LoadISOFileToIOP(vagdir_file, &gVagDir,
g_game_version == GameVersion::Jak1 ? sizeof(VagDir) : sizeof(VagDirJak2));
} else {
printf("IOP: ======================================================================\n");
printf("IOP : iso InitISOFS : cannot load VAG directory\n");
printf("IOP: ======================================================================\n");
}
FileRecord* loading_screen_file = FindISOFile(loading_screen);
if (loading_screen_file) {
@@ -381,18 +415,22 @@ u32 ISOThread() {
}
// Got a DGO command. There is one LoadDGO command for the entire DGO.
// queued successfully, open the file.
auto* load_single_cmd = (IsoCommandLoadSingle*)msg_from_mbx;
load_single_cmd->fd = isofs->open(load_single_cmd->file_record, -1);
if (!load_single_cmd->fd) {
auto* load_dgo_cmd = (DgoCommand*)msg_from_mbx;
load_dgo_cmd->fd = isofs->open(load_dgo_cmd->fr, -1);
if (!load_dgo_cmd->fd) {
// failed to open, return error
load_single_cmd->status = CMD_STATUS_FAILED_TO_OPEN;
UnqueueMessage(load_single_cmd);
ReturnMessage(load_single_cmd);
load_dgo_cmd->status = CMD_STATUS_FAILED_TO_OPEN;
UnqueueMessage(load_dgo_cmd);
if (g_game_version == GameVersion::Jak1) {
ReturnMessage(load_dgo_cmd);
} else {
SendMbx(iso_mbx, &sLoadDGO);
}
} else {
// init DGO state machine and register as the callback.
load_single_cmd->status = CMD_STATUS_IN_PROGRESS;
((DgoCommand*)load_single_cmd)->dgo_state = DgoState::Init;
load_single_cmd->callback_function = RunDGOStateMachine;
load_dgo_cmd->status = CMD_STATUS_IN_PROGRESS;
load_dgo_cmd->dgo_state = DgoState::Init;
load_dgo_cmd->callback_function = RunDGOStateMachine;
}
} break;
@@ -598,17 +636,19 @@ u32 ISOThread() {
// Handle Sound
////////////////////////////
if (in_progress_vag_command && !CheckVAGStreamProgress(in_progress_vag_command)) {
gVAGCMD = nullptr;
StopVAG(in_progress_vag_command);
ReleaseMessage(in_progress_vag_command);
in_progress_vag_command = nullptr;
// added. this variable seems to determine whether a vag stream is actually playing, and it is
// possible to get into a scenario where (for example) you want to unpause a vag stream but a
// different sound command hasn't run yet to correct this value, which makes the game either
// play the wrong sound or crash right away if no actual sound is to be played with the vag
// stream
unk = 0;
if (g_game_version == GameVersion::Jak1) {
if (in_progress_vag_command && !CheckVAGStreamProgress(in_progress_vag_command)) {
gVAGCMD = nullptr;
StopVAG(in_progress_vag_command);
ReleaseMessage(in_progress_vag_command);
in_progress_vag_command = nullptr;
// added. this variable seems to determine whether a vag stream is actually playing, and it
// is possible to get into a scenario where (for example) you want to unpause a vag stream
// but a different sound command hasn't run yet to correct this value, which makes the game
// either play the wrong sound or crash right away if no actual sound is to be played with
// the vag stream
unk = 0;
}
}
////////////////////////////
@@ -1456,11 +1496,10 @@ void CancelDGO(RPC_Dgo_Cmd* cmd) {
// this will cause a crash if we cancel because we try to load 2 dgos at the same time.
// this should succeed if it's an actual cancel because we changed which level we're trying to
// load.
// I don't understand how this works in the real game.
// maybe the IOP doesn't crash on writing to 0x0?
// This is weird in the original game, the IOP doesn't crash on writing to 0
// or, we have some other bug.
// NOTE : actually got fixed in Jak 2 so who cares
if (cmd) {
printf("null pointer case in CancelDGO hit!\n");
cmd->result = DGO_RPC_RESULT_ABORTED;
}
+6
View File
@@ -27,6 +27,12 @@ struct VagDir {
VagDirEntry vag[VAG_COUNT];
};
static constexpr int VAG_COUNT_JAK2 = 2728;
struct VagDirJak2 {
u32 count;
VagDirEntry vag[VAG_COUNT_JAK2];
};
void iso_init_globals();
FileRecord* FindISOFile(const char* name);
u32 GetISOFileLength(FileRecord* f);
+11 -9
View File
@@ -163,7 +163,8 @@ void FreeBuffer(IsoBufferHeader* buffer) {
void DisplayQueue() {
for (int pri = 0; pri < N_PRIORITIES; pri++) {
for (int cmd = 0; cmd < (int)gPriStack[pri].n; cmd++) {
lg::debug(" PRI {} elt {} {}", pri, cmd, gPriStack[pri].names[cmd]);
lg::debug(" PRI {} elt {} {} @ #x{:X}", pri, cmd, gPriStack[pri].names[cmd],
(u64)gPriStack[pri].cmds[cmd]);
}
}
}
@@ -180,7 +181,7 @@ u32 QueueMessage(IsoMessage* cmd, int32_t priority, const char* name) {
gPriStack[priority].names[gPriStack[priority].n] = name;
gPriStack[priority].n++;
lg::debug("[OVERLORD] Queue {} ({}/{}), {}", priority, gPriStack[priority].n, PRI_STACK_LENGTH,
gPriStack[priority].names[gPriStack[priority].n - 1].c_str());
name);
DisplayQueue();
} else {
lg::warn("[OVERLORD ISO QUEUE] Failed to queue!");
@@ -200,24 +201,25 @@ void UnqueueMessage(IsoMessage* cmd) {
// loop over priorities
for (pri = 0; pri < N_PRIORITIES; pri++) {
pse = gPriStack + pri;
pse = &gPriStack[pri];
// loop over entries
for (idx = 0; idx < gPriStack[pri].n; idx++) {
for (idx = 0; idx < pse->n; idx++) {
if (pse->cmds[idx] == cmd) {
goto found;
}
}
}
lg::warn("[OVERLORD ISO QUEUE] Failed to unqueue!");
return;
found:
ASSERT(gPriStack[pri].cmds[idx] == cmd);
ASSERT(pse->cmds[idx] == cmd);
// pop
gPriStack[pri].n--;
pse->n--;
// and move other entries up.
while (idx < gPriStack[pri].n) {
while (idx < pse->n) {
pse->cmds[idx] = pse->cmds[idx + 1];
idx++;
}
@@ -233,8 +235,8 @@ found:
IsoMessage* GetMessage() {
// loop over all priorities
for (int pri = (N_PRIORITIES - 1); pri >= 0; pri--) {
auto pse = gPriStack + pri;
int idx = gPriStack[pri].n;
auto pse = &gPriStack[pri];
int idx = pse->n;
for (idx = idx - 1; idx >= 0; idx--) {
if (pse->cmds[idx]->fd && pse->cmds[idx]->status == CMD_STATUS_IN_PROGRESS &&
pse->cmds[idx]->ready_for_data) {
+2 -2
View File
@@ -26,8 +26,8 @@
(define-extern *level-load-list* pair)
(defmacro start-debug (str &rest args)
`(format 0 ,(string-append "[START] " str) ,@args)
)
;`(format 0 ,(string-append "[START] " str) ,@args)
0)
(defenum load-buffer-mode
+8 -3
View File
@@ -414,7 +414,7 @@ into 7 sections, which might explain the weird sizes in the center.
the level object.
This function is the way to transition from loaded to alive/active."
(start-debug "level-status-update trying to do ~A to ~A~%" (-> obj status) arg0)
(start-debug "level-status-update trying to do ~A to ~A for ~A~%" (-> obj status) arg0 (-> obj name))
(case arg0
(('inactive)
;; any request to go inactive should unload.
@@ -634,7 +634,6 @@ into 7 sections, which might explain the weird sizes in the center.
(set! sv-16 (the-as symbol #f))
(let ((s5-0 (dgo-load-get-next (& sv-16))))
(when s5-0
(start-debug "dgo-load-get-next: #x~X~%" s5-0)
;; we got something! remember where and update stats
(set! (-> obj load-buffer-last) (the-as uint s5-0))
(+! (-> *level* load-size) (-> (the-as (pointer uint32) s5-0)))
@@ -1039,6 +1038,7 @@ into 7 sections, which might explain the weird sizes in the center.
;; - we can't allocate during login. Or if we allocate more than our link data, then bad things happen.
(set! (-> obj load-buffer-mode) (load-buffer-mode borrow))
(let ((a3-19 (logand -64 (&+ (-> obj heap current) 63))))
(start-debug "DGO-LOAD-BEGIN FOR BORROW: #x~x~%" a3-19)
;; start dgo loader!
(dgo-load-begin *temp-string* a3-19 a3-19 a3-19)
)
@@ -2457,7 +2457,12 @@ into 7 sections, which might explain the weird sizes in the center.
)
)
(when (>= unload-idx 0) ;; did we find one to unload?
;; did we find one to unload?
;; PC NOTE : added an extra check for DGO time. If you start a load and discard it on the next frame,
;; you may attempt to start a new load right away before the ISO thread can properly stop the previous load
;; which will just crash the game. Sadly this means loads may sometimes be delayed by one frame. The horror.
(when ;(>= unload-idx 0)
(and (>= unload-idx 0) (< 1 (- (-> *display* real-clock integral-frame-counter) *dgo-time*)))
(let ((lev-to-unload (-> *level* level unload-idx)))
(format 0 "Discarding level ~A~%" (-> lev-to-unload name))
(level-status-update! lev-to-unload 'inactive) ;; kill it.
+11
View File
@@ -61,6 +61,15 @@
(cgo-file "kernel.gd" ())
;;;;;;;;;;;;;;;;;;;;;
;; misc files
;;;;;;;;;;;;;;;;;;;;;
;; the VAGDIR file
(defstep :in "$ISO/VAG/VAGDIR.AYB"
:tool 'copy
:out '("$OUT/iso/VAGDIR.AYB"))
;;;;;;;;;;;;;;;;;;;;;
;; DGOs
;;;;;;;;;;;;;;;;;;;;;
@@ -324,6 +333,8 @@
(group-list "iso"
`("$OUT/iso/0COMMON.TXT"
"$OUT/iso/TWEAKVAL.MUS"
"$OUT/iso/VAGDIR.AYB"
,@(reverse *all-vis*)
,@(reverse *all-str*)
,@(reverse *all-sbk*)