81 lines
3.3 KiB
C#
81 lines
3.3 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Cysharp.Threading.Tasks;
|
|
using ShrinkContext;
|
|
|
|
namespace ShrinkModFramework
|
|
{
|
|
/// <summary>把 IShrinkMod 四阶段生命周期映射为一个可逆 Cordis 组件。</summary>
|
|
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<string> Inject => _inject;
|
|
public IReadOnlyList<string> 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;
|
|
|
|
// 模组网络 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;
|
|
}
|
|
}
|
|
}
|