This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using ShrinkContext;
|
||||
using ShrinkEventBus;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user