Files
bd2/plugins/LocalIdentity/Plugin.cs
T
Flechazo 992fa47fd5 feat(all): add game SDK and harden client login and game rules
- Add costume burst upgrades with durable replay and fix permanent SR equipment gacha.
- Add server game.json rules for optional collaboration UR weapons, with packaging and documentation.
- Add GameNames/GameSdk NuGet tooling, readable types, reobfuscation, complete source/PDB navigation and shared-runtime installation.
- Split plugin responsibilities, prefer typeof/nameof, centralize MSBuild settings and ignore local paths; remove the unused LoginUI test project.
- Fix login recovery and TLS through native platform HTTP and a private game relay; read device region directly from the OS time zone.

Validation: go test ./... -count=1, go vet ./..., plugin Release builds, SDK/runtime self-tests, Roslyn embedded-source navigation, gofmt check and git diff --check.
2026-10-03 23:04:32 +08:00

109 lines
4.0 KiB
C#

using System;
using BD2.GameNames;
using static BD2.GameNames.Game;
using System.Reflection;
using System.Threading;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;
namespace Bd2LocalIdentity;
[BepInPlugin(Guid, Name, Version)]
public sealed class Plugin : BaseUnityPlugin
{
public const string Guid = "bd2.localidentity";
public const string Name = "BD2 Local Identity";
public const string Version = Bd2Build.Versions.Plugin;
private static ManualLogSource Log;
private static ClientRouting Routing;
private static int ShutdownHooksInstalled;
internal static void LogWarning(string message)
{
Log?.LogWarning(message);
}
private void Awake()
{
try
{
Log = Logger;
Game.Validate(typeof(Plugin).Assembly, Bd2Build.Versions.Game, message => Logger.LogInfo(message));
// The non-SDK branch still needs a local bootstrap identity for
// MaintenanceInfo. OAuth LoginUI replaces this value after its
// browser/device transaction completes.
PlayerPrefs.SetString("AccessToken", "bd2-local-development-user");
PlayerPrefs.Save();
Routing = ClientRouting.Load(Logger);
if (Interlocked.Exchange(ref ShutdownHooksInstalled, 1) == 0)
{
AppDomain.CurrentDomain.ProcessExit += delegate { DisposeRouting(); };
AppDomain.CurrentDomain.DomainUnload += delegate { DisposeRouting(); };
}
Type appManager = typeof(AppManager);
MethodInfo getter = Game.Getter<AppManager, bool>(app => app.IsPlatformLogin);
if (getter == null || getter.ReturnType != typeof(bool) || getter.GetParameters().Length != 0)
{
throw new MissingMethodException("AppManager.IsPlatformLogin getter was not found (client version mismatch)");
}
MethodInfo prefix = typeof(Plugin).GetGameMethod(
nameof(UseSdkPrefix),
BindingFlags.Static | BindingFlags.NonPublic);
Harmony harmony = new Harmony(Guid);
harmony.Patch(getter, prefix: new HarmonyMethod(prefix));
TryInstall("OS time zone device country", () => SystemTimeZoneRegion.Install(harmony, Logger));
ClientPresentation.Initialize(Logger);
LocalAccountPolicy.Initialize(Logger);
ClientDiagnostics.Initialize(Logger);
Type introUI = typeof(IntroUI);
Routing.Install(harmony);
TryInstall("startup fullscreen", () => ClientPresentation.InstallStartupFullscreen(harmony, appManager));
TryInstall("performance overlay suppression", () => ClientPresentation.InstallPerformanceOverlaySuppression(harmony));
TryInstall("maintenance timeout guard", () => ClientDiagnostics.InstallMaintenanceTimeoutGuard(harmony, introUI));
TryInstall("age-gate persistence", () => LocalAccountPolicy.InstallAgeGatePersistence(harmony));
TryInstall("local purchase bypass", () => LocalAccountPolicy.InstallLocalPurchaseBypass(harmony));
TryInstall("database diagnostics", () => ClientDiagnostics.InstallDatabaseDiagnostics(harmony));
Logger.LogInfo("Local identity active: AppManager.IsPlatformLogin => false");
}
catch (Exception ex)
{
Logger.LogError("Local identity patch failed: " + ex);
}
}
private void OnApplicationQuit()
{
DisposeRouting();
}
private static void DisposeRouting()
{
ClientRouting routing = Interlocked.Exchange(ref Routing, null);
routing?.Dispose();
}
private void TryInstall(string name, Action install)
{
try
{
install();
}
catch (Exception ex)
{
Logger.LogError("Local identity " + name + " patch failed: " + ex);
}
}
private static bool UseSdkPrefix(ref bool __result)
{
__result = false;
return false;
}
}