mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-12 18:27:23 +01:00
Merge branch 'net5'
This commit is contained in:
commit
7648566325
8 changed files with 200 additions and 61 deletions
|
|
@ -27,7 +27,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Lumina" Version="3.7.0" />
|
<PackageReference Include="Lumina" Version="3.8.0" />
|
||||||
<PackageReference Include="Lumina.Excel" Version="6.1.1" />
|
<PackageReference Include="Lumina.Excel" Version="6.1.1" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.333">
|
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.333">
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="CheapLoc" Version="1.1.6" />
|
<PackageReference Include="CheapLoc" Version="1.1.6" />
|
||||||
<PackageReference Include="JetBrains.Annotations" Version="2021.2.0" />
|
<PackageReference Include="JetBrains.Annotations" Version="2021.2.0" />
|
||||||
<PackageReference Include="Lumina" Version="3.7.0" />
|
<PackageReference Include="Lumina" Version="3.8.0" />
|
||||||
<PackageReference Include="Lumina.Excel" Version="6.1.1" />
|
<PackageReference Include="Lumina.Excel" Version="6.1.1" />
|
||||||
<PackageReference Include="MinSharp" Version="1.0.4" />
|
<PackageReference Include="MinSharp" Version="1.0.4" />
|
||||||
<PackageReference Include="MonoMod.RuntimeDetour" Version="21.10.10.01" />
|
<PackageReference Include="MonoMod.RuntimeDetour" Version="21.10.10.01" />
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
|
||||||
namespace Dalamud.Game
|
namespace Dalamud.Game
|
||||||
{
|
{
|
||||||
|
|
@ -21,7 +22,16 @@ namespace Dalamud.Game
|
||||||
protected bool IsResolved { get; set; }
|
protected bool IsResolved { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Setup the resolver, calling the appopriate method based on the process architecture.
|
/// Setup the resolver, calling the appropriate method based on the process architecture,
|
||||||
|
/// using the default SigScanner.
|
||||||
|
///
|
||||||
|
/// For plugins. Not intended to be called from Dalamud Service{T} constructors.
|
||||||
|
/// </summary>
|
||||||
|
[UsedImplicitly]
|
||||||
|
public void Setup() => this.Setup(Service<SigScanner>.Get());
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Setup the resolver, calling the appropriate method based on the process architecture.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="scanner">The SigScanner instance.</param>
|
/// <param name="scanner">The SigScanner instance.</param>
|
||||||
public void Setup(SigScanner scanner)
|
public void Setup(SigScanner scanner)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
|
@ -27,7 +28,7 @@ namespace Dalamud.Game
|
||||||
private IntPtr moduleCopyPtr;
|
private IntPtr moduleCopyPtr;
|
||||||
private long moduleCopyOffset;
|
private long moduleCopyOffset;
|
||||||
|
|
||||||
private Dictionary<string, long>? textCache;
|
private ConcurrentDictionary<string, long>? textCache;
|
||||||
|
|
||||||
[ServiceManager.ServiceConstructor]
|
[ServiceManager.ServiceConstructor]
|
||||||
private SigScanner(DalamudStartInfo startInfo)
|
private SigScanner(DalamudStartInfo startInfo)
|
||||||
|
|
@ -340,10 +341,13 @@ namespace Dalamud.Game
|
||||||
/// <returns>The real offset of the found signature.</returns>
|
/// <returns>The real offset of the found signature.</returns>
|
||||||
public IntPtr ScanText(string signature)
|
public IntPtr ScanText(string signature)
|
||||||
{
|
{
|
||||||
if (this.textCache != null && this.textCache.TryGetValue(signature, out var address))
|
if (this.textCache != null)
|
||||||
|
{
|
||||||
|
if (this.textCache.TryGetValue(signature, out var address))
|
||||||
{
|
{
|
||||||
return new IntPtr(address + this.Module.BaseAddress.ToInt64());
|
return new IntPtr(address + this.Module.BaseAddress.ToInt64());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var mBase = this.IsCopy ? this.moduleCopyPtr : this.TextSectionBase;
|
var mBase = this.IsCopy ? this.moduleCopyPtr : this.TextSectionBase;
|
||||||
var scanRet = Scan(mBase, this.TextSectionSize, signature);
|
var scanRet = Scan(mBase, this.TextSectionSize, signature);
|
||||||
|
|
@ -356,7 +360,10 @@ namespace Dalamud.Game
|
||||||
if (insnByte == 0xE8 || insnByte == 0xE9)
|
if (insnByte == 0xE8 || insnByte == 0xE9)
|
||||||
scanRet = ReadJmpCallSig(scanRet);
|
scanRet = ReadJmpCallSig(scanRet);
|
||||||
|
|
||||||
this.textCache?.Add(signature, scanRet.ToInt64() - this.Module.BaseAddress.ToInt64());
|
if (this.textCache != null)
|
||||||
|
{
|
||||||
|
this.textCache[signature] = scanRet.ToInt64() - this.Module.BaseAddress.ToInt64();
|
||||||
|
}
|
||||||
|
|
||||||
return scanRet;
|
return scanRet;
|
||||||
}
|
}
|
||||||
|
|
@ -551,7 +558,7 @@ namespace Dalamud.Game
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.textCache = JsonConvert.DeserializeObject<Dictionary<string, long>>(File.ReadAllText(this.cacheFile.FullName)) ?? new Dictionary<string, long>();
|
this.textCache = JsonConvert.DeserializeObject<ConcurrentDictionary<string, long>>(File.ReadAllText(this.cacheFile.FullName)) ?? new ConcurrentDictionary<string, long>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -120,11 +120,6 @@ namespace Dalamud.Interface.Internal
|
||||||
|
|
||||||
private delegate void InstallRTSSHook();
|
private delegate void InstallRTSSHook();
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a task that gets completed when scene gets initialized.
|
|
||||||
/// </summary>
|
|
||||||
public Task SceneInitializeTask => this.sceneInitializeTaskCompletionSource.Task;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This event gets called each frame to facilitate ImGui drawing.
|
/// This event gets called each frame to facilitate ImGui drawing.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -165,6 +160,11 @@ namespace Dalamud.Interface.Internal
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static ImFontPtr MonoFont { get; private set; }
|
public static ImFontPtr MonoFont { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a task that gets completed when scene gets initialized.
|
||||||
|
/// </summary>
|
||||||
|
public Task SceneInitializeTask => this.sceneInitializeTaskCompletionSource.Task;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the pointer to ImGui.IO(), when it was last used.
|
/// Gets or sets the pointer to ImGui.IO(), when it was last used.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -448,7 +448,6 @@ namespace Dalamud.Interface.Internal
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
this.scene = new RawDX11Scene(swapChain);
|
this.scene = new RawDX11Scene(swapChain);
|
||||||
this.sceneInitializeTaskCompletionSource.SetResult();
|
|
||||||
}
|
}
|
||||||
catch (DllNotFoundException ex)
|
catch (DllNotFoundException ex)
|
||||||
{
|
{
|
||||||
|
|
@ -568,11 +567,17 @@ namespace Dalamud.Interface.Internal
|
||||||
|
|
||||||
this.RenderImGui();
|
this.RenderImGui();
|
||||||
|
|
||||||
|
if (!this.SceneInitializeTask.IsCompleted)
|
||||||
|
this.sceneInitializeTaskCompletionSource.SetResult();
|
||||||
|
|
||||||
return pRes;
|
return pRes;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.RenderImGui();
|
this.RenderImGui();
|
||||||
|
|
||||||
|
if (!this.SceneInitializeTask.IsCompleted)
|
||||||
|
this.sceneInitializeTaskCompletionSource.SetResult();
|
||||||
|
|
||||||
return this.presentHook.Original(swapChain, syncInterval, presentFlags);
|
return this.presentHook.Original(swapChain, syncInterval, presentFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,9 @@ namespace Dalamud.Interface.Internal.Windows.PluginInstaller
|
||||||
MaximumSize = new Vector2(5000, 5000),
|
MaximumSize = new Vector2(5000, 5000),
|
||||||
};
|
};
|
||||||
|
|
||||||
var pluginManager = Service<PluginManager>.Get();
|
Service<PluginManager>.GetAsync().ContinueWith(pluginManagerTask =>
|
||||||
|
{
|
||||||
|
var pluginManager = pluginManagerTask.Result;
|
||||||
|
|
||||||
// For debugging
|
// For debugging
|
||||||
if (pluginManager.PluginsReady)
|
if (pluginManager.PluginsReady)
|
||||||
|
|
@ -116,6 +118,7 @@ namespace Dalamud.Interface.Internal.Windows.PluginInstaller
|
||||||
{
|
{
|
||||||
this.testerImagePaths[i] = string.Empty;
|
this.testerImagePaths[i] = string.Empty;
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum OperationStatus
|
private enum OperationStatus
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
@ -16,10 +17,13 @@ using Dalamud.Game;
|
||||||
using Dalamud.Game.Gui;
|
using Dalamud.Game.Gui;
|
||||||
using Dalamud.Game.Gui.Dtr;
|
using Dalamud.Game.Gui.Dtr;
|
||||||
using Dalamud.Game.Text;
|
using Dalamud.Game.Text;
|
||||||
|
using Dalamud.Interface;
|
||||||
|
using Dalamud.Interface.Internal;
|
||||||
using Dalamud.Logging.Internal;
|
using Dalamud.Logging.Internal;
|
||||||
using Dalamud.Plugin.Internal.Exceptions;
|
using Dalamud.Plugin.Internal.Exceptions;
|
||||||
using Dalamud.Plugin.Internal.Types;
|
using Dalamud.Plugin.Internal.Types;
|
||||||
using Dalamud.Utility;
|
using Dalamud.Utility;
|
||||||
|
using Dalamud.Utility.Timing;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace Dalamud.Plugin.Internal;
|
namespace Dalamud.Plugin.Internal;
|
||||||
|
|
@ -37,6 +41,7 @@ internal partial class PluginManager : IDisposable
|
||||||
|
|
||||||
private static readonly ModuleLog Log = new("PLUGINM");
|
private static readonly ModuleLog Log = new("PLUGINM");
|
||||||
|
|
||||||
|
private readonly object pluginListLock = new();
|
||||||
private readonly DirectoryInfo pluginDirectory;
|
private readonly DirectoryInfo pluginDirectory;
|
||||||
private readonly DirectoryInfo devPluginDirectory;
|
private readonly DirectoryInfo devPluginDirectory;
|
||||||
private readonly BannedPlugin[] bannedPlugins;
|
private readonly BannedPlugin[] bannedPlugins;
|
||||||
|
|
@ -310,13 +315,18 @@ internal partial class PluginManager : IDisposable
|
||||||
// Dev plugins should load first.
|
// Dev plugins should load first.
|
||||||
pluginDefs.InsertRange(0, devPluginDefs);
|
pluginDefs.InsertRange(0, devPluginDefs);
|
||||||
|
|
||||||
void LoadPlugins(IEnumerable<PluginDef> pluginDefsList)
|
void LoadPluginOnBoot(string logPrefix, PluginDef pluginDef)
|
||||||
{
|
{
|
||||||
foreach (var pluginDef in pluginDefsList)
|
using (Timings.Start($"{pluginDef.DllFile.Name}: {logPrefix}Boot"))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
this.LoadPlugin(pluginDef.DllFile, pluginDef.Manifest, PluginLoadReason.Boot, pluginDef.IsDev, isBoot: true);
|
this.LoadPlugin(
|
||||||
|
pluginDef.DllFile,
|
||||||
|
pluginDef.Manifest,
|
||||||
|
PluginLoadReason.Boot,
|
||||||
|
pluginDef.IsDev,
|
||||||
|
isBoot: true);
|
||||||
}
|
}
|
||||||
catch (InvalidPluginException)
|
catch (InvalidPluginException)
|
||||||
{
|
{
|
||||||
|
|
@ -324,25 +334,93 @@ internal partial class PluginManager : IDisposable
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Log.Error(ex, "During boot plugin load, an unexpected error occurred");
|
Log.Error(ex, "{0}: During boot plugin load, an unexpected error occurred", logPrefix);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load sync plugins
|
void LoadPluginsSync(string logPrefix, IEnumerable<PluginDef> pluginDefsList)
|
||||||
var syncPlugins = pluginDefs.Where(def => def.Manifest?.LoadPriority > 0);
|
{
|
||||||
LoadPlugins(syncPlugins);
|
foreach (var pluginDef in pluginDefsList)
|
||||||
|
LoadPluginOnBoot(logPrefix, pluginDef);
|
||||||
|
}
|
||||||
|
|
||||||
var asyncPlugins = pluginDefs.Where(def => def.Manifest == null || def.Manifest.LoadPriority <= 0);
|
Task LoadPluginsAsync(string logPrefix, IEnumerable<PluginDef> pluginDefsList)
|
||||||
Task.Run(() => LoadPlugins(asyncPlugins))
|
{
|
||||||
.ContinueWith(_ =>
|
return Task.WhenAll(
|
||||||
|
pluginDefsList
|
||||||
|
.Select(pluginDef => Task.Run(() => LoadPluginOnBoot(logPrefix, pluginDef)))
|
||||||
|
.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
var syncPlugins = pluginDefs.Where(def => def.Manifest?.LoadSync == true).ToList();
|
||||||
|
var asyncPlugins = pluginDefs.Where(def => def.Manifest?.LoadSync != true).ToList();
|
||||||
|
var loadTasks = new List<Task>();
|
||||||
|
|
||||||
|
// Load plugins that can be loaded anytime
|
||||||
|
LoadPluginsSync(
|
||||||
|
"AnytimeSync",
|
||||||
|
syncPlugins.Where(def => def.Manifest?.LoadRequiredState == 2));
|
||||||
|
loadTasks.Add(
|
||||||
|
LoadPluginsAsync(
|
||||||
|
"AnytimeAsync",
|
||||||
|
asyncPlugins.Where(def => def.Manifest?.LoadRequiredState == 2)));
|
||||||
|
|
||||||
|
// Load plugins that want to be loaded during Framework.Tick
|
||||||
|
loadTasks.Add(
|
||||||
|
Service<Framework>
|
||||||
|
.GetAsync()
|
||||||
|
.ContinueWith(
|
||||||
|
x => x.Result.RunOnTick(
|
||||||
|
() => LoadPluginsSync(
|
||||||
|
"FrameworkTickSync",
|
||||||
|
syncPlugins.Where(def => def.Manifest?.LoadRequiredState == 1))),
|
||||||
|
TaskContinuationOptions.RunContinuationsAsynchronously)
|
||||||
|
.Unwrap()
|
||||||
|
.ContinueWith(
|
||||||
|
_ => LoadPluginsAsync(
|
||||||
|
"FrameworkTickAsync",
|
||||||
|
asyncPlugins.Where(def => def.Manifest?.LoadRequiredState == 1)),
|
||||||
|
TaskContinuationOptions.RunContinuationsAsynchronously)
|
||||||
|
.Unwrap());
|
||||||
|
|
||||||
|
// Load plugins that want to be loaded during Framework.Tick, when drawing facilities are available
|
||||||
|
loadTasks.Add(
|
||||||
|
Service<InterfaceManager>
|
||||||
|
.GetAsync()
|
||||||
|
.ContinueWith(
|
||||||
|
x => x.Result.SceneInitializeTask,
|
||||||
|
TaskContinuationOptions.RunContinuationsAsynchronously)
|
||||||
|
.Unwrap()
|
||||||
|
.ContinueWith(
|
||||||
|
_ => Service<Framework>.Get().RunOnTick(() =>
|
||||||
|
{
|
||||||
|
LoadPluginsSync(
|
||||||
|
"DrawAvailableSync",
|
||||||
|
syncPlugins.Where(def => def.Manifest?.LoadRequiredState is 0 or null));
|
||||||
|
return LoadPluginsAsync(
|
||||||
|
"DrawAvailableAsync",
|
||||||
|
asyncPlugins.Where(def => def.Manifest?.LoadRequiredState is 0 or null));
|
||||||
|
}))
|
||||||
|
.Unwrap());
|
||||||
|
|
||||||
|
// Save signatures when all plugins are done loading, successful or not.
|
||||||
|
_ = Task
|
||||||
|
.WhenAll(loadTasks)
|
||||||
|
.ContinueWith(
|
||||||
|
_ => Service<SigScanner>.GetAsync(),
|
||||||
|
TaskContinuationOptions.RunContinuationsAsynchronously)
|
||||||
|
.Unwrap()
|
||||||
|
.ContinueWith(
|
||||||
|
sigScannerTask =>
|
||||||
{
|
{
|
||||||
this.PluginsReady = true;
|
this.PluginsReady = true;
|
||||||
this.NotifyInstalledPluginsChanged();
|
this.NotifyInstalledPluginsChanged();
|
||||||
|
|
||||||
// Save signatures, makes sense to do it here since all plugins will be loaded
|
sigScannerTask.Result.Save();
|
||||||
Service<SigScanner>.Get().Save();
|
},
|
||||||
});
|
TaskContinuationOptions.RunContinuationsAsynchronously)
|
||||||
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -352,6 +430,8 @@ internal partial class PluginManager : IDisposable
|
||||||
{
|
{
|
||||||
var aggregate = new List<Exception>();
|
var aggregate = new List<Exception>();
|
||||||
|
|
||||||
|
lock (this.pluginListLock)
|
||||||
|
{
|
||||||
foreach (var plugin in this.InstalledPlugins)
|
foreach (var plugin in this.InstalledPlugins)
|
||||||
{
|
{
|
||||||
if (plugin.IsLoaded)
|
if (plugin.IsLoaded)
|
||||||
|
|
@ -368,6 +448,7 @@ internal partial class PluginManager : IDisposable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (aggregate.Any())
|
if (aggregate.Any())
|
||||||
{
|
{
|
||||||
|
|
@ -444,8 +525,11 @@ internal partial class PluginManager : IDisposable
|
||||||
foreach (var dllFile in devDllFiles)
|
foreach (var dllFile in devDllFiles)
|
||||||
{
|
{
|
||||||
// This file is already known to us
|
// This file is already known to us
|
||||||
|
lock (this.pluginListLock)
|
||||||
|
{
|
||||||
if (this.InstalledPlugins.Any(lp => lp.DllFile.FullName == dllFile.FullName))
|
if (this.InstalledPlugins.Any(lp => lp.DllFile.FullName == dllFile.FullName))
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Manifests are not required for devPlugins. the Plugin type will handle any null manifests.
|
// Manifests are not required for devPlugins. the Plugin type will handle any null manifests.
|
||||||
var manifestFile = LocalPluginManifest.GetManifestFile(dllFile);
|
var manifestFile = LocalPluginManifest.GetManifestFile(dllFile);
|
||||||
|
|
@ -624,7 +708,7 @@ internal partial class PluginManager : IDisposable
|
||||||
}
|
}
|
||||||
catch (InvalidPluginException)
|
catch (InvalidPluginException)
|
||||||
{
|
{
|
||||||
PluginLocations.Remove(plugin.AssemblyName?.FullName ?? string.Empty);
|
PluginLocations.Remove(plugin.AssemblyName?.FullName ?? string.Empty, out _);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
catch (BannedPluginException)
|
catch (BannedPluginException)
|
||||||
|
|
@ -647,13 +731,17 @@ internal partial class PluginManager : IDisposable
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PluginLocations.Remove(plugin.AssemblyName?.FullName ?? string.Empty);
|
PluginLocations.Remove(plugin.AssemblyName?.FullName ?? string.Empty, out _);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lock (this.pluginListLock)
|
||||||
|
{
|
||||||
this.InstalledPlugins = this.InstalledPlugins.Add(plugin);
|
this.InstalledPlugins = this.InstalledPlugins.Add(plugin);
|
||||||
|
}
|
||||||
|
|
||||||
return plugin;
|
return plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -666,8 +754,12 @@ internal partial class PluginManager : IDisposable
|
||||||
if (plugin.State != PluginState.Unloaded)
|
if (plugin.State != PluginState.Unloaded)
|
||||||
throw new InvalidPluginOperationException($"Unable to remove {plugin.Name}, not unloaded");
|
throw new InvalidPluginOperationException($"Unable to remove {plugin.Name}, not unloaded");
|
||||||
|
|
||||||
|
lock (this.pluginListLock)
|
||||||
|
{
|
||||||
this.InstalledPlugins = this.InstalledPlugins.Remove(plugin);
|
this.InstalledPlugins = this.InstalledPlugins.Remove(plugin);
|
||||||
PluginLocations.Remove(plugin.AssemblyName?.FullName ?? string.Empty);
|
}
|
||||||
|
|
||||||
|
PluginLocations.Remove(plugin.AssemblyName?.FullName ?? string.Empty, out _);
|
||||||
|
|
||||||
this.NotifyInstalledPluginsChanged();
|
this.NotifyInstalledPluginsChanged();
|
||||||
this.NotifyAvailablePluginsChanged();
|
this.NotifyAvailablePluginsChanged();
|
||||||
|
|
@ -834,8 +926,11 @@ internal partial class PluginManager : IDisposable
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
plugin.DllFile.Delete();
|
plugin.DllFile.Delete();
|
||||||
|
lock (this.pluginListLock)
|
||||||
|
{
|
||||||
this.InstalledPlugins = this.InstalledPlugins.Remove(plugin);
|
this.InstalledPlugins = this.InstalledPlugins.Remove(plugin);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Log.Error(ex, "Error during delete (update)");
|
Log.Error(ex, "Error during delete (update)");
|
||||||
|
|
@ -848,8 +943,11 @@ internal partial class PluginManager : IDisposable
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
plugin.Disable();
|
plugin.Disable();
|
||||||
|
lock (this.pluginListLock)
|
||||||
|
{
|
||||||
this.InstalledPlugins = this.InstalledPlugins.Remove(plugin);
|
this.InstalledPlugins = this.InstalledPlugins.Remove(plugin);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Log.Error(ex, "Error during disable (update)");
|
Log.Error(ex, "Error during disable (update)");
|
||||||
|
|
@ -1030,7 +1128,7 @@ internal partial class PluginManager
|
||||||
/// A mapping of plugin assembly name to patch data. Used to fill in missing data due to loading
|
/// A mapping of plugin assembly name to patch data. Used to fill in missing data due to loading
|
||||||
/// plugins via byte[].
|
/// plugins via byte[].
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static readonly Dictionary<string, PluginPatchData> PluginLocations = new();
|
internal static readonly ConcurrentDictionary<string, PluginPatchData> PluginLocations = new();
|
||||||
|
|
||||||
private MonoMod.RuntimeDetour.Hook? assemblyLocationMonoHook;
|
private MonoMod.RuntimeDetour.Hook? assemblyLocationMonoHook;
|
||||||
private MonoMod.RuntimeDetour.Hook? assemblyCodeBaseMonoHook;
|
private MonoMod.RuntimeDetour.Hook? assemblyCodeBaseMonoHook;
|
||||||
|
|
|
||||||
|
|
@ -134,6 +134,22 @@ internal record PluginManifest
|
||||||
[JsonProperty]
|
[JsonProperty]
|
||||||
public string DownloadLinkTesting { get; init; } = null!;
|
public string DownloadLinkTesting { get; init; } = null!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the required Dalamud load step for this plugin to load. Takes precedence over LoadPriority.
|
||||||
|
/// Valid values are:
|
||||||
|
/// 0. During Framework.Tick, when drawing facilities are available
|
||||||
|
/// 1. During Framework.Tick
|
||||||
|
/// 2. No requirement
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty]
|
||||||
|
public int LoadRequiredState { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether Dalamud must load this plugin not at the same time with other plugins and the game.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty]
|
||||||
|
public bool LoadSync { get; init; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the load priority for this plugin. Higher values means higher priority. 0 is default priority.
|
/// Gets the load priority for this plugin. Higher values means higher priority. 0 is default priority.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue