From b2c09d56d6551d74f6b6654098f24b1afd03d1a7 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Fri, 24 Apr 2026 13:34:51 -0600 Subject: [PATCH 1/7] Remove unnecessary logic from dMirror_packet_c::entryModel --- src/d/actor/d_a_mirror.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/d/actor/d_a_mirror.cpp b/src/d/actor/d_a_mirror.cpp index 746f32a9f6..86ef4314f3 100644 --- a/src/d/actor/d_a_mirror.cpp +++ b/src/d/actor/d_a_mirror.cpp @@ -84,13 +84,6 @@ void dMirror_packet_c::calcMinMax() { } int dMirror_packet_c::entryModel(J3DModel* i_model) { -#if TARGET_PC - if (mbReset) { - mModelCount = 0; - mbReset = false; - } -#endif - if (mModelCount >= 0x40) { return 0; } From 171dbdd0a14b46b5baebfd3f6ad929547a0cce92 Mon Sep 17 00:00:00 2001 From: roeming Date: Fri, 24 Apr 2026 16:50:31 -0400 Subject: [PATCH 2/7] Implement custom sorting when sorting event flags by flag on/off --- src/dusk/imgui/ImGuiSaveEditor.cpp | 96 +++++++++++++++++++++++------- 1 file changed, 76 insertions(+), 20 deletions(-) diff --git a/src/dusk/imgui/ImGuiSaveEditor.cpp b/src/dusk/imgui/ImGuiSaveEditor.cpp index eced44c7f7..cc89d37275 100644 --- a/src/dusk/imgui/ImGuiSaveEditor.cpp +++ b/src/dusk/imgui/ImGuiSaveEditor.cpp @@ -1347,6 +1347,51 @@ namespace dusk { } } + template + concept FlagIter = requires(T t) { + ++t; + --t; + t + 1; + t < t; + { t->flagID } -> std::convertible_to; + }; + + template + concept FlagTester = requires(T t, u16 flagID) { + { t(flagID) } -> std::convertible_to; + }; + + static void sortByFlags(FlagIter auto begin, FlagIter auto end, FlagTester auto&& flagTester) { + if (begin == end) return; + + FlagIter auto fullEnd = end; + + // We want to find the location of where we can swap our `On` flags to. + // We're gonna put the `Off` bits first, and the `On` bits last. 0 < 1 + // We can achieve this by skipping all the `On` bits at the end. + + // backtrack until we find a bit that is off + while (begin < --end && flagTester(end->flagID)) { + // move the end pointer back while we find on bits + } + + // end should now be pointing to a bit that is off + while (begin < end) { + // if there's a flag that's on + if (flagTester(begin->flagID)) { + // move it to the end + std::rotate(begin, begin + 1, fullEnd); + // move back the end of where we're checking + --end; + // begin will now point to the next piece of data + // because we've rotated the data >= begin to the left + } else { + // not on, check next flag + ++begin; + } + } + } + void ImGuiSaveEditor::drawFlagsTab() { if (ImGui::TreeNode("Current Region Flags")) { dSv_memBit_c& membit = g_dComIfG_gameInfo.info.mMemory.mBit; @@ -1446,30 +1491,41 @@ namespace dusk { sort != nullptr && sort->SpecsCount > 0 && (sort->SpecsDirty || sort->Specs[0].ColumnIndex == COLUMN_FLAG)) { - auto column = sort->Specs->ColumnIndex; - const auto cmp = [&](const duskImguiEventFlagEntry& l, - const duskImguiEventFlagEntry& r) -> bool { - switch (column) { - case COLUMN_FLAG: - return (bool)event.isEventBit(l.flagID) < - (bool)event.isEventBit(r.flagID); - case COLUMN_NAME: - return l.flagName < r.flagName; - case COLUMN_LOC: - return l.location < r.location; - case COLUMN_DESC: - return l.description < r.description; - } - return false; - }; - + const auto column = sort->Specs[0].ColumnIndex; const auto direction = sort->Specs[0].SortDirection; - if (direction == ImGuiSortDirection_Ascending) { - std::sort(std::begin(duskImguiEventFlags), std::end(duskImguiEventFlags), cmp); + // if we're sorting by flags, do special sort, regular sort is bad for sorting bools + // it can swap values that are the same, and that causes constant reordering + if (column == COLUMN_FLAG) { + const auto testEventFunc = [&event](u16 flag) -> bool { return event.isEventBit(flag); }; + + if (direction == ImGuiSortDirection_Ascending) { + sortByFlags(std::begin(duskImguiEventFlags), + std::end(duskImguiEventFlags), testEventFunc); + } else { + sortByFlags(std::rbegin(duskImguiEventFlags), + std::rend(duskImguiEventFlags), testEventFunc); + } } else { - std::sort(std::rbegin(duskImguiEventFlags), std::rend(duskImguiEventFlags), cmp); + const auto cmp = [column](const duskImguiEventFlagEntry& l, + const duskImguiEventFlagEntry& r) -> bool { + switch (column) { + case COLUMN_NAME: return l.flagName < r.flagName; + case COLUMN_LOC: return l.location < r.location; + case COLUMN_DESC: return l.description < r.description; + default: return false; + } + }; + + if (direction == ImGuiSortDirection_Ascending) { + std::sort(std::begin(duskImguiEventFlags), + std::end(duskImguiEventFlags), cmp); + } else { + std::sort(std::rbegin(duskImguiEventFlags), + std::rend(duskImguiEventFlags), cmp); + } } + sort->SpecsDirty = false; } From d5aabe9f9ed2a13d275413cca114bf4b99c929b1 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Fri, 24 Apr 2026 18:06:02 -0400 Subject: [PATCH 3/7] Even faster tears to match TPHD --- src/d/actor/d_a_obj_drop.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/d/actor/d_a_obj_drop.cpp b/src/d/actor/d_a_obj_drop.cpp index 275a3d6e12..2b373c1e64 100644 --- a/src/d/actor/d_a_obj_drop.cpp +++ b/src/d/actor/d_a_obj_drop.cpp @@ -265,7 +265,7 @@ int daObjDrop_c::modeParentWait() { mModeAction = 1; #if TARGET_PC - mModeTimer = dusk::getSettings().game.fastTears && dComIfGp_event_getMode() == 0 ? 20 : 40; + mModeTimer = dusk::getSettings().game.fastTears && dComIfGp_event_getMode() == 0 ? 0 : 40; if (dusk::getSettings().game.fastTears && dComIfGp_event_getMode() == 0) { current.pos.y += 100.0f; } else { @@ -285,7 +285,7 @@ int daObjDrop_c::modeParentWait() { case 2: createBodyEffect(); #if TARGET_PC - mModeTimer = dusk::getSettings().game.fastTears && dComIfGp_event_getMode() == 0 ? 5 : 45; + mModeTimer = dusk::getSettings().game.fastTears && dComIfGp_event_getMode() == 0 ? 0 : 45; #else mModeTimer = 45; #endif From 274bf61b3ea216ec4f3e0db0610d8858e9d9420e Mon Sep 17 00:00:00 2001 From: Irastris Date: Fri, 24 Apr 2026 22:56:47 -0400 Subject: [PATCH 4/7] Fix Link's hands detaching when interp is enabled --- src/d/actor/d_a_alink.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/d/actor/d_a_alink.cpp b/src/d/actor/d_a_alink.cpp index e6943baf96..4fea05cd53 100644 --- a/src/d/actor/d_a_alink.cpp +++ b/src/d/actor/d_a_alink.cpp @@ -18936,11 +18936,20 @@ void daAlink_c::setDrawHand() { mpLinkHandModel->setBaseTRMtx(mpLinkModel->getBaseTRMtx()); mpLinkHandModel->calc(); +#if TARGET_PC + // FRAME INTERP NOTE: Always set these, otherwise the hands occasionally zip to origin. + // Doing it regardless of interpolation being active seems harmless. + mpLinkHandModel->setAnmMtx(1, mpLinkModel->getAnmMtx(9)); + mpLinkHandModel->setAnmMtx(2, mpLinkModel->getAnmMtx(0xE)); +#endif + if (var_r30 == 0xFE || var_r30 == 0xFB) { field_0x06d0 = field_0x06d8; } else { field_0x06d0 = mpLinkHandModel->getModelData()->getMaterialNodePointer(var_r30)->getShape(); +#if !TARGET_PC mpLinkHandModel->setAnmMtx(1, mpLinkModel->getAnmMtx(9)); +#endif } if (var_r30 == 0xFB) { @@ -18959,7 +18968,9 @@ void daAlink_c::setDrawHand() { field_0x06d4 = field_0x06dc; } else { field_0x06d4 = mpLinkHandModel->getModelData()->getMaterialNodePointer(var_r29)->getShape(); +#if !TARGET_PC mpLinkHandModel->setAnmMtx(2, mpLinkModel->getAnmMtx(0xE)); +#endif } if (var_r29 == 0xFB) { From c61e32cd4fd52af7495fc9366fae7c2f86c81384 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Fri, 24 Apr 2026 22:10:56 -0600 Subject: [PATCH 5/7] Update aurora for GXPeekZ Resolves #281 Resolves #468 --- extern/aurora | 2 +- src/dusk/stubs.cpp | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/extern/aurora b/extern/aurora index 9ff83bcb97..8d9618dc4b 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit 9ff83bcb9718391a25c3c5ffa1faf470effb1c86 +Subproject commit 8d9618dc4bd82e476754c5b841b85fba6ee6ddab diff --git a/src/dusk/stubs.cpp b/src/dusk/stubs.cpp index 07e420445c..c6832d2cac 100644 --- a/src/dusk/stubs.cpp +++ b/src/dusk/stubs.cpp @@ -1020,10 +1020,6 @@ void GXInitTexCacheRegion(GXTexRegion* region, GXBool is_32b_mipmap, u32 tmem_ev // XXX, this should be some struct? // GXRenderModeObj GXNtsc480IntDf; //GXRenderModeObj GXNtsc480Int; -void GXPeekZ(u16 x, u16 y, u32* z) { - STUB_LOG(); - *z = 0; -} void GXReadXfRasMetric(u32* xf_wait_in, u32* xf_wait_out, u32* ras_busy, u32* clocks) { STUB_LOG(); *xf_wait_in = 0; From c8e89a0f998b88bf464aeabfc3913c4af6675a46 Mon Sep 17 00:00:00 2001 From: Irastris Date: Sat, 25 Apr 2026 00:31:37 -0400 Subject: [PATCH 6/7] Fix grass cutting when interp is enabled --- src/d/d_particle.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/d/d_particle.cpp b/src/d/d_particle.cpp index 248424e9a2..9b89afc7b1 100644 --- a/src/d/d_particle.cpp +++ b/src/d/d_particle.cpp @@ -1972,7 +1972,12 @@ void dPa_light8PcallBack::draw(JPABaseEmitter* param_1, JPABaseParticle* param_2 JGeometry::TVec3 local_154; JGeometry::TVec3 local_160; JGeometry::TVec3 local_16c; - dPa_setWindPower(param_2); +#if TARGET_PC + if (dusk::frame_interp::is_sim_frame()) +#endif + { + dPa_setWindPower(param_2); + } MTXIdentity(local_60); MTXIdentity(auStack_90); param_2->getBaseAxis(&local_10c); From 4e264d6a22d98835d62b3c29cb48376e9a88adaa Mon Sep 17 00:00:00 2001 From: Luke Street Date: Fri, 24 Apr 2026 22:53:41 -0600 Subject: [PATCH 7/7] Fix Zbuffer texture binding Resolves #511 --- src/d/d_resorce.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/d/d_resorce.cpp b/src/d/d_resorce.cpp index 73f031beae..bb982c4afb 100644 --- a/src/d/d_resorce.cpp +++ b/src/d/d_resorce.cpp @@ -102,11 +102,7 @@ static void setIndirectTex(J3DModelData* i_modelData) { texture->setResTIMG(i, *mDoGph_gInf_c::getFrameBufferTimg()); } if (memcmp(textureName, "Zbuffer", 8) == 0) { -#if !TARGET_PC texture->setResTIMG(i, *mDoGph_gInf_c::getZbufferTimg()); -#else - DuskLog.warn("Zbuffer texture binding not yet supported"); -#endif } } }