using BepInEx; using BepInEx.Unity.IL2CPP; using BepInEx.Logging; using HarmonyLib; using MiraAPI.PluginLoading; using Reactor; using System; using System.Reflection; namespace TownOfUsStatsExporter; /// /// Main BepInEx plugin for TownOfUs Stats Exporter. /// This is a standalone plugin that uses reflection to access TOU Mira data /// and exports game statistics to a cloud API. /// [BepInPlugin(PluginGuid, PluginName, PluginVersion)] [BepInDependency("auavengers.tou.mira", BepInDependency.DependencyFlags.HardDependency)] [BepInDependency(ReactorPlugin.Id, BepInDependency.DependencyFlags.HardDependency)] public class TownOfUsStatsPlugin : BasePlugin { /// /// Plugin GUID for BepInEx identification. /// public const string PluginGuid = "com.townofus.stats.exporter"; /// /// Plugin display name. /// public const string PluginName = "TownOfUs Stats Exporter"; /// /// Plugin version. /// public const string PluginVersion = "1.0.3"; /// /// Logger instance for the plugin. /// internal static ManualLogSource Logger { get; private set; } = null!; /// /// Harmony instance for patching. /// internal static Harmony Harmony { get; private set; } = null!; private TownOfUsStatsExporter.Reflection.TouMiraReflectionBridge? reflectionBridge; /// /// Called when the plugin is loaded by BepInEx. /// public override void Load() { Logger = Log; Harmony = new Harmony(PluginGuid); Logger.LogInfo("========================================"); Logger.LogInfo($"{PluginName} v{PluginVersion}"); Logger.LogInfo("========================================"); // Initialize reflection bridge reflectionBridge = new TownOfUsStatsExporter.Reflection.TouMiraReflectionBridge(); if (!reflectionBridge.Initialize()) { Logger.LogError("Failed to initialize TOU Mira reflection bridge!"); Logger.LogError("This plugin may not be compatible with your TOU Mira version."); Logger.LogError("Plugin will be disabled."); return; } Logger.LogInfo($"Successfully connected to TOU Mira v{reflectionBridge.TouMiraVersion}"); Logger.LogInfo($"Compatibility: {reflectionBridge.CompatibilityStatus}"); // Store bridge in static context for patches ReflectionBridgeProvider.SetBridge(reflectionBridge); // Apply Harmony patches try { Harmony.PatchAll(Assembly.GetExecutingAssembly()); Logger.LogInfo("Harmony patches applied successfully"); } catch (Exception ex) { Logger.LogError($"Failed to apply Harmony patches: {ex}"); return; } Logger.LogInfo($"{PluginName} loaded successfully!"); Logger.LogInfo("Stats will be exported at the end of each game."); } /// /// Called when the plugin is unloaded. /// /// True if unloading was successful. public override bool Unload() { Logger.LogInfo($"Unloading {PluginName}..."); Harmony?.UnpatchSelf(); return true; } } /// /// Static provider for accessing reflection bridge from patches. /// internal static class ReflectionBridgeProvider { private static TownOfUsStatsExporter.Reflection.TouMiraReflectionBridge? bridge; /// /// Sets the reflection bridge instance. /// /// The bridge instance. public static void SetBridge(TownOfUsStatsExporter.Reflection.TouMiraReflectionBridge b) => bridge = b; /// /// Gets the reflection bridge instance. /// /// The bridge instance. /// Thrown if bridge is not initialized. public static TownOfUsStatsExporter.Reflection.TouMiraReflectionBridge GetBridge() => bridge ?? throw new InvalidOperationException("Bridge not initialized"); }