Skip to content

Commit 652f653

Browse files
authored
Refresh IUpdateable list immediately when waiting for plugin unload. (#801)
1 parent 69ed36a commit 652f653

File tree

5 files changed

+30
-15
lines changed

5 files changed

+30
-15
lines changed

NWN.Anvil/src/main/Plugins/Plugin.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,10 @@ internal void Load()
108108
}
109109
}
110110

111-
internal WeakReference Unload()
111+
internal WeakReference Unload(bool immediateDispose)
112112
{
113113
RemoveResourceDirectory();
114-
RemoveIsolatedContainer();
114+
RemoveIsolatedContainer(immediateDispose);
115115

116116
Assembly = null;
117117
PluginTypes = null;
@@ -204,11 +204,11 @@ private void RemoveResourceDirectory()
204204
}
205205
}
206206

207-
private void RemoveIsolatedContainer()
207+
private void RemoveIsolatedContainer(bool immediateDispose)
208208
{
209209
if (Container != null)
210210
{
211-
ServiceManager.DisposePluginContainer(Container, this);
211+
ServiceManager.DisposePluginContainer(Container, this, immediateDispose);
212212
Container = null;
213213
}
214214
}

NWN.Anvil/src/main/Plugins/PluginManager.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ public WeakReference UnloadPlugin(Plugin plugin, bool waitForUnload = true)
154154
throw new InvalidOperationException($"Non-isolated plugin {plugin.Name} may not be unloaded at runtime.");
155155
}
156156

157-
WeakReference pluginRef = UnloadPluginInternal(plugin);
157+
WeakReference pluginRef = UnloadPluginInternal(plugin, waitForUnload);
158158
if (waitForUnload)
159159
{
160160
WaitForPendingUnloads(new Dictionary<WeakReference, string>
@@ -201,7 +201,7 @@ void ICoreService.Unload()
201201
foreach (Plugin plugin in Plugins)
202202
{
203203
bool waitForUnload = EnvironmentConfig.ReloadEnabled || plugin.PluginInfo.Isolated;
204-
WeakReference pluginRef = UnloadPluginInternal(plugin);
204+
WeakReference pluginRef = UnloadPluginInternal(plugin, waitForUnload);
205205

206206
if (waitForUnload)
207207
{
@@ -306,12 +306,12 @@ private void LoadPluginInternal(Plugin plugin)
306306
}
307307
}
308308

309-
private WeakReference UnloadPluginInternal(Plugin plugin)
309+
private WeakReference UnloadPluginInternal(Plugin plugin, bool immediateDispose)
310310
{
311311
if (plugin.IsLoaded)
312312
{
313313
Log.Info("Unloading DotNET plugin {PluginName} - {PluginPath}", plugin.Name.Name, plugin.Path);
314-
return plugin.Unload();
314+
return plugin.Unload(immediateDispose);
315315
}
316316

317317
return new WeakReference(null);

NWN.Anvil/src/main/Services/Messages/AnvilMessageService.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,19 @@ internal sealed class AnvilMessageService : ICoreService
1717
[Inject]
1818
private IServiceManager ServiceManager { get; init; } = null!;
1919

20+
private bool updateTargetsModified;
21+
2022
internal void RunServerLoop()
2123
{
2224
for (int i = 0; i < updateTargets.Count; i++)
2325
{
2426
updateTargets[i].Update();
27+
28+
if (updateTargetsModified)
29+
{
30+
updateTargetsModified = false;
31+
break;
32+
}
2533
}
2634

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

59-
private void OnContainerDispose(IServiceContainer container, Plugin? plugin)
67+
private void OnContainerDispose(IServiceContainer container, Plugin? plugin, bool immediateDispose)
6068
{
6169
pendingRemoveTargets.AddRange(container.GetAllInstances<IUpdateable>());
6270

6371
foreach (ILateDisposable lateDisposeTarget in container.GetAllInstances<ILateDisposable>())
6472
{
6573
lateDisposeTargets.Add(lateDisposeTarget);
6674
}
75+
76+
if (immediateDispose)
77+
{
78+
UpdateLoopList();
79+
updateTargetsModified = true;
80+
}
6781
}
6882

6983
void ICoreService.Init()

NWN.Anvil/src/main/Services/Services/AnvilServiceManager.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ internal sealed class AnvilServiceManager : IServiceManager
2424
public ServiceContainer CoreServiceContainer { get; }
2525

2626
public event Action<IServiceContainer, Plugin?>? OnContainerCreate;
27-
public event Action<IServiceContainer, Plugin?>? OnContainerDispose;
27+
public event Action<IServiceContainer, Plugin?, bool>? OnContainerDispose;
2828
public event Action<IServiceContainer, Plugin?>? OnContainerPostDispose;
2929

3030
public AnvilServiceManager()
@@ -68,9 +68,9 @@ IServiceContainer IServiceManager.CreatePluginContainer(Plugin plugin)
6868
return pluginContainer;
6969
}
7070

71-
void IServiceManager.DisposePluginContainer(IServiceContainer container, Plugin plugin)
71+
void IServiceManager.DisposePluginContainer(IServiceContainer container, Plugin plugin, bool immediateDispose)
7272
{
73-
OnContainerDispose?.Invoke(container, plugin);
73+
OnContainerDispose?.Invoke(container, plugin, immediateDispose);
7474
container.Dispose();
7575
OnContainerPostDispose?.Invoke(container, plugin);
7676
}
@@ -153,7 +153,7 @@ private void UnloadAnvilServices()
153153
Log.Info("Unloading anvil services...");
154154

155155
// 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.
156-
OnContainerDispose?.Invoke(AnvilServiceContainer, null);
156+
OnContainerDispose?.Invoke(AnvilServiceContainer, null, true);
157157
AnvilServiceContainer.Dispose();
158158
AnvilServiceContainer = anvilContainerFactory.CreateContainer(CoreServiceContainer);
159159
}

NWN.Anvil/src/main/Services/Services/IServiceManager.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public interface IServiceManager
2727
/// <summary>
2828
/// Called when a service container is about to be disposed.
2929
/// </summary>
30-
event Action<IServiceContainer, Plugin?> OnContainerDispose;
30+
event Action<IServiceContainer, Plugin?, bool> OnContainerDispose;
3131

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

5758
/// <summary>
5859
/// Called during NWNX initialization. Core services should be initialized here.

0 commit comments

Comments
 (0)