diff --git a/Analyzers/NWPluginAPI.Analyzers.CodeFixes/CodeFixResources.Designer.cs b/Analyzers/NWPluginAPI.Analyzers.CodeFixes/CodeFixResources.Designer.cs
deleted file mode 100644
index 06cf466..0000000
--- a/Analyzers/NWPluginAPI.Analyzers.CodeFixes/CodeFixResources.Designer.cs
+++ /dev/null
@@ -1,72 +0,0 @@
-//------------------------------------------------------------------------------
-//
-// This code was generated by a tool.
-// Runtime Version:4.0.30319.42000
-//
-// Changes to this file may cause incorrect behavior and will be lost if
-// the code is regenerated.
-//
-//------------------------------------------------------------------------------
-
-namespace NWPluginAPI.Analyzers {
- using System;
-
-
- ///
- /// A strongly-typed resource class, for looking up localized strings, etc.
- ///
- // This class was auto-generated by the StronglyTypedResourceBuilder
- // class via a tool like ResGen or Visual Studio.
- // To add or remove a member, edit your .ResX file then rerun ResGen
- // with the /str option, or rebuild your VS project.
- [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
- internal class CodeFixResources {
-
- private static global::System.Resources.ResourceManager resourceMan;
-
- private static global::System.Globalization.CultureInfo resourceCulture;
-
- [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- internal CodeFixResources() {
- }
-
- ///
- /// Returns the cached ResourceManager instance used by this class.
- ///
- [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
- internal static global::System.Resources.ResourceManager ResourceManager {
- get {
- if (object.ReferenceEquals(resourceMan, null)) {
- global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("NWPluginAPI.Analyzers.CodeFixResources", typeof(CodeFixResources).Assembly);
- resourceMan = temp;
- }
- return resourceMan;
- }
- }
-
- ///
- /// Overrides the current thread's CurrentUICulture property for all
- /// resource lookups using this strongly typed resource class.
- ///
- [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
- internal static global::System.Globalization.CultureInfo Culture {
- get {
- return resourceCulture;
- }
- set {
- resourceCulture = value;
- }
- }
-
- ///
- /// Looks up a localized string similar to Make uppercase.
- ///
- internal static string CodeFixTitle {
- get {
- return ResourceManager.GetString("CodeFixTitle", resourceCulture);
- }
- }
- }
-}
diff --git a/Analyzers/NWPluginAPI.Analyzers.CodeFixes/CodeFixResources.resx b/Analyzers/NWPluginAPI.Analyzers.CodeFixes/CodeFixResources.resx
deleted file mode 100644
index 97abe68..0000000
--- a/Analyzers/NWPluginAPI.Analyzers.CodeFixes/CodeFixResources.resx
+++ /dev/null
@@ -1,124 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- text/microsoft-resx
-
-
- 2.0
-
-
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- Make uppercase
- The title of the code fix.
-
-
\ No newline at end of file
diff --git a/Analyzers/NWPluginAPI.Analyzers.CodeFixes/NWPluginAPI.Analyzers.CodeFixes.csproj b/Analyzers/NWPluginAPI.Analyzers.CodeFixes/NWPluginAPI.Analyzers.CodeFixes.csproj
deleted file mode 100644
index ae3a5f5..0000000
--- a/Analyzers/NWPluginAPI.Analyzers.CodeFixes/NWPluginAPI.Analyzers.CodeFixes.csproj
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- netstandard2.0
- false
- NWPluginAPI.Analyzers
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Analyzers/NWPluginAPI.Analyzers.CodeFixes/NWPluginAPIAnalyzersCodeFixProvider.cs b/Analyzers/NWPluginAPI.Analyzers.CodeFixes/NWPluginAPIAnalyzersCodeFixProvider.cs
deleted file mode 100644
index 5a47404..0000000
--- a/Analyzers/NWPluginAPI.Analyzers.CodeFixes/NWPluginAPIAnalyzersCodeFixProvider.cs
+++ /dev/null
@@ -1,63 +0,0 @@
-using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.CodeActions;
-using Microsoft.CodeAnalysis.CodeFixes;
-using Microsoft.CodeAnalysis.CSharp;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
-using System.Collections.Immutable;
-using System.Composition;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace NWPluginAPI.Analyzers
-{
- [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(NWPluginAPIAnalyzersCodeFixProvider)), Shared]
- public class NWPluginAPIAnalyzersCodeFixProvider : CodeFixProvider
- {
- public sealed override ImmutableArray FixableDiagnosticIds
- {
- get { return ImmutableArray.Create(NWPluginAPIAnalyzersAnalyzer.DiagnosticId); }
- }
-
- public sealed override FixAllProvider GetFixAllProvider()
- {
- // See https://github.com/dotnet/roslyn/blob/main/docs/analyzers/FixAllProvider.md for more information on Fix All Providers
- return WellKnownFixAllProviders.BatchFixer;
- }
-
- public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
- {
- var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
-
- // TODO: Replace the following code with your own analysis, generating a CodeAction for each fix to suggest
- var diagnostic = context.Diagnostics.First();
- var diagnosticSpan = diagnostic.Location.SourceSpan;
-
- // Find the type declaration identified by the diagnostic.
- var declaration = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType().First();
-
- // Register a code action that will invoke the fix.
- context.RegisterCodeFix(
- CodeAction.Create(
- title: "Add missing parameters",
- createChangedDocument: c => MakeUppercaseAsync(context.Document, declaration, c),
- equivalenceKey: nameof(CodeFixResources.CodeFixTitle)),
- diagnostic);
- }
-
- private async Task MakeUppercaseAsync(Document document, MethodDeclarationSyntax param, CancellationToken cancellationToken)
- {
- var attribute = SyntaxFactory.AttributeList(
- SyntaxFactory.SingletonSeparatedList(
- SyntaxFactory.Attribute(SyntaxFactory.IdentifierName("PluginEvent"), null)));
-
- var newParam = param.WithAttributeLists(param.AttributeLists.Add(attribute));
-
- var root = await document.GetSyntaxRootAsync();
- var newRoot = root.ReplaceNode(param, newParam);
- var newDocument = document.WithSyntaxRoot(newRoot);
-
- return newDocument;
- }
- }
-}
diff --git a/Analyzers/NWPluginAPI.Analyzers/Enums/ActionType.cs b/Analyzers/NWPluginAPI.Analyzers/Enums/ActionType.cs
new file mode 100644
index 0000000..0546c2b
--- /dev/null
+++ b/Analyzers/NWPluginAPI.Analyzers/Enums/ActionType.cs
@@ -0,0 +1,10 @@
+namespace NWPluginAPI.Analyzers.Enums
+{
+ public enum ActionType
+ {
+ Add,
+ Replace,
+ Remove,
+ None
+ }
+}
diff --git a/Analyzers/NWPluginAPI.Analyzers/Generated/GeneratedEventManager.cs b/Analyzers/NWPluginAPI.Analyzers/Generated/GeneratedEventManager.cs
new file mode 100644
index 0000000..64cd7c2
--- /dev/null
+++ b/Analyzers/NWPluginAPI.Analyzers/Generated/GeneratedEventManager.cs
@@ -0,0 +1,214 @@
+using System.Collections.Generic;
+
+public class Event
+{
+ public readonly EventParameter[] Parameters;
+
+ public Event(params EventParameter[] parameters)
+ {
+ Parameters = parameters;
+ }
+}
+
+public class EventParameter
+{
+ public string BaseType { get; set; }
+ public bool IsArray { get; set; }
+ public string DefaultIdentifierName { get; set; }
+
+ public EventParameter(string baseType, bool isArray, string defaultIdentifierName)
+ {
+ BaseType = baseType;
+ IsArray = isArray;
+ DefaultIdentifierName = defaultIdentifierName;
+ }
+}
+
+public static class EventManager
+{
+ public static Dictionary Events = new Dictionary()
+ {
+ { 0, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player")) },
+ { 1, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player")) },
+ { 2, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "attacker"),
+ new EventParameter("PlayerStatsSystem.DamageHandlerBase", false, "damageHandler")) },
+ { 3, new Event() },
+ { 4, new Event(
+ new EventParameter("System.Int32", false, "id")) },
+ { 5, new Event() },
+ { 6, new Event(
+ new EventParameter("InventorySystem.Items.Pickups.ItemPickupBase", false, "grenade")) },
+ { 7, new Event(
+ new EventParameter("ItemType", false, "item")) },
+ { 8, new Event(
+ new EventParameter("MapGeneration.Distributors.Scp079Generator", false, "generator")) },
+ { 9, new Event() },
+ { 10, new Event() },
+ { 11, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("MapGeneration.Distributors.Scp079Generator", false, "generator")) },
+ { 12, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("InventorySystem.Items.Firearms.Firearm", false, "firearm"),
+ new EventParameter("System.Boolean", false, "isAiming")) },
+ { 13, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "issuer"),
+ new EventParameter("System.String", false, "reason"),
+ new EventParameter("System.Int64", false, "duration")) },
+ { 14, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("InventorySystem.Items.Usables.UsableItem", false, "item")) },
+ { 15, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("System.UInt16", false, "oldItem"),
+ new EventParameter("System.UInt16", false, "newItem")) },
+ { 16, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("InventorySystem.Items.Radio.RadioItem", false, "radio"),
+ new EventParameter("System.Byte", false, "range")) },
+ { 17, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "oldTarget"),
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "newTarget")) },
+ { 18, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("MapGeneration.Distributors.Scp079Generator", false, "generator")) },
+ { 19, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("AdminToys.ShootingTarget", false, "shootingTarget"),
+ new EventParameter("PlayerStatsSystem.DamageHandlerBase", false, "damageHandler"),
+ new EventParameter("System.Single", false, "damageAmount")) },
+ { 20, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("BreakableWindow", false, "window"),
+ new EventParameter("PlayerStatsSystem.DamageHandlerBase", false, "damageHandler"),
+ new EventParameter("System.Single", false, "damageAmount")) },
+ { 21, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("MapGeneration.Distributors.Scp079Generator", false, "generator")) },
+ { 22, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("ItemType", false, "item"),
+ new EventParameter("System.Int32", false, "amount")) },
+ { 23, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("InventorySystem.Items.ItemBase", false, "item")) },
+ { 24, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("InventorySystem.Items.Firearms.Firearm", false, "firearm")) },
+ { 25, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("PlayerRoles.RoleTypeId", false, "newRole")) },
+ { 26, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "target")) },
+ { 27, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "target")) },
+ { 28, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "target"),
+ new EventParameter("PlayerStatsSystem.DamageHandlerBase", false, "damageHandler")) },
+ { 29, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player")) },
+ { 30, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player")) },
+ { 31, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player")) },
+ { 32, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player")) },
+ { 33, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "issuer"),
+ new EventParameter("System.String", false, "reason")) },
+ { 34, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player")) },
+ { 35, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("MapGeneration.Distributors.Scp079Generator", false, "generator")) },
+ { 36, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("InventorySystem.Items.Pickups.ItemPickupBase", false, "item")) },
+ { 37, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("InventorySystem.Items.Pickups.ItemPickupBase", false, "item")) },
+ { 38, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("InventorySystem.Items.Pickups.ItemPickupBase", false, "item")) },
+ { 39, new Event(
+ new EventParameter("System.String", false, "userId"),
+ new EventParameter("System.String", false, "ipAddress"),
+ new EventParameter("System.Int64", false, "expiration"),
+ new EventParameter("CentralAuthPreauthFlags", false, "centralFlags"),
+ new EventParameter("System.String", false, "region"),
+ new EventParameter("System.Byte", true, "signature"),
+ new EventParameter("LiteNetLib.ConnectionRequest", false, "connectionRequest"),
+ new EventParameter("System.Int32", false, "readerStartPosition")) },
+ { 40, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("CustomPlayerEffects.PlayerEffect", false, "effect")) },
+ { 41, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("InventorySystem.Items.Firearms.Firearm", false, "firearm")) },
+ { 42, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("PlayerRoles.PlayerRoleBase", false, "oldRole"),
+ new EventParameter("PlayerRoles.PlayerRoleBase", false, "newRole"),
+ new EventParameter("PlayerRoles.RoleChangeReason", false, "changeReason")) },
+ { 43, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("InventorySystem.Items.Pickups.ItemPickupBase", false, "item")) },
+ { 44, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("InventorySystem.Items.Pickups.ItemPickupBase", false, "item")) },
+ { 45, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("InventorySystem.Items.Firearms.Firearm", false, "firearm")) },
+ { 46, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("PlayerRoles.RoleTypeId", false, "role")) },
+ { 47, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("PlayerRoles.IRagdollRole", false, "ragdoll"),
+ new EventParameter("PlayerStatsSystem.DamageHandlerBase", false, "damageHandler")) },
+ { 48, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("InventorySystem.Items.ItemBase", false, "item")) },
+ { 49, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("InventorySystem.Items.ItemBase", false, "item"),
+ new EventParameter("System.Boolean", false, "isToggled")) },
+ { 50, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("InventorySystem.Items.Firearms.Firearm", false, "firearm")) },
+ { 51, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("MapGeneration.Distributors.Scp079Generator", false, "generator")) },
+ { 52, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("InventorySystem.Items.ItemBase", false, "item")) },
+ { 53, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("ActionName", false, "action")) },
+ { 54, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("InventorySystem.Items.Usables.UsableItem", false, "item")) },
+ { 55, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "target"),
+ new EventParameter("System.String", false, "reason")) },
+ { 56, new Event(
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "player"),
+ new EventParameter("PluginAPI.Core.Interfaces.IPlayer", false, "target"),
+ new EventParameter("System.String", false, "reason")) },
+ { 57, new Event() },
+ { 58, new Event() },
+ { 59, new Event() },
+ { 60, new Event() },
+ };
+}
diff --git a/Analyzers/NWPluginAPI.Analyzers/NWPluginAPI.Analyzers.csproj b/Analyzers/NWPluginAPI.Analyzers/NWPluginAPI.Analyzers.csproj
index 7176c81..fbc4881 100644
--- a/Analyzers/NWPluginAPI.Analyzers/NWPluginAPI.Analyzers.csproj
+++ b/Analyzers/NWPluginAPI.Analyzers/NWPluginAPI.Analyzers.csproj
@@ -1,21 +1,13 @@
-
+
netstandard2.0
false
-
-
- *$(MSBuildProjectFile)*
-
+
+
-
-
-
-
-
-
diff --git a/Analyzers/NWPluginAPI.Analyzers/NWPluginAPIAnalyzersAnalyzer.cs b/Analyzers/NWPluginAPI.Analyzers/NWPluginAPIAnalyzersAnalyzer.cs
index e626438..17dc98d 100644
--- a/Analyzers/NWPluginAPI.Analyzers/NWPluginAPIAnalyzersAnalyzer.cs
+++ b/Analyzers/NWPluginAPI.Analyzers/NWPluginAPIAnalyzersAnalyzer.cs
@@ -1,41 +1,187 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
+using NWPluginAPI.Analyzers.Enums;
+using System;
+using System.Collections.Generic;
using System.Collections.Immutable;
+using System.Linq;
namespace NWPluginAPI.Analyzers
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class NWPluginAPIAnalyzersAnalyzer : DiagnosticAnalyzer
{
- public const string DiagnosticId = "NWPluginAPIAnalyzers";
+ public const string ParameterNotRequiredDiagnosticId = "NWAPIRP";
+ public const string WrongParameterDiagnosticId = "NWAPIWP";
+ public const string MissingParameterDiagnosticId = "NWAPIMP";
+ public const string MissingParametersDiagnosticId = "NWAPIMPS";
- // You can change these strings in the Resources.resx file. If you do not want your analyzer to be localize-able, you can use regular strings for Title and MessageFormat.
- // See https://github.com/dotnet/roslyn/blob/main/docs/analyzers/Localizing%20Analyzers.md for more on localization
- private static readonly LocalizableString Title = new LocalizableResourceString(nameof(Resources.AnalyzerTitle), Resources.ResourceManager, typeof(Resources));
- private static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(Resources.AnalyzerMessageFormat), Resources.ResourceManager, typeof(Resources));
- private static readonly LocalizableString Description = new LocalizableResourceString(nameof(Resources.AnalyzerDescription), Resources.ResourceManager, typeof(Resources));
- private const string Category = "Naming";
- private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Warning, isEnabledByDefault: true, description: Description);
+ private static readonly DiagnosticDescriptor ParameterNotRequiredRule = new DiagnosticDescriptor(ParameterNotRequiredDiagnosticId,
+ "Parameter not required",
+ "Parameter '{0}' is not used in this event!",
+ "Naming",
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true);
- public override ImmutableArray SupportedDiagnostics { get { return ImmutableArray.Create(Rule); } }
+ private static readonly DiagnosticDescriptor WrongParameterRule = new DiagnosticDescriptor(WrongParameterDiagnosticId,
+ "Wrong type used",
+ "Type '{0}' is not used in this event, use type '{1}'!",
+ "Naming",
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true);
+
+ private static readonly DiagnosticDescriptor MissingParameterRule = new DiagnosticDescriptor(MissingParameterDiagnosticId,
+ "Missing parameter",
+ "Parameter of type '{0}' is missing in this event!",
+ "Naming",
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true);
+
+ private static readonly DiagnosticDescriptor MissingParametersRule = new DiagnosticDescriptor(MissingParametersDiagnosticId,
+ "Missing parameters",
+ "Parameters of type '{0}' are missing in this event!",
+ "Naming",
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true);
+
+
+ public override ImmutableArray SupportedDiagnostics { get { return ImmutableArray.Create(ParameterNotRequiredRule, WrongParameterRule, MissingParameterRule, MissingParametersRule); } }
public override void Initialize(AnalysisContext context)
{
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
context.EnableConcurrentExecution();
-
context.RegisterSymbolAction(AnalyzeSymbol, SymbolKind.Method);
}
private static void AnalyzeSymbol(SymbolAnalysisContext context)
{
- // TODO: Replace the following code with your own analysis, generating Diagnostic objects for any issues you find
- var namedTypeSymbol = (INamedTypeSymbol)context.Symbol;
+ var methodSymbol = (IMethodSymbol)context.Symbol;
+
+ INamedTypeSymbol attribute = context.Compilation.GetTypeByMetadataName("PluginAPI.Core.Attributes.PluginEvent");
+
+ INamedTypeSymbol eventTypeEnum = context.Compilation.GetTypeByMetadataName("PluginAPI.Enums.ServerEventType");
+
+ var eventAttribute = methodSymbol.GetAttributes().FirstOrDefault(x => SymbolEqualityComparer.Default.Equals(x.AttributeClass, attribute));
+
+ if (eventAttribute == null) return;
+
+ var eventType = eventAttribute.ConstructorArguments.FirstOrDefault(x => SymbolEqualityComparer.Default.Equals(x.Type, eventTypeEnum));
+
+ if (eventType.IsNull) return;
+
+ if (!(eventType.Value is int eventNum)) return;
+
+ if (!EventManager.Events.TryGetValue(eventNum, out Event ev)) return;
+
+ List requiredSymbols = new List();
+
+ for (int x = 0; x < ev.Parameters.Length; x++)
+ {
+ requiredSymbols.Add(context.Compilation.GetTypeByMetadataName(ev.Parameters[x].BaseType));
+ }
+
+ List result = new List();
+
+ for (int x = 0; x < ev.Parameters.Length; x++)
+ {
+ result.Add(ActionType.Add);
+ }
+
+ for (int x = 0; x < methodSymbol.Parameters.Length; x++)
+ {
+ var parameter = methodSymbol.Parameters[x];
+
+ if (requiredSymbols.Count < x+1)
+ {
+ var diagTooMuchParams = Diagnostic.Create(ParameterNotRequiredRule, parameter.Locations[0], parameter.Name);
+
+ context.ReportDiagnostic(diagTooMuchParams);
+ result.Add(ActionType.Remove);
+ continue;
+ }
+
+ if (parameter.Type.TypeKind == requiredSymbols[x].TypeKind)
+ {
+ if (parameter.Type.SpecialType == SpecialType.System_Array && ev.Parameters[x].IsArray)
+ {
+ result[x] = ActionType.None;
+ continue;
+ }
+
+ if (ev.Parameters[x].IsArray)
+ {
+ var diagReplace = Diagnostic.Create(WrongParameterRule, parameter.Locations[0], parameter.Type.Name, requiredSymbols[x].Name);
+
+ context.ReportDiagnostic(diagReplace);
+ result[x] = ActionType.Replace;
+ continue;
+ }
+ }
+ else
+ {
+ if (requiredSymbols[x].AllInterfaces.Length != 0)
+ {
+ if (context.Compilation.IsSymbolAccessibleWithin(requiredSymbols[x], parameter.Type))
+ {
+ result[x] = ActionType.None;
+ continue;
+ }
+ }
+
+ var diagWrongParam = Diagnostic.Create(WrongParameterRule, parameter.Locations[0], parameter.Type.Name, requiredSymbols[x].Name);
+
+ context.ReportDiagnostic(diagWrongParam);
+ result[x] = ActionType.Replace;
+ continue;
+ }
+
+ result[x] = ActionType.None;
+ }
+
+ Dictionary missingParameters = new Dictionary();
+
+ for (int x = 0; x < result.Count; x++)
+ {
+ if (result[x] != ActionType.Add) continue;
+
+ missingParameters.Add(x, ev.Parameters[x]);
+ }
+
+ if (missingParameters.Count != 0)
+ {
+ Dictionary paramsToAdd = new Dictionary()
+ {
+ { "eventId", eventNum.ToString() }
+ };
+
+ string missingParams = string.Empty;
+ string missingParamsStr = string.Empty;
+
+ foreach (var missingParam in missingParameters)
+ {
+ missingParams += $"{missingParam.Key},";
+ missingParamsStr += $"{missingParam.Value.BaseType}, ";
+ }
+
+ missingParams = missingParams.Substring(0, missingParams.Length - 1);
+
+ paramsToAdd.Add("parameters", missingParams);
- var diagnostic = Diagnostic.Create(Rule, namedTypeSymbol.Locations[0], namedTypeSymbol.Name);
+ missingParamsStr = missingParamsStr.Substring(0, missingParamsStr.Length - 2);
- context.ReportDiagnostic(diagnostic);
+ if (missingParams.Length == 1)
+ {
+ var diagMissingParam = Diagnostic.Create(MissingParameterRule, methodSymbol.Locations[0], ImmutableDictionary.CreateRange(paramsToAdd), missingParamsStr);
+ context.ReportDiagnostic(diagMissingParam);
+ }
+ else
+ {
+ var diagMissingParams = Diagnostic.Create(MissingParametersRule, methodSymbol.Locations[0], ImmutableDictionary.CreateRange(paramsToAdd), missingParamsStr);
+ context.ReportDiagnostic(diagMissingParams);
+ }
+ }
}
}
}
diff --git a/Analyzers/NWPluginAPI.Analyzers/NWPluginAPIAnalyzersCodeFixProvider.cs b/Analyzers/NWPluginAPI.Analyzers/NWPluginAPIAnalyzersCodeFixProvider.cs
new file mode 100644
index 0000000..578f8e7
--- /dev/null
+++ b/Analyzers/NWPluginAPI.Analyzers/NWPluginAPIAnalyzersCodeFixProvider.cs
@@ -0,0 +1,144 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CodeActions;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Editing;
+using Microsoft.CodeAnalysis.Simplification;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Composition;
+using System.Linq;
+using System.Reflection;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace NWPluginAPI.Analyzers
+{
+ [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(NWPluginAPIAnalyzersCodeFixProvider)), Shared]
+ public class NWPluginAPIAnalyzersCodeFixProvider : CodeFixProvider
+ {
+ public sealed override ImmutableArray FixableDiagnosticIds
+ {
+ get { return ImmutableArray.Create(NWPluginAPIAnalyzersAnalyzer.WrongParameterDiagnosticId, NWPluginAPIAnalyzersAnalyzer.MissingParameterDiagnosticId, NWPluginAPIAnalyzersAnalyzer.MissingParametersDiagnosticId, NWPluginAPIAnalyzersAnalyzer.ParameterNotRequiredDiagnosticId); }
+ }
+
+ public sealed override FixAllProvider GetFixAllProvider()
+ {
+ return WellKnownFixAllProviders.BatchFixer;
+ }
+
+ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
+ {
+ var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
+
+ foreach(var diagnostic in context.Diagnostics)
+ {
+ var diagnosticSpan = diagnostic.Location.SourceSpan;
+
+ var declaration = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType().First();
+
+ switch (diagnostic.Id)
+ {
+ case NWPluginAPIAnalyzersAnalyzer.WrongParameterDiagnosticId:
+ context.RegisterCodeFix(
+ CodeAction.Create(
+ title: "Replace parameter",
+ createChangedDocument: c => ReplaceParameterAsync(context.Document, diagnostic.Properties, declaration, c),
+ equivalenceKey: "Replace parameter"),
+ diagnostic);
+ break;
+ case NWPluginAPIAnalyzersAnalyzer.MissingParameterDiagnosticId:
+ context.RegisterCodeFix(
+ CodeAction.Create(
+ title: "Add parameter",
+ createChangedDocument: c => AddParameterAsync(context.Document, diagnostic.Properties, declaration, c),
+ equivalenceKey: "Add parameter"),
+ diagnostic);
+ break;
+ case NWPluginAPIAnalyzersAnalyzer.MissingParametersDiagnosticId:
+ context.RegisterCodeFix(
+ CodeAction.Create(
+ title: "Add parameters",
+ createChangedDocument: c => AddParametersAsync(context.Document, diagnostic.Properties, declaration, c),
+ equivalenceKey: "Add parameters"),
+ diagnostic);
+ break;
+ }
+ }
+ }
+
+ private async Task ReplaceParameterAsync(Document document, ImmutableDictionary properties, MethodDeclarationSyntax method, CancellationToken token)
+ {
+ var root = await document.GetSyntaxRootAsync();
+
+ var updatedMethod = method.AddParameterListParameters(
+ SyntaxFactory.Parameter(
+ SyntaxFactory.Identifier("amogus"))
+ .WithType(SyntaxFactory.ParseTypeName("PluginAPI.Core.Player")));
+
+ var updatedSyntaxTree = root.ReplaceNode(method, updatedMethod);
+
+ return document.WithSyntaxRoot(updatedSyntaxTree);
+ }
+
+ private async Task AddParameterAsync(Document document, ImmutableDictionary properties, MethodDeclarationSyntax method, CancellationToken token)
+ {
+ var root = await document.GetSyntaxRootAsync();
+
+ if (!properties.TryGetValue("eventId", out string rawEventId)) return document;
+
+ if (!int.TryParse(rawEventId, out int eventId)) return document;
+
+ if (!EventManager.Events.TryGetValue(eventId, out Event ev)) return document;
+
+ if (!properties.TryGetValue("parameters", out string rawParam)) return document;
+
+ if (!int.TryParse(rawParam, out int parameterIndex)) return document;
+
+ var updatedMethod = method.AddParameterListParameters(
+ SyntaxFactory.Parameter(
+ SyntaxFactory.Identifier(
+ ev.Parameters[parameterIndex].DefaultIdentifierName)).WithType(
+ SyntaxFactory.ParseTypeName(ev.Parameters[parameterIndex].BaseType + (ev.Parameters[parameterIndex].IsArray ? "[]" : string.Empty))
+ .WithAdditionalAnnotations(Simplifier.Annotation)));
+
+ var updatedSyntaxTree = root.ReplaceNode(method, updatedMethod);
+
+ return document.WithSyntaxRoot(updatedSyntaxTree);
+ }
+
+ private async Task AddParametersAsync(Document document, ImmutableDictionary properties, MethodDeclarationSyntax method, CancellationToken token)
+ {
+ var root = await document.GetSyntaxRootAsync();
+
+ if (!properties.TryGetValue("eventId", out string rawEventId)) return document;
+
+ if (!int.TryParse(rawEventId, out int eventId)) return document;
+
+ if (!EventManager.Events.TryGetValue(eventId, out Event ev)) return document;
+
+ if (!properties.TryGetValue("parameters", out string rawParam)) return document;
+
+ var indexes = rawParam.Split(',').Select(x => int.Parse(x));
+
+ List parameters = new List();
+
+ foreach (var index in indexes)
+ {
+ parameters.Add(
+ SyntaxFactory.Parameter(
+ SyntaxFactory.Identifier(
+ ev.Parameters[index].DefaultIdentifierName)).WithType(
+ SyntaxFactory.ParseTypeName(ev.Parameters[index].BaseType + (ev.Parameters[index].IsArray ? "[]" : string.Empty))
+ .WithAdditionalAnnotations(Simplifier.Annotation)));
+ }
+
+ MethodDeclarationSyntax updatedMethod = method.AddParameterListParameters(parameters.ToArray());
+
+ var updatedSyntaxTree = root.ReplaceNode(method, updatedMethod);
+
+ return document.WithSyntaxRoot(updatedSyntaxTree);
+ }
+ }
+}
diff --git a/Analyzers/NWPluginAPI.Analyzers/Resources.Designer.cs b/Analyzers/NWPluginAPI.Analyzers/Resources.Designer.cs
deleted file mode 100644
index 7e3a20d..0000000
--- a/Analyzers/NWPluginAPI.Analyzers/Resources.Designer.cs
+++ /dev/null
@@ -1,105 +0,0 @@
-//------------------------------------------------------------------------------
-//
-// This code was generated by a tool.
-// Runtime Version:4.0.30319.0
-//
-// Changes to this file may cause incorrect behavior and will be lost if
-// the code is regenerated.
-//
-//------------------------------------------------------------------------------
-
-using System;
-using System.Reflection;
-
-namespace NWPluginAPI.Analyzers
-{
- ///
- /// A strongly-typed resource class, for looking up localized strings, etc.
- ///
- // This class was auto-generated by the StronglyTypedResourceBuilder
- // class via a tool like ResGen or Visual Studio.
- // To add or remove a member, edit your .ResX file then rerun ResGen
- // with the /str option, or rebuild your VS project.
- [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
- internal class Resources
- {
-
- private static global::System.Resources.ResourceManager resourceMan;
-
- private static global::System.Globalization.CultureInfo resourceCulture;
-
- [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- internal Resources()
- {
- }
-
- ///
- /// Returns the cached ResourceManager instance used by this class.
- ///
- [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
- internal static global::System.Resources.ResourceManager ResourceManager
- {
- get
- {
- if (object.ReferenceEquals(resourceMan, null))
- {
- global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("NWPluginAPI.Analyzers.Resources", typeof(Resources).GetTypeInfo().Assembly);
- resourceMan = temp;
- }
- return resourceMan;
- }
- }
-
- ///
- /// Overrides the current thread's CurrentUICulture property for all
- /// resource lookups using this strongly typed resource class.
- ///
- [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
- internal static global::System.Globalization.CultureInfo Culture
- {
- get
- {
- return resourceCulture;
- }
- set
- {
- resourceCulture = value;
- }
- }
-
- ///
- /// Looks up a localized string similar to Type names should be all uppercase..
- ///
- internal static string AnalyzerDescription
- {
- get
- {
- return ResourceManager.GetString("AnalyzerDescription", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Type name '{0}' contains lowercase letters.
- ///
- internal static string AnalyzerMessageFormat
- {
- get
- {
- return ResourceManager.GetString("AnalyzerMessageFormat", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Type name contains lowercase letters.
- ///
- internal static string AnalyzerTitle
- {
- get
- {
- return ResourceManager.GetString("AnalyzerTitle", resourceCulture);
- }
- }
- }
-}
diff --git a/Analyzers/NWPluginAPI.Analyzers/Resources.resx b/Analyzers/NWPluginAPI.Analyzers/Resources.resx
deleted file mode 100644
index 410edcc..0000000
--- a/Analyzers/NWPluginAPI.Analyzers/Resources.resx
+++ /dev/null
@@ -1,132 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- text/microsoft-resx
-
-
- 2.0
-
-
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- Type names should be all uppercase.
- An optional longer localizable description of the diagnostic.
-
-
- Type name '{0}' contains lowercase letters
- The format-able message the diagnostic displays.
-
-
- Type name contains lowercase letters
- The title of the diagnostic.
-
-
\ No newline at end of file
diff --git a/Analyzers/NwPluginAPI.Analyzers.Generator/NwPluginAPI.Analyzers.Generator.csproj b/Analyzers/NwPluginAPI.Analyzers.Generator/NwPluginAPI.Analyzers.Generator.csproj
new file mode 100644
index 0000000..1670ef6
--- /dev/null
+++ b/Analyzers/NwPluginAPI.Analyzers.Generator/NwPluginAPI.Analyzers.Generator.csproj
@@ -0,0 +1,13 @@
+
+
+
+ Exe
+ net6.0
+ enable
+ enable
+
+
+
+
+
+
diff --git a/Analyzers/NwPluginAPI.Analyzers.Generator/Program.cs b/Analyzers/NwPluginAPI.Analyzers.Generator/Program.cs
new file mode 100644
index 0000000..d9613ff
--- /dev/null
+++ b/Analyzers/NwPluginAPI.Analyzers.Generator/Program.cs
@@ -0,0 +1,58 @@
+using PluginAPI.Events;
+using System.Text;
+
+StringBuilder builder = new StringBuilder();
+builder.AppendLine("using System.Collections.Generic;");
+builder.AppendLine(string.Empty);
+builder.AppendLine("public class Event");
+builder.AppendLine("{");
+builder.AppendLine(" public readonly EventParameter[] Parameters;");
+builder.AppendLine(string.Empty);
+builder.AppendLine(" public Event(params EventParameter[] parameters)");
+builder.AppendLine(" {");
+builder.AppendLine(" Parameters = parameters;");
+builder.AppendLine(" }");
+builder.AppendLine("}");
+builder.AppendLine(string.Empty);
+builder.AppendLine("public class EventParameter");
+builder.AppendLine("{");
+builder.AppendLine(" public string BaseType { get; set; }");
+builder.AppendLine(" public bool IsArray { get; set; }");
+builder.AppendLine(" public string DefaultIdentifierName { get; set; }");
+builder.AppendLine(string.Empty);
+builder.AppendLine(" public EventParameter(string baseType, bool isArray, string defaultIdentifierName)");
+builder.AppendLine(" {");
+builder.AppendLine(" BaseType = baseType;");
+builder.AppendLine(" IsArray = isArray;");
+builder.AppendLine(" DefaultIdentifierName = defaultIdentifierName;");
+builder.AppendLine(" }");
+builder.AppendLine("}");
+builder.AppendLine(string.Empty);
+builder.AppendLine("public static class EventManager");
+builder.AppendLine("{");
+builder.AppendLine(" public static Dictionary Events = new Dictionary()");
+builder.AppendLine(" {");
+
+foreach (var ev in EventManager.Events)
+{
+ if (ev.Value.Parameters.Length == 0)
+ builder.AppendLine(" { " + (int)ev.Key + ", new Event() },");
+ else
+ {
+ builder.AppendLine(" { " + (int)ev.Key + ", new Event(");
+ for(int x = 0; x < ev.Value.Parameters.Length; x++)
+ {
+ var param = ev.Value.Parameters[x];
+
+ if (param.BaseType.IsArray)
+ builder.AppendLine(" new EventParameter(\"" + param.BaseType.GetElementType()?.FullName + "\", true, \"" + param.DefaultIdentifierName+ "\")" + (x == (ev.Value.Parameters.Length - 1) ? ") }," : ","));
+ else
+ builder.AppendLine(" new EventParameter(\"" + param.BaseType.FullName + "\", false, \"" + param.DefaultIdentifierName+ "\")" + (x == (ev.Value.Parameters.Length - 1) ? ") }," : ","));
+ }
+ }
+}
+
+builder.AppendLine(" };");
+builder.AppendLine("}");
+
+File.WriteAllText($"..\\..\\..\\..\\NWPluginAPI.Analyzers\\Generated\\GeneratedEventManager.cs", builder.ToString());
diff --git a/NwPluginAPI.sln b/NwPluginAPI.sln
index 4338137..82e60a4 100644
--- a/NwPluginAPI.sln
+++ b/NwPluginAPI.sln
@@ -14,9 +14,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TemplatePlugin", "TemplateP
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Analyzers", "Analyzers", "{3CA0C582-BA36-455A-A480-8DD78BDD24D0}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NWPluginAPI.Analyzers", "Analyzers\NWPluginAPI.Analyzers\NWPluginAPI.Analyzers.csproj", "{4BE5D776-39A9-4532-9390-C59FB45E9571}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NwPluginAPI.Analyzers", "Analyzers\NWPluginAPI.Analyzers\NwPluginAPI.Analyzers.csproj", "{4BE5D776-39A9-4532-9390-C59FB45E9571}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NWPluginAPI.Analyzers.CodeFixes", "Analyzers\NWPluginAPI.Analyzers.CodeFixes\NWPluginAPI.Analyzers.CodeFixes.csproj", "{2044B87B-5C3C-478A-8048-452367690DF8}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NwPluginAPI.Analyzers.Generator", "Analyzers\NwPluginAPI.Analyzers.Generator\NwPluginAPI.Analyzers.Generator.csproj", "{9638A1ED-142B-4487-8DAA-A24E1F42E04C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -36,17 +36,17 @@ Global
{4BE5D776-39A9-4532-9390-C59FB45E9571}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4BE5D776-39A9-4532-9390-C59FB45E9571}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4BE5D776-39A9-4532-9390-C59FB45E9571}.Release|Any CPU.Build.0 = Release|Any CPU
- {2044B87B-5C3C-478A-8048-452367690DF8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {2044B87B-5C3C-478A-8048-452367690DF8}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {2044B87B-5C3C-478A-8048-452367690DF8}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {2044B87B-5C3C-478A-8048-452367690DF8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {9638A1ED-142B-4487-8DAA-A24E1F42E04C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {9638A1ED-142B-4487-8DAA-A24E1F42E04C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9638A1ED-142B-4487-8DAA-A24E1F42E04C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {9638A1ED-142B-4487-8DAA-A24E1F42E04C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{4BE5D776-39A9-4532-9390-C59FB45E9571} = {3CA0C582-BA36-455A-A480-8DD78BDD24D0}
- {2044B87B-5C3C-478A-8048-452367690DF8} = {3CA0C582-BA36-455A-A480-8DD78BDD24D0}
+ {9638A1ED-142B-4487-8DAA-A24E1F42E04C} = {3CA0C582-BA36-455A-A480-8DD78BDD24D0}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {1737D319-028C-47BB-8B5F-7E1F5DEB9264}
diff --git a/NwPluginAPI.sln.DotSettings b/NwPluginAPI.sln.DotSettings
new file mode 100644
index 0000000..643e12a
--- /dev/null
+++ b/NwPluginAPI.sln.DotSettings
@@ -0,0 +1,2 @@
+
+ True
\ No newline at end of file
diff --git a/NwPluginAPI/Core/FactoryManager.cs b/NwPluginAPI/Core/FactoryManager.cs
index ef44f82..24d7ff4 100644
--- a/NwPluginAPI/Core/FactoryManager.cs
+++ b/NwPluginAPI/Core/FactoryManager.cs
@@ -36,10 +36,16 @@ public static void RegisterPlayerFactory(object plugin, PlayerFactory factory)
PlayerFactories.Add(type, factory);
}
+ ///
+ /// Registers new player factory.
+ ///
+ /// The plugin object.
+ public static void RegisterPlayerFactory(object plugin) where T : PlayerFactory => RegisterPlayerFactory(plugin, Activator.CreateInstance());
+
///
/// Initializes factory manager.
///
- public static void Init()
+ public static void Init()
{
StaticUnityMethods.OnUpdate += OnUpdate;
StaticUnityMethods.OnLateUpdate += OnLateUpdate;
@@ -53,7 +59,14 @@ static void OnUpdate()
{
foreach(var entity in factory.Entities)
{
- entity.Value.OnUpdate();
+ try
+ {
+ entity.Value.OnUpdate();
+ }
+ catch (Exception ex)
+ {
+ Log.Error($"Failed executing OnUpdate in {entity.Value.GetType().Name}, error\n {ex}");
+ }
}
}
}
@@ -103,14 +116,17 @@ static void RemovePlayer(ReferenceHub obj)
try
{
- PlayerSharedStorage.DestroyStorage(plr);
plr.OnDestroy();
}
catch (Exception ex)
{
Log.Error($"Failed executing OnDestroy in {plr.GetType().Name}, error\n {ex}");
}
- factory.Entities.Remove(obj);
+
+ if (plr is Player p)
+ p.OnInternalDestroy();
+
+ factory.Entities.Remove(obj);
}
}
}
diff --git a/NwPluginAPI/Core/Player.cs b/NwPluginAPI/Core/Player.cs
index 46c453b..81fb5bb 100644
--- a/NwPluginAPI/Core/Player.cs
+++ b/NwPluginAPI/Core/Player.cs
@@ -493,7 +493,7 @@ public ItemBase CurrentItem
public bool IsIntercomMuted => VoiceChatMutes.QueryLocalMute(UserId, true);
///
- /// Gets if player is using voiec chat.
+ /// Gets if player is using voicechat.
///
public bool IsUsingVoiceChat => PersonalRadioPlayback.IsTransmitting(ReferenceHub);
@@ -617,6 +617,9 @@ public Player(IGameComponent component)
EffectsManager = new EffectsManager(this);
DamageManager = new DamageManager(this);
+ if (!PlayersIds.ContainsKey(PlayerId))
+ PlayersIds.Add(PlayerId, ReferenceHub);
+
try
{
OnStart();
@@ -628,6 +631,16 @@ public Player(IGameComponent component)
}
#endregion
+ #region Internal Methods
+ internal void OnInternalDestroy()
+ {
+ PlayerSharedStorage.DestroyStorage(this);
+ PlayersIds.Remove(PlayerId);
+ if (UserId != null)
+ PlayersUserIds.Remove(UserId);
+ }
+ #endregion
+
#region Public Methods
///
/// Shows a broadcast to the player.
diff --git a/NwPluginAPI/Events/Event.cs b/NwPluginAPI/Events/Event.cs
new file mode 100644
index 0000000..7693e94
--- /dev/null
+++ b/NwPluginAPI/Events/Event.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+
+namespace PluginAPI.Events
+{
+ public class Event
+ {
+ public readonly Dictionary> Invokers = new Dictionary>();
+
+ public readonly EventParameter[] Parameters;
+
+ public Event(params EventParameter[] parameters)
+ {
+ Parameters = parameters;
+ }
+
+ public void RegisterInvoker(Type plugin, object handle, MethodInfo method)
+ {
+ if (!Invokers.ContainsKey(plugin))
+ Invokers.Add(plugin, new List());
+
+ Invokers[plugin].Add(new EventInvokeLocation()
+ {
+ Plugin = plugin,
+ Target = handle,
+ Method = method
+ });
+ }
+ }
+}
diff --git a/NwPluginAPI/Events/EventInvokeLocation.cs b/NwPluginAPI/Events/EventInvokeLocation.cs
new file mode 100644
index 0000000..3d41413
--- /dev/null
+++ b/NwPluginAPI/Events/EventInvokeLocation.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+
+namespace PluginAPI.Events
+{
+ public class EventInvokeLocation
+ {
+ public Type Plugin;
+ public object Target;
+ public MethodInfo Method;
+
+ public object Invoke(List
/// The object of plugin.
- public static void RegisterEvents(object plugin) where T : Type => RegisterEvents(plugin.GetType(), typeof(T));
+ public static void RegisterEvents(object plugin) where T : Type
+ {
+ if (!EventHandlers.TryGetValue(typeof(T), out object handler))
+ {
+ handler = Activator.CreateInstance(typeof(T));
+ EventHandlers.Add(typeof(T), handler);
+ }
+
+ RegisterEvents(plugin.GetType(), handler);
+ }
///
/// Registers events in plugin.
///
/// The object of plugin.
/// The event handler.
- static void RegisterEvents(Type plugin, Type eventHandler)
+ static void RegisterEvents(Type plugin, object eventHandler)
{
- if (!EventHandlers.ContainsKey(plugin))
- EventHandlers.Add(plugin, new List());
-
- if (!EventHandlers[plugin].Contains(eventHandler))
- EventHandlers[plugin].Add(eventHandler);
-
- if (!HandlerInstances.TryGetValue(eventHandler, out object handle))
- {
- handle = Activator.CreateInstance(eventHandler);
- HandlerInstances.Add(eventHandler, handle);
- }
-
- foreach (var method in eventHandler.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
+ foreach (var method in eventHandler.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
{
var attribute = method.GetCustomAttribute();
@@ -170,23 +279,21 @@ static void RegisterEvents(Type plugin, Type eventHandler)
{
case PluginEvent pluginEvent:
+ if (!Events.TryGetValue(pluginEvent.EventType, out Event ev))
+ {
+ Log.Error($"Event &6{pluginEvent.EventType}&r is not registered in manager! ( create issue on github )");
+ continue;
+ }
+
var eventParameters = method.GetParameters().Select(p => p.ParameterType).ToArray();
- if (!ValidateEvent(eventParameters, RequiredParameters[pluginEvent.EventType]))
+ if (!ValidateEvent(eventParameters, ev.Parameters.Select(x => x.BaseType).ToArray()))
{
- Log.Error($"Event &6{method.Name}&r (&6{pluginEvent.EventType}&r) in plugin &6{plugin.FullName}&r contains wrong parameters\n - &6{(string.Join(", ", eventParameters.Select(p => p.Name)))}\n - Required:\n - &6{(string.Join(", ", RequiredParameters[pluginEvent.EventType].Select(p => p.Name)))}.");
+ Log.Error($"Event &6{method.Name}&r (&6{pluginEvent.EventType}&r) in plugin &6{plugin.FullName}&r contains wrong parameters\n - &6{(string.Join(", ", eventParameters.Select(p => p.Name)))}\n - Required:\n - &6{(string.Join(", ", ev.Parameters.Select(p => p.BaseType.Name)))}.");
continue;
}
- if (!RegisteredEvents.ContainsKey(pluginEvent.EventType))
- RegisteredEvents.Add(pluginEvent.EventType, new List());
-
- RegisteredEvents[pluginEvent.EventType].Add(new EventInfo()
- {
- Plugin = plugin,
- Target = handle,
- Method = method,
- });
+ ev.RegisterInvoker(plugin, eventHandler, method);
Log.Info($"Registered event &6{method.Name}&r (&6{pluginEvent.EventType}&r) in plugin &6{plugin.FullName}&r!");
break;
@@ -194,7 +301,7 @@ static void RegisterEvents(Type plugin, Type eventHandler)
}
}
- private static PlayerFactory GetPlayerFactory(EventInfo ev)
+ private static PlayerFactory GetPlayerFactory(EventInvokeLocation ev)
{
if (!FactoryManager.PlayerFactories.TryGetValue(ev.Plugin, out PlayerFactory pFactory))
pFactory = FactoryManager.PlayerFactories[typeof(EventManager)];
@@ -208,23 +315,40 @@ private static PlayerFactory GetPlayerFactory(EventInfo ev)
/// The type of event
/// The arguments of event.
/// If false event is canceled.
- public static bool ExecuteEvent(ServerEventType type, params object[] args)
+ public static bool ExecuteEvent(ServerEventType type, params object[] args) => ExecuteEvent(type, args);
+
+ ///
+ /// Executes event.
+ ///
+ /// The type of event
+ /// The arguments of event.
+ /// Event cancellation data.
+ // ReSharper disable once MemberCanBePrivate.Global
+ public static T ExecuteEvent(ServerEventType type, params object[] args) where T : struct
{
- if (!RegisteredEvents.TryGetValue(type, out var registeredEvents))
- return true;
+ if (!Events.TryGetValue(type, out Event ev))
+ {
+ Log.Error($"Event &6{type}&r is not registered in manager! ( create issue on github )");
+ return default;
+ }
+
+ switch (type)
+ {
+ case ServerEventType.PlayerJoined:
+ if (!(args[0] is IGameComponent component)) break;
+
+ if (!Player.TryGet(component, out Player plr)) break;
+
+ Player.PlayersUserIds.Add(plr.UserId, component);
+ break;
+ }
var constructEventParameters = new List
\ No newline at end of file