feat(render): implement Campaign AR and terrain fidelity
This commit is contained in:
parent
99cf26e00c
commit
7a5f96ede5
368 changed files with 50611 additions and 950 deletions
|
|
@ -2,6 +2,7 @@ using System.Text.Json;
|
|||
using AcDream.Core.Plugins;
|
||||
using AcDream.Core.Selection;
|
||||
using AcDream.Plugin.Abstractions;
|
||||
using AcDream.Plugin.Abstractions.Rendering;
|
||||
|
||||
namespace AcDream.Core.Tests.Plugins;
|
||||
|
||||
|
|
@ -73,11 +74,118 @@ public sealed class PluginSessionTests
|
|||
Assert.Empty(statuses);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GraphicalKindSet_RegistersRenderPackAndWithdrawsBeforeUnload()
|
||||
{
|
||||
using var temporary = new TemporaryDirectory();
|
||||
InstallFixture(
|
||||
temporary.Path,
|
||||
"render",
|
||||
"acdream.test.render",
|
||||
[PluginKind.RenderPack]);
|
||||
var statuses = new List<PluginSessionStatus>();
|
||||
var registry = new RecordingRenderPackRegistry();
|
||||
var plugins = new PluginSession(
|
||||
new StubHost(),
|
||||
statuses.Add,
|
||||
registry,
|
||||
[PluginKind.Gameplay, PluginKind.RenderPack]);
|
||||
|
||||
plugins.Start([temporary.Path], allowList: null);
|
||||
|
||||
Assert.Equal(1, plugins.LoadedCount);
|
||||
Assert.Equal(1, registry.ActiveCount);
|
||||
Assert.Equal("acdream.test.noop-pack", registry.Descriptor?.Id);
|
||||
IReadOnlyList<WeakReference> contexts =
|
||||
plugins.CaptureLoadContextWeakReferences();
|
||||
plugins.Dispose();
|
||||
Assert.Equal(0, registry.ActiveCount);
|
||||
Collect(contexts);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GameplayOnlyHost_SkipsUnrequestedRenderPackBeforeDllProbe()
|
||||
{
|
||||
using var temporary = new TemporaryDirectory();
|
||||
InstallBroken(
|
||||
temporary.Path,
|
||||
"render",
|
||||
"acdream.test.render",
|
||||
[PluginKind.RenderPack]);
|
||||
var statuses = new List<PluginSessionStatus>();
|
||||
using var plugins = new PluginSession(new StubHost(), statuses.Add);
|
||||
|
||||
plugins.Start([temporary.Path], allowList: null);
|
||||
|
||||
Assert.Equal(0, plugins.LoadedCount);
|
||||
Assert.Empty(statuses);
|
||||
Assert.Empty(plugins.CaptureLoadContextWeakReferences());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RenderPackRegisterFailure_WithdrawsPartialRegistrationBeforeUnload()
|
||||
{
|
||||
using var temporary = new TemporaryDirectory();
|
||||
InstallFixture(
|
||||
temporary.Path,
|
||||
"render",
|
||||
"acdream.test.render",
|
||||
[PluginKind.RenderPack]);
|
||||
File.WriteAllText(
|
||||
Path.Combine(temporary.Path, "render", "throw-after-render-register"),
|
||||
string.Empty);
|
||||
var registry = new RecordingRenderPackRegistry();
|
||||
var statuses = new List<PluginSessionStatus>();
|
||||
var plugins = new PluginSession(
|
||||
new StubHost(),
|
||||
statuses.Add,
|
||||
registry,
|
||||
[PluginKind.Gameplay, PluginKind.RenderPack]);
|
||||
|
||||
plugins.Start([temporary.Path], allowList: null);
|
||||
|
||||
Assert.Equal(0, plugins.LoadedCount);
|
||||
Assert.Equal(0, registry.ActiveCount);
|
||||
PluginSessionStatus status = Assert.Single(statuses);
|
||||
Assert.Equal(PluginSessionStatusKind.Failed, status.Kind);
|
||||
Assert.Contains("failed after publishing", status.Error);
|
||||
IReadOnlyList<WeakReference> contexts =
|
||||
plugins.CaptureLoadContextWeakReferences();
|
||||
plugins.Dispose();
|
||||
Collect(contexts);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GameplayOnlyHost_ExplicitRenderPackReportsKindWithoutDllProbe()
|
||||
{
|
||||
using var temporary = new TemporaryDirectory();
|
||||
InstallBroken(
|
||||
temporary.Path,
|
||||
"render",
|
||||
"acdream.test.render",
|
||||
[PluginKind.RenderPack]);
|
||||
var statuses = new List<PluginSessionStatus>();
|
||||
using var plugins = new PluginSession(new StubHost(), statuses.Add);
|
||||
|
||||
plugins.Start([temporary.Path], ["acdream.test.render"]);
|
||||
|
||||
PluginSessionStatus status = Assert.Single(statuses);
|
||||
Assert.Equal(PluginSessionStatusKind.Failed, status.Kind);
|
||||
Assert.Contains("does not support", status.Error);
|
||||
Assert.DoesNotContain("entry dll", status.Error);
|
||||
Assert.Empty(plugins.CaptureLoadContextWeakReferences());
|
||||
}
|
||||
|
||||
private static void ReleaseAndCollect(PluginSession plugins)
|
||||
{
|
||||
IReadOnlyList<WeakReference> contexts =
|
||||
plugins.CaptureLoadContextWeakReferences();
|
||||
plugins.Dispose();
|
||||
Collect(contexts);
|
||||
}
|
||||
|
||||
private static void Collect(IReadOnlyList<WeakReference> contexts)
|
||||
{
|
||||
for (int attempt = 0;
|
||||
attempt < 10 && contexts.Any(static context => context.IsAlive);
|
||||
attempt++)
|
||||
|
|
@ -90,6 +198,13 @@ public sealed class PluginSessionTests
|
|||
}
|
||||
|
||||
private static void InstallFixture(string root, string folder, string id)
|
||||
=> InstallFixture(root, folder, id, kinds: null);
|
||||
|
||||
private static void InstallFixture(
|
||||
string root,
|
||||
string folder,
|
||||
string id,
|
||||
IReadOnlyList<PluginKind>? kinds)
|
||||
{
|
||||
string source = FixturePluginPath();
|
||||
Assert.True(File.Exists(source), $"fixture DLL not found: {source}");
|
||||
|
|
@ -97,20 +212,25 @@ public sealed class PluginSessionTests
|
|||
Directory.CreateDirectory(pluginDirectory);
|
||||
string fileName = Path.GetFileName(source);
|
||||
File.Copy(source, Path.Combine(pluginDirectory, fileName));
|
||||
WriteManifest(pluginDirectory, id, fileName);
|
||||
WriteManifest(pluginDirectory, id, fileName, kinds);
|
||||
}
|
||||
|
||||
private static void InstallBroken(string root, string folder, string id)
|
||||
private static void InstallBroken(
|
||||
string root,
|
||||
string folder,
|
||||
string id,
|
||||
IReadOnlyList<PluginKind>? kinds = null)
|
||||
{
|
||||
string pluginDirectory = Path.Combine(root, folder);
|
||||
Directory.CreateDirectory(pluginDirectory);
|
||||
WriteManifest(pluginDirectory, id, "missing.dll");
|
||||
WriteManifest(pluginDirectory, id, "missing.dll", kinds);
|
||||
}
|
||||
|
||||
private static void WriteManifest(
|
||||
string directory,
|
||||
string id,
|
||||
string entryDll) =>
|
||||
string entryDll,
|
||||
IReadOnlyList<PluginKind>? kinds = null) =>
|
||||
File.WriteAllText(
|
||||
Path.Combine(directory, "plugin.json"),
|
||||
JsonSerializer.Serialize(new
|
||||
|
|
@ -120,8 +240,46 @@ public sealed class PluginSessionTests
|
|||
version = "1.0.0",
|
||||
entryDll,
|
||||
apiVersion = 1,
|
||||
kinds = kinds?.Select(static kind => kind.ToString()),
|
||||
}));
|
||||
|
||||
private sealed class RecordingRenderPackRegistry : IRenderPackRegistry
|
||||
{
|
||||
private readonly List<Registration> _registrations = [];
|
||||
|
||||
internal int ActiveCount => _registrations.Count;
|
||||
internal RenderPackDescriptor? Descriptor { get; private set; }
|
||||
|
||||
public IDisposable Register(
|
||||
RenderPackDescriptor descriptor,
|
||||
IRenderPackAssets assets)
|
||||
{
|
||||
Descriptor = descriptor;
|
||||
var registration = new Registration(this, assets);
|
||||
_registrations.Add(registration);
|
||||
return registration;
|
||||
}
|
||||
|
||||
private void Remove(Registration registration) =>
|
||||
_registrations.Remove(registration);
|
||||
|
||||
private sealed class Registration(
|
||||
RecordingRenderPackRegistry owner,
|
||||
IRenderPackAssets assets) : IDisposable
|
||||
{
|
||||
private RecordingRenderPackRegistry? _owner = owner;
|
||||
private IRenderPackAssets? _assets = assets;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
RecordingRenderPackRegistry? current =
|
||||
Interlocked.Exchange(ref _owner, null);
|
||||
_assets = null;
|
||||
current?.Remove(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string FixturePluginPath()
|
||||
{
|
||||
string configuration = new DirectoryInfo(AppContext.BaseDirectory)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue