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;
}
}
}