Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions NWN.Anvil/src/main/Plugins/Plugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,10 @@ internal void Load()
}
}

internal WeakReference Unload()
internal WeakReference Unload(bool immediateDispose)
{
RemoveResourceDirectory();
RemoveIsolatedContainer();
RemoveIsolatedContainer(immediateDispose);

Assembly = null;
PluginTypes = null;
Expand Down Expand Up @@ -204,11 +204,11 @@ private void RemoveResourceDirectory()
}
}

private void RemoveIsolatedContainer()
private void RemoveIsolatedContainer(bool immediateDispose)
{
if (Container != null)
{
ServiceManager.DisposePluginContainer(Container, this);
ServiceManager.DisposePluginContainer(Container, this, immediateDispose);
Container = null;
}
}
Expand Down
8 changes: 4 additions & 4 deletions NWN.Anvil/src/main/Plugins/PluginManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ public WeakReference UnloadPlugin(Plugin plugin, bool waitForUnload = true)
throw new InvalidOperationException($"Non-isolated plugin {plugin.Name} may not be unloaded at runtime.");
}

WeakReference pluginRef = UnloadPluginInternal(plugin);
WeakReference pluginRef = UnloadPluginInternal(plugin, waitForUnload);
if (waitForUnload)
{
WaitForPendingUnloads(new Dictionary<WeakReference, string>
Expand Down Expand Up @@ -201,7 +201,7 @@ void ICoreService.Unload()
foreach (Plugin plugin in Plugins)
{
bool waitForUnload = EnvironmentConfig.ReloadEnabled || plugin.PluginInfo.Isolated;
WeakReference pluginRef = UnloadPluginInternal(plugin);
WeakReference pluginRef = UnloadPluginInternal(plugin, waitForUnload);

if (waitForUnload)
{
Expand Down Expand Up @@ -306,12 +306,12 @@ private void LoadPluginInternal(Plugin plugin)
}
}

private WeakReference UnloadPluginInternal(Plugin plugin)
private WeakReference UnloadPluginInternal(Plugin plugin, bool immediateDispose)
{
if (plugin.IsLoaded)
{
Log.Info("Unloading DotNET plugin {PluginName} - {PluginPath}", plugin.Name.Name, plugin.Path);
return plugin.Unload();
return plugin.Unload(immediateDispose);
}

return new WeakReference(null);
Expand Down
16 changes: 15 additions & 1 deletion NWN.Anvil/src/main/Services/Messages/AnvilMessageService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,19 @@ internal sealed class AnvilMessageService : ICoreService
[Inject]
private IServiceManager ServiceManager { get; init; } = null!;

private bool updateTargetsModified;

internal void RunServerLoop()
{
for (int i = 0; i < updateTargets.Count; i++)
{
updateTargets[i].Update();

if (updateTargetsModified)
{
updateTargetsModified = false;
break;
}
}

if (pendingAddTargets.Count > 0 || pendingRemoveTargets.Count > 0)
Expand Down Expand Up @@ -56,14 +64,20 @@ private void OnContainerCreate(IServiceContainer container, Plugin? plugin)
pendingAddTargets.AddRange(container.GetAllInstances<IUpdateable>().OrderBy(service => service.GetType().GetServicePriority()));
}

private void OnContainerDispose(IServiceContainer container, Plugin? plugin)
private void OnContainerDispose(IServiceContainer container, Plugin? plugin, bool immediateDispose)
{
pendingRemoveTargets.AddRange(container.GetAllInstances<IUpdateable>());

foreach (ILateDisposable lateDisposeTarget in container.GetAllInstances<ILateDisposable>())
{
lateDisposeTargets.Add(lateDisposeTarget);
}

if (immediateDispose)
{
UpdateLoopList();
updateTargetsModified = true;
}
}

void ICoreService.Init()
Expand Down
8 changes: 4 additions & 4 deletions NWN.Anvil/src/main/Services/Services/AnvilServiceManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ internal sealed class AnvilServiceManager : IServiceManager
public ServiceContainer CoreServiceContainer { get; }

public event Action<IServiceContainer, Plugin?>? OnContainerCreate;
public event Action<IServiceContainer, Plugin?>? OnContainerDispose;
public event Action<IServiceContainer, Plugin?, bool>? OnContainerDispose;
public event Action<IServiceContainer, Plugin?>? OnContainerPostDispose;

public AnvilServiceManager()
Expand Down Expand Up @@ -68,9 +68,9 @@ IServiceContainer IServiceManager.CreatePluginContainer(Plugin plugin)
return pluginContainer;
}

void IServiceManager.DisposePluginContainer(IServiceContainer container, Plugin plugin)
void IServiceManager.DisposePluginContainer(IServiceContainer container, Plugin plugin, bool immediateDispose)
{
OnContainerDispose?.Invoke(container, plugin);
OnContainerDispose?.Invoke(container, plugin, immediateDispose);
container.Dispose();
OnContainerPostDispose?.Invoke(container, plugin);
}
Expand Down Expand Up @@ -153,7 +153,7 @@ private void UnloadAnvilServices()
Log.Info("Unloading anvil services...");

// This must always happen in a separate scope/method, otherwise in Debug and some Release configurations, AnvilServiceContainer will hold a strong reference and prevent plugin unload.
OnContainerDispose?.Invoke(AnvilServiceContainer, null);
OnContainerDispose?.Invoke(AnvilServiceContainer, null, true);
AnvilServiceContainer.Dispose();
AnvilServiceContainer = anvilContainerFactory.CreateContainer(CoreServiceContainer);
}
Expand Down
5 changes: 3 additions & 2 deletions NWN.Anvil/src/main/Services/Services/IServiceManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public interface IServiceManager
/// <summary>
/// Called when a service container is about to be disposed.
/// </summary>
event Action<IServiceContainer, Plugin?> OnContainerDispose;
event Action<IServiceContainer, Plugin?, bool> OnContainerDispose;

/// <summary>
/// Called when a service container has been disposed.
Expand All @@ -52,7 +52,8 @@ public interface IServiceManager
/// </summary>
/// <param name="container">The container to dispose.</param>
/// <param name="plugin">The plugin owning this container.</param>
void DisposePluginContainer(IServiceContainer container, Plugin plugin);
/// <param name="immediate">If the plugin container should complete dispose immediately (true) or at the end of the current frame (false)</param>
void DisposePluginContainer(IServiceContainer container, Plugin plugin, bool immediate);

/// <summary>
/// Called during NWNX initialization. Core services should be initialized here.
Expand Down
Loading