mirror of
https://github.com/goatcorp/Dalamud.git
synced 2026-02-17 21:37:43 +01:00
Add support for Titles to IUnlockState
This commit is contained in:
parent
907b585b75
commit
1ba18e54bf
2 changed files with 58 additions and 3 deletions
|
|
@ -50,6 +50,7 @@ internal unsafe class UnlockState : IInternalDisposableService, IUnlockState
|
||||||
|
|
||||||
private readonly ConcurrentDictionary<Type, HashSet<uint>> cachedUnlockedRowIds = [];
|
private readonly ConcurrentDictionary<Type, HashSet<uint>> cachedUnlockedRowIds = [];
|
||||||
private readonly Hook<SetAchievementCompletedDelegate> setAchievementCompletedHook;
|
private readonly Hook<SetAchievementCompletedDelegate> setAchievementCompletedHook;
|
||||||
|
private readonly Hook<SetTitleUnlockedDelegate> setTitleUnlockedHook;
|
||||||
|
|
||||||
[ServiceManager.ServiceConstructor]
|
[ServiceManager.ServiceConstructor]
|
||||||
private UnlockState()
|
private UnlockState()
|
||||||
|
|
@ -62,17 +63,27 @@ internal unsafe class UnlockState : IInternalDisposableService, IUnlockState
|
||||||
this.sigScanner.ScanText("81 FA ?? ?? ?? ?? 0F 87 ?? ?? ?? ?? 53"),
|
this.sigScanner.ScanText("81 FA ?? ?? ?? ?? 0F 87 ?? ?? ?? ?? 53"),
|
||||||
this.SetAchievementCompletedDetour);
|
this.SetAchievementCompletedDetour);
|
||||||
|
|
||||||
|
this.setTitleUnlockedHook = Hook<SetTitleUnlockedDelegate>.FromAddress(
|
||||||
|
this.sigScanner.ScanText("B8 ?? ?? ?? ?? 66 3B D0 73 ?? 44 0F B7 C2 49 C1 E8 ?? 4C 03 C1 0F B7 C2 83 E0 ?? 41 0F B6 48 ?? 0F AB C1"),
|
||||||
|
this.SetTitleUnlockedDetour);
|
||||||
|
|
||||||
this.setAchievementCompletedHook.Enable();
|
this.setAchievementCompletedHook.Enable();
|
||||||
|
this.setTitleUnlockedHook.Enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
private delegate void SetAchievementCompletedDelegate(CSAchievement* thisPtr, uint id);
|
private delegate void SetAchievementCompletedDelegate(CSAchievement* thisPtr, uint id);
|
||||||
|
|
||||||
|
private delegate void SetTitleUnlockedDelegate(TitleList* thisPtr, ushort id);
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public event IUnlockState.UnlockDelegate Unlock;
|
public event IUnlockState.UnlockDelegate Unlock;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public bool IsAchievementListLoaded => CSAchievement.Instance()->IsLoaded();
|
public bool IsAchievementListLoaded => CSAchievement.Instance()->IsLoaded();
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public bool IsTitleListLoaded => UIState.Instance()->TitleList.DataReceived;
|
||||||
|
|
||||||
private bool IsLoaded => PlayerState.Instance()->IsLoaded;
|
private bool IsLoaded => PlayerState.Instance()->IsLoaded;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
|
|
@ -448,6 +459,19 @@ internal unsafe class UnlockState : IInternalDisposableService, IUnlockState
|
||||||
return PlayerState.Instance()->IsSecretRecipeBookUnlocked(row.RowId);
|
return PlayerState.Instance()->IsSecretRecipeBookUnlocked(row.RowId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public bool IsTitleUnlocked(Title row)
|
||||||
|
{
|
||||||
|
// Only check for login state here as individual Titles
|
||||||
|
// may be flagged as complete when you unlock them, regardless
|
||||||
|
// of whether the full Titles list was loaded or not.
|
||||||
|
|
||||||
|
if (!this.IsLoaded)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return UIState.Instance()->TitleList.IsTitleUnlocked((ushort)row.RowId);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public bool IsTraitUnlocked(Trait row)
|
public bool IsTraitUnlocked(Trait row)
|
||||||
{
|
{
|
||||||
|
|
@ -608,6 +632,9 @@ internal unsafe class UnlockState : IInternalDisposableService, IUnlockState
|
||||||
if (rowRef.TryGetValue<SecretRecipeBook>(out var secretRecipeBookRow))
|
if (rowRef.TryGetValue<SecretRecipeBook>(out var secretRecipeBookRow))
|
||||||
return this.IsSecretRecipeBookUnlocked(secretRecipeBookRow);
|
return this.IsSecretRecipeBookUnlocked(secretRecipeBookRow);
|
||||||
|
|
||||||
|
if (rowRef.TryGetValue<Title>(out var titleRow))
|
||||||
|
return this.IsTitleUnlocked(titleRow);
|
||||||
|
|
||||||
if (rowRef.TryGetValue<Trait>(out var traitRow))
|
if (rowRef.TryGetValue<Trait>(out var traitRow))
|
||||||
return this.IsTraitUnlocked(traitRow);
|
return this.IsTraitUnlocked(traitRow);
|
||||||
|
|
||||||
|
|
@ -667,14 +694,24 @@ internal unsafe class UnlockState : IInternalDisposableService, IUnlockState
|
||||||
this.RaiseUnlockSafely((RowRef)LuminaUtils.CreateRef<AchievementSheet>(id));
|
this.RaiseUnlockSafely((RowRef)LuminaUtils.CreateRef<AchievementSheet>(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SetTitleUnlockedDetour(TitleList* thisPtr, ushort id)
|
||||||
|
{
|
||||||
|
this.setTitleUnlockedHook.Original(thisPtr, id);
|
||||||
|
|
||||||
|
if (!this.IsLoaded)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.RaiseUnlockSafely((RowRef)LuminaUtils.CreateRef<Title>(id));
|
||||||
|
}
|
||||||
|
|
||||||
private void Update()
|
private void Update()
|
||||||
{
|
{
|
||||||
if (!this.IsLoaded)
|
if (!this.IsLoaded)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Log.Verbose("Checking for new unlocks...");
|
Log.Verbose("Checking for new unlocks...");
|
||||||
|
|
||||||
// Do not check for Achievements here!
|
// Do not check for Achievements or Titles here!
|
||||||
|
|
||||||
this.UpdateUnlocksForSheet<ActionSheet>();
|
this.UpdateUnlocksForSheet<ActionSheet>();
|
||||||
this.UpdateUnlocksForSheet<AetherCurrent>();
|
this.UpdateUnlocksForSheet<AetherCurrent>();
|
||||||
|
|
@ -736,7 +773,6 @@ internal unsafe class UnlockState : IInternalDisposableService, IUnlockState
|
||||||
// - EmjCostume
|
// - EmjCostume
|
||||||
|
|
||||||
// Probably not happening, because it requires fetching data from server:
|
// Probably not happening, because it requires fetching data from server:
|
||||||
// - Titles
|
|
||||||
// - Bozjan Field Notes
|
// - Bozjan Field Notes
|
||||||
// - Support/Phantom Jobs, which require to be in Occult Crescent, because it checks the jobs level for != 0
|
// - Support/Phantom Jobs, which require to be in Occult Crescent, because it checks the jobs level for != 0
|
||||||
}
|
}
|
||||||
|
|
@ -806,6 +842,9 @@ internal class UnlockStatePluginScoped : IInternalDisposableService, IUnlockStat
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public bool IsAchievementListLoaded => this.unlockStateService.IsAchievementListLoaded;
|
public bool IsAchievementListLoaded => this.unlockStateService.IsAchievementListLoaded;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public bool IsTitleListLoaded => this.unlockStateService.IsTitleListLoaded;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public bool IsAchievementComplete(AchievementSheet row) => this.unlockStateService.IsAchievementComplete(row);
|
public bool IsAchievementComplete(AchievementSheet row) => this.unlockStateService.IsAchievementComplete(row);
|
||||||
|
|
||||||
|
|
@ -932,6 +971,9 @@ internal class UnlockStatePluginScoped : IInternalDisposableService, IUnlockStat
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public bool IsSecretRecipeBookUnlocked(SecretRecipeBook row) => this.unlockStateService.IsSecretRecipeBookUnlocked(row);
|
public bool IsSecretRecipeBookUnlocked(SecretRecipeBook row) => this.unlockStateService.IsSecretRecipeBookUnlocked(row);
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public bool IsTitleUnlocked(Title row) => this.unlockStateService.IsTitleUnlocked(row);
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public bool IsTraitUnlocked(Trait row) => this.unlockStateService.IsTraitUnlocked(row);
|
public bool IsTraitUnlocked(Trait row) => this.unlockStateService.IsTraitUnlocked(row);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,11 @@ public interface IUnlockState : IDalamudService
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool IsAchievementListLoaded { get; }
|
bool IsAchievementListLoaded { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether the full Titles list was received.
|
||||||
|
/// </summary>
|
||||||
|
bool IsTitleListLoaded { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether the specified Achievement is completed.<br/>
|
/// Determines whether the specified Achievement is completed.<br/>
|
||||||
/// Requires that the player requested the Achievements list (can be chcked with <see cref="IsAchievementListLoaded"/>).
|
/// Requires that the player requested the Achievements list (can be chcked with <see cref="IsAchievementListLoaded"/>).
|
||||||
|
|
@ -322,6 +327,14 @@ public interface IUnlockState : IDalamudService
|
||||||
/// <returns><see langword="true"/> if unlocked; otherwise, <see langword="false"/>.</returns>
|
/// <returns><see langword="true"/> if unlocked; otherwise, <see langword="false"/>.</returns>
|
||||||
bool IsSecretRecipeBookUnlocked(SecretRecipeBook row);
|
bool IsSecretRecipeBookUnlocked(SecretRecipeBook row);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the specified Title is unlocked.<br/>
|
||||||
|
/// Requires that the player requested the Titles list (can be chcked with <see cref="IsTitleListLoaded"/>).
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="row">The Title row to check.</param>
|
||||||
|
/// <returns><see langword="true"/> if unlocked; otherwise, <see langword="false"/>.</returns>
|
||||||
|
bool IsTitleUnlocked(Title row);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether the specified Trait is unlocked.
|
/// Determines whether the specified Trait is unlocked.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue