From e62781367a94d940324216bb2f528581a47a02c2 Mon Sep 17 00:00:00 2001 From: Liam Date: Sun, 7 Jan 2024 22:19:18 -0500 Subject: [PATCH] Fix ARR title screens and detect title/lobby more reliably --- TitleEdit/GameLobbyType.cs | 13 ++++ TitleEdit/TitleEdit.cs | 93 +++++++++++---------------- TitleEdit/TitleEdit.csproj | 2 +- TitleEdit/TitleEditAddressResolver.cs | 20 ++++++ 4 files changed, 72 insertions(+), 56 deletions(-) create mode 100644 TitleEdit/GameLobbyType.cs diff --git a/TitleEdit/GameLobbyType.cs b/TitleEdit/GameLobbyType.cs new file mode 100644 index 0000000..83f3882 --- /dev/null +++ b/TitleEdit/GameLobbyType.cs @@ -0,0 +1,13 @@ +namespace TitleEdit; + +public enum GameLobbyType +{ + Movie = -1, + Title = 0, + CharaSelect = 1, + Aetherial = 2, + LaNoscea = 3, + BlackShroud = 4, + Thanalan = 5, + Residence = 6, +} \ No newline at end of file diff --git a/TitleEdit/TitleEdit.cs b/TitleEdit/TitleEdit.cs index 7165819..024c92a 100644 --- a/TitleEdit/TitleEdit.cs +++ b/TitleEdit/TitleEdit.cs @@ -25,6 +25,7 @@ private delegate IntPtr OnFixOn(IntPtr self, private delegate ulong OnLoadLogoResource(IntPtr p1, string p2, int p3, int p4); private delegate IntPtr OnPlayMusic(IntPtr self, string filename, float volume, uint fadeTime); private delegate void SetTimePrototype(ushort timeOffset); + private delegate byte LobbyUpdate(GameLobbyType mapId, int time); // The size of the BGMControl object private const int ControlSize = 88; @@ -34,13 +35,14 @@ private delegate IntPtr OnFixOn(IntPtr self, private readonly Hook _playMusicHook; private readonly Hook _fixOnHook; private readonly Hook _loadLogoResourceHook; - + private readonly Hook _lobbyUpdateHook; private readonly SetTimePrototype _setTime; private readonly string _titleScreenBasePath; private bool _titleCameraNeedsSet; private bool _amForcingTime; private bool _amForcingWeather; + private GameLobbyType _lastLobbyUpdateMapId = GameLobbyType.Movie; private TitleEditScreen _currentScreen; @@ -72,10 +74,37 @@ public TitleEdit(TitleEditConfiguration configuration, string screenDir) _fixOnHook = DalamudApi.Hooks.HookFromAddress(TitleEditAddressResolver.FixOn, HandleFixOn); _loadLogoResourceHook = DalamudApi.Hooks.HookFromAddress(TitleEditAddressResolver.LoadLogoResource, HandleLoadLogoResource); + _lobbyUpdateHook = DalamudApi.Hooks.HookFromAddress(TitleEditAddressResolver.LobbyUpdate, LobbyUpdateDetour); _setTime = Marshal.GetDelegateForFunctionPointer(TitleEditAddressResolver.SetTime); DalamudApi.PluginLog.Info("TitleEdit hook init finished"); } + + private byte LobbyUpdateDetour(GameLobbyType mapId, int time) + { + _lastLobbyUpdateMapId = mapId; + var gameTitleScreen = TitleEditAddressResolver.GetGameExpectedTitleScreen(); // this is expac title, not GameLobbyType + var currentMap = (GameLobbyType)TitleEditAddressResolver.CurrentLobbyMap; + + var isARRTitleScreen = gameTitleScreen == 0; + var isTitleScreenToLobby = currentMap == GameLobbyType.Title && mapId == GameLobbyType.CharaSelect; + var isLobbyToTitleScreen = currentMap == GameLobbyType.CharaSelect && mapId == GameLobbyType.Title; + var shouldApply = isARRTitleScreen && (isTitleScreenToLobby || isLobbyToTitleScreen); + + DalamudApi.PluginLog.Verbose($"[LobbyUpdateDetour] map {mapId} time {time} currentMap {currentMap} " + + $"gameTitleScreen {gameTitleScreen} isARRTitleScreen {isARRTitleScreen} " + + $"isTitleScreenToLobby {isTitleScreenToLobby} isLobbyToTitleScreen {isLobbyToTitleScreen} " + + $"shouldApply {shouldApply}"); + + if (shouldApply) + { + DalamudApi.PluginLog.Debug($"[LobbyUpdateDetour] Running!"); + // This tells the game it was playing a movie so it skips the "same zone" check entirely + TitleEditAddressResolver.CurrentLobbyMap = (short)GameLobbyType.Movie; + } + + return _lobbyUpdateHook.Original(mapId, time); + } internal void RefreshCurrentTitleEditScreen() { @@ -130,9 +159,7 @@ internal void RefreshCurrentTitleEditScreen() if (GetState("_TitleMenu") == UiState.Visible) DalamudApi.PluginInterface.UiBuilder.AddNotification($"Now displaying: {_currentScreen.Name}", "Title Edit", NotificationType.Info); }); - } - } private bool IsScreenValid(TitleEditScreen screen) @@ -158,25 +185,15 @@ private int HandleCreateScene(string p1, uint p2, IntPtr p3, uint p4, IntPtr p5, _amForcingTime = false; _amForcingWeather = false; - if (IsLobby(p1)) + if (_lastLobbyUpdateMapId == GameLobbyType.CharaSelect) { Log("Loading lobby and lobby fixon."); var returnVal = _createSceneHook.Original(p1, p2, p3, p4, p5, p6, p7); FixOn(new Vector3(0, 0, 0), new Vector3(0, 0.8580103f, 0), 1); return returnVal; } - - // Log("---------------"); - // GetState("_ScreenText"); - // GetState("Title"); - // GetState("_TitleLogo"); - // GetState("_TitleMenu"); - // GetState("_TitleRevision"); - // GetState("_TitleRights"); - // GetState("CursorAddon"); - // Log("---------------"); - - if (IsTitleScreen(p1))// && GetState("_ScreenText") != UiState.Null) + + if (_lastLobbyUpdateMapId == GameLobbyType.Title) { Log("Loading custom title."); RefreshCurrentTitleEditScreen(); @@ -295,6 +312,7 @@ public void Enable() _createSceneHook.Enable(); _playMusicHook.Enable(); _fixOnHook.Enable(); + _lobbyUpdateHook.Enable(); } public void Dispose() @@ -305,6 +323,7 @@ public void Dispose() _createSceneHook.Dispose(); _playMusicHook.Dispose(); _fixOnHook.Dispose(); + _lobbyUpdateHook.Dispose(); } private void ForceTime(ushort timeOffset, int forceTime) @@ -382,39 +401,6 @@ public void SetWeather(byte weather) } } - // TODO: Eventually figure out how to do these without excluding free trial players - private bool IsTitleScreen(string path) - { - var ret = - (path == "ex4/05_zon_z5/chr/z5c1/level/z5c1" - || path == "ex3/05_zon_z4/chr/z4c1/level/z4c1" - || path == "ex2/05_zon_z3/chr/z3c1/level/z3c1" - || path == "ex1/05_zon_z2/chr/z2c1/level/z2c1" - || path == "ffxiv/zon_z1/chr/z1c1/level/z1c1") - && !IsLobby(path) - && !IsCharaMake(path); - Log($"IsTitleScreen: {ret}"); - return ret; - } - - private bool IsLobby(string path) - { - var ret = - GetState("CharaSelect") == UiState.Visible - && path == "ffxiv/zon_z1/chr/z1c1/level/z1c1"; - Log($"IsLobby: {ret}"); - return ret; - } - - private bool IsCharaMake(string path) - { - var ret = - GetState("_CharaMakeBgSelector") == UiState.Visible - && path == "ffxiv/zon_z1/chr/z1c1/level/z1c1"; - Log($"IsCharaMake: {ret}"); - return ret; - } - enum UiState { Null, @@ -425,7 +411,7 @@ enum UiState private unsafe UiState GetState(string uiName) { // Log($"GetState({uiName})"); - var ui = (AtkUnitBase*)DalamudApi.GameGui.GetAddonByName(uiName, 1); + var ui = (AtkUnitBase*)DalamudApi.GameGui.GetAddonByName(uiName); var ret = UiState.Null; if (ui != null) { @@ -442,7 +428,7 @@ public unsafe void DisableTitleLogo(int delay = 2001) Task.Delay(delay).ContinueWith(_ => { Log($"Logo task running after {delay} delay"); - var addon = (AtkUnitBase*)DalamudApi.GameGui.GetAddonByName("_TitleLogo", 1); + var addon = (AtkUnitBase*)DalamudApi.GameGui.GetAddonByName("_TitleLogo"); if (addon == null || addon->UldManager.NodeListCount < 2) return; var node = addon->UldManager.NodeList[1]; if (node == null) return; @@ -469,7 +455,7 @@ public unsafe void DisableTitleLogo(int delay = 2001) public unsafe void EnableTitleLogo() { - var addon = (AtkUnitBase*)DalamudApi.GameGui.GetAddonByName("_TitleLogo", 1); + var addon = (AtkUnitBase*)DalamudApi.GameGui.GetAddonByName("_TitleLogo"); if (addon == null || addon->UldManager.NodeListCount < 2) return; var node = addon->UldManager.NodeList[1]; if (node == null) return; @@ -589,9 +575,6 @@ private float[] FloatArrayFromVector3(Vector3 floats) private void Log(string s) { -#if !DEBUG - if (_configuration.DebugLogging) -#endif DalamudApi.PluginLog.Debug($"[dbg] {s}"); } } \ No newline at end of file diff --git a/TitleEdit/TitleEdit.csproj b/TitleEdit/TitleEdit.csproj index 16d37b6..e5f5ba4 100644 --- a/TitleEdit/TitleEdit.csproj +++ b/TitleEdit/TitleEdit.csproj @@ -1,7 +1,7 @@  $(appdata)\XIVLauncher\addon\Hooks\dev\ - 2.2.6.13 + 2.2.7.0 net7.0-windows diff --git a/TitleEdit/TitleEditAddressResolver.cs b/TitleEdit/TitleEditAddressResolver.cs index a987fce..9dca265 100644 --- a/TitleEdit/TitleEditAddressResolver.cs +++ b/TitleEdit/TitleEditAddressResolver.cs @@ -27,6 +27,9 @@ public static IntPtr RenderCamera public static IntPtr PlayMusic { get; private set; } public static IntPtr BgmControl { get; private set; } public static IntPtr WeatherPtrBase { get; private set; } + public static IntPtr LobbyUpdate { get; private set; } + public static IntPtr LobbyCurrentMap { get; private set; } + public static IntPtr LobbyThing { get; private set; } public static void Setup64Bit() { @@ -38,6 +41,23 @@ public static void Setup64Bit() PlayMusic = DalamudApi.SigScanner.ScanText("E8 ?? ?? ?? ?? 48 89 47 18 89 5F 20"); BgmControl = DalamudApi.SigScanner.GetStaticAddressFromSig("48 8B 05 ?? ?? ?? ?? 48 85 C0 74 37 83 78 08 04"); WeatherPtrBase = DalamudApi.SigScanner.GetStaticAddressFromSig("48 8B 05 ?? ?? ?? ?? 48 8B D9 0F 29 7C 24 ?? 41 8B FF"); + LobbyUpdate = DalamudApi.SigScanner.ScanText("E8 ?? ?? ?? ?? EB 1C 3B CF"); + LobbyCurrentMap = DalamudApi.SigScanner.GetStaticAddressFromSig("0F B7 05 ?? ?? ?? ?? 49 8B CE"); + LobbyThing = DalamudApi.SigScanner.GetStaticAddressFromSig("48 8B 0D ?? ?? ?? ?? 8B 51 38 2B D3"); + } + + public static int GetGameExpectedTitleScreen() + { + unsafe + { + return *(int*) (*((nint*)LobbyThing) + 56); + } + } + + public static short CurrentLobbyMap + { + get => Marshal.ReadInt16(LobbyCurrentMap); + set => Marshal.WriteInt16(LobbyCurrentMap, value); } } } \ No newline at end of file