Implement hunting AP and progress, event tasks, exchanges, games, stories and actions; connect battle and reward handling. Add CashShop plugin and installation, server purchases and entitlements, recharge rules and plugin version metadata. Distribute binary calendars independently; cache GameData in memory and fix single-connection query deadlocks. Improve automatic login and recovery diagnostics; document configuration and release flows.
84 lines
3.3 KiB
C#
84 lines
3.3 KiB
C#
using System;
|
|
using BD2.GameNames;
|
|
using static BD2.GameNames.Game;
|
|
using System.Reflection;
|
|
using BepInEx.Logging;
|
|
using HarmonyLib;
|
|
using UnityEngine;
|
|
|
|
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,
|
|
new[] { typeof(bool), typeof(int), typeof(int), typeof(int), typeof(Action) },
|
|
null);
|
|
if (updateAgeGate == 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();
|
|
if (needsAgeVerificationSetter == null)
|
|
{
|
|
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();
|
|
};
|
|
}
|
|
|
|
}
|