diff --git a/CREDITS.md b/CREDITS.md index a2579151d1..9d8cd0ef6d 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -289,6 +289,7 @@ This page lists all the individual contributions to the project by their author. - Guard range customizations - Wall overlay unit sell exploit fix - Fix vehicles disguised as trees incorrectly displaying veterancy insignia when they shouldn't + - GapGen + SpySat desync fix - **Morton (MortonPL)**: - `XDrawOffset` for animations - Shield passthrough & absorption diff --git a/docs/Fixed-or-Improved-Logics.md b/docs/Fixed-or-Improved-Logics.md index 69a21a62df..5b27cb345b 100644 --- a/docs/Fixed-or-Improved-Logics.md +++ b/docs/Fixed-or-Improved-Logics.md @@ -307,6 +307,7 @@ This page describes all ingame logics that are fixed or improved in Phobos witho - Fixed the bug that `DeploysInto` and `UndeploysInto` will make damaged techno lose 1 health - Fixed rare cases where paradropped techno killed by falling down. - Fixed the issue that the Jumpjet must end its movement before starting the next mission. +- Fixed a desync due to an inconsistent shroud state caused by `GapGenerator` and `SpySat` interaction. ## Fixes / interactions with other extensions diff --git a/docs/Whats-New.md b/docs/Whats-New.md index 9ff161a340..23882224d0 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -656,6 +656,7 @@ Fixes / interactions with other extensions: Vanilla fixes: - Vehicles overlapping `Wall=true` OverlayTypes no longer display sell cursor and cannot be sold (by CnCRAZER & Starkku) +- Fixed a desync due to an inconsistent shroud state caused by `GapGenerator` and `SpySat` interaction (by Starkku) Phobos fixes: - Fixed vehicles disguised as trees incorrectly displaying veterancy insignia when they shouldn't (by Starkku) diff --git a/src/Misc/Hooks.BugFixes.cpp b/src/Misc/Hooks.BugFixes.cpp index 4c34158b30..eb5c49e4f1 100644 --- a/src/Misc/Hooks.BugFixes.cpp +++ b/src/Misc/Hooks.BugFixes.cpp @@ -3164,3 +3164,92 @@ DEFINE_HOOK(0x7442AB, UnitClass_ReadyToNextMission_FallingDown, 0x6) GET(FootClass*, pThis, ESI); return pThis->IsFallingDown ? ReturnZero : 0; } + +#pragma region ShroudFix + +// These map cells are what SpySat skips revealing in MP normally. +static bool inline ShroudFix_IsCellInvalid(CellStruct* pMapCell) +{ + int x = pMapCell->X; + int y = pMapCell->Y; + auto const& rect = MapClass::Instance.MapRect; + + if (x == 7 && y == rect.Width + 5) + return true; + + if (x == 13 && y == rect.Width + 11) + return true; + + if (x == rect.Height + 13 && y == rect.Width + rect.Height -15 ) + return true; + + return false; +} + +DEFINE_HOOK(0x6FB5E5, TechnoClass_DeleteGap_CellCheck, 0x5) +{ + enum { SkipCell = 0x6FB6F3 }; + + GET(CellStruct*, pMapCell, EDX); + + if (ShroudFix_IsCellInvalid(pMapCell)) + return SkipCell; + + return 0; +} + +DEFINE_HOOK(0x6FB2FB, TechnoClass_CreateGap_CellCheck, 0x5) +{ + enum { SkipCell = 0x6FB416 }; + + GET(CellStruct*, pMapCell, EDX); + + if (ShroudFix_IsCellInvalid(pMapCell)) + return SkipCell; + + return 0; +} + +// Replace the entire cell iterator loop for perf reasons. +DEFINE_HOOK(0x577AFF, MapClass_ResetShroud_CellCheck, 0x6) +{ + enum { SkipGameCode = 0x577B75 }; + + auto& map = MapClass::Instance; + map.CellIteratorReset(); + + for (auto pCell = map.CellIteratorNext(); pCell; pCell = map.CellIteratorNext()) + { + if (ShroudFix_IsCellInvalid(&pCell->MapCoords)) + continue; + + pCell->Flags &= ~(CellFlags::CenterRevealed | CellFlags::EdgeRevealed); + pCell->AltFlags &= ~(AltCellFlags::Mapped | AltCellFlags::NoFog); + pCell->ShroudCounter = 1; + pCell->GapsCoveringThisCell = 0; + } + + return SkipGameCode; +} + +// Replace the entire cell iterator loop for perf reasons. +DEFINE_HOOK(0x577BF1, MapClass_ResetShroudForTMission_CellCheck, 0x6) +{ + enum { SkipGameCode = 0x577C57 }; + + auto& map = MapClass::Instance; + map.CellIteratorReset(); + + for (auto pCell = map.CellIteratorNext(); pCell; pCell = map.CellIteratorNext()) + { + if (ShroudFix_IsCellInvalid(&pCell->MapCoords)) + continue; + + pCell->Flags &= ~(CellFlags::CenterRevealed | CellFlags::EdgeRevealed); + pCell->AltFlags &= ~(AltCellFlags::Mapped | AltCellFlags::NoFog); + } + + return SkipGameCode; +} + +#pragma endregion diff --git a/src/Phobos.cpp b/src/Phobos.cpp index c061b50170..60ce544c2f 100644 --- a/src/Phobos.cpp +++ b/src/Phobos.cpp @@ -271,6 +271,18 @@ void Phobos::ApplyOptimizations() if (!SessionClass::IsMultiplayer()) { + // Disable TechnoClass_DeleteGap_CellCheck + Patch::Apply_RAW(0x6FB5E5, { 0xB9, 0xE8, 0xF7, 0x87, 0x00 }); + + // Disable TechnoClass_CreateGap_CellCheck + Patch::Apply_RAW(0x6FB2FB, { 0xB9, 0xE8, 0xF7, 0x87, 0x00 }); + + // Disable MapClass_ResetShroud_CellCheck + Patch::Apply_RAW(0x577AFF, { 0x8B, 0x86, 0xF4, 0x00, 0x00, 0x00 }); + + // Disable MapClass_ResetShroudForTMission_CellCheck + Patch::Apply_RAW(0x577BF1, { 0x8B, 0x86, 0xF4, 0x00, 0x00, 0x00 }); + // Disable Random2Class_Random_SyncLog Patch::Apply_RAW(0x65C7D0, { 0xC3, 0x90, 0x90, 0x90, 0x90 });