ember_movie_ui.cpp 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647
  1. #include "internal.h"
  2. #include "../ember_movies/ember_movies.h"
  3. #include "../ember_movies/playback_rules.h"
  4. #include "../../../core/logging/log.h"
  5. namespace sunrise::client::hooks::bootflow {
  6. namespace {
  7. hooking::detour::Handle handle{};
  8. using SelectState=bool(__fastcall*)(void*,int);
  9. bool __fastcall select_state(void* ui,int requested) noexcept {
  10. // E2EAE0 selects 22h when a cinematic is active and C4C070 is false.
  11. // The movie component's D8 callback is DD1D10 (false), so this is its
  12. // native presentation state. E1CD60 owns window/category transitions.
  13. // Preserve loading/error/menu requests; substitute only normal gameplay.
  14. const int selected=ember_movies::movie_ui_state(requested,ember_movies::presenting());
  15. auto original=reinterpret_cast<SelectState>(handle.original);
  16. if (!original) return false;
  17. const bool result=original(ui,selected);
  18. static bool wasCinematic{};
  19. const bool cinematic=selected!=requested;
  20. if (cinematic!=wasCinematic) {
  21. core::log::writef(core::log::Channel::client,core::log::Level::info,
  22. "ev=ember_movie result=presentation_state requested=%d selected=%d applied=%d category=%d",
  23. requested,selected,*reinterpret_cast<int*>(static_cast<std::byte*>(ui)+0x204),
  24. *reinterpret_cast<int*>(static_cast<std::byte*>(ui)+0x200));
  25. wasCinematic=cinematic;
  26. }
  27. return result;
  28. }
  29. }
  30. StageResult stage_ember_movie_ui(hooking::detour::Spec& spec) noexcept {
  31. if (handle.attached) return StageResult::attached;
  32. constexpr auto sig=signature<signature_length("40 55 53 57 41 54 41 55 41 57 48 8D AC 24 08 FD FF FF 48 81 EC F8 03 00 00 48 8B 05 ? ? ? ? 48 33 C4 48 89 85 E0 02 00 00 4C 8B E9 8B DA")>(
  33. "40 55 53 57 41 54 41 55 41 57 48 8D AC 24 08 FD FF FF 48 81 EC F8 03 00 00 48 8B 05 ? ? ? ? 48 33 C4 48 89 85 E0 02 00 00 4C 8B E9 8B DA");
  34. auto* target=scan_main_image_unique(sig,"ember_movie_presentation_state");
  35. if (!target) return StageResult::unavailable;
  36. spec={target,reinterpret_cast<void*>(&select_state)};return StageResult::staged;
  37. }
  38. void publish_ember_movie_ui(const hooking::detour::Handle& value) noexcept {
  39. handle=value;ember_movies::ui_ready(value.attached);
  40. core::log::write(core::log::Channel::client,core::log::Level::info,
  41. value.attached ? "ev=ember_movie result=presentation_attached" : "ev=ember_movie result=presentation_attach_failed");
  42. }
  43. void uninstall_ember_movie_ui() noexcept {
  44. ember_movies::ui_ready(false);
  45. static_cast<void>(hooking::detour::uninstall(handle));
  46. }
  47. }