Files
bd2/plugins/LocalIdentity/LocalAccountPolicy.cs
T

75 lines
3.1 KiB
C#

using System;
using BD2.GameNames;
using static BD2.GameNames.Game;
using System.Reflection;
using BepInEx.Logging;
using HarmonyLib;
namespace Bd2LocalIdentity;
internal static class LocalAccountPolicy
{
private static ManualLogSource Log;
internal static void Initialize(ManualLogSource logger) => Log = logger;
internal static void InstallAgeGatePersistence(Harmony harmony)
{
// LoginUserResponse field 13 is the client's sole gate for opening
// AgeGatePopupUI. Retain the original first-run UI and request; only
// change a later LoginUser parse after its successful local state has
// been read from disk.
Type commonPacket = typeof(BDNetwork.CommonPacket);
MethodInfo updateAgeGate = (commonPacket?.GetGameMethod(
nameof(BDNetwork.CommonPacket.SendUpdateAgeGateRequest),
BindingFlags.Static | BindingFlags.Public,
null,
[typeof(bool), typeof(int), typeof(int), typeof(int), typeof(Action)],
null)) ?? throw new MissingMethodException("CommonPacket.SendUpdateAgeGateRequest(bool, int, int, int, Action) was not found");
Type loginUserResponse = typeof(Proto.Net.LoginUserResponse);
MethodInfo needsAgeVerificationSetter = (loginUserResponse?.GetGameProperty(
nameof(Proto.Net.LoginUserResponse.NeedsAgeVerification),
BindingFlags.Instance | BindingFlags.Public)?.GetSetMethod()) ?? throw new MissingMethodException("LoginUserResponse.NeedsAgeVerification setter was not found");
harmony.Patch(
updateAgeGate,
prefix: new HarmonyMethod(typeof(LocalAccountPolicy), nameof(UpdateAgeGateRequestPrefix)));
harmony.Patch(
needsAgeVerificationSetter,
prefix: new HarmonyMethod(typeof(LocalAccountPolicy), nameof(NeedsAgeVerificationSetterPrefix)));
Log?.LogInfo("Local age-gate confirmation persistence active (confirmed=" + AgeGateState.IsConfirmed() + ")");
}
private static void NeedsAgeVerificationSetterPrefix(ref bool value)
{
if (value && AgeGateState.IsConfirmed())
{
value = false;
Log?.LogInfo("Used persisted local age-gate confirmation for LoginUser");
}
}
private static void UpdateAgeGateRequestPrefix(ref Action __4)
{
// CommonPacket invokes this callback only after it has parsed the
// empty UpdateAgeGateResponse and accepted errorType == 0. Wrapping
// it therefore never records failed/cancelled submissions.
Action continuation = __4;
__4 = delegate
{
try
{
AgeGateState.MarkConfirmed();
Log?.LogInfo("Stored successful local age-gate confirmation");
}
catch (Exception ex)
{
// Preserve the original continuation: inability to persist
// should not break a successfully completed first login.
Log?.LogWarning("Could not persist local age-gate confirmation: " + ex.Message);
}
continuation?.Invoke();
};
}
}