fix: make plugin work on stock Dalamud
Use some horrible, cursed AppDomain shit to load dependencies that break on normal Dalamud in their own environment, then do classification there instead.
This commit is contained in:
parent
76462ff628
commit
22ebb14e40
|
@ -1,35 +0,0 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Channels;
|
||||
using Microsoft.ML;
|
||||
|
||||
namespace NoSoliciting.Classifier {
|
||||
public class Classifier : IDisposable {
|
||||
private string ConfigPath { get; }
|
||||
|
||||
private MLContext Context { get; }
|
||||
private ITransformer Model { get; }
|
||||
private DataViewSchema Schema { get; }
|
||||
|
||||
private PredictionEngine<MessageData, MessagePrediction> PredictionEngine { get; }
|
||||
|
||||
public Classifier(string configPath) {
|
||||
this.ConfigPath = configPath;
|
||||
|
||||
this.Context = new MLContext();
|
||||
this.Model = this.Context.Model.Load(Path.Combine(this.ConfigPath, "model.zip"), out var schema);
|
||||
this.Schema = schema;
|
||||
this.PredictionEngine = this.Context.Model.CreatePredictionEngine<MessageData, MessagePrediction>(this.Model, this.Schema);
|
||||
}
|
||||
|
||||
public string Classify(ushort channel, string message) {
|
||||
var data = new MessageData(channel, message);
|
||||
var pred = this.PredictionEngine.Predict(data);
|
||||
return pred.Category;
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
this.PredictionEngine.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
using Microsoft.ML.Data;
|
||||
|
||||
namespace NoSoliciting.Classifier {
|
||||
public class MessageData {
|
||||
public string? Category { get; }
|
||||
|
||||
public uint Channel { get; }
|
||||
|
||||
public string Message { get; }
|
||||
|
||||
public MessageData(uint channel, string message) {
|
||||
this.Channel = channel;
|
||||
this.Message = message;
|
||||
}
|
||||
}
|
||||
|
||||
public class MessagePrediction {
|
||||
[ColumnName("PredictedLabel")]
|
||||
public string Category { get; set; } = null!;
|
||||
|
||||
[ColumnName("Score")]
|
||||
public float[] Probabilities { get; set; } = null!;
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<configuration>
|
||||
<runtime>
|
||||
<assemblyBinding>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Numerics.Vectors"
|
||||
culture="neutral"
|
||||
publicKeyToken="b03f5f7f11d50a3a" />
|
||||
<bindingRedirect oldVersion="4.1.3.0"
|
||||
newVersion="4.1.4.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
|
@ -0,0 +1,31 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.ML;
|
||||
using NoSoliciting.Interface;
|
||||
|
||||
namespace NoSoliciting.CursedWorkaround {
|
||||
[Serializable]
|
||||
public class CursedWorkaround : MarshalByRefObject, IClassifier, IDisposable {
|
||||
private MLContext Context { get; set; } = null!;
|
||||
private ITransformer Model { get; set; } = null!;
|
||||
private DataViewSchema Schema { get; set; } = null!;
|
||||
private PredictionEngine<MessageData, MessagePrediction> PredictionEngine { get; set; } = null!;
|
||||
|
||||
public void Initialise(byte[] data) {
|
||||
this.Context = new MLContext();
|
||||
using var stream = new MemoryStream(data);
|
||||
var model = this.Context.Model.Load(stream, out var schema);
|
||||
this.Model = model;
|
||||
this.Schema = schema;
|
||||
this.PredictionEngine = this.Context.Model.CreatePredictionEngine<MessageData, MessagePrediction>(this.Model, this.Schema);
|
||||
}
|
||||
|
||||
public string Classify(ushort channel, string message) {
|
||||
return this.PredictionEngine.Predict(new MessageData(channel, message)).Category;
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
this.PredictionEngine.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,14 +3,7 @@
|
|||
<Costura>
|
||||
<ExcludeAssemblies>
|
||||
Costura
|
||||
NoSoliciting.Interface
|
||||
</ExcludeAssemblies>
|
||||
<Unmanaged64Assemblies>
|
||||
CpuMathNative
|
||||
LdaNative
|
||||
</Unmanaged64Assemblies>
|
||||
<PreloadOrder>
|
||||
CpuMathNative
|
||||
LdaNative
|
||||
</PreloadOrder>
|
||||
</Costura>
|
||||
</Weavers>
|
|
@ -0,0 +1,63 @@
|
|||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.ML.Data;
|
||||
|
||||
namespace NoSoliciting.CursedWorkaround {
|
||||
public class MessageData {
|
||||
private static readonly Regex WardRegex = new Regex(@"w.{0,2}\d", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
private static readonly Regex PlotRegex = new Regex(@"p.{0,2}\d", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
private static readonly string[] PlotWords = {
|
||||
"plot",
|
||||
"apartment",
|
||||
"apt",
|
||||
};
|
||||
|
||||
private static readonly Regex NumbersRegex = new Regex(@"\d{1,2}.{0,2}\d{1,2}", RegexOptions.Compiled);
|
||||
|
||||
private static readonly string[] TradeWords = {
|
||||
"B>",
|
||||
"S>",
|
||||
"buy",
|
||||
"sell",
|
||||
};
|
||||
|
||||
public string? Category { get; }
|
||||
|
||||
public uint Channel { get; }
|
||||
|
||||
public string Message { get; }
|
||||
|
||||
public bool PartyFinder => this.Channel == 0;
|
||||
|
||||
public bool Shout => this.Channel == 11 || this.Channel == 30;
|
||||
|
||||
public bool ContainsWard => this.Message.ContainsIgnoreCase("ward") || WardRegex.IsMatch(this.Message);
|
||||
|
||||
public bool ContainsPlot => PlotWords.Any(word => this.Message.ContainsIgnoreCase(word)) || PlotRegex.IsMatch(this.Message);
|
||||
|
||||
public bool ContainsHousingNumbers => NumbersRegex.IsMatch(this.Message);
|
||||
|
||||
public bool ContainsTradeWords => TradeWords.Any(word => this.Message.ContainsIgnoreCase(word));
|
||||
|
||||
public MessageData(uint channel, string message) {
|
||||
this.Channel = channel;
|
||||
this.Message = message;
|
||||
}
|
||||
}
|
||||
|
||||
public class MessagePrediction {
|
||||
[ColumnName("PredictedLabel")]
|
||||
public string Category { get; set; } = null!;
|
||||
|
||||
[ColumnName("Score")]
|
||||
public float[] Probabilities { get; set; } = null!;
|
||||
}
|
||||
|
||||
public static class RmtExtensions {
|
||||
public static bool ContainsIgnoreCase(this string haystack, string needle) {
|
||||
return CultureInfo.InvariantCulture.CompareInfo.IndexOf(haystack, needle, CompareOptions.IgnoreCase) >= 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,16 +2,9 @@
|
|||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net48</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<LangVersion>8</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<Nullable>enable</Nullable>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -25,4 +18,13 @@
|
|||
<PackageReference Include="Microsoft.ML" Version="1.5.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\NoSoliciting.Interface\NoSoliciting.Interface.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="costura64\CpuMathNative.dll" />
|
||||
<EmbeddedResource Include="costura64\CpuMathNative.dll" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
Binary file not shown.
|
@ -0,0 +1,7 @@
|
|||
namespace NoSoliciting.Interface {
|
||||
public interface IClassifier {
|
||||
void Initialise(byte[] data);
|
||||
|
||||
string Classify(ushort channel, string message);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net48</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
|
@ -9,7 +9,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NoSoliciting.Tests", "NoSoliciting.Tests\NoSoliciting.Tests.csproj", "{1962D91F-543A-4214-88FD-788BB7ACECE3}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NoSoliciting.Classifier", "NoSoliciting.Classifier\NoSoliciting.Classifier.csproj", "{F5F1671E-8DC4-47E4-AD3E-55DA5BDF1B93}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NoSoliciting.CursedWorkaround", "NoSoliciting.CursedWorkaround\NoSoliciting.CursedWorkaround.csproj", "{F3238422-A9D8-4E71-9365-9EFFEC85CB59}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NoSoliciting.Interface", "NoSoliciting.Interface\NoSoliciting.Interface.csproj", "{E88E57AB-EFB8-4F2F-93DB-F63123638C44}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
@ -25,10 +27,14 @@ Global
|
|||
{1962D91F-543A-4214-88FD-788BB7ACECE3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1962D91F-543A-4214-88FD-788BB7ACECE3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1962D91F-543A-4214-88FD-788BB7ACECE3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F5F1671E-8DC4-47E4-AD3E-55DA5BDF1B93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F5F1671E-8DC4-47E4-AD3E-55DA5BDF1B93}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F5F1671E-8DC4-47E4-AD3E-55DA5BDF1B93}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F5F1671E-8DC4-47E4-AD3E-55DA5BDF1B93}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F3238422-A9D8-4E71-9365-9EFFEC85CB59}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F3238422-A9D8-4E71-9365-9EFFEC85CB59}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F3238422-A9D8-4E71-9365-9EFFEC85CB59}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F3238422-A9D8-4E71-9365-9EFFEC85CB59}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E88E57AB-EFB8-4F2F-93DB-F63123638C44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E88E57AB-EFB8-4F2F-93DB-F63123638C44}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E88E57AB-EFB8-4F2F-93DB-F63123638C44}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E88E57AB-EFB8-4F2F-93DB-F63123638C44}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -30,10 +30,11 @@ namespace NoSoliciting {
|
|||
public Message(uint defsVersion, ChatType type, string sender, string content, string? reason) : this(
|
||||
defsVersion,
|
||||
type,
|
||||
new SeString(new Payload[] { new TextPayload(sender) }),
|
||||
new SeString(new Payload[] { new TextPayload(content) }),
|
||||
new SeString(new Payload[] {new TextPayload(sender)}),
|
||||
new SeString(new Payload[] {new TextPayload(content)}),
|
||||
reason
|
||||
) { }
|
||||
) {
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
[JsonObject(NamingStrategyType = typeof(SnakeCaseNamingStrategy))]
|
||||
|
@ -41,7 +42,9 @@ namespace NoSoliciting {
|
|||
public Guid Id { get; set; }
|
||||
public uint DefinitionsVersion { get; set; }
|
||||
public DateTime Timestamp { get; set; }
|
||||
|
||||
public ushort Type { get; set; }
|
||||
|
||||
// note: cannot use byte[] because Newtonsoft thinks it's a good idea to always base64 byte[]
|
||||
// and I don't want to write a custom converter to overwrite their stupiditiy
|
||||
public List<byte> Sender { get; set; }
|
||||
|
@ -54,7 +57,7 @@ namespace NoSoliciting {
|
|||
Id = this.Id,
|
||||
DefinitionsVersion = this.DefinitionsVersion,
|
||||
Timestamp = this.Timestamp,
|
||||
Type = (ushort)this.ChatType,
|
||||
Type = (ushort) this.ChatType,
|
||||
Sender = this.Sender.Encode().ToList(),
|
||||
Content = this.Content.Encode().ToList(),
|
||||
Reason = this.FilterReason,
|
||||
|
@ -154,12 +157,17 @@ namespace NoSoliciting {
|
|||
public static class ChatTypeExt {
|
||||
private const ushort Clear7 = ~(~0 << 7);
|
||||
|
||||
public static byte LogKind(this ChatType type) => type switch {
|
||||
ChatType.TellIncoming => (byte) ChatType.TellOutgoing,
|
||||
_ => (byte) type,
|
||||
};
|
||||
|
||||
public static ChatType FromCode(ushort code) {
|
||||
return (ChatType)(code & Clear7);
|
||||
return (ChatType) (code & Clear7);
|
||||
}
|
||||
|
||||
public static ChatType FromDalamud(XivChatType type) {
|
||||
return FromCode((ushort)type);
|
||||
return FromCode((ushort) type);
|
||||
}
|
||||
|
||||
public static bool IsBattle(this ChatType type) {
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Dalamud.Plugin;
|
||||
using Microsoft.ML;
|
||||
using NoSoliciting.Properties;
|
||||
using NoSoliciting.Interface;
|
||||
using YamlDotNet.Core;
|
||||
using YamlDotNet.Serialization;
|
||||
using YamlDotNet.Serialization.NamingConventions;
|
||||
|
@ -20,29 +18,37 @@ namespace NoSoliciting.Ml {
|
|||
private const string Url = "http://localhost:8000/manifest.yaml";
|
||||
|
||||
public uint Version { get; }
|
||||
private MLContext Context { get; }
|
||||
private ITransformer Model { get; }
|
||||
private DataViewSchema Schema { get; }
|
||||
private PredictionEngine<MessageData, MessagePrediction> PredictionEngine { get; }
|
||||
private IClassifier Classifier { get; }
|
||||
|
||||
private MlFilter(uint version, MLContext context, ITransformer model, DataViewSchema schema) {
|
||||
private MlFilter(uint version, IClassifier classifier) {
|
||||
this.Version = version;
|
||||
this.Context = context;
|
||||
this.Model = model;
|
||||
this.Schema = schema;
|
||||
this.PredictionEngine = this.Context.Model.CreatePredictionEngine<MessageData, MessagePrediction>(this.Model, this.Schema);
|
||||
this.Classifier = classifier;
|
||||
}
|
||||
|
||||
// private MLContext Context { get; }
|
||||
// private ITransformer Model { get; }
|
||||
// private DataViewSchema Schema { get; }
|
||||
// private PredictionEngine<MessageData, MessagePrediction> PredictionEngine { get; }
|
||||
//
|
||||
// private MlFilter(uint version, MLContext context, ITransformer model, DataViewSchema schema) {
|
||||
// this.Version = version;
|
||||
// this.Context = context;
|
||||
// this.Model = model;
|
||||
// this.Schema = schema;
|
||||
// this.PredictionEngine = this.Context.Model.CreatePredictionEngine<MessageData, MessagePrediction>(this.Model, this.Schema);
|
||||
// }
|
||||
|
||||
public MessageCategory ClassifyMessage(ushort channel, string message) {
|
||||
var data = new MessageData(channel, message);
|
||||
var pred = this.PredictionEngine.Predict(data);
|
||||
var category = MessageCategoryExt.FromString(pred.Category);
|
||||
// var data = new MessageData(channel, message);
|
||||
// var pred = this.PredictionEngine.Predict(data);
|
||||
var rawCategory = this.Classifier.Classify(channel, message);
|
||||
var category = MessageCategoryExt.FromString(rawCategory);
|
||||
|
||||
if (category != null) {
|
||||
return (MessageCategory) category;
|
||||
}
|
||||
|
||||
PluginLog.LogWarning($"Unknown message category: {pred.Category}");
|
||||
PluginLog.LogWarning($"Unknown message category: {rawCategory}");
|
||||
return MessageCategory.Normal;
|
||||
}
|
||||
|
||||
|
@ -72,11 +78,18 @@ namespace NoSoliciting.Ml {
|
|||
UpdateCachedFile(plugin, ModelName, data);
|
||||
UpdateCachedFile(plugin, ManifestName, Encoding.UTF8.GetBytes(manifest.Item2));
|
||||
|
||||
var context = new MLContext();
|
||||
using var stream = new MemoryStream(data);
|
||||
var model = context.Model.Load(stream, out var schema);
|
||||
// var context = new MLContext();
|
||||
// using var stream = new MemoryStream(data);
|
||||
// var model = context.Model.Load(stream, out var schema);
|
||||
|
||||
return new MlFilter(manifest.Item1.Version, context, model, schema);
|
||||
// return new MlFilter(manifest.Item1.Version, context, model, schema);
|
||||
|
||||
plugin.Classifier.Initialise(data);
|
||||
|
||||
return new MlFilter(
|
||||
manifest.Item1.Version,
|
||||
plugin.Classifier
|
||||
);
|
||||
}
|
||||
|
||||
private static async Task<byte[]?> DownloadModel(Uri url) {
|
||||
|
@ -150,7 +163,7 @@ namespace NoSoliciting.Ml {
|
|||
}
|
||||
|
||||
public void Dispose() {
|
||||
this.PredictionEngine.Dispose();
|
||||
// this.PredictionEngine.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,57 +4,6 @@ using System.Text.RegularExpressions;
|
|||
using Microsoft.ML.Data;
|
||||
|
||||
namespace NoSoliciting.Ml {
|
||||
public class MessageData {
|
||||
private static readonly Regex WardRegex = new Regex(@"w.{0,2}\d", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
private static readonly Regex PlotRegex = new Regex(@"p.{0,2}\d", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
private static readonly string[] PlotWords = {
|
||||
"plot",
|
||||
"apartment",
|
||||
"apt",
|
||||
};
|
||||
|
||||
private static readonly Regex NumbersRegex = new Regex(@"\d{1,2}.{0,2}\d{1,2}", RegexOptions.Compiled);
|
||||
|
||||
private static readonly string[] TradeWords = {
|
||||
"B>",
|
||||
"S>",
|
||||
"buy",
|
||||
"sell",
|
||||
};
|
||||
|
||||
public string? Category { get; }
|
||||
|
||||
public uint Channel { get; }
|
||||
|
||||
public string Message { get; }
|
||||
|
||||
public bool PartyFinder => this.Channel == 0;
|
||||
|
||||
public bool Shout => this.Channel == 11 || this.Channel == 30;
|
||||
|
||||
public bool ContainsWard => this.Message.ContainsIgnoreCase("ward") || WardRegex.IsMatch(this.Message);
|
||||
|
||||
public bool ContainsPlot => PlotWords.Any(word => this.Message.ContainsIgnoreCase(word)) || PlotRegex.IsMatch(this.Message);
|
||||
|
||||
public bool ContainsHousingNumbers => NumbersRegex.IsMatch(this.Message);
|
||||
|
||||
public bool ContainsTradeWords => TradeWords.Any(word => this.Message.ContainsIgnoreCase(word));
|
||||
|
||||
public MessageData(uint channel, string message) {
|
||||
this.Channel = channel;
|
||||
this.Message = message;
|
||||
}
|
||||
}
|
||||
|
||||
public class MessagePrediction {
|
||||
[ColumnName("PredictedLabel")]
|
||||
public string Category { get; set; } = null!;
|
||||
|
||||
[ColumnName("Score")]
|
||||
public float[] Probabilities { get; set; } = null!;
|
||||
}
|
||||
|
||||
public enum MessageCategory {
|
||||
Trade,
|
||||
FreeCompany,
|
||||
|
@ -80,13 +29,13 @@ namespace NoSoliciting.Ml {
|
|||
};
|
||||
|
||||
public static string Name(this MessageCategory category) => category switch {
|
||||
MessageCategory.Trade => "Trades",
|
||||
MessageCategory.Trade => "Trade ads",
|
||||
MessageCategory.FreeCompany => "Free Company ads",
|
||||
MessageCategory.Normal => "Normal messages",
|
||||
MessageCategory.Phishing => "Phishing messages",
|
||||
MessageCategory.RmtContent => "RMT (content)",
|
||||
MessageCategory.RmtGil => "RMT (gil)",
|
||||
MessageCategory.Roleplaying => "Roleplaying",
|
||||
MessageCategory.Roleplaying => "Roleplaying ads",
|
||||
MessageCategory.Static => "Static recruitment",
|
||||
_ => throw new ArgumentException("Invalid category", nameof(category)),
|
||||
};
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.ML" Version="1.5.4" />
|
||||
<PackageReference Include="YamlDotNet" Version="9.1.0" />
|
||||
<PackageReference Include="ILRepack.Lib.MSBuild.Task" Version="2.0.18.2" />
|
||||
</ItemGroup>
|
||||
|
@ -53,4 +52,12 @@
|
|||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Update="NoSoliciting.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\NoSoliciting.CursedWorkaround\NoSoliciting.CursedWorkaround.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"Author": "ascclemens",
|
||||
"Name": "NoSoliciting",
|
||||
"Description": "Hides RMT in chat and the party finder. /prmt",
|
||||
"Description": "Customisable chat and Party Finder filtering. In addition to letting you filter anything from chat and PF, it comes with built-in filters for the following:\n\n- RMT (both gil and content)\n- FC ads\n- RP ads\n- Phishing messages\n- Static recruitment\n- Trade ads\n- Any PF with an item level over the max\n\nNow with experimental machine learning!",
|
||||
"InternalName": "NoSoliciting",
|
||||
"AssemblyVersion": "1.5.0",
|
||||
"RepoUrl": "https://git.sr.ht/~jkcclemens/NoSoliciting",
|
||||
|
|
|
@ -5,6 +5,7 @@ using System.Collections.Generic;
|
|||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using NoSoliciting.Interface;
|
||||
using NoSoliciting.Ml;
|
||||
|
||||
namespace NoSoliciting {
|
||||
|
@ -33,9 +34,20 @@ namespace NoSoliciting {
|
|||
// ReSharper disable once AutoPropertyCanBeMadeGetOnly.Local
|
||||
public string AssemblyLocation { get; private set; } = Assembly.GetExecutingAssembly().Location;
|
||||
|
||||
private const string LibraryName = "NoSoliciting.CursedWorkaround";
|
||||
|
||||
private AppDomain InnerDomain { get; set; } = null!;
|
||||
|
||||
public IClassifier Classifier { get; private set; } = null!;
|
||||
|
||||
public void Initialize(DalamudPluginInterface pluginInterface) {
|
||||
// NOTE: THE SECRET IS TO DOWNGRADE System.Numerics.Vectors THAT'S INCLUDED WITH DALAMUD
|
||||
// CRY
|
||||
// FIXME: eventually this cursed workaround for old System.Numerics.Vectors should be destroyed
|
||||
this.InnerDomain = AppDomain.CreateDomain(LibraryName, AppDomain.CurrentDomain.Evidence, new AppDomainSetup {
|
||||
ApplicationName = LibraryName,
|
||||
ConfigurationFile = $"{LibraryName}.dll.config",
|
||||
ApplicationBase = Path.GetDirectoryName(this.AssemblyLocation),
|
||||
});
|
||||
this.Classifier = (IClassifier) this.InnerDomain.CreateInstanceAndUnwrap(LibraryName, $"{LibraryName}.CursedWorkaround");
|
||||
|
||||
string path = Environment.GetEnvironmentVariable("PATH")!;
|
||||
string newPath = Path.GetDirectoryName(this.AssemblyLocation)!;
|
||||
|
@ -78,7 +90,11 @@ namespace NoSoliciting {
|
|||
}
|
||||
|
||||
Task.Run(async () => { this.MlFilter = await MlFilter.Load(this); })
|
||||
.ContinueWith(_ => PluginLog.Log("Machine learning model loaded"));
|
||||
.ContinueWith(e => {
|
||||
if (!e.IsFaulted) {
|
||||
PluginLog.Log("Machine learning model loaded");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
internal void UpdateDefinitions() {
|
||||
|
@ -125,6 +141,9 @@ namespace NoSoliciting {
|
|||
this.Interface.UiBuilder.OnBuildUi -= this.Ui.Draw;
|
||||
this.Interface.UiBuilder.OnOpenConfigUi -= this.Ui.OpenSettings;
|
||||
this.Interface.CommandManager.RemoveHandler("/prmt");
|
||||
|
||||
// AppDomain.CurrentDomain.AssemblyResolve -= this.ResolveAssembly;
|
||||
AppDomain.Unload(this.InnerDomain);
|
||||
}
|
||||
|
||||
this._disposedValue = true;
|
||||
|
|
|
@ -11,6 +11,7 @@ using System.Net;
|
|||
using System.Numerics;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using NoSoliciting.Ml;
|
||||
|
||||
namespace NoSoliciting {
|
||||
|
@ -275,7 +276,13 @@ namespace NoSoliciting {
|
|||
var types = this.Plugin.Config.MlFilters[category];
|
||||
|
||||
void DrawTypes(ChatType type) {
|
||||
var name = type == ChatType.None ? "Party Finder" : type.ToString();
|
||||
string name;
|
||||
if (type == ChatType.None) {
|
||||
name = "Party Finder";
|
||||
} else {
|
||||
var lf = this.Plugin.Interface.Data.GetExcelSheet<LogFilter>().FirstOrDefault(lf => lf.LogKind == type.LogKind());
|
||||
name = lf?.Name?.ToString() ?? type.ToString();
|
||||
}
|
||||
|
||||
var check = types.Contains(type);
|
||||
if (!ImGui.Checkbox(name, ref check)) {
|
||||
|
|
Loading…
Reference in New Issue