using System; using System.Collections.Generic; using System.Linq; using Cysharp.Threading.Tasks; using ShrinkContext; using ShrinkEventBus; namespace ShrinkModFramework { /// 把 IShrinkMod 四阶段生命周期映射为一个可逆 Cordis 组件。 internal sealed class ShrinkModComponent : IShrinkComponent { private readonly ShrinkModContextHost _host; private readonly ShrinkModComponentSource _source; private readonly string[] _inject; private readonly string[] _provide; public ShrinkModComponent(ShrinkModContextHost host, ShrinkModComponentSource source) { _host = host ?? throw new ArgumentNullException(nameof(host)); _source = source ?? throw new ArgumentNullException(nameof(source)); _inject = source.Info.Dependencies .Where(dependency => !dependency.Optional) .Select(dependency => ShrinkModContextHost.GetModKey(dependency.ModId)) .Distinct(StringComparer.Ordinal) .ToArray(); _provide = new[] { ShrinkModContextHost.GetModKey(source.Info.ModId) }; } public string Name => "shrink.mod/" + _source.Info.ModId; public IReadOnlyList Inject => _inject; public IReadOnlyList Provide => _provide; public UniTask ApplyAsync(ShrinkCtx ctx, object config) { var instance = _source.Factory(); if (instance == null) throw new InvalidOperationException($"Mod factory returned null: {_source.Info.ModId}"); var handle = new ShrinkModHandle(_source.Info, instance) { Generation = _host.NextGeneration() }; ctx.Effect( () => _host.RegisterHandle(handle), () => { _host.UnregisterHandle(handle); handle.State = ShrinkModState.Unloaded; }); IDisposable harmonyLease = null; ctx.Effect( () => harmonyLease = ShrinkHarmonyPatchService.AcquirePatchesIfNeeded( handle.Info, _host.EnableHarmonyPatching, _host.VerboseLogging), () => harmonyLease?.Dispose()); var modContext = new ShrinkModContext(handle.Info, _host.RegistryManager, _host.Mods, _host.VerboseLogging, ctx); instance.OnConstruct(modContext); handle.State = ShrinkModState.Constructed; // 先登记归属清理,OnRegisterContent 中途失败也能撤回已注册的部分内容。 ctx.Effect(() => { }, () => _host.RegistryManager.RemoveOwnedEntries(handle.Info.ModId)); instance.OnRegisterContent(modContext); handle.State = ShrinkModState.ContentRegistered; IDisposable eventBinding = null; ctx.Effect( () => eventBinding = ShrinkModOptionalRuntimeIntegration.TryAttachEventBusInstance( instance.GetType(), instance, handle.Info.ModId, _host.VerboseLogging), () => { eventBinding?.Dispose(); EventBus.RemoveBus(ShrinkBusKey.Mod(handle.Info.ModId)); }); // 模组网络 handler 以 ModId 为归属键,可在失败或卸载时整体撤回。 ctx.Effect(() => { }, () => ShrinkModNetworkManager.UnregisterHandlers(handle.Info.ModId)); instance.OnInitialize(modContext); handle.State = ShrinkModState.Initialized; instance.OnReady(modContext); handle.State = ShrinkModState.Ready; ctx.Set(_provide[0], handle); return UniTask.CompletedTask; } } }