From e35bb0700f4886e9c78b693f07ce2e6e10a8c95b Mon Sep 17 00:00:00 2001 From: Wiseguy <68165316+Mr-Wiseguy@users.noreply.github.com> Date: Mon, 8 Jul 2024 16:33:33 -0400 Subject: [PATCH 01/49] Fix bug where ocarina inputs are dropped right after taking out the ocarina (#428) --- patches/fixes.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/patches/fixes.c b/patches/fixes.c index 7a62450..0dad6b9 100644 --- a/patches/fixes.c +++ b/patches/fixes.c @@ -357,3 +357,111 @@ void DayTelop_Init(GameState* thisx) { DayTelop_LoadGraphics(this); Audio_PlaySfx(NA_SE_OC_TELOP_IMPACT); } + +extern PlayerAnimationHeader* D_8085D17C[PLAYER_FORM_MAX]; +void Player_TalkWithPlayer(PlayState* play, Actor* actor); +void Player_Action_88(Player* this, PlayState* play); +void Player_SetAction_PreserveItemAction(PlayState* play, Player* this, PlayerActionFunc actionFunc, s32 arg3); +void Player_AnimationPlayOnceReverse(PlayState* play, Player* this, PlayerAnimationHeader* anim); +s32 Player_ActionChange_13(Player* this, PlayState* play); +s32 func_8085B28C(PlayState* play, Player* this, PlayerCsAction csAction); +void func_808525C4(PlayState* play, Player* this); +void func_8085255C(PlayState* play, Player* this); +void func_80836A5C(Player* this, PlayState* play); +s32 func_8082DA90(PlayState* play); + +// @recomp Patched to fix the issue where ocarina inputs are discarded for the first 3 frames (150ms). +void Player_Action_63(Player* this, PlayState* play) { + if ((this->unk_AA5 != PLAYER_UNKAA5_4) && ((PlayerAnimation_Update(play, &this->skelAnime) && + (this->skelAnime.animation == D_8085D17C[this->transformation])) || + ((this->skelAnime.mode == 0) && (this->av2.actionVar2 == 0)))) { + func_808525C4(play, this); + // @recomp Fix the bug where ocarina inputs are discarded for 3 frames by only running this on the first frame of this state. + if (this->av2.actionVar2 == 1) { + if (!(this->actor.flags & ACTOR_FLAG_20000000) || (this->unk_A90->id == ACTOR_EN_ZOT)) { + Message_DisplayOcarinaStaff(play, OCARINA_ACTION_FREE_PLAY); + } + } + } else if (this->av2.actionVar2 != 0) { + if (play->msgCtx.ocarinaMode == OCARINA_MODE_END) { + play->interfaceCtx.unk_222 = 0; + CutsceneManager_Stop(play->playerCsIds[PLAYER_CS_ID_ITEM_OCARINA]); + this->actor.flags &= ~ACTOR_FLAG_20000000; + + if ((this->talkActor != NULL) && (this->talkActor == this->unk_A90) && (this->unk_A94 >= 0.0f)) { + Player_TalkWithPlayer(play, this->talkActor); + } else if (this->tatlTextId < 0) { + this->talkActor = this->tatlActor; + this->tatlActor->textId = -this->tatlTextId; + Player_TalkWithPlayer(play, this->talkActor); + } else if (!Player_ActionChange_13(this, play)) { + func_80836A5C(this, play); + Player_AnimationPlayOnceReverse(play, this, D_8085D17C[this->transformation]); + } + } else { + s32 var_v1 = (play->msgCtx.ocarinaMode >= OCARINA_MODE_WARP_TO_GREAT_BAY_COAST) && + (play->msgCtx.ocarinaMode <= OCARINA_MODE_WARP_TO_ENTRANCE); + s32 pad[2]; + + if (var_v1 || (play->msgCtx.ocarinaMode == OCARINA_MODE_APPLY_SOT) || + (play->msgCtx.ocarinaMode == OCARINA_MODE_APPLY_DOUBLE_SOT) || + (play->msgCtx.ocarinaMode == OCARINA_MODE_APPLY_INV_SOT_FAST) || + (play->msgCtx.ocarinaMode == OCARINA_MODE_APPLY_INV_SOT_SLOW)) { + if (play->msgCtx.ocarinaMode == OCARINA_MODE_APPLY_SOT) { + if (!func_8082DA90(play)) { + if (gSaveContext.save.saveInfo.playerData.threeDayResetCount == 1) { + play->nextEntrance = ENTRANCE(CUTSCENE, 1); + } else { + play->nextEntrance = ENTRANCE(CUTSCENE, 0); + } + + gSaveContext.nextCutsceneIndex = 0xFFF7; + play->transitionTrigger = TRANS_TRIGGER_START; + } + } else { + Actor* actor; + + play->interfaceCtx.unk_222 = 0; + CutsceneManager_Stop(play->playerCsIds[PLAYER_CS_ID_ITEM_OCARINA]); + this->actor.flags &= ~ACTOR_FLAG_20000000; + + actor = Actor_Spawn(&play->actorCtx, play, var_v1 ? ACTOR_EN_TEST7 : ACTOR_EN_TEST6, + this->actor.world.pos.x, this->actor.world.pos.y, this->actor.world.pos.z, 0, 0, + 0, play->msgCtx.ocarinaMode); + if (actor != NULL) { + this->stateFlags1 &= ~PLAYER_STATE1_20000000; + this->csAction = PLAYER_CSACTION_NONE; + func_8085B28C(play, NULL, PLAYER_CSACTION_19); + this->stateFlags1 |= PLAYER_STATE1_10000000 | PLAYER_STATE1_20000000; + } else { + func_80836A5C(this, play); + Player_AnimationPlayOnceReverse(play, this, D_8085D17C[this->transformation]); + } + } + } else if ((play->msgCtx.ocarinaMode == OCARINA_MODE_EVENT) && + (play->msgCtx.lastPlayedSong == OCARINA_SONG_ELEGY)) { + play->interfaceCtx.unk_222 = 0; + CutsceneManager_Stop(play->playerCsIds[PLAYER_CS_ID_ITEM_OCARINA]); + + this->actor.flags &= ~ACTOR_FLAG_20000000; + Player_SetAction_PreserveItemAction(play, this, Player_Action_88, 0); + this->stateFlags1 |= PLAYER_STATE1_10000000 | PLAYER_STATE1_20000000; + } else if (this->unk_AA5 == PLAYER_UNKAA5_4) { + f32 temp_fa0 = this->skelAnime.jointTable[PLAYER_LIMB_ROOT - 1].x; + f32 temp_fa1 = this->skelAnime.jointTable[PLAYER_LIMB_ROOT - 1].z; + f32 var_fv1; + + var_fv1 = sqrtf(SQ(temp_fa0) + SQ(temp_fa1)); + if (var_fv1 != 0.0f) { + var_fv1 = (var_fv1 - 100.0f) / var_fv1; + var_fv1 = CLAMP_MIN(var_fv1, 0.0f); + } + + this->skelAnime.jointTable[PLAYER_LIMB_ROOT - 1].x = temp_fa0 * var_fv1; + this->skelAnime.jointTable[PLAYER_LIMB_ROOT - 1].z = temp_fa1 * var_fv1; + } else { + func_8085255C(play, this); + } + } + } +} From 97912578e90c67094b58f16f0b66e01afbce41f3 Mon Sep 17 00:00:00 2001 From: Mr-Wiseguy Date: Wed, 24 Jul 2024 23:42:33 -0400 Subject: [PATCH 02/49] Fix patching error that resulted in the rewind button highlight being in the wrong position --- patches/options.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/patches/options.c b/patches/options.c index ba89f87..bbaa96d 100644 --- a/patches/options.c +++ b/patches/options.c @@ -55,7 +55,9 @@ extern s16 D_80814630[]; extern s16 D_80814638[]; extern s16 D_80814644[]; extern s16 D_8081464C[]; -extern s16 D_80814650[]; + +// @recomp Added a third position for the rewind button. +s16 D_80814650_patched[] = { 940, 944, 948 }; void FileSelect_Main(GameState* thisx); void FileSelect_InitContext(GameState* thisx); @@ -739,7 +741,7 @@ void FileSelect_SetWindowContentVtx(GameState *thisx) { } } else { - j = D_80814650[this->confirmButtonIndex]; + j = D_80814650_patched[this->confirmButtonIndex]; } this->windowContentVtx[vtxId + 0].v.ob[0] = this->windowContentVtx[vtxId + 2].v.ob[0] = this->windowPosX - 0xA; From a8a5e216feb0f4e3c5569a2157733fbaeee6b023 Mon Sep 17 00:00:00 2001 From: Wiseguy <68165316+Mr-Wiseguy@users.noreply.github.com> Date: Thu, 25 Jul 2024 22:17:00 -0400 Subject: [PATCH 03/49] Tag all patches with the RECOMP_PATCH attribute in preparation for the recompiler's strict mode (#441) --- patches/actor_transform_tagging.c | 38 ++++++++++---------- patches/autosaving.c | 16 ++++----- patches/billboard_tagging.c | 40 +++++++++++----------- patches/camera_patches.c | 14 ++++---- patches/camera_transform_tagging.c | 8 ++--- patches/culling.c | 10 +++--- patches/cutscene_patches.c | 10 +++--- patches/effect_patches.c | 8 ++--- patches/effect_transform_tagging.c | 12 +++---- patches/fixes.c | 14 ++++---- patches/input.c | 30 ++++++++-------- patches/input_latency.c | 10 +++--- patches/item_transform_tagging.c | 6 ++-- patches/ocarina_effect_patches.c | 16 ++++----- patches/options.c | 12 +++---- patches/particle_transform_tagging.c | 16 ++++----- patches/patches.h | 4 +++ patches/patches.ld | 14 ++++---- patches/play_patches.c | 4 +-- patches/required_patches.c | 4 +-- patches/save_patches.c | 4 +-- patches/skip_sos.c | 2 +- patches/sky_transform_tagging.c | 4 +-- patches/song_transform_tagging.c | 4 +-- patches/sound_patches.c | 4 +-- patches/specific_actor_transform_tagging.c | 40 +++++++++++----------- patches/terrain_transform_tagging.c | 6 ++-- patches/ui_patches.c | 16 ++++----- patches/ui_transform_tagging.c | 8 ++--- 29 files changed, 190 insertions(+), 184 deletions(-) diff --git a/patches/actor_transform_tagging.c b/patches/actor_transform_tagging.c index d379f53..2484db0 100644 --- a/patches/actor_transform_tagging.c +++ b/patches/actor_transform_tagging.c @@ -8,7 +8,7 @@ extern FaultClient sActorFaultClient; Actor* Actor_Delete(ActorContext* actorCtx, Actor* actor, PlayState* play); void ZeldaArena_Free(void* ptr); -void Actor_CleanupContext(ActorContext* actorCtx, PlayState* play) { +RECOMP_PATCH void Actor_CleanupContext(ActorContext* actorCtx, PlayState* play) { s32 i; Fault_RemoveClient(&sActorFaultClient); @@ -47,7 +47,7 @@ u32 create_actor_transform_id() { return ret; } -void Actor_Init(Actor* actor, PlayState* play) { +RECOMP_PATCH void Actor_Init(Actor* actor, PlayState* play) { Actor_SetWorldToHome(actor); Actor_SetShapeRotToWorld(actor); Actor_SetFocus(actor, 0.0f); @@ -135,7 +135,7 @@ Gfx* pop_post_limb_matrix_group(Gfx* dlist, Actor* actor) { /* * Draws the limb at `limbIndex` with a level of detail display lists index by `dListIndex` */ -void SkelAnime_DrawLimbLod(PlayState* play, s32 limbIndex, void** skeleton, Vec3s* jointTable, +RECOMP_PATCH void SkelAnime_DrawLimbLod(PlayState* play, s32 limbIndex, void** skeleton, Vec3s* jointTable, OverrideLimbDrawOpa overrideLimbDraw, PostLimbDrawOpa postLimbDraw, Actor* actor, s32 lod) { LodLimb* limb; Gfx* dList; @@ -197,7 +197,7 @@ void SkelAnime_DrawLimbLod(PlayState* play, s32 limbIndex, void** skeleton, Vec3 * Draw all limbs of type `LodLimb` in a given skeleton * Near or far display list is specified via `lod` */ -void SkelAnime_DrawLod(PlayState* play, void** skeleton, Vec3s* jointTable, OverrideLimbDrawOpa overrideLimbDraw, +RECOMP_PATCH void SkelAnime_DrawLod(PlayState* play, void** skeleton, Vec3s* jointTable, OverrideLimbDrawOpa overrideLimbDraw, PostLimbDrawOpa postLimbDraw, Actor* actor, s32 lod) { LodLimb* rootLimb; s32 pad; @@ -261,7 +261,7 @@ void SkelAnime_DrawLod(PlayState* play, void** skeleton, Vec3s* jointTable, Over * Draw a limb of type `LodLimb` contained within a flexible skeleton * Near or far display list is specified via `lod` */ -void SkelAnime_DrawFlexLimbLod(PlayState* play, s32 limbIndex, void** skeleton, Vec3s* jointTable, +RECOMP_PATCH void SkelAnime_DrawFlexLimbLod(PlayState* play, s32 limbIndex, void** skeleton, Vec3s* jointTable, OverrideLimbDrawFlex overrideLimbDraw, PostLimbDrawFlex postLimbDraw, Actor* actor, s32 lod, Mtx** mtx) { LodLimb* limb; @@ -332,7 +332,7 @@ void SkelAnime_DrawFlexLimbLod(PlayState* play, s32 limbIndex, void** skeleton, * Limbs in a flexible skeleton have meshes that can stretch to line up with other limbs. * An array of matrices is dynamically allocated so each limb can access any transform to ensure its meshes line up. */ -void SkelAnime_DrawFlexLod(PlayState* play, void** skeleton, Vec3s* jointTable, s32 dListCount, +RECOMP_PATCH void SkelAnime_DrawFlexLod(PlayState* play, void** skeleton, Vec3s* jointTable, s32 dListCount, OverrideLimbDrawFlex overrideLimbDraw, PostLimbDrawFlex postLimbDraw, Actor* actor, s32 lod) { LodLimb* rootLimb; @@ -403,7 +403,7 @@ void SkelAnime_DrawFlexLod(PlayState* play, void** skeleton, Vec3s* jointTable, /* * Draws the limb of the Skeleton `skeleton` at `limbIndex` */ -void SkelAnime_DrawLimbOpa(PlayState* play, s32 limbIndex, void** skeleton, Vec3s* jointTable, +RECOMP_PATCH void SkelAnime_DrawLimbOpa(PlayState* play, s32 limbIndex, void** skeleton, Vec3s* jointTable, OverrideLimbDrawOpa overrideLimbDraw, PostLimbDrawOpa postLimbDraw, Actor* actor) { StandardLimb* limb; Gfx* dList; @@ -463,7 +463,7 @@ void SkelAnime_DrawLimbOpa(PlayState* play, s32 limbIndex, void** skeleton, Vec3 /** * Draw all limbs of type `StandardLimb` in a given skeleton to the polyOpa buffer */ -void SkelAnime_DrawOpa(PlayState* play, void** skeleton, Vec3s* jointTable, OverrideLimbDrawOpa overrideLimbDraw, +RECOMP_PATCH void SkelAnime_DrawOpa(PlayState* play, void** skeleton, Vec3s* jointTable, OverrideLimbDrawOpa overrideLimbDraw, PostLimbDrawOpa postLimbDraw, Actor* actor) { StandardLimb* rootLimb; s32 pad; @@ -521,7 +521,7 @@ void SkelAnime_DrawOpa(PlayState* play, void** skeleton, Vec3s* jointTable, Over CLOSE_DISPS(play->state.gfxCtx); } -void SkelAnime_DrawFlexLimbOpa(PlayState* play, s32 limbIndex, void** skeleton, Vec3s* jointTable, +RECOMP_PATCH void SkelAnime_DrawFlexLimbOpa(PlayState* play, s32 limbIndex, void** skeleton, Vec3s* jointTable, OverrideLimbDrawOpa overrideLimbDraw, PostLimbDrawOpa postLimbDraw, Actor* actor, Mtx** limbMatricies) { StandardLimb* limb; @@ -591,7 +591,7 @@ void SkelAnime_DrawFlexLimbOpa(PlayState* play, s32 limbIndex, void** skeleton, * Limbs in a flexible skeleton have meshes that can stretch to line up with other limbs. * An array of matrices is dynamically allocated so each limb can access any transform to ensure its meshes line up. */ -void SkelAnime_DrawFlexOpa(PlayState* play, void** skeleton, Vec3s* jointTable, s32 dListCount, +RECOMP_PATCH void SkelAnime_DrawFlexOpa(PlayState* play, void** skeleton, Vec3s* jointTable, s32 dListCount, OverrideLimbDrawOpa overrideLimbDraw, PostLimbDrawOpa postLimbDraw, Actor* actor) { StandardLimb* rootLimb; s32 pad; @@ -661,7 +661,7 @@ void SkelAnime_DrawFlexOpa(PlayState* play, void** skeleton, Vec3s* jointTable, CLOSE_DISPS(play->state.gfxCtx); } -void SkelAnime_DrawTransformFlexLimbOpa(PlayState* play, s32 limbIndex, void** skeleton, Vec3s* jointTable, +RECOMP_PATCH void SkelAnime_DrawTransformFlexLimbOpa(PlayState* play, s32 limbIndex, void** skeleton, Vec3s* jointTable, OverrideLimbDrawOpa overrideLimbDraw, PostLimbDrawOpa postLimbDraw, TransformLimbDrawOpa transformLimbDraw, Actor* actor, Mtx** mtx) { StandardLimb* limb; @@ -744,7 +744,7 @@ void SkelAnime_DrawTransformFlexLimbOpa(PlayState* play, s32 limbIndex, void** s * coordinates. * Note that the `TransformLimbDraw` does not have a NULL check, so must be provided even if empty. */ -void SkelAnime_DrawTransformFlexOpa(PlayState* play, void** skeleton, Vec3s* jointTable, s32 dListCount, +RECOMP_PATCH void SkelAnime_DrawTransformFlexOpa(PlayState* play, void** skeleton, Vec3s* jointTable, s32 dListCount, OverrideLimbDrawOpa overrideLimbDraw, PostLimbDrawOpa postLimbDraw, TransformLimbDrawOpa transformLimbDraw, Actor* actor) { StandardLimb* rootLimb; @@ -825,7 +825,7 @@ void SkelAnime_DrawTransformFlexOpa(PlayState* play, void** skeleton, Vec3s* joi * Draws the Skeleton `skeleton`'s limb at index `limbIndex`. Appends all generated graphics commands to * `gfx`. Returns a pointer to the next gfx to be appended to. */ -Gfx* SkelAnime_DrawLimb(PlayState* play, s32 limbIndex, void** skeleton, Vec3s* jointTable, +RECOMP_PATCH Gfx* SkelAnime_DrawLimb(PlayState* play, s32 limbIndex, void** skeleton, Vec3s* jointTable, OverrideLimbDraw overrideLimbDraw, PostLimbDraw postLimbDraw, Actor* actor, Gfx* gfx) { StandardLimb* limb; Gfx* dList; @@ -884,7 +884,7 @@ Gfx* SkelAnime_DrawLimb(PlayState* play, s32 limbIndex, void** skeleton, Vec3s* * Draws the Skeleton `skeleton` Appends all generated graphics to `gfx`, and returns a pointer to the * next gfx to be appended to. */ -Gfx* SkelAnime_Draw(PlayState* play, void** skeleton, Vec3s* jointTable, OverrideLimbDraw overrideLimbDraw, +RECOMP_PATCH Gfx* SkelAnime_Draw(PlayState* play, void** skeleton, Vec3s* jointTable, OverrideLimbDraw overrideLimbDraw, PostLimbDraw postLimbDraw, Actor* actor, Gfx* gfx) { StandardLimb* rootLimb; s32 pad; @@ -944,7 +944,7 @@ Gfx* SkelAnime_Draw(PlayState* play, void** skeleton, Vec3s* jointTable, Overrid /** * Draw a limb of type `StandardLimb` contained within a flexible skeleton to the specified display buffer */ -Gfx* SkelAnime_DrawFlexLimb(PlayState* play, s32 limbIndex, void** skeleton, Vec3s* jointTable, +RECOMP_PATCH Gfx* SkelAnime_DrawFlexLimb(PlayState* play, s32 limbIndex, void** skeleton, Vec3s* jointTable, OverrideLimbDraw overrideLimbDraw, PostLimbDraw postLimbDraw, Actor* actor, Mtx** mtx, Gfx* gfx) { StandardLimb* limb; @@ -1014,7 +1014,7 @@ Gfx* SkelAnime_DrawFlexLimb(PlayState* play, s32 limbIndex, void** skeleton, Vec * Limbs in a flexible skeleton have meshes that can stretch to line up with other limbs. * An array of matrices is dynamically allocated so each limb can access any transform to ensure its meshes line up. */ -Gfx* SkelAnime_DrawFlex(PlayState* play, void** skeleton, Vec3s* jointTable, s32 dListCount, +RECOMP_PATCH Gfx* SkelAnime_DrawFlex(PlayState* play, void** skeleton, Vec3s* jointTable, s32 dListCount, OverrideLimbDraw overrideLimbDraw, PostLimbDraw postLimbDraw, Actor* actor, Gfx* gfx) { StandardLimb* rootLimb; s32 pad; @@ -1085,7 +1085,7 @@ Gfx* SkelAnime_DrawFlex(PlayState* play, void** skeleton, Vec3s* jointTable, s32 extern MtxF gSkinLimbMatrices[]; -void Skin_DrawImpl(Actor* actor, PlayState* play, Skin* skin, SkinPostDraw postDraw, +RECOMP_PATCH void Skin_DrawImpl(Actor* actor, PlayState* play, Skin* skin, SkinPostDraw postDraw, SkinOverrideLimbDraw overrideLimbDraw, s32 setTranslation, s32 arg6, s32 drawFlags) { s32 i; SkinLimb** skeleton; @@ -1145,7 +1145,7 @@ close_disps:; CLOSE_DISPS(gfxCtx); } -__attribute__((noinline)) s32 scan_for_matrices(Gfx* start, Gfx* end) { +s32 scan_for_matrices(Gfx* start, Gfx* end) { s32 matrix_count = 0; Gfx* cur = start; // Count any G_MTX commands between the start and end commands. @@ -1201,7 +1201,7 @@ void tag_actor_displaylists(Actor* actor, PlayState* play, Gfx* opa_start, Gfx* } // @recomp Patched to automatically add transform tagging to actor matrices based on what DL commands they write in their draw function -void Actor_Draw(PlayState* play, Actor* actor) { +RECOMP_PATCH void Actor_Draw(PlayState* play, Actor* actor) { Lights* light; OPEN_DISPS(play->state.gfxCtx); diff --git a/patches/autosaving.c b/patches/autosaving.c index 56da1a0..46f1e8a 100644 --- a/patches/autosaving.c +++ b/patches/autosaving.c @@ -14,7 +14,7 @@ s32 ShrinkWindow_Letterbox_GetSizeTarget(void); void ShrinkWindow_Letterbox_SetSizeTarget(s32 target); // @recomp Patched function to set a global variable if the player can pause -void KaleidoSetup_Update(PlayState* play) { +RECOMP_PATCH void KaleidoSetup_Update(PlayState* play) { Input* input = CONTROLLER1(&play->state); MessageContext* msgCtx = &play->msgCtx; Player* player = GET_PLAYER(play); @@ -100,7 +100,7 @@ void do_autosave(PlayState* play) { } // @recomp Do not clear the save if the save was an autosave. -void func_80147314(SramContext* sramCtx, s32 fileNum) { +RECOMP_PATCH void func_80147314(SramContext* sramCtx, s32 fileNum) { s32 save_type = gSaveContext.save.isOwlSave; gSaveContext.save.isOwlSave = false; @@ -156,7 +156,7 @@ void delete_owl_save(SramContext* sramCtx, s32 fileNum) { } // @recomp Patched to delete owl saves when making regular saves. -void func_8014546C(SramContext* sramCtx) { +RECOMP_PATCH void func_8014546C(SramContext* sramCtx) { s32 i; if (gSaveContext.save.isOwlSave) { @@ -199,7 +199,7 @@ extern u16 D_801F6AF0; extern u8 D_801F6AF2; // @recomp Patched to call the new owl save deletion function. -void Sram_EraseSave(FileSelectState* fileSelect2, SramContext* sramCtx, s32 fileNum) { +RECOMP_PATCH void Sram_EraseSave(FileSelectState* fileSelect2, SramContext* sramCtx, s32 fileNum) { FileSelectState* fileSelect = fileSelect2; s32 pad; @@ -468,7 +468,7 @@ extern s16 sSceneCutsceneCount; bool skip_entry_cutscene = false; // @recomp Patched to skip the entrance cutscene if the flag is enabled. -s16 CutsceneManager_FindEntranceCsId(void) { +RECOMP_PATCH s16 CutsceneManager_FindEntranceCsId(void) { PlayState* play; s32 csId; @@ -523,7 +523,7 @@ s32 spawn_entrance_from_autosave_entrance(s16 autosave_entrance) { } // @recomp Patched to change the entrance for autosaves and initialize autosaves. -void Sram_OpenSave(FileSelectState* fileSelect, SramContext* sramCtx) { +RECOMP_PATCH void Sram_OpenSave(FileSelectState* fileSelect, SramContext* sramCtx) { s32 i; s32 pad; s32 phi_t1 = 0; @@ -658,7 +658,7 @@ void Sram_OpenSave(FileSelectState* fileSelect, SramContext* sramCtx) { extern s32 Actor_ProcessTalkRequest(Actor* actor, GameState* gameState); // @recomp Reset the autosave timer when the moon crashes. -void Sram_ResetSaveFromMoonCrash(SramContext* sramCtx) { +RECOMP_PATCH void Sram_ResetSaveFromMoonCrash(SramContext* sramCtx) { s32 i; s32 cutsceneIndex = gSaveContext.save.cutsceneIndex; @@ -710,7 +710,7 @@ void Sram_ResetSaveFromMoonCrash(SramContext* sramCtx) { // @recomp If autosave is enabled, skip the part of the owl statue dialog that talks about the file being deleted on load, since it's not true. -void ObjWarpstone_Update(Actor* thisx, PlayState* play) { +RECOMP_PATCH void ObjWarpstone_Update(Actor* thisx, PlayState* play) { ObjWarpstone* this = (ObjWarpstone*)thisx; s32 pad; diff --git a/patches/billboard_tagging.c b/patches/billboard_tagging.c index 303a5a1..a6eecfb 100644 --- a/patches/billboard_tagging.c +++ b/patches/billboard_tagging.c @@ -61,7 +61,7 @@ void edit_billboard_groups(PlayState* play) { CLOSE_DISPS(play->state.gfxCtx); } -Mtx* Matrix_NewMtx(GraphicsContext* gfxCtx) { +RECOMP_PATCH Mtx* Matrix_NewMtx(GraphicsContext* gfxCtx) { Mtx* ret = Matrix_ToMtx(GRAPH_ALLOC(gfxCtx, sizeof(Mtx))); if (*current_billboard_state) { @@ -77,7 +77,7 @@ Mtx* Matrix_NewMtx(GraphicsContext* gfxCtx) { return ret; } -void Matrix_Init(GameState* gameState) { +RECOMP_PATCH void Matrix_Init(GameState* gameState) { sMatrixStack = THA_AllocTailAlign16(&gameState->tha, MATRIX_STACK_SIZE * sizeof(MtxF)); sCurrentMatrix = sMatrixStack; @@ -94,7 +94,7 @@ void matrix_play_update(PlayState* play) { play_billboard_matrix = &play->billboardMtxF; } -void Matrix_Push(void) { +RECOMP_PATCH void Matrix_Push(void) { MtxF* prev = sCurrentMatrix; sCurrentMatrix++; @@ -106,20 +106,20 @@ void Matrix_Push(void) { *current_billboard_state = *prev_billboard; } -void Matrix_Pop(void) { +RECOMP_PATCH void Matrix_Pop(void) { sCurrentMatrix--; // @recomp Pop the matrix stack billboard state. current_billboard_state--; } -void Matrix_Put(MtxF* src) { +RECOMP_PATCH void Matrix_Put(MtxF* src) { Matrix_MtxFCopy(sCurrentMatrix, src); // @recomp Update the current billboard state. *current_billboard_state = (src == play_billboard_matrix); } -void Matrix_ReplaceRotation(MtxF* mf) { +RECOMP_PATCH void Matrix_ReplaceRotation(MtxF* mf) { MtxF* cmf = sCurrentMatrix; f32 acc; f32 component; @@ -168,7 +168,7 @@ void Matrix_ReplaceRotation(MtxF* mf) { *current_billboard_state = (mf == play_billboard_matrix); } -void Matrix_Mult(MtxF* mf, MatrixMode mode) { +RECOMP_PATCH void Matrix_Mult(MtxF* mf, MatrixMode mode) { MtxF* cmf = Matrix_GetCurrent(); if (mode == MTXMODE_APPLY) { @@ -183,7 +183,7 @@ void Matrix_Mult(MtxF* mf, MatrixMode mode) { } } -void Matrix_Translate(f32 x, f32 y, f32 z, MatrixMode mode) { +RECOMP_PATCH void Matrix_Translate(f32 x, f32 y, f32 z, MatrixMode mode) { MtxF* cmf = sCurrentMatrix; f32 tempX; f32 tempY; @@ -209,7 +209,7 @@ void Matrix_Translate(f32 x, f32 y, f32 z, MatrixMode mode) { } } -void Matrix_Scale(f32 x, f32 y, f32 z, MatrixMode mode) { +RECOMP_PATCH void Matrix_Scale(f32 x, f32 y, f32 z, MatrixMode mode) { MtxF* cmf = sCurrentMatrix; if (mode == MTXMODE_APPLY) { @@ -233,7 +233,7 @@ void Matrix_Scale(f32 x, f32 y, f32 z, MatrixMode mode) { } } -void Matrix_RotateXS(s16 x, MatrixMode mode) { +RECOMP_PATCH void Matrix_RotateXS(s16 x, MatrixMode mode) { MtxF* cmf; f32 sin; f32 cos; @@ -300,7 +300,7 @@ void Matrix_RotateXS(s16 x, MatrixMode mode) { } } -void Matrix_RotateXF(f32 x, MatrixMode mode) { +RECOMP_PATCH void Matrix_RotateXF(f32 x, MatrixMode mode) { MtxF* cmf; f32 sin; f32 cos; @@ -369,7 +369,7 @@ void Matrix_RotateXF(f32 x, MatrixMode mode) { } } -void Matrix_RotateXFNew(f32 x) { +RECOMP_PATCH void Matrix_RotateXFNew(f32 x) { MtxF* cmf = sCurrentMatrix; s32 pad[2]; f32 sin; @@ -406,7 +406,7 @@ void Matrix_RotateXFNew(f32 x) { // @recomp Clear the current billboard state. *current_billboard_state = false; } -void Matrix_RotateYS(s16 y, MatrixMode mode) { +RECOMP_PATCH void Matrix_RotateYS(s16 y, MatrixMode mode) { MtxF* cmf; f32 sin; f32 cos; @@ -473,7 +473,7 @@ void Matrix_RotateYS(s16 y, MatrixMode mode) { } } -void Matrix_RotateYF(f32 y, MatrixMode mode) { +RECOMP_PATCH void Matrix_RotateYF(f32 y, MatrixMode mode) { MtxF* cmf; f32 sin; f32 cos; @@ -542,7 +542,7 @@ void Matrix_RotateYF(f32 y, MatrixMode mode) { } } -void Matrix_RotateZS(s16 z, MatrixMode mode) { +RECOMP_PATCH void Matrix_RotateZS(s16 z, MatrixMode mode) { MtxF* cmf; f32 sin; f32 cos; @@ -611,7 +611,7 @@ void Matrix_RotateZS(s16 z, MatrixMode mode) { } } -void Matrix_RotateZF(f32 z, MatrixMode mode) { +RECOMP_PATCH void Matrix_RotateZF(f32 z, MatrixMode mode) { MtxF* cmf; f32 sin; f32 cos; @@ -678,7 +678,7 @@ void Matrix_RotateZF(f32 z, MatrixMode mode) { } } -void Matrix_RotateZYX(s16 x, s16 y, s16 z, MatrixMode mode) { +RECOMP_PATCH void Matrix_RotateZYX(s16 x, s16 y, s16 z, MatrixMode mode) { MtxF* cmf = sCurrentMatrix; f32 temp1; f32 temp2; @@ -768,7 +768,7 @@ void Matrix_RotateZYX(s16 x, s16 y, s16 z, MatrixMode mode) { } } -void Matrix_SetTranslateRotateYXZ(f32 x, f32 y, f32 z, Vec3s* rot) { +RECOMP_PATCH void Matrix_SetTranslateRotateYXZ(f32 x, f32 y, f32 z, Vec3s* rot) { MtxF* cmf = sCurrentMatrix; f32 sinY = Math_SinS(rot->y); f32 cosY = Math_CosS(rot->y); @@ -829,7 +829,7 @@ void Matrix_SetTranslateRotateYXZ(f32 x, f32 y, f32 z, Vec3s* rot) { *current_billboard_state = false; } -void Matrix_RotateAxisF(f32 angle, Vec3f* axis, MatrixMode mode) { +RECOMP_PATCH void Matrix_RotateAxisF(f32 angle, Vec3f* axis, MatrixMode mode) { MtxF* cmf; f32 sin; f32 cos; @@ -926,7 +926,7 @@ void Matrix_RotateAxisF(f32 angle, Vec3f* axis, MatrixMode mode) { } } -void Matrix_RotateAxisS(s16 angle, Vec3f* axis, MatrixMode mode) { +RECOMP_PATCH void Matrix_RotateAxisS(s16 angle, Vec3f* axis, MatrixMode mode) { MtxF* cmf; f32 cos; f32 sin; diff --git a/patches/camera_patches.c b/patches/camera_patches.c index a5c6eda..f0ae7e0 100644 --- a/patches/camera_patches.c +++ b/patches/camera_patches.c @@ -176,7 +176,7 @@ void Camera_UpdateInterface(s32 interfaceFlags); s32 func_800CB7CC(Camera* camera); s32 func_800CB854(Camera* camera); -Vec3s Camera_Update(Camera* camera) { +RECOMP_PATCH Vec3s Camera_Update(Camera* camera) { Vec3f viewAt; Vec3f viewEye; Vec3f viewUp; @@ -461,7 +461,7 @@ s32 func_800CBA7C(Camera* camera); #define RELOAD_PARAMS(camera) ((camera->animState == 0) || (camera->animState == 10) || (camera->animState == 20)) // @recomp Patched for analog cam. -s32 Camera_Normal1(Camera* camera) { +RECOMP_PATCH s32 Camera_Normal1(Camera* camera) { Vec3f* eye = &camera->eye; Vec3f* at = &camera->at; Vec3f* eyeNext = &camera->eyeNext; @@ -870,7 +870,7 @@ s32 Camera_Normal1(Camera* camera) { * Camera for climbing structures */ // @recomp Patched for analog cam. -s32 Camera_Jump2(Camera* camera) { +RECOMP_PATCH s32 Camera_Jump2(Camera* camera) { Vec3f* eye = &camera->eye; Vec3f* at = &camera->at; Vec3f* eyeNext = &camera->eyeNext; @@ -1063,7 +1063,7 @@ s32 Camera_Jump2(Camera* camera) { * Used for targeting */ // @recomp Patched for analog cam. -s32 Camera_Parallel1(Camera* camera) { +RECOMP_PATCH s32 Camera_Parallel1(Camera* camera) { Vec3f* eye = &camera->eye; Vec3f* at = &camera->at; Vec3f* eyeNext = &camera->eyeNext; @@ -1421,7 +1421,7 @@ s32 Camera_Parallel1(Camera* camera) { * Riding Epona and Zora */ // @recomp Patched for analog cam. -s32 Camera_Normal3(Camera* camera) { +RECOMP_PATCH s32 Camera_Normal3(Camera* camera) { Normal3ReadOnlyData* roData = &camera->paramData.norm3.roData; Normal3ReadWriteData* rwData = &camera->paramData.norm3.rwData; f32 sp8C; @@ -1620,7 +1620,7 @@ s32 Camera_Normal3(Camera* camera) { * e.g. Gyorg, Pinnacle Rock, whirlpool, water */ // @recomp Patched for analog cam. -s32 Camera_Jump3(Camera* camera) { +RECOMP_PATCH s32 Camera_Jump3(Camera* camera) { Vec3f* sp48 = &camera->eye; Vec3f* sp44 = &camera->at; Vec3f* sp40 = &camera->eyeNext; @@ -1905,7 +1905,7 @@ extern u8 D_809EE4D0; // @recomp Patch the Wart boss fight in the Great Bay temple so that the fight starts if you look at it with the right stick analog camera, // instead of requiring entering first person mode mode. -void func_809EC568(Boss04* this, PlayState* play) { +RECOMP_PATCH void func_809EC568(Boss04* this, PlayState* play) { Player* player = GET_PLAYER(play); f32 x; f32 y; diff --git a/patches/camera_transform_tagging.c b/patches/camera_transform_tagging.c index b775158..b077b28 100644 --- a/patches/camera_transform_tagging.c +++ b/patches/camera_transform_tagging.c @@ -95,7 +95,7 @@ void force_camera_ignore_tracking() { camera_ignore_tracking = true; } -void KaleidoScope_SetView(PauseContext* pauseCtx, f32 eyeX, f32 eyeY, f32 eyeZ) { +RECOMP_PATCH void KaleidoScope_SetView(PauseContext* pauseCtx, f32 eyeX, f32 eyeY, f32 eyeZ) { Vec3f eye; Vec3f at; Vec3f up; @@ -117,7 +117,7 @@ void KaleidoScope_SetView(PauseContext* pauseCtx, f32 eyeX, f32 eyeY, f32 eyeZ) } -void FileSelect_SetView(FileSelectState* this, f32 eyeX, f32 eyeY, f32 eyeZ) { +RECOMP_PATCH void FileSelect_SetView(FileSelectState* this, f32 eyeX, f32 eyeY, f32 eyeZ) { Vec3f eye; Vec3f lookAt; Vec3f up; @@ -197,7 +197,7 @@ bool should_interpolate_perspective(Vec3f* eye, Vec3f* at) { /** * Apply view to POLY_OPA_DISP, POLY_XLU_DISP (and OVERLAY_DISP if ortho) */ -void View_Apply(View* view, s32 mask) { +RECOMP_PATCH void View_Apply(View* view, s32 mask) { mask = (view->flags & mask) | (mask >> 4); // @recomp Determine if the camera should be interpolated this frame. @@ -292,7 +292,7 @@ Vec3f Camera_Vec3sToVec3f(Vec3s* src); * Used for many fixed-based camera settings i.e. camera is fixed in rotation, and often position (but not always) */ // @recomp Modified to not force interpolation while panning. -s32 Camera_Fixed1(Camera* camera) { +RECOMP_PATCH s32 Camera_Fixed1(Camera* camera) { s32 pad[2]; s32 yawDiff; VecGeo eyeOffset; diff --git a/patches/culling.c b/patches/culling.c index 61ca136..4cbdb8e 100644 --- a/patches/culling.c +++ b/patches/culling.c @@ -1,7 +1,7 @@ #include "patches.h" // Disable frustum culling for actors, but leave distance culling intact -s32 func_800BA2FC(PlayState* play, Actor* actor, Vec3f* projectedPos, f32 projectedW) { +RECOMP_PATCH s32 func_800BA2FC(PlayState* play, Actor* actor, Vec3f* projectedPos, f32 projectedW) { if ((-actor->uncullZoneScale < projectedPos->z) && (projectedPos->z < (actor->uncullZoneForward + actor->uncullZoneScale))) { // f32 phi_f12; @@ -30,7 +30,7 @@ s32 func_800BA2FC(PlayState* play, Actor* actor, Vec3f* projectedPos, f32 projec } // Disable frustum culling for bush spawning -// s32 EnWood02_SpawnZoneCheck(EnWood02* this, PlayState* play, Vec3f* arg2) { +// RECOMP_PATCH s32 EnWood02_SpawnZoneCheck(EnWood02* this, PlayState* play, Vec3f* arg2) { // f32 phi_f12; // SkinMatrix_Vec3fMtxFMultXYZW(&play->viewProjectionMtxF, arg2, &this->actor.projectedPos, &this->actor.projectedW); @@ -52,7 +52,7 @@ s32 func_800BA2FC(PlayState* play, Actor* actor, Vec3f* projectedPos, f32 projec // } // Disable frustum culling for grass -s32 func_809A9110(PlayState* play, Vec3f* pos) { +RECOMP_PATCH s32 func_809A9110(PlayState* play, Vec3f* pos) { f32 w; Vec3f projectedPos; @@ -73,7 +73,7 @@ s32 func_809A9110(PlayState* play, Vec3f* pos) { // Replace point light glow effect with RT64 point Z test so it works in widescreen -void Lights_GlowCheck(PlayState* play) { +RECOMP_PATCH void Lights_GlowCheck(PlayState* play) { LightNode* light = play->lightCtx.listHead; while (light != NULL) { @@ -107,7 +107,7 @@ extern Gfx gameplay_keep_DL_029CF0[]; Vtx light_test_vert = VTX(0, 0, 0, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF); -void Lights_DrawGlow(PlayState* play) { +RECOMP_PATCH void Lights_DrawGlow(PlayState* play) { Gfx* dl; LightPoint* params; LightNode* light = play->lightCtx.listHead; diff --git a/patches/cutscene_patches.c b/patches/cutscene_patches.c index 361022a..e5f5e10 100644 --- a/patches/cutscene_patches.c +++ b/patches/cutscene_patches.c @@ -6,7 +6,7 @@ CsCmdActorCue* prev_cues_checked[ARRAY_COUNT(((CutsceneContext*)0)->actorCues)] = {0}; -void Cutscene_ActorTranslate(Actor* actor, PlayState* play, s32 cueChannel) { +RECOMP_PATCH void Cutscene_ActorTranslate(Actor* actor, PlayState* play, s32 cueChannel) { Vec3f startPos; Vec3f endPos; CsCmdActorCue* cue = play->csCtx.actorCues[cueChannel]; @@ -39,7 +39,7 @@ extern EnHorseCsFunc D_808890F0[]; extern EnHorseCsFunc D_8088911C[]; // @recomp Patched to skip interpolation on Epona when she's teleported by a cutscene. -void func_80884718(EnHorse* this, PlayState* play) { +RECOMP_PATCH void func_80884718(EnHorse* this, PlayState* play) { CsCmdActorCue* cue; if (Cutscene_IsCueInChannel(play, CS_CMD_ACTOR_CUE_112)) { @@ -75,7 +75,7 @@ void func_80884718(EnHorse* this, PlayState* play) { } // @recomp Patched to skip interpolation on Epona when she's teleported by a cutscene. -void func_80883B70(EnHorse* this, CsCmdActorCue* cue) { +RECOMP_PATCH void func_80883B70(EnHorse* this, CsCmdActorCue* cue) { // @recomp Being teleported by a new cue, so skip interpolation. actor_set_interpolation_skipped(&this->actor); @@ -90,7 +90,7 @@ void func_80883B70(EnHorse* this, CsCmdActorCue* cue) { } // @recomp Patched to skip interpolation on Link when he's teleported to a new cue. -void Player_Cutscene_SetPosAndYawToStart(Player* this, CsCmdActorCue* cue) { +RECOMP_PATCH void Player_Cutscene_SetPosAndYawToStart(Player* this, CsCmdActorCue* cue) { // @recomp Being teleported by a new cue, so skip interpolation. actor_set_interpolation_skipped(&this->actor); @@ -104,7 +104,7 @@ void Player_Cutscene_SetPosAndYawToStart(Player* this, CsCmdActorCue* cue) { CsCmdActorCue* prev_link_cue = NULL; // @recomp Patched to skip interpolation on Link when he's teleported to a new cue. -void Player_Cutscene_Translate(PlayState* play, Player* this, CsCmdActorCue* cue) { +RECOMP_PATCH void Player_Cutscene_Translate(PlayState* play, Player* this, CsCmdActorCue* cue) { f32 startX = cue->startPos.x; f32 startY = cue->startPos.y; f32 startZ = cue->startPos.z; diff --git a/patches/effect_patches.c b/patches/effect_patches.c index 27f3d54..1b34a12 100644 --- a/patches/effect_patches.c +++ b/patches/effect_patches.c @@ -9,7 +9,7 @@ extern Gfx sTransWipe3DL[]; #define THIS ((TransitionWipe3*)thisx) // @recomp patched to scale the transition based on aspect ratio -void TransitionWipe3_Draw(void* thisx, Gfx** gfxP) { +RECOMP_PATCH void TransitionWipe3_Draw(void* thisx, Gfx** gfxP) { Gfx* gfx = *gfxP; Mtx* modelView = &THIS->modelView[THIS->frame]; f32 scale = 14.8f; @@ -53,7 +53,7 @@ extern s32 gFramerateDivisor; // @recomp Motion blur works fine normally, but when running at a higher framerate the effect is much less pronounced // as the previous frames decay quicker due to there being more frames drawn in the same period of time. -void Play_DrawMotionBlur(PlayState* this) { +RECOMP_PATCH void Play_DrawMotionBlur(PlayState* this) { GraphicsContext* gfxCtx = this->state.gfxCtx; s32 alpha; Gfx* gfx; @@ -126,7 +126,7 @@ void Play_DrawMotionBlur(PlayState* this) { } // @recomp Patched to increase the scale based on the aspect ratio. -void Actor_DrawLensOverlay(Gfx** gfxP, s32 lensMaskSize) { +RECOMP_PATCH void Actor_DrawLensOverlay(Gfx** gfxP, s32 lensMaskSize) { // @recomp Calculate the increase in aspect ratio. f32 original_aspect_ratio = (float)SCREEN_WIDTH / SCREEN_HEIGHT; f32 aspect_ratio_scale = recomp_get_aspect_ratio(original_aspect_ratio) / original_aspect_ratio; @@ -139,7 +139,7 @@ void Actor_DrawLensOverlay(Gfx** gfxP, s32 lensMaskSize) { // @recomp Patched to use ortho tris for interpolation and to prevent the telescope and lens effects from getting stretched wide. -void TransitionCircle_LoadAndSetTexture(Gfx** gfxp, TexturePtr texture, s32 fmt, s32 arg3, s32 masks, s32 maskt, +RECOMP_PATCH void TransitionCircle_LoadAndSetTexture(Gfx** gfxp, TexturePtr texture, s32 fmt, s32 arg3, s32 masks, s32 maskt, f32 arg6) { Gfx* gfx = *gfxp; s32 xh = gCfbWidth; diff --git a/patches/effect_transform_tagging.c b/patches/effect_transform_tagging.c index 405547e..6ce4b7b 100644 --- a/patches/effect_transform_tagging.c +++ b/patches/effect_transform_tagging.c @@ -13,7 +13,7 @@ extern Gfx gEffDustDL[]; ((&(particle).unk_1C)[1]) // @recomp Patched to record when a particle is moved to skip interpolation. -void func_808DC454(ObjectKankyo* this, PlayState* play) { +RECOMP_PATCH void func_808DC454(ObjectKankyo* this, PlayState* play) { s16 i; s32 pad1; f32 phi_f20; @@ -155,7 +155,7 @@ void func_808DC454(ObjectKankyo* this, PlayState* play) { } } -void func_808DD3C8(Actor* thisx, PlayState* play2) { +RECOMP_PATCH void func_808DD3C8(Actor* thisx, PlayState* play2) { PlayState* play = play2; ObjectKankyo* this = (ObjectKankyo*)thisx; Vec3f worldPos; @@ -331,7 +331,7 @@ static inline void pop_effect_tag(GraphicsContext* gfxCtx) { } // @recomp Patched to tag effects. -void Effect_DrawAll(GraphicsContext* gfxCtx) { +RECOMP_PATCH void Effect_DrawAll(GraphicsContext* gfxCtx) { s32 i; @@ -442,7 +442,7 @@ static TexturePtr sWaterSplashTextures[] = { * applies to all effects of that type while drawing the first effect of that type. */ // @recomp Patched to tag matrices. -void EnClearTag_DrawEffects(Actor* thisx, PlayState* play) { +RECOMP_PATCH void EnClearTag_DrawEffects(Actor* thisx, PlayState* play) { u8 isMaterialApplied = false; s16 i; s16 j; @@ -694,7 +694,7 @@ void EnClearTag_DrawEffects(Actor* thisx, PlayState* play) { } // @recomp Patched to tag the two custom lens flares (used by the Igos du Ikana curtains). -void Environment_DrawCustomLensFlare(PlayState* play) { +RECOMP_PATCH void Environment_DrawCustomLensFlare(PlayState* play) { Vec3f pos; // @recomp Set up the graphics context. @@ -739,7 +739,7 @@ void Environment_DrawCustomLensFlare(PlayState* play) { } // @recomp Patched to tag the sun lens flare. -void Environment_DrawSunLensFlare(PlayState* play, EnvironmentContext* envCtx, View* view, GraphicsContext* gfxCtx, +RECOMP_PATCH void Environment_DrawSunLensFlare(PlayState* play, EnvironmentContext* envCtx, View* view, GraphicsContext* gfxCtx, Vec3f vec) { if ((play->envCtx.precipitation[PRECIP_RAIN_CUR] == 0) && !(GET_ACTIVE_CAM(play)->stateFlags & CAM_STATE_UNDERWATER) && (play->skyboxId == SKYBOX_NORMAL_SKY)) { diff --git a/patches/fixes.c b/patches/fixes.c index 0dad6b9..7d159c1 100644 --- a/patches/fixes.c +++ b/patches/fixes.c @@ -25,7 +25,7 @@ s16 sVtxPageGameOverSaveQuadsY[VTX_PAGE_SAVE_QUADS] = { }; // @recomp patched to draw as strips with bilerp compensation instead of tiles. -s16 KaleidoScope_SetPageVertices(PlayState* play, Vtx* vtx, s16 vtxPage, s16 numQuads) { +RECOMP_PATCH s16 KaleidoScope_SetPageVertices(PlayState* play, Vtx* vtx, s16 vtxPage, s16 numQuads) { PauseContext* pauseCtx = &play->pauseCtx; GameOverContext* gameOverCtx = &play->gameOverCtx; s16* quadsX; @@ -204,7 +204,7 @@ void KaleidoDrawWrapper(PlayState* play) { } } -void KaleidoScopeCall_Init(PlayState* play) { +RECOMP_PATCH void KaleidoScopeCall_Init(PlayState* play) { // @recomp Set the update and draw func pointers to the wrappers instead of the actual functions. sKaleidoScopeUpdateFunc = KaleidoUpdateWrapper; sKaleidoScopeDrawFunc = KaleidoDrawWrapper; @@ -212,7 +212,7 @@ void KaleidoScopeCall_Init(PlayState* play) { } // @recomp patched to fix bilerp seams. -Gfx* KaleidoScope_DrawPageSections(Gfx* gfx, Vtx* vertices, TexturePtr* textures) { +RECOMP_PATCH Gfx* KaleidoScope_DrawPageSections(Gfx* gfx, Vtx* vertices, TexturePtr* textures) { s32 i; s32 j; @@ -264,7 +264,7 @@ int extra_vis = 0; // @recomp Patch the giants cutscene to make certain frames take longer to mimic performance on console. // This prevents the music from desyncing from the cutscene as it was designed around the console's frame times. -void Cutscene_UpdateScripted(PlayState* play, CutsceneContext* csCtx) { +RECOMP_PATCH void Cutscene_UpdateScripted(PlayState* play, CutsceneContext* csCtx) { if ((gSaveContext.cutsceneTrigger != 0) && (play->transitionTrigger == TRANS_TRIGGER_START)) { gSaveContext.cutsceneTrigger = 0; } @@ -297,7 +297,7 @@ void Cutscene_UpdateScripted(PlayState* play, CutsceneContext* csCtx) { } // @recomp Fix a texture scroll using an incorrect tile size, which resulted in the scroll jumping during the animation. -s32 DemoEffect_OverrideLimbDrawTimewarp(PlayState* play, SkelCurve* skelCurve, s32 limbIndex, Actor* thisx) { +RECOMP_PATCH s32 DemoEffect_OverrideLimbDrawTimewarp(PlayState* play, SkelCurve* skelCurve, s32 limbIndex, Actor* thisx) { s32 pad; DemoEffect* this = (DemoEffect*)thisx; u32 frames = play->gameplayFrames; @@ -333,7 +333,7 @@ void DayTelop_Noop(DayTelopState* this); void DayTelop_LoadGraphics(DayTelopState* this); // @recomp Increase the length of the "Dawn of the X Day" screen to account for faster loading. -void DayTelop_Init(GameState* thisx) { +RECOMP_PATCH void DayTelop_Init(GameState* thisx) { DayTelopState* this = (DayTelopState*)thisx; GameState_SetFramerateDivisor(&this->state, 1); @@ -371,7 +371,7 @@ void func_80836A5C(Player* this, PlayState* play); s32 func_8082DA90(PlayState* play); // @recomp Patched to fix the issue where ocarina inputs are discarded for the first 3 frames (150ms). -void Player_Action_63(Player* this, PlayState* play) { +RECOMP_PATCH void Player_Action_63(Player* this, PlayState* play) { if ((this->unk_AA5 != PLAYER_UNKAA5_4) && ((PlayerAnimation_Update(play, &this->skelAnime) && (this->skelAnime.animation == D_8085D17C[this->transformation])) || ((this->skelAnime.mode == 0) && (this->av2.actionVar2 == 0)))) { diff --git a/patches/input.c b/patches/input.c index 52a321f..53f7eb3 100644 --- a/patches/input.c +++ b/patches/input.c @@ -11,7 +11,7 @@ s16 func_80832754(Player* this, s32 arg1); s32 func_8082EF20(Player* this); // @recomp Patched to add gyro and mouse aiming. -s32 func_80847190(PlayState* play, Player* this, s32 arg2) { +RECOMP_PATCH s32 func_80847190(PlayState* play, Player* this, s32 arg2) { s32 pad; s16 var_s0; // @recomp Get the aiming camera inversion state. @@ -147,7 +147,7 @@ extern Input* sPlayerControlInput; * - B exits, using the RESPAWN_MODE_DOWN entrance */ // @recomp Patched for aiming inversion and supporting the right stick in dual analog. -void func_8083A98C(Actor* thisx, PlayState* play2) { +RECOMP_PATCH void func_8083A98C(Actor* thisx, PlayState* play2) { PlayState* play = play2; Player* this = (Player*)thisx; s32 camMode; @@ -351,7 +351,7 @@ u8* get_button_item_equip_ptr(u32 form, u32 button) { } // Return currently-pressed button, in order of priority D-Pad, B, CLEFT, CDOWN, CRIGHT. -EquipSlot func_8082FDC4(void) { +RECOMP_PATCH EquipSlot func_8082FDC4(void) { EquipSlot i; for (int extra_slot_index = 0; extra_slot_index < ARRAY_COUNT(buttons_to_extra_slot); extra_slot_index++) { @@ -369,7 +369,7 @@ EquipSlot func_8082FDC4(void) { return i; } -ItemId Player_GetItemOnButton(PlayState* play, Player* player, EquipSlot slot) { +RECOMP_PATCH ItemId Player_GetItemOnButton(PlayState* play, Player* player, EquipSlot slot) { if (slot >= EQUIP_SLOT_A) { return ITEM_NONE; } @@ -444,7 +444,7 @@ bool func_808323C0(Player *this, s16 csId); void func_80855218(PlayState *play, Player *this, struct_8085D910 **arg2); void func_808550D0(PlayState *play, Player *this, f32 arg2, f32 arg3, s32 arg4); -void Player_Action_86(Player *this, PlayState *play) { +RECOMP_PATCH void Player_Action_86(Player *this, PlayState *play) { struct_8085D910 *sp4C = D_8085D910; s32 sp48 = false; @@ -540,7 +540,7 @@ extern void* gWorkBuffer; u16 func_801A5100(void); // @recomp Patched to update status of extra buttons via set_extra_item_slot_status. -void Interface_UpdateButtonsPart1(PlayState* play) { +RECOMP_PATCH void Interface_UpdateButtonsPart1(PlayState* play) { InterfaceContext* interfaceCtx = &play->interfaceCtx; Player* player = GET_PLAYER(play); s32 pad; @@ -807,7 +807,7 @@ void Interface_UpdateButtonsPart1(PlayState* play) { * Also used directly when opening the pause menu i.e. skips part 1 */ // @recomp Patched in the same way as Interface_UpdateButtonsPart1 -void Interface_UpdateButtonsPart2(PlayState* play) { +RECOMP_PATCH void Interface_UpdateButtonsPart2(PlayState* play) { MessageContext* msgCtx = &play->msgCtx; InterfaceContext* interfaceCtx = &play->interfaceCtx; Player* player = GET_PLAYER(play); @@ -1300,7 +1300,7 @@ void Interface_UpdateButtonsPart2(PlayState* play) { * Sets the button alphas to be dimmed for disabled buttons, or to the requested alpha for non-disabled buttons */ // @recomp Patched to also set extra slot alpha values. -void Interface_UpdateButtonAlphasByStatus(PlayState* play, s16 risingAlpha) { +RECOMP_PATCH void Interface_UpdateButtonAlphasByStatus(PlayState* play, s16 risingAlpha) { InterfaceContext* interfaceCtx = &play->interfaceCtx; if ((gSaveContext.buttonStatus[EQUIP_SLOT_B] == BTN_DISABLED) || (gSaveContext.bButtonStatus == BTN_DISABLED)) { @@ -1373,7 +1373,7 @@ void Interface_UpdateButtonAlphasByStatus(PlayState* play, s16 risingAlpha) { * depending on button status */ // @recomp Patched to also set extra slot alpha values. -void Interface_UpdateButtonAlphas(PlayState* play, s16 dimmingAlpha, s16 risingAlpha) { +RECOMP_PATCH void Interface_UpdateButtonAlphas(PlayState* play, s16 dimmingAlpha, s16 risingAlpha) { InterfaceContext* interfaceCtx = &play->interfaceCtx; if (gSaveContext.hudVisibilityForceButtonAlphasByStatus) { @@ -1410,7 +1410,7 @@ void Interface_UpdateButtonAlphas(PlayState* play, s16 dimmingAlpha, s16 risingA } // @recomp Patched to also set extra slot alpha values. -void Interface_UpdateHudAlphas(PlayState* play, s16 dimmingAlpha) { +RECOMP_PATCH void Interface_UpdateHudAlphas(PlayState* play, s16 dimmingAlpha) { InterfaceContext* interfaceCtx = &play->interfaceCtx; s16 risingAlpha = 255 - dimmingAlpha; @@ -2336,7 +2336,7 @@ extern s8 sOcarinaInstrumentId; extern f32 AudioOcarina_BendPitchTwoSemitones(s8 bendIndex); // @recomp Patch the function in order to read DPad inputs for the ocarina as well as CButton inputs. -void AudioOcarina_PlayControllerInput(u8 isOcarinaSfxSuppressedWhenCancelled) { +RECOMP_PATCH void AudioOcarina_PlayControllerInput(u8 isOcarinaSfxSuppressedWhenCancelled) { u32 ocarinaBtnsHeld; // Prevents two different ocarina notes from being played on two consecutive frames @@ -2453,7 +2453,7 @@ extern void AudioOcarina_CheckIfStartedSong(void); extern void AudioOcarina_UpdateCurOcarinaSong(void); // @recomp Patch the L button check (for free ocarina playing) to account for DPad ocarina. -void AudioOcarina_CheckSongsWithoutMusicStaff(void) { +RECOMP_PATCH void AudioOcarina_CheckSongsWithoutMusicStaff(void) { u32 pitch; u8 ocarinaStaffPlayingPosStart; u8 songIndex; @@ -2528,7 +2528,7 @@ extern bool get_analog_cam_active(); extern void skip_analog_cam_once(); // @recomp Updates yaw while inside of deku flower. -void func_80855F9C(PlayState* play, Player* this) { +RECOMP_PATCH void func_80855F9C(PlayState* play, Player* this) { f32 speedTarget; s16 yawTarget; @@ -2553,7 +2553,7 @@ extern void Player_Action_4(Player* this, PlayState* play); extern s32 Player_SetAction(PlayState* play, Player* this, PlayerActionFunc actionFunc, s32 arg3); extern LinkAnimationHeader gPlayerAnim_pg_maru_change; -s32 func_80857950(PlayState* play, Player* this) { +RECOMP_PATCH s32 func_80857950(PlayState* play, Player* this) { // @recomp track if newly going from non-spike roll to spike roll (spike rolling when this->unk_B86[1] == 1) static bool wasOff = true; bool isOff = this->unk_B86[1] == 0; @@ -2597,7 +2597,7 @@ extern void func_8082DC38(Player* this); extern void func_80836A5C(Player* this, PlayState* play); // @recomp Patch the shielding function to respect the aiming axis inversion setting. -void Player_Action_18(Player* this, PlayState* play) { +RECOMP_PATCH void Player_Action_18(Player* this, PlayState* play) { func_80832F24(this); if (this->transformation == PLAYER_FORM_GORON) { diff --git a/patches/input_latency.c b/patches/input_latency.c index 2e04c52..8007c6a 100644 --- a/patches/input_latency.c +++ b/patches/input_latency.c @@ -34,7 +34,7 @@ typedef enum { /* 2 */ VOICE_INIT_SUCCESS // voice initialized } VoiceInitStatus; -void PadMgr_HandleRetrace(void) { +RECOMP_PATCH void PadMgr_HandleRetrace(void) { // Execute rumble callback if (sPadMgrInstance->rumbleRetraceCallback != NULL) { sPadMgrInstance->rumbleRetraceCallback(sPadMgrInstance->rumbleRetraceArg); @@ -113,7 +113,7 @@ void poll_inputs(void) { } // @recomp Patched to do the actual input polling. -void PadMgr_GetInput(Input* inputs, s32 gameRequest) { +RECOMP_PATCH void PadMgr_GetInput(Input* inputs, s32 gameRequest) { // @recomp Do an actual poll if gameRequest is true. if (gameRequest) { poll_inputs(); @@ -126,7 +126,7 @@ void PadMgr_GetInput(Input* inputs, s32 gameRequest) { } // @recomp Just call PadMgr_GetInput. -void PadMgr_GetInput2(Input* inputs, s32 gameRequest) { +RECOMP_PATCH void PadMgr_GetInput2(Input* inputs, s32 gameRequest) { PadMgr_GetInput(inputs, gameRequest); } @@ -138,7 +138,7 @@ void* osViGetCurrentFramebuffer_recomp(); OSMesgQueue *rdp_queue_ptr = NULL; // @recomp Immediately sends the graphics task instead of queueing it in the scheduler. -void Graph_TaskSet00(GraphicsContext* gfxCtx, GameState* gameState) { +RECOMP_PATCH void Graph_TaskSet00(GraphicsContext* gfxCtx, GameState* gameState) { static s32 retryCount = 10; static s32 cfbIdx = 0; OSTask_t* task = &gfxCtx->task.list.t; @@ -271,7 +271,7 @@ extern VisZbuf sGameVisZbuf; extern VisMono sGameVisMono; extern ViMode sGameViMode; -void GameState_Destroy(GameState* gameState) { +RECOMP_PATCH void GameState_Destroy(GameState* gameState) { AudioMgr_StopAllSfxExceptSystem(); Audio_Update(); diff --git a/patches/item_transform_tagging.c b/patches/item_transform_tagging.c index 900807a..0811c46 100644 --- a/patches/item_transform_tagging.c +++ b/patches/item_transform_tagging.c @@ -16,7 +16,7 @@ extern Gfx gHookshotChainDL[]; void ArmsHook_Shoot(ArmsHook* this, PlayState* play); -void ArmsHook_Draw(Actor* thisx, PlayState* play) { +RECOMP_PATCH void ArmsHook_Draw(Actor* thisx, PlayState* play) { ArmsHook* this = THIS; f32 f0; Player* player = GET_PLAYER(play); @@ -73,7 +73,7 @@ void ArmsHook_Draw(Actor* thisx, PlayState* play) { #undef THIS extern Gfx gHookshotReticleDL[]; -void Player_DrawHookshotReticle(PlayState* play, Player* player, f32 hookshotDistance) { +RECOMP_PATCH void Player_DrawHookshotReticle(PlayState* play, Player* player, f32 hookshotDistance) { static Vec3f D_801C094C = { -500.0f, -100.0f, 0.0f }; CollisionPoly* poly; s32 bgId; @@ -143,7 +143,7 @@ Gfx bowstring_end_hook_dl[] = { gsSPEndDisplayList(), }; -void Player_DrawGameplay(PlayState* play, Player* this, s32 lod, Gfx* cullDList, +RECOMP_PATCH void Player_DrawGameplay(PlayState* play, Player* this, s32 lod, Gfx* cullDList, OverrideLimbDrawFlex overrideLimbDraw) { OPEN_DISPS(play->state.gfxCtx); diff --git a/patches/ocarina_effect_patches.c b/patches/ocarina_effect_patches.c index 35d6410..b46c311 100644 --- a/patches/ocarina_effect_patches.c +++ b/patches/ocarina_effect_patches.c @@ -1030,7 +1030,7 @@ void set_ocarina_vertex_alphas(Vtx* verts, s32 count, u8 alpha) { extern Gfx sSongOfTimeFrustumMaterialDL[]; -void OceffWipe_Draw(Actor* thisx, PlayState* play) { +RECOMP_PATCH void OceffWipe_Draw(Actor* thisx, PlayState* play) { u32 scroll = play->state.frames & 0xFF; OceffWipe* this = (OceffWipe*)thisx; f32 z; @@ -1098,7 +1098,7 @@ void OceffWipe_Draw(Actor* thisx, PlayState* play) { extern Gfx sEponaSongFrustumMaterialDL[]; -void OceffWipe2_Draw(Actor* thisx, PlayState* play) { +RECOMP_PATCH void OceffWipe2_Draw(Actor* thisx, PlayState* play) { u32 scroll = play->state.frames & 0xFF; OceffWipe2* this = (OceffWipe2*)thisx; f32 z; @@ -1152,7 +1152,7 @@ void OceffWipe2_Draw(Actor* thisx, PlayState* play) { extern Gfx sSariaSongFrustrumMaterialDL[]; -void OceffWipe3_Draw(Actor* thisx, PlayState* play) { +RECOMP_PATCH void OceffWipe3_Draw(Actor* thisx, PlayState* play) { u32 scroll = play->state.frames & 0xFFF; OceffWipe3* this = (OceffWipe3*)thisx; f32 z; @@ -1207,7 +1207,7 @@ extern Gfx sScarecrowSongUnusedMaterialDL[]; extern Gfx sScarecrowSongMaterialDL[]; extern Gfx sScarecrowSongModelDL[]; -void OceffWipe4_Draw(Actor* thisx, PlayState* play) { +RECOMP_PATCH void OceffWipe4_Draw(Actor* thisx, PlayState* play) { u32 scroll = play->state.frames & 0xFFF; OceffWipe4* this = (OceffWipe4*)thisx; f32 z; @@ -1273,7 +1273,7 @@ static u8 sEnvColors[] = { extern Gfx gOceff5DL[]; extern AnimatedMaterial gOceff5TexAnim[]; -void OceffWipe5_Draw(Actor* thisx, PlayState* play) { +RECOMP_PATCH void OceffWipe5_Draw(Actor* thisx, PlayState* play) { OceffWipe5* this = (OceffWipe5*)thisx; f32 z; s32 pad; @@ -1342,7 +1342,7 @@ void OceffWipe5_Draw(Actor* thisx, PlayState* play) { extern Gfx gOceff6DL[]; extern AnimatedMaterial ovl_Oceff_Wipe6_Matanimheader_000338[]; -void OceffWipe6_Draw(Actor* thisx, PlayState* play) { +RECOMP_PATCH void OceffWipe6_Draw(Actor* thisx, PlayState* play) { OceffWipe6* this = (OceffWipe6*)thisx; f32 z; u8 alpha; @@ -1394,7 +1394,7 @@ void OceffWipe6_Draw(Actor* thisx, PlayState* play) { extern Gfx sSongOfHealingEffectFrustumDL[]; extern AnimatedMaterial sSongofHealingEffectTexAnim[]; -void OceffWipe7_Draw(Actor* thisx, PlayState* play) { +RECOMP_PATCH void OceffWipe7_Draw(Actor* thisx, PlayState* play) { OceffWipe7* this = (OceffWipe7*)thisx; f32 z; u8 alpha; @@ -1445,7 +1445,7 @@ extern AnimatedMaterial object_stk2_Matanimheader_009F60[]; // @recomp Patch the Skull Kid curse effect as well, which works similarly to the ocarina effects. // In this case, the patch also includes effect transform tagging patches. -void EffStk_Draw(Actor* thisx, PlayState* play) { +RECOMP_PATCH void EffStk_Draw(Actor* thisx, PlayState* play) { EffStk* this = (EffStk*)thisx; s32 pad; Camera* activeCam = GET_ACTIVE_CAM(play); diff --git a/patches/options.c b/patches/options.c index bbaa96d..c26133c 100644 --- a/patches/options.c +++ b/patches/options.c @@ -65,11 +65,11 @@ void FileSelect_DrawFileInfo(GameState *thisx, s16 fileIndex); void FileSelect_SplitNumber(u16 value, u16 *hundreds, u16 *tens, u16 *ones); // @recomp The options button is now the quit button, so close recomp instead of opening the options. -void FileSelect_RotateToOptions(GameState* thisx) { +RECOMP_PATCH void FileSelect_RotateToOptions(GameState* thisx) { recomp_exit(); } -void FileSelect_Init(GameState* thisx) { +RECOMP_PATCH void FileSelect_Init(GameState* thisx) { s32 pad; FileSelectState* this = (FileSelectState*)thisx; size_t size; @@ -109,7 +109,7 @@ void FileSelect_Init(GameState* thisx) { } -void FileSelect_SetWindowContentVtx(GameState *thisx) { +RECOMP_PATCH void FileSelect_SetWindowContentVtx(GameState *thisx) { FileSelectState *this = (FileSelectState *)thisx; u16 vtxId; s16 j; @@ -786,7 +786,7 @@ void FileSelect_SetWindowContentVtx(GameState *thisx) { * Draw most window contents including buttons, labels, and icons. * Does not include anything from the keyboard and settings windows. */ -void FileSelect_DrawWindowContents(GameState *thisx) { +RECOMP_PATCH void FileSelect_DrawWindowContents(GameState *thisx) { FileSelectState *this = (FileSelectState *)thisx; s16 fileIndex; s16 temp; @@ -991,7 +991,7 @@ void FileSelect_DrawWindowContents(GameState *thisx) { CLOSE_DISPS(this->state.gfxCtx); } -void FileSelect_ConfirmFile(GameState *thisx) { +RECOMP_PATCH void FileSelect_ConfirmFile(GameState *thisx) { FileSelectState *this = (FileSelectState *)thisx; Input *input = CONTROLLER1(&this->state); @@ -1040,7 +1040,7 @@ void FileSelect_ConfirmFile(GameState *thisx) { * Load the save for the appropriate file and start the game. * Update function for `SM_LOAD_GAME` */ -void FileSelect_LoadGame(GameState* thisx) { +RECOMP_PATCH void FileSelect_LoadGame(GameState* thisx) { FileSelectState* this = (FileSelectState*)thisx; u16 i; diff --git a/patches/particle_transform_tagging.c b/patches/particle_transform_tagging.c index ab9b6ac..64b0ee6 100644 --- a/patches/particle_transform_tagging.c +++ b/patches/particle_transform_tagging.c @@ -10,7 +10,7 @@ extern EffectSsInfo sEffectSsInfo; u8 particle_reset_list[MAX_PARTICLES]; // @recomp Patched to track that the particle has been reset. -void EffectSS_ResetEntry(EffectSs* particle) { +RECOMP_PATCH void EffectSS_ResetEntry(EffectSs* particle) { u32 i; particle->type = EFFECT_SS_MAX; @@ -39,7 +39,7 @@ void EffectSS_ResetEntry(EffectSs* particle) { } // @recomp Check numEntries to be sure enough space has been allocated for tracking particle statuses. -void EffectSS_Init(PlayState* play, s32 numEntries) { +RECOMP_PATCH void EffectSS_Init(PlayState* play, s32 numEntries) { u32 i; EffectSs* effectsSs; EffectSsOverlay* overlay; @@ -66,7 +66,7 @@ void EffectSS_Init(PlayState* play, s32 numEntries) { } // @recomp Add transform tags to particles -void EffectSS_DrawParticle(PlayState* play, s32 index) { +RECOMP_PATCH void EffectSS_DrawParticle(PlayState* play, s32 index) { EffectSs* entry = &sEffectSsInfo.dataTable[index]; OPEN_DISPS(play->state.gfxCtx); @@ -164,7 +164,7 @@ void func_80B22FA8_patched(Actor* thisx, EnHanabiStruct* arg0, PlayState* play2) } // @recomp Patched to call a custom version of a vanilla function. -void EnHanabi_Draw(Actor* thisx, PlayState* play) { +RECOMP_PATCH void EnHanabi_Draw(Actor* thisx, PlayState* play) { EnHanabi* this = (EnHanabi*)thisx; Matrix_Push(); @@ -176,7 +176,7 @@ void EnHanabi_Draw(Actor* thisx, PlayState* play) { Vec3f kankyo_prev_pos_base[DEMOKANKYO_EFFECT_COUNT] = {0}; // @recomp Patched to draw the lost woods particles outside the 4:3 region and tag their transforms. -void DemoKakyo_DrawLostWoodsSparkle(Actor* thisx, PlayState* play2) { +RECOMP_PATCH void DemoKakyo_DrawLostWoodsSparkle(Actor* thisx, PlayState* play2) { PlayState* play = play2; DemoKankyo* this = (DemoKankyo*)thisx; s16 i; @@ -286,7 +286,7 @@ extern Gfx gBubbleDL[]; extern Gfx gLightOrbModelDL[]; // @recomp Patched to draw the lost woods particles outside the 4:3 region and tag their transforms. -void DemoKankyo_DrawMoonAndGiant(Actor* thisx, PlayState* play2) { +RECOMP_PATCH void DemoKankyo_DrawMoonAndGiant(Actor* thisx, PlayState* play2) { PlayState* play = play2; DemoKankyo* this = (DemoKankyo*)thisx; s16 i; @@ -386,7 +386,7 @@ static Vec3f D_80A5AFB0 = { 0.0f, 0.0f, 0.0f }; #define WATER_EFFECT_RESPAWNED(ptr) (&(ptr)->unk_01)[1] // @recomp Mark respawned water effect particles so they can be skipped for the first frame. -void func_80A599E8(EnWaterEffect* this, Vec3f* arg1, u8 arg2) { +RECOMP_PATCH void func_80A599E8(EnWaterEffect* this, Vec3f* arg1, u8 arg2) { s16 i; EnWaterEffectStruct* ptr = &this->unk_144[0]; @@ -433,7 +433,7 @@ extern Gfx object_water_effect_DL_0043E8[]; extern Gfx gameplay_keep_DL_06AB30[]; // @recomp Tag the transforms for falling fire rocks. -void func_80A5A184(Actor* thisx, PlayState* play2) { +RECOMP_PATCH void func_80A5A184(Actor* thisx, PlayState* play2) { PlayState* play = play2; EnWaterEffect* this = (EnWaterEffect*)thisx; GraphicsContext* gfxCtx = play->state.gfxCtx; diff --git a/patches/patches.h b/patches/patches.h index 23243ca..f0f2b5e 100644 --- a/patches/patches.h +++ b/patches/patches.h @@ -1,6 +1,10 @@ #ifndef __PATCHES_H__ #define __PATCHES_H__ +#define RECOMP_EXPORT __attribute__((section(".recomp_export"))) +#define RECOMP_PATCH __attribute__((section(".recomp_patch"))) +#define RECOMP_FORCE_PATCH __attribute__((section(".recomp_force_patch"))) + // TODO fix renaming symbols in patch recompilation #define osCreateMesgQueue osCreateMesgQueue_recomp #define osRecvMesg osRecvMesg_recomp diff --git a/patches/patches.ld b/patches/patches.ld index 4f7c56a..b0a3b7f 100644 --- a/patches/patches.ld +++ b/patches/patches.ld @@ -7,12 +7,14 @@ MEMORY { } SECTIONS { - .ctors : { *(.ctors*) *(.init_array*) } >extram AT >rom - .dtors : { *(.dtors*) } >extram AT >rom - .text : { *(.text*) } >extram AT >rom - .rodata : { *(.rodata*) } >extram AT >rom - .data : { *(.data*) } >extram AT >rom - .bss (NOLOAD) : { *(.bss*) *(COMMON) } >extram + .ctors : { *(.ctors*) *(.init_array*) } >extram AT >rom + .dtors : { *(.dtors*) } >extram AT >rom + .text : { *(.text*) } >extram AT >rom + .recomp_patch : { *(.recomp_patch*) *(.recomp_force_patch*) } >extram AT >rom + .recomp_export : { *(.recomp_export*) } >extram AT >rom + .rodata : { *(.rodata*) } >extram AT >rom + .data : { *(.data*) } >extram AT >rom + .bss (NOLOAD) : { *(.bss*) *(COMMON) } >extram ASSERT(. < RAMBASE + EXTRA_RAM_SIZE, "Maxed out recomp extra ram") .reloc 0 : { *(.reloc*) } diff --git a/patches/play_patches.c b/patches/play_patches.c index bff7066..e3d7c84 100644 --- a/patches/play_patches.c +++ b/patches/play_patches.c @@ -9,7 +9,7 @@ void controls_play_update(PlayState* play) { } // @recomp Patched to add hooks for various added functionality. -void Play_Main(GameState* thisx) { +RECOMP_PATCH void Play_Main(GameState* thisx) { static Input* prevInput = NULL; PlayState* this = (PlayState*)thisx; @@ -54,7 +54,7 @@ void Play_Main(GameState* thisx) { } // @recomp Patched to add load a hook for loading rooms. -s32 Room_HandleLoadCallbacks(PlayState* play, RoomContext* roomCtx) { +RECOMP_PATCH s32 Room_HandleLoadCallbacks(PlayState* play, RoomContext* roomCtx) { if (roomCtx->status == 1) { if (osRecvMesg(&roomCtx->loadQueue, NULL, OS_MESG_NOBLOCK) == 0) { roomCtx->status = 0; diff --git a/patches/required_patches.c b/patches/required_patches.c index e491a61..721a41a 100644 --- a/patches/required_patches.c +++ b/patches/required_patches.c @@ -8,7 +8,7 @@ void Main_InitScreen(void); // @recomp Patched to load the code segment in the recomp runtime. -void Main_Init(void) { +RECOMP_PATCH void Main_Init(void) { DmaRequest dmaReq; OSMesgQueue mq; OSMesg msg[1]; @@ -36,7 +36,7 @@ void Main_Init(void) { void Overlay_Relocate(void* allocatedRamAddr, OverlayRelocationSection* ovlRelocs, uintptr_t vramStart); // @recomp Patched to load the overlay in the recomp runtime. -size_t Overlay_Load(uintptr_t vromStart, uintptr_t vromEnd, void* ramStart, void* ramEnd, void* allocatedRamAddr) { +RECOMP_PATCH size_t Overlay_Load(uintptr_t vromStart, uintptr_t vromEnd, void* ramStart, void* ramEnd, void* allocatedRamAddr) { uintptr_t vramStart = (uintptr_t)ramStart; uintptr_t vramEnd = (uintptr_t)ramEnd; s32 size = vromEnd - vromStart; diff --git a/patches/save_patches.c b/patches/save_patches.c index 229fed2..75644f5 100644 --- a/patches/save_patches.c +++ b/patches/save_patches.c @@ -8,7 +8,7 @@ s32 SysFlashrom_IsInit(void); void Sleep_Msec(u32 ms); // @recomp Patched to not wait a hardcoded amount of time for the save to complete. -void Sram_UpdateWriteToFlashDefault(SramContext* sramCtx) { +RECOMP_PATCH void Sram_UpdateWriteToFlashDefault(SramContext* sramCtx) { if (sramCtx->status == 2) { if (SysFlashrom_IsBusy() != 0) { // if task running if (SysFlashrom_AwaitResult() == 0) { // wait for task done @@ -26,7 +26,7 @@ void Sram_UpdateWriteToFlashDefault(SramContext* sramCtx) { } // @recomp Patched to not wait a hardcoded amount of time for the save to complete. -void Sram_UpdateWriteToFlashOwlSave(SramContext* sramCtx) { +RECOMP_PATCH void Sram_UpdateWriteToFlashOwlSave(SramContext* sramCtx) { if (sramCtx->status == 7) { if (SysFlashrom_IsBusy() != 0) { // Is task running if (SysFlashrom_AwaitResult() == 0) { // Wait for task done diff --git a/patches/skip_sos.c b/patches/skip_sos.c index 71a6f76..3b1c0fa 100644 --- a/patches/skip_sos.c +++ b/patches/skip_sos.c @@ -7,7 +7,7 @@ void func_80AF118C(PlayState* play, OwlWarpFeather* feathers, EnTest7* this, s32 arg3, s32 arg4); // EnTest7_UpdateFeathers void func_80AF2350(EnTest7* this, PlayState* play); // EnTest7_WarpCsWarp -void EnTest7_Update(Actor* thisx, PlayState* play) { +RECOMP_PATCH void EnTest7_Update(Actor* thisx, PlayState* play) { EnTest7* this = THIS; this->actionFunc(this, play); diff --git a/patches/sky_transform_tagging.c b/patches/sky_transform_tagging.c index 9503a62..c776468 100644 --- a/patches/sky_transform_tagging.c +++ b/patches/sky_transform_tagging.c @@ -5,7 +5,7 @@ extern Mtx* sSkyboxDrawMatrix; -void Skybox_Draw(SkyboxContext* skyboxCtx, GraphicsContext* gfxCtx, s16 skyboxId, s16 blend, f32 x, f32 y, f32 z) { +RECOMP_PATCH void Skybox_Draw(SkyboxContext* skyboxCtx, GraphicsContext* gfxCtx, s16 skyboxId, s16 blend, f32 x, f32 y, f32 z) { OPEN_DISPS(gfxCtx); Gfx_SetupDL40_Opa(gfxCtx); @@ -112,7 +112,7 @@ f32 view_aspect_ratio(View* view) { } // @recomp Patched to set up the RSP for drawing stars with ortho rects and tag star transforms. -void Environment_DrawSkyboxStarsImpl(PlayState* play, Gfx** gfxP) { +RECOMP_PATCH void Environment_DrawSkyboxStarsImpl(PlayState* play, Gfx** gfxP) { static const Vec3s D_801DD880[] = { { 0x0384, 0x2328, 0xD508 }, { 0x09C4, 0x2328, 0xDA1C }, { 0x0E74, 0x22D8, 0xDA1C }, { 0x1450, 0x2468, 0xD8F0 }, { 0x1C84, 0x28A0, 0xCBA8 }, { 0x1F40, 0x2134, 0xD8F0 }, { 0x1F40, 0x28A0, 0xDAE4 }, { 0xE4A8, 0x4A38, 0x4A38 }, diff --git a/patches/song_transform_tagging.c b/patches/song_transform_tagging.c index 2325c8b..f11e2f7 100644 --- a/patches/song_transform_tagging.c +++ b/patches/song_transform_tagging.c @@ -15,7 +15,7 @@ s32 func_80AF31D0(PlayState* play, SkeletonInfo* skeletonInfo, s32 limbIndex, Gf extern AnimatedMaterial gSoaringWarpCsWindCapsuleTexAnim; extern Gfx gSoaringWarpCsWindCapsuleDL[]; -void EnTest7_Draw(Actor* thisx, PlayState* play) { +RECOMP_PATCH void EnTest7_Draw(Actor* thisx, PlayState* play) { s32 pad[2]; EnTest7* this = (EnTest7*)thisx; s32 sp40; @@ -104,7 +104,7 @@ extern SoTCsAmmoDrops sSoTCsAmmoDrops[12]; /** * Draws clocks in a double spiral above and below player */ -void EnTest6_DrawThreeDayResetSoTCutscene(EnTest6* this, PlayState* play) { +RECOMP_PATCH void EnTest6_DrawThreeDayResetSoTCutscene(EnTest6* this, PlayState* play) { s16 clock1Yaw; s16 clock2Yaw; s16 angle; diff --git a/patches/sound_patches.c b/patches/sound_patches.c index dd4c7ea..504f9ec 100644 --- a/patches/sound_patches.c +++ b/patches/sound_patches.c @@ -17,7 +17,7 @@ bool is_bgm_player(u8 player_index) { /** * Update different commands and requests for active sequences */ -void AudioSeq_UpdateActiveSequences(void) { +RECOMP_PATCH void AudioSeq_UpdateActiveSequences(void) { u32 tempoCmd; u16 tempoPrev; u16 seqId; @@ -338,7 +338,7 @@ void AudioSeq_UpdateActiveSequences(void) { } // @recomp Patched to add the ability to turn off low health beeps. -void LifeMeter_UpdateSizeAndBeep(PlayState* play) { +RECOMP_PATCH void LifeMeter_UpdateSizeAndBeep(PlayState* play) { InterfaceContext* interfaceCtx = &play->interfaceCtx; if (interfaceCtx->lifeSizeChangeDirection != 0) { diff --git a/patches/specific_actor_transform_tagging.c b/patches/specific_actor_transform_tagging.c index 352619e..a444d4a 100644 --- a/patches/specific_actor_transform_tagging.c +++ b/patches/specific_actor_transform_tagging.c @@ -30,7 +30,7 @@ extern Gfx gEffWaterRippleDL[]; u8 special_effect_reset_states[MAX_SPECIAL_EFFECTS]; // @recomp Tag Wart's bubbles -void EnTanron2_Draw(Actor* thisx, PlayState* play2) { +RECOMP_PATCH void EnTanron2_Draw(Actor* thisx, PlayState* play2) { PlayState* play = play2; s32 i; s32 j; @@ -153,7 +153,7 @@ void EnTanron2_Draw(Actor* thisx, PlayState* play2) { } // @recomp Track this effect's reset state. -void Boss03_SpawnEffectWetSpot(PlayState* play, Vec3f* pos) { +RECOMP_PATCH void Boss03_SpawnEffectWetSpot(PlayState* play, Vec3f* pos) { s16 i; GyorgEffect* eff = play->specialEffects; @@ -177,7 +177,7 @@ void Boss03_SpawnEffectWetSpot(PlayState* play, Vec3f* pos) { } // @recomp Track this effect's reset state. -void Boss03_SpawnEffectDroplet(PlayState* play, Vec3f* pos) { +RECOMP_PATCH void Boss03_SpawnEffectDroplet(PlayState* play, Vec3f* pos) { s16 i; GyorgEffect* eff = play->specialEffects; @@ -204,7 +204,7 @@ void Boss03_SpawnEffectDroplet(PlayState* play, Vec3f* pos) { } // @recomp Track this effect's reset state. -void Boss03_SpawnEffectSplash(PlayState* play, Vec3f* pos, Vec3f* velocity) { +RECOMP_PATCH void Boss03_SpawnEffectSplash(PlayState* play, Vec3f* pos, Vec3f* velocity) { Vec3f accel = { 0.0f, -1.0f, 0.0f }; f32 temp_f2; GyorgEffect* eff = play->specialEffects; @@ -231,7 +231,7 @@ void Boss03_SpawnEffectSplash(PlayState* play, Vec3f* pos, Vec3f* velocity) { } // @recomp Track this effect's reset state. -void Boss03_SpawnEffectBubble(PlayState* play, Vec3f* pos) { +RECOMP_PATCH void Boss03_SpawnEffectBubble(PlayState* play, Vec3f* pos) { s16 i; GyorgEffect* eff = play->specialEffects; @@ -261,7 +261,7 @@ extern u8 gEffDust1Tex[]; void Boss03_SetObject(PlayState* play, s16 objectId); // @recomp Tag Gyorg's effects. -void Boss03_DrawEffects(PlayState* play) { +RECOMP_PATCH void Boss03_DrawEffects(PlayState* play) { u8 flag = false; s16 i; GraphicsContext* gfxCtx = play->state.gfxCtx; @@ -410,7 +410,7 @@ extern Gfx object_water_effect_DL_000420[]; extern Gfx object_water_effect_DL_000A48[]; extern Gfx object_water_effect_DL_000CD8[]; -void func_80A5A6B8(Actor* thisx, PlayState* play2) { +RECOMP_PATCH void func_80A5A6B8(Actor* thisx, PlayState* play2) { PlayState* play = play2; EnWaterEffect* this = (EnWaterEffect*)thisx; EnWaterEffectStruct* ptr = &this->unk_144[0]; @@ -547,7 +547,7 @@ void func_80A5A6B8(Actor* thisx, PlayState* play2) { } // @recomp Tag normal water effects. -void EnWaterEffect_Draw(Actor* thisx, PlayState* play2) { +RECOMP_PATCH void EnWaterEffect_Draw(Actor* thisx, PlayState* play2) { PlayState* play = play2; GraphicsContext* gfxCtx = play->state.gfxCtx; EnWaterEffect* this = (EnWaterEffect*)thisx; @@ -641,7 +641,7 @@ extern Gfx gGohtStalactiteMaterialDL[]; extern Gfx gGohtStalactiteModelDL[]; // @recomp Tag Goht's rocks. -void func_80B0C398(BossHakugin* this, PlayState* play) { +RECOMP_PATCH void func_80B0C398(BossHakugin* this, PlayState* play) { BossHakuginEffect* effect; s32 i; @@ -722,7 +722,7 @@ void EnOsn_HandleCsAction(EnOsn* this, PlayState* play); void EnOsn_Idle(EnOsn* this, PlayState* play); // @recomp Patched to skip interpolation when the Happy Mask Salesman changes animations. -void EnOsn_ChooseAction(EnOsn* this, PlayState* play) { +RECOMP_PATCH void EnOsn_ChooseAction(EnOsn* this, PlayState* play) { u32 isSwitchFlagSet = Flags_GetSwitch(play, 0); this->csId = this->actor.csId; @@ -743,7 +743,7 @@ void EnOsn_LookFromMask(EnOsn* this); void EnOsn_FadeOut(EnOsn* this); // @recomp Patched to skip interpolation when the Happy Mask Salesman changes animations. -void EnOsn_HandleCsAction(EnOsn* this, PlayState* play) { +RECOMP_PATCH void EnOsn_HandleCsAction(EnOsn* this, PlayState* play) { u8 pad; s32 cueChannel; @@ -880,7 +880,7 @@ void EnOsn_HandleCsAction(EnOsn* this, PlayState* play) { } // @recomp Patched to tag this actor's draws using linear order matching. -void EnFall2_Draw(Actor* thisx, PlayState* play) { +RECOMP_PATCH void EnFall2_Draw(Actor* thisx, PlayState* play) { s32 pad; EnFall2* this = (EnFall2*)thisx; Mtx* mtx; @@ -909,7 +909,7 @@ void EnFall2_Draw(Actor* thisx, PlayState* play) { } // @recomp Skip interpolation on item pickups the frame they're collected. -void func_800A6A40(EnItem00* this, PlayState* play) { +RECOMP_PATCH void func_800A6A40(EnItem00* this, PlayState* play) { Player* player = GET_PLAYER(play); if (this->getItemId != GI_NONE) { @@ -952,7 +952,7 @@ extern Vtx ovl_Obj_Entotu_Vtx_000D10[7]; extern Gfx object_f53_obj_DL_001C00[]; // @recomp Skip rotation interpolation for the Clock Town chimney's smoke when the camera skips interolation. -void func_80A34B28(ObjEntotu* this, PlayState* play) { +RECOMP_PATCH void func_80A34B28(ObjEntotu* this, PlayState* play) { u8 sp57; u8 sp56; s32 i; @@ -1002,7 +1002,7 @@ void func_80A34B28(ObjEntotu* this, PlayState* play) { extern Gfx object_f53_obj_DL_000158[]; // @recomp Skip rotation interpolation for the Clock Town chimney when the camera skips interolation. -void func_80A34A44(ObjEntotu* this, PlayState* play) { +RECOMP_PATCH void func_80A34A44(ObjEntotu* this, PlayState* play) { Matrix_Translate(this->actor.world.pos.x, this->actor.world.pos.y, this->actor.world.pos.z, MTXMODE_NEW); this->actor.shape.rot.y = BINANG_ROT180(Camera_GetCamDirYaw(GET_ACTIVE_CAM(play))); Matrix_RotateYS(this->actor.shape.rot.y, MTXMODE_APPLY); @@ -1032,7 +1032,7 @@ void func_80A34A44(ObjEntotu* this, PlayState* play) { void Environment_DrawRainImpl(PlayState* play, View* view, GraphicsContext* gfxCtx); // @recomp Skip interpolation for the splashes that raindrops make. -void Environment_DrawRain(PlayState* play, View* view, GraphicsContext* gfxCtx) { +RECOMP_PATCH void Environment_DrawRain(PlayState* play, View* view, GraphicsContext* gfxCtx) { if (!(GET_ACTIVE_CAM(play)->stateFlags & CAM_STATE_UNDERWATER) && (play->envCtx.precipitation[PRECIP_SNOW_CUR] == 0)) { @@ -1058,7 +1058,7 @@ void Environment_DrawRain(PlayState* play, View* view, GraphicsContext* gfxCtx) } // @recomp Skip interpolation on the boulders in the path to Snowhead and the path to Ikana Canyon when they teleport back to their home position. -void func_8093EE64(EnGoroiwa* this, s32 arg1) { +RECOMP_PATCH void func_8093EE64(EnGoroiwa* this, s32 arg1) { Vec3s* temp_v0 = &this->pathPoints[arg1]; this->actor.world.pos.x = temp_v0->x; @@ -1075,7 +1075,7 @@ extern Gfx object_twig_DL_001C38[]; extern Gfx object_twig_DL_0014C8[]; // @recomp Skip interpolation on the rotation for the beaver race rings in order to retain the intended animation look. -void EnTwig_Draw(Actor* thisx, PlayState* play) { +RECOMP_PATCH void EnTwig_Draw(Actor* thisx, PlayState* play) { EnTwig* this = (EnTwig*)thisx; switch (this->unk_160) { @@ -1101,7 +1101,7 @@ extern Gfx gEffFire1DL[]; #define HONOTRAP_EXTRA_BYTE_1(flameGroup) (&(flameGroup)->flameList[0].isDrawn)[1] #define HONOTRAP_EXTRA_BYTE_2(flameGroup) (&(flameGroup)->flameList[1].isDrawn)[1] -void EnHonotrap_FlameGroup(EnHonotrap* this, PlayState* play) { +RECOMP_PATCH void EnHonotrap_FlameGroup(EnHonotrap* this, PlayState* play) { s32 i; EnHonotrapFlameGroup* flameGroup = &this->flameGroup; f32 var_fs0; @@ -1203,7 +1203,7 @@ void EnHonotrap_FlameGroup(EnHonotrap* this, PlayState* play) { // @recomp Patched to tag the flames that come out of fire eyes. -void EnHonotrap_DrawFlameGroup(Actor* thisx, PlayState* play) { +RECOMP_PATCH void EnHonotrap_DrawFlameGroup(Actor* thisx, PlayState* play) { s32 pad; EnHonotrap* this = (EnHonotrap*)thisx; EnHonotrapFlameElement* flameElem; diff --git a/patches/terrain_transform_tagging.c b/patches/terrain_transform_tagging.c index 3a521b6..00dd046 100644 --- a/patches/terrain_transform_tagging.c +++ b/patches/terrain_transform_tagging.c @@ -7,7 +7,7 @@ static Vec3f sZeroVec = { 0.0f, 0.0f, 0.0f }; extern RoomDrawHandler sRoomDrawHandlers[]; -void Room_Draw(PlayState* play, Room* room, u32 flags) { +RECOMP_PATCH void Room_Draw(PlayState* play, Room* room, u32 flags) { if (room->segment != NULL) { gSegments[3] = OS_K0_TO_PHYSICAL(room->segment); @@ -51,7 +51,7 @@ extern Gfx gKeikokuDemoTallTreeStraightDL[]; extern Gfx gKeikokuDemoTallTreeStraightEmptyDL[]; // @recomp Tag the ground in the intro cutscene to not interpolate rotation. -void DmOpstage_Draw(Actor* thisx, PlayState* play) { +RECOMP_PATCH void DmOpstage_Draw(Actor* thisx, PlayState* play) { DmOpstage* this = (DmOpstage*)thisx; if (DMOPSTAGE_GET_TYPE(&this->dyna.actor) > DMOPSTAGE_TYPE_GROUND) { @@ -130,7 +130,7 @@ extern s16 D_80AAAAC8; extern s16 D_80AAAACC; // @recomp Patched to enable vertex interpolation for the dynamic water as Woodfall temple rises from below the water. -void DmChar01_Draw(Actor* thisx, PlayState* play) { +RECOMP_PATCH void DmChar01_Draw(Actor* thisx, PlayState* play) { // @recomp Move function statics to externs so they still get reset on overlay load like normal. DmChar01* this = (DmChar01*)thisx; f32 temp_f12; diff --git a/patches/ui_patches.c b/patches/ui_patches.c index f40387c..a057655 100644 --- a/patches/ui_patches.c +++ b/patches/ui_patches.c @@ -22,7 +22,7 @@ typedef struct { BiggerGfxPool gBiggerGfxPools[2]; // @recomp Use the bigger gfx pools and enable RT64 extended GBI mode. -void Graph_SetNextGfxPool(GraphicsContext* gfxCtx) { +RECOMP_PATCH void Graph_SetNextGfxPool(GraphicsContext* gfxCtx) { GfxPool* pool = &gGfxPools[gfxCtx->gfxPoolIdx % 2]; BiggerGfxPool* bigger_pool = &gBiggerGfxPools[gfxCtx->gfxPoolIdx % 2]; @@ -85,7 +85,7 @@ extern int extra_vis; * Run the game state logic, then finalize the gfx buffer * and run the graphics task for this frame. */ -void Graph_ExecuteAndDraw(GraphicsContext* gfxCtx, GameState* gameState) { +RECOMP_PATCH void Graph_ExecuteAndDraw(GraphicsContext* gfxCtx, GameState* gameState) { u32 problem; gameState->unk_A3 = 0; @@ -238,7 +238,7 @@ void Interface_SetOrthoView(InterfaceContext* interfaceCtx); void Interface_SetVertices(PlayState* play); void Magic_DrawMeter(PlayState* play); -void Interface_Draw(PlayState* play) { +RECOMP_PATCH void Interface_Draw(PlayState* play) { s32 pad; InterfaceContext* interfaceCtx = &play->interfaceCtx; Player* player = GET_PLAYER(play); @@ -756,7 +756,7 @@ extern u64 gArcheryScoreIconTex[]; extern u16 sMinigameScoreDigits[]; // @recomp Patched to draw the carrot icons with an extended gbi texrect so they don't inherit the current origin. -void Interface_DrawMinigameIcons(PlayState* play) { +RECOMP_PATCH void Interface_DrawMinigameIcons(PlayState* play) { InterfaceContext* interfaceCtx = &play->interfaceCtx; s16 i; s16 numDigitsDrawn; @@ -881,7 +881,7 @@ extern s16 sTextboxTexHeight; extern u64 gOcarinaTrebleClefTex[]; // @recomp Patch textboxes to use ortho tris with a matrix so they can be interpolated. -void Message_DrawTextBox(PlayState* play, Gfx** gfxP) { +RECOMP_PATCH void Message_DrawTextBox(PlayState* play, Gfx** gfxP) { MessageContext* msgCtx = &play->msgCtx; Gfx* gfx = *gfxP; @@ -1018,7 +1018,7 @@ void View_SetScissor(Gfx** gfx, s32 ulx, s32 uly, s32 lrx, s32 lry); // @recomp Patched to not actually letterbox the scissor. The letterbox effect will be achieved by drawing an overlay on top instead, which // will get interpolated unlike a scissor. -void View_ApplyLetterbox(View* view) { +RECOMP_PATCH void View_ApplyLetterbox(View* view) { s32 letterboxY; s32 letterboxX; s32 pad1; @@ -1085,7 +1085,7 @@ typedef struct { extern ShrinkWindow* sShrinkWindowPtr; // @recomp Replace the rects used to letterbox with ortho tris so they can be interpolated. -void ShrinkWindow_Draw(GraphicsContext* gfxCtx) { +RECOMP_PATCH void ShrinkWindow_Draw(GraphicsContext* gfxCtx) { Gfx* gfx; s8 letterboxSize = sShrinkWindowPtr->letterboxSize; s8 pillarboxSize = sShrinkWindowPtr->pillarboxSize; @@ -1189,7 +1189,7 @@ extern u64 gSceneTitleCardGradientTex[]; // @recomp Patch the scene title card (the one with purple background when entering a new scene) // to not glitch out on the right edge, which is hidden by overscan on N64. -void Message_DrawSceneTitleCard(PlayState* play, Gfx** gfxP) { +RECOMP_PATCH void Message_DrawSceneTitleCard(PlayState* play, Gfx** gfxP) { MessageContext* msgCtx = &play->msgCtx; Gfx* gfx; diff --git a/patches/ui_transform_tagging.c b/patches/ui_transform_tagging.c index b071bab..b403795 100644 --- a/patches/ui_transform_tagging.c +++ b/patches/ui_transform_tagging.c @@ -56,7 +56,7 @@ extern TexturePtr sMaskPageBgTextures[]; // @recomp Patched to set pageIndex to a dummy value when KaleidoScope_SetVertices is called to make it // allocate vertices for all pages at all times. This is simpler than patching KaleidoScope_SetVertices directly. -void KaleidoScope_Draw(PlayState* play) { +RECOMP_PATCH void KaleidoScope_Draw(PlayState* play) { s32 pad; PauseContext* pauseCtx = &play->pauseCtx; InterfaceContext* interfaceCtx = &play->interfaceCtx; @@ -137,7 +137,7 @@ void KaleidoScope_Draw(PlayState* play) { CLOSE_DISPS(play->state.gfxCtx); } -void KaleidoScope_DrawCursor(PlayState* play) { +RECOMP_PATCH void KaleidoScope_DrawCursor(PlayState* play) { PauseContext* pauseCtx = &play->pauseCtx; s16 i; @@ -219,7 +219,7 @@ extern s16 sPauseZRCursorAlpha; // 8082DA56 32899 -9642 */ // @recomp Patched to tag the matrix for interpolating the vertices of the Z button, R button, and name panel. -void KaleidoScope_DrawInfoPanel(PlayState* play) { +RECOMP_PATCH void KaleidoScope_DrawInfoPanel(PlayState* play) { static const s16 sPauseZRCursorColorTargets[][4] = { { 180, 210, 255, 220 }, { 100, 100, 150, 220 }, @@ -587,7 +587,7 @@ void KaleidoScope_DrawInfoPanel(PlayState* play) { } // @recomp Patched to draw always all 4 pages and tag their matrices. -void KaleidoScope_DrawPages(PlayState* play, GraphicsContext* gfxCtx) { +RECOMP_PATCH void KaleidoScope_DrawPages(PlayState* play, GraphicsContext* gfxCtx) { static s16 sCursorColorTimer = 10; static s16 sCursorColorTargetIndex = 0; PauseContext* pauseCtx = &play->pauseCtx; From 5aa650bffa061b118426b70e68d6000fbd8a926d Mon Sep 17 00:00:00 2001 From: Reonu Date: Fri, 26 Jul 2024 04:08:23 +0100 Subject: [PATCH 04/49] Update RT64 for HD texture framework and DXIL linker (#262) * WIP HD texture support * Remove STB implementation as it's already defined in RT64 * Fix texcoords for seamless pause background patch * Fix RT64 compilation error and temporarily disable shader cache * Fix vertices for bottom strip in seamless pause background patch * Update RT64 for mip preloading and alignment fixes * Update RT64 for zipped texture pack support and fix CMake warning flags for clang-cl * Update RT64 to have multiple pack loading and texture memory stats in the debugger * Update RT64 to fix replace button crash * Update to RT64 main as HD textures were merged and completely removed shader cache as it's not needed --------- Co-authored-by: Wiseguy <68165316+Mr-Wiseguy@users.noreply.github.com> --- CMakeLists.txt | 5 ++++- lib/rt64 | 2 +- patches/fixes.c | 6 +++--- src/main/main.cpp | 8 -------- 4 files changed, 8 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7acd983..b1b6e79 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,9 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) # set(CMAKE_CXX_VISIBILITY_PRESET hidden) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-everything -Wall -Wextra") +if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-everything /W4") +endif() # Avoid warning about DOWNLOAD_EXTRACT_TIMESTAMP in CMake 3.24: if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0") @@ -29,6 +31,7 @@ SET(LUNASVG_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) add_subdirectory(${CMAKE_SOURCE_DIR}/lib/lunasvg) # set(BUILD_SHARED_LIBS "${BUILD_SHARED_LIBS_SAVED}") SET(ENABLE_SVG_PLUGIN ON CACHE BOOL "" FORCE) +SET(RMLUI_TESTS_ENABLED OFF CACHE BOOL "" FORCE) add_subdirectory(${CMAKE_SOURCE_DIR}/lib/RmlUi) add_subdirectory(${CMAKE_SOURCE_DIR}/lib/N64ModernRuntime) diff --git a/lib/rt64 b/lib/rt64 index 36e3114..0fd6d05 160000 --- a/lib/rt64 +++ b/lib/rt64 @@ -1 +1 @@ -Subproject commit 36e3114cd23a80683504c257729ff7a419735f50 +Subproject commit 0fd6d05b8a0ec5daae313ad9e8504812ec31775d diff --git a/patches/fixes.c b/patches/fixes.c index 7d159c1..2f3f8b2 100644 --- a/patches/fixes.c +++ b/patches/fixes.c @@ -35,11 +35,11 @@ RECOMP_PATCH s16 KaleidoScope_SetPageVertices(PlayState* play, Vtx* vtx, s16 vtx s32 cur_y; u32 row; - cur_y = PAGE_BG_HEIGHT / 2; + cur_y = (PAGE_BG_HEIGHT + 2) / 2; // 2 verts per row plus 2 extra verts at the start and the end. for (row = 0; row < RECOMP_PAGE_ROW_COUNT + 2; row++) { - s32 next_y = MAX(cur_y - RECOMP_PAGE_ROW_HEIGHT, -PAGE_BG_HEIGHT / 2); + s32 next_y = MAX(cur_y - RECOMP_PAGE_ROW_HEIGHT, -(PAGE_BG_HEIGHT + 2) / 2); vtx[4 * row + 0].v.ob[0] = -PAGE_BG_WIDTH / 2; vtx[4 * row + 1].v.ob[0] = PAGE_BG_WIDTH / 2; @@ -234,7 +234,7 @@ RECOMP_PATCH Gfx* KaleidoScope_DrawPageSections(Gfx* gfx, Vtx* vertices, Texture // Draw the rows. for (u32 bg_row = 0; bg_row < RECOMP_PAGE_ROW_COUNT; bg_row++) { - u32 cur_row_height = MIN(RECOMP_PAGE_ROW_HEIGHT, PAGE_BG_HEIGHT - bg_row * RECOMP_PAGE_ROW_HEIGHT); + u32 cur_row_height = MIN(RECOMP_PAGE_ROW_HEIGHT, PAGE_BG_HEIGHT + 1 - bg_row * RECOMP_PAGE_ROW_HEIGHT); gDPLoadTextureTile(gfx++, *cur_image, G_IM_FMT_IA, G_IM_SIZ_8b, // fmt, siz PAGE_BG_WIDTH + 2, PAGE_BG_HEIGHT + 2, // width, height diff --git a/src/main/main.cpp b/src/main/main.cpp index 50edd04..99d940b 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -28,17 +28,12 @@ #include "ovl_patches.hpp" #include "librecomp/game.hpp" -#ifdef HAS_MM_SHADER_CACHE -#include "mm_shader_cache.h" -#endif - #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include #include "SDL_syswm.h" #endif -#define STB_IMAGE_IMPLEMENTATION #include "../../lib/rt64/src/contrib/stb/stb_image.h" template @@ -332,9 +327,6 @@ std::vector supported_games = { .rom_hash = 0xEF18B4A9E2386169ULL, .internal_name = "ZELDA MAJORA'S MASK", .game_id = u8"mm.n64.us.1.0", -#ifdef HAS_MM_SHADER_CACHE - .cache_data = {mm_shader_cache_bytes, sizeof(mm_shader_cache_bytes)}, -#endif .is_enabled = true, .entrypoint_address = get_entrypoint_address(), .entrypoint = recomp_entrypoint, From c21d55938b3ec6195908828ea0e448a39085066e Mon Sep 17 00:00:00 2001 From: Wiseguy <68165316+Mr-Wiseguy@users.noreply.github.com> Date: Fri, 26 Jul 2024 18:57:22 -0400 Subject: [PATCH 05/49] Update RT64 for odd-sized HD texture mipmap fix (#445) --- lib/rt64 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rt64 b/lib/rt64 index 0fd6d05..82375da 160000 --- a/lib/rt64 +++ b/lib/rt64 @@ -1 +1 @@ -Subproject commit 0fd6d05b8a0ec5daae313ad9e8504812ec31775d +Subproject commit 82375dabaaf08d9567db2de4b95f9deb6e75155c From 4c2cc2003adfa889805f6b317e0617d3d60681a5 Mon Sep 17 00:00:00 2001 From: Wiseguy <68165316+Mr-Wiseguy@users.noreply.github.com> Date: Fri, 26 Jul 2024 21:44:28 -0400 Subject: [PATCH 06/49] Opt out of constexpr mutex constructor on windows to prevent vcredist issues (#444) --- CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index b1b6e79..62bce6f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,11 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_SIMULATE_ID STREQUAL "M set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-everything /W4") endif() +# Opt out of constexpr mutex constructor on windows to prevent vcredist issues +if (WIN32) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR") +endif() + # Avoid warning about DOWNLOAD_EXTRACT_TIMESTAMP in CMake 3.24: if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0") cmake_policy(SET CMP0135 NEW) From 528a22d86f6479626bbfef42f100360c8d946499 Mon Sep 17 00:00:00 2001 From: Wiseguy <68165316+Mr-Wiseguy@users.noreply.github.com> Date: Sun, 28 Jul 2024 12:10:07 -0400 Subject: [PATCH 07/49] Update RT64 to fix compilation error from missing includes on some compilers (#448) --- lib/rt64 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rt64 b/lib/rt64 index 82375da..8747507 160000 --- a/lib/rt64 +++ b/lib/rt64 @@ -1 +1 @@ -Subproject commit 82375dabaaf08d9567db2de4b95f9deb6e75155c +Subproject commit 8747507cf96a4921efe83ea492dd0afbac1481f5 From 9981b922dcb210dd309951e3dd594a0b17c18438 Mon Sep 17 00:00:00 2001 From: Wiseguy <68165316+Mr-Wiseguy@users.noreply.github.com> Date: Sun, 28 Jul 2024 21:43:14 -0400 Subject: [PATCH 08/49] Fix .recomp_patch section functions not getting loaded (#449) --- lib/N64ModernRuntime | 2 +- src/main/register_patches.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/N64ModernRuntime b/lib/N64ModernRuntime index ce68e96..47feaaa 160000 --- a/lib/N64ModernRuntime +++ b/lib/N64ModernRuntime @@ -1 +1 @@ -Subproject commit ce68e96c171f7f036e29f539e22a604da04af824 +Subproject commit 47feaaaa0da5b5f80e90b9daca144a4141b641b8 diff --git a/src/main/register_patches.cpp b/src/main/register_patches.cpp index 71b9972..12c5725 100644 --- a/src/main/register_patches.cpp +++ b/src/main/register_patches.cpp @@ -6,5 +6,5 @@ #include "librecomp/game.hpp" void zelda64::register_patches() { - recomp::overlays::register_patches(mm_patches_bin, sizeof(mm_patches_bin), section_table); + recomp::overlays::register_patches(mm_patches_bin, sizeof(mm_patches_bin), section_table, ARRLEN(section_table)); } From c90434962f6a03103a5483808350b63f7d7d6411 Mon Sep 17 00:00:00 2001 From: Wiseguy <68165316+Mr-Wiseguy@users.noreply.github.com> Date: Sun, 28 Jul 2024 22:00:39 -0400 Subject: [PATCH 09/49] Preload executable into memory on Windows to prevent stutters (#450) --- src/main/main.cpp | 119 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/src/main/main.cpp b/src/main/main.cpp index 99d940b..e3dd529 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -416,8 +416,123 @@ namespace zelda64 { } } +#ifdef _WIN32 + +struct PreloadContext { + HANDLE handle; + HANDLE mapping_handle; + SIZE_T size; + PVOID view; +}; + +bool preload_executable(PreloadContext& context) { + wchar_t module_name[MAX_PATH]; + GetModuleFileNameW(NULL, module_name, MAX_PATH); + + context.handle = CreateFileW(module_name, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); + if (context.handle == INVALID_HANDLE_VALUE) { + fprintf(stderr, "Failed to load executable into memory!"); + context = {}; + return false; + } + + LARGE_INTEGER module_size; + if (!GetFileSizeEx(context.handle, &module_size)) { + fprintf(stderr, "Failed to get size of executable!"); + CloseHandle(context.handle); + context = {}; + return false; + } + + context.size = module_size.QuadPart; + + context.mapping_handle = CreateFileMappingW(context.handle, nullptr, PAGE_READONLY, 0, 0, nullptr); + if (context.mapping_handle == nullptr) { + recompui::message_box("Failed to create file mapping of executable!"); + CloseHandle(context.handle); + context = {}; + return EXIT_FAILURE; + } + + context.view = MapViewOfFile(context.mapping_handle, FILE_MAP_READ, 0, 0, 0); + if (context.view == nullptr) { + fprintf(stderr, "Failed to map view of of executable!"); + CloseHandle(context.mapping_handle); + CloseHandle(context.handle); + context = {}; + return false; + } + + DWORD pid = GetCurrentProcessId(); + HANDLE process_handle = OpenProcess(PROCESS_SET_QUOTA | PROCESS_QUERY_INFORMATION, FALSE, pid); + if (process_handle == nullptr) { + fprintf(stderr, "Failed to open own process!"); + CloseHandle(context.mapping_handle); + CloseHandle(context.handle); + context = {}; + return false; + } + + SIZE_T minimum_set_size, maximum_set_size; + if (!GetProcessWorkingSetSize(process_handle, &minimum_set_size, &maximum_set_size)) { + fprintf(stderr, "Failed to get working set size!"); + CloseHandle(context.mapping_handle); + CloseHandle(context.handle); + context = {}; + return false; + } + + if (!SetProcessWorkingSetSize(process_handle, minimum_set_size + context.size, maximum_set_size + context.size)) { + fprintf(stderr, "Failed to set working set size!"); + CloseHandle(context.mapping_handle); + CloseHandle(context.handle); + context = {}; + return false; + } + + if (VirtualLock(context.view, context.size) == 0) { + fprintf(stderr, "Failed to lock view of executable! (Error: %08lx)\n", GetLastError()); + CloseHandle(context.mapping_handle); + CloseHandle(context.handle); + context = {}; + return false; + } + + return true; +} + +void release_preload(PreloadContext& context) { + VirtualUnlock(context.view, context.size); + CloseHandle(context.mapping_handle); + CloseHandle(context.handle); + context = {}; +} + +#else + +struct PreloadContext { + +}; + +// TODO implement on other platforms +bool preload_executable(PreloadContext& context) { + return false; +} + +void release_preload(PreloadContext& context) { +} + +#endif int main(int argc, char** argv) { + // Map this executable into memory and lock it, which should keep it in physical memory. This ensures + // that there are no stutters from the OS having to load new pages of the executable whenever a new code page is run. + PreloadContext preload_context; + bool preloaded = preload_executable(preload_context); + + if (!preloaded) { + fprintf(stderr, "Failed to preload executable!\n"); + } #ifdef _WIN32 // Set up console output to accept UTF-8 on windows @@ -518,5 +633,9 @@ int main(int argc, char** argv) { NFD_Quit(); + if (preloaded) { + release_preload(preload_context); + } + return EXIT_SUCCESS; } From 334640077512b55bdb5dbb2d50ec9ca5403cf240 Mon Sep 17 00:00:00 2001 From: Mr-Wiseguy Date: Sun, 28 Jul 2024 22:04:14 -0400 Subject: [PATCH 10/49] Fix message box being used by accident in preload_executable --- src/main/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/main.cpp b/src/main/main.cpp index e3dd529..d350b6d 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -448,7 +448,7 @@ bool preload_executable(PreloadContext& context) { context.mapping_handle = CreateFileMappingW(context.handle, nullptr, PAGE_READONLY, 0, 0, nullptr); if (context.mapping_handle == nullptr) { - recompui::message_box("Failed to create file mapping of executable!"); + fprintf(stderr, "Failed to create file mapping of executable!"); CloseHandle(context.handle); context = {}; return EXIT_FAILURE; From 6598da434ea97d930482032ff4ab8732c79d6891 Mon Sep 17 00:00:00 2001 From: David Chavez Date: Thu, 1 Aug 2024 13:02:35 +0200 Subject: [PATCH 11/49] chore(ci): link and update build artifacts for PRs (#453) --- .github/workflows/update-pr-artifacts.yml | 57 +++++++++++++++++++ ...ate_external.yml => validate-external.yml} | 0 ...ate_internal.yml => validate-internal.yml} | 0 3 files changed, 57 insertions(+) create mode 100644 .github/workflows/update-pr-artifacts.yml rename .github/workflows/{validate_external.yml => validate-external.yml} (100%) rename .github/workflows/{validate_internal.yml => validate-internal.yml} (100%) diff --git a/.github/workflows/update-pr-artifacts.yml b/.github/workflows/update-pr-artifacts.yml new file mode 100644 index 0000000..2a51c36 --- /dev/null +++ b/.github/workflows/update-pr-artifacts.yml @@ -0,0 +1,57 @@ +name: update-pr-artifacts +on: + workflow_run: + workflows: [validate] + types: + - completed +jobs: + update-pr-artifacts: + runs-on: ubuntu-latest + if: github.event.workflow_run.event == 'pull_request' + name: Update PR Artifacts + steps: + - name: Get PR Number + id: pr-number + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + # Get list of PR's associated to the commit that triggered the workflow run + prs=$(gh api \ + -H "Accept: application/vnd.github+json" \ + /repos/${{ github.event.pull_request.head.repo.full_name }}/commits/${{ github.event.workflow_run.head_sha }}/pulls) + + # Find the PR against the current repo + pr_number=$(echo "$prs" | jq -r '.[] | select(.base.repo.full_name == "${{ github.repository }}") | .number' | head -n1) + + if [ -z "$pr_number" ]; then + echo "No pull request found for this workflow run" + exit 1 + else + echo "pr_number=$pr_number" >> $GITHUB_OUTPUT + echo "PR number: $pr_number" + fi + - name: Create Artifacts Content + id: artifacts-content + uses: actions/github-script@v7 + with: + result-encoding: string + script: | + const artifacts = await github.rest.actions.listWorkflowRunArtifacts({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: context.payload.workflow_run.id, + }); + + const nightlyLinks = artifacts.data.artifacts.reduce((acc, item) => { + acc += `- [${item.name}.zip](https://nightly.link/${context.repo.owner}/${context.repo.repo}/actions/artifacts/${item.id}.zip)\n`; + return acc; + }, '### Build Artifacts\n'); + + return nightlyLinks; + - name: Update PR Description + uses: garrettjoecox/pr-section@3.1.0 + with: + section-name: 'artifacts' + repo-token: '${{ secrets.GITHUB_TOKEN }}' + pr-number: ${{ steps.pr-number.outputs.pr_number }} + section-value: '${{ steps.artifacts-content.outputs.result }}' diff --git a/.github/workflows/validate_external.yml b/.github/workflows/validate-external.yml similarity index 100% rename from .github/workflows/validate_external.yml rename to .github/workflows/validate-external.yml diff --git a/.github/workflows/validate_internal.yml b/.github/workflows/validate-internal.yml similarity index 100% rename from .github/workflows/validate_internal.yml rename to .github/workflows/validate-internal.yml From 142b4d021b4404bc79ba4d44d41685d02c35f001 Mon Sep 17 00:00:00 2001 From: David Chavez Date: Thu, 1 Aug 2024 14:39:40 +0200 Subject: [PATCH 12/49] chore(ci): further tweaks to PR description updates (#454) --- .github/workflows/update-pr-artifacts.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/update-pr-artifacts.yml b/.github/workflows/update-pr-artifacts.yml index 2a51c36..204269c 100644 --- a/.github/workflows/update-pr-artifacts.yml +++ b/.github/workflows/update-pr-artifacts.yml @@ -1,13 +1,13 @@ name: update-pr-artifacts on: workflow_run: - workflows: [validate] + workflows: [validate-external, validate-internal] types: - completed jobs: update-pr-artifacts: runs-on: ubuntu-latest - if: github.event.workflow_run.event == 'pull_request' + if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' name: Update PR Artifacts steps: - name: Get PR Number From d782d3dcb9281cd4538dfec6a8fe9fd889b7d13a Mon Sep 17 00:00:00 2001 From: David Chavez Date: Thu, 1 Aug 2024 21:00:38 +0200 Subject: [PATCH 13/49] chore(ci): finalize PR build artifacts (#455) --- .github/workflows/update-pr-artifacts.yml | 49 +++++++++++++---------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/.github/workflows/update-pr-artifacts.yml b/.github/workflows/update-pr-artifacts.yml index 204269c..4a7c16d 100644 --- a/.github/workflows/update-pr-artifacts.yml +++ b/.github/workflows/update-pr-artifacts.yml @@ -7,32 +7,39 @@ on: jobs: update-pr-artifacts: runs-on: ubuntu-latest - if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' + if: (github.event.workflow_run.event == 'pull_request' || github.event.workflow_run.event == 'pull_request_target') && github.event.workflow_run.conclusion == 'success' name: Update PR Artifacts steps: - name: Get PR Number id: pr-number - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - # Get list of PR's associated to the commit that triggered the workflow run - prs=$(gh api \ - -H "Accept: application/vnd.github+json" \ - /repos/${{ github.event.pull_request.head.repo.full_name }}/commits/${{ github.event.workflow_run.head_sha }}/pulls) - - # Find the PR against the current repo - pr_number=$(echo "$prs" | jq -r '.[] | select(.base.repo.full_name == "${{ github.repository }}") | .number' | head -n1) - - if [ -z "$pr_number" ]; then - echo "No pull request found for this workflow run" - exit 1 - else - echo "pr_number=$pr_number" >> $GITHUB_OUTPUT - echo "PR number: $pr_number" - fi + uses: actions/github-script@v6 + with: + result-encoding: string + script: | + const { owner, repo } = context.repo; + + const findPRNumber = async () => { + const pulls = await github.rest.pulls.list({ owner, repo }); + for await (const { data } of github.paginate.iterator(pulls)) { + for (const pull of data) { + if (pull.head.sha === '${{ github.event.workflow_run.head_sha }}' && pull.user.id === ${{ github.event.sender.id }}) { + return pull.number; + } + } + } + + return null; + }; + + const prNumber = await findPRNumber(); + if (!prNumber) { + core.error(`No matching pull request found`); + } else { + return prNumber; + } - name: Create Artifacts Content id: artifacts-content - uses: actions/github-script@v7 + uses: actions/github-script@v6 with: result-encoding: string script: | @@ -53,5 +60,5 @@ jobs: with: section-name: 'artifacts' repo-token: '${{ secrets.GITHUB_TOKEN }}' - pr-number: ${{ steps.pr-number.outputs.pr_number }} + pr-number: ${{ steps.pr-number.outputs.result }} section-value: '${{ steps.artifacts-content.outputs.result }}' From 473b3d3d02ea8d17fb03e37f2383bc913e922700 Mon Sep 17 00:00:00 2001 From: Wiseguy <68165316+Mr-Wiseguy@users.noreply.github.com> Date: Fri, 9 Aug 2024 23:43:43 -0400 Subject: [PATCH 14/49] Add transform tagging for moths to fix their interpolation (#460) Co-authored-by: Tharo <17233964+Thar0@users.noreply.github.com> --- patches/specific_actor_transform_tagging.c | 72 ++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/patches/specific_actor_transform_tagging.c b/patches/specific_actor_transform_tagging.c index a444d4a..9169303 100644 --- a/patches/specific_actor_transform_tagging.c +++ b/patches/specific_actor_transform_tagging.c @@ -11,6 +11,7 @@ #include "overlays/actors/ovl_En_Goroiwa/z_en_goroiwa.h" #include "overlays/actors/ovl_En_Twig/z_en_twig.h" #include "overlays/actors/ovl_En_Honotrap/z_en_honotrap.h" +#include "overlays/actors/ovl_En_Tanron1/z_en_tanron1.h" // Decomp renames, TODO update decomp and remove these #define EnHonotrap_FlameGroup func_8092F878 @@ -1259,3 +1260,74 @@ RECOMP_PATCH void EnHonotrap_DrawFlameGroup(Actor* thisx, PlayState* play) { CLOSE_DISPS(play->state.gfxCtx); } + +extern Gfx ovl_En_Tanron1_DL_001428[]; +extern Gfx ovl_En_Tanron1_DL_001888[]; +extern Gfx ovl_En_Tanron1_DL_001900[]; + +// @recomp Patched to interpolate the moths that circle torches. +void func_80BB5AAC(EnTanron1* this, PlayState* play) { + EnTanron1Struct* ptrBase = &this->unk_160[0]; + s16 i; + u8 flag = 0; + EnTanron1Struct* ptr = ptrBase; + + // @recomp Get actor transform id + u32 cur_transform_id = actor_transform_id(&this->actor); + + OPEN_DISPS(play->state.gfxCtx); + + Gfx_SetupDL25_Opa(play->state.gfxCtx); + + for (i = 0; i < this->actor.params; i++, ptr++) { + if (ptr->unk_24 == 1) { + if (!flag) { + gSPDisplayList(POLY_OPA_DISP++, ovl_En_Tanron1_DL_001888); + flag++; + } + Matrix_Translate(ptr->unk_00.x, ptr->unk_00.y, ptr->unk_00.z, MTXMODE_NEW); + Matrix_RotateYS(ptr->unk_1A, MTXMODE_APPLY); + Matrix_RotateXS(ptr->unk_18 * -1, MTXMODE_APPLY); + Matrix_Scale(1.2f, ptr->unk_2C, 1.2f, MTXMODE_APPLY); + + // @recomp Write matrix group for POLY_OPA + gEXMatrixGroupDecomposedNormal(POLY_OPA_DISP++, cur_transform_id + i, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_ALLOW); + + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_OPA_DISP++, ovl_En_Tanron1_DL_001900); + + // @recomp Pop matrix group + gEXPopMatrixGroup(POLY_OPA_DISP++, G_MTX_MODELVIEW); + } + } + + flag = 0; + ptr = ptrBase; + for (i = 0; i < this->actor.params; i++, ptr++) { + if (ptr->unk_24 == 2) { + if (!flag) { + gSPDisplayList(POLY_OPA_DISP++, ovl_En_Tanron1_DL_001888); + gDPLoadTextureBlock(POLY_OPA_DISP++, ovl_En_Tanron1_DL_001428, G_IM_FMT_RGBA, G_IM_SIZ_16b, 16, 32, 0, + G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMIRROR | G_TX_CLAMP, 4, 5, G_TX_NOLOD, + G_TX_NOLOD); + flag++; + } + + Matrix_Translate(ptr->unk_00.x, ptr->unk_00.y, ptr->unk_00.z, MTXMODE_NEW); + Matrix_RotateYS(ptr->unk_1A, MTXMODE_APPLY); + Matrix_RotateXS(ptr->unk_18 * -1, MTXMODE_APPLY); + Matrix_Scale(1.0f, ptr->unk_2C, 1.0f, MTXMODE_APPLY); + + // @recomp Write matrix group for POLY_OPA + gEXMatrixGroupDecomposedNormal(POLY_OPA_DISP++, cur_transform_id + i, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_ALLOW); + + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_OPA_DISP++, ovl_En_Tanron1_DL_001900); + + // @recomp Pop matrix group + gEXPopMatrixGroup(POLY_OPA_DISP++, G_MTX_MODELVIEW); + } + } + + CLOSE_DISPS(play->state.gfxCtx); +} From 7697a972a3a45f2376804ba5215c02fa29f605e7 Mon Sep 17 00:00:00 2001 From: Wiseguy <68165316+Mr-Wiseguy@users.noreply.github.com> Date: Sat, 10 Aug 2024 19:31:37 -0400 Subject: [PATCH 15/49] Update RT64 for many things, most notably re-spirv (#463) --- lib/rt64 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rt64 b/lib/rt64 index 8747507..88c618c 160000 --- a/lib/rt64 +++ b/lib/rt64 @@ -1 +1 @@ -Subproject commit 8747507cf96a4921efe83ea492dd0afbac1481f5 +Subproject commit 88c618c1f8d8089f94e78537e49e0d77798fc0be From 83ecc68d188c0aec4d624a492c079f811647894a Mon Sep 17 00:00:00 2001 From: Wiseguy <68165316+Mr-Wiseguy@users.noreply.github.com> Date: Fri, 16 Aug 2024 09:50:01 -0400 Subject: [PATCH 16/49] Improve build times by using the recompiler to output multiple functions per file (#465) * Update RT64 for many things, most notably re-spirv * Improve build times by using the recompiler to output multiple functions per file --- .github/workflows/validate.yml | 2 +- lib/N64ModernRuntime | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 31b5089..99b0987 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -9,7 +9,7 @@ on: N64RECOMP_COMMIT: type: string required: false - default: 'ba4aede49c9a5302ecfc1fa599f7acc3925042f9' + default: '65f29f1a71c446d6de546ebcde0e1b3e768a271d' DXC_CHECKSUM: type: string required: false diff --git a/lib/N64ModernRuntime b/lib/N64ModernRuntime index 47feaaa..0a53855 160000 --- a/lib/N64ModernRuntime +++ b/lib/N64ModernRuntime @@ -1 +1 @@ -Subproject commit 47feaaaa0da5b5f80e90b9daca144a4141b641b8 +Subproject commit 0a538553330ea5fdb1673708704bb92a854241b9 From af1404b83d19decbc73364dac233a0ace758e0ca Mon Sep 17 00:00:00 2001 From: Wiseguy <68165316+Mr-Wiseguy@users.noreply.github.com> Date: Fri, 16 Aug 2024 10:15:20 -0400 Subject: [PATCH 17/49] Fix commit of N64Recomp used by workflow (#468) --- .github/workflows/validate.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 99b0987..0cecec2 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -9,7 +9,7 @@ on: N64RECOMP_COMMIT: type: string required: false - default: '65f29f1a71c446d6de546ebcde0e1b3e768a271d' + default: 'f8d439aeee6048b7365d1cb3bcd2578ec27a0288' DXC_CHECKSUM: type: string required: false From d99a84f04f6803a0df49383b6a05f4253a1b7c0a Mon Sep 17 00:00:00 2001 From: Mr-Wiseguy Date: Fri, 6 Sep 2024 16:46:43 -0400 Subject: [PATCH 18/49] Fix strict mode validation failure in latest N64Recomp version and update N64Recomp commit in github workflow --- .github/workflows/validate.yml | 8 ++++---- patches/specific_actor_transform_tagging.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 0cecec2..4440cc2 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -9,7 +9,7 @@ on: N64RECOMP_COMMIT: type: string required: false - default: 'f8d439aeee6048b7365d1cb3bcd2578ec27a0288' + default: '5b17bf8bb556d2544c6161487232a455eae8f188' DXC_CHECKSUM: type: string required: false @@ -64,7 +64,7 @@ jobs: # Build N64Recomp & RSPRecomp cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER=g++-11 -DCMAKE_C_COMPILER=gcc-11 -DCMAKE_MAKE_PROGRAM=ninja -G Ninja -S . -B cmake-build - cmake --build cmake-build --config Release --target N64Recomp -j $(nproc) + cmake --build cmake-build --config Release --target N64RecompCLI -j $(nproc) cmake --build cmake-build --config Release --target RSPRecomp -j $(nproc) # Copy N64Recomp & RSPRecomp to root directory @@ -160,7 +160,7 @@ jobs: # Build N64Recomp & RSPRecomp cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER=g++-11 -DCMAKE_C_COMPILER=gcc-11 -DCMAKE_MAKE_PROGRAM=ninja -G Ninja -S . -B cmake-build - cmake --build cmake-build --config Release --target N64Recomp -j $(nproc) + cmake --build cmake-build --config Release --target N64RecompCLI -j $(nproc) cmake --build cmake-build --config Release --target RSPRecomp -j $(nproc) # Copy N64Recomp & RSPRecomp to root directory @@ -234,7 +234,7 @@ jobs: $cpuCores = (Get-CimInstance -ClassName Win32_Processor).NumberOfLogicalProcessors cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_MAKE_PROGRAM=ninja -G Ninja -S . -B cmake-build - cmake --build cmake-build --config Release --target N64Recomp -j $cpuCores + cmake --build cmake-build --config Release --target N64RecompCLI -j $cpuCores cmake --build cmake-build --config Release --target RSPRecomp -j $cpuCores # Copy N64Recomp & RSPRecomp to root directory diff --git a/patches/specific_actor_transform_tagging.c b/patches/specific_actor_transform_tagging.c index 9169303..78d2463 100644 --- a/patches/specific_actor_transform_tagging.c +++ b/patches/specific_actor_transform_tagging.c @@ -1266,7 +1266,7 @@ extern Gfx ovl_En_Tanron1_DL_001888[]; extern Gfx ovl_En_Tanron1_DL_001900[]; // @recomp Patched to interpolate the moths that circle torches. -void func_80BB5AAC(EnTanron1* this, PlayState* play) { +RECOMP_PATCH void func_80BB5AAC(EnTanron1* this, PlayState* play) { EnTanron1Struct* ptrBase = &this->unk_160[0]; s16 i; u8 flag = 0; From 0d0f64e32f15c2ecc95c9e4945caa37ec19ce1ce Mon Sep 17 00:00:00 2001 From: lkoger <42499966+lkoger@users.noreply.github.com> Date: Sun, 6 Oct 2024 12:07:26 -0500 Subject: [PATCH 19/49] Fix ninja package name in Ubuntu build instructions (#482) --- BUILDING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BUILDING.md b/BUILDING.md index 4bf3423..4245b8b 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -20,7 +20,7 @@ For Linux the instructions for Ubuntu are provided, but you can find the equival ```bash # For Ubuntu, simply run: -sudo apt-get install cmake ninja libsdl2-dev libgtk-3-dev lld llvm clang-15 +sudo apt-get install cmake ninja-build libsdl2-dev libgtk-3-dev lld llvm clang ``` ### Windows From 670bd610673432beead61b1b8d41c78f316afde1 Mon Sep 17 00:00:00 2001 From: Mr-Wiseguy Date: Fri, 5 Jul 2024 21:24:43 -0400 Subject: [PATCH 20/49] Updated RT64 and enabled RT64 extended RDRAM mode --- patches/ui_patches.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/patches/ui_patches.c b/patches/ui_patches.c index a057655..0177611 100644 --- a/patches/ui_patches.c +++ b/patches/ui_patches.c @@ -56,9 +56,10 @@ RECOMP_PATCH void Graph_SetNextGfxPool(GraphicsContext* gfxCtx) { gSPEndDisplayList(&gGfxMasterDL->disps[4]); gSPBranchList(&gGfxMasterDL->debugDisp[0], bigger_pool->debugBuffer); - // @recomp Enable RT64 extended GBI mode and set the current framerate + // @recomp Enable RT64 extended GBI mode and extended rdram. OPEN_DISPS(gfxCtx); gEXEnable(POLY_OPA_DISP++); + gEXSetRDRAMExtended(POLY_OPA_DISP++, 1); CLOSE_DISPS(gfxCtx); } From cf1943fe6af3655eff0e9c80170c4a311dfb8b1e Mon Sep 17 00:00:00 2001 From: Mr-Wiseguy Date: Sun, 11 Aug 2024 12:51:26 -0400 Subject: [PATCH 21/49] Removed shader cache --- CMakeLists.txt | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 62bce6f..d4ef3ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -138,16 +138,6 @@ add_custom_target(DownloadGameControllerDB add_executable(Zelda64Recompiled) add_dependencies(Zelda64Recompiled DownloadGameControllerDB) -# Generate mm_shader_cache.c from the MM shader cache if it exists -if (EXISTS ${CMAKE_SOURCE_DIR}/shadercache/mm_shader_cache.bin) - set(HAS_MM_SHADER_CACHE TRUE) - target_compile_definitions(Zelda64Recompiled PRIVATE HAS_MM_SHADER_CACHE) - add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/mm_shader_cache.c ${CMAKE_CURRENT_BINARY_DIR}/mm_shader_cache.h - COMMAND file_to_c ${CMAKE_SOURCE_DIR}/shadercache/mm_shader_cache.bin mm_shader_cache_bytes ${CMAKE_CURRENT_BINARY_DIR}/mm_shader_cache.c ${CMAKE_CURRENT_BINARY_DIR}/mm_shader_cache.h - DEPENDS ${CMAKE_SOURCE_DIR}/shadercache/mm_shader_cache.bin - ) -endif() - set (SOURCES ${CMAKE_SOURCE_DIR}/src/main/main.cpp ${CMAKE_SOURCE_DIR}/src/main/register_overlays.cpp @@ -174,10 +164,6 @@ set (SOURCES ${CMAKE_SOURCE_DIR}/lib/RmlUi/Backends/RmlUi_Platform_SDL.cpp ) -if (HAS_MM_SHADER_CACHE) - list(APPEND SOURCES ${CMAKE_CURRENT_BINARY_DIR}/mm_shader_cache.c) -endif() - target_include_directories(Zelda64Recompiled PRIVATE ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/lib/concurrentqueue From ba39a73dca67898b2afb32f2ceb2c9d53b74e513 Mon Sep 17 00:00:00 2001 From: Mr-Wiseguy Date: Mon, 2 Sep 2024 12:01:22 -0400 Subject: [PATCH 22/49] Update modern runtime for mod support, add some exports and events in the patches --- lib/N64ModernRuntime | 2 +- patches.toml | 2 ++ patches/autosaving.c | 28 ++++++++++++++-------------- patches/patches.h | 5 +++++ patches/patches.ld | 5 +++-- patches/play_patches.c | 7 +++++++ patches/print.c | 2 +- src/main/main.cpp | 9 +++++++-- src/main/register_patches.cpp | 2 ++ src/ui/ui_renderer.cpp | 6 ++++++ us.rev1.toml | 1 + 11 files changed, 49 insertions(+), 20 deletions(-) diff --git a/lib/N64ModernRuntime b/lib/N64ModernRuntime index 0a53855..5699906 160000 --- a/lib/N64ModernRuntime +++ b/lib/N64ModernRuntime @@ -1 +1 @@ -Subproject commit 0a538553330ea5fdb1673708704bb92a854241b9 +Subproject commit 5699906f34fcc82905303092d081ad92aa74f926 diff --git a/patches.toml b/patches.toml index 6d928be..2206f23 100644 --- a/patches.toml +++ b/patches.toml @@ -14,3 +14,5 @@ data_reference_syms_files = [ "Zelda64RecompSyms/mm.us.rev1.datasyms.toml", "Zel output_binary_path = "patches/patches.bin" # Do not emit warnings for unpaired LO16 values, as clang produces many of them. unpaired_lo16_warnings = false +# Allow exporting functions and events for mods to use. +allow_exports = true diff --git a/patches/autosaving.c b/patches/autosaving.c index 46f1e8a..809c98d 100644 --- a/patches/autosaving.c +++ b/patches/autosaving.c @@ -67,10 +67,10 @@ RECOMP_PATCH void KaleidoSetup_Update(PlayState* play) { void Sram_SyncWriteToFlash(SramContext* sramCtx, s32 curPage, s32 numPages); -void autosave_reset_timer(); -void autosave_reset_timer_slow(); +void recomp_reset_autosave_timer(); +void recomp_reset_autosave_timer_slow(); -void do_autosave(PlayState* play) { +RECOMP_EXPORT void recomp_do_autosave(PlayState* play) { // Transfer the scene flags into the cycle flags. Play_SaveCycleSceneFlags(&play->state); // Transfer the cycle flags into the save buffer. Logic copied from func_8014546C. @@ -176,7 +176,7 @@ RECOMP_PATCH void func_8014546C(SramContext* sramCtx) { // @recomp Delete the owl save. delete_owl_save(sramCtx, gSaveContext.fileNum); // @recomp Reset the autosave timer. - autosave_reset_timer(); + recomp_reset_autosave_timer(); for (i = 0; i < ARRAY_COUNT(gSaveContext.cycleSceneFlags); i++) { gSaveContext.save.saveInfo.permanentSceneFlags[i].chest = gSaveContext.cycleSceneFlags[i].chest; gSaveContext.save.saveInfo.permanentSceneFlags[i].switch0 = gSaveContext.cycleSceneFlags[i].switch0; @@ -344,11 +344,11 @@ void draw_autosave_icon(PlayState* play) { CLOSE_DISPS(play->state.gfxCtx); } -void show_autosave_icon() { +RECOMP_EXPORT void recomp_show_autosave_icon() { autosave_icon_counter = AUTOSAVE_ICON_TOTAL_FRAMES; } -u32 recomp_autosave_interval() { +RECOMP_EXPORT u32 recomp_autosave_interval() { return 2 * 60 * 1000; } @@ -367,12 +367,12 @@ bool reached_final_three_hours() { return false; } -void autosave_reset_timer() { +RECOMP_EXPORT void recomp_reset_autosave_timer() { last_autosave_time = osGetTime(); extra_autosave_delay_milliseconds = 0; } -void autosave_reset_timer_slow() { +RECOMP_EXPORT void recomp_reset_autosave_timer_slow() { // Set the most recent autosave time in the future to give extra time before an autosave triggers. last_autosave_time = osGetTime(); extra_autosave_delay_milliseconds = 2 * 60 * 1000; @@ -425,20 +425,20 @@ void autosave_post_play_update(PlayState* play) { frames_since_autosave_ready >= MIN_FRAMES_SINCE_READY && time_now - last_autosave_time > (OS_USEC_TO_CYCLES(1000 * (recomp_autosave_interval() + extra_autosave_delay_milliseconds))) ) { - do_autosave(play); - show_autosave_icon(); - autosave_reset_timer(); + recomp_do_autosave(play); + recomp_show_autosave_icon(); + recomp_reset_autosave_timer(); } } else { // Update the last autosave time to the current time to prevent autosaving immediately if autosaves are turned back on. - autosave_reset_timer(); + recomp_reset_autosave_timer(); } gCanPause = false; } void autosave_init() { - autosave_reset_timer_slow(); + recomp_reset_autosave_timer_slow(); Lib_MemCpy(&prev_save_ctx, &gSaveContext, offsetof(SaveContext, fileNum)); } @@ -705,7 +705,7 @@ RECOMP_PATCH void Sram_ResetSaveFromMoonCrash(SramContext* sramCtx) { gSaveContext.jinxTimer = 0; // @recomp Use the slow autosave timer to give the player extra time to respond to the moon crashing to decide if they want to reload their autosave. - autosave_reset_timer_slow(); + recomp_reset_autosave_timer_slow(); } diff --git a/patches/patches.h b/patches/patches.h index f0f2b5e..a93a6fd 100644 --- a/patches/patches.h +++ b/patches/patches.h @@ -4,6 +4,11 @@ #define RECOMP_EXPORT __attribute__((section(".recomp_export"))) #define RECOMP_PATCH __attribute__((section(".recomp_patch"))) #define RECOMP_FORCE_PATCH __attribute__((section(".recomp_force_patch"))) +#define RECOMP_DECLARE_EVENT(func) \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wunused-parameter\"") \ + __attribute__((noinline, weak, used, section(".recomp_event"))) void func {} \ + _Pragma("GCC diagnostic pop") // TODO fix renaming symbols in patch recompilation #define osCreateMesgQueue osCreateMesgQueue_recomp diff --git a/patches/patches.ld b/patches/patches.ld index b0a3b7f..fad9148 100644 --- a/patches/patches.ld +++ b/patches/patches.ld @@ -1,5 +1,5 @@ RAMBASE = 0x80801000; /* Used to hold any new symbols */ -EXTRA_RAM_SIZE = 0x01000000; /* Amount of extra ram allocated by recomp */ +PATCH_RAM_END = 0x81000000; /* Amount of extra ram allocated by recomp */ MEMORY { extram : ORIGIN = RAMBASE, LENGTH = 64M @@ -12,10 +12,11 @@ SECTIONS { .text : { *(.text*) } >extram AT >rom .recomp_patch : { *(.recomp_patch*) *(.recomp_force_patch*) } >extram AT >rom .recomp_export : { *(.recomp_export*) } >extram AT >rom + .recomp_event : { *(.recomp_event*) } >extram AT >rom .rodata : { *(.rodata*) } >extram AT >rom .data : { *(.data*) } >extram AT >rom .bss (NOLOAD) : { *(.bss*) *(COMMON) } >extram - ASSERT(. < RAMBASE + EXTRA_RAM_SIZE, "Maxed out recomp extra ram") + ASSERT(. <= PATCH_RAM_END, "Maxed out recomp extra ram") .reloc 0 : { *(.reloc*) } .symtab 0 : { *(.symtab) } diff --git a/patches/play_patches.c b/patches/play_patches.c index e3d7c84..eedda5d 100644 --- a/patches/play_patches.c +++ b/patches/play_patches.c @@ -4,6 +4,10 @@ extern Input D_801F6C18; +RECOMP_DECLARE_EVENT(recomp_on_play_main(PlayState* play)); +RECOMP_DECLARE_EVENT(recomp_before_play_update(PlayState* play)); +RECOMP_DECLARE_EVENT(recomp_after_play_update(PlayState* play)); + void controls_play_update(PlayState* play) { gSaveContext.options.zTargetSetting = recomp_get_targeting_mode(); } @@ -12,6 +16,7 @@ void controls_play_update(PlayState* play) { RECOMP_PATCH void Play_Main(GameState* thisx) { static Input* prevInput = NULL; PlayState* this = (PlayState*)thisx; + recomp_on_play_main(this); // @recomp debug_play_update(this); @@ -32,7 +37,9 @@ RECOMP_PATCH void Play_Main(GameState* thisx) { this->state.gfxCtx = NULL; } camera_pre_play_update(this); + recomp_before_play_update(this); Play_Update(this); + recomp_after_play_update(this); camera_post_play_update(this); analog_cam_post_play_update(this); autosave_post_play_update(this); diff --git a/patches/print.c b/patches/print.c index 0fec414..d5216b3 100644 --- a/patches/print.c +++ b/patches/print.c @@ -6,7 +6,7 @@ void* proutPrintf(void* dst, const char* fmt, size_t size) { return (void*)1; } -int recomp_printf(const char* fmt, ...) { +RECOMP_EXPORT int recomp_printf(const char* fmt, ...) { va_list args; va_start(args, fmt); diff --git a/src/main/main.cpp b/src/main/main.cpp index d350b6d..0fbf6f6 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -27,6 +27,7 @@ #include "zelda_render.h" #include "ovl_patches.hpp" #include "librecomp/game.hpp" +#include "librecomp/mods.hpp" #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN @@ -327,6 +328,7 @@ std::vector supported_games = { .rom_hash = 0xEF18B4A9E2386169ULL, .internal_name = "ZELDA MAJORA'S MASK", .game_id = u8"mm.n64.us.1.0", + .mod_game_id = "mm", .is_enabled = true, .entrypoint_address = get_entrypoint_address(), .entrypoint = recomp_entrypoint, @@ -568,6 +570,8 @@ int main(int argc, char** argv) { fprintf(stderr, "Failed to load controller mappings: %s\n", SDL_GetError()); } + recomp::register_config_path(zelda64::get_app_folder_path()); + // Register supported games and patches for (const auto& game : supported_games) { recomp::register_game(game); @@ -575,8 +579,6 @@ int main(int argc, char** argv) { zelda64::register_overlays(); zelda64::register_patches(); - - recomp::register_config_path(zelda64::get_app_folder_path()); zelda64::load_config(); recomp::rsp::callbacks_t rsp_callbacks{ @@ -619,7 +621,10 @@ int main(int argc, char** argv) { .get_game_thread_name = zelda64::get_game_thread_name, }; + recomp::mods::scan_mods(); + recomp::start( + 64 * 1024 * 1024, // 64MB to have plenty of room for loading mods {}, rsp_callbacks, renderer_callbacks, diff --git a/src/main/register_patches.cpp b/src/main/register_patches.cpp index 12c5725..8725f81 100644 --- a/src/main/register_patches.cpp +++ b/src/main/register_patches.cpp @@ -7,4 +7,6 @@ void zelda64::register_patches() { recomp::overlays::register_patches(mm_patches_bin, sizeof(mm_patches_bin), section_table, ARRLEN(section_table)); + recomp::overlays::register_base_exports(export_table); + recomp::overlays::register_base_events(event_name_table); } diff --git a/src/ui/ui_renderer.cpp b/src/ui/ui_renderer.cpp index 8fb93d4..a234d7c 100644 --- a/src/ui/ui_renderer.cpp +++ b/src/ui/ui_renderer.cpp @@ -1287,6 +1287,12 @@ void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderFramebuffer* s static recompui::Menu prev_menu = recompui::Menu::None; recompui::Menu cur_menu = open_menu.load(); + // Return to the launcher if no menu is open and the game isn't started. + if (cur_menu == recompui::Menu::None && !ultramodern::is_game_started()) { + cur_menu = recompui::Menu::Launcher; + recompui::set_current_menu(cur_menu); + } + if (reload_sheets) { ui_context->rml.load_documents(); prev_menu = recompui::Menu::None; diff --git a/us.rev1.toml b/us.rev1.toml index 7e776f4..7257691 100644 --- a/us.rev1.toml +++ b/us.rev1.toml @@ -5,6 +5,7 @@ entrypoint = 0x80080000 # Paths are relative to the location of this config file. output_func_path = "RecompiledFuncs" relocatable_sections_path = "overlays.us.rev1.txt" +# elf_path = "mm.us.rev1.rom_uncompressed.elf" symbols_file_path = "Zelda64RecompSyms/mm.us.rev1.syms.toml" rom_file_path = "mm.us.rev1.rom_uncompressed.z64" From 2c23d5f29b78c6ed3713dceef87ceb71f4f3bcf5 Mon Sep 17 00:00:00 2001 From: Mr-Wiseguy Date: Mon, 2 Sep 2024 12:04:14 -0400 Subject: [PATCH 23/49] Update N64Recomp commit for CI --- .github/workflows/validate.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 4440cc2..442d031 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -9,7 +9,7 @@ on: N64RECOMP_COMMIT: type: string required: false - default: '5b17bf8bb556d2544c6161487232a455eae8f188' + default: 'd33d38161798167929b114c2b0fd445f9670e10a' DXC_CHECKSUM: type: string required: false From be70a2a8f175e185c22403938c5e4ceb02e98916 Mon Sep 17 00:00:00 2001 From: Mr-Wiseguy Date: Mon, 2 Sep 2024 20:00:47 -0400 Subject: [PATCH 24/49] Parse version number from a string and provide it to the runtime --- assets/launcher.rml | 2 +- lib/N64ModernRuntime | 2 +- src/main/main.cpp | 9 +++++++++ src/ui/ui_launcher.cpp | 6 ++++-- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/assets/launcher.rml b/assets/launcher.rml index d4a77d1..6496117 100644 --- a/assets/launcher.rml +++ b/assets/launcher.rml @@ -58,7 +58,7 @@
- +
diff --git a/lib/N64ModernRuntime b/lib/N64ModernRuntime index 5699906..09f5759 160000 --- a/lib/N64ModernRuntime +++ b/lib/N64ModernRuntime @@ -1 +1 @@ -Subproject commit 5699906f34fcc82905303092d081ad92aa74f926 +Subproject commit 09f5759d3a68437d407d54922e3fddf0c52f4dad diff --git a/src/main/main.cpp b/src/main/main.cpp index 0fbf6f6..cc34fa8 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -37,6 +37,8 @@ #include "../../lib/rt64/src/contrib/stb/stb_image.h" +const std::string version_string = "1.2.0-dev"; + template void exit_error(const char* str, Ts ...args) { // TODO pop up an error @@ -527,6 +529,12 @@ void release_preload(PreloadContext& context) { #endif int main(int argc, char** argv) { + recomp::Version project_version{}; + if (!recomp::Version::from_string(version_string, project_version)) { + ultramodern::error_handling::message_box(("Invalid version string: " + version_string).c_str()); + return EXIT_FAILURE; + } + // Map this executable into memory and lock it, which should keep it in physical memory. This ensures // that there are no stutters from the OS having to load new pages of the executable whenever a new code page is run. PreloadContext preload_context; @@ -625,6 +633,7 @@ int main(int argc, char** argv) { recomp::start( 64 * 1024 * 1024, // 64MB to have plenty of room for loading mods + project_version, {}, rsp_callbacks, renderer_callbacks, diff --git a/src/ui/ui_launcher.cpp b/src/ui/ui_launcher.cpp index b4b6312..f699eb7 100644 --- a/src/ui/ui_launcher.cpp +++ b/src/ui/ui_launcher.cpp @@ -6,7 +6,7 @@ #include "nfd.h" #include -std::string version_number = "v1.1.1"; +static std::string version_string; Rml::DataModelHandle model_handle; bool mm_rom_valid = false; @@ -103,7 +103,9 @@ public: Rml::DataModelConstructor constructor = context->CreateDataModel("launcher_model"); constructor.Bind("mm_rom_valid", &mm_rom_valid); - constructor.Bind("version_number", &version_number); + + version_string = recomp::get_project_version().to_string(); + constructor.Bind("version_number", &version_string); model_handle = constructor.GetModelHandle(); } From e6892248c73849024c75782baf457698b5927629 Mon Sep 17 00:00:00 2001 From: Mr-Wiseguy Date: Mon, 2 Sep 2024 23:46:38 -0400 Subject: [PATCH 25/49] Update runtime for new mod manifest schema --- lib/N64ModernRuntime | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/N64ModernRuntime b/lib/N64ModernRuntime index 09f5759..3718758 160000 --- a/lib/N64ModernRuntime +++ b/lib/N64ModernRuntime @@ -1 +1 @@ -Subproject commit 09f5759d3a68437d407d54922e3fddf0c52f4dad +Subproject commit 3718758cd529c779018a880ab645cec9d9888803 From ea0cc6e6be76e40d189e9e39ec077dae8efdf9f4 Mon Sep 17 00:00:00 2001 From: Mr-Wiseguy Date: Tue, 3 Sep 2024 00:04:17 -0400 Subject: [PATCH 26/49] Update runtime to have mod list functionality --- lib/N64ModernRuntime | 2 +- src/main/main.cpp | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/N64ModernRuntime b/lib/N64ModernRuntime index 3718758..986881e 160000 --- a/lib/N64ModernRuntime +++ b/lib/N64ModernRuntime @@ -1 +1 @@ -Subproject commit 3718758cd529c779018a880ab645cec9d9888803 +Subproject commit 986881e4e1b19d39ad0efd5a301be7ed439434b1 diff --git a/src/main/main.cpp b/src/main/main.cpp index cc34fa8..579071a 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -631,6 +631,12 @@ int main(int argc, char** argv) { recomp::mods::scan_mods(); + printf("Found mods:\n"); + for (const auto& mod : recomp::mods::get_mod_details("mm")) { + printf(" %s(%s)\n", mod.mod_id.c_str(), mod.version.to_string().c_str()); + } + printf("\n"); + recomp::start( 64 * 1024 * 1024, // 64MB to have plenty of room for loading mods project_version, From 60b8d58e734a47d2bcf94b792aef78881e7493c4 Mon Sep 17 00:00:00 2001 From: Mr-Wiseguy Date: Wed, 4 Sep 2024 02:29:01 -0400 Subject: [PATCH 27/49] Update runtime and print mod authors and dependencies --- lib/N64ModernRuntime | 2 +- src/main/main.cpp | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/N64ModernRuntime b/lib/N64ModernRuntime index 986881e..b9592c6 160000 --- a/lib/N64ModernRuntime +++ b/lib/N64ModernRuntime @@ -1 +1 @@ -Subproject commit 986881e4e1b19d39ad0efd5a301be7ed439434b1 +Subproject commit b9592c625d87ab45ddd12d9ad30c886ee77a5d68 diff --git a/src/main/main.cpp b/src/main/main.cpp index 579071a..910f545 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -634,6 +634,22 @@ int main(int argc, char** argv) { printf("Found mods:\n"); for (const auto& mod : recomp::mods::get_mod_details("mm")) { printf(" %s(%s)\n", mod.mod_id.c_str(), mod.version.to_string().c_str()); + if (!mod.authors.empty()) { + printf(" Authors: %s", mod.authors[0].c_str()); + for (size_t author_index = 1; author_index < mod.authors.size(); author_index++) { + const std::string& author = mod.authors[author_index]; + printf(", %s", author.c_str()); + } + printf("\n"); + } + if (!mod.dependencies.empty()) { + printf(" Dependencies: %s:%s", mod.dependencies[0].mod_id.c_str(), mod.dependencies[0].version.to_string().c_str()); + for (size_t dep_index = 1; dep_index < mod.dependencies.size(); dep_index++) { + const recomp::mods::Dependency& dep = mod.dependencies[dep_index]; + printf(", %s:%s", dep.mod_id.c_str(), dep.version.to_string().c_str()); + } + printf("\n"); + } } printf("\n"); From 359f8a9279a7b429e1314d1e6be872277cc1f431 Mon Sep 17 00:00:00 2001 From: Mr-Wiseguy Date: Sun, 8 Sep 2024 22:45:37 -0400 Subject: [PATCH 28/49] Update runtime for mod loading on posix systems, enable all mods temporarily --- include/recomp_input.h | 5 +++-- lib/N64ModernRuntime | 2 +- src/main/main.cpp | 2 ++ src/main/register_patches.cpp | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/include/recomp_input.h b/include/recomp_input.h index db9b160..8599628 100644 --- a/include/recomp_input.h +++ b/include/recomp_input.h @@ -120,7 +120,8 @@ namespace recomp { std::vector apply_menu; }; - constexpr const std::vector& get_default_mapping_for_input(const DefaultN64Mappings& defaults, const GameInput input) { + inline const std::vector& get_default_mapping_for_input(const DefaultN64Mappings& defaults, const GameInput input) { + static const std::vector empty_input_field{}; switch (input) { case GameInput::A: return defaults.a; case GameInput::B: return defaults.b; @@ -143,7 +144,7 @@ namespace recomp { case GameInput::TOGGLE_MENU: return defaults.toggle_menu; case GameInput::ACCEPT_MENU: return defaults.accept_menu; case GameInput::APPLY_MENU: return defaults.apply_menu; - default: return std::vector(); + default: return empty_input_field; } } diff --git a/lib/N64ModernRuntime b/lib/N64ModernRuntime index b9592c6..a7e5a77 160000 --- a/lib/N64ModernRuntime +++ b/lib/N64ModernRuntime @@ -1 +1 @@ -Subproject commit b9592c625d87ab45ddd12d9ad30c886ee77a5d68 +Subproject commit a7e5a7770f2344aa504725af6465e2db4565292c diff --git a/src/main/main.cpp b/src/main/main.cpp index 910f545..6007ffa 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -650,6 +650,8 @@ int main(int argc, char** argv) { } printf("\n"); } + // TODO load all mods as a temporary solution to not having a UI yet. + recomp::mods::enable_mod(mod.mod_id, true); } printf("\n"); diff --git a/src/main/register_patches.cpp b/src/main/register_patches.cpp index 8725f81..ef800fd 100644 --- a/src/main/register_patches.cpp +++ b/src/main/register_patches.cpp @@ -8,5 +8,5 @@ void zelda64::register_patches() { recomp::overlays::register_patches(mm_patches_bin, sizeof(mm_patches_bin), section_table, ARRLEN(section_table)); recomp::overlays::register_base_exports(export_table); - recomp::overlays::register_base_events(event_name_table); + recomp::overlays::register_base_events(event_names); } From 2463fe4613a855d899d672fb992e33327cf5efc1 Mon Sep 17 00:00:00 2001 From: Mr-Wiseguy Date: Mon, 9 Sep 2024 02:02:47 -0400 Subject: [PATCH 29/49] Update N64ModernRuntime for mod mips32 relocs and function lookups --- lib/N64ModernRuntime | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/N64ModernRuntime b/lib/N64ModernRuntime index a7e5a77..26a0543 160000 --- a/lib/N64ModernRuntime +++ b/lib/N64ModernRuntime @@ -1 +1 @@ -Subproject commit a7e5a7770f2344aa504725af6465e2db4565292c +Subproject commit 26a05439c2215ea9e1c0b0d572b46b3584a90a4f From 765d1d32f0acd9b920ca99b210df2c38f6460416 Mon Sep 17 00:00:00 2001 From: Mr-Wiseguy Date: Mon, 9 Sep 2024 23:23:57 -0400 Subject: [PATCH 30/49] Update runtime after merge --- lib/N64ModernRuntime | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/N64ModernRuntime b/lib/N64ModernRuntime index 26a0543..45e9f7a 160000 --- a/lib/N64ModernRuntime +++ b/lib/N64ModernRuntime @@ -1 +1 @@ -Subproject commit 26a05439c2215ea9e1c0b0d572b46b3584a90a4f +Subproject commit 45e9f7a6cb46b743cb4ada142be3b398445a8b20 From eda1979bf0883f9da148f39df4999c330c2e0dfc Mon Sep 17 00:00:00 2001 From: Mr-Wiseguy Date: Thu, 12 Sep 2024 00:10:29 -0400 Subject: [PATCH 31/49] Update runtime to fix reference symbols --- lib/N64ModernRuntime | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/N64ModernRuntime b/lib/N64ModernRuntime index 45e9f7a..81ce18d 160000 --- a/lib/N64ModernRuntime +++ b/lib/N64ModernRuntime @@ -1 +1 @@ -Subproject commit 45e9f7a6cb46b743cb4ada142be3b398445a8b20 +Subproject commit 81ce18d0d3448308d29ca1cc1a835344571126c9 From 33806821e287d898f2e48423b990728c139fac6d Mon Sep 17 00:00:00 2001 From: Mr-Wiseguy Date: Thu, 12 Sep 2024 00:55:35 -0400 Subject: [PATCH 32/49] Update runtime for populating missing runtime pointers in offline compiled mods --- lib/N64ModernRuntime | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/N64ModernRuntime b/lib/N64ModernRuntime index 81ce18d..c4ee705 160000 --- a/lib/N64ModernRuntime +++ b/lib/N64ModernRuntime @@ -1 +1 @@ -Subproject commit 81ce18d0d3448308d29ca1cc1a835344571126c9 +Subproject commit c4ee705250e53af3d84678bcccafeb50e4655e06 From a568261064f1490440f2c40372f70da4c71ab4b8 Mon Sep 17 00:00:00 2001 From: Mr-Wiseguy Date: Thu, 12 Sep 2024 19:24:04 -0400 Subject: [PATCH 33/49] Update runtime after merge --- lib/N64ModernRuntime | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/N64ModernRuntime b/lib/N64ModernRuntime index c4ee705..356b9f9 160000 --- a/lib/N64ModernRuntime +++ b/lib/N64ModernRuntime @@ -1 +1 @@ -Subproject commit c4ee705250e53af3d84678bcccafeb50e4655e06 +Subproject commit 356b9f901e65dcde3b7368116f5a7e84087b07ef From 5dc260f35aef040253bd20f9d1cdece2630e5c34 Mon Sep 17 00:00:00 2001 From: Mr-Wiseguy Date: Fri, 27 Sep 2024 00:57:49 -0400 Subject: [PATCH 34/49] Update runtime to add DLL search path, enable strict mode in patch recompilation --- lib/N64ModernRuntime | 2 +- patches.toml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/N64ModernRuntime b/lib/N64ModernRuntime index 356b9f9..46797d6 160000 --- a/lib/N64ModernRuntime +++ b/lib/N64ModernRuntime @@ -1 +1 @@ -Subproject commit 356b9f901e65dcde3b7368116f5a7e84087b07ef +Subproject commit 46797d6cadca6ff78377e7065d073a176d988025 diff --git a/patches.toml b/patches.toml index 2206f23..38910ee 100644 --- a/patches.toml +++ b/patches.toml @@ -16,3 +16,5 @@ output_binary_path = "patches/patches.bin" unpaired_lo16_warnings = false # Allow exporting functions and events for mods to use. allow_exports = true +# # Enable strict patch mode, validates that patched symbols exist and that non-patch functions aren't symbols. +strict_patch_mode = true From 5a8a1cb2ba6936a10a3d4a78df1e8e6f0919740a Mon Sep 17 00:00:00 2001 From: Mr-Wiseguy Date: Sat, 28 Sep 2024 16:50:58 -0400 Subject: [PATCH 35/49] Update runtime for custom mod content types and add RT64 texture pack support --- include/zelda_render.h | 8 +++++ lib/N64ModernRuntime | 2 +- src/game/config.cpp | 1 - src/main/main.cpp | 23 ++++++++++++++ src/main/rt64_render_context.cpp | 54 ++++++++++++++++++++++++++++++++ 5 files changed, 86 insertions(+), 2 deletions(-) diff --git a/include/zelda_render.h b/include/zelda_render.h index 684672b..2d909e4 100644 --- a/include/zelda_render.h +++ b/include/zelda_render.h @@ -1,8 +1,12 @@ #ifndef __ZELDA_RENDER_H__ #define __ZELDA_RENDER_H__ +#include +#include + #include "common/rt64_user_configuration.h" #include "ultramodern/renderer_context.hpp" +#include "librecomp/mods.hpp" namespace RT64 { struct Application; @@ -29,6 +33,7 @@ namespace zelda64 { protected: std::unique_ptr app; + std::unordered_set enabled_texture_packs; }; std::unique_ptr create_render_context(uint8_t *rdram, ultramodern::renderer::WindowHandle window_handle, bool developer_mode); @@ -36,6 +41,9 @@ namespace zelda64 { RT64::UserConfiguration::Antialiasing RT64MaxMSAA(); bool RT64SamplePositionsSupported(); bool RT64HighPrecisionFBEnabled(); + + void enable_texture_pack(const recomp::mods::ModHandle& mod); + void disable_texture_pack(const recomp::mods::ModHandle& mod); } } diff --git a/lib/N64ModernRuntime b/lib/N64ModernRuntime index 46797d6..a4f5ee1 160000 --- a/lib/N64ModernRuntime +++ b/lib/N64ModernRuntime @@ -1 +1 @@ -Subproject commit 46797d6cadca6ff78377e7065d073a176d988025 +Subproject commit a4f5ee10c8303474d9028468e84845b192e9297d diff --git a/src/game/config.cpp b/src/game/config.cpp index ac8ebff..ab24e0a 100644 --- a/src/game/config.cpp +++ b/src/game/config.cpp @@ -19,7 +19,6 @@ constexpr std::u8string_view general_filename = u8"general.json"; constexpr std::u8string_view graphics_filename = u8"graphics.json"; constexpr std::u8string_view controls_filename = u8"controls.json"; constexpr std::u8string_view sound_filename = u8"sound.json"; -constexpr std::u8string_view program_id = u8"Zelda64Recompiled"; constexpr auto res_default = ultramodern::renderer::Resolution::Auto; constexpr auto hr_default = ultramodern::renderer::HUDRatioMode::Clamp16x9; diff --git a/src/main/main.cpp b/src/main/main.cpp index 6007ffa..cbeb63a 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -528,6 +528,16 @@ void release_preload(PreloadContext& context) { #endif +void enable_texture_pack(recomp::mods::ModContext& context, const recomp::mods::ModHandle& mod) { + (void)context; + zelda64::renderer::enable_texture_pack(mod); +} + +void disable_texture_pack(recomp::mods::ModContext& context, const recomp::mods::ModHandle& mod) { + (void)context; + zelda64::renderer::disable_texture_pack(mod); +} + int main(int argc, char** argv) { recomp::Version project_version{}; if (!recomp::Version::from_string(version_string, project_version)) { @@ -629,6 +639,18 @@ int main(int argc, char** argv) { .get_game_thread_name = zelda64::get_game_thread_name, }; + // Register the texture pack content type with rt64.json as its content file. + recomp::mods::ModContentType texture_pack_content_type{ + .content_filename = "rt64.json", + .allow_runtime_toggle = true, + .on_enabled = enable_texture_pack, + .on_disabled = disable_texture_pack, + }; + auto texture_pack_content_type_id = recomp::mods::register_mod_content_type(texture_pack_content_type); + + // Register the .rtz texture pack file format with the previous content type as its only allowed content type. + recomp::mods::register_mod_container_type("rtz", std::vector{ texture_pack_content_type_id }, false); + recomp::mods::scan_mods(); printf("Found mods:\n"); @@ -641,6 +663,7 @@ int main(int argc, char** argv) { printf(", %s", author.c_str()); } printf("\n"); + printf(" Runtime toggleable: %d\n", mod.runtime_toggleable); } if (!mod.dependencies.empty()) { printf(" Dependencies: %s:%s", mod.dependencies[0].mod_id.c_str(), mod.dependencies[0].version.to_string().c_str()); diff --git a/src/main/rt64_render_context.cpp b/src/main/rt64_render_context.cpp index 497e504..8d5c735 100644 --- a/src/main/rt64_render_context.cpp +++ b/src/main/rt64_render_context.cpp @@ -1,5 +1,6 @@ #include #include +#include #define HLSL_CPU #include "hle/rt64_application.h" @@ -10,6 +11,13 @@ #include "zelda_render.h" #include "recomp_ui.h" +#include "concurrentqueue.h" + +// Helper class for variant visiting. +template +struct overloaded : Ts... { using Ts::operator()...; }; +template +overloaded(Ts...) -> overloaded; static RT64::UserConfiguration::Antialiasing device_max_msaa = RT64::UserConfiguration::Antialiasing::None; static bool sample_positions_supported = false; @@ -18,6 +26,18 @@ static bool high_precision_fb_enabled = false; static uint8_t DMEM[0x1000]; static uint8_t IMEM[0x1000]; +struct TexturePackEnableAction { + std::filesystem::path path; +}; + +struct TexturePackDisableAction { + std::filesystem::path path; +}; + +using TexturePackAction = std::variant; + +static moodycamel::ConcurrentQueue texture_pack_action_queue; + unsigned int MI_INTR_REG = 0; unsigned int DPC_START_REG = 0; @@ -286,6 +306,32 @@ zelda64::renderer::RT64Context::RT64Context(uint8_t* rdram, ultramodern::rendere zelda64::renderer::RT64Context::~RT64Context() = default; void zelda64::renderer::RT64Context::send_dl(const OSTask* task) { + bool packs_disabled = false; + TexturePackAction cur_action; + while (texture_pack_action_queue.try_dequeue(cur_action)) { + std::visit(overloaded{ + [&](TexturePackDisableAction& to_disable) { + enabled_texture_packs.erase(to_disable.path); + packs_disabled = true; + }, + [&](TexturePackEnableAction& to_enable) { + enabled_texture_packs.insert(to_enable.path); + // Load the pack now if no packs have been disabled. + if (!packs_disabled) { + app->textureCache->loadReplacementDirectory(to_enable.path); + } + } + }, cur_action); + } + + // If any packs were disabled, unload all packs and load all the active ones. + if (packs_disabled) { + app->textureCache->clearReplacementDirectories(); + for (const std::filesystem::path& cur_pack_path : enabled_texture_packs) { + app->textureCache->loadReplacementDirectory(cur_pack_path); + } + } + app->state->rsp->reset(); app->interpreter->loadUCodeGBI(task->t.ucode & 0x3FFFFFF, task->t.ucode_data & 0x3FFFFFF, true); app->processDisplayLists(app->core.RDRAM, task->t.data_ptr & 0x3FFFFFF, 0, true); @@ -376,3 +422,11 @@ bool zelda64::renderer::RT64SamplePositionsSupported() { bool zelda64::renderer::RT64HighPrecisionFBEnabled() { return high_precision_fb_enabled; } + +void zelda64::renderer::enable_texture_pack(const recomp::mods::ModHandle& mod) { + texture_pack_action_queue.enqueue(TexturePackEnableAction{mod.manifest.mod_root_path}); +} + +void zelda64::renderer::disable_texture_pack(const recomp::mods::ModHandle& mod) { + texture_pack_action_queue.enqueue(TexturePackDisableAction{mod.manifest.mod_root_path}); +} From 24c436a572be8934d44e66362a977783302b5f04 Mon Sep 17 00:00:00 2001 From: LittleCube Date: Fri, 4 Oct 2024 00:01:23 -0400 Subject: [PATCH 36/49] add exports and events for moon crash save and owl save (#487) * add exports and events for moon crash save and owl save * fix recomp_on_owl_save event, add exports and callbacks for save loading * add more flexible owl events * add init event * fix init event to not be terrible * rename a couple events * use deletes instead of resets * use better names, add better annotations * use full signature for event annotations --- patches/autosaving.c | 104 ++++++++++++++++++++++++++++++------- patches/play_patches.c | 12 ++++- patches/required_patches.c | 5 ++ 3 files changed, 100 insertions(+), 21 deletions(-) diff --git a/patches/autosaving.c b/patches/autosaving.c index 809c98d..bcf5c3c 100644 --- a/patches/autosaving.c +++ b/patches/autosaving.c @@ -99,13 +99,22 @@ RECOMP_EXPORT void recomp_do_autosave(PlayState* play) { gSaveContext.save.isOwlSave = false; } -// @recomp Do not clear the save if the save was an autosave. +bool loading_deletes_owl_save = true; + +// @recomp_export void recomp_set_loading_deletes_owl_save(bool new_val): Set whether loading an owl save should also delete it. +RECOMP_EXPORT void recomp_set_loading_deletes_owl_save(bool new_val) +{ + loading_deletes_owl_save = new_val; +} + +// @recomp Do not clear the save if the save was an autosave, or if mods have disabled save deletion. RECOMP_PATCH void func_80147314(SramContext* sramCtx, s32 fileNum) { s32 save_type = gSaveContext.save.isOwlSave; gSaveContext.save.isOwlSave = false; - // @recomp Prevent owl save/autosave deletion if autosaving is enabled. - if (!recomp_autosave_enabled()) { + // @recomp Prevent owl save/autosave deletion if autosaving is enabled, and... + // @recomp_use_export_var loading_deletes_owl_save: Prevent owl save deletion if mods disable it. + if (!recomp_autosave_enabled() && loading_deletes_owl_save) { gSaveContext.save.saveInfo.playerData.newf[0] = '\0'; gSaveContext.save.saveInfo.playerData.newf[1] = '\0'; gSaveContext.save.saveInfo.playerData.newf[2] = '\0'; @@ -522,6 +531,9 @@ s32 spawn_entrance_from_autosave_entrance(s16 autosave_entrance) { } } +RECOMP_DECLARE_EVENT(recomp_on_load_save(FileSelectState* fileSelect, SramContext* sramCtx)); +RECOMP_DECLARE_EVENT(recomp_after_load_save(FileSelectState* fileSelect, SramContext* sramCtx)); + // @recomp Patched to change the entrance for autosaves and initialize autosaves. RECOMP_PATCH void Sram_OpenSave(FileSelectState* fileSelect, SramContext* sramCtx) { s32 i; @@ -530,6 +542,9 @@ RECOMP_PATCH void Sram_OpenSave(FileSelectState* fileSelect, SramContext* sramCt s32 pad1; s32 fileNum; + // @recomp_event recomp_on_load_save(FileSelectState* fileSelect, SramContext* sramCtx): A save-file was just chosen. + recomp_on_load_save(fileSelect, sramCtx); + if (gSaveContext.flashSaveAvailable) { bzero(sramCtx->saveBuf, SAVE_BUFFER_SIZE); @@ -653,29 +668,49 @@ RECOMP_PATCH void Sram_OpenSave(FileSelectState* fileSelect, SramContext* sramCt // @recomp Initialize the autosave state tracking. autosave_init(); + + // @recomp_event recomp_after_load_save(FileSelectState* fileSelect, SramContext* sramCtx): The save has finished loading. + recomp_after_load_save(fileSelect, sramCtx); +} + +bool moon_crash_resets_save = true; + +// @recomp_export void recomp_set_moon_crash_resets_save(bool new_val): Set whether a moon crash should revert the player's save data. +RECOMP_EXPORT void recomp_set_moon_crash_resets_save(bool new_val) +{ + moon_crash_resets_save = new_val; } extern s32 Actor_ProcessTalkRequest(Actor* actor, GameState* gameState); +RECOMP_DECLARE_EVENT(recomp_on_moon_crash(SramContext* sramCtx)); +RECOMP_DECLARE_EVENT(recomp_after_moon_crash(SramContext* sramCtx)); + // @recomp Reset the autosave timer when the moon crashes. RECOMP_PATCH void Sram_ResetSaveFromMoonCrash(SramContext* sramCtx) { s32 i; s32 cutsceneIndex = gSaveContext.save.cutsceneIndex; - bzero(sramCtx->saveBuf, SAVE_BUFFER_SIZE); + // @recomp_event recomp_on_moon_crash(SramContext* sramCtx): A moon crash has just been triggered. + recomp_on_moon_crash(sramCtx); - if (SysFlashrom_ReadData(sramCtx->saveBuf, gFlashSaveStartPages[gSaveContext.fileNum * 2], - gFlashSaveNumPages[gSaveContext.fileNum * 2]) != 0) { - SysFlashrom_ReadData(sramCtx->saveBuf, gFlashSaveStartPages[gSaveContext.fileNum * 2 + 1], - gFlashSaveNumPages[gSaveContext.fileNum * 2 + 1]); + if (moon_crash_resets_save) + { + bzero(sramCtx->saveBuf, SAVE_BUFFER_SIZE); + + if (SysFlashrom_ReadData(sramCtx->saveBuf, gFlashSaveStartPages[gSaveContext.fileNum * 2], + gFlashSaveNumPages[gSaveContext.fileNum * 2]) != 0) { + SysFlashrom_ReadData(sramCtx->saveBuf, gFlashSaveStartPages[gSaveContext.fileNum * 2 + 1], + gFlashSaveNumPages[gSaveContext.fileNum * 2 + 1]); + } + Lib_MemCpy(&gSaveContext.save, sramCtx->saveBuf, sizeof(Save)); + if (CHECK_NEWF(gSaveContext.save.saveInfo.playerData.newf)) { + SysFlashrom_ReadData(sramCtx->saveBuf, gFlashSaveStartPages[gSaveContext.fileNum * 2 + 1], + gFlashSaveNumPages[gSaveContext.fileNum * 2 + 1]); + Lib_MemCpy(&gSaveContext, sramCtx->saveBuf, sizeof(Save)); + } + gSaveContext.save.cutsceneIndex = cutsceneIndex; } - Lib_MemCpy(&gSaveContext.save, sramCtx->saveBuf, sizeof(Save)); - if (CHECK_NEWF(gSaveContext.save.saveInfo.playerData.newf)) { - SysFlashrom_ReadData(sramCtx->saveBuf, gFlashSaveStartPages[gSaveContext.fileNum * 2 + 1], - gFlashSaveNumPages[gSaveContext.fileNum * 2 + 1]); - Lib_MemCpy(&gSaveContext, sramCtx->saveBuf, sizeof(Save)); - } - gSaveContext.save.cutsceneIndex = cutsceneIndex; for (i = 0; i < ARRAY_COUNT(gSaveContext.eventInf); i++) { gSaveContext.eventInf[i] = 0; @@ -706,24 +741,55 @@ RECOMP_PATCH void Sram_ResetSaveFromMoonCrash(SramContext* sramCtx) { // @recomp Use the slow autosave timer to give the player extra time to respond to the moon crashing to decide if they want to reload their autosave. recomp_reset_autosave_timer_slow(); + + // @recomp_event recomp_after_moon_crash(SramContext* sramCtx): The effects of moon crash have been written. + recomp_after_moon_crash(sramCtx); } -// @recomp If autosave is enabled, skip the part of the owl statue dialog that talks about the file being deleted on load, since it's not true. +bool owls_save_and_quit = true; + +// @recomp_export void recomp_set_owls_save_and_quit(bool new_val): Set if owls should use their code to save and quit. If false is passed, owl saves now do nothing. +RECOMP_EXPORT void recomp_set_owls_save_and_quit(bool new_val) +{ + owls_save_and_quit = new_val; +} + +RECOMP_DECLARE_EVENT(recomp_on_owl_update(ObjWarpstone* this, PlayState* play)); +RECOMP_DECLARE_EVENT(recomp_on_owl_save(ObjWarpstone* this, PlayState* play)); +RECOMP_DECLARE_EVENT(recomp_after_owl_save(ObjWarpstone* this, PlayState* play)); + +// @recomp If autosave is enabled or owl save deletion is disabled, skip the part of the owl statue dialog that talks about the file being deleted on load, since it's not true. RECOMP_PATCH void ObjWarpstone_Update(Actor* thisx, PlayState* play) { ObjWarpstone* this = (ObjWarpstone*)thisx; s32 pad; + // @recomp_event recomp_on_owl_update(ObjWarpstone* this, PlayState* play): Allow mods to handle owl update frames. + recomp_on_owl_update(this, play); + if (this->isTalking) { if (Actor_TextboxIsClosing(&this->dyna.actor, play)) { this->isTalking = false; } else if ((Message_GetState(&play->msgCtx) == TEXT_STATE_CHOICE) && Message_ShouldAdvance(play)) { if (play->msgCtx.choiceIndex != 0) { + // @recomp_event recomp_on_owl_save(ObjWarpstone* this, PlayState* play): The player chose to save from an owl statue. + recomp_on_owl_save(this, play); + Audio_PlaySfx_MessageDecide(); - play->msgCtx.msgMode = MSGMODE_OWL_SAVE_0; + + // @recomp_use_export_var owls_save_and_quit: Only use normal owl save if quit flag is set. + if (owls_save_and_quit) { + play->msgCtx.msgMode = MSGMODE_OWL_SAVE_0; + } else { + Message_CloseTextbox(play); + } + play->msgCtx.unk120D6 = 0; play->msgCtx.unk120D4 = 0; gSaveContext.save.owlWarpId = OBJ_WARPSTONE_GET_OWL_WARP_ID(&this->dyna.actor); + + // @recomp_event recomp_after_owl_save(ObjWarpstone* this, PlayState* play): Owl save is finished. + recomp_after_owl_save(this, play); } else { Message_CloseTextbox(play); } @@ -734,8 +800,8 @@ RECOMP_PATCH void ObjWarpstone_Update(Actor* thisx, PlayState* play) { Actor_OfferTalkNearColChkInfoCylinder(&this->dyna.actor, play); } - // @recomp Skip the text talking about the save being deleted on load, if autosave is enabled. - if (recomp_autosave_enabled()) { + // @recomp_use_export_var loading_deletes_owl_save: Skip the text talking about the save being deleted on load, if autosave is enabled or if owl save deletion is disabled. + if (recomp_autosave_enabled() || !loading_deletes_owl_save) { if (this->isTalking && play->msgCtx.currentTextId == 0xC01 && play->msgCtx.msgBufPos == 269) { play->msgCtx.msgBufPos = 530; } diff --git a/patches/play_patches.c b/patches/play_patches.c index eedda5d..db5deeb 100644 --- a/patches/play_patches.c +++ b/patches/play_patches.c @@ -5,7 +5,7 @@ extern Input D_801F6C18; RECOMP_DECLARE_EVENT(recomp_on_play_main(PlayState* play)); -RECOMP_DECLARE_EVENT(recomp_before_play_update(PlayState* play)); +RECOMP_DECLARE_EVENT(recomp_on_play_update(PlayState* play)); RECOMP_DECLARE_EVENT(recomp_after_play_update(PlayState* play)); void controls_play_update(PlayState* play) { @@ -16,6 +16,8 @@ void controls_play_update(PlayState* play) { RECOMP_PATCH void Play_Main(GameState* thisx) { static Input* prevInput = NULL; PlayState* this = (PlayState*)thisx; + + // @recomp_event recomp_on_play_main(PlayState* play): Allow mods to execute code every frame. recomp_on_play_main(this); // @recomp @@ -37,9 +39,15 @@ RECOMP_PATCH void Play_Main(GameState* thisx) { this->state.gfxCtx = NULL; } camera_pre_play_update(this); - recomp_before_play_update(this); + + // @recomp_event recomp_on_play_update(PlayState* play): Play_Update is about to be called. + recomp_on_play_update(this); + Play_Update(this); + + // @recomp_event recomp_after_play_update(PlayState* play): Play_Update was called. recomp_after_play_update(this); + camera_post_play_update(this); analog_cam_post_play_update(this); autosave_post_play_update(this); diff --git a/patches/required_patches.c b/patches/required_patches.c index 721a41a..7aada58 100644 --- a/patches/required_patches.c +++ b/patches/required_patches.c @@ -7,6 +7,8 @@ void Main_InitMemory(void); void Main_InitScreen(void); +RECOMP_DECLARE_EVENT(recomp_on_init()); + // @recomp Patched to load the code segment in the recomp runtime. RECOMP_PATCH void Main_Init(void) { DmaRequest dmaReq; @@ -14,6 +16,9 @@ RECOMP_PATCH void Main_Init(void) { OSMesg msg[1]; size_t prevSize; + // @recomp_event recomp_on_init(): Allow mods to initialize themselves once. + recomp_on_init(); + osCreateMesgQueue(&mq, msg, ARRAY_COUNT(msg)); prevSize = gDmaMgrDmaBuffSize; From cd12bc0c2053c1235bd0aa9fdf84ac67e4f6e9cc Mon Sep 17 00:00:00 2001 From: Mr-Wiseguy Date: Mon, 7 Oct 2024 01:35:56 -0400 Subject: [PATCH 37/49] Disable identical code folding to prevent mods from conflicting with themselves due to merged functions --- CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index d4ef3ef..0b900bc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -196,6 +196,11 @@ else() ) endif() +if (MSVC) + # Disable identical code folding, since this breaks mod function patching as multiple functions can get merged into one. + target_link_options(Zelda64Recompiled PRIVATE /OPT:NOICF) +endif() + if (WIN32) include(FetchContent) From aeefc1b6bb4470df88ee4e8f160b8af582b9545b Mon Sep 17 00:00:00 2001 From: David Chavez Date: Tue, 8 Oct 2024 05:27:13 +0200 Subject: [PATCH 38/49] chore(ci): Bundle Windows PDBs (#492) * update runners * Save PDB * Build RelWithDebInfo * Update copy on runners * Archive PDB separately * Update copy * Update PDB archive name --- .github/workflows/validate.yml | 13 ++++++++++--- README.md | 2 +- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 442d031..b9f7c96 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -22,7 +22,7 @@ concurrency: cancel-in-progress: true jobs: build-linux: - runs-on: ${{ matrix.os }} + runs-on: ${{ format('blaze/compute/{0}-amd64', matrix.os) }} container: image: dcvz/n64recomp:ubuntu-18.04 volumes: @@ -108,7 +108,7 @@ jobs: name: Zelda64Recompiled-AppImage-X64-${{ matrix.type }} path: Zelda64Recompiled-*.AppImage build-linux-arm64: - runs-on: ${{ format('blaze/{0}', matrix.os) }} + runs-on: ${{ format('blaze/compute/{0}', matrix.os) }} strategy: matrix: type: [ Debug, Release ] @@ -199,7 +199,7 @@ jobs: runs-on: windows-latest strategy: matrix: - type: [ Debug, Release ] + type: [ Debug, RelWithDebInfo ] name: windows (${{ matrix.type }}) steps: - name: Checkout @@ -264,6 +264,7 @@ jobs: Move-Item -Path "cmake-build/dxcompiler.dll" -Destination "dxcompiler.dll" Move-Item -Path "cmake-build/dxil.dll" -Destination "dxil.dll" Move-Item -Path "cmake-build/SDL2.dll" -Destination "SDL2.dll" + Move-Item -Path "cmake-build/Zelda64Recompiled.pdb" -Destination "Zelda64Recompiled.pdb" Remove-Item -Path "assets/scss" -Recurse -Force - name: Archive Zelda64Recomp uses: actions/upload-artifact@v4 @@ -276,3 +277,9 @@ jobs: SDL2.dll assets/ gamecontrollerdb.txt + - name: Archive Debug Files + uses: actions/upload-artifact@v4 + with: + name: Zelda64Recompiled-PDB-${{ matrix.type }} + path: | + Zelda64Recompiled.pdb diff --git a/README.md b/README.md index d840f9e..95f9aa3 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Zelda 64: Recompiled is a project that uses [N64: Recompiled](https://github.com
-_Thank you [Blaze](https://runblaze.dev) for supporting this project by providing Linux ARM64 and Apple Silicon macOS Github Action Runners!_ +_Special thanks to [Blaze](https://runblaze.dev) for their support of this project. They provide high-performance Linux (AMD64 & ARM64) and Apple Silicon macOS runners for GitHub Actions, greatly reducing our automated build times._ From fdbdf5edb07f4150ac2a127a11a6d0d4ea8678b8 Mon Sep 17 00:00:00 2001 From: Mr-Wiseguy Date: Fri, 11 Oct 2024 21:15:11 -0400 Subject: [PATCH 39/49] Add custom symbols toml and made non-relocatable versions of original gamestate functions, added base patch for Play_Init --- patches.toml | 2 +- patches/custom_syms.toml | 16 ++ patches/options.c | 5 +- patches/play_patches.c | 326 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 347 insertions(+), 2 deletions(-) create mode 100644 patches/custom_syms.toml diff --git a/patches.toml b/patches.toml index 38910ee..18a8856 100644 --- a/patches.toml +++ b/patches.toml @@ -9,7 +9,7 @@ single_file_output = true use_absolute_symbols = true # Point the recompiler at the symbol files so that it can resolve relocations during recompilation. func_reference_syms_file = "Zelda64RecompSyms/mm.us.rev1.syms.toml" -data_reference_syms_files = [ "Zelda64RecompSyms/mm.us.rev1.datasyms.toml", "Zelda64RecompSyms/mm.us.rev1.datasyms_static.toml" ] +data_reference_syms_files = [ "Zelda64RecompSyms/mm.us.rev1.datasyms.toml", "Zelda64RecompSyms/mm.us.rev1.datasyms_static.toml", "patches/custom_syms.toml" ] # Tell the recompiler to write the output binary. Doing this instead of using objcopy allows the recompiler to patch MIPS32 relocs. output_binary_path = "patches/patches.bin" # Do not emit warnings for unpaired LO16 values, as clang produces many of them. diff --git a/patches/custom_syms.toml b/patches/custom_syms.toml new file mode 100644 index 0000000..9128278 --- /dev/null +++ b/patches/custom_syms.toml @@ -0,0 +1,16 @@ +# Custom symbols used for patches. +[[section]] +name = "ABSOLUTE_SYMS" +vram = 0x00000000 +size = 0x0 + +symbols = [ + # Alternate references to symbols that would otherwise be relocated + { name = "Setup_Init_NORELOCATE", vram = 0x80173338 }, # Not relocatable, but here for uniformity with the other gamestate funcs + { name = "MapSelect_Init_NORELOCATE", vram = 0x80801B4C }, + { name = "ConsoleLogo_Init_NORELOCATE", vram = 0x8080074C }, + { name = "Play_Init_NORELOCATE", vram = 0x8016A2C8 }, + { name = "TitleSetup_Init_NORELOCATE", vram = 0x80803F30 }, + { name = "FileSelect_Init_NORELOCATE", vram = 0x80813C98 }, + { name = "DayTelop_Init_NORELOCATE", vram = 0x80815820 }, +] diff --git a/patches/options.c b/patches/options.c index c26133c..07c0a23 100644 --- a/patches/options.c +++ b/patches/options.c @@ -1036,6 +1036,9 @@ RECOMP_PATCH void FileSelect_ConfirmFile(GameState *thisx) { } } +// Non-relocatable reference to the original address of Play_Init. +void Play_Init_NORELOCATE(GameState*); + /** * Load the save for the appropriate file and start the game. * Update function for `SM_LOAD_GAME` @@ -1060,7 +1063,7 @@ RECOMP_PATCH void FileSelect_LoadGame(GameState* thisx) { gSaveContext.gameMode = GAMEMODE_NORMAL; STOP_GAMESTATE(&this->state); - SET_NEXT_GAMESTATE(&this->state, Play_Init, sizeof(PlayState)); + SET_NEXT_GAMESTATE(&this->state, Play_Init_NORELOCATE, sizeof(PlayState)); gSaveContext.respawnFlag = 0; gSaveContext.respawn[RESPAWN_MODE_DOWN].entrance = ENTR_LOAD_OPENING; diff --git a/patches/play_patches.c b/patches/play_patches.c index db5deeb..712b612 100644 --- a/patches/play_patches.c +++ b/patches/play_patches.c @@ -1,6 +1,30 @@ #include "play_patches.h" #include "z64debug_display.h" #include "input.h" +#include "prevent_bss_reordering.h" +#include "z64.h" +#include "regs.h" +#include "functions.h" +#include "z64vismono.h" +#include "z64visfbuf.h" +#include "buffers.h" + +#include "variables.h" +#include "macros.h" +#include "buffers.h" +#include "idle.h" +#include "sys_cfb.h" +#include "z64bombers_notebook.h" +#include "z64quake.h" +#include "z64rumble.h" +#include "z64shrink_window.h" +#include "z64view.h" + +#include "overlays/gamestates/ovl_daytelop/z_daytelop.h" +#include "overlays/gamestates/ovl_opening/z_opening.h" +#include "overlays/gamestates/ovl_file_choose/z_file_select.h" +#include "overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope.h" +#include "debug.h" extern Input D_801F6C18; @@ -98,3 +122,305 @@ RECOMP_PATCH s32 Room_HandleLoadCallbacks(PlayState* play, RoomContext* roomCtx) return 1; } + +void ZeldaArena_Init(void* start, size_t size); + +void Play_SpawnScene(PlayState* this, s32 sceneId, s32 spawn); +void Play_InitMotionBlur(void); + +extern s16 sTransitionFillTimer; +extern Input D_801F6C18; +extern TransitionTile sTransitionTile; +extern s32 gTransitionTileState; +extern VisMono sPlayVisMono; +extern Color_RGBA8_u32 gVisMonoColor; +extern VisFbuf sPlayVisFbuf; +extern VisFbuf* sPlayVisFbufInstance; +extern BombersNotebook sBombersNotebook; +extern u8 sBombersNotebookOpen; +extern u8 sMotionBlurStatus; + +extern s32 gDbgCamEnabled; +extern u8 D_801D0D54; + +extern u8 gPictoPhotoI8[]; +extern u8 D_80784600[]; + +// Non-relocatable references to the original addresses of these game state functions. +void DayTelop_Init_NORELOCATE(GameState*); +void TitleSetup_Init_NORELOCATE(GameState*); + +RECOMP_PATCH void Play_Init(GameState* thisx) { + PlayState* this = (PlayState*)thisx; + GraphicsContext* gfxCtx = this->state.gfxCtx; + s32 pad; + uintptr_t zAlloc; + s32 zAllocSize; + Player* player; + s32 i; + s32 spawn; + u8 sceneLayer; + s32 scene; + + if ((gSaveContext.respawnFlag == -4) || (gSaveContext.respawnFlag == -0x63)) { + if (CHECK_EVENTINF(EVENTINF_TRIGGER_DAYTELOP)) { + CLEAR_EVENTINF(EVENTINF_TRIGGER_DAYTELOP); + STOP_GAMESTATE(&this->state); + // Use non-relocatable reference to DayTelop_Init instead. + SET_NEXT_GAMESTATE(&this->state, DayTelop_Init_NORELOCATE, sizeof(DayTelopState)); + return; + } + + gSaveContext.unk_3CA7 = 1; + if (gSaveContext.respawnFlag == -0x63) { + gSaveContext.respawnFlag = 2; + } + } else { + gSaveContext.unk_3CA7 = 0; + } + + if (gSaveContext.save.entrance == -1) { + gSaveContext.save.entrance = 0; + STOP_GAMESTATE(&this->state); + // Use non-relocatable reference to TitleSetup_Init instead. + SET_NEXT_GAMESTATE(&this->state, TitleSetup_Init_NORELOCATE, sizeof(TitleSetupState)); + return; + } + + if ((gSaveContext.nextCutsceneIndex == 0xFFEF) || (gSaveContext.nextCutsceneIndex == 0xFFF0)) { + scene = ((void)0, gSaveContext.save.entrance) >> 9; + spawn = (((void)0, gSaveContext.save.entrance) >> 4) & 0x1F; + + if (CHECK_WEEKEVENTREG(WEEKEVENTREG_CLEARED_SNOWHEAD_TEMPLE)) { + if (scene == ENTR_SCENE_MOUNTAIN_VILLAGE_WINTER) { + scene = ENTR_SCENE_MOUNTAIN_VILLAGE_SPRING; + } else if (scene == ENTR_SCENE_GORON_VILLAGE_WINTER) { + scene = ENTR_SCENE_GORON_VILLAGE_SPRING; + } else if (scene == ENTR_SCENE_PATH_TO_GORON_VILLAGE_WINTER) { + scene = ENTR_SCENE_PATH_TO_GORON_VILLAGE_SPRING; + } else if ((scene == ENTR_SCENE_SNOWHEAD) || (scene == ENTR_SCENE_PATH_TO_SNOWHEAD) || + (scene == ENTR_SCENE_PATH_TO_MOUNTAIN_VILLAGE) || (scene == ENTR_SCENE_GORON_SHRINE) || + (scene == ENTR_SCENE_GORON_RACETRACK)) { + gSaveContext.nextCutsceneIndex = 0xFFF0; + } + } + + if (CHECK_WEEKEVENTREG(WEEKEVENTREG_CLEARED_WOODFALL_TEMPLE)) { + if (scene == ENTR_SCENE_SOUTHERN_SWAMP_POISONED) { + scene = ENTR_SCENE_SOUTHERN_SWAMP_CLEARED; + } else if (scene == ENTR_SCENE_WOODFALL) { + gSaveContext.nextCutsceneIndex = 0xFFF1; + } + } + + if (CHECK_WEEKEVENTREG(WEEKEVENTREG_CLEARED_STONE_TOWER_TEMPLE) && (scene == ENTR_SCENE_IKANA_CANYON)) { + gSaveContext.nextCutsceneIndex = 0xFFF2; + } + + if (CHECK_WEEKEVENTREG(WEEKEVENTREG_CLEARED_GREAT_BAY_TEMPLE) && + ((scene == ENTR_SCENE_GREAT_BAY_COAST) || (scene == ENTR_SCENE_ZORA_CAPE))) { + gSaveContext.nextCutsceneIndex = 0xFFF0; + } + + // "First cycle" Termina Field + if (INV_CONTENT(ITEM_OCARINA_OF_TIME) != ITEM_OCARINA_OF_TIME) { + if ((scene == ENTR_SCENE_TERMINA_FIELD) && + (((void)0, gSaveContext.save.entrance) != ENTRANCE(TERMINA_FIELD, 10))) { + gSaveContext.nextCutsceneIndex = 0xFFF4; + } + } + //! FAKE: + gSaveContext.save.entrance = + Entrance_Create(((void)0, scene), spawn, ((void)0, gSaveContext.save.entrance) & 0xF); + } + + GameState_Realloc(&this->state, 0); + KaleidoManager_Init(this); + ShrinkWindow_Init(); + View_Init(&this->view, gfxCtx); + Audio_SetExtraFilter(0); + Quake_Init(); + Distortion_Init(this); + + for (i = 0; i < ARRAY_COUNT(this->cameraPtrs); i++) { + this->cameraPtrs[i] = NULL; + } + + Camera_Init(&this->mainCamera, &this->view, &this->colCtx, this); + Camera_ChangeStatus(&this->mainCamera, CAM_STATUS_ACTIVE); + + for (i = 0; i < ARRAY_COUNT(this->subCameras); i++) { + Camera_Init(&this->subCameras[i], &this->view, &this->colCtx, this); + Camera_ChangeStatus(&this->subCameras[i], CAM_STATUS_INACTIVE); + } + + this->cameraPtrs[CAM_ID_MAIN] = &this->mainCamera; + this->cameraPtrs[CAM_ID_MAIN]->uid = CAM_ID_MAIN; + this->activeCamId = CAM_ID_MAIN; + + Camera_OverwriteStateFlags(&this->mainCamera, CAM_STATE_0 | CAM_STATE_CHECK_WATER | CAM_STATE_2 | CAM_STATE_3 | + CAM_STATE_4 | CAM_STATE_DISABLE_MODE_CHANGE | CAM_STATE_6); + Sram_Alloc(&this->state, &this->sramCtx); + Regs_InitData(this); + Message_Init(this); + GameOver_Init(this); + SoundSource_InitAll(this); + EffFootmark_Init(this); + Effect_Init(this); + EffectSS_Init(this, 100); + CollisionCheck_InitContext(this, &this->colChkCtx); + AnimationContext_Reset(&this->animationCtx); + Cutscene_InitContext(this, &this->csCtx); + + if (gSaveContext.nextCutsceneIndex != 0xFFEF) { + gSaveContext.save.cutsceneIndex = gSaveContext.nextCutsceneIndex; + gSaveContext.nextCutsceneIndex = 0xFFEF; + } + + if (gSaveContext.save.cutsceneIndex == 0xFFFD) { + gSaveContext.save.cutsceneIndex = 0; + } + + if (gSaveContext.nextDayTime != NEXT_TIME_NONE) { + gSaveContext.save.time = gSaveContext.nextDayTime; + gSaveContext.skyboxTime = gSaveContext.nextDayTime; + } + + if ((CURRENT_TIME >= CLOCK_TIME(18, 0)) || (CURRENT_TIME < CLOCK_TIME(6, 30))) { + gSaveContext.save.isNight = true; + } else { + gSaveContext.save.isNight = false; + } + + func_800EDDB0(this); + + if (((gSaveContext.gameMode != GAMEMODE_NORMAL) && (gSaveContext.gameMode != GAMEMODE_TITLE_SCREEN)) || + (gSaveContext.save.cutsceneIndex >= 0xFFF0)) { + gSaveContext.nayrusLoveTimer = 0; + Magic_Reset(this); + gSaveContext.sceneLayer = (gSaveContext.save.cutsceneIndex & 0xF) + 1; + + // Set saved cutscene to 0 so it doesn't immediately play, but instead let the `CutsceneManager` handle it. + gSaveContext.save.cutsceneIndex = 0; + } else { + gSaveContext.sceneLayer = 0; + } + + sceneLayer = gSaveContext.sceneLayer; + + Play_SpawnScene( + this, Entrance_GetSceneIdAbsolute(((void)0, gSaveContext.save.entrance) + ((void)0, gSaveContext.sceneLayer)), + Entrance_GetSpawnNum(((void)0, gSaveContext.save.entrance) + ((void)0, gSaveContext.sceneLayer))); + KaleidoScopeCall_Init(this); + Interface_Init(this); + + if (gSaveContext.nextDayTime != NEXT_TIME_NONE) { + if (gSaveContext.nextDayTime == NEXT_TIME_DAY) { + gSaveContext.save.day++; + gSaveContext.save.eventDayCount++; + gSaveContext.dogIsLost = true; + gSaveContext.nextDayTime = NEXT_TIME_DAY_SET; + } else { + gSaveContext.nextDayTime = NEXT_TIME_NIGHT_SET; + } + } + + Play_InitMotionBlur(); + + R_PAUSE_BG_PRERENDER_STATE = PAUSE_BG_PRERENDER_OFF; + R_PICTO_PHOTO_STATE = PICTO_PHOTO_STATE_OFF; + + PreRender_Init(&this->pauseBgPreRender); + PreRender_SetValuesSave(&this->pauseBgPreRender, gCfbWidth, gCfbHeight, NULL, NULL, NULL); + PreRender_SetValues(&this->pauseBgPreRender, gCfbWidth, gCfbHeight, NULL, NULL); + + this->unk_18E64 = gWorkBuffer; + this->pictoPhotoI8 = gPictoPhotoI8; + this->unk_18E68 = D_80784600; + this->unk_18E58 = D_80784600; + this->unk_18E60 = D_80784600; + gTransitionTileState = TRANS_TILE_OFF; + this->transitionMode = TRANS_MODE_OFF; + D_801D0D54 = false; + + FrameAdvance_Init(&this->frameAdvCtx); + Rand_Seed(osGetTime()); + Matrix_Init(&this->state); + + this->state.main = Play_Main; + this->state.destroy = Play_Destroy; + + this->transitionTrigger = TRANS_TRIGGER_END; + this->worldCoverAlpha = 0; + this->bgCoverAlpha = 0; + this->haltAllActors = false; + this->unk_18844 = false; + + if (gSaveContext.gameMode != GAMEMODE_TITLE_SCREEN) { + if (gSaveContext.nextTransitionType == TRANS_NEXT_TYPE_DEFAULT) { + this->transitionType = + (Entrance_GetTransitionFlags(((void)0, gSaveContext.save.entrance) + sceneLayer) >> 7) & 0x7F; + } else { + this->transitionType = gSaveContext.nextTransitionType; + gSaveContext.nextTransitionType = TRANS_NEXT_TYPE_DEFAULT; + } + } else { + this->transitionType = TRANS_TYPE_FADE_BLACK; + } + + TransitionFade_Init(&this->unk_18E48); + TransitionFade_SetType(&this->unk_18E48, 3); + TransitionFade_SetColor(&this->unk_18E48, RGBA8(160, 160, 160, 255)); + TransitionFade_Start(&this->unk_18E48); + VisMono_Init(&sPlayVisMono); + + gVisMonoColor.a = 0; + sPlayVisFbufInstance = &sPlayVisFbuf; + VisFbuf_Init(sPlayVisFbufInstance); + sPlayVisFbufInstance->lodProportion = 0.0f; + sPlayVisFbufInstance->mode = VIS_FBUF_MODE_GENERAL; + sPlayVisFbufInstance->primColor.r = 0; + sPlayVisFbufInstance->primColor.g = 0; + sPlayVisFbufInstance->primColor.b = 0; + sPlayVisFbufInstance->primColor.a = 0; + sPlayVisFbufInstance->envColor.r = 0; + sPlayVisFbufInstance->envColor.g = 0; + sPlayVisFbufInstance->envColor.b = 0; + sPlayVisFbufInstance->envColor.a = 0; + CutsceneFlags_UnsetAll(this); + THA_GetRemaining(&this->state.tha); + zAllocSize = THA_GetRemaining(&this->state.tha); + zAlloc = (uintptr_t)THA_AllocTailAlign16(&this->state.tha, zAllocSize); + + //! @bug: Incorrect ALIGN16s + ZeldaArena_Init((void*)((zAlloc + 8) & ~0xF), (zAllocSize - ((zAlloc + 8) & ~0xF)) + zAlloc); + + Actor_InitContext(this, &this->actorCtx, this->linkActorEntry); + + while (!Room_HandleLoadCallbacks(this, &this->roomCtx)) {} + + if ((CURRENT_DAY != 0) && ((this->roomCtx.curRoom.behaviorType1 == ROOM_BEHAVIOR_TYPE1_1) || + (this->roomCtx.curRoom.behaviorType1 == ROOM_BEHAVIOR_TYPE1_5))) { + Actor_Spawn(&this->actorCtx, this, ACTOR_EN_TEST4, 0.0f, 0.0f, 0.0f, 0, 0, 0, 0); + } + + player = GET_PLAYER(this); + + Camera_InitFocalActorSettings(&this->mainCamera, &player->actor); + gDbgCamEnabled = false; + + if (PLAYER_GET_BG_CAM_INDEX(&player->actor) != 0xFF) { + Camera_ChangeActorCsCamIndex(&this->mainCamera, PLAYER_GET_BG_CAM_INDEX(&player->actor)); + } + + CutsceneManager_StoreCamera(&this->mainCamera); + Interface_SetSceneRestrictions(this); + Environment_PlaySceneSequence(this); + gSaveContext.seqId = this->sequenceCtx.seqId; + gSaveContext.ambienceId = this->sequenceCtx.ambienceId; + AnimationContext_Update(this, &this->animationCtx); + Cutscene_HandleEntranceTriggers(this); + gSaveContext.respawnFlag = 0; + sBombersNotebookOpen = false; + BombersNotebook_Init(&sBombersNotebook); +} From e5699e59a1cfb0f7af363123a483748a87f74efe Mon Sep 17 00:00:00 2001 From: Mr-Wiseguy Date: Sat, 12 Oct 2024 01:12:02 -0400 Subject: [PATCH 40/49] Update runtime to fix mod section alignment --- lib/N64ModernRuntime | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/N64ModernRuntime b/lib/N64ModernRuntime index a4f5ee1..9e9ae17 160000 --- a/lib/N64ModernRuntime +++ b/lib/N64ModernRuntime @@ -1 +1 @@ -Subproject commit a4f5ee10c8303474d9028468e84845b192e9297d +Subproject commit 9e9ae173ee2c378c6ff5f7bbfe452503a80212d9 From 8c8f5b889fcbc4fcdf91a93a373c43fffe802656 Mon Sep 17 00:00:00 2001 From: LittleCube Date: Sat, 12 Oct 2024 23:13:42 -0400 Subject: [PATCH 41/49] Add events and exports for Play_Init (#495) --- patches/play_patches.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/patches/play_patches.c b/patches/play_patches.c index 712b612..1d38632 100644 --- a/patches/play_patches.c +++ b/patches/play_patches.c @@ -150,6 +150,15 @@ extern u8 D_80784600[]; void DayTelop_Init_NORELOCATE(GameState*); void TitleSetup_Init_NORELOCATE(GameState*); +RECOMP_DECLARE_EVENT(recomp_on_play_init(PlayState* this)); + +bool allow_no_ocarina_tf = false; + +// @recomp_export void recomp_set_allow_no_ocarina(bool new_val): Set whether to force Termina Field to load normally even if Link has no ocarina. +RECOMP_EXPORT void recomp_set_allow_no_ocarina(bool new_val) { + allow_no_ocarina_tf = new_val; +} + RECOMP_PATCH void Play_Init(GameState* thisx) { PlayState* this = (PlayState*)thisx; GraphicsContext* gfxCtx = this->state.gfxCtx; @@ -162,6 +171,9 @@ RECOMP_PATCH void Play_Init(GameState* thisx) { u8 sceneLayer; s32 scene; + // @recomp_event recomp_on_play_init(PlayState* this): A new PlayState is being constructed. + recomp_on_play_init(this); + if ((gSaveContext.respawnFlag == -4) || (gSaveContext.respawnFlag == -0x63)) { if (CHECK_EVENTINF(EVENTINF_TRIGGER_DAYTELOP)) { CLEAR_EVENTINF(EVENTINF_TRIGGER_DAYTELOP); @@ -223,7 +235,8 @@ RECOMP_PATCH void Play_Init(GameState* thisx) { } // "First cycle" Termina Field - if (INV_CONTENT(ITEM_OCARINA_OF_TIME) != ITEM_OCARINA_OF_TIME) { + // @recomp_use_export_var allow_no_ocarina_tf: Skip loading into "First cycle" Termina Field if mods enable it. + if (!allow_no_ocarina_tf && INV_CONTENT(ITEM_OCARINA_OF_TIME) != ITEM_OCARINA_OF_TIME) { if ((scene == ENTR_SCENE_TERMINA_FIELD) && (((void)0, gSaveContext.save.entrance) != ENTRANCE(TERMINA_FIELD, 10))) { gSaveContext.nextCutsceneIndex = 0xFFF4; From 21ca074bf7489e615c382dd553b43ed075104a40 Mon Sep 17 00:00:00 2001 From: LittleCube Date: Sun, 13 Oct 2024 00:02:08 -0400 Subject: [PATCH 42/49] Add exports for fd anywhere and epona fix patches (#494) * add exports for fd anywhere and epona fix patches * use better logic for restoreHudVisibility * cleanup * fix a couple edge cases (being sent the bow while riding Epona) --- patches/input.c | 95 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 78 insertions(+), 17 deletions(-) diff --git a/patches/input.c b/patches/input.c index 53f7eb3..f65d2cc 100644 --- a/patches/input.c +++ b/patches/input.c @@ -534,6 +534,13 @@ RECOMP_PATCH void Player_Action_86(Player *this, PlayState *play) { func_808550D0(play, this, this->unk_B10[4], this->unk_B10[5], (this->transformation == PLAYER_FORM_HUMAN) ? 0 : 1); } +bool no_bow_epona_fix = false; + +// @recomp_export void recomp_set_no_bow_epona_fix(bool new_val): Set whether to enable the fix for getting on Epona without a bow. +RECOMP_EXPORT void recomp_set_no_bow_epona_fix(bool new_val) { + no_bow_epona_fix = new_val; +} + extern s16 sPictoState; extern s16 sPictoPhotoBeingTaken; extern void* gWorkBuffer; @@ -603,24 +610,46 @@ RECOMP_PATCH void Interface_UpdateButtonsPart1(PlayState* play) { BUTTON_STATUS(EQUIP_SLOT_C_RIGHT) = BTN_DISABLED; set_extra_item_slot_status(BTN_DISABLED); } else { - BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B) = ITEM_BOW; + // @recomp_use_export_var no_bow_epona_fix: Part of the no bow Epona fix. + if (no_bow_epona_fix) { + if (gSaveContext.save.saveInfo.inventory.items[SLOT_BOW] == ITEM_BOW) { + BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B) = ITEM_BOW; + BUTTON_STATUS(EQUIP_SLOT_B) = BTN_ENABLED; + } + } else { + BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B) = ITEM_BOW; + } if (play->unk_1887C >= 2) { Interface_LoadItemIconImpl(play, EQUIP_SLOT_B); } else if (gSaveContext.save.saveInfo.inventory.items[SLOT_BOW] == ITEM_NONE) { - BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B) = ITEM_NONE; + // @recomp_use_export_var no_bow_epona_fix: Part of the no bow Epona fix. + if (no_bow_epona_fix) { + gSaveContext.buttonStatus[EQUIP_SLOT_B] = BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B); + BUTTON_STATUS(EQUIP_SLOT_B) = BTN_DISABLED; + } else { + BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B) = ITEM_NONE; + } } else { Interface_LoadItemIconImpl(play, EQUIP_SLOT_B); } - BUTTON_STATUS(EQUIP_SLOT_C_LEFT) = BTN_DISABLED; - BUTTON_STATUS(EQUIP_SLOT_C_DOWN) = BTN_DISABLED; - BUTTON_STATUS(EQUIP_SLOT_C_RIGHT) = BTN_DISABLED; - set_extra_item_slot_status(BTN_DISABLED); - Interface_SetHudVisibility(HUD_VISIBILITY_A_HEARTS_MAGIC_MINIMAP_WITH_OVERWRITE); + // @recomp_use_export_var no_bow_epona_fix: If the B button does not contain a sword, don't disable the UI. + if (!no_bow_epona_fix || BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B) < ITEM_SWORD_KOKIRI || + BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B) > ITEM_SWORD_GILDED) { + BUTTON_STATUS(EQUIP_SLOT_C_LEFT) = BTN_DISABLED; + BUTTON_STATUS(EQUIP_SLOT_C_DOWN) = BTN_DISABLED; + BUTTON_STATUS(EQUIP_SLOT_C_RIGHT) = BTN_DISABLED; + set_extra_item_slot_status(BTN_DISABLED); + Interface_SetHudVisibility(HUD_VISIBILITY_A_HEARTS_MAGIC_MINIMAP_WITH_OVERWRITE); + } } } + if (BUTTON_STATUS(EQUIP_SLOT_B) == BTN_DISABLED && BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B) == ITEM_BOW) { + BUTTON_STATUS(EQUIP_SLOT_B) = BTN_ENABLED; + } + if (play->transitionMode != TRANS_MODE_OFF) { Interface_SetHudVisibility(HUD_VISIBILITY_NONE); } else if ((gSaveContext.minigameStatus == MINIGAME_STATUS_ACTIVE) && @@ -662,27 +691,51 @@ RECOMP_PATCH void Interface_UpdateButtonsPart1(PlayState* play) { BUTTON_STATUS(EQUIP_SLOT_C_RIGHT) = BTN_DISABLED; set_extra_item_slot_status(BTN_DISABLED); } else { - BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B) = ITEM_BOW; + // @recomp_use_export_var no_bow_epona_fix: Part of the no bow Epona fix. + if (no_bow_epona_fix) { + if (gSaveContext.save.saveInfo.inventory.items[SLOT_BOW] == ITEM_BOW) { + BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B) = ITEM_BOW; + BUTTON_STATUS(EQUIP_SLOT_B) = BTN_ENABLED; + } + } else { + BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B) = ITEM_BOW; + } } if (play->unk_1887C >= 2) { Interface_LoadItemIconImpl(play, EQUIP_SLOT_B); } else if (gSaveContext.save.saveInfo.inventory.items[SLOT_BOW] == ITEM_NONE) { - BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B) = ITEM_NONE; + // @recomp_use_export_var no_bow_epona_fix: Part of the no bow Epona fix. + if (no_bow_epona_fix) { + gSaveContext.buttonStatus[EQUIP_SLOT_B] = BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B); + BUTTON_STATUS(EQUIP_SLOT_B) = BTN_DISABLED; + } else { + BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B) = ITEM_NONE; + } } else { Interface_LoadItemIconImpl(play, EQUIP_SLOT_B); } if (BUTTON_STATUS(EQUIP_SLOT_B) == BTN_DISABLED) { - BUTTON_STATUS(EQUIP_SLOT_B) = BTN_ENABLED; - restoreHudVisibility = true; + // @recomp_use_export_var no_bow_epona_fix: Don't enable the B button unless it is being used for the bow. + if (!no_bow_epona_fix || BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B) == ITEM_BOW) { + BUTTON_STATUS(EQUIP_SLOT_B) = BTN_ENABLED; + } + + // @recomp_use_export_var no_bow_epona_fix: Don't restore hud visibility from Epona without a sword. + if (!no_bow_epona_fix || (player->stateFlags1 & PLAYER_STATE1_800000) == 0) { + restoreHudVisibility = true; + } } - BUTTON_STATUS(EQUIP_SLOT_C_LEFT) = BTN_DISABLED; - BUTTON_STATUS(EQUIP_SLOT_C_DOWN) = BTN_DISABLED; - BUTTON_STATUS(EQUIP_SLOT_C_RIGHT) = BTN_DISABLED; - set_extra_item_slot_status(BTN_DISABLED); - Interface_SetHudVisibility(HUD_VISIBILITY_A_HEARTS_MAGIC_MINIMAP_WITH_OVERWRITE); + // @recomp_use_export_var no_bow_epona_fix: If the B button does not contain the bow, don't disable the UI. + if (!no_bow_epona_fix || BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B) == ITEM_BOW) { + BUTTON_STATUS(EQUIP_SLOT_C_LEFT) = BTN_DISABLED; + BUTTON_STATUS(EQUIP_SLOT_C_DOWN) = BTN_DISABLED; + BUTTON_STATUS(EQUIP_SLOT_C_RIGHT) = BTN_DISABLED; + set_extra_item_slot_status(BTN_DISABLED); + Interface_SetHudVisibility(HUD_VISIBILITY_A_HEARTS_MAGIC_MINIMAP_WITH_OVERWRITE); + } if (play->transitionMode != TRANS_MODE_OFF) { Interface_SetHudVisibility(HUD_VISIBILITY_NONE); @@ -802,6 +855,13 @@ RECOMP_PATCH void Interface_UpdateButtonsPart1(PlayState* play) { } } +bool fd_anywhere = false; + +// @recomp_export void recomp_set_fd_anywhere(bool new_val): Set whether the Fierce Deity's Mask has scene restrictions. +RECOMP_EXPORT void recomp_set_fd_anywhere(bool new_val) { + fd_anywhere = new_val; +} + /** * A continuation of the if-else chain from Interface_UpdateButtonsPart1 * Also used directly when opening the pause menu i.e. skips part 1 @@ -1181,7 +1241,8 @@ RECOMP_PATCH void Interface_UpdateButtonsPart2(PlayState* play) { } } else if (GET_CUR_FORM_BTN_ITEM(i) == ITEM_MASK_FIERCE_DEITY) { // Fierce Deity's Mask is equipped - if ((play->sceneId != SCENE_MITURIN_BS) && (play->sceneId != SCENE_HAKUGIN_BS) && + // @recomp_use_export_var fd_anywhere: Allow the player to use the Fierce Deity's Mask anywhere if mods enable it. + if (!fd_anywhere && (play->sceneId != SCENE_MITURIN_BS) && (play->sceneId != SCENE_HAKUGIN_BS) && (play->sceneId != SCENE_SEA_BS) && (play->sceneId != SCENE_INISIE_BS) && (play->sceneId != SCENE_LAST_BS)) { if (BUTTON_STATUS(i) != BTN_DISABLED) { From 0f924106203c2b2a0153acce151cdbc93b423a9f Mon Sep 17 00:00:00 2001 From: LittleCube Date: Mon, 14 Oct 2024 16:53:30 -0400 Subject: [PATCH 43/49] Add recomp_after_play_init event (#496) * fix signature for recomp_set_allow_no_ocarina_tf, add new event recomp_after_play_init * say initialize instead of construct --- patches/play_patches.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/patches/play_patches.c b/patches/play_patches.c index 1d38632..04f7b88 100644 --- a/patches/play_patches.c +++ b/patches/play_patches.c @@ -151,11 +151,12 @@ void DayTelop_Init_NORELOCATE(GameState*); void TitleSetup_Init_NORELOCATE(GameState*); RECOMP_DECLARE_EVENT(recomp_on_play_init(PlayState* this)); +RECOMP_DECLARE_EVENT(recomp_after_play_init(PlayState* this)); bool allow_no_ocarina_tf = false; -// @recomp_export void recomp_set_allow_no_ocarina(bool new_val): Set whether to force Termina Field to load normally even if Link has no ocarina. -RECOMP_EXPORT void recomp_set_allow_no_ocarina(bool new_val) { +// @recomp_export void recomp_set_allow_no_ocarina_tf(bool new_val): Set whether to force Termina Field to load normally even if Link has no ocarina. +RECOMP_EXPORT void recomp_set_allow_no_ocarina_tf(bool new_val) { allow_no_ocarina_tf = new_val; } @@ -171,7 +172,7 @@ RECOMP_PATCH void Play_Init(GameState* thisx) { u8 sceneLayer; s32 scene; - // @recomp_event recomp_on_play_init(PlayState* this): A new PlayState is being constructed. + // @recomp_event recomp_on_play_init(PlayState* this): A new PlayState is being initialized. recomp_on_play_init(this); if ((gSaveContext.respawnFlag == -4) || (gSaveContext.respawnFlag == -0x63)) { @@ -436,4 +437,7 @@ RECOMP_PATCH void Play_Init(GameState* thisx) { gSaveContext.respawnFlag = 0; sBombersNotebookOpen = false; BombersNotebook_Init(&sBombersNotebook); + + // @recomp_event recomp_after_play_init(PlayState* this): The new PlayState has finished initializing. + recomp_after_play_init(this); } From e862a38135a73fa7df4de31ac13257bb8c304dae Mon Sep 17 00:00:00 2001 From: LittleCube Date: Sun, 20 Oct 2024 19:35:41 -0400 Subject: [PATCH 44/49] More vanilla bug fix exports (#497) --- patches/input.c | 43 +++++++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/patches/input.c b/patches/input.c index f65d2cc..2962204 100644 --- a/patches/input.c +++ b/patches/input.c @@ -541,11 +541,24 @@ RECOMP_EXPORT void recomp_set_no_bow_epona_fix(bool new_val) { no_bow_epona_fix = new_val; } +bool h_and_d_no_sword_fix = false; + +// @recomp_export void recomp_set_h_and_d_no_sword_fix(bool new_val): Set whether to enable the fix for playing Honey and Darling without a sword. +RECOMP_EXPORT void recomp_set_h_and_d_no_sword_fix(bool new_val) { + h_and_d_no_sword_fix = new_val; +} + extern s16 sPictoState; extern s16 sPictoPhotoBeingTaken; extern void* gWorkBuffer; u16 func_801A5100(void); +#define ON_EPONA (player->stateFlags1 & PLAYER_STATE1_800000) +#define EPONA_FIX_ACTIVE (no_bow_epona_fix && ON_EPONA) + +#define AT_H_AND_D (play->sceneId == SCENE_BOWLING) +#define H_AND_D_FIX_ACTIVE (h_and_d_no_sword_fix && AT_H_AND_D) + // @recomp Patched to update status of extra buttons via set_extra_item_slot_status. RECOMP_PATCH void Interface_UpdateButtonsPart1(PlayState* play) { InterfaceContext* interfaceCtx = &play->interfaceCtx; @@ -555,11 +568,11 @@ RECOMP_PATCH void Interface_UpdateButtonsPart1(PlayState* play) { if (gSaveContext.save.cutsceneIndex < 0xFFF0) { gSaveContext.hudVisibilityForceButtonAlphasByStatus = false; - if ((player->stateFlags1 & PLAYER_STATE1_800000) || CHECK_WEEKEVENTREG(WEEKEVENTREG_08_01) || + if (ON_EPONA || CHECK_WEEKEVENTREG(WEEKEVENTREG_08_01) || (!CHECK_EVENTINF(EVENTINF_41) && (play->unk_1887C >= 2))) { // Riding Epona OR Honey & Darling minigame OR Horseback balloon minigame OR related to swamp boat // (non-minigame?) - if ((player->stateFlags1 & PLAYER_STATE1_800000) && (player->currentMask == PLAYER_MASK_BLAST) && + if (ON_EPONA && (player->currentMask == PLAYER_MASK_BLAST) && (gSaveContext.bButtonStatus == BTN_DISABLED)) { // Riding Epona with blast mask? restoreHudVisibility = true; @@ -611,7 +624,7 @@ RECOMP_PATCH void Interface_UpdateButtonsPart1(PlayState* play) { set_extra_item_slot_status(BTN_DISABLED); } else { // @recomp_use_export_var no_bow_epona_fix: Part of the no bow Epona fix. - if (no_bow_epona_fix) { + if (EPONA_FIX_ACTIVE) { if (gSaveContext.save.saveInfo.inventory.items[SLOT_BOW] == ITEM_BOW) { BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B) = ITEM_BOW; BUTTON_STATUS(EQUIP_SLOT_B) = BTN_ENABLED; @@ -624,7 +637,7 @@ RECOMP_PATCH void Interface_UpdateButtonsPart1(PlayState* play) { Interface_LoadItemIconImpl(play, EQUIP_SLOT_B); } else if (gSaveContext.save.saveInfo.inventory.items[SLOT_BOW] == ITEM_NONE) { // @recomp_use_export_var no_bow_epona_fix: Part of the no bow Epona fix. - if (no_bow_epona_fix) { + if (EPONA_FIX_ACTIVE) { gSaveContext.buttonStatus[EQUIP_SLOT_B] = BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B); BUTTON_STATUS(EQUIP_SLOT_B) = BTN_DISABLED; } else { @@ -635,7 +648,7 @@ RECOMP_PATCH void Interface_UpdateButtonsPart1(PlayState* play) { } // @recomp_use_export_var no_bow_epona_fix: If the B button does not contain a sword, don't disable the UI. - if (!no_bow_epona_fix || BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B) < ITEM_SWORD_KOKIRI || + if (!EPONA_FIX_ACTIVE || BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B) < ITEM_SWORD_KOKIRI || BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B) > ITEM_SWORD_GILDED) { BUTTON_STATUS(EQUIP_SLOT_C_LEFT) = BTN_DISABLED; BUTTON_STATUS(EQUIP_SLOT_C_DOWN) = BTN_DISABLED; @@ -669,12 +682,12 @@ RECOMP_PATCH void Interface_UpdateButtonsPart1(PlayState* play) { BUTTON_STATUS(EQUIP_SLOT_C_RIGHT) = BTN_DISABLED; set_extra_item_slot_status(BTN_DISABLED); Interface_SetHudVisibility(HUD_VISIBILITY_A_B_MINIMAP); - } else if (player->stateFlags1 & PLAYER_STATE1_800000) { + } else if (ON_EPONA) { Interface_SetHudVisibility(HUD_VISIBILITY_A_B_MINIMAP); } } } else { - if (player->stateFlags1 & PLAYER_STATE1_800000) { + if (ON_EPONA) { Interface_SetHudVisibility(HUD_VISIBILITY_A_B_MINIMAP); } @@ -686,13 +699,16 @@ RECOMP_PATCH void Interface_UpdateButtonsPart1(PlayState* play) { } else { BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B) = ITEM_BOW; } + if (h_and_d_no_sword_fix) { + BUTTON_STATUS(EQUIP_SLOT_B) = BTN_ENABLED; + } BUTTON_STATUS(EQUIP_SLOT_C_LEFT) = BTN_DISABLED; BUTTON_STATUS(EQUIP_SLOT_C_DOWN) = BTN_DISABLED; BUTTON_STATUS(EQUIP_SLOT_C_RIGHT) = BTN_DISABLED; set_extra_item_slot_status(BTN_DISABLED); } else { // @recomp_use_export_var no_bow_epona_fix: Part of the no bow Epona fix. - if (no_bow_epona_fix) { + if (EPONA_FIX_ACTIVE) { if (gSaveContext.save.saveInfo.inventory.items[SLOT_BOW] == ITEM_BOW) { BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B) = ITEM_BOW; BUTTON_STATUS(EQUIP_SLOT_B) = BTN_ENABLED; @@ -704,9 +720,9 @@ RECOMP_PATCH void Interface_UpdateButtonsPart1(PlayState* play) { if (play->unk_1887C >= 2) { Interface_LoadItemIconImpl(play, EQUIP_SLOT_B); - } else if (gSaveContext.save.saveInfo.inventory.items[SLOT_BOW] == ITEM_NONE) { + } else if (gSaveContext.save.saveInfo.inventory.items[SLOT_BOW] == ITEM_NONE && !H_AND_D_FIX_ACTIVE) { // @recomp_use_export_var no_bow_epona_fix: Part of the no bow Epona fix. - if (no_bow_epona_fix) { + if (EPONA_FIX_ACTIVE) { gSaveContext.buttonStatus[EQUIP_SLOT_B] = BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B); BUTTON_STATUS(EQUIP_SLOT_B) = BTN_DISABLED; } else { @@ -729,7 +745,7 @@ RECOMP_PATCH void Interface_UpdateButtonsPart1(PlayState* play) { } // @recomp_use_export_var no_bow_epona_fix: If the B button does not contain the bow, don't disable the UI. - if (!no_bow_epona_fix || BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B) == ITEM_BOW) { + if ((!no_bow_epona_fix || BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B) == ITEM_BOW) && !H_AND_D_FIX_ACTIVE) { BUTTON_STATUS(EQUIP_SLOT_C_LEFT) = BTN_DISABLED; BUTTON_STATUS(EQUIP_SLOT_C_DOWN) = BTN_DISABLED; BUTTON_STATUS(EQUIP_SLOT_C_RIGHT) = BTN_DISABLED; @@ -753,8 +769,11 @@ RECOMP_PATCH void Interface_UpdateButtonsPart1(PlayState* play) { BUTTON_STATUS(EQUIP_SLOT_C_RIGHT) = BTN_DISABLED; set_extra_item_slot_status(BTN_DISABLED); Interface_SetHudVisibility(HUD_VISIBILITY_A_B_MINIMAP); - } else if (player->stateFlags1 & PLAYER_STATE1_800000) { + } else if (ON_EPONA) { Interface_SetHudVisibility(HUD_VISIBILITY_A_B_MINIMAP); + } else if (H_AND_D_FIX_ACTIVE) { + Interface_LoadItemIconImpl(play, EQUIP_SLOT_B); + Interface_SetHudVisibility(HUD_VISIBILITY_B); } } } else if (sPictoState != PICTO_BOX_STATE_OFF) { From db4d9c668d7b9e3aa996c0ba4957df3326090134 Mon Sep 17 00:00:00 2001 From: Mr-Wiseguy Date: Mon, 21 Oct 2024 22:25:16 -0400 Subject: [PATCH 45/49] Update runtime for heap allocator --- lib/N64ModernRuntime | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/N64ModernRuntime b/lib/N64ModernRuntime index 9e9ae17..3e39c2e 160000 --- a/lib/N64ModernRuntime +++ b/lib/N64ModernRuntime @@ -1 +1 @@ -Subproject commit 9e9ae173ee2c378c6ff5f7bbfe452503a80212d9 +Subproject commit 3e39c2ec34340e245a5b7e353560b5a793b9990b From 323cf54888950496e7db69c14d9622b4b2fb71ac Mon Sep 17 00:00:00 2001 From: Mr-Wiseguy Date: Sun, 10 Nov 2024 14:55:16 -0500 Subject: [PATCH 46/49] Update RT64 for optimized ubershaders and update recomp runtime --- include/zelda_render.h | 1 - lib/N64ModernRuntime | 2 +- lib/rt64 | 2 +- src/main/main.cpp | 2 +- src/main/rt64_render_context.cpp | 10 ---------- 5 files changed, 3 insertions(+), 14 deletions(-) diff --git a/include/zelda_render.h b/include/zelda_render.h index 2d909e4..91820b2 100644 --- a/include/zelda_render.h +++ b/include/zelda_render.h @@ -29,7 +29,6 @@ namespace zelda64 { void shutdown() override; uint32_t get_display_framerate() const override; float get_resolution_scale() const override; - void load_shader_cache(std::span cache_binary) override; protected: std::unique_ptr app; diff --git a/lib/N64ModernRuntime b/lib/N64ModernRuntime index 3e39c2e..d5c81d0 160000 --- a/lib/N64ModernRuntime +++ b/lib/N64ModernRuntime @@ -1 +1 @@ -Subproject commit 3e39c2ec34340e245a5b7e353560b5a793b9990b +Subproject commit d5c81d0a6bf2e5f36747a095a7a060d7623bbf58 diff --git a/lib/rt64 b/lib/rt64 index 88c618c..c7e270c 160000 --- a/lib/rt64 +++ b/lib/rt64 @@ -1 +1 @@ -Subproject commit 88c618c1f8d8089f94e78537e49e0d77798fc0be +Subproject commit c7e270cf1588b7bbf73913d542ca5d40ee2728a2 diff --git a/src/main/main.cpp b/src/main/main.cpp index cbeb63a..bf13a28 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -331,6 +331,7 @@ std::vector supported_games = { .internal_name = "ZELDA MAJORA'S MASK", .game_id = u8"mm.n64.us.1.0", .mod_game_id = "mm", + .save_type = recomp::SaveType::Flashram, .is_enabled = true, .entrypoint_address = get_entrypoint_address(), .entrypoint = recomp_entrypoint, @@ -679,7 +680,6 @@ int main(int argc, char** argv) { printf("\n"); recomp::start( - 64 * 1024 * 1024, // 64MB to have plenty of room for loading mods project_version, {}, rsp_callbacks, diff --git a/src/main/rt64_render_context.cpp b/src/main/rt64_render_context.cpp index 8d5c735..e800d99 100644 --- a/src/main/rt64_render_context.cpp +++ b/src/main/rt64_render_context.cpp @@ -397,16 +397,6 @@ float zelda64::renderer::RT64Context::get_resolution_scale() const { } } -void zelda64::renderer::RT64Context::load_shader_cache(std::span cache_binary) { - // TODO figure out how to avoid a copy here. - std::istringstream cache_stream{std::string{cache_binary.data(), cache_binary.size()}}; - - if (!app->rasterShaderCache->loadOfflineList(cache_stream)) { - printf("Failed to preload shader cache!\n"); - assert(false); - } -} - RT64::UserConfiguration::Antialiasing zelda64::renderer::RT64MaxMSAA() { return device_max_msaa; } From 2ed55b4ff27c8e7ba16e1994085dd0d6bdb5e46e Mon Sep 17 00:00:00 2001 From: Mr-Wiseguy Date: Sun, 17 Nov 2024 20:54:10 -0500 Subject: [PATCH 47/49] Update RT64 for S2DEX replacements --- include/zelda_render.h | 2 +- lib/rt64 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/zelda_render.h b/include/zelda_render.h index 91820b2..0143471 100644 --- a/include/zelda_render.h +++ b/include/zelda_render.h @@ -14,7 +14,7 @@ namespace RT64 { namespace zelda64 { namespace renderer { - class RT64Context : public ultramodern::renderer::RendererContext { + class RT64Context final : public ultramodern::renderer::RendererContext { public: ~RT64Context() override; RT64Context(uint8_t *rdram, ultramodern::renderer::WindowHandle window_handle, bool developer_mode); diff --git a/lib/rt64 b/lib/rt64 index c7e270c..67422c3 160000 --- a/lib/rt64 +++ b/lib/rt64 @@ -1 +1 @@ -Subproject commit c7e270cf1588b7bbf73913d542ca5d40ee2728a2 +Subproject commit 67422c3b647058d3d38f2813a2abe79cf1638f13 From 552a82b3b010baaaa5a67bdfd85fcb6dab573136 Mon Sep 17 00:00:00 2001 From: danielryb <59661841+danielryb@users.noreply.github.com> Date: Thu, 21 Nov 2024 04:48:22 +0100 Subject: [PATCH 48/49] Add API function export for camera Z-targeting fixes (#503) --- patches/camera_patches.c | 108 ++++++++++++++++++++++++++++++++------- 1 file changed, 90 insertions(+), 18 deletions(-) diff --git a/patches/camera_patches.c b/patches/camera_patches.c index f0ae7e0..46e018f 100644 --- a/patches/camera_patches.c +++ b/patches/camera_patches.c @@ -9,6 +9,8 @@ #include "z64shrink_window.h" #include "z64player.h" +static bool camera_fixes = false; + static bool prev_analog_cam_active = false; static bool can_use_analog_cam = false; static bool analog_cam_active = false; @@ -26,6 +28,10 @@ float analog_camera_y_sensitivity = 500.0f; static const float analog_cam_threshold = 0.1f; +RECOMP_EXPORT void recomp_set_camera_fixes(bool new_val) { + camera_fixes = new_val; +} + void update_analog_camera_params(Camera* camera) { // recomp_printf("Camera at: %.2f %.2f %.2f\n" // " eye: %.2f %.2f %.2f\n" @@ -48,17 +54,17 @@ void update_analog_camera_params(Camera* camera) { void update_analog_cam(Camera* c) { can_use_analog_cam = true; - + Player* player = GET_PLAYER(c->play); // recomp_printf(" val: %d\n", func_80123434(player)); - + // Check if the player just started Z targeting and reset to auto cam if so. static bool prev_targeting_held = false; bool targeting_held = func_80123434(player) || player->lockOnActor != NULL; if (targeting_held && !prev_targeting_held) { analog_cam_active = false; } - + // Enable analog cam if the right stick is held. float input_x, input_y; recomp_get_camera_inputs(&input_x, &input_y); @@ -66,12 +72,12 @@ void update_analog_cam(Camera* c) { if (fabsf(input_x) >= analog_cam_threshold || fabsf(input_y) >= analog_cam_threshold) { analog_cam_active = true; } - + if (analog_cam_skip_once) { analog_cam_active = false; analog_cam_skip_once = false; } - + // Record the Z targeting state. prev_targeting_held = targeting_held; @@ -92,7 +98,7 @@ void update_analog_cam(Camera* c) { analog_camera_pos.pitch += analog_camera_pitch_vel; analog_camera_pos.yaw += analog_camera_yaw_vel; - + if (analog_camera_pos.pitch > 0x36B0) { analog_camera_pos.pitch = 0x36B0; } @@ -784,7 +790,7 @@ RECOMP_PATCH s32 Camera_Normal1(Camera* camera) { // @recomp Update the analog camera. if (recomp_analog_cam_enabled()) { update_analog_cam(camera); - + if (analog_cam_active) { spB4.pitch = analog_camera_pos.pitch; // spB4.r = analog_camera_pos.r; @@ -1017,14 +1023,14 @@ RECOMP_PATCH s32 Camera_Jump2(Camera* camera) { camera->pitchUpdateRateInv = 100.0f; camera->rUpdateRateInv = 100.0f; } - + spB4.pitch = CLAMP_MAX(spB4.pitch, DEG_TO_BINANG(60.43f)); spB4.pitch = CLAMP_MIN(spB4.pitch, -DEG_TO_BINANG(60.43f)); // @recomp Update the analog camera. if (recomp_analog_cam_enabled()) { update_analog_cam(camera); - + if (analog_cam_active) { spB4.pitch = analog_camera_pos.pitch; // spB4.r = analog_camera_pos.r; @@ -1064,6 +1070,10 @@ RECOMP_PATCH s32 Camera_Jump2(Camera* camera) { */ // @recomp Patched for analog cam. RECOMP_PATCH s32 Camera_Parallel1(Camera* camera) { + // @recomp + static bool prev_targeting_held = false; + bool isChargingDekuFlowerDive = !!(((Player*)camera->focalActor)->stateFlags3 & PLAYER_STATE3_100); + Vec3f* eye = &camera->eye; Vec3f* at = &camera->at; Vec3f* eyeNext = &camera->eyeNext; @@ -1089,6 +1099,10 @@ RECOMP_PATCH s32 Camera_Parallel1(Camera* camera) { CameraModeValue* values; f32 yNormal; + // @recomp Read timer4 from timer2. + s16 timer4 = rwData->timer2 >> 5; // @recomp Used to check if z-target can be quit. Mirrors timer2 values during z-target in unmodified function. + rwData->timer2 &= 0x001F; + if (!RELOAD_PARAMS(camera)) { } else { values = sCameraSettings[camera->setting].cameraModes[camera->mode].values; @@ -1151,6 +1165,8 @@ RECOMP_PATCH s32 Camera_Parallel1(Camera* camera) { rwData->timer2 = 20; } else { rwData->timer2 = 6; + // @recomp Initiate timer4 for z-target. + timer4 = 6; } if ((camera->focalActor == &GET_PLAYER(camera->play)->actor) && (camera->mode == CAM_MODE_CHARGE)) { @@ -1187,12 +1203,55 @@ RECOMP_PATCH s32 Camera_Parallel1(Camera* camera) { rwData->unk_26 = 1; camera->animState = 1; sCameraInterfaceFlags = roData->interfaceFlags; + + // @recomp Reset prev_targeting_held after transition. + prev_targeting_held = false; + break; } + // @recomp Change behavior for z-target only. + if (camera_fixes) { + if ((roData->interfaceFlags & (PARALLEL1_FLAG_3 | PARALLEL1_FLAG_2 | PARALLEL1_FLAG_1)) == PARALLEL1_FLAG_1) { + Player* player = GET_PLAYER(camera->play); + bool targeting_held = func_80123434(player) || player->lockOnActor != NULL; + + // @recomp Fix camera rotating with player if z-target gets released too fast after transition. + if ((targeting_held) && (!prev_targeting_held)) { + // @recomp Reset timer2 to avoid immediate rotation, if player presses, releases and presses z-target in a very short time-window. + rwData->timer2 = 6; + rwData->unk_1E = BINANG_ROT180(camera->focalActorPosRot.rot.y) + roData->unk_22; + } + + // @recomp Maintain vanilla behavior for quitting z-target. + if ((timer4 == 0) && (!targeting_held)) { + rwData->timer2 = 0; + } + + // @recomp Decrease timer4 only in cases where timer2 would be decreased. + if ((timer4 > 0) + && (rwData->timer3 <= 0)) { + timer4--; + } + + prev_targeting_held = targeting_held; + } + } + if (rwData->timer2 != 0) { switch (roData->interfaceFlags & (PARALLEL1_FLAG_3 | PARALLEL1_FLAG_2 | PARALLEL1_FLAG_1)) { case PARALLEL1_FLAG_1: + if (camera_fixes) { + // @recomp Fix camera rotating with player if z-target gets released too fast after transition. + if (isChargingDekuFlowerDive) { + // @recomp Fix camera wiggle during dive into deku flower. + rwData->unk_1E = BINANG_ROT180(camera->focalActorPosRot.rot.y) + roData->unk_22; + } + rwData->unk_20 = roData->unk_20; + break; + } + // @recomp fallthrough + case (PARALLEL1_FLAG_3 | PARALLEL1_FLAG_2 | PARALLEL1_FLAG_1): rwData->unk_1E = BINANG_ROT180(camera->focalActorPosRot.rot.y) + roData->unk_22; rwData->unk_20 = roData->unk_20; @@ -1374,7 +1433,7 @@ RECOMP_PATCH s32 Camera_Parallel1(Camera* camera) { // @recomp Update the analog camera. if (recomp_analog_cam_enabled()) { update_analog_cam(camera); - + if (analog_cam_active) { sp90.pitch = analog_camera_pos.pitch; // sp90.r = analog_camera_pos.r; @@ -1400,10 +1459,20 @@ RECOMP_PATCH s32 Camera_Parallel1(Camera* camera) { func_800CBFA4(camera, at, eye, 3); } - if (rwData->timer2 != 0) { - sUpdateCameraDirection = true; + if (camera_fixes) { + // @recomp Fix camera not updating input dir for the first few frames after transition. + if ((isChargingDekuFlowerDive) && (rwData->timer2 != 0)) { + // @recomp Fix camera wiggle during dive into deku flower. + sUpdateCameraDirection = true; + } else { + sUpdateCameraDirection = false; + } } else { - sUpdateCameraDirection = false; + if (rwData->timer2 != 0) { + sUpdateCameraDirection = true; + } else { + sUpdateCameraDirection = false; + } } } @@ -1412,6 +1481,9 @@ RECOMP_PATCH s32 Camera_Parallel1(Camera* camera) { camera->atLerpStepScale = Camera_ClampLerpScale(camera, sp72 ? roData->unk_1C : roData->unk_18); rwData->unk_26 &= ~1; + // @recomp Save timer4 in unused bits of timer2. + rwData->timer2 |= timer4 << 5; + return 1; } @@ -1580,11 +1652,11 @@ RECOMP_PATCH s32 Camera_Normal3(Camera* camera) { Camera_UnsetStateFlag(camera, CAM_STATE_DISABLE_MODE_CHANGE); } } - + // @recomp Update the analog camera. if (recomp_analog_cam_enabled()) { update_analog_cam(camera); - + if (analog_cam_active) { sp80.pitch = analog_camera_pos.pitch; // sp80.r = analog_camera_pos.r; @@ -1822,7 +1894,7 @@ RECOMP_PATCH s32 Camera_Jump3(Camera* camera) { // @recomp Update the analog camera. if (recomp_analog_cam_enabled()) { update_analog_cam(camera); - + if (analog_cam_active) { spAC.pitch = analog_camera_pos.pitch; // spAC.r = analog_camera_pos.r; @@ -1871,7 +1943,7 @@ void analog_cam_post_play_update(PlayState* play) { // recomp_printf("prev_analog_cam_active: %d can_use_analog_cam: %d\n", prev_analog_cam_active, can_use_analog_cam); // recomp_printf("setting: %d mode: %d func: %d\n", active_cam->setting, active_cam->mode, sCameraSettings[active_cam->setting].cameraModes[active_cam->mode].funcId); // recomp_printf("active cam yaw %d\n", Camera_GetInputDirYaw(GET_ACTIVE_CAM(play))); - + // Update parameters for the analog cam if the game is unpaused. if (play->pauseCtx.state == PAUSE_STATE_OFF && R_PAUSE_BG_PRERENDER_STATE == PAUSE_BG_PRERENDER_OFF) { update_analog_camera_params(active_cam); @@ -2056,7 +2128,7 @@ RECOMP_PATCH void func_809EC568(Boss04* this, PlayState* play) { if (this->unk_704 == 70) { this->unk_2C8 = 300; this->unk_2D0 = 0.0f; - + D_809EE4D0 = 1; this->unk_2E2 = 60; this->unk_2E0 = 93; From 1bbdbfacd2fb2e9c54d36e95b2bf000fb29f5ffa Mon Sep 17 00:00:00 2001 From: LT_SCHMIDDY Date: Sat, 23 Nov 2024 21:55:31 -0500 Subject: [PATCH 49/49] Added Recomp Events for before and after first-person aiming update. (#511) * Added Recomp Events for first-person aiming. * Mods can now force right-stick aiming. * Refactored aiming event code for formatting and clarity. --- patches/input.c | 50 +++++++++++++++++++++++++++++++++++------ patches/input.h | 7 ++++++ patches/input_latency.c | 5 ++++- 3 files changed, 54 insertions(+), 8 deletions(-) diff --git a/patches/input.c b/patches/input.c index 2962204..7812dc4 100644 --- a/patches/input.c +++ b/patches/input.c @@ -6,21 +6,35 @@ #include "z64voice.h" #include "audiothread_cmd.h" +RECOMP_DECLARE_EVENT(recomp_before_first_person_aiming_update_event(PlayState* play, Player* this, bool in_free_look, RecompAimingOverideMode* recomp_aiming_override_mode)); +RECOMP_DECLARE_EVENT(recomp_after_first_person_aiming_update_event(PlayState* play, Player* this, bool in_free_look)); + s32 func_80847190(PlayState* play, Player* this, s32 arg2); s16 func_80832754(Player* this, s32 arg1); s32 func_8082EF20(Player* this); +// This flag is reset every frame by 'poll_inputs()'. +RecompAimingOverideMode recomp_aiming_override_mode = RECOMP_AIMING_OVERRIDE_OFF; + // @recomp Patched to add gyro and mouse aiming. RECOMP_PATCH s32 func_80847190(PlayState* play, Player* this, s32 arg2) { s32 pad; s16 var_s0; + + // Checks if we're in free look (C-Up look around mode). + bool in_free_look = (!func_800B7128(this) && !func_8082EF20(this) && !arg2); + + // Checking if any mods have disabled aiming with the left stick. + recomp_before_first_person_aiming_update_event(play, this, in_free_look, &recomp_aiming_override_mode); + // @recomp Get the aiming camera inversion state. s32 inverted_x, inverted_y; recomp_get_inverted_axes(&inverted_x, &inverted_y); - // @recomp Get the analog camera input values if analog cam is enabled. + + // @recomp Get the analog camera input values if analog cam is enabled, or right-stick aiming is being forced. s32 analog_x = 0; s32 analog_y = 0; - if (recomp_analog_cam_enabled()) { + if (recomp_analog_cam_enabled() || recomp_aiming_override_mode == RECOMP_AIMING_OVERRIDE_FORCE_RIGHT_STICK) { float analog_x_float = 0.0f; float analog_y_float = 0.0f; recomp_get_camera_inputs(&analog_x_float, &analog_y_float); @@ -35,9 +49,13 @@ RECOMP_PATCH s32 func_80847190(PlayState* play, Player* this, s32 arg2) { // play->state.input[0].rel.stick_x, play->state.input[0].rel.stick_y, // analog_x, analog_y); - if (!func_800B7128(this) && !func_8082EF20(this) && !arg2) { + if (in_free_look) { // @recomp Add in the analog camera Y input. Clamp to prevent moving the camera twice as fast if both sticks are held. - var_s0 = CLAMP(play->state.input[0].rel.stick_y + analog_y, -61, 61) * 0xF0; + s32 cam_input_y = analog_y; + if (recomp_aiming_override_mode == RECOMP_AIMING_OVERRIDE_OFF) { + cam_input_y += play->state.input[0].rel.stick_y; + } + var_s0 = CLAMP(cam_input_y, -61, 61) * 0xF0; // @recomp Invert the Y axis accordingly (default is inverted, so negate if not inverted). if (!inverted_y) { @@ -46,7 +64,11 @@ RECOMP_PATCH s32 func_80847190(PlayState* play, Player* this, s32 arg2) { Math_SmoothStepToS(&this->actor.focus.rot.x, var_s0, 0xE, 0xFA0, 0x1E); // @recomp Add in the analog camera X input. Clamp to prevent moving the camera twice as fast if both sticks are held. - var_s0 = CLAMP(play->state.input[0].rel.stick_x + analog_x, -61, 61) * -0x10; + s32 cam_input_x = analog_x; + if (recomp_aiming_override_mode == RECOMP_AIMING_OVERRIDE_OFF) { + cam_input_x += play->state.input[0].rel.stick_x; + } + var_s0 = CLAMP(cam_input_x, -61, 61) * -0x10; // @recomp Invert the X axis accordingly if (inverted_x) { @@ -97,7 +119,13 @@ RECOMP_PATCH s32 func_80847190(PlayState* play, Player* this, s32 arg2) { // @recomp Invert the Y axis accordingly (default is inverted, so negate if not inverted). // Also add in the analog camera Y input. Clamp to prevent moving the camera twice as fast if both sticks are held. - s32 stick_y = CLAMP(play->state.input[0].rel.stick_y + analog_y, -61, 61); + s32 cam_input_y = analog_y; + if (recomp_aiming_override_mode == RECOMP_AIMING_OVERRIDE_OFF) { + cam_input_y += play->state.input[0].rel.stick_y; + } + s32 stick_y; + stick_y = CLAMP(cam_input_y, -61, 61); + if (!inverted_y) { stick_y = -stick_y; } @@ -118,7 +146,13 @@ RECOMP_PATCH s32 func_80847190(PlayState* play, Player* this, s32 arg2) { // @recomp Invert the X axis accordingly. Also add in the analog camera Y input. // Clamp to prevent moving the camera twice as fast if both sticks are held. - s32 stick_x = CLAMP(play->state.input[0].rel.stick_x + analog_x, -61, 61); + s32 cam_input_x = analog_x; + if (recomp_aiming_override_mode == RECOMP_AIMING_OVERRIDE_OFF) { + cam_input_x += play->state.input[0].rel.stick_x; + } + s32 stick_x; + stick_x = CLAMP(cam_input_x, -61, 61); + if (inverted_x) { stick_x = -stick_x; } @@ -130,6 +164,8 @@ RECOMP_PATCH s32 func_80847190(PlayState* play, Player* this, s32 arg2) { this->actor.focus.rot.y = CLAMP(var_s0, -0x4AAA, 0x4AAA) + this->actor.shape.rot.y; } + recomp_after_first_person_aiming_update_event(play, this, in_free_look); + this->unk_AA6 |= 2; return func_80832754(this, (play->unk_1887C != 0) || func_800B7128(this) || func_8082EF20(this)); diff --git a/patches/input.h b/patches/input.h index 0f00e36..efb4443 100644 --- a/patches/input.h +++ b/patches/input.h @@ -8,7 +8,14 @@ typedef enum { RECOMP_CAMERA_DUALANALOG, } RecompCameraMode; +typedef enum { + RECOMP_AIMING_OVERRIDE_OFF = 0, + RECOMP_AIMING_OVERRIDE_DISABLE_LEFT_STICK = 1, + RECOMP_AIMING_OVERRIDE_FORCE_RIGHT_STICK = 2 +} RecompAimingOverideMode; + extern RecompCameraMode recomp_camera_mode; +extern RecompAimingOverideMode recomp_aiming_override_mode; DECLARE_FUNC(void, recomp_get_gyro_deltas, float* x, float* y); DECLARE_FUNC(void, recomp_get_mouse_deltas, float* x, float* y); diff --git a/patches/input_latency.c b/patches/input_latency.c index 8007c6a..b5974f9 100644 --- a/patches/input_latency.c +++ b/patches/input_latency.c @@ -70,8 +70,11 @@ void poll_inputs(void) { // Begin reading controller data osContStartReadData(serialEventQueue); + bool needs_right_stick = recomp_analog_cam_enabled() || recomp_aiming_override_mode == RECOMP_AIMING_OVERRIDE_FORCE_RIGHT_STICK; // Suppress the right analog stick if analog camera is active unless the ocarina is in use. - recomp_set_right_analog_suppressed(recomp_analog_cam_enabled() && sOcarinaInstrumentId == OCARINA_INSTRUMENT_OFF); + recomp_set_right_analog_suppressed(needs_right_stick && sOcarinaInstrumentId == OCARINA_INSTRUMENT_OFF); + // Resets this flag for the next frame; + recomp_aiming_override_mode = RECOMP_AIMING_OVERRIDE_OFF; // Wait for controller data osRecvMesg(serialEventQueue, NULL, OS_MESG_BLOCK);